diff options
Diffstat (limited to 'drivers/bluetooth/ath3k.c')
-rw-r--r-- | drivers/bluetooth/ath3k.c | 290 |
1 files changed, 285 insertions, 5 deletions
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 333c21289d97..5577ed656e2f 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c | |||
@@ -31,6 +31,30 @@ | |||
31 | 31 | ||
32 | #define VERSION "1.0" | 32 | #define VERSION "1.0" |
33 | 33 | ||
34 | #define ATH3K_DNLOAD 0x01 | ||
35 | #define ATH3K_GETSTATE 0x05 | ||
36 | #define ATH3K_SET_NORMAL_MODE 0x07 | ||
37 | #define ATH3K_GETVERSION 0x09 | ||
38 | #define USB_REG_SWITCH_VID_PID 0x0a | ||
39 | |||
40 | #define ATH3K_MODE_MASK 0x3F | ||
41 | #define ATH3K_NORMAL_MODE 0x0E | ||
42 | |||
43 | #define ATH3K_PATCH_UPDATE 0x80 | ||
44 | #define ATH3K_SYSCFG_UPDATE 0x40 | ||
45 | |||
46 | #define ATH3K_XTAL_FREQ_26M 0x00 | ||
47 | #define ATH3K_XTAL_FREQ_40M 0x01 | ||
48 | #define ATH3K_XTAL_FREQ_19P2 0x02 | ||
49 | #define ATH3K_NAME_LEN 0xFF | ||
50 | |||
51 | struct ath3k_version { | ||
52 | unsigned int rom_version; | ||
53 | unsigned int build_version; | ||
54 | unsigned int ram_version; | ||
55 | unsigned char ref_clock; | ||
56 | unsigned char reserved[0x07]; | ||
57 | }; | ||
34 | 58 | ||
35 | static struct usb_device_id ath3k_table[] = { | 59 | static struct usb_device_id ath3k_table[] = { |
36 | /* Atheros AR3011 */ | 60 | /* Atheros AR3011 */ |
@@ -41,13 +65,32 @@ static struct usb_device_id ath3k_table[] = { | |||
41 | 65 | ||
42 | /* Atheros AR9285 Malbec with sflash firmware */ | 66 | /* Atheros AR9285 Malbec with sflash firmware */ |
43 | { USB_DEVICE(0x03F0, 0x311D) }, | 67 | { USB_DEVICE(0x03F0, 0x311D) }, |
68 | |||
69 | /* Atheros AR3012 with sflash firmware*/ | ||
70 | { USB_DEVICE(0x0CF3, 0x3004) }, | ||
71 | |||
72 | /* Atheros AR5BBU12 with sflash firmware */ | ||
73 | { USB_DEVICE(0x0489, 0xE02C) }, | ||
74 | |||
44 | { } /* Terminating entry */ | 75 | { } /* Terminating entry */ |
45 | }; | 76 | }; |
46 | 77 | ||
47 | MODULE_DEVICE_TABLE(usb, ath3k_table); | 78 | MODULE_DEVICE_TABLE(usb, ath3k_table); |
48 | 79 | ||
80 | #define BTUSB_ATH3012 0x80 | ||
81 | /* This table is to load patch and sysconfig files | ||
82 | * for AR3012 */ | ||
83 | static struct usb_device_id ath3k_blist_tbl[] = { | ||
84 | |||
85 | /* Atheros AR3012 with sflash firmware*/ | ||
86 | { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, | ||
87 | |||
88 | { } /* Terminating entry */ | ||
89 | }; | ||
90 | |||
49 | #define USB_REQ_DFU_DNLOAD 1 | 91 | #define USB_REQ_DFU_DNLOAD 1 |
50 | #define BULK_SIZE 4096 | 92 | #define BULK_SIZE 4096 |
93 | #define FW_HDR_SIZE 20 | ||
51 | 94 | ||
52 | static int ath3k_load_firmware(struct usb_device *udev, | 95 | static int ath3k_load_firmware(struct usb_device *udev, |
53 | const struct firmware *firmware) | 96 | const struct firmware *firmware) |
@@ -103,28 +146,265 @@ error: | |||
103 | return err; | 146 | return err; |
104 | } | 147 | } |
105 | 148 | ||
149 | static int ath3k_get_state(struct usb_device *udev, unsigned char *state) | ||
150 | { | ||
151 | int pipe = 0; | ||
152 | |||
153 | pipe = usb_rcvctrlpipe(udev, 0); | ||
154 | return usb_control_msg(udev, pipe, ATH3K_GETSTATE, | ||
155 | USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, | ||
156 | state, 0x01, USB_CTRL_SET_TIMEOUT); | ||
157 | } | ||
158 | |||
159 | static int ath3k_get_version(struct usb_device *udev, | ||
160 | struct ath3k_version *version) | ||
161 | { | ||
162 | int pipe = 0; | ||
163 | |||
164 | pipe = usb_rcvctrlpipe(udev, 0); | ||
165 | return usb_control_msg(udev, pipe, ATH3K_GETVERSION, | ||
166 | USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version, | ||
167 | sizeof(struct ath3k_version), | ||
168 | USB_CTRL_SET_TIMEOUT); | ||
169 | } | ||
170 | |||
171 | static int ath3k_load_fwfile(struct usb_device *udev, | ||
172 | const struct firmware *firmware) | ||
173 | { | ||
174 | u8 *send_buf; | ||
175 | int err, pipe, len, size, count, sent = 0; | ||
176 | int ret; | ||
177 | |||
178 | count = firmware->size; | ||
179 | |||
180 | send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC); | ||
181 | if (!send_buf) { | ||
182 | BT_ERR("Can't allocate memory chunk for firmware"); | ||
183 | return -ENOMEM; | ||
184 | } | ||
185 | |||
186 | size = min_t(uint, count, FW_HDR_SIZE); | ||
187 | memcpy(send_buf, firmware->data, size); | ||
188 | |||
189 | pipe = usb_sndctrlpipe(udev, 0); | ||
190 | ret = usb_control_msg(udev, pipe, ATH3K_DNLOAD, | ||
191 | USB_TYPE_VENDOR, 0, 0, send_buf, | ||
192 | size, USB_CTRL_SET_TIMEOUT); | ||
193 | if (ret < 0) { | ||
194 | BT_ERR("Can't change to loading configuration err"); | ||
195 | kfree(send_buf); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | sent += size; | ||
200 | count -= size; | ||
201 | |||
202 | while (count) { | ||
203 | size = min_t(uint, count, BULK_SIZE); | ||
204 | pipe = usb_sndbulkpipe(udev, 0x02); | ||
205 | |||
206 | memcpy(send_buf, firmware->data + sent, size); | ||
207 | |||
208 | err = usb_bulk_msg(udev, pipe, send_buf, size, | ||
209 | &len, 3000); | ||
210 | if (err || (len != size)) { | ||
211 | BT_ERR("Error in firmware loading err = %d," | ||
212 | "len = %d, size = %d", err, len, size); | ||
213 | kfree(send_buf); | ||
214 | return err; | ||
215 | } | ||
216 | sent += size; | ||
217 | count -= size; | ||
218 | } | ||
219 | |||
220 | kfree(send_buf); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int ath3k_switch_pid(struct usb_device *udev) | ||
225 | { | ||
226 | int pipe = 0; | ||
227 | |||
228 | pipe = usb_sndctrlpipe(udev, 0); | ||
229 | return usb_control_msg(udev, pipe, USB_REG_SWITCH_VID_PID, | ||
230 | USB_TYPE_VENDOR, 0, 0, | ||
231 | NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
232 | } | ||
233 | |||
234 | static int ath3k_set_normal_mode(struct usb_device *udev) | ||
235 | { | ||
236 | unsigned char fw_state; | ||
237 | int pipe = 0, ret; | ||
238 | |||
239 | ret = ath3k_get_state(udev, &fw_state); | ||
240 | if (ret < 0) { | ||
241 | BT_ERR("Can't get state to change to normal mode err"); | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) { | ||
246 | BT_DBG("firmware was already in normal mode"); | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | pipe = usb_sndctrlpipe(udev, 0); | ||
251 | return usb_control_msg(udev, pipe, ATH3K_SET_NORMAL_MODE, | ||
252 | USB_TYPE_VENDOR, 0, 0, | ||
253 | NULL, 0, USB_CTRL_SET_TIMEOUT); | ||
254 | } | ||
255 | |||
256 | static int ath3k_load_patch(struct usb_device *udev) | ||
257 | { | ||
258 | unsigned char fw_state; | ||
259 | char filename[ATH3K_NAME_LEN] = {0}; | ||
260 | const struct firmware *firmware; | ||
261 | struct ath3k_version fw_version, pt_version; | ||
262 | int ret; | ||
263 | |||
264 | ret = ath3k_get_state(udev, &fw_state); | ||
265 | if (ret < 0) { | ||
266 | BT_ERR("Can't get state to change to load ram patch err"); | ||
267 | return ret; | ||
268 | } | ||
269 | |||
270 | if (fw_state & ATH3K_PATCH_UPDATE) { | ||
271 | BT_DBG("Patch was already downloaded"); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | ret = ath3k_get_version(udev, &fw_version); | ||
276 | if (ret < 0) { | ||
277 | BT_ERR("Can't get version to change to load ram patch err"); | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu", | ||
282 | fw_version.rom_version); | ||
283 | |||
284 | ret = request_firmware(&firmware, filename, &udev->dev); | ||
285 | if (ret < 0) { | ||
286 | BT_ERR("Patch file not found %s", filename); | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8); | ||
291 | pt_version.build_version = *(int *) | ||
292 | (firmware->data + firmware->size - 4); | ||
293 | |||
294 | if ((pt_version.rom_version != fw_version.rom_version) || | ||
295 | (pt_version.build_version <= fw_version.build_version)) { | ||
296 | BT_ERR("Patch file version did not match with firmware"); | ||
297 | release_firmware(firmware); | ||
298 | return -EINVAL; | ||
299 | } | ||
300 | |||
301 | ret = ath3k_load_fwfile(udev, firmware); | ||
302 | release_firmware(firmware); | ||
303 | |||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | static int ath3k_load_syscfg(struct usb_device *udev) | ||
308 | { | ||
309 | unsigned char fw_state; | ||
310 | char filename[ATH3K_NAME_LEN] = {0}; | ||
311 | const struct firmware *firmware; | ||
312 | struct ath3k_version fw_version; | ||
313 | int clk_value, ret; | ||
314 | |||
315 | ret = ath3k_get_state(udev, &fw_state); | ||
316 | if (ret < 0) { | ||
317 | BT_ERR("Can't get state to change to load configration err"); | ||
318 | return -EBUSY; | ||
319 | } | ||
320 | |||
321 | ret = ath3k_get_version(udev, &fw_version); | ||
322 | if (ret < 0) { | ||
323 | BT_ERR("Can't get version to change to load ram patch err"); | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | switch (fw_version.ref_clock) { | ||
328 | |||
329 | case ATH3K_XTAL_FREQ_26M: | ||
330 | clk_value = 26; | ||
331 | break; | ||
332 | case ATH3K_XTAL_FREQ_40M: | ||
333 | clk_value = 40; | ||
334 | break; | ||
335 | case ATH3K_XTAL_FREQ_19P2: | ||
336 | clk_value = 19; | ||
337 | break; | ||
338 | default: | ||
339 | clk_value = 0; | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s", | ||
344 | fw_version.rom_version, clk_value, ".dfu"); | ||
345 | |||
346 | ret = request_firmware(&firmware, filename, &udev->dev); | ||
347 | if (ret < 0) { | ||
348 | BT_ERR("Configuration file not found %s", filename); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | ret = ath3k_load_fwfile(udev, firmware); | ||
353 | release_firmware(firmware); | ||
354 | |||
355 | return ret; | ||
356 | } | ||
357 | |||
106 | static int ath3k_probe(struct usb_interface *intf, | 358 | static int ath3k_probe(struct usb_interface *intf, |
107 | const struct usb_device_id *id) | 359 | const struct usb_device_id *id) |
108 | { | 360 | { |
109 | const struct firmware *firmware; | 361 | const struct firmware *firmware; |
110 | struct usb_device *udev = interface_to_usbdev(intf); | 362 | struct usb_device *udev = interface_to_usbdev(intf); |
363 | int ret; | ||
111 | 364 | ||
112 | BT_DBG("intf %p id %p", intf, id); | 365 | BT_DBG("intf %p id %p", intf, id); |
113 | 366 | ||
114 | if (intf->cur_altsetting->desc.bInterfaceNumber != 0) | 367 | if (intf->cur_altsetting->desc.bInterfaceNumber != 0) |
115 | return -ENODEV; | 368 | return -ENODEV; |
116 | 369 | ||
117 | if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) { | 370 | /* match device ID in ath3k blacklist table */ |
118 | return -EIO; | 371 | if (!id->driver_info) { |
372 | const struct usb_device_id *match; | ||
373 | match = usb_match_id(intf, ath3k_blist_tbl); | ||
374 | if (match) | ||
375 | id = match; | ||
119 | } | 376 | } |
120 | 377 | ||
121 | if (ath3k_load_firmware(udev, firmware)) { | 378 | /* load patch and sysconfig files for AR3012 */ |
122 | release_firmware(firmware); | 379 | if (id->driver_info & BTUSB_ATH3012) { |
380 | ret = ath3k_load_patch(udev); | ||
381 | if (ret < 0) { | ||
382 | BT_ERR("Loading patch file failed"); | ||
383 | return ret; | ||
384 | } | ||
385 | ret = ath3k_load_syscfg(udev); | ||
386 | if (ret < 0) { | ||
387 | BT_ERR("Loading sysconfig file failed"); | ||
388 | return ret; | ||
389 | } | ||
390 | ret = ath3k_set_normal_mode(udev); | ||
391 | if (ret < 0) { | ||
392 | BT_ERR("Set normal mode failed"); | ||
393 | return ret; | ||
394 | } | ||
395 | ath3k_switch_pid(udev); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) { | ||
400 | BT_ERR("Error loading firmware"); | ||
123 | return -EIO; | 401 | return -EIO; |
124 | } | 402 | } |
403 | |||
404 | ret = ath3k_load_firmware(udev, firmware); | ||
125 | release_firmware(firmware); | 405 | release_firmware(firmware); |
126 | 406 | ||
127 | return 0; | 407 | return ret; |
128 | } | 408 | } |
129 | 409 | ||
130 | static void ath3k_disconnect(struct usb_interface *intf) | 410 | static void ath3k_disconnect(struct usb_interface *intf) |