tegra: Make tegra_vi01_device accessible
[linux-2.6.git] / drivers / bluetooth / btusb.c
index 6fcb971..9cbac6b 100644 (file)
@@ -54,14 +54,33 @@ static struct usb_driver btusb_driver;
 #define BTUSB_BCM92035         0x10
 #define BTUSB_BROKEN_ISOC      0x20
 #define BTUSB_WRONG_SCO_MTU    0x40
+#define BTUSB_ATH3012          0x80
 
 static struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth USB device */
        { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
 
+       /* Apple MacBookPro 7,1 */
+       { USB_DEVICE(0x05ac, 0x8213) },
+
        /* Apple iMac11,1 */
        { USB_DEVICE(0x05ac, 0x8215) },
 
+       /* Apple MacBookPro6,2 */
+       { USB_DEVICE(0x05ac, 0x8218) },
+
+       /* Apple MacBookAir3,1, MacBookAir3,2 */
+       { USB_DEVICE(0x05ac, 0x821b) },
+
+       /* Apple MacBookAir4,1 */
+       { USB_DEVICE(0x05ac, 0x821f) },
+
+       /* Apple MacBookPro8,2 */
+       { USB_DEVICE(0x05ac, 0x821a) },
+
+       /* Apple MacMini5,1 */
+       { USB_DEVICE(0x05ac, 0x8281) },
+
        /* AVM BlueFRITZ! USB v2.0 */
        { USB_DEVICE(0x057c, 0x3800) },
 
@@ -90,6 +109,20 @@ static struct usb_device_id blacklist_table[] = {
        /* Broadcom BCM2033 without firmware */
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
 
+       /* Atheros 3011 with sflash firmware */
+       { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+       { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
+       { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
+
+       /* Atheros AR9285 Malbec with sflash firmware */
+       { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
+
+       /* Atheros 3012 with sflash firmware */
+       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+
+       /* Atheros AR5BBU12 with sflash firmware */
+       { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
+
        /* Broadcom BCM2035 */
        { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
        { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -149,6 +182,7 @@ static struct usb_device_id blacklist_table[] = {
 #define BTUSB_BULK_RUNNING     1
 #define BTUSB_ISOC_RUNNING     2
 #define BTUSB_SUSPENDING       3
+#define BTUSB_DID_ISO_RESUME   4
 
 struct btusb_data {
        struct hci_dev       *hdev;
@@ -182,7 +216,6 @@ struct btusb_data {
        unsigned int sco_num;
        int isoc_altsetting;
        int suspend_count;
-       int did_iso_resume:1;
 };
 
 static int inc_tx(struct btusb_data *data)
@@ -230,7 +263,10 @@ static void btusb_intr_complete(struct urb *urb)
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p failed to resubmit (%d)",
+               /* -EPERM: urb is being killed;
+                * -ENODEV: device got disconnected */
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p failed to resubmit (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -314,7 +350,10 @@ static void btusb_bulk_complete(struct urb *urb)
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p failed to resubmit (%d)",
+               /* -EPERM: urb is being killed;
+                * -ENODEV: device got disconnected */
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p failed to resubmit (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -403,13 +442,16 @@ static void btusb_isoc_complete(struct urb *urb)
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p failed to resubmit (%d)",
+               /* -EPERM: urb is being killed;
+                * -ENODEV: device got disconnected */
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p failed to resubmit (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
 }
 
-static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
+static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
 {
        int i, offset = 0;
 
@@ -666,7 +708,8 @@ static int btusb_send_frame(struct sk_buff *skb)
                break;
 
        case HCI_ACLDATA_PKT:
-               if (!data->bulk_tx_ep || hdev->conn_hash.acl_num < 1)
+               if (!data->bulk_tx_ep || (hdev->conn_hash.acl_num < 1 &&
+                                               hdev->conn_hash.le_num < 1))
                        return -ENODEV;
 
                urb = usb_alloc_urb(0, GFP_ATOMIC);
@@ -693,15 +736,11 @@ static int btusb_send_frame(struct sk_buff *skb)
                pipe = usb_sndisocpipe(data->udev,
                                        data->isoc_tx_ep->bEndpointAddress);
 
-               urb->dev      = data->udev;
-               urb->pipe     = pipe;
-               urb->context  = skb;
-               urb->complete = btusb_isoc_tx_complete;
-               urb->interval = data->isoc_tx_ep->bInterval;
+               usb_fill_int_urb(urb, data->udev, pipe,
+                               skb->data, skb->len, btusb_isoc_tx_complete,
+                               skb, data->isoc_tx_ep->bInterval);
 
                urb->transfer_flags  = URB_ISO_ASAP;
-               urb->transfer_buffer = skb->data;
-               urb->transfer_buffer_length = skb->len;
 
                __fill_isoc_descriptor(urb, skb->len,
                                le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
@@ -760,7 +799,7 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
        }
 }
 
-static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting)
+static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
 {
        struct btusb_data *data = hdev->driver_data;
        struct usb_interface *intf = data->isoc;
@@ -810,15 +849,15 @@ static void btusb_work(struct work_struct *work)
        int err;
 
        if (hdev->conn_hash.sco_num > 0) {
-               if (!data->did_iso_resume) {
-                       err = usb_autopm_get_interface(data->isoc);
+               if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) {
+                       err = usb_autopm_get_interface(data->isoc ? data->isoc : data->intf);
                        if (err < 0) {
                                clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
                                usb_kill_anchored_urbs(&data->isoc_anchor);
                                return;
                        }
 
-                       data->did_iso_resume = 1;
+                       set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
                }
                if (data->isoc_altsetting != 2) {
                        clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
@@ -839,10 +878,8 @@ static void btusb_work(struct work_struct *work)
                usb_kill_anchored_urbs(&data->isoc_anchor);
 
                __set_isoc_interface(hdev, 0);
-               if (data->did_iso_resume) {
-                       data->did_iso_resume = 0;
-                       usb_autopm_put_interface(data->isoc);
-               }
+               if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags))
+                       usb_autopm_put_interface(data->isoc ? data->isoc : data->intf);
        }
 }
 
@@ -891,6 +928,15 @@ static int btusb_probe(struct usb_interface *intf,
        if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
                return -ENODEV;
 
+       if (id->driver_info & BTUSB_ATH3012) {
+               struct usb_device *udev = interface_to_usbdev(intf);
+
+               /* Old firmware would otherwise let ath3k driver load
+                * patch and sysconfig files */
+               if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
+                       return -ENODEV;
+       }
+
        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;