]> git.hungrycats.org Git - linux/commitdiff
[Bluetooth] Send HCI_Reset for some Broadcom dongles
authorMarcel Holtmann <marcel@holtmann.org>
Fri, 5 Mar 2004 18:27:52 +0000 (19:27 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 5 Mar 2004 18:27:52 +0000 (19:27 +0100)
This patch introduces a quirk flag for sending the HCI_Reset command. In
general the HCI_Reset is not needed, but some Broadcom dongles uses this
reset command to switch from HID to HCI mode. And it is not safe to send
the HCI_Reset to every Bluetooth device, because the CSR firmware prior
HCI 12.x will reset the host transport and this is wrong according to the
Bluetooth specification.

drivers/bluetooth/hci_usb.c
drivers/bluetooth/hci_usb.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c

index c0feb4fd222325a3efe8ecc7b128e8226590e626..e288e65947d96f1fd132e537911d820babd519ef 100644 (file)
@@ -31,7 +31,7 @@
  *
  * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $    
  */
-#define VERSION "2.4"
+#define VERSION "2.5"
 
 #include <linux/config.h>
 #include <linux/module.h>
 static struct usb_driver hci_usb_driver; 
 
 static struct usb_device_id bluetooth_ids[] = {
-       /* Broadcom BCM2033 without firmware */
-       { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
-
-       /* Digianswer device */
-       { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
-
        /* Generic Bluetooth USB device */
        { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
 
@@ -93,6 +87,19 @@ static struct usb_device_id bluetooth_ids[] = {
 
 MODULE_DEVICE_TABLE (usb, bluetooth_ids);
 
+static struct usb_device_id blacklist_ids[] = {
+       /* Broadcom BCM2033 without firmware */
+       { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
+
+       /* Broadcom BCM2035 */
+       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET },
+
+       /* Digianswer device */
+       { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
+
+       { }     /* Terminating entry */
+};
+
 struct _urb *_urb_alloc(int isoc, int gfp)
 {
        struct _urb *_urb = kmalloc(sizeof(struct _urb) +
@@ -644,7 +651,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
 #endif
                        }
                        BT_DBG("new packet len %d", len);
-                               
+
                        skb = bt_skb_alloc(len, GFP_ATOMIC);
                        if (!skb) {
                                BT_ERR("%s no memory for the packet", husb->hdev->name);
@@ -790,6 +797,13 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        BT_DBG("udev %p ifnum %d", udev, ifnum);
 
+       if (!id->driver_info) {
+               const struct usb_device_id *match;
+               match = usb_match_id(intf, blacklist_ids);
+               if (match)
+                       id = match;
+       }
+
        iface = udev->actconfig->interface[0];
 
        if (id->driver_info & HCI_IGNORE)
@@ -928,6 +942,9 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
        hdev->owner = THIS_MODULE;
 
+       if (id->driver_info & HCI_RESET)
+               set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
                hci_free_dev(hdev);
@@ -994,6 +1011,6 @@ void hci_usb_cleanup(void)
 module_init(hci_usb_init);
 module_exit(hci_usb_cleanup);
 
-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
 MODULE_LICENSE("GPL");
index 09381b215bf17094e2574c6474c970e41dae40d0..94437b0c89aaa49b64b8f146e6b2f2d37174ea62 100644 (file)
@@ -38,7 +38,8 @@
 #define HCI_DIGI_REQ        0x40
 
 #define HCI_IGNORE           0x01
-#define HCI_DIGIANSWER       0x02
+#define HCI_RESET            0x02
+#define HCI_DIGIANSWER       0x04
 
 #define HCI_MAX_IFACE_NUM      3 
 
index 39bce6f7bd5d9fd3536b6811ba2871af47494a54..6f235638a7acdb58752e69e5b8e761f7acf49b8e 100644 (file)
 #define HCI_RS232      4
 #define HCI_PCI                5
 
+/* HCI device quirks */
+enum {
+       HCI_QUIRK_RESET_ON_INIT
+};
+
 /* HCI device flags */
 enum {
        HCI_UP,
index 4ce3430b34edbc278c74476b52ed0e7fe6e68689..9e1278484a50e21c2ba61a2cfd64c8db0ee5d28e 100644 (file)
@@ -77,6 +77,8 @@ struct hci_dev {
        __u16           link_policy;
        __u16           link_mode;
 
+       unsigned long   quirks;
+
        atomic_t        cmd_cnt;
        unsigned int    acl_cnt;
        unsigned int    sco_cnt;
index 77e7e9b7fcc97a36e4b598f41055f18ee7ed5334..35a874bde343c44efd377f54493db684092dfa9f 100644 (file)
@@ -189,6 +189,10 @@ 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))
+                       hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+
        /* Read Local Supported Features */
        hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);