~ubuntu-branches/ubuntu/natty/linux-backports-modules-2.6.38/natty-proposed

« back to all changes in this revision

Viewing changes to updates/compat-wireless-2.6.36/linux-next-pending/0011-btusb-Add-fw-load-support.patch

  • Committer: Bazaar Package Importer
  • Author(s): Tim Gardner, Tim Gardner
  • Date: 2011-06-08 10:44:09 UTC
  • Revision ID: james.westby@ubuntu.com-20110608104409-fnl8carkdo15bwsz
Tags: 2.6.38-10.6
[ Tim Gardner ]

Shorten compat-wireless package name to cw to accomodate
CDROM file name length restrictions.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Reason for this not being merged upstream:
2
 
 
3
 
It was first rejected without any alternatives suggested. Then
4
 
an alternative was finally suggested but too late for integration
5
 
upstream.
6
 
 
7
 
This is a work around until a new firmware and patch is being worked
8
 
on which is acceptable upstream.
9
 
 
10
 
For details refer to:
11
 
 
12
 
http://lkml.org/lkml/2010/10/5/195
13
 
 
14
 
From 4ac276c14578b380d0c6a27658eeaa364efe6432 Mon Sep 17 00:00:00 2001
15
 
From: Bala Shanmugam <sbalashanmugam@atheros.com>
16
 
Date: Fri, 1 Oct 2010 15:18:02 +0530
17
 
Subject: [PATCH] Added support to load firmware to target RAM from btusb transport driver.
18
 
 Each BT device vendor can add their product ID, firmware file, load and unload function
19
 
 to btusb_fwcbs array. When the device is inserted btusb will call appropriate
20
 
 firmware load function.  This support will significantly reduce cost of
21
 
 BT chip because of RAM based firmware.
22
 
 Signed-off-by: Bala Shanmugam <sbalashanmugam@atheros.com>
23
 
 
24
 
---
25
 
 drivers/bluetooth/Makefile |    1 +
26
 
 drivers/bluetooth/btusb.c  |   67 +++++++++++++++
27
 
 drivers/bluetooth/fwload.c |  199 ++++++++++++++++++++++++++++++++++++++++++++
28
 
 drivers/bluetooth/fwload.h |   39 +++++++++
29
 
 4 files changed, 306 insertions(+), 0 deletions(-)
30
 
 create mode 100644 drivers/bluetooth/fwload.c
31
 
 create mode 100644 drivers/bluetooth/fwload.h
32
 
 
33
 
--- a/drivers/bluetooth/Makefile
34
 
+++ b/drivers/bluetooth/Makefile
35
 
@@ -13,6 +13,7 @@ obj-$(CONFIG_BT_HCIBLUECARD)  += bluecard
36
 
 obj-$(CONFIG_BT_HCIBTUART)     += btuart_cs.o
37
 
 
38
 
 obj-$(CONFIG_BT_HCIBTUSB)      += btusb.o
39
 
+obj-$(CONFIG_BT_HCIBTUSB)      += fwload.o
40
 
 obj-$(CONFIG_BT_HCIBTSDIO)     += btsdio.o
41
 
 
42
 
 obj-$(CONFIG_BT_ATH3K)         += ath3k.o
43
 
--- a/drivers/bluetooth/btusb.c
44
 
+++ b/drivers/bluetooth/btusb.c
45
 
@@ -34,6 +34,7 @@
46
 
 
47
 
 #include <net/bluetooth/bluetooth.h>
48
 
 #include <net/bluetooth/hci_core.h>
49
 
+#include "fwload.h"
50
 
 
51
 
 #define VERSION "0.6"
52
 
 
53
 
@@ -55,6 +56,26 @@ static struct usb_driver btusb_driver;
54
 
 #define BTUSB_BROKEN_ISOC      0x20
55
 
 #define BTUSB_WRONG_SCO_MTU    0x40
56
 
 
57
 
+static struct usb_device_id ath_table[] = {
58
 
+       /* Atheros AR3011 */
59
 
+       { USB_DEVICE(0x0CF3, 0x3002) },
60
 
+       { USB_DEVICE(0x13D3, 0x3304) },
61
 
+       { }     /* Terminating entry */
62
 
+};
63
 
+
64
 
+/* Add firmware file, load and unload function
65
 
+ * to download the firmware to target RAM
66
 
+ */
67
 
+static struct fw_cb_config btusb_fwcbs[] = {
68
 
+       {
69
 
+               .fwfile = "ath3k-1.fw",
70
 
+               .usb_id_table = ath_table,
71
 
+               .fwload = ath_fw_load,
72
 
+               .fwunload = ath_fw_unload
73
 
+       },
74
 
+       {}
75
 
+};
76
 
