Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: btusb: Add support for latest Apple controllers

The latest Apple Bluetooth controllers with Broadcom chip in it have
a small design change. Instead of including a USB hub with mouse and
keyboard devices, they are now HID interfaces on the same device.

T: Bus=04 Lev=02 Prnt=02 Port=04 Cnt=01 Dev#= 39 Spd=12 MxCh= 0
D: Ver= 2.01 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=05ac ProdID=8290 Rev= 0.79
S: Manufacturer=Broadcom Corp.
S: Product=Bluetooth USB Host Controller
C:* #Ifs= 6 Cfg#= 1 Atr=e0 MxPwr= 0mA
A: FirstIf#= 2 IfCount= 4 Cls=ff(vend.) Sub=01 Prot=01
I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=01 Driver=usbhid
E: Ad=85(I) Atr=03(Int.) MxPS= 8 Ivl=10ms
I:* If#= 1 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=usbhid
E: Ad=86(I) Atr=03(Int.) MxPS= 8 Ivl=10ms
I:* If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
I: If#= 3 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
I: If#= 3 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
I: If#= 3 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
I: If#= 3 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
I: If#= 3 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
I:* If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=btusb
E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
I:* If#= 5 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)

The general layout of Bluetooth devices is that interface 0 is the main
interface and interface 1 is for audio data. This design obviously moves
it to main interface 2 and audio data on interface 3.

Starting with the MacBookPro12,1 (early 2015 models) the new Broadcom
BCM943602CS cards are used which show this interface layout.

usb 4-1.5: New USB device found, idVendor=05ac, idProduct=8290
usb 4-1.5: New USB device strings: Mfr=1, Product=2, SerialNumber=0
usb 4-1.5: Product: Bluetooth USB Host Controller
usb 4-1.5: Manufacturer: Broadcom Corp.
Bluetooth: hci0: BCM: chip id 102 build 0243
Bluetooth: hci0: BCM: product 05ac:8290
Bluetooth: hci0: BCM20703A1 Generic USB UHE Apple 20Mhz fcbga_X87

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>

+15 -7
+15 -7
drivers/bluetooth/btusb.c
··· 61 61 #define BTUSB_BCM_APPLE 0x10000 62 62 #define BTUSB_REALTEK 0x20000 63 63 #define BTUSB_BCM2045 0x40000 64 + #define BTUSB_IFNUM_2 0x80000 64 65 65 66 static const struct usb_device_id btusb_table[] = { 66 67 /* Generic Bluetooth USB device */ ··· 75 74 76 75 /* Apple-specific (Broadcom) devices */ 77 76 { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01), 78 - .driver_info = BTUSB_BCM_APPLE }, 77 + .driver_info = BTUSB_BCM_APPLE | BTUSB_IFNUM_2 }, 79 78 80 79 /* MediaTek MT76x0E */ 81 80 { USB_DEVICE(0x0e8d, 0x763f) }, ··· 2759 2758 struct usb_endpoint_descriptor *ep_desc; 2760 2759 struct btusb_data *data; 2761 2760 struct hci_dev *hdev; 2761 + unsigned ifnum_base; 2762 2762 int i, err; 2763 2763 2764 2764 BT_DBG("intf %p id %p", intf, id); 2765 2765 2766 2766 /* interface numbers are hardcoded in the spec */ 2767 - if (intf->cur_altsetting->desc.bInterfaceNumber != 0) 2768 - return -ENODEV; 2767 + if (intf->cur_altsetting->desc.bInterfaceNumber != 0) { 2768 + if (!(id->driver_info & BTUSB_IFNUM_2)) 2769 + return -ENODEV; 2770 + if (intf->cur_altsetting->desc.bInterfaceNumber != 2) 2771 + return -ENODEV; 2772 + } 2773 + 2774 + ifnum_base = intf->cur_altsetting->desc.bInterfaceNumber; 2769 2775 2770 2776 if (!id->driver_info) { 2771 2777 const struct usb_device_id *match; ··· 2888 2880 hdev->set_bdaddr = btbcm_set_bdaddr; 2889 2881 2890 2882 /* Broadcom LM_DIAG Interface numbers are hardcoded */ 2891 - data->diag = usb_ifnum_to_if(data->udev, 2); 2883 + data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2); 2892 2884 } 2893 2885 2894 2886 if (id->driver_info & BTUSB_BCM_APPLE) { ··· 2897 2889 hdev->set_diag = btusb_bcm_set_diag; 2898 2890 2899 2891 /* Broadcom LM_DIAG Interface numbers are hardcoded */ 2900 - data->diag = usb_ifnum_to_if(data->udev, 2); 2892 + data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2); 2901 2893 } 2902 2894 #endif 2903 2895 ··· 2961 2953 /* AMP controllers do not support SCO packets */ 2962 2954 data->isoc = NULL; 2963 2955 } else { 2964 - /* Interface numbers are hardcoded in the specification */ 2965 - data->isoc = usb_ifnum_to_if(data->udev, 1); 2956 + /* Interface orders are hardcoded in the specification */ 2957 + data->isoc = usb_ifnum_to_if(data->udev, ifnum_base + 1); 2966 2958 } 2967 2959 2968 2960 if (!reset)