diff options
Diffstat (limited to 'drivers/bluetooth/btusb.c')
-rw-r--r-- | drivers/bluetooth/btusb.c | 222 |
1 files changed, 192 insertions, 30 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a1c80b0c766..292c38e8aa1 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -30,9 +30,6 @@ #define VERSION "0.6" -static bool ignore_dga; -static bool ignore_csr; -static bool ignore_sniffer; static bool disable_scofix; static bool force_scofix; @@ -49,7 +46,9 @@ static struct usb_driver btusb_driver; #define BTUSB_WRONG_SCO_MTU 0x40 #define BTUSB_ATH3012 0x80 #define BTUSB_INTEL 0x100 -#define BTUSB_BCM_PATCHRAM 0x200 +#define BTUSB_INTEL_BOOT 0x200 +#define BTUSB_BCM_PATCHRAM 0x400 +#define BTUSB_MARVELL 0x800 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -115,12 +114,19 @@ static const struct usb_device_id btusb_table[] = { { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01), .driver_info = BTUSB_BCM_PATCHRAM }, + /* ASUSTek Computer - Broadcom based */ + { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01) }, + /* Belkin F8065bf - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, /* IMC Networks - Broadcom based */ { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, + /* Intel Bluetooth USB Bootloader (RAM module) */ + { USB_DEVICE(0x8087, 0x0a5a), + .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC }, + { } /* Terminating entry */ }; @@ -162,7 +168,6 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, @@ -176,6 +181,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, @@ -229,15 +235,21 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE }, /* CSR BlueCore Bluetooth Sniffer */ - { USB_DEVICE(0x0a12, 0x0002), .driver_info = BTUSB_SNIFFER }, + { USB_DEVICE(0x0a12, 0x0002), + .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC }, /* Frontline ComProbe Bluetooth Sniffer */ - { USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER }, + { USB_DEVICE(0x16d3, 0x0002), + .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC }, /* Intel Bluetooth device */ { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL }, + /* Marvell device */ + { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL }, + { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, + { } /* Terminating entry */ }; @@ -1183,6 +1195,51 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev, return 0; } +#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) + +static int btusb_check_bdaddr_intel(struct hci_dev *hdev) +{ + struct sk_buff *skb; + struct hci_rp_read_bd_addr *rp; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s reading Intel device address failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*rp)) { + BT_ERR("%s Intel device address length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + rp = (struct hci_rp_read_bd_addr *) skb->data; + if (rp->status) { + BT_ERR("%s Intel device address result failed (%02x)", + hdev->name, rp->status); + kfree_skb(skb); + return -bt_to_errno(rp->status); + } + + /* For some Intel based controllers, the default Bluetooth device + * address 00:03:19:9E:8B:00 can be found. These controllers are + * fully operational, but have the danger of duplicate addresses + * and that in turn can cause problems with Bluetooth operation. + */ + if (!bacmp(&rp->bdaddr, BDADDR_INTEL)) { + BT_ERR("%s found Intel default device address (%pMR)", + hdev->name, &rp->bdaddr); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + + kfree_skb(skb); + + return 0; +} + static int btusb_setup_intel(struct hci_dev *hdev) { struct sk_buff *skb; @@ -1255,6 +1312,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) BT_INFO("%s: Intel device is already patched. patch num: %02x", hdev->name, ver->fw_patch_num); kfree_skb(skb); + btusb_check_bdaddr_intel(hdev); return 0; } @@ -1267,6 +1325,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) fw = btusb_setup_intel_get_fw(hdev, ver); if (!fw) { kfree_skb(skb); + btusb_check_bdaddr_intel(hdev); return 0; } fw_ptr = fw->data; @@ -1346,6 +1405,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) BT_INFO("%s: Intel Bluetooth firmware patch completed and activated", hdev->name); + btusb_check_bdaddr_intel(hdev); return 0; exit_mfg_disable: @@ -1360,6 +1420,8 @@ exit_mfg_disable: kfree_skb(skb); BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name); + + btusb_check_bdaddr_intel(hdev); return 0; exit_mfg_deactivate: @@ -1380,9 +1442,52 @@ exit_mfg_deactivate: BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated", hdev->name); + btusb_check_bdaddr_intel(hdev); + return 0; +} + +static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + long ret; + + skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: changing Intel device address failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + return 0; } +static int btusb_set_bdaddr_marvell(struct hci_dev *hdev, + const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + u8 buf[8]; + long ret; + + buf[0] = 0xfe; + buf[1] = sizeof(bdaddr_t); + memcpy(buf + 2, bdaddr, sizeof(bdaddr_t)); + + skb = __hci_cmd_sync(hdev, 0xfc22, sizeof(buf), buf, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: changing Marvell device address failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + + return 0; +} + +#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) + static int btusb_setup_bcm_patchram(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -1396,6 +1501,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) u16 opcode; struct sk_buff *skb; struct hci_rp_read_local_version *ver; + struct hci_rp_read_bd_addr *bda; long ret; snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd", @@ -1405,8 +1511,7 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) ret = request_firmware(&fw, fw_name, &hdev->dev); if (ret < 0) { - BT_INFO("%s: BCM: patch %s not found", hdev->name, - fw_name); + BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); return 0; } @@ -1525,12 +1630,67 @@ reset_fw: ver->lmp_ver, ver->lmp_subver); kfree_skb(skb); + /* Read BD Address */ + skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)", + hdev->name, ret); + goto done; + } + + if (skb->len != sizeof(*bda)) { + BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch", + hdev->name); + kfree_skb(skb); + ret = -EIO; + goto done; + } + + bda = (struct hci_rp_read_bd_addr *) skb->data; + if (bda->status) { + BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)", + hdev->name, bda->status); + kfree_skb(skb); + ret = -bt_to_errno(bda->status); + goto done; + } + + /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller + * with no configured address. + */ + if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) { + BT_INFO("%s: BCM: using default device address (%pMR)", + hdev->name, &bda->bdaddr); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + + kfree_skb(skb); + done: release_firmware(fw); return ret; } +static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + long ret; + + skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + ret = PTR_ERR(skb); + BT_ERR("%s: BCM: Change address command failed (%ld)", + hdev->name, ret); + return ret; + } + kfree_skb(skb); + + return 0; +} + static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1555,15 +1715,6 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info == BTUSB_IGNORE) return -ENODEV; - if (ignore_dga && id->driver_info & BTUSB_DIGIANSWER) - return -ENODEV; - - if (ignore_csr && id->driver_info & BTUSB_CSR) - return -ENODEV; - - if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER) - return -ENODEV; - if (id->driver_info & BTUSB_ATH3012) { struct usb_device *udev = interface_to_usbdev(intf); @@ -1636,11 +1787,21 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; - if (id->driver_info & BTUSB_BCM_PATCHRAM) + if (id->driver_info & BTUSB_BCM_PATCHRAM) { hdev->setup = btusb_setup_bcm_patchram; + hdev->set_bdaddr = btusb_set_bdaddr_bcm; + } - if (id->driver_info & BTUSB_INTEL) + if (id->driver_info & BTUSB_INTEL) { hdev->setup = btusb_setup_intel; + hdev->set_bdaddr = btusb_set_bdaddr_intel; + } + + if (id->driver_info & BTUSB_MARVELL) + hdev->set_bdaddr = btusb_set_bdaddr_marvell; + + if (id->driver_info & BTUSB_INTEL_BOOT) + set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); @@ -1680,8 +1841,18 @@ static int btusb_probe(struct usb_interface *intf, /* New sniffer firmware has crippled HCI interface */ if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); + } - data->isoc = NULL; + if (id->driver_info & BTUSB_INTEL_BOOT) { + /* A bug in the bootloader causes that interrupt interface is + * only enabled after receiving SetInterface(0, AltSetting=0). + */ + err = usb_set_interface(data->udev, 0, 0); + if (err < 0) { + BT_ERR("failed to set interface 0, alt 0 %d", err); + hci_free_dev(hdev); + return err; + } } if (data->isoc) { @@ -1846,15 +2017,6 @@ static struct usb_driver btusb_driver = { module_usb_driver(btusb_driver); -module_param(ignore_dga, bool, 0644); -MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001"); - -module_param(ignore_csr, bool, 0644); -MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); - -module_param(ignore_sniffer, bool, 0644); -MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002"); - module_param(disable_scofix, bool, 0644); MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size"); |