From: Olivier Galibert Some bluetooth adapters return an incorrect number of sco packets in READ_BUFFER_SIZE. Add a quirk hook to fix it from the driver side, and use the hook for a first adapter. This is definitively not limited to broadcom USB devices, googling for "SCO MTU 64:0" has interesting results. Signed-off-by: Olivier Galibert Cc: Pavel Machek Cc: Marcel Holtmann Cc: Greg KH Signed-off-by: Andrew Morton --- drivers/bluetooth/hci_usb.c | 12 ++++++++++++ drivers/bluetooth/hci_usb.h | 1 + include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_event.c | 23 +++++++++++++++++++++-- 4 files changed, 35 insertions(+), 2 deletions(-) diff -puN drivers/bluetooth/hci_usb.c~fix-sco-on-some-bluetooth-adapters drivers/bluetooth/hci_usb.c --- devel/drivers/bluetooth/hci_usb.c~fix-sco-on-some-bluetooth-adapters 2006-04-27 02:33:11.000000000 -0700 +++ devel-akpm/drivers/bluetooth/hci_usb.c 2006-04-27 02:33:11.000000000 -0700 @@ -130,6 +130,9 @@ static struct usb_device_id blacklist_id /* CSR BlueCore Bluetooth Sniffer */ { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER }, + /* Belkin F8T012 */ + { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_READ_BUFFER_SIZE }, + { } /* Terminating entry */ }; @@ -817,6 +820,12 @@ static void hci_usb_notify(struct hci_de BT_DBG("%s evt %d", hdev->name, evt); } +static void hci_usb_quirk_read_buffer_size(struct hci_dev *hdev) +{ + if (!hdev->sco_pkts) + hdev->sco_pkts = 8; +} + static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); @@ -985,6 +994,9 @@ static int hci_usb_probe(struct usb_inte if (reset || id->driver_info & HCI_RESET) set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (id->driver_info & HCI_READ_BUFFER_SIZE) + hdev->quirk_read_buffer_size = hci_usb_quirk_read_buffer_size; + if (id->driver_info & HCI_SNIFFER) { if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); diff -puN drivers/bluetooth/hci_usb.h~fix-sco-on-some-bluetooth-adapters drivers/bluetooth/hci_usb.h --- devel/drivers/bluetooth/hci_usb.h~fix-sco-on-some-bluetooth-adapters 2006-04-27 02:33:11.000000000 -0700 +++ devel-akpm/drivers/bluetooth/hci_usb.h 2006-04-27 02:33:11.000000000 -0700 @@ -35,6 +35,7 @@ #define HCI_SNIFFER 0x10 #define HCI_BCM92035 0x20 #define HCI_BROKEN_ISOC 0x40 +#define HCI_READ_BUFFER_SIZE 0x80 #define HCI_MAX_IFACE_NUM 3 diff -puN include/net/bluetooth/hci_core.h~fix-sco-on-some-bluetooth-adapters include/net/bluetooth/hci_core.h --- devel/include/net/bluetooth/hci_core.h~fix-sco-on-some-bluetooth-adapters 2006-04-27 02:33:11.000000000 -0700 +++ devel-akpm/include/net/bluetooth/hci_core.h 2006-04-27 02:33:11.000000000 -0700 @@ -134,6 +134,7 @@ struct hci_dev { void (*destruct)(struct hci_dev *hdev); void (*notify)(struct hci_dev *hdev, unsigned int evt); int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); + void (*quirk_read_buffer_size)(struct hci_dev *hdev); }; struct hci_conn { diff -puN net/bluetooth/hci_event.c~fix-sco-on-some-bluetooth-adapters net/bluetooth/hci_event.c --- devel/net/bluetooth/hci_event.c~fix-sco-on-some-bluetooth-adapters 2006-04-27 02:33:11.000000000 -0700 +++ devel-akpm/net/bluetooth/hci_event.c 2006-04-27 02:33:18.000000000 -0700 @@ -321,8 +321,27 @@ static void hci_cc_info_param(struct hci hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64; - hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); - hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); + hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt); + hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt); + + if (hdev->quirk_read_buffer_size) + hdev->quirk_read_buffer_size(hdev); + + if (!hdev->acl_mtu || !hdev->sco_mtu || !hdev->acl_pkts || + !hdev->sco_pkts) { + printk(KERN_WARNING "Your Bluetooth adapter has an " + "incorrect OCF_READ_BUFFER_SIZE reply " + "(%d:%d, %d:%d)\n", + hdev->acl_mtu, hdev->acl_pkts, hdev->sco_mtu, + hdev->sco_pkts); + printk(KERN_WARNING "It won't work correctly. Please " + "contact Marcel Holtmann " + "with information about your device to try " + "workarounds.\n"); + } + + hdev->acl_cnt = hdev->acl_pkts; + hdev->sco_cnt = hdev->sco_pkts; BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); _