fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / bluetooth / hci_usb.c
index ed961bb..5f0f0a7 100644 (file)
  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
  *
- * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $    
  */
-#define VERSION "2.5"
 
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -42,6 +39,7 @@
 #include <linux/unistd.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/moduleparam.h>
 
 #include <linux/slab.h>
 #include <linux/errno.h>
@@ -57,9 +55,7 @@
 
 #ifndef CONFIG_BT_HCIUSB_DEBUG
 #undef  BT_DBG
-#define BT_DBG( A... )
-#undef  BT_DMP
-#define BT_DMP( A... )
+#define BT_DBG(D...)
 #endif
 
 #ifndef CONFIG_BT_HCIUSB_ZERO_PACKET
 #define URB_ZERO_PACKET 0
 #endif
 
+static int ignore = 0;
+static int ignore_dga = 0;
+static int ignore_csr = 0;
+static int ignore_sniffer = 0;
+static int disable_scofix = 0;
+static int force_scofix = 0;
+static int reset = 0;
+
+#ifdef CONFIG_BT_HCIUSB_SCO
+static int isoc = 2;
+#endif
+
+#define VERSION "2.9"
+
 static struct usb_driver hci_usb_driver; 
 
 static struct usb_device_id bluetooth_ids[] = {
@@ -76,14 +86,18 @@ static struct usb_device_id bluetooth_ids[] = {
        /* AVM BlueFRITZ! USB v2.0 */
        { USB_DEVICE(0x057c, 0x3800) },
 
-       /* Ericsson with non-standard id */
-       { USB_DEVICE(0x0bdb, 0x1002) },
+       /* Bluetooth Ultraport Module from IBM */
+       { USB_DEVICE(0x04bf, 0x030a) },
 
-       /* ALPS Module with non-standard id */
+       /* ALPS Modules with non-standard id */
+       { USB_DEVICE(0x044e, 0x3001) },
        { USB_DEVICE(0x044e, 0x3002) },
 
-       /* Bluetooth Ultraport Module from IBM */
-       { USB_DEVICE(0x04bf, 0x030a) },
+       /* Ericsson with non-standard id */
+       { USB_DEVICE(0x0bdb, 0x1002) },
+
+       /* Canyon CN-BTU1 with HID interfaces */
+       { USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET },
 
        { }     /* Terminating entry */
 };
@@ -91,19 +105,62 @@ static struct usb_device_id bluetooth_ids[] = {
 MODULE_DEVICE_TABLE (usb, bluetooth_ids);
 
 static struct usb_device_id blacklist_ids[] = {
+       /* CSR BlueCore devices */
+       { USB_DEVICE(0x0a12, 0x0001), .driver_info = HCI_CSR },
+
        /* Broadcom BCM2033 without firmware */
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
 
        /* Broadcom BCM2035 */
-       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET },
+       { USB_DEVICE(0x0a5c, 0x2035), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
+
+       /* IBM/Lenovo ThinkPad with Broadcom chip */
+       { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU },
+
+       /* ANYCOM Bluetooth USB-200 and USB-250 */
+       { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
+
+       /* HP laptop with Broadcom chip */
+       { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_WRONG_SCO_MTU },
+
+       /* Dell laptop with Broadcom chip */
+       { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_WRONG_SCO_MTU },
+
+       /* Microsoft Wireless Transceiver for Bluetooth 2.0 */
+       { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
+
+       /* Kensington Bluetooth USB adapter */
+       { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET },
+       { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_WRONG_SCO_MTU },
 
-       /* Digianswer device */
+       /* ISSC Bluetooth Adapter v3.1 */
+       { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
+
+       /* RTX Telecom based adapters with buggy SCO support */
+       { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC },
+       { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC },
+
+       /* Belkin F8T012 and F8T013 devices */
+       { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_WRONG_SCO_MTU },
+       { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_WRONG_SCO_MTU },
+
+       /* Digianswer devices */
        { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
+       { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE },
 
-       { }     /* Terminating entry */
+       /* CSR BlueCore Bluetooth Sniffer */
+       { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER },
+
+       /* Frontline ComProbe Bluetooth Sniffer */
+       { USB_DEVICE(0x16d3, 0x0002), .driver_info = HCI_SNIFFER },
+
+       { }     /* Terminating entry */
 };
 
-struct _urb *_urb_alloc(int isoc, int gfp)
+static struct _urb *_urb_alloc(int isoc, gfp_t gfp)
 {
        struct _urb *_urb = kmalloc(sizeof(struct _urb) +
                                sizeof(struct usb_iso_packet_descriptor) * isoc, gfp);
@@ -114,7 +171,7 @@ struct _urb *_urb_alloc(int isoc, int gfp)
        return _urb;
 }
 
-struct _urb *_urb_dequeue(struct _urb_queue *q)
+static struct _urb *_urb_dequeue(struct _urb_queue *q)
 {
        struct _urb *_urb = NULL;
        unsigned long flags;
@@ -131,8 +188,8 @@ struct _urb *_urb_dequeue(struct _urb_queue *q)
        return _urb;
 }
 
-static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs);
-static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs);
+static void hci_usb_rx_complete(struct urb *urb);
+static void hci_usb_tx_complete(struct urb *urb);
 
 #define __pending_tx(husb, type)  (&husb->pending_tx[type-1])
 #define __pending_q(husb, type)   (&husb->pending_q[type-1])
@@ -176,7 +233,7 @@ static int hci_usb_intr_rx_submit(struct hci_usb *husb)
 
        BT_DBG("%s", husb->hdev->name);
 
-       size = husb->intr_in_ep->desc.wMaxPacketSize;
+       size = le16_to_cpu(husb->intr_in_ep->desc.wMaxPacketSize);
 
        buf = kmalloc(size, GFP_ATOMIC);
        if (!buf)
@@ -251,7 +308,7 @@ static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
        int err, mtu, size;
        void *buf;
 
-       mtu  = husb->isoc_in_ep->desc.wMaxPacketSize;
+       mtu  = le16_to_cpu(husb->isoc_in_ep->desc.wMaxPacketSize);
        size = mtu * HCI_MAX_ISOC_FRAMES;
 
        buf = kmalloc(size, GFP_ATOMIC);
@@ -335,26 +392,18 @@ static int hci_usb_flush(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
-       for (i=0; i < 4; i++)
+       for (i = 0; i < 4; i++)
                skb_queue_purge(&husb->transmit_q[i]);
        return 0;
 }
 
-static inline void hci_usb_wait_for_urb(struct urb *urb)
-{
-       while (atomic_read(&urb->count) > 1) {
-               current->state = TASK_UNINTERRUPTIBLE;
-               schedule_timeout((5 * HZ + 999) / 1000);
-       }
-}
-
 static void hci_usb_unlink_urbs(struct hci_usb *husb)
 {
        int i;
 
        BT_DBG("%s", husb->hdev->name);
 
-       for (i=0; i < 4; i++) {
+       for (i = 0; i < 4; i++) {
                struct _urb *_urb;
                struct urb *urb;
 
@@ -363,8 +412,7 @@ static void hci_usb_unlink_urbs(struct hci_usb *husb)
                        urb = &_urb->urb;
                        BT_DBG("%s unlinking _urb %p type %d urb %p", 
                                        husb->hdev->name, _urb, _urb->type, urb);
-                       usb_unlink_urb(urb);
-                       hci_usb_wait_for_urb(urb);
+                       usb_kill_urb(urb);
                        _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
                }
 
@@ -373,10 +421,8 @@ static void hci_usb_unlink_urbs(struct hci_usb *husb)
                        urb = &_urb->urb;
                        BT_DBG("%s freeing _urb %p type %d urb %p",
                                        husb->hdev->name, _urb, _urb->type, urb);
-                       if (urb->setup_packet)
-                               kfree(urb->setup_packet);
-                       if (urb->transfer_buffer)
-                               kfree(urb->transfer_buffer);
+                       kfree(urb->setup_packet);
+                       kfree(urb->transfer_buffer);
                        _urb_free(_urb);
                }
 
@@ -393,7 +439,7 @@ static int hci_usb_close(struct hci_dev *hdev)
 {
        struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
        unsigned long flags;
-       
+
        if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
                return 0;
 
@@ -402,7 +448,7 @@ static int hci_usb_close(struct hci_dev *hdev)
        /* Synchronize with completion handlers */
        write_lock_irqsave(&husb->completion_lock, flags);
        write_unlock_irqrestore(&husb->completion_lock, flags);
-       
+
        hci_usb_unlink_urbs(husb);
        hci_usb_flush(hdev);
        return 0;
@@ -414,7 +460,7 @@ static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
        int err;
 
        BT_DBG("%s urb %p type %d", husb->hdev->name, urb, _urb->type);
-       
+
        _urb_queue_tail(__pending_q(husb, _urb->type), _urb);
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err) {
@@ -430,7 +476,7 @@ static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
 
 static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 {
-       struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+       struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
        struct usb_ctrlrequest *dr;
        struct urb *urb;
 
@@ -438,7 +484,7 @@ static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
                _urb = _urb_alloc(0, GFP_ATOMIC);
                if (!_urb)
                        return -ENOMEM;
-               _urb->type = skb->pkt_type;
+               _urb->type = bt_cb(skb)->pkt_type;
 
                dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
                if (!dr) {
@@ -466,7 +512,7 @@ static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 
 static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 {
-       struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+       struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
        struct urb *urb;
        int pipe;
 
@@ -474,7 +520,7 @@ static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
                _urb = _urb_alloc(0, GFP_ATOMIC);
                if (!_urb)
                        return -ENOMEM;
-               _urb->type = skb->pkt_type;
+               _urb->type = bt_cb(skb)->pkt_type;
        }
 
        urb  = &_urb->urb;
@@ -492,14 +538,14 @@ static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
 #ifdef CONFIG_BT_HCIUSB_SCO
 static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
 {
-       struct _urb *_urb = __get_completed(husb, skb->pkt_type);
+       struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type);
        struct urb *urb;
 
        if (!_urb) {
                _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
                if (!_urb)
                        return -ENOMEM;
-               _urb->type = skb->pkt_type;
+               _urb->type = bt_cb(skb)->pkt_type;
        }
 
        BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len);
@@ -517,7 +563,7 @@ static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
        urb->transfer_buffer = skb->data;
        urb->transfer_buffer_length = skb->len;
 
-       __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->desc.wMaxPacketSize);
+       __fill_isoc_desc(urb, skb->len, le16_to_cpu(husb->isoc_out_ep->desc.wMaxPacketSize));
 
        _urb->priv = skb;
        return __tx_submit(husb, _urb);
@@ -551,7 +597,7 @@ static void hci_usb_tx_process(struct hci_usb *husb)
                                skb_queue_head(q, skb);
                }
 #endif
-               
+
                /* Process ACL queue */
                q = __transmit_q(husb, HCI_ACLDATA_PKT);
                while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
@@ -588,11 +634,11 @@ static int hci_usb_send_frame(struct sk_buff *skb)
        if (!test_bit(HCI_RUNNING, &hdev->flags))
                return -EBUSY;
 
-       BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+       BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
        husb = (struct hci_usb *) hdev->driver_data;
 
-       switch (skb->pkt_type) {
+       switch (bt_cb(skb)->pkt_type) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
                break;
@@ -614,7 +660,7 @@ static int hci_usb_send_frame(struct sk_buff *skb)
 
        read_lock(&husb->completion_lock);
 
-       skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
+       skb_queue_tail(__transmit_q(husb, bt_cb(skb)->pkt_type), skb);
        hci_usb_tx_wakeup(husb);
 
        read_unlock(&husb->completion_lock);
@@ -656,7 +702,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
                                if (count >= HCI_SCO_HDR_SIZE) {
                                        struct hci_sco_hdr *h = data;
                                        len = HCI_SCO_HDR_SIZE + h->dlen;
-                               } else 
+                               } else
                                        return -EILSEQ;
                                break;
 #endif
@@ -669,7 +715,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
                                return -ENOMEM;
                        }
                        skb->dev = (void *) husb->hdev;
-                       skb->pkt_type = type;
+                       bt_cb(skb)->pkt_type = type;
        
                        __reassembly(husb, type) = skb;
 
@@ -689,6 +735,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
                if (!scb->expect) {
                        /* Complete frame */
                        __reassembly(husb, type) = NULL;
+                       bt_cb(skb)->pkt_type = type;
                        hci_recv_frame(skb);
                }
 
@@ -697,12 +744,12 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
        return 0;
 }
 
-static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs)
+static void hci_usb_rx_complete(struct urb *urb)
 {
        struct _urb *_urb = container_of(urb, struct _urb, urb);
        struct hci_usb *husb = (void *) urb->context;
        struct hci_dev *hdev = husb->hdev;
-       int    err, count = urb->actual_length;
+       int err, count = urb->actual_length;
 
        BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
                        _urb->type, urb->status, count, urb->transfer_flags);
@@ -743,7 +790,7 @@ static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs)
 
 resubmit:
        urb->dev = husb->udev;
-       err      = usb_submit_urb(urb, GFP_ATOMIC);
+       err = usb_submit_urb(urb, GFP_ATOMIC);
        BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
                        _urb->type, err);
 
@@ -751,7 +798,7 @@ unlock:
        read_unlock(&husb->completion_lock);
 }
 
-static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs)
+static void hci_usb_tx_complete(struct urb *urb)
 {
        struct _urb *_urb = container_of(urb, struct _urb, urb);
        struct hci_usb *husb = (void *) urb->context;
@@ -779,7 +826,7 @@ static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs)
        _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
 
        hci_usb_tx_wakeup(husb);
-       
+
        read_unlock(&husb->completion_lock);
 }
 
@@ -792,20 +839,23 @@ static void hci_usb_destruct(struct hci_dev *hdev)
        kfree(husb);
 }
 
-int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static void hci_usb_notify(struct hci_dev *hdev, unsigned int evt)
+{
+       BT_DBG("%s evt %d", hdev->name, evt);
+}
+
+static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
        struct usb_device *udev = interface_to_usbdev(intf);
-       struct usb_host_endpoint *bulk_out_ep[HCI_MAX_IFACE_NUM];
-       struct usb_host_endpoint *isoc_out_ep[HCI_MAX_IFACE_NUM];
-       struct usb_host_endpoint *bulk_in_ep[HCI_MAX_IFACE_NUM];
-       struct usb_host_endpoint *isoc_in_ep[HCI_MAX_IFACE_NUM];
-       struct usb_host_endpoint *intr_in_ep[HCI_MAX_IFACE_NUM];
+       struct usb_host_endpoint *bulk_out_ep = NULL;
+       struct usb_host_endpoint *bulk_in_ep = NULL;
+       struct usb_host_endpoint *intr_in_ep = NULL;
        struct usb_host_endpoint  *ep;
        struct usb_host_interface *uif;
-       struct usb_interface *iface, *isoc_iface;
+       struct usb_interface *isoc_iface;
        struct hci_usb *husb;
        struct hci_dev *hdev;
-       int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
+       int i, e, size, isoc_ifnum, isoc_alts;
 
        BT_DBG("udev %p intf %p", udev, intf);
 
@@ -816,118 +866,122 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
                        id = match;
        }
 
-       iface = udev->actconfig->interface[0];
+       if (ignore || id->driver_info & HCI_IGNORE)
+               return -ENODEV;
 
-       if (id->driver_info & HCI_IGNORE)
+       if (ignore_dga && id->driver_info & HCI_DIGIANSWER)
                return -ENODEV;
 
-       if (intf->altsetting->desc.bInterfaceNumber > 0)
+       if (ignore_csr && id->driver_info & HCI_CSR)
                return -ENODEV;
 
-       /* Check number of endpoints */
-       if (intf->altsetting[0].desc.bNumEndpoints < 3)
-               return -EIO;
+       if (ignore_sniffer && id->driver_info & HCI_SNIFFER)
+               return -ENODEV;
 
-       memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
-       memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
-       memset(bulk_in_ep,  0, sizeof(bulk_in_ep));
-       memset(isoc_in_ep,  0, sizeof(isoc_in_ep));
-       memset(intr_in_ep,  0, sizeof(intr_in_ep));
+       if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
+               return -ENODEV;
 
-       size = 0; 
-       isoc_iface = NULL;
-       isoc_alts  = isoc_ifnum = 0;
-       
        /* Find endpoints that we need */
-
-       ifn = min_t(unsigned int, udev->actconfig->desc.bNumInterfaces, HCI_MAX_IFACE_NUM);
-       for (i = 0; i < ifn; i++) {
-               iface = udev->actconfig->interface[i];
-               for (a = 0; a < iface->num_altsetting; a++) {
-                       uif = &iface->altsetting[a];
-                       for (e = 0; e < uif->desc.bNumEndpoints; e++) {
-                               ep = &uif->endpoint[e];
-
-                               switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-                               case USB_ENDPOINT_XFER_INT:
-                                       if (ep->desc.bEndpointAddress & USB_DIR_IN)
-                                               intr_in_ep[i] = ep;
-                                       break;
-
-                               case USB_ENDPOINT_XFER_BULK:
-                                       if (ep->desc.bEndpointAddress & USB_DIR_IN)
-                                               bulk_in_ep[i]  = ep;
-                                       else
-                                               bulk_out_ep[i] = ep;
-                                       break;
-
-#ifdef CONFIG_BT_HCIUSB_SCO
-                               case USB_ENDPOINT_XFER_ISOC:
-                                       if (ep->desc.wMaxPacketSize < size || a > 2)
-                                               break;
-                                       size = ep->desc.wMaxPacketSize;
-
-                                       isoc_iface = iface;
-                                       isoc_alts  = a;
-                                       isoc_ifnum = i;
-
-                                       if (ep->desc.bEndpointAddress & USB_DIR_IN)
-                                               isoc_in_ep[i]  = ep;
-                                       else
-                                               isoc_out_ep[i] = ep;
-                                       break;
-#endif
-                               }
-                       }
+       uif = intf->cur_altsetting;
+       for (e = 0; e < uif->desc.bNumEndpoints; e++) {
+               ep = &uif->endpoint[e];
+
+               switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+               case USB_ENDPOINT_XFER_INT:
+                       if (ep->desc.bEndpointAddress & USB_DIR_IN)
+                               intr_in_ep = ep;
+                       break;
+
+               case USB_ENDPOINT_XFER_BULK:
+                       if (ep->desc.bEndpointAddress & USB_DIR_IN)
+                               bulk_in_ep  = ep;
+                       else
+                               bulk_out_ep = ep;
+                       break;
                }
        }
 
-       if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {
+       if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
                BT_DBG("Bulk endpoints not found");
                goto done;
        }
 
-#ifdef CONFIG_BT_HCIUSB_SCO
-       if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
-               BT_DBG("Isoc endpoints not found");
-               isoc_iface = NULL;
-       }
-#endif
-
-       if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
+       if (!(husb = kzalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
                BT_ERR("Can't allocate: control structure");
                goto done;
        }
 
-       memset(husb, 0, sizeof(struct hci_usb));
-
        husb->udev = udev;
-       husb->bulk_out_ep = bulk_out_ep[0];
-       husb->bulk_in_ep  = bulk_in_ep[0];
-       husb->intr_in_ep  = intr_in_ep[0];
+       husb->bulk_out_ep = bulk_out_ep;
+       husb->bulk_in_ep  = bulk_in_ep;
+       husb->intr_in_ep  = intr_in_ep;
 
        if (id->driver_info & HCI_DIGIANSWER)
-               husb->ctrl_req = HCI_DIGI_REQ;
+               husb->ctrl_req = USB_TYPE_VENDOR;
        else
-               husb->ctrl_req = HCI_CTRL_REQ;
+               husb->ctrl_req = USB_TYPE_CLASS;
+
+       /* Find isochronous endpoints that we can use */
+       size = 0; 
+       isoc_iface = NULL;
+       isoc_alts  = 0;
+       isoc_ifnum = 1;
 
 #ifdef CONFIG_BT_HCIUSB_SCO
+       if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER)))
+               isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum);
+
        if (isoc_iface) {
-               BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
-               if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
-                       BT_ERR("Can't set isoc interface settings");
-                       isoc_iface = NULL;
+               int a;
+               struct usb_host_endpoint *isoc_out_ep = NULL;
+               struct usb_host_endpoint *isoc_in_ep = NULL;
+
+               for (a = 0; a < isoc_iface->num_altsetting; a++) {
+                       uif = &isoc_iface->altsetting[a];
+                       for (e = 0; e < uif->desc.bNumEndpoints; e++) {
+                               ep = &uif->endpoint[e];
+
+                               switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+                               case USB_ENDPOINT_XFER_ISOC:
+                                       if (le16_to_cpu(ep->desc.wMaxPacketSize) < size ||
+                                                       uif->desc.bAlternateSetting != isoc)
+                                               break;
+                                       size = le16_to_cpu(ep->desc.wMaxPacketSize);
+
+                                       isoc_alts = uif->desc.bAlternateSetting;
+
+                                       if (ep->desc.bEndpointAddress & USB_DIR_IN)
+                                               isoc_in_ep  = ep;
+                                       else
+                                               isoc_out_ep = ep;
+                                       break;
+                               }
+                       }
+               }
+
+               if (!isoc_in_ep || !isoc_out_ep)
+                       BT_DBG("Isoc endpoints not found");
+               else {
+                       BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
+                       if (usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb) != 0)
+                               BT_ERR("Can't claim isoc interface");
+                       else if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
+                               BT_ERR("Can't set isoc interface settings");
+                               husb->isoc_iface = isoc_iface;
+                               usb_driver_release_interface(&hci_usb_driver, isoc_iface);
+                               husb->isoc_iface = NULL;
+                       } else {
+                               husb->isoc_iface  = isoc_iface;
+                               husb->isoc_in_ep  = isoc_in_ep;
+                               husb->isoc_out_ep = isoc_out_ep;
+                       }
                }
-               usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
-               husb->isoc_iface  = isoc_iface;
-               husb->isoc_in_ep  = isoc_in_ep[isoc_ifnum];
-               husb->isoc_out_ep = isoc_out_ep[isoc_ifnum];
        }
 #endif
-       
-       husb->completion_lock = RW_LOCK_UNLOCKED;
 
-       for (i = 0; i < 4; i++) {       
+       rwlock_init(&husb->completion_lock);
+
+       for (i = 0; i < 4; i++) {
                skb_queue_head_init(&husb->transmit_q[i]);
                _urb_queue_init(&husb->pending_q[i]);
                _urb_queue_init(&husb->completed_q[i]);
@@ -946,17 +1000,39 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
        hdev->driver_data = husb;
        SET_HCIDEV_DEV(hdev, &intf->dev);
 
-       hdev->open  = hci_usb_open;
-       hdev->close = hci_usb_close;
-       hdev->flush = hci_usb_flush;
-       hdev->send  = hci_usb_send_frame;
+       hdev->open     = hci_usb_open;
+       hdev->close    = hci_usb_close;
+       hdev->flush    = hci_usb_flush;
+       hdev->send     = hci_usb_send_frame;
        hdev->destruct = hci_usb_destruct;
+       hdev->notify   = hci_usb_notify;
 
        hdev->owner = THIS_MODULE;
 
-       if (id->driver_info & HCI_RESET)
+       if (reset || id->driver_info & HCI_RESET)
                set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
 
+       if (force_scofix || id->driver_info & HCI_WRONG_SCO_MTU) {
+               if (!disable_scofix)
+                       set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
+       }
+
+       if (id->driver_info & HCI_SNIFFER) {
+               if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
+                       set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+       }
+
+       if (id->driver_info & HCI_BCM92035) {
+               unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 };
+               struct sk_buff *skb;
+
+               skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
+               if (skb) {
+                       memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
+                       skb_queue_tail(&hdev->driver_init, skb);
+               }
+       }
+
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
                hci_free_dev(hdev);
@@ -967,6 +1043,8 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
        return 0;
 
 probe_error:
+       if (husb->isoc_iface)
+               usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
        kfree(husb);
 
 done:
@@ -976,11 +1054,13 @@ done:
 static void hci_usb_disconnect(struct usb_interface *intf)
 {
        struct hci_usb *husb = usb_get_intfdata(intf);
-       struct hci_dev *hdev = husb->hdev;
+       struct hci_dev *hdev;
 
-       if (!husb)
+       if (!husb || intf == husb->isoc_iface)
                return;
+
        usb_set_intfdata(intf, NULL);
+       hdev = husb->hdev;
 
        BT_DBG("%s", hdev->name);
 
@@ -995,12 +1075,82 @@ static void hci_usb_disconnect(struct usb_interface *intf)
        hci_free_dev(hdev);
 }
 
+static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct hci_usb *husb = usb_get_intfdata(intf);
+       struct list_head killed;
+       unsigned long flags;
+       int i;
+
+       if (!husb || intf == husb->isoc_iface)
+               return 0;
+
+       hci_suspend_dev(husb->hdev);
+
+       INIT_LIST_HEAD(&killed);
+
+       for (i = 0; i < 4; i++) {
+               struct _urb_queue *q = &husb->pending_q[i];
+               struct _urb *_urb, *_tmp;
+
+               while ((_urb = _urb_dequeue(q))) {
+                       /* reset queue since _urb_dequeue sets it to NULL */
+                       _urb->queue = q;
+                       usb_kill_urb(&_urb->urb);
+                       list_add(&_urb->list, &killed);
+               }
+
+               spin_lock_irqsave(&q->lock, flags);
+
+               list_for_each_entry_safe(_urb, _tmp, &killed, list) {
+                       list_move_tail(&_urb->list, &q->head);
+               }
+
+               spin_unlock_irqrestore(&q->lock, flags);
+       }
+
+       return 0;
+}
+
+static int hci_usb_resume(struct usb_interface *intf)
+{
+       struct hci_usb *husb = usb_get_intfdata(intf);
+       unsigned long flags;
+       int i, err = 0;
+
+       if (!husb || intf == husb->isoc_iface)
+               return 0;
+       
+       for (i = 0; i < 4; i++) {
+               struct _urb_queue *q = &husb->pending_q[i];
+               struct _urb *_urb;
+
+               spin_lock_irqsave(&q->lock, flags);
+
+               list_for_each_entry(_urb, &q->head, list) {
+                       err = usb_submit_urb(&_urb->urb, GFP_ATOMIC);
+                       if (err)
+                               break;
+               }
+
+               spin_unlock_irqrestore(&q->lock, flags);
+
+               if (err)
+                       return -EIO;
+       }
+
+       hci_resume_dev(husb->hdev);
+
+       return 0;
+}
+
 static struct usb_driver hci_usb_driver = {
-       .owner      =  THIS_MODULE,
-       .name       =  "hci_usb",
-       .probe      =  hci_usb_probe,
-       .disconnect =  hci_usb_disconnect,
-       .id_table   =  bluetooth_ids,
+       .name           = "hci_usb",
+       .probe          = hci_usb_probe,
+       .disconnect     = hci_usb_disconnect,
+       .suspend        = hci_usb_suspend,
+       .resume         = hci_usb_resume,
+       .id_table       = bluetooth_ids,
 };
 
 static int __init hci_usb_init(void)
@@ -1023,6 +1173,32 @@ static void __exit hci_usb_exit(void)
 module_init(hci_usb_init);
 module_exit(hci_usb_exit);
 
+module_param(ignore, bool, 0644);
+MODULE_PARM_DESC(ignore, "Ignore devices from the matching table");
+
+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");
+
+module_param(force_scofix, bool, 0644);
+MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size");
+
+module_param(reset, bool, 0644);
+MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
+
+#ifdef CONFIG_BT_HCIUSB_SCO
+module_param(isoc, int, 0644);
+MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support");
+#endif
+
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
 MODULE_VERSION(VERSION);