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