diff options
Diffstat (limited to 'drivers/bluetooth/btusb.c')
-rw-r--r-- | drivers/bluetooth/btusb.c | 53 |
1 files changed, 51 insertions, 2 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3980fd18f6ea..baeaaed299e4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -150,6 +150,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 }, @@ -164,6 +165,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, @@ -224,6 +226,7 @@ static const struct usb_device_id blacklist_table[] = { /* Intel Bluetooth device */ { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, + { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, { } /* Terminating entry */ }; @@ -962,6 +965,45 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev) return 0; } +static int btusb_setup_csr(struct hci_dev *hdev) +{ + struct hci_rp_read_local_version *rp; + struct sk_buff *skb; + int ret; + + BT_DBG("%s", hdev->name); + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb)); + return -PTR_ERR(skb); + } + + rp = (struct hci_rp_read_local_version *) skb->data; + + if (!rp->status) { + if (le16_to_cpu(rp->manufacturer) != 10) { + /* Clear the reset quirk since this is not an actual + * early Bluetooth 1.1 device from CSR. + */ + clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + + /* These fake CSR controllers have all a broken + * stored link key handling and so just disable it. + */ + set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, + &hdev->quirks); + } + } + + ret = -bt_to_errno(rp->status); + + kfree_skb(skb); + + return ret; +} + struct intel_version { u8 status; u8 hw_platform; @@ -1436,8 +1478,10 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; - if (id->driver_info & BTUSB_INTEL) + if (id->driver_info & BTUSB_INTEL) { + usb_enable_autosuspend(data->udev); hdev->setup = btusb_setup_intel; + } /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); @@ -1460,10 +1504,15 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_CSR) { struct usb_device *udev = data->udev; + u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice); /* Old firmware would otherwise execute USB reset */ - if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) + if (bcdDevice < 0x117) set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + + /* Fake CSR devices with broken commands */ + if (bcdDevice <= 0x100) + hdev->setup = btusb_setup_csr; } if (id->driver_info & BTUSB_SNIFFER) { |