+
77
 
 static struct usb_device_id btusb_table[] = {
78
 
        /* Generic Bluetooth USB device */
79
 
        { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
80
 
@@ -863,6 +884,7 @@ static int btusb_probe(struct usb_interf
81
 
        struct btusb_data *data;
82
 
        struct hci_dev *hdev;
83
 
        int i, err;
84
 
+       const struct usb_device_id *match;
85
 
 
86
 
        BT_DBG("intf %p id %p", intf, id);
87
 
 
88
 
@@ -922,6 +944,19 @@ static int btusb_probe(struct usb_interf
89
 
        data->udev = interface_to_usbdev(intf);
90
 
        data->intf = intf;
91
 
 
92
 
+       for (i = 0; btusb_fwcbs[i].fwfile; i++) {
93
 
+               match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
94
 
+               if (match) {
95
 
+                       if (btusb_fwcbs[i].fwload) {
96
 
+                               btusb_fwcbs[i].data =
97
 
+                                       btusb_fwcbs[i].fwload(intf,
98
 
+                                               btusb_fwcbs[i].fwfile,
99
 
+                                               &btusb_fwcbs[i].bsuspend);
100
 
+                       }
101
 
+                       break;
102
 
+               }
103
 
+       }
104
 
+
105
 
        spin_lock_init(&data->lock);
106
 
 
107
 
        INIT_WORK(&data->work, btusb_work);
108
 
@@ -1030,12 +1065,26 @@ static void btusb_disconnect(struct usb_
109
 
 {
110
 
        struct btusb_data *data = usb_get_intfdata(intf);
111
 
        struct hci_dev *hdev;
112
 
+       const struct usb_device_id *match;
113
 
+       int i;
114
 
 
115
 
        BT_DBG("intf %p", intf);
116
 
 
117
 
        if (!data)
118
 
                return;
119
 
 
120
 
+       for (i = 0; btusb_fwcbs[i].fwfile; i++) {
121
 
+               match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
122
 
+               if (match) {
123
 
+                       if (btusb_fwcbs[i].fwunload) {
124
 
+                               btusb_fwcbs[i].fwunload(btusb_fwcbs[i].data,
125
 
+                                               btusb_fwcbs[i].bsuspend);
126
 
+                               btusb_fwcbs[i].data = NULL;
127
 
+                       }
128
 
+                       break;
129
 
+               }
130
 
+       }
131
 
+
132
 
        hdev = data->hdev;
133
 
 
134
 
        __hci_dev_hold(hdev);
135
 
@@ -1061,12 +1110,22 @@ static void btusb_disconnect(struct usb_
136
 
 static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
137
 
 {
138
 
        struct btusb_data *data = usb_get_intfdata(intf);
139
 
+       const struct usb_device_id *match;
140
 
+       int i;
141
 
 
142
 
        BT_DBG("intf %p", intf);
143
 
 
144
 
        if (data->suspend_count++)
145
 
                return 0;
146
 
 
147
 
+       for (i = 0; btusb_fwcbs[i].fwfile; i++) {
148
 
+               match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
149
 
+               if (match) {
150
 
+                       btusb_fwcbs[i].bsuspend = 1;
151
 
+                       break;
152
 
+               }
153
 
+       }
154
 
+
155
 
        spin_lock_irq(&data->txlock);
156
 
        if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
157
 
                set_bit(BTUSB_SUSPENDING, &data->flags);
158
 
@@ -1179,6 +1238,14 @@ static int __init btusb_init(void)
159
 
 
160
 
 static void __exit btusb_exit(void)
161
 
 {
162
 
+       int i;
163
 
+       for (i = 0; btusb_fwcbs[i].fwfile; i++) {
164
 
+               if (btusb_fwcbs[i].fwunload && btusb_fwcbs[i].data) {
165
 
+                       btusb_fwcbs[i].fwunload(btusb_fwcbs[i].data,
166
 
+                                       btusb_fwcbs[i].bsuspend);
167
 
+                       btusb_fwcbs[i].data = NULL;
168
 
+               }
169
 
+       }
170
 
        usb_deregister(&btusb_driver);
171
 
 }
172
 
 
173
 
--- /dev/null
174
 
+++ b/drivers/bluetooth/fwload.c
175
 
@@ -0,0 +1,199 @@
176
 
+/*
177
 
+ *
178
 
+ *  Generic Bluetooth USB DFU driver to download firmware to target RAM
179
 
+ *
180
 
+ *  Copyright (c) 2009-2010 Atheros Communications Inc.
181
 
+ *
182
 
+ *  This program is free software; you can redistribute it and/or modify
183
 
+ *  it under the terms of the GNU General Public License as published by
184
 
+ *  the Free Software Foundation; either version 2 of the License, or
185
 
+ *  (at your option) any later version.
186
 
+ *
187
 
+ *  This program is distributed in the hope that it will be useful,
188
 
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
189
 
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
190
 
+ *  GNU General Public License for more details.
191
 
+ *
192
 
+ *  You should have received a copy of the GNU General Public License
193
 
+ *  along with this program; if not, write to the Free Software
194
 
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
195
 
+ *
196
 
+ */
197
 
+
198
 
+#include <linux/module.h>
199
 
+#include <linux/kernel.h>
200
 
+#include <linux/init.h>
201
 
+#include <linux/slab.h>
202
 
+#include <linux/types.h>
203
 
+#include <linux/device.h>
204
 
+#include <linux/firmware.h>
205
 
+#include <linux/usb.h>
206
 
+#include <net/bluetooth/bluetooth.h>
207
 
+
208
 
+#define USB_REQ_DFU_DNLOAD     1
209
 
+#define USB_REQ_GET_STATE      5
210
 
+#define USB_FIRMWARE_RAM_MODE 11
211
 
+#define USB_FIRMWARE_FLASH_MODE 12
212
 
+#define BULK_SIZE              4096
213
 
+#define VERSION "1.0"
214
 
+
215
 
+struct firmware_data {
216
 
+       struct usb_device *udev;
217
 
+       u8 *fw_data;
218
 
+       u32 fw_size;
219
 
+       u32 fw_sent;
220
 
+};
221
 
+
222
 
+static int load_firmware(struct firmware_data *data,
223
 
+                               unsigned char *firmware,
224
 
+                               int count)
225
 
+{
226
 
+       u8 *send_buf;
227
 
+       int err, pipe, len, size, sent = 0;
228
 
+       char ucFirmware = 0;
229
 
+
230
 
+       BT_DBG("ath3k %p udev %p", data, data->udev);
231
 
+
232
 
+       if ((usb_control_msg(data->udev, usb_rcvctrlpipe(data->udev, 0),
233
 
+                               USB_REQ_GET_STATE,
234
 
+                               USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
235
 
+                               &ucFirmware, 1, USB_CTRL_SET_TIMEOUT)) < 0) {
236
 
+               BT_ERR("Can't change to loading configuration err");
237
 
+               return -EBUSY;
238
 
+       }
239
 
+
240
 
+       if (ucFirmware == USB_FIRMWARE_RAM_MODE) {
241
 
+               /* RAM based firmware is available in the target.
242
 
+                * No need to load the firmware to RAM */
243
 
+               BT_DBG("RAM based firmware is available");
244
 
+               return 0;
245
 
+       }
246
 
+
247
 
+       pipe = usb_sndctrlpipe(data->udev, 0);
248
 
+       if ((usb_control_msg(data->udev, pipe,
249
 
+                               USB_REQ_DFU_DNLOAD,
250
 
+                               USB_TYPE_VENDOR, 0, 0,
251
 
+                               firmware, 20, USB_CTRL_SET_TIMEOUT)) < 0) {
252
 
+               BT_ERR("Can't change to loading configuration err");
253
 
+               return -EBUSY;
254
 
+       }
255
 
+       sent += 20;
256
 
+       count -= 20;
257
 
+
258
 
+       send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
259
 
+       if (!send_buf) {
260
 
+               BT_ERR("Can't allocate memory chunk for firmware");
261
 
+               return -ENOMEM;
262
 
+       }
263
 
+
264
 
+       while (count) {
265
 
+               size = min_t(uint, count, BULK_SIZE);
266
 
+               pipe = usb_sndbulkpipe(data->udev, 0x02);
267
 
+               memcpy(send_buf, firmware + sent, size);
268
 
+
269
 
+               err = usb_bulk_msg(data->udev, pipe, send_buf, size,
270
 
+                                       &len, 3000);
271
 
+
272
 
+               if (err || (len != size)) {
273
 
+                       BT_ERR("Error in firmware loading err = %d,"
274
 
+                               "len = %d, size = %d", err, len, size);
275
 
+                       goto error;
276
 
+               }
277
 
+
278
 
+               sent  += size;
279
 
+               count -= size;
280
 
+       }
281
 
+
282
 
+       kfree(send_buf);
283
 
+       return 0;
284
 
+
285
 
+error:
286
 
+       kfree(send_buf);
287
 
+       return err;
288
 
+}
289
 
+
290
 
+void *ath_fw_load(struct usb_interface *intf,
291
 
+                       const char *fwfile, bool *suspend)
292
 
+{
293
 
+       const struct firmware *firmware;
294
 
+       struct usb_device *udev = interface_to_usbdev(intf);
295
 
+       static struct firmware_data *data;
296
 
+       int size;
297
 
+
298
 
+       BT_DBG("\nintf %p suspend %d\n", intf, *suspend);
299
 
+
300
 
+       if (*suspend) {
301
 
+               load_firmware(data, data->fw_data, data->fw_size);
302
 
+               *suspend = 0;
303
 
+               return data;
304
 
+       }
305
 
+
306
 
+       if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
307
 
+               return NULL;
308
 
+
309
 
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
310
 
+       if (!data)
311
 
+               return NULL;
312
 
+       data->udev = udev;
313
 
+
314
 
+       if (request_firmware(&firmware, fwfile, &udev->dev) < 0) {
315
 
+               kfree(data);
316
 
+               return NULL;
317
 
+       }
318
 
+
319
 
+       size = max_t(uint, firmware->size, 4096);
320
 
+       data->fw_data = kmalloc(size, GFP_KERNEL);
321
 
+       if (!data->fw_data) {
322
 
+               release_firmware(firmware);
323
 
+               kfree(data);
324
 
+               return NULL;
325
 
+       }
326
 
+
327
 
+       memcpy(data->fw_data, firmware->data, firmware->size);
328
 
+       data->fw_size = firmware->size;
329
 
+       data->fw_sent = 0;
330
 
+       release_firmware(firmware);
331
 
+
332
 
+       if (load_firmware(data, data->fw_data, data->fw_size)) {
333
 
+               kfree(data->fw_data);
334
 
+               kfree(data);
335
 
+               return NULL;
336
 
+       }
337
 
+       return data;
338
 
+}
339
 
+EXPORT_SYMBOL(ath_fw_load);
340
 
+
341
 
+void ath_fw_unload(void *pdata, bool bsuspend)
342
 
+{
343
 
+       struct firmware_data *data = (struct firmware_data *)pdata;
344
 
+
345
 
+       if (data == NULL)
346
 
+               return;
347
 
+
348
 
+       /* do not free the data on suspend as we will
349
 
+        * use it on resume */
350
 
+       if (!bsuspend) {
351
 
+               kfree(data->fw_data);
352
 
+               kfree(data);
353
 
+       }
354
 
+}
355
 
+EXPORT_SYMBOL(ath_fw_unload);
356
 
+
357
 
+static int __init fwload_init(void)
358
 
+{
359
 
+       BT_INFO("Firmware load driver init. Version:%s", VERSION);
360
 
+       return 0;
361
 
+}
362
 
+
363
 
+static void __exit fwload_deinit(void)
364
 
+{
365
 
+       BT_INFO("Firmware load driver deinit");
366
 
+}
367
 
+
368
 
+module_init(fwload_init);
369
 
+module_exit(fwload_deinit);
370
 
+
371
 
+MODULE_AUTHOR("Atheros Communications");
372
 
+MODULE_DESCRIPTION("Firmware load driver");
373
 
+MODULE_VERSION(VERSION);
374
 
+MODULE_LICENSE("GPL");
375
 
--- /dev/null
376
 
+++ b/drivers/bluetooth/fwload.h
377
 
@@ -0,0 +1,39 @@
378
 
+/*
379
 
+ *
380
 
+ *  Generic Bluetooth USB DFU driver to download firmware to target RAM
381
 
+ *
382
 
+ *  Copyright (c) 2009-2010 Atheros Communications Inc.
383
 
+ *
384
 
+ *  This program is free software; you can redistribute it and/or modify
385
 
+ *  it under the terms of the GNU General Public License as published by
386
 
+ *  the Free Software Foundation; either version 2 of the License, or
387
 
+ *  (at your option) any later version.
388
 
+ *
389
 
+ *  This program is distributed in the hope that it will be useful,
390
 
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
391
 
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
392
 
+ *  GNU General Public License for more details.
393
 
+ *
394
 
+ *  You should have received a copy of the GNU General Public License
395
 
+ *  along with this program; if not, write to the Free Software
396
 
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
397
 
+ *
398
 
+ */
399
 
+#ifndef _FWLOAD_H_
400
 
+#define _FWLOAD_H_
401
 
+
402
 
+/* callbacks to load firmware to BT device RAM
403
 
+ * when it is inserted */
404
 
+struct fw_cb_config {
405
 
+       const char *fwfile;
406
 
+       void * (*fwload)(struct usb_interface *intf, const char *fwfile,
407
 
+                        bool *bsuspend);
408
 
+       void (*fwunload)(void *, bool);
409
 
+       const struct usb_device_id *usb_id_table;
410
 
+       void *data;
411
 
+       bool bsuspend;
412
 
+};
413
 
+void *ath_fw_load(struct usb_interface *intf, const char *, bool *);
414
 
+void ath_fw_unload(void *pdata, bool bsuspend);
415
 
+
416
 
+#endif /* _FWLOAD_H_ */