Skip to content

Commit d9f51b5

Browse files
Bala ShanmugamGustavo F. Padovan
authored andcommitted
Bluetooth: Add firmware support for Atheros 3012
Blacklisted AR3012 PID in btusb and added the same in ath3k to load patch and sysconfig files. Signed-off-by: Bala Shanmugam <sbalashanmugam@atheros.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
1 parent e3fb592 commit d9f51b5

File tree

2 files changed

+282
-0
lines changed

2 files changed

+282
-0
lines changed

drivers/bluetooth/ath3k.c

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@
3131

3232
#define VERSION "1.0"
3333

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+
};
3458

3559
static struct usb_device_id ath3k_table[] = {
3660
/* Atheros AR3011 */
@@ -41,13 +65,29 @@ static struct usb_device_id ath3k_table[] = {
4165

4266
/* Atheros AR9285 Malbec with sflash firmware */
4367
{ USB_DEVICE(0x03F0, 0x311D) },
68+
69+
/* Atheros AR3012 with sflash firmware*/
70+
{ USB_DEVICE(0x0CF3, 0x3004) },
71+
4472
{ } /* Terminating entry */
4573
};
4674

4775
MODULE_DEVICE_TABLE(usb, ath3k_table);
4876

77+
#define BTUSB_ATH3012 0x80
78+
/* This table is to load patch and sysconfig files
79+
* for AR3012 */
80+
static struct usb_device_id ath3k_blist_tbl[] = {
81+
82+
/* Atheros AR3012 with sflash firmware*/
83+
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
84+
85+
{ } /* Terminating entry */
86+
};
87+
4988
#define USB_REQ_DFU_DNLOAD 1
5089
#define BULK_SIZE 4096
90+
#define FW_HDR_SIZE 20
5191

5292
static int ath3k_load_firmware(struct usb_device *udev,
5393
const struct firmware *firmware)
@@ -103,6 +143,215 @@ static int ath3k_load_firmware(struct usb_device *udev,
103143
return err;
104144
}
105145

146+
static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
147+
{
148+
int pipe = 0;
149+
150+
pipe = usb_rcvctrlpipe(udev, 0);
151+
return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
152+
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
153+
state, 0x01, USB_CTRL_SET_TIMEOUT);
154+
}
155+
156+
static int ath3k_get_version(struct usb_device *udev,
157+
struct ath3k_version *version)
158+
{
159+
int pipe = 0;
160+
161+
pipe = usb_rcvctrlpipe(udev, 0);
162+
return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
163+
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
164+
sizeof(struct ath3k_version),
165+
USB_CTRL_SET_TIMEOUT);
166+
}
167+
168+
static int ath3k_load_fwfile(struct usb_device *udev,
169+
const struct firmware *firmware)
170+
{
171+
u8 *send_buf;
172+
int err, pipe, len, size, count, sent = 0;
173+
int ret;
174+
175+
count = firmware->size;
176+
177+
send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC);
178+
if (!send_buf) {
179+
BT_ERR("Can't allocate memory chunk for firmware");
180+
return -ENOMEM;
181+
}
182+
183+
size = min_t(uint, count, FW_HDR_SIZE);
184+
memcpy(send_buf, firmware->data, size);
185+
186+
pipe = usb_sndctrlpipe(udev, 0);
187+
ret = usb_control_msg(udev, pipe, ATH3K_DNLOAD,
188+
USB_TYPE_VENDOR, 0, 0, send_buf,
189+
size, USB_CTRL_SET_TIMEOUT);
190+
if (ret < 0) {
191+
BT_ERR("Can't change to loading configuration err");
192+
kfree(send_buf);
193+
return ret;
194+
}
195+
196+
sent += size;
197+
count -= size;
198+
199+
while (count) {
200+
size = min_t(uint, count, BULK_SIZE);
201+
pipe = usb_sndbulkpipe(udev, 0x02);
202+
203+
memcpy(send_buf, firmware->data + sent, size);
204+
205+
err = usb_bulk_msg(udev, pipe, send_buf, size,
206+
&len, 3000);
207+
if (err || (len != size)) {
208+
BT_ERR("Error in firmware loading err = %d,"
209+
"len = %d, size = %d", err, len, size);
210+
kfree(send_buf);
211+
return err;
212+
}
213+
sent += size;
214+
count -= size;
215+
}
216+
217+
kfree(send_buf);
218+
return 0;
219+
}
220+
221+
static int ath3k_switch_pid(struct usb_device *udev)
222+
{
223+
int pipe = 0;
224+
225+
pipe = usb_sndctrlpipe(udev, 0);
226+
return usb_control_msg(udev, pipe, USB_REG_SWITCH_VID_PID,
227+
USB_TYPE_VENDOR, 0, 0,
228+
NULL, 0, USB_CTRL_SET_TIMEOUT);
229+
}
230+
231+
static int ath3k_set_normal_mode(struct usb_device *udev)
232+
{
233+
unsigned char fw_state;
234+
int pipe = 0, ret;
235+
236+
ret = ath3k_get_state(udev, &fw_state);
237+
if (ret < 0) {
238+
BT_ERR("Can't get state to change to normal mode err");
239+
return ret;
240+
}
241+
242+
if ((fw_state & ATH3K_MODE_MASK) == ATH3K_NORMAL_MODE) {
243+
BT_DBG("firmware was already in normal mode");
244+
return 0;
245+
}
246+
247+
pipe = usb_sndctrlpipe(udev, 0);
248+
return usb_control_msg(udev, pipe, ATH3K_SET_NORMAL_MODE,
249+
USB_TYPE_VENDOR, 0, 0,
250+
NULL, 0, USB_CTRL_SET_TIMEOUT);
251+
}
252+
253+
static int ath3k_load_patch(struct usb_device *udev)
254+
{
255+
unsigned char fw_state;
256+
char filename[ATH3K_NAME_LEN] = {0};
257+
const struct firmware *firmware;
258+
struct ath3k_version fw_version, pt_version;
259+
int ret;
260+
261+
ret = ath3k_get_state(udev, &fw_state);
262+
if (ret < 0) {
263+
BT_ERR("Can't get state to change to load ram patch err");
264+
return ret;
265+
}
266+
267+
if (fw_state & ATH3K_PATCH_UPDATE) {
268+
BT_DBG("Patch was already downloaded");
269+
return 0;
270+
}
271+
272+
ret = ath3k_get_version(udev, &fw_version);
273+
if (ret < 0) {
274+
BT_ERR("Can't get version to change to load ram patch err");
275+
return ret;
276+
}
277+
278+
snprintf(filename, ATH3K_NAME_LEN, "ar3k/AthrBT_0x%08x.dfu",
279+
fw_version.rom_version);
280+
281+
ret = request_firmware(&firmware, filename, &udev->dev);
282+
if (ret < 0) {
283+
BT_ERR("Patch file not found %s", filename);
284+
return ret;
285+
}
286+
287+
pt_version.rom_version = *(int *)(firmware->data + firmware->size - 8);
288+
pt_version.build_version = *(int *)
289+
(firmware->data + firmware->size - 4);
290+
291+
if ((pt_version.rom_version != fw_version.rom_version) ||
292+
(pt_version.build_version <= fw_version.build_version)) {
293+
BT_ERR("Patch file version did not match with firmware");
294+
release_firmware(firmware);
295+
return -EINVAL;
296+
}
297+
298+
ret = ath3k_load_fwfile(udev, firmware);
299+
release_firmware(firmware);
300+
301+
return ret;
302+
}
303+
304+
static int ath3k_load_syscfg(struct usb_device *udev)
305+
{
306+
unsigned char fw_state;
307+
char filename[ATH3K_NAME_LEN] = {0};
308+
const struct firmware *firmware;
309+
struct ath3k_version fw_version;
310+
int clk_value, ret;
311+
312+
ret = ath3k_get_state(udev, &fw_state);
313+
if (ret < 0) {
314+
BT_ERR("Can't get state to change to load configration err");
315+
return -EBUSY;
316+
}
317+
318+
ret = ath3k_get_version(udev, &fw_version);
319+
if (ret < 0) {
320+
BT_ERR("Can't get version to change to load ram patch err");
321+
return ret;
322+
}
323+
324+
switch (fw_version.ref_clock) {
325+
326+
case ATH3K_XTAL_FREQ_26M:
327+
clk_value = 26;
328+
break;
329+
case ATH3K_XTAL_FREQ_40M:
330+
clk_value = 40;
331+
break;
332+
case ATH3K_XTAL_FREQ_19P2:
333+
clk_value = 19;
334+
break;
335+
default:
336+
clk_value = 0;
337+
break;
338+
}
339+
340+
snprintf(filename, ATH3K_NAME_LEN, "ar3k/ramps_0x%08x_%d%s",
341+
fw_version.rom_version, clk_value, ".dfu");
342+
343+
ret = request_firmware(&firmware, filename, &udev->dev);
344+
if (ret < 0) {
345+
BT_ERR("Configuration file not found %s", filename);
346+
return ret;
347+
}
348+
349+
ret = ath3k_load_fwfile(udev, firmware);
350+
release_firmware(firmware);
351+
352+
return ret;
353+
}
354+
106355
static int ath3k_probe(struct usb_interface *intf,
107356
const struct usb_device_id *id)
108357
{
@@ -115,7 +364,37 @@ static int ath3k_probe(struct usb_interface *intf,
115364
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
116365
return -ENODEV;
117366

367+
/* match device ID in ath3k blacklist table */
368+
if (!id->driver_info) {
369+
const struct usb_device_id *match;
370+
match = usb_match_id(intf, ath3k_blist_tbl);
371+
if (match)
372+
id = match;
373+
}
374+
375+
/* load patch and sysconfig files for AR3012 */
376+
if (id->driver_info & BTUSB_ATH3012) {
377+
ret = ath3k_load_patch(udev);
378+
if (ret < 0) {
379+
BT_ERR("Loading patch file failed");
380+
return ret;
381+
}
382+
ret = ath3k_load_syscfg(udev);
383+
if (ret < 0) {
384+
BT_ERR("Loading sysconfig file failed");
385+
return ret;
386+
}
387+
ret = ath3k_set_normal_mode(udev);
388+
if (ret < 0) {
389+
BT_ERR("Set normal mode failed");
390+
return ret;
391+
}
392+
ath3k_switch_pid(udev);
393+
return 0;
394+
}
395+
118396
if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
397+
BT_ERR("Error loading firmware");
119398
return -EIO;
120399
}
121400

drivers/bluetooth/btusb.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ static struct usb_device_id blacklist_table[] = {
105105
/* Atheros AR9285 Malbec with sflash firmware */
106106
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
107107

108+
/* Atheros 3012 with sflash firmware */
109+
{ USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE },
110+
108111
/* Broadcom BCM2035 */
109112
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
110113
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },

0 commit comments

Comments
 (0)