Skip to content

Commit 0671c06

Browse files
jwrdegoedeJohan Hedberg
authored andcommitted
Bluetooth: btusb: Add workaround for remote-wakeup issues with Barrot 8041a02 fake CSR controllers
With the recent btusb change to detect and deal with more fake CSR controllers, I decided to see if fake CSR controllers with Barrot 8041a02 chips would now work. After much experimentation I came to the conclusion that it works, if I have autosuspend enabled initially and then disable it after the device has suspended at least once. Yes this is very weird, but I've tried many things, like manually clearing the remote-wakeup feature. Doing a runtime-resume + runtime suspend is the only way to get the receiver to actually report received data (and/or pairing info) through its bulk rx endpoint. But the funkyness of the bulk-endpoint does not stop there, I mainly found out about this problem, because with autosuspend enabled (which usually ensures the suspend at least once condition is met), the receiver stops reporting received data through its bulk rx endpoint as soon as autosuspend kicks in. So I initially just disabled autosuspend, but then the receiver does not work at all. This was with a fake CSR receiver with a Barrot 8041a02 chip with a bcdDevice value of 0x8891, a lmp_subver of 0x1012, a hci_rev of 0x0810 and a hci_ver of BLUETOOTH_VER_4_0. Summarizing this specific fake CSR receiver has the following 2 issues: 1. The bulk rx endpoint will never report any data unless the device was suspended at least once. 2. They will not wakeup when autosuspended and receiving data on their bulk rx endpoint from e.g. a keyboard or mouse (IOW remote-wakeup support is broken for the bulk endpoint). Add a workaround for 1. which enables runtime-suspend, force-suspends the hci and then wakes-it up by disabling runtime-suspend again. Add a workaround for 2. which clears the hci's can_wake flag, this way the hci will still be autosuspended when it is not open. Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]> Signed-off-by: Johan Hedberg <[email protected]>
1 parent d74e0ae commit 0671c06

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

drivers/bluetooth/btusb.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,7 @@ static int btusb_setup_csr(struct hci_dev *hdev)
17941794
struct hci_rp_read_local_version *rp;
17951795
struct sk_buff *skb;
17961796
bool is_fake = false;
1797+
int ret;
17971798

17981799
BT_DBG("%s", hdev->name);
17991800

@@ -1882,6 +1883,43 @@ static int btusb_setup_csr(struct hci_dev *hdev)
18821883
*/
18831884
clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
18841885
clear_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
1886+
1887+
/*
1888+
* Special workaround for clones with a Barrot 8041a02 chip,
1889+
* these clones are really messed-up:
1890+
* 1. Their bulk rx endpoint will never report any data unless
1891+
* the device was suspended at least once (yes really).
1892+
* 2. They will not wakeup when autosuspended and receiving data
1893+
* on their bulk rx endpoint from e.g. a keyboard or mouse
1894+
* (IOW remote-wakeup support is broken for the bulk endpoint).
1895+
*
1896+
* To fix 1. enable runtime-suspend, force-suspend the
1897+
* hci and then wake-it up by disabling runtime-suspend.
1898+
*
1899+
* To fix 2. clear the hci's can_wake flag, this way the hci
1900+
* will still be autosuspended when it is not open.
1901+
*/
1902+
if (bcdDevice == 0x8891 &&
1903+
le16_to_cpu(rp->lmp_subver) == 0x1012 &&
1904+
le16_to_cpu(rp->hci_rev) == 0x0810 &&
1905+
le16_to_cpu(rp->hci_ver) == BLUETOOTH_VER_4_0) {
1906+
bt_dev_warn(hdev, "CSR: detected a fake CSR dongle using a Barrot 8041a02 chip, this chip is very buggy and may have issues\n");
1907+
1908+
pm_runtime_allow(&data->udev->dev);
1909+
1910+
ret = pm_runtime_suspend(&data->udev->dev);
1911+
if (ret >= 0)
1912+
msleep(200);
1913+
else
1914+
bt_dev_err(hdev, "Failed to suspend the device for Barrot 8041a02 receive-issue workaround\n");
1915+
1916+
pm_runtime_forbid(&data->udev->dev);
1917+
1918+
device_set_wakeup_capable(&data->udev->dev, false);
1919+
/* Re-enable autosuspend if this was requested */
1920+
if (enable_autosuspend)
1921+
usb_enable_autosuspend(data->udev);
1922+
}
18851923
}
18861924

18871925
kfree_skb(skb);

0 commit comments

Comments
 (0)