Root/
1 | /* |
2 | * |
3 | * Broadcom Blutonium firmware driver |
4 | * |
5 | * Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com> |
6 | * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org> |
7 | * |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. |
13 | * |
14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | * |
23 | */ |
24 | |
25 | #include <linux/module.h> |
26 | |
27 | #include <linux/atomic.h> |
28 | #include <linux/kernel.h> |
29 | #include <linux/init.h> |
30 | #include <linux/slab.h> |
31 | #include <linux/types.h> |
32 | #include <linux/errno.h> |
33 | |
34 | #include <linux/device.h> |
35 | #include <linux/firmware.h> |
36 | |
37 | #include <linux/usb.h> |
38 | |
39 | #include <net/bluetooth/bluetooth.h> |
40 | |
41 | #define VERSION "1.2" |
42 | |
43 | static const struct usb_device_id bcm203x_table[] = { |
44 | /* Broadcom Blutonium (BCM2033) */ |
45 | { USB_DEVICE(0x0a5c, 0x2033) }, |
46 | |
47 | { } /* Terminating entry */ |
48 | }; |
49 | |
50 | MODULE_DEVICE_TABLE(usb, bcm203x_table); |
51 | |
52 | #define BCM203X_ERROR 0 |
53 | #define BCM203X_RESET 1 |
54 | #define BCM203X_LOAD_MINIDRV 2 |
55 | #define BCM203X_SELECT_MEMORY 3 |
56 | #define BCM203X_CHECK_MEMORY 4 |
57 | #define BCM203X_LOAD_FIRMWARE 5 |
58 | #define BCM203X_CHECK_FIRMWARE 6 |
59 | |
60 | #define BCM203X_IN_EP 0x81 |
61 | #define BCM203X_OUT_EP 0x02 |
62 | |
63 | struct bcm203x_data { |
64 | struct usb_device *udev; |
65 | |
66 | unsigned long state; |
67 | |
68 | struct work_struct work; |
69 | atomic_t shutdown; |
70 | |
71 | struct urb *urb; |
72 | unsigned char *buffer; |
73 | |
74 | unsigned char *fw_data; |
75 | unsigned int fw_size; |
76 | unsigned int fw_sent; |
77 | }; |
78 | |
79 | static void bcm203x_complete(struct urb *urb) |
80 | { |
81 | struct bcm203x_data *data = urb->context; |
82 | struct usb_device *udev = urb->dev; |
83 | int len; |
84 | |
85 | BT_DBG("udev %p urb %p", udev, urb); |
86 | |
87 | if (urb->status) { |
88 | BT_ERR("URB failed with status %d", urb->status); |
89 | data->state = BCM203X_ERROR; |
90 | return; |
91 | } |
92 | |
93 | switch (data->state) { |
94 | case BCM203X_LOAD_MINIDRV: |
95 | memcpy(data->buffer, "#", 1); |
96 | |
97 | usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), |
98 | data->buffer, 1, bcm203x_complete, data); |
99 | |
100 | data->state = BCM203X_SELECT_MEMORY; |
101 | |
102 | /* use workqueue to have a small delay */ |
103 | schedule_work(&data->work); |
104 | break; |
105 | |
106 | case BCM203X_SELECT_MEMORY: |
107 | usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), |
108 | data->buffer, 32, bcm203x_complete, data, 1); |
109 | |
110 | data->state = BCM203X_CHECK_MEMORY; |
111 | |
112 | if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) |
113 | BT_ERR("Can't submit URB"); |
114 | break; |
115 | |
116 | case BCM203X_CHECK_MEMORY: |
117 | if (data->buffer[0] != '#') { |
118 | BT_ERR("Memory select failed"); |
119 | data->state = BCM203X_ERROR; |
120 | break; |
121 | } |
122 | |
123 | data->state = BCM203X_LOAD_FIRMWARE; |
124 | |
125 | case BCM203X_LOAD_FIRMWARE: |
126 | if (data->fw_sent == data->fw_size) { |
127 | usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), |
128 | data->buffer, 32, bcm203x_complete, data, 1); |
129 | |
130 | data->state = BCM203X_CHECK_FIRMWARE; |
131 | } else { |
132 | len = min_t(uint, data->fw_size - data->fw_sent, 4096); |
133 | |
134 | usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), |
135 | data->fw_data + data->fw_sent, len, bcm203x_complete, data); |
136 | |
137 | data->fw_sent += len; |
138 | } |
139 | |
140 | if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) |
141 | BT_ERR("Can't submit URB"); |
142 | break; |
143 | |
144 | case BCM203X_CHECK_FIRMWARE: |
145 | if (data->buffer[0] != '.') { |
146 | BT_ERR("Firmware loading failed"); |
147 | data->state = BCM203X_ERROR; |
148 | break; |
149 | } |
150 | |
151 | data->state = BCM203X_RESET; |
152 | break; |
153 | } |
154 | } |
155 | |
156 | static void bcm203x_work(struct work_struct *work) |
157 | { |
158 | struct bcm203x_data *data = |
159 | container_of(work, struct bcm203x_data, work); |
160 | |
161 | if (atomic_read(&data->shutdown)) |
162 | return; |
163 | |
164 | if (usb_submit_urb(data->urb, GFP_KERNEL) < 0) |
165 | BT_ERR("Can't submit URB"); |
166 | } |
167 | |
168 | static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id) |
169 | { |
170 | const struct firmware *firmware; |
171 | struct usb_device *udev = interface_to_usbdev(intf); |
172 | struct bcm203x_data *data; |
173 | int size; |
174 | |
175 | BT_DBG("intf %p id %p", intf, id); |
176 | |
177 | if (intf->cur_altsetting->desc.bInterfaceNumber != 0) |
178 | return -ENODEV; |
179 | |
180 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
181 | if (!data) { |
182 | BT_ERR("Can't allocate memory for data structure"); |
183 | return -ENOMEM; |
184 | } |
185 | |
186 | data->udev = udev; |
187 | data->state = BCM203X_LOAD_MINIDRV; |
188 | |
189 | data->urb = usb_alloc_urb(0, GFP_KERNEL); |
190 | if (!data->urb) { |
191 | BT_ERR("Can't allocate URB"); |
192 | kfree(data); |
193 | return -ENOMEM; |
194 | } |
195 | |
196 | if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { |
197 | BT_ERR("Mini driver request failed"); |
198 | usb_free_urb(data->urb); |
199 | kfree(data); |
200 | return -EIO; |
201 | } |
202 | |
203 | BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size); |
204 | |
205 | size = max_t(uint, firmware->size, 4096); |
206 | |
207 | data->buffer = kmalloc(size, GFP_KERNEL); |
208 | if (!data->buffer) { |
209 | BT_ERR("Can't allocate memory for mini driver"); |
210 | release_firmware(firmware); |
211 | usb_free_urb(data->urb); |
212 | kfree(data); |
213 | return -ENOMEM; |
214 | } |
215 | |
216 | memcpy(data->buffer, firmware->data, firmware->size); |
217 | |
218 | usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), |
219 | data->buffer, firmware->size, bcm203x_complete, data); |
220 | |
221 | release_firmware(firmware); |
222 | |
223 | if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { |
224 | BT_ERR("Firmware request failed"); |
225 | usb_free_urb(data->urb); |
226 | kfree(data->buffer); |
227 | kfree(data); |
228 | return -EIO; |
229 | } |
230 | |
231 | BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); |
232 | |
233 | data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL); |
234 | if (!data->fw_data) { |
235 | BT_ERR("Can't allocate memory for firmware image"); |
236 | release_firmware(firmware); |
237 | usb_free_urb(data->urb); |
238 | kfree(data->buffer); |
239 | kfree(data); |
240 | return -ENOMEM; |
241 | } |
242 | |
243 | data->fw_size = firmware->size; |
244 | data->fw_sent = 0; |
245 | |
246 | release_firmware(firmware); |
247 | |
248 | INIT_WORK(&data->work, bcm203x_work); |
249 | |
250 | usb_set_intfdata(intf, data); |
251 | |
252 | /* use workqueue to have a small delay */ |
253 | schedule_work(&data->work); |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | static void bcm203x_disconnect(struct usb_interface *intf) |
259 | { |
260 | struct bcm203x_data *data = usb_get_intfdata(intf); |
261 | |
262 | BT_DBG("intf %p", intf); |
263 | |
264 | atomic_inc(&data->shutdown); |
265 | cancel_work_sync(&data->work); |
266 | |
267 | usb_kill_urb(data->urb); |
268 | |
269 | usb_set_intfdata(intf, NULL); |
270 | |
271 | usb_free_urb(data->urb); |
272 | kfree(data->fw_data); |
273 | kfree(data->buffer); |
274 | kfree(data); |
275 | } |
276 | |
277 | static struct usb_driver bcm203x_driver = { |
278 | .name = "bcm203x", |
279 | .probe = bcm203x_probe, |
280 | .disconnect = bcm203x_disconnect, |
281 | .id_table = bcm203x_table, |
282 | .disable_hub_initiated_lpm = 1, |
283 | }; |
284 | |
285 | module_usb_driver(bcm203x_driver); |
286 | |
287 | MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); |
288 | MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); |
289 | MODULE_VERSION(VERSION); |
290 | MODULE_LICENSE("GPL"); |
291 | MODULE_FIRMWARE("BCM2033-MD.hex"); |
292 | MODULE_FIRMWARE("BCM2033-FW.bin"); |
293 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9