Skip to content

Instantly share code, notes, and snippets.

@pmp-p
Forked from nevack/archived.md
Created June 10, 2020 16:30
Show Gist options
  • Save pmp-p/e9e0502affcca582966962d7800c693f to your computer and use it in GitHub Desktop.
Save pmp-p/e9e0502affcca582966962d7800c693f to your computer and use it in GitHub Desktop.
Fix for CSR Dongle 0a12:0001 ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
#!/usr/bin/env sh
version="${1:-$(uname -r | cut -d'-' -f1)}"
extra="${2:-$(uname -r | cut -d'-' -f2-)}"
fullversion="$version-$extra"
echo Making patch for kernel $fullversion
name="linux-$version"
archive="$name.tar.xz"
echo Downloading kernel $name
wget -c https://cdn.kernel.org/pub/linux/kernel/v5.x/$archive -O $archive
echo Extracting $archive
tar -xJf $archive
echo Setting up kernel config
make -C $name mrproper
cp /usr/lib/modules/$fullversion/build/.config $name/
cp /usr/lib/modules/$fullversion/build/Module.symvers $name/
make -C $name oldconfig
echo Applying btusb fix
patch -p1 -d $name < fix_btusb.patch
echo Making bluetooth kernel module
make -C $name EXTRAVERSION=-$extra modules_prepare
make -C $name M=drivers/bluetooth
xz $name/drivers/bluetooth/btusb.ko
echo Installing
sudo mkdir -p /usr/lib/modules/$fullversion/updates
sudo cp -f $name/drivers/bluetooth/btusb.ko.xz /usr/lib/modules/$fullversion/updates/btusb.ko.xz
sudo mkinitcpio -p linux
echo Removing temp files
rm -f $archive
rm -rf $name
if [ "$fullversion" = "$(uname -r)" ]; then
sudo depmod
sudo modeprobe -r btusb
sudo modeprobe btusb
else
echo Now you can reboot to the new kernel version
fi
options btusb fixups=0x0800000:0x000004:0x0a12:0x0001:0x8891
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index a9c35ebb30f8..d52a760bb2b4 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -26,7 +26,12 @@
#include "btrtl.h"
#define VERSION "0.8"
+const char *driver_name = "btusb";
+static char *fixups[8];
+static int nfixups;
+static unsigned long disable_fixups;
+static unsigned long force_fixups;
static bool disable_scofix;
static bool force_scofix;
static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND);
@@ -53,11 +58,22 @@ static struct usb_driver btusb_driver;
#define BTUSB_QCA_ROME 0x8000
#define BTUSB_BCM_APPLE 0x10000
#define BTUSB_REALTEK 0x20000
-#define BTUSB_BCM2045 0x40000
+#define BTUSB_BCM2045 0x40000 /* May be replaced by BTUSB_BROKEN_SLK */
#define BTUSB_IFNUM_2 0x80000
-#define BTUSB_CW6622 0x100000
+#define BTUSB_CW6622 0x100000 /* May be replaced by BTUSB_BROKEN_SLK */
#define BTUSB_MEDIATEK 0x200000
+#define BTUSB_FAKECSR 0x00400000
+
+#define BTUSB_BROKEN_SLK 0x00800000 /* HCI_QUIRK_BROKEN_STORED_LINK_KEY */
+#define BTUSB_SIM_DISC 0x01000000 /* HCI_QUIRK_SIMULTANEOUS_DISCOVERY */
+#define BTUSB_NP_SETUP 0x02000000 /* HCI_QUIRK_NON_PERSISTENT_SETUP */
+#define BTUSB_ROC 0x04000000 /* HCI_QUIRK_RESET_ON_CLOSE */
+#define BTUSB_RAWDEV 0x08000000 /* HCI_QUIRK_RAW_DEVICE */
+#define BTUSB_INQMODE 0x10000000 /* HCI_QUIRK_FIXUP_INQUIRY_MODE */
+#define BTUSB_LOCALCOMM 0x20000000 /* HCI_QUIRK_BROKEN_LOCAL_COMMANDS */
+#define BTUSB_DUPFILTER 0x40000000 /* HCI_QUIRK_STRICT_DUPLICATE_FILTER */
+
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
@@ -1642,7 +1658,8 @@ static int btusb_setup_csr(struct hci_de
/* Detect controllers which aren't real CSR ones. */
if (le16_to_cpu(rp->manufacturer) != 10 ||
- le16_to_cpu(rp->lmp_subver) == 0x0c5c) {
+ le16_to_cpu(rp->lmp_subver) == 0x0c5c ||
+ le16_to_cpu(rp->lmp_subver) == 0x0811) {
/* Clear the reset quirk since this is not an actual
* early Bluetooth 1.1 device from CSR.
*/
@@ -3584,6 +3601,32 @@ static void btusb_check_needs_reset_resu
interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
}
+static void parse_fixup_args(int idVendor, int idProduct, u16 bcdDevice)
+{
+ int i;
+ unsigned int vendor = 0, product = 0, bcddev = 0;
+ unsigned long force = 0, disable = 0;
+
+ for (i = 0; i < nfixups; i++) {
+ int n;
+
+ n = sscanf(fixups[i], "%lx:%lx:%x:%x:%x", &force, &disable,
+ &vendor, &product, &bcddev);
+
+ if ((!bcddev || bcddev == bcdDevice) &&
+ (!product || product == idProduct) &&
+ (!vendor || vendor == idVendor)
+ ) {
+ pr_info("%s: New fixups. Device: 0x%04x:0x%04x/0x%04x. Rule %u/%u (%u terms): 0x%04x:0x%04x/0x%04x",
+ driver_name, idVendor, idProduct, bcdDevice,
+ i+1, nfixups, n, vendor, product, bcddev);
+ force_fixups = force;
+ disable_fixups = disable;
+ break;
+ }
+ }
+}
+
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -3593,6 +3636,9 @@ static int btusb_probe(struct usb_interf
struct hci_dev *hdev;
unsigned ifnum_base;
int i, err;
+ unsigned long info;
+ struct usb_device *udev;
+ u16 bcdDevice;
BT_DBG("intf %p id %p", intf, id);
@@ -3614,11 +3660,24 @@ static int btusb_probe(struct usb_interf
id = match;
}
- if (id->driver_info == BTUSB_IGNORE)
+ udev = interface_to_usbdev(intf);
+ bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);
+ parse_fixup_args(id->idVendor, id->idProduct, bcdDevice);
+
+ if (force_fixups | disable_fixups) {
+ info = (id->driver_info | force_fixups) & ~disable_fixups;
+ pr_info("%s: driver flags: initial => 0x%016lx", driver_name,
+ id->driver_info);
+ pr_info("%s: driver flags: masked => 0x%016lx", driver_name,
+ info);
+ } else {
+ info = id->driver_info;
+ }
+
+ if (info & BTUSB_IGNORE)
return -ENODEV;
- if (id->driver_info & BTUSB_ATH3012) {
- struct usb_device *udev = interface_to_usbdev(intf);
+ if (info & BTUSB_ATH3012) {
/* Old firmware would otherwise let ath3k driver load
* patch and sysconfig files
@@ -3654,7 +3713,7 @@ static int btusb_probe(struct usb_interf
if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
return -ENODEV;
- if (id->driver_info & BTUSB_AMP) {
+ if (info & BTUSB_AMP) {
data->cmdreq_type = USB_TYPE_CLASS | 0x01;
data->cmdreq = 0x2b;
} else {
@@ -3662,7 +3721,7 @@ static int btusb_probe(struct usb_interf
data->cmdreq = 0x00;
}
- data->udev = interface_to_usbdev(intf);
+ data->udev = udev;
data->intf = intf;
INIT_WORK(&data->work, btusb_work);
@@ -3678,7 +3737,7 @@ static int btusb_probe(struct usb_interf
init_usb_anchor(&data->ctrl_anchor);
spin_lock_init(&data->rxlock);
- if (id->driver_info & BTUSB_INTEL_NEW) {
+ if (info & BTUSB_INTEL_NEW) {
data->recv_event = btusb_recv_event_intel;
data->recv_bulk = btusb_recv_bulk_intel;
set_bit(BTUSB_BOOTLOADER, &data->flags);
@@ -3694,7 +3753,7 @@ static int btusb_probe(struct usb_interf
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
- if (id->driver_info & BTUSB_AMP)
+ if (info & BTUSB_AMP)
hdev->dev_type = HCI_AMP;
else
hdev->dev_type = HCI_PRIMARY;
@@ -3724,23 +3783,23 @@ static int btusb_probe(struct usb_interf
goto out_free_dev;
/* Marvell devices may need a specific chip configuration */
- if (id->driver_info & BTUSB_MARVELL && data->oob_wake_irq) {
+ if (info & BTUSB_MARVELL && data->oob_wake_irq) {
err = marvell_config_oob_wake(hdev);
if (err)
goto out_free_dev;
}
#endif
- if (id->driver_info & BTUSB_CW6622)
+ if (info & BTUSB_CW6622)
set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
- if (id->driver_info & BTUSB_BCM2045)
+ if (info & BTUSB_BCM2045)
set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
- if (id->driver_info & BTUSB_BCM92035)
+ if (info & BTUSB_BCM92035)
hdev->setup = btusb_setup_bcm92035;
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) &&
- (id->driver_info & BTUSB_BCM_PATCHRAM)) {
+ (info & BTUSB_BCM_PATCHRAM)) {
hdev->manufacturer = 15;
hdev->setup = btbcm_setup_patchram;
hdev->set_diag = btusb_bcm_set_diag;
@@ -3751,7 +3810,7 @@ static int btusb_probe(struct usb_interf
}
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_BCM) &&
- (id->driver_info & BTUSB_BCM_APPLE)) {
+ (info & BTUSB_BCM_APPLE)) {
hdev->manufacturer = 15;
hdev->setup = btbcm_setup_apple;
hdev->set_diag = btusb_bcm_set_diag;
@@ -3760,7 +3819,7 @@ static int btusb_probe(struct usb_interf
data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
}
- if (id->driver_info & BTUSB_INTEL) {
+ if (info & BTUSB_INTEL) {
hdev->manufacturer = 2;
hdev->setup = btusb_setup_intel;
hdev->shutdown = btusb_shutdown_intel;
@@ -3772,7 +3831,7 @@ static int btusb_probe(struct usb_interf
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
}
- if (id->driver_info & BTUSB_INTEL_NEW) {
+ if (info & BTUSB_INTEL_NEW) {
hdev->manufacturer = 2;
hdev->send = btusb_send_frame_intel;
hdev->setup = btusb_setup_intel_new;
@@ -3786,35 +3845,35 @@ static int btusb_probe(struct usb_interf
set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
}
- if (id->driver_info & BTUSB_MARVELL)
+ if (info & BTUSB_MARVELL)
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_MTK) &&
- (id->driver_info & BTUSB_MEDIATEK)) {
+ (info & BTUSB_MEDIATEK)) {
hdev->setup = btusb_mtk_setup;
hdev->shutdown = btusb_mtk_shutdown;
hdev->manufacturer = 70;
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
}
- if (id->driver_info & BTUSB_SWAVE) {
+ if (info & BTUSB_SWAVE) {
set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
}
- if (id->driver_info & BTUSB_INTEL_BOOT) {
+ if (info & BTUSB_INTEL_BOOT) {
hdev->manufacturer = 2;
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
}
- if (id->driver_info & BTUSB_ATH3012) {
+ if (info & BTUSB_ATH3012) {
data->setup_on_usb = btusb_setup_qca;
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
}
- if (id->driver_info & BTUSB_QCA_ROME) {
+ if (info & BTUSB_QCA_ROME) {
data->setup_on_usb = btusb_setup_qca;
hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
@@ -3822,7 +3881,7 @@ static int btusb_probe(struct usb_interf
}
if (IS_ENABLED(CONFIG_BT_HCIBTUSB_RTL) &&
- (id->driver_info & BTUSB_REALTEK)) {
+ (info & BTUSB_REALTEK)) {
hdev->setup = btrtl_setup_realtek;
hdev->shutdown = btrtl_shutdown_realtek;
hdev->cmd_timeout = btusb_rtl_cmd_timeout;
@@ -3838,7 +3897,7 @@ static int btusb_probe(struct usb_interf
goto out_free_dev;
}
- if (id->driver_info & BTUSB_AMP) {
+ if (info & BTUSB_AMP) {
/* AMP controllers do not support SCO packets */
data->isoc = NULL;
} else {
@@ -3850,43 +3909,38 @@ static int btusb_probe(struct usb_interf
if (!reset)
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
- if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
+ if (force_scofix || info & BTUSB_WRONG_SCO_MTU) {
if (!disable_scofix)
set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
}
- if (id->driver_info & BTUSB_BROKEN_ISOC)
+ if (info & BTUSB_BROKEN_ISOC)
data->isoc = NULL;
- if (id->driver_info & BTUSB_DIGIANSWER) {
+ if (info & BTUSB_DIGIANSWER) {
data->cmdreq_type = USB_TYPE_VENDOR;
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
}
- if (id->driver_info & BTUSB_CSR) {
- struct usb_device *udev = data->udev;
- u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);
-
+ if (info & BTUSB_CSR) {
/* Old firmware would otherwise execute USB reset */
if (bcdDevice < 0x117)
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
/* Fake CSR devices with broken commands */
- if (bcdDevice <= 0x100 || bcdDevice == 0x134)
+ if (bcdDevice <= 0x100 || bcdDevice == 0x134 || bcdDevice == 0x8891)
hdev->setup = btusb_setup_csr;
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
}
- if (id->driver_info & BTUSB_SNIFFER) {
- struct usb_device *udev = data->udev;
-
+ if (info & BTUSB_SNIFFER) {
/* New sniffer firmware has crippled HCI interface */
- if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
+ if (bcdDevice > 0x997)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
}
- if (id->driver_info & BTUSB_INTEL_BOOT) {
+ if (info & BTUSB_INTEL_BOOT) {
/* A bug in the bootloader causes that interrupt interface is
* only enabled after receiving SetInterface(0, AltSetting=0).
*/
@@ -3897,6 +3951,46 @@ static int btusb_probe(struct usb_interf
}
}
+ if (disable_fixups & BTUSB_BROKEN_SLK)
+ clear_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
+ else if (force_fixups & BTUSB_BROKEN_SLK)
+ set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
+
+ if (disable_fixups & BTUSB_ROC)
+ clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+ else if (force_fixups & BTUSB_ROC)
+ set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+ if (disable_fixups & BTUSB_SIM_DISC)
+ clear_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
+ else if (force_fixups & BTUSB_SIM_DISC)
+ set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
+
+ if (disable_fixups & BTUSB_NP_SETUP)
+ clear_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
+ else if (force_fixups & BTUSB_NP_SETUP)
+ set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
+
+ if (disable_fixups & BTUSB_RAWDEV)
+ clear_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+ else if (force_fixups & BTUSB_RAWDEV)
+ set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+
+ if (disable_fixups & BTUSB_INQMODE)
+ clear_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
+ else if (force_fixups & BTUSB_INQMODE)
+ set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
+
+ if (disable_fixups & BTUSB_LOCALCOMM)
+ clear_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
+ else if (force_fixups & BTUSB_LOCALCOMM)
+ set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
+
+ if (disable_fixups & BTUSB_DUPFILTER)
+ clear_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+ else if (force_fixups & BTUSB_DUPFILTER)
+ set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+
if (data->isoc) {
err = usb_driver_claim_interface(&btusb_driver,
data->isoc, data);
@@ -4131,6 +4225,9 @@ static struct usb_driver btusb_driver =
module_usb_driver(btusb_driver);
+module_param_array(fixups, charp, &nfixups, 0644);
+MODULE_PARM_DESC(disable_fixups, "Control up to 8 fixups (final = default | force_fixups & ~disable_fixups). Syntax: fixups=<force_hex>[:<disable_hex>[:<vendor_hex>[:<model_hex>[:<bcdDevice>]]]]");
+
module_param(disable_scofix, bool, 0644);
MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment