Bluetooth: Send HCI Reset command by default on device initialization
Marcel Holtmann [Sun, 30 Nov 2008 11:17:26 +0000 (12:17 +0100)]
The Bluetooth subsystem was not using the HCI Reset command when doing
device initialization. The Bluetooth 1.0b specification was ambiguous
on how the device firmware was suppose to handle it. Almost every device
was triggering a transport reset at the same time. In case of USB this
ended up in disconnects from the bus.

All modern Bluetooth dongles handle this perfectly fine and a lot of
them actually require that HCI Reset is sent. If not then they are
either stuck in their HID Proxy mode or their internal structures for
inquiry and paging are not correctly setup.

To handle old and new devices smoothly the Bluetooth subsystem contains
a quirk to force the HCI Reset on initialization. However maintaining
such a quirk becomes more and more complicated. This patch turns the
logic around and lets the old devices disable the HCI Reset command.

The only device where the HCI_QUIRK_NO_RESET is still needed are the
original Digianswer devices and dongles with an early CSR firmware.

CSR reported that they fixed this for version 12 firmware. The last
official release of version 11 firmware is build ID 115. The first
version 12 candidate was build ID 117.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

drivers/bluetooth/bpa10x.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_ldisc.c
include/net/bluetooth/hci.h
net/bluetooth/af_bluetooth.c
net/bluetooth/hci_core.c

index b936d8c..4f0a572 100644 (file)
@@ -489,6 +489,8 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
 
        hdev->owner = THIS_MODULE;
 
+       set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+
        err = hci_register_dev(hdev);
        if (err < 0) {
                hci_free_dev(hdev);
index 0cd4a55..5d97bed 100644 (file)
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "0.3"
+#define VERSION "0.4"
 
 static int ignore_dga;
 static int ignore_csr;
 static int ignore_sniffer;
 static int disable_scofix;
 static int force_scofix;
-static int reset;
+
+static int reset = 1;
 
 static struct usb_driver btusb_driver;
 
 #define BTUSB_IGNORE           0x01
-#define BTUSB_RESET            0x02
-#define BTUSB_DIGIANSWER       0x04
-#define BTUSB_CSR              0x08
-#define BTUSB_SNIFFER          0x10
-#define BTUSB_BCM92035         0x20
-#define BTUSB_BROKEN_ISOC      0x40
-#define BTUSB_WRONG_SCO_MTU    0x80
+#define BTUSB_DIGIANSWER       0x02
+#define BTUSB_CSR              0x04
+#define BTUSB_SNIFFER          0x08
+#define BTUSB_BCM92035         0x10
+#define BTUSB_BROKEN_ISOC      0x20
+#define BTUSB_WRONG_SCO_MTU    0x40
 
 static struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth USB device */
@@ -79,7 +79,7 @@ static struct usb_device_id btusb_table[] = {
        { USB_DEVICE(0x0bdb, 0x1002) },
 
        /* Canyon CN-BTU1 with HID interfaces */
-       { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_RESET },
+       { USB_DEVICE(0x0c10, 0x0000) },
 
        { }     /* Terminating entry */
 };
@@ -94,52 +94,36 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
 
        /* Broadcom BCM2035 */
-       { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
 
        /* Broadcom BCM2045 */
-       { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-       { USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-       /* Broadcom BCM2046 */
-       { USB_DEVICE(0x0a5c, 0x2146), .driver_info = BTUSB_RESET },
-       { USB_DEVICE(0x0a5c, 0x2151), .driver_info = BTUSB_RESET },
-
-       /* Apple MacBook Pro with Broadcom chip */
-       { USB_DEVICE(0x05ac, 0x820f), .driver_info = BTUSB_RESET },
+       { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* IBM/Lenovo ThinkPad with Broadcom chip */
-       { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-       { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-       /* Targus ACB10US */
-       { USB_DEVICE(0x0a5c, 0x2100), .driver_info = BTUSB_RESET },
-       { USB_DEVICE(0x0a5c, 0x2154), .driver_info = BTUSB_RESET },
-
-       /* ANYCOM Bluetooth USB-200 and USB-250 */
-       { USB_DEVICE(0x0a5c, 0x2111), .driver_info = BTUSB_RESET },
+       { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* HP laptop with Broadcom chip */
-       { USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* Dell laptop with Broadcom chip */
-       { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* Dell Wireless 370 */
-       { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* Dell Wireless 410 */
-       { USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-       /* Microsoft Wireless Transceiver for Bluetooth 2.0 */
-       { USB_DEVICE(0x045e, 0x009c), .driver_info = BTUSB_RESET },
+       { USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* Kensington Bluetooth USB adapter */
-       { USB_DEVICE(0x047d, 0x105d), .driver_info = BTUSB_RESET },
-       { USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_WRONG_SCO_MTU },
 
-       /* ISSC Bluetooth Adapter v3.1 */
-       { USB_DEVICE(0x1131, 0x1001), .driver_info = BTUSB_RESET },
+       /* Belkin F8T012 and F8T013 devices */
+       { USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_WRONG_SCO_MTU },
+       { USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_WRONG_SCO_MTU },
 
        /* RTX Telecom based adapters with buggy SCO support */
        { USB_DEVICE(0x0400, 0x0807), .driver_info = BTUSB_BROKEN_ISOC },
@@ -148,13 +132,6 @@ static struct usb_device_id blacklist_table[] = {
        /* CONWISE Technology based adapters with buggy SCO support */
        { USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
 
-       /* Belkin F8T012 and F8T013 devices */
-       { USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-       { USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU },
-
-       /* Belkin F8T016 device */
-       { USB_DEVICE(0x050d, 0x016a), .driver_info = BTUSB_RESET },
-
        /* Digianswer devices */
        { USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
        { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
@@ -197,6 +174,8 @@ struct btusb_data {
        struct usb_endpoint_descriptor *isoc_tx_ep;
        struct usb_endpoint_descriptor *isoc_rx_ep;
 
+       __u8 cmdreq_type;
+
        int isoc_altsetting;
        int suspend_count;
 };
@@ -590,7 +569,7 @@ static int btusb_send_frame(struct sk_buff *skb)
                        return -ENOMEM;
                }
 
-               dr->bRequestType = USB_TYPE_CLASS;
+               dr->bRequestType = data->cmdreq_type;
                dr->bRequest     = 0;
                dr->wIndex       = 0;
                dr->wValue       = 0;
@@ -828,6 +807,8 @@ static int btusb_probe(struct usb_interface *intf,
                return -ENODEV;
        }
 
+       data->cmdreq_type = USB_TYPE_CLASS;
+
        data->udev = interface_to_usbdev(intf);
        data->intf = intf;
 
@@ -862,11 +843,11 @@ static int btusb_probe(struct usb_interface *intf,
 
        hdev->owner = THIS_MODULE;
 
-       /* interface numbers are hardcoded in the spec */
+       /* Interface numbers are hardcoded in the specification */
        data->isoc = usb_ifnum_to_if(data->udev, 1);
 
-       if (reset || id->driver_info & BTUSB_RESET)
-               set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+       if (!reset)
+               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
        if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
                if (!disable_scofix)
@@ -876,9 +857,23 @@ static int btusb_probe(struct usb_interface *intf,
        if (id->driver_info & BTUSB_BROKEN_ISOC)
                data->isoc = NULL;
 
+       if (id->driver_info & BTUSB_DIGIANSWER) {
+               data->cmdreq_type = USB_TYPE_VENDOR;
+               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+       }
+
+       if (id->driver_info & BTUSB_CSR) {
+               struct usb_device *udev = data->udev;
+
+               /* Old firmware would otherwise execute USB reset */
+               if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
+                       set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+       }
+
        if (id->driver_info & BTUSB_SNIFFER) {
                struct usb_device *udev = data->udev;
 
+               /* New sniffer firmware has crippled HCI interface */
                if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
                        set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
index 4426bb5..cb46bf5 100644 (file)
@@ -399,8 +399,8 @@ static int hci_uart_register_dev(struct hci_uart *hu)
 
        hdev->owner = THIS_MODULE;
 
-       if (reset)
-               set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+       if (!reset)
+               set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
 
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
index 3cc2949..3645139 100644 (file)
@@ -54,7 +54,7 @@
 
 /* HCI device quirks */
 enum {
-       HCI_QUIRK_RESET_ON_INIT,
+       HCI_QUIRK_NO_RESET,
        HCI_QUIRK_RAW_DEVICE,
        HCI_QUIRK_FIXUP_BUFFER_SIZE
 };
index 41f07f5..f6f216e 100644 (file)
@@ -46,7 +46,7 @@
 #define BT_DBG(D...)
 #endif
 
-#define VERSION "2.13"
+#define VERSION "2.14"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO   8
index 7bb0f1c..fa7c537 100644 (file)
@@ -205,7 +205,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
        /* Mandatory initialization */
 
        /* Reset */
-       if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks))
+       if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks))
                        hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
 
        /* Read Local Supported Features */