bnx2x: PBA Table Page Alignment Workaround
[safe/jmp/linux-2.6] / drivers / bluetooth / hci_usb.c
index 95afce1..e397572 100644 (file)
@@ -35,7 +35,6 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/sched.h>
 #include <linux/unistd.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #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 reset = 0;
+static int ignore_dga;
+static int ignore_csr;
+static int ignore_sniffer;
+static int disable_scofix;
+static int force_scofix;
+static int reset;
 
 #ifdef CONFIG_BT_HCIUSB_SCO
 static int isoc = 2;
 #endif
 
-#define VERSION "2.9"
+#define VERSION "2.10"
 
 static struct usb_driver hci_usb_driver; 
 
@@ -94,6 +94,9 @@ static struct usb_device_id bluetooth_ids[] = {
        /* 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 */
 };
 
@@ -107,20 +110,57 @@ static struct usb_device_id blacklist_ids[] = {
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
 
        /* Broadcom BCM2035 */
-       { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC },
+       { 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 },
 
+       /* Broadcom BCM2045 */
+       { USB_DEVICE(0x0a5c, 0x2039), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+
+       /* IBM/Lenovo ThinkPad with Broadcom chip */
+       { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+       { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+
+       /* Targus ACB10US */
+       { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET },
+
+       /* 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_RESET | HCI_WRONG_SCO_MTU },
+
+       /* Dell laptop with Broadcom chip */
+       { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+       /* Dell Wireless 370 */
+       { USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+       /* Dell Wireless 410 */
+       { USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+
+       /* Broadcom 2046 */
+       { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET },
+
        /* 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_RESET | HCI_WRONG_SCO_MTU },
 
        /* ISSC Bluetooth Adapter v3.1 */
        { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
 
-       /* RTX Telecom based adapter with buggy SCO support */
+       /* 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 },
+
+       /* CONWISE Technology based adapters with buggy SCO support */
+       { USB_DEVICE(0x0e5e, 0x6622), .driver_info = HCI_BROKEN_ISOC },
+
+       /* Belkin F8T012 and F8T013 devices */
+       { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
+       { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
 
        /* Digianswer devices */
        { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
@@ -163,14 +203,13 @@ static 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])
 #define __completed_q(husb, type) (&husb->completed_q[type-1])
 #define __transmit_q(husb, type)  (&husb->transmit_q[type-1])
-#define __reassembly(husb, type)  (husb->reassembly[type-1])
 
 static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
 {
@@ -232,7 +271,7 @@ static int hci_usb_intr_rx_submit(struct hci_usb *husb)
                BT_ERR("%s intr rx submit failed urb %p err %d",
                                husb->hdev->name, urb, err);
                _urb_unlink(_urb);
-               _urb_free(_urb);
+               kfree(_urb);
                kfree(buf);
        }
        return err;
@@ -269,7 +308,7 @@ static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
                BT_ERR("%s bulk rx submit failed urb %p err %d",
                                husb->hdev->name, urb, err);
                _urb_unlink(_urb);
-               _urb_free(_urb);
+               kfree(_urb);
                kfree(buf);
        }
        return err;
@@ -320,7 +359,7 @@ static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
                BT_ERR("%s isoc rx submit failed urb %p err %d",
                                husb->hdev->name, urb, err);
                _urb_unlink(_urb);
-               _urb_free(_urb);
+               kfree(_urb);
                kfree(buf);
        }
        return err;
@@ -398,13 +437,7 @@ static void hci_usb_unlink_urbs(struct hci_usb *husb)
                                        husb->hdev->name, _urb, _urb->type, urb);
                        kfree(urb->setup_packet);
                        kfree(urb->transfer_buffer);
-                       _urb_free(_urb);
-               }
-
-               /* Release reassembly buffers */
-               if (husb->reassembly[i]) {
-                       kfree_skb(husb->reassembly[i]);
-                       husb->reassembly[i] = NULL;
+                       kfree(_urb);
                }
        }
 }
@@ -463,7 +496,7 @@ static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
 
                dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
                if (!dr) {
-                       _urb_free(_urb);
+                       kfree(_urb);
                        return -ENOMEM;
                }
        } else
@@ -642,84 +675,7 @@ static int hci_usb_send_frame(struct sk_buff *skb)
        return 0;
 }
 
-static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
-{
-       BT_DBG("%s type %d data %p count %d", husb->hdev->name, type, data, count);
-
-       husb->hdev->stat.byte_rx += count;
-
-       while (count) {
-               struct sk_buff *skb = __reassembly(husb, type);
-               struct { int expect; } *scb;
-               int len = 0;
-       
-               if (!skb) {
-                       /* Start of the frame */
-
-                       switch (type) {
-                       case HCI_EVENT_PKT:
-                               if (count >= HCI_EVENT_HDR_SIZE) {
-                                       struct hci_event_hdr *h = data;
-                                       len = HCI_EVENT_HDR_SIZE + h->plen;
-                               } else
-                                       return -EILSEQ;
-                               break;
-
-                       case HCI_ACLDATA_PKT:
-                               if (count >= HCI_ACL_HDR_SIZE) {
-                                       struct hci_acl_hdr *h = data;
-                                       len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
-                               } else
-                                       return -EILSEQ;
-                               break;
-#ifdef CONFIG_BT_HCIUSB_SCO
-                       case HCI_SCODATA_PKT:
-                               if (count >= HCI_SCO_HDR_SIZE) {
-                                       struct hci_sco_hdr *h = data;
-                                       len = HCI_SCO_HDR_SIZE + h->dlen;
-                               } else
-                                       return -EILSEQ;
-                               break;
-#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);
-                               return -ENOMEM;
-                       }
-                       skb->dev = (void *) husb->hdev;
-                       bt_cb(skb)->pkt_type = type;
-       
-                       __reassembly(husb, type) = skb;
-
-                       scb = (void *) skb->cb;
-                       scb->expect = len;
-               } else {
-                       /* Continuation */
-                       scb = (void *) skb->cb;
-                       len = scb->expect;
-               }
-
-               len = min(len, count);
-               
-               memcpy(skb_put(skb, len), data, len);
-
-               scb->expect -= len;
-               if (!scb->expect) {
-                       /* Complete frame */
-                       __reassembly(husb, type) = NULL;
-                       bt_cb(skb)->pkt_type = type;
-                       hci_recv_frame(skb);
-               }
-
-               count -= len; data += len;
-       }
-       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;
@@ -746,16 +702,19 @@ static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs)
                                        urb->iso_frame_desc[i].offset,
                                        urb->iso_frame_desc[i].actual_length);
        
-                       if (!urb->iso_frame_desc[i].status)
-                               __recv_frame(husb, _urb->type, 
+                       if (!urb->iso_frame_desc[i].status) {
+                               husb->hdev->stat.byte_rx += urb->iso_frame_desc[i].actual_length;
+                               hci_recv_fragment(husb->hdev, _urb->type, 
                                        urb->transfer_buffer + urb->iso_frame_desc[i].offset,
                                        urb->iso_frame_desc[i].actual_length);
+                       }
                }
 #else
                ;
 #endif
        } else {
-               err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
+               husb->hdev->stat.byte_rx += count;
+               err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count);
                if (err < 0) { 
                        BT_ERR("%s corrupted packet: type %d count %d",
                                        husb->hdev->name, _urb->type, count);
@@ -773,7 +732,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;
@@ -841,7 +800,7 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
                        id = match;
        }
 
-       if (ignore || id->driver_info & HCI_IGNORE)
+       if (id->driver_info & HCI_IGNORE)
                return -ENODEV;
 
        if (ignore_dga && id->driver_info & HCI_DIGIANSWER)
@@ -987,6 +946,11 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
        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);
@@ -1045,10 +1009,81 @@ 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 = {
        .name           = "hci_usb",
        .probe          = hci_usb_probe,
        .disconnect     = hci_usb_disconnect,
+       .suspend        = hci_usb_suspend,
+       .resume         = hci_usb_resume,
        .id_table       = bluetooth_ids,
 };
 
@@ -1072,9 +1107,6 @@ 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");
 
@@ -1084,6 +1116,12 @@ 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");