Skip to content

Commit 0ea2f5a

Browse files
committed
Bluetooth: btusb: Enable Mediatek modules to work on USB 3.0 busses
MT7921U and possibly other related chips expose a different configuration on USB 3.0 vs. USB 2.0. Current driver logic only works with the USB 2.0 configuration, while connecting the module to a USB 3.0-only bus results in enumeration and scanning succeeding but connections silently failing. Add a special case for Mediatek modules on SuperSpeed busses to select the right bulk OUT endpoint (second not first) to make them work. Signed-off-by: Alexey Charkov <alchark@flipper.net>
1 parent 2535ba1 commit 0ea2f5a

1 file changed

Lines changed: 43 additions & 0 deletions

File tree

drivers/bluetooth/btusb.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4122,6 +4122,49 @@ static int btusb_probe(struct usb_interface *intf,
41224122
if (err)
41234123
goto err_free_data;
41244124

4125+
/*
4126+
* MediaTek MT7921U (and likely related MTK combo chips), when
4127+
* attached over the SuperSpeed lanes, present a HCI interface with
4128+
* *two* bulk OUT endpoints: the lower-numbered one is a vendor /
4129+
* diagnostic pipe that silently consumes data without ever raising
4130+
* a transfer-complete event, and the higher-numbered one is the
4131+
* actual ACL OUT. usb_find_common_endpoints() returns the first
4132+
* match, which sinks all outbound HCI traffic and leaves the device
4133+
* able to scan but unable to complete any connection.
4134+
*
4135+
* Most MT7921U deployments wire the Bluetooth function to the USB
4136+
* 2.0 differential pair and enumerate at High-Speed, where the
4137+
* descriptor only exposes a single bulk OUT and this code path is
4138+
* a no-op.
4139+
*/
4140+
if ((id->driver_info & BTUSB_MEDIATEK) &&
4141+
interface_to_usbdev(intf)->speed >= USB_SPEED_SUPER) {
4142+
struct usb_host_interface *alt = intf->cur_altsetting;
4143+
struct usb_endpoint_descriptor *ep, *second_bulk_out = NULL;
4144+
int i, bulk_out_count = 0;
4145+
4146+
for (i = 0; i < alt->desc.bNumEndpoints; i++) {
4147+
ep = &alt->endpoint[i].desc;
4148+
if (!usb_endpoint_is_bulk_out(ep))
4149+
continue;
4150+
if (++bulk_out_count == 2)
4151+
second_bulk_out = ep;
4152+
}
4153+
4154+
if (bulk_out_count == 2 && second_bulk_out &&
4155+
second_bulk_out != data->bulk_tx_ep) {
4156+
dev_info(&intf->dev,
4157+
"btusb: MTK: SuperSpeed: using bEP 0x%02x as ACL OUT (overrides diag bEP 0x%02x)\n",
4158+
second_bulk_out->bEndpointAddress,
4159+
data->bulk_tx_ep->bEndpointAddress);
4160+
data->bulk_tx_ep = second_bulk_out;
4161+
} else if (bulk_out_count > 2) {
4162+
dev_warn(&intf->dev,
4163+
"btusb: MTK: SuperSpeed: unexpected bulk OUT count %d, leaving default selection\n",
4164+
bulk_out_count);
4165+
}
4166+
}
4167+
41254168
if (id->driver_info & BTUSB_AMP) {
41264169
data->cmdreq_type = USB_TYPE_CLASS | 0x01;
41274170
data->cmdreq = 0x2b;

0 commit comments

Comments
 (0)