#include <linux/unistd.h>
#include <linux/types.h>
#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#ifndef CONFIG_BT_HCIUSB_DEBUG
#undef BT_DBG
#define BT_DBG(D...)
-#undef BT_DMP
-#define BT_DMP(D...)
#endif
#ifndef CONFIG_BT_HCIUSB_ZERO_PACKET
#define URB_ZERO_PACKET 0
#endif
-#define VERSION "2.6"
+static int ignore = 0;
+static int ignore_dga = 0;
+static int ignore_csr = 0;
+static int ignore_sniffer = 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;
/* 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) },
{ } /* Terminating entry */
};
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, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC },
+ { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
- /* Digianswer device */
- { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
+ /* 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 },
+
+ /* ISSC Bluetooth Adapter v3.1 */
+ { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
/* 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, gfp_t gfp)
{
struct _urb *_urb = kmalloc(sizeof(struct _urb) +
sizeof(struct usb_iso_packet_descriptor) * isoc, 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;
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)
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);
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->kref.refcount) > 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;
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);
}
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);
}
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;
_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) {
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;
_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;
#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);
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);
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;
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);
return -ENOMEM;
}
skb->dev = (void *) husb->hdev;
- skb->pkt_type = type;
+ bt_cb(skb)->pkt_type = type;
__reassembly(husb, type) = skb;
if (!scb->expect) {
/* Complete frame */
__reassembly(husb, type) = NULL;
+ bt_cb(skb)->pkt_type = type;
hci_recv_frame(skb);
}
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;
id = match;
}
- if (id->driver_info & HCI_IGNORE)
+ if (ignore || id->driver_info & HCI_IGNORE)
+ return -ENODEV;
+
+ if (ignore_dga && id->driver_info & HCI_DIGIANSWER)
+ return -ENODEV;
+
+ if (ignore_csr && id->driver_info & HCI_CSR)
+ return -ENODEV;
+
+ if (ignore_sniffer && id->driver_info & HCI_SNIFFER)
return -ENODEV;
if (intf->cur_altsetting->desc.bInterfaceNumber > 0)
goto done;
}
- 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;
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_ifnum = 1;
#ifdef CONFIG_BT_HCIUSB_SCO
- if (!(id->driver_info & HCI_BROKEN_ISOC))
+ if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER)))
isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum);
if (isoc_iface) {
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;
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;
}
#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]);
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);
}
static struct usb_driver hci_usb_driver = {
- .owner = THIS_MODULE,
.name = "hci_usb",
.probe = hci_usb_probe,
.disconnect = hci_usb_disconnect,
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(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);