Bluetooth: ath3k: Add support of AR3012 bluetooth 13d3:3423 device
[pandora-kernel.git] / drivers / bluetooth / btusb.c
index 19cf2cf..1211c74 100644 (file)
@@ -49,6 +49,7 @@ static struct usb_driver btusb_driver;
 #define BTUSB_INTEL_BOOT       0x200
 #define BTUSB_BCM_PATCHRAM     0x400
 #define BTUSB_MARVELL          0x800
+#define BTUSB_SWAVE            0x1000
 
 static const struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth USB device */
@@ -85,7 +86,7 @@ static const struct usb_device_id btusb_table[] = {
        { USB_DEVICE(0x05ac, 0x8281) },
 
        /* AVM BlueFRITZ! USB v2.0 */
-       { USB_DEVICE(0x057c, 0x3800) },
+       { USB_DEVICE(0x057c, 0x3800), .driver_info = BTUSB_SWAVE },
 
        /* Bluetooth Ultraport Module from IBM */
        { USB_DEVICE(0x04bf, 0x030a) },
@@ -188,6 +189,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
@@ -237,6 +239,9 @@ static const struct usb_device_id blacklist_table[] = {
        /* CONWISE Technology based adapters with buggy SCO support */
        { USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
 
+       /* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
+       { USB_DEVICE(0x1300, 0x0001), .driver_info = BTUSB_SWAVE },
+
        /* Digianswer devices */
        { USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
        { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
@@ -305,6 +310,7 @@ struct btusb_data {
        int isoc_altsetting;
        int suspend_count;
 
+       int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
        int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
 };
 
@@ -370,7 +376,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
 
                if (bt_cb(skb)->expect == 0) {
                        /* Complete frame */
-                       hci_recv_frame(data->hdev, skb);
+                       data->recv_event(data->hdev, skb);
                        skb = NULL;
                }
        }
@@ -1943,6 +1949,31 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr)
        return 0;
 }
 
+static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
+                                   const bdaddr_t *bdaddr)
+{
+       struct sk_buff *skb;
+       u8 buf[10];
+       long ret;
+
+       buf[0] = 0x01;
+       buf[1] = 0x01;
+       buf[2] = 0x00;
+       buf[3] = sizeof(bdaddr_t);
+       memcpy(buf + 4, bdaddr, sizeof(bdaddr_t));
+
+       skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               ret = PTR_ERR(skb);
+               BT_ERR("%s: Change address command failed (%ld)",
+                      hdev->name, ret);
+               return ret;
+       }
+       kfree_skb(skb);
+
+       return 0;
+}
+
 static int btusb_probe(struct usb_interface *intf,
                       const struct usb_device_id *id)
 {
@@ -2019,6 +2050,7 @@ static int btusb_probe(struct usb_interface *intf,
        init_usb_anchor(&data->isoc_anchor);
        spin_lock_init(&data->rxlock);
 
+       data->recv_event = hci_recv_frame;
        data->recv_bulk = btusb_recv_bulk;
 
        hdev = hci_alloc_dev();
@@ -2055,9 +2087,17 @@ static int btusb_probe(struct usb_interface *intf,
        if (id->driver_info & BTUSB_MARVELL)
                hdev->set_bdaddr = btusb_set_bdaddr_marvell;
 
+       if (id->driver_info & BTUSB_SWAVE) {
+               set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
+               set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
+       }
+
        if (id->driver_info & BTUSB_INTEL_BOOT)
                set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
 
+       if (id->driver_info & BTUSB_ATH3012)
+               hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
+
        /* Interface numbers are hardcoded in the specification */
        data->isoc = usb_ifnum_to_if(data->udev, 1);