| Index: chromeos/compat-wireless/drivers/bluetooth/btusb.c
|
| diff --git a/chromeos/compat-wireless/drivers/bluetooth/btusb.c b/chromeos/compat-wireless/drivers/bluetooth/btusb.c
|
| index d22ce3cc611e7bb60f0377ff344fa41fb7bde2db..13e0fb845e1069312bd66e7206a1a259a29225d7 100644
|
| --- a/chromeos/compat-wireless/drivers/bluetooth/btusb.c
|
| +++ b/chromeos/compat-wireless/drivers/bluetooth/btusb.c
|
| @@ -34,6 +34,7 @@
|
|
|
| #include <net/bluetooth/bluetooth.h>
|
| #include <net/bluetooth/hci_core.h>
|
| +#include "fwload.h"
|
|
|
| #define VERSION "0.6"
|
|
|
| @@ -55,6 +56,26 @@ static struct usb_driver btusb_driver;
|
| #define BTUSB_BROKEN_ISOC 0x20
|
| #define BTUSB_WRONG_SCO_MTU 0x40
|
|
|
| +static struct usb_device_id ath_table[] = {
|
| + /* Atheros AR3011 */
|
| + { USB_DEVICE(0x0CF3, 0x3002) },
|
| + { USB_DEVICE(0x13D3, 0x3304) },
|
| + { } /* Terminating entry */
|
| +};
|
| +
|
| +/* Add firmware file, load and unload function
|
| + * to download the firmware to target RAM
|
| + */
|
| +static struct fw_cb_config btusb_fwcbs[] = {
|
| + {
|
| + .fwfile = "ath3k-1.fw",
|
| + .usb_id_table = ath_table,
|
| + .fwload = ath_fw_load,
|
| + .fwunload = ath_fw_unload
|
| + },
|
| + {}
|
| +};
|
| +
|
| static struct usb_device_id btusb_table[] = {
|
| /* Generic Bluetooth USB device */
|
| { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
| @@ -863,6 +884,7 @@ static int btusb_probe(struct usb_interface *intf,
|
| struct btusb_data *data;
|
| struct hci_dev *hdev;
|
| int i, err;
|
| + const struct usb_device_id *match;
|
|
|
| BT_DBG("intf %p id %p", intf, id);
|
|
|
| @@ -922,6 +944,19 @@ static int btusb_probe(struct usb_interface *intf,
|
| data->udev = interface_to_usbdev(intf);
|
| data->intf = intf;
|
|
|
| + for (i = 0; btusb_fwcbs[i].fwfile; i++) {
|
| + match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
|
| + if (match) {
|
| + if (btusb_fwcbs[i].fwload) {
|
| + btusb_fwcbs[i].data =
|
| + btusb_fwcbs[i].fwload(intf,
|
| + btusb_fwcbs[i].fwfile,
|
| + &btusb_fwcbs[i].bsuspend);
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +
|
| spin_lock_init(&data->lock);
|
|
|
| INIT_WORK(&data->work, btusb_work);
|
| @@ -1030,12 +1065,26 @@ static void btusb_disconnect(struct usb_interface *intf)
|
| {
|
| struct btusb_data *data = usb_get_intfdata(intf);
|
| struct hci_dev *hdev;
|
| + const struct usb_device_id *match;
|
| + int i;
|
|
|
| BT_DBG("intf %p", intf);
|
|
|
| if (!data)
|
| return;
|
|
|
| + for (i = 0; btusb_fwcbs[i].fwfile; i++) {
|
| + match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
|
| + if (match) {
|
| + if (btusb_fwcbs[i].fwunload) {
|
| + btusb_fwcbs[i].fwunload(btusb_fwcbs[i].data,
|
| + btusb_fwcbs[i].bsuspend);
|
| + btusb_fwcbs[i].data = NULL;
|
| + }
|
| + break;
|
| + }
|
| + }
|
| +
|
| hdev = data->hdev;
|
|
|
| __hci_dev_hold(hdev);
|
| @@ -1061,12 +1110,22 @@ static void btusb_disconnect(struct usb_interface *intf)
|
| static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
|
| {
|
| struct btusb_data *data = usb_get_intfdata(intf);
|
| + const struct usb_device_id *match;
|
| + int i;
|
|
|
| BT_DBG("intf %p", intf);
|
|
|
| if (data->suspend_count++)
|
| return 0;
|
|
|
| + for (i = 0; btusb_fwcbs[i].fwfile; i++) {
|
| + match = usb_match_id(intf, btusb_fwcbs[i].usb_id_table);
|
| + if (match) {
|
| + btusb_fwcbs[i].bsuspend = 1;
|
| + break;
|
| + }
|
| + }
|
| +
|
| spin_lock_irq(&data->txlock);
|
| if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
|
| set_bit(BTUSB_SUSPENDING, &data->flags);
|
| @@ -1179,6 +1238,14 @@ static int __init btusb_init(void)
|
|
|
| static void __exit btusb_exit(void)
|
| {
|
| + int i;
|
| + for (i = 0; btusb_fwcbs[i].fwfile; i++) {
|
| + if (btusb_fwcbs[i].fwunload && btusb_fwcbs[i].data) {
|
| + btusb_fwcbs[i].fwunload(btusb_fwcbs[i].data,
|
| + btusb_fwcbs[i].bsuspend);
|
| + btusb_fwcbs[i].data = NULL;
|
| + }
|
| + }
|
| usb_deregister(&btusb_driver);
|
| }
|
|
|
|
|