Commit fa72b93b authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Support Broadcom BCM92035 USB dongles

This patch adds support for special initialization commands inside
the Bluetooth core layer. It is used for the BCM92035 USB dongles
from Broadcom to switch them from HID mode into HCI mode.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 85714da1
...@@ -73,7 +73,7 @@ static int reset = 0; ...@@ -73,7 +73,7 @@ static int reset = 0;
static int isoc = 2; static int isoc = 2;
#endif #endif
#define VERSION "2.7" #define VERSION "2.8"
static struct usb_driver hci_usb_driver; static struct usb_driver hci_usb_driver;
...@@ -104,11 +104,11 @@ static struct usb_device_id blacklist_ids[] = { ...@@ -104,11 +104,11 @@ static struct usb_device_id blacklist_ids[] = {
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
/* Broadcom BCM2035 */ /* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_RESET | HCI_BROKEN_ISOC },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, { 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 */ /* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET | HCI_BROKEN_ISOC }, { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_BCM92035 },
/* ISSC Bluetooth Adapter v3.1 */ /* ISSC Bluetooth Adapter v3.1 */
{ USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
...@@ -977,6 +977,17 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id ...@@ -977,6 +977,17 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); 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) { if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device"); BT_ERR("Can't register HCI device");
hci_free_dev(hdev); hci_free_dev(hdev);
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define HCI_DIGIANSWER 0x04 #define HCI_DIGIANSWER 0x04
#define HCI_SNIFFER 0x08 #define HCI_SNIFFER 0x08
#define HCI_BROKEN_ISOC 0x10 #define HCI_BROKEN_ISOC 0x10
#define HCI_BCM92035 0x20
#define HCI_MAX_IFACE_NUM 3 #define HCI_MAX_IFACE_NUM 3
......
...@@ -119,6 +119,8 @@ struct hci_dev { ...@@ -119,6 +119,8 @@ struct hci_dev {
struct hci_dev_stats stat; struct hci_dev_stats stat;
struct sk_buff_head driver_init;
void *driver_data; void *driver_data;
void *core_data; void *core_data;
......
...@@ -183,10 +183,22 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) ...@@ -183,10 +183,22 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
static void hci_init_req(struct hci_dev *hdev, unsigned long opt) static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
{ {
struct sk_buff *skb;
__u16 param; __u16 param;
BT_DBG("%s %ld", hdev->name, opt); BT_DBG("%s %ld", hdev->name, opt);
/* Driver initialization */
/* Special commands */
while ((skb = skb_dequeue(&hdev->driver_init))) {
skb->pkt_type = HCI_COMMAND_PKT;
skb->dev = (void *) hdev;
skb_queue_tail(&hdev->cmd_q, skb);
hci_sched_cmd(hdev);
}
skb_queue_purge(&hdev->driver_init);
/* Mandatory initialization */ /* Mandatory initialization */
/* Reset */ /* Reset */
...@@ -792,6 +804,8 @@ struct hci_dev *hci_alloc_dev(void) ...@@ -792,6 +804,8 @@ struct hci_dev *hci_alloc_dev(void)
memset(hdev, 0, sizeof(struct hci_dev)); memset(hdev, 0, sizeof(struct hci_dev));
skb_queue_head_init(&hdev->driver_init);
return hdev; return hdev;
} }
EXPORT_SYMBOL(hci_alloc_dev); EXPORT_SYMBOL(hci_alloc_dev);
...@@ -799,6 +813,8 @@ EXPORT_SYMBOL(hci_alloc_dev); ...@@ -799,6 +813,8 @@ EXPORT_SYMBOL(hci_alloc_dev);
/* Free HCI device */ /* Free HCI device */
void hci_free_dev(struct hci_dev *hdev) void hci_free_dev(struct hci_dev *hdev)
{ {
skb_queue_purge(&hdev->driver_init);
/* will free via class release */ /* will free via class release */
class_device_put(&hdev->class_dev); class_device_put(&hdev->class_dev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment