X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fbluetooth%2Fhci_usb.c;h=4c8e968651f07e46d77c788b6b229039fa302f86;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=bca96831013ed7354172f58daf47252ae695d5ae;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index bca968310..4c8e96865 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,14 @@ #define URB_ZERO_PACKET 0 #endif -#define VERSION "2.7" +static int ignore = 0; +static int reset = 0; + +#ifdef CONFIG_BT_HCIUSB_SCO +static int isoc = 2; +#endif + +#define VERSION "2.8" static struct usb_driver hci_usb_driver; @@ -97,20 +105,28 @@ static struct usb_device_id blacklist_ids[] = { /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, + { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, + + /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ + { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, /* ISSC Bluetooth Adapter v3.1 */ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, - /* Digianswer device */ - { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, - /* RTX Telecom based adapter with buggy SCO support */ { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, + /* Digianswer devices */ + { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, + { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE }, + + /* CSR BlueCore Bluetooth Sniffer */ + { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER }, + { } /* Terminating entry */ }; -struct _urb *_urb_alloc(int isoc, int gfp) +static struct _urb *_urb_alloc(int isoc, int gfp) { struct _urb *_urb = kmalloc(sizeof(struct _urb) + sizeof(struct usb_iso_packet_descriptor) * isoc, gfp); @@ -121,7 +137,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; @@ -183,7 +199,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) @@ -258,7 +274,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); @@ -515,7 +531,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); @@ -790,7 +806,12 @@ 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 = NULL; @@ -812,7 +833,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) id = match; } - if (id->driver_info & HCI_IGNORE) + if (ignore || id->driver_info & HCI_IGNORE) return -ENODEV; if (intf->cur_altsetting->desc.bInterfaceNumber > 0) @@ -856,9 +877,9 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 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; @@ -867,7 +888,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) isoc_ifnum = 1; #ifdef CONFIG_BT_HCIUSB_SCO - if (!(id->driver_info & HCI_BROKEN_ISOC)) + if (isoc && !(id->driver_info & HCI_BROKEN_ISOC)) isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum); if (isoc_iface) { @@ -882,10 +903,10 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_ISOC: - if (ep->desc.wMaxPacketSize < size || - uif->desc.bAlternateSetting > 2) + if (le16_to_cpu(ep->desc.wMaxPacketSize) < size || + uif->desc.bAlternateSetting != isoc) break; - size = ep->desc.wMaxPacketSize; + size = le16_to_cpu(ep->desc.wMaxPacketSize); isoc_alts = uif->desc.bAlternateSetting; @@ -906,7 +927,9 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 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; @@ -916,7 +939,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) } #endif - husb->completion_lock = RW_LOCK_UNLOCKED; + rwlock_init(&husb->completion_lock); for (i = 0; i < 4; i++) { skb_queue_head_init(&husb->transmit_q[i]); @@ -942,12 +965,29 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) 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 (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); @@ -1018,6 +1058,17 @@ 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(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 , Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); MODULE_VERSION(VERSION);