Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/bluetooth/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 127 kB image not shown  

Quelle  btusb.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *
 *  Generic Bluetooth USB driver
 *
 *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
 */


#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/firmware.h>
#include <linux/iopoll.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/suspend.h>
#include <linux/gpio/consumer.h>
#include <linux/debugfs.h>
#include <linux/unaligned.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_drv.h>

#include "btintel.h"
#include "btbcm.h"
#include "btrtl.h"
#include "btmtk.h"

#define VERSION "0.8"

static bool disable_scofix;
static bool force_scofix;
static bool enable_autosuspend = IS_ENABLED(CONFIG_BT_HCIBTUSB_AUTOSUSPEND);
static bool enable_poll_sync = IS_ENABLED(CONFIG_BT_HCIBTUSB_POLL_SYNC);
static bool reset = true;

static struct usb_driver btusb_driver;

#define BTUSB_IGNORE   BIT(0)
#define BTUSB_DIGIANSWER  BIT(1)
#define BTUSB_CSR   BIT(2)
#define BTUSB_SNIFFER   BIT(3)
#define BTUSB_BCM92035   BIT(4)
#define BTUSB_BROKEN_ISOC  BIT(5)
#define BTUSB_WRONG_SCO_MTU  BIT(6)
#define BTUSB_ATH3012   BIT(7)
#define BTUSB_INTEL_COMBINED  BIT(8)
#define BTUSB_INTEL_BOOT  BIT(9)
#define BTUSB_BCM_PATCHRAM  BIT(10)
#define BTUSB_MARVELL   BIT(11)
#define BTUSB_SWAVE   BIT(12)
#define BTUSB_AMP   BIT(13)
#define BTUSB_QCA_ROME   BIT(14)
#define BTUSB_BCM_APPLE   BIT(15)
#define BTUSB_REALTEK   BIT(16)
#define BTUSB_BCM2045   BIT(17)
#define BTUSB_IFNUM_2   BIT(18)
#define BTUSB_CW6622   BIT(19)
#define BTUSB_MEDIATEK   BIT(20)
#define BTUSB_WIDEBAND_SPEECH  BIT(21)
#define BTUSB_INVALID_LE_STATES  BIT(22)
#define BTUSB_QCA_WCN6855  BIT(23)
#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED BIT(24)
#define BTUSB_INTEL_BROKEN_INITIAL_NCMD BIT(25)
#define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26)
#define BTUSB_ACTIONS_SEMI  BIT(27)
#define BTUSB_BARROT   BIT(28)

static const struct usb_device_id btusb_table[] = {
 /* Generic Bluetooth USB device */
 { USB_DEVICE_INFO(0xe0, 0x01, 0x01) },

 /* Generic Bluetooth AMP device */
 { USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP },

 /* Generic Bluetooth USB interface */
 { USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },

 /* Apple-specific (Broadcom) devices */
 { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_APPLE | BTUSB_IFNUM_2 },

 /* MediaTek MT76x0E */
 { USB_DEVICE(0x0e8d, 0x763f) },

 /* Broadcom SoftSailing reporting vendor specific */
 { USB_DEVICE(0x0a5c, 0x21e1) },

 /* Apple MacBookPro 7,1 */
 { USB_DEVICE(0x05ac, 0x8213) },

 /* Apple iMac11,1 */
 { USB_DEVICE(0x05ac, 0x8215) },

 /* Apple MacBookPro6,2 */
 { USB_DEVICE(0x05ac, 0x8218) },

 /* Apple MacBookAir3,1, MacBookAir3,2 */
 { USB_DEVICE(0x05ac, 0x821b) },

 /* Apple MacBookAir4,1 */
 { USB_DEVICE(0x05ac, 0x821f) },

 /* Apple MacBookPro8,2 */
 { USB_DEVICE(0x05ac, 0x821a) },

 /* Apple MacMini5,1 */
 { USB_DEVICE(0x05ac, 0x8281) },

 /* AVM BlueFRITZ! USB v2.0 */
 { USB_DEVICE(0x057c, 0x3800), .driver_info = BTUSB_SWAVE },

 /* Bluetooth Ultraport Module from IBM */
 { USB_DEVICE(0x04bf, 0x030a) },

 /* ALPS Modules with non-standard id */
 { USB_DEVICE(0x044e, 0x3001) },
 { USB_DEVICE(0x044e, 0x3002) },

 /* Ericsson with non-standard id */
 { USB_DEVICE(0x0bdb, 0x1002) },

 /* Canyon CN-BTU1 with HID interfaces */
 { USB_DEVICE(0x0c10, 0x0000) },

 /* Broadcom BCM20702B0 (Dynex/Insignia) */
 { USB_DEVICE(0x19ff, 0x0239), .driver_info = BTUSB_BCM_PATCHRAM },

 /* Broadcom BCM43142A0 (Foxconn/Lenovo) */
 { USB_VENDOR_AND_INTERFACE_INFO(0x105b, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Broadcom BCM920703 (HTC Vive) */
 { USB_VENDOR_AND_INTERFACE_INFO(0x0bb4, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Foxconn - Hon Hai */
 { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Lite-On Technology - Broadcom based */
 { USB_VENDOR_AND_INTERFACE_INFO(0x04ca, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Broadcom devices with vendor specific id */
 { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* ASUSTek Computer - Broadcom based */
 { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Belkin F8065bf - Broadcom based */
 { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* IMC Networks - Broadcom based */
 { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Dell Computer - Broadcom based  */
 { USB_VENDOR_AND_INTERFACE_INFO(0x413c, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Toshiba Corp - Broadcom based */
 { USB_VENDOR_AND_INTERFACE_INFO(0x0930, 0xff, 0x01, 0x01),
   .driver_info = BTUSB_BCM_PATCHRAM },

 /* Intel Bluetooth USB Bootloader (RAM module) */
 { USB_DEVICE(0x8087, 0x0a5a),
   .driver_info = BTUSB_INTEL_BOOT | BTUSB_BROKEN_ISOC },

 { } /* Terminating entry */
};

MODULE_DEVICE_TABLE(usb, btusb_table);

static const struct usb_device_id quirks_table[] = {
 /* CSR BlueCore devices */
 { USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR },

 /* Broadcom BCM2033 without firmware */
 { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },

 /* Broadcom BCM2045 devices */
 { USB_DEVICE(0x0a5c, 0x2045), .driver_info = BTUSB_BCM2045 },

 /* Atheros 3011 with sflash firmware */
 { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
 { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
 { USB_DEVICE(0x04f2, 0xaff1), .driver_info = BTUSB_IGNORE },
 { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
 { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
 { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
 { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },

 /* Atheros AR9285 Malbec with sflash firmware */
 { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },

 /* Atheros 3012 with sflash firmware */
 { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe05f), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe076), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe078), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe095), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x300d), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x300f), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3010), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3014), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x04ca, 0x3018), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0930, 0x021c), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x311f), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0x817b), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0cf3, 0xe006), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3395), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3472), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3474), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3487), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x13d3, 0x3490), .driver_info = BTUSB_ATH3012 },

 /* Atheros AR5BBU12 with sflash firmware */
 { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },

 /* Atheros AR5BBU12 with sflash firmware */
 { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },
 { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },

 /* QCA ROME chipset */
 { USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe500), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3021), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME |
           BTUSB_WIDEBAND_SPEECH },

 /* QCA WCN6855 chipset */
 { USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0ca), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3a22), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3a24), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3a26), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x28de, 0x1401), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },

 /* QCA WCN785x chipset */
 { USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0fc), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0f3), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe100), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe103), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe10a), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe10d), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe11b), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe11c), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe11f), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe141), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe14a), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe14b), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe14d), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3623), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3624), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2c7c, 0x0130), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2c7c, 0x0131), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2c7c, 0x0132), .driver_info = BTUSB_QCA_WCN6855 |
           BTUSB_WIDEBAND_SPEECH },

 /* Broadcom BCM2035 */
 { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
 { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
 { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* Broadcom BCM2045 */
 { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
 { USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* IBM/Lenovo ThinkPad with Broadcom chip */
 { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU },
 { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* HP laptop with Broadcom chip */
 { USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* Dell laptop with Broadcom chip */
 { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* Dell Wireless 370 and 410 devices */
 { USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_WRONG_SCO_MTU },
 { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* Belkin F8T012 and F8T013 devices */
 { USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_WRONG_SCO_MTU },
 { USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* Asus WL-BTD202 device */
 { USB_DEVICE(0x0b05, 0x1715), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* Kensington Bluetooth USB adapter */
 { USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_WRONG_SCO_MTU },

 /* RTX Telecom based adapters with buggy SCO support */
 { USB_DEVICE(0x0400, 0x0807), .driver_info = BTUSB_BROKEN_ISOC },
 { USB_DEVICE(0x0400, 0x080a), .driver_info = BTUSB_BROKEN_ISOC },

 /* CONWISE Technology based adapters with buggy SCO support */
 { USB_DEVICE(0x0e5e, 0x6622),
   .driver_info = BTUSB_BROKEN_ISOC | BTUSB_CW6622},

 /* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
 { USB_DEVICE(0x1310, 0x0001), .driver_info = BTUSB_SWAVE },

 /* Digianswer devices */
 { USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
 { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },

 /* CSR BlueCore Bluetooth Sniffer */
 { USB_DEVICE(0x0a12, 0x0002),
   .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC },

 /* Frontline ComProbe Bluetooth Sniffer */
 { USB_DEVICE(0x16d3, 0x0002),
   .driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC },

 /* Marvell Bluetooth devices */
 { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL },
 { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
 { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL },

 /* Intel Bluetooth devices */
 { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0029), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0032), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0035), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0036), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0037), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0038), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0039), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
 { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
           BTUSB_INTEL_NO_WBS_SUPPORT |
           BTUSB_INTEL_BROKEN_INITIAL_NCMD |
           BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
 { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED |
           BTUSB_INTEL_NO_WBS_SUPPORT |
           BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
 { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_COMBINED },
 { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED |
           BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
 { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_COMBINED },

 /* Other Intel Bluetooth devices */
 { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01),
   .driver_info = BTUSB_IGNORE },

 /* Realtek 8821CE Bluetooth devices */
 { USB_DEVICE(0x13d3, 0x3529), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8822CE Bluetooth devices */
 { USB_DEVICE(0x0bda, 0xb00c), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0xc822), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8822CU Bluetooth devices */
 { USB_DEVICE(0x13d3, 0x3549), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8851BE Bluetooth devices */
 { USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3601), .driver_info = BTUSB_REALTEK },

 /* Realtek 8851BU Bluetooth devices */
 { USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2001, 0x332a), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8852AE Bluetooth devices */
 { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0xc852), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0x385a), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0x4852), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04c5, 0x165c), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x4006), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cb8, 0xc549), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8852CE Bluetooth devices */
 { USB_DEVICE(0x04ca, 0x4007), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04c5, 0x1675), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cb8, 0xc558), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3587), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3586), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3592), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe122), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8852BE Bluetooth devices */
 { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0x4853), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0xb85b), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3570), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3572), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3618), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8852BT/8852BE-VT Bluetooth devices */
 { USB_DEVICE(0x0bda, 0x8520), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek 8922AE Bluetooth devices */
 { USB_DEVICE(0x0bda, 0x8922), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3617), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3616), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe130), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Realtek Bluetooth devices */
 { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
   .driver_info = BTUSB_REALTEK },

 /* MediaTek Bluetooth devices */
 { USB_VENDOR_AND_INTERFACE_INFO(0x0e8d, 0xe0, 0x01, 0x01),
   .driver_info = BTUSB_MEDIATEK |
    BTUSB_WIDEBAND_SPEECH },

 /* Additional MediaTek MT7615E Bluetooth devices */
 { USB_DEVICE(0x13d3, 0x3560), .driver_info = BTUSB_MEDIATEK},

 /* Additional MediaTek MT7663 Bluetooth devices */
 { USB_DEVICE(0x043e, 0x310c), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3801), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Additional MediaTek MT7668 Bluetooth devices */
 { USB_DEVICE(0x043e, 0x3109), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Additional MediaTek MT7920 Bluetooth devices */
 { USB_DEVICE(0x0489, 0xe134), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3620), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3621), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3622), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Additional MediaTek MT7921 Bluetooth devices */
 { USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0cd), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0e0), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0e8d, 0x0608), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3563), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3564), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3567), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3576), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3578), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3583), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3606), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },

 /* MediaTek MT7922 Bluetooth devices */
 { USB_DEVICE(0x13d3, 0x3585), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3610), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },

 /* MediaTek MT7922A Bluetooth devices */
 { USB_DEVICE(0x0489, 0xe0d8), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0d9), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0e2), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0e4), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0f1), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0f2), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0f5), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe0f6), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe102), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe152), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3568), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3584), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3605), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3607), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3614), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3615), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3633), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x35f5, 0x7922), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Additional MediaTek MT7925 Bluetooth devices */
 { USB_DEVICE(0x0489, 0xe111), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe113), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe118), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe11e), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe124), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe139), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe14e), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe14f), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe150), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0489, 0xe151), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3602), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3603), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3604), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3608), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3613), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3627), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3628), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2c7c, 0x7009), .driver_info = BTUSB_MEDIATEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Additional Realtek 8723AE Bluetooth devices */
 { USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3394), .driver_info = BTUSB_REALTEK },

 /* Additional Realtek 8723BE Bluetooth devices */
 { USB_DEVICE(0x0489, 0xe085), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x0489, 0xe08b), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x04f2, 0xb49f), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3494), .driver_info = BTUSB_REALTEK },

 /* Additional Realtek 8723BU Bluetooth devices */
 { USB_DEVICE(0x7392, 0xa611), .driver_info = BTUSB_REALTEK },

 /* Additional Realtek 8723DE Bluetooth devices */
 { USB_DEVICE(0x0bda, 0xb009), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x2ff8, 0xb011), .driver_info = BTUSB_REALTEK },

 /* Additional Realtek 8761BUV Bluetooth devices */
 { USB_DEVICE(0x2357, 0x0604), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0b05, 0x190e), .driver_info = BTUSB_REALTEK |
             BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2550, 0x8761), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0x8771), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x6655, 0x8771), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x7392, 0xc611), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2b89, 0x8761), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Additional Realtek 8821AE Bluetooth devices */
 { USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3458), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3461), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x13d3, 0x3462), .driver_info = BTUSB_REALTEK },

 /* Additional Realtek 8822BE Bluetooth devices */
 { USB_DEVICE(0x13d3, 0x3526), .driver_info = BTUSB_REALTEK },
 { USB_DEVICE(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },

 /* Additional Realtek 8822CE Bluetooth devices */
 { USB_DEVICE(0x04ca, 0x4005), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x04c5, 0x161f), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0b05, 0x18ef), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3548), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3549), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3553), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x13d3, 0x3555), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x2ff8, 0x3051), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x1358, 0xc123), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0bda, 0xc123), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },
 { USB_DEVICE(0x0cb5, 0xc547), .driver_info = BTUSB_REALTEK |
           BTUSB_WIDEBAND_SPEECH },

 /* Barrot Technology Bluetooth devices */
 { USB_DEVICE(0x33fa, 0x0010), .driver_info = BTUSB_BARROT },
 { USB_DEVICE(0x33fa, 0x0012), .driver_info = BTUSB_BARROT },

 /* Actions Semiconductor ATS2851 based devices */
 { USB_DEVICE(0x10d7, 0xb012), .driver_info = BTUSB_ACTIONS_SEMI },

 /* Silicon Wave based devices */
 { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_SWAVE },

 { } /* Terminating entry */
};

/* The Bluetooth USB module build into some devices needs to be reset on resume,
 * this is a problem with the platform (likely shutting off all power) not with
 * the module itself. So we use a DMI list to match known broken platforms.
 */

static const struct dmi_system_id btusb_needs_reset_resume_table[] = {
 {
  /* Dell OptiPlex 3060 (QCA ROME device 0cf3:e007) */
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
   DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 3060"),
  },
 },
 {
  /* Dell XPS 9360 (QCA ROME device 0cf3:e300) */
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
   DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9360"),
  },
 },
 {
  /* Dell Inspiron 5565 (QCA ROME device 0cf3:e009) */
  .matches = {
   DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
   DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5565"),
  },
 },
 {}
};

struct qca_dump_info {
 /* fields for dump collection */
 u16 id_vendor;
 u16 id_product;
 u32 fw_version;
 u32 controller_id;
 u32 ram_dump_size;
 u16 ram_dump_seqno;
};

#define BTUSB_MAX_ISOC_FRAMES 10

#define BTUSB_INTR_RUNNING 0
#define BTUSB_BULK_RUNNING 1
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
#define BTUSB_DID_ISO_RESUME 4
#define BTUSB_BOOTLOADER 5
#define BTUSB_DOWNLOADING 6
#define BTUSB_FIRMWARE_LOADED 7
#define BTUSB_FIRMWARE_FAILED 8
#define BTUSB_BOOTING  9
#define BTUSB_DIAG_RUNNING 10
#define BTUSB_OOB_WAKE_ENABLED 11
#define BTUSB_HW_RESET_ACTIVE 12
#define BTUSB_TX_WAIT_VND_EVT 13
#define BTUSB_WAKEUP_AUTOSUSPEND 14
#define BTUSB_USE_ALT3_FOR_WBS 15
#define BTUSB_ALT6_CONTINUOUS_TX 16
#define BTUSB_HW_SSR_ACTIVE 17

struct btusb_data {
 struct hci_dev       *hdev;
 struct usb_device    *udev;
 struct usb_interface *intf;
 struct usb_interface *isoc;
 struct usb_interface *diag;
 unsigned isoc_ifnum;

 unsigned long flags;

 bool poll_sync;
 int intr_interval;
 struct work_struct  work;
 struct work_struct  waker;
 struct delayed_work rx_work;

 struct sk_buff_head acl_q;

 struct usb_anchor deferred;
 struct usb_anchor tx_anchor;
 int tx_in_flight;
 spinlock_t txlock;

 struct usb_anchor intr_anchor;
 struct usb_anchor bulk_anchor;
 struct usb_anchor isoc_anchor;
 struct usb_anchor diag_anchor;
 struct usb_anchor ctrl_anchor;
 spinlock_t rxlock;

 struct sk_buff *evt_skb;
 struct sk_buff *acl_skb;
 struct sk_buff *sco_skb;

 struct usb_endpoint_descriptor *intr_ep;
 struct usb_endpoint_descriptor *bulk_tx_ep;
 struct usb_endpoint_descriptor *bulk_rx_ep;
 struct usb_endpoint_descriptor *isoc_tx_ep;
 struct usb_endpoint_descriptor *isoc_rx_ep;
 struct usb_endpoint_descriptor *diag_tx_ep;
 struct usb_endpoint_descriptor *diag_rx_ep;

 struct gpio_desc *reset_gpio;

 __u8 cmdreq_type;
 __u8 cmdreq;

 unsigned int sco_num;
 unsigned int air_mode;
 bool usb_alt6_packet_flow;
 int isoc_altsetting;
 int suspend_count;

 int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
 int (*recv_acl)(struct hci_dev *hdev, struct sk_buff *skb);
 int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);

 int (*setup_on_usb)(struct hci_dev *hdev);

 int (*suspend)(struct hci_dev *hdev);
 int (*resume)(struct hci_dev *hdev);
 int (*disconnect)(struct hci_dev *hdev);

 int oob_wake_irq;   /* irq for out-of-band wake-on-bt */

 struct qca_dump_info qca_dump;
};

static void btusb_reset(struct hci_dev *hdev)
{
 struct btusb_data *data;
 int err;

 data = hci_get_drvdata(hdev);
 /* This is not an unbalanced PM reference since the device will reset */
 err = usb_autopm_get_interface(data->intf);
 if (err) {
  bt_dev_err(hdev, "Failed usb_autopm_get_interface: %d", err);
  return;
 }

 bt_dev_err(hdev, "Resetting usb device.");
 usb_queue_reset_device(data->intf);
}

static void btusb_intel_reset(struct hci_dev *hdev)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct gpio_desc *reset_gpio = data->reset_gpio;
 struct btintel_data *intel_data = hci_get_priv(hdev);

 if (intel_data->acpi_reset_method) {
  if (test_and_set_bit(INTEL_ACPI_RESET_ACTIVE, intel_data->flags)) {
   bt_dev_err(hdev, "acpi: last reset failed ? Not resetting again");
   return;
  }

  bt_dev_err(hdev, "Initiating acpi reset method");
  /* If ACPI reset method fails, lets try with legacy GPIO
 * toggling
 */

  if (!intel_data->acpi_reset_method(hdev)) {
   return;
  }
 }

 if (!reset_gpio) {
  btusb_reset(hdev);
  return;
 }

 /*
 * Toggle the hard reset line if the platform provides one. The reset
 * is going to yank the device off the USB and then replug. So doing
 * once is enough. The cleanup is handled correctly on the way out
 * (standard USB disconnect), and the new device is detected cleanly
 * and bound to the driver again like it should be.
 */

 if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
  bt_dev_err(hdev, "last reset failed? Not resetting again");
  return;
 }

 bt_dev_err(hdev, "Initiating HW reset via gpio");
 gpiod_set_value_cansleep(reset_gpio, 1);
 msleep(100);
 gpiod_set_value_cansleep(reset_gpio, 0);
}

#define RTK_DEVCOREDUMP_CODE_MEMDUMP  0x01
#define RTK_DEVCOREDUMP_CODE_HW_ERR  0x02
#define RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT 0x03

#define RTK_SUB_EVENT_CODE_COREDUMP  0x34

struct rtk_dev_coredump_hdr {
 u8 type;
 u8 code;
 u8 reserved[2];
} __packed;

static inline void btusb_rtl_alloc_devcoredump(struct hci_dev *hdev,
  struct rtk_dev_coredump_hdr *hdr, u8 *buf, u32 len)
{
 struct sk_buff *skb;

 skb = alloc_skb(len + sizeof(*hdr), GFP_ATOMIC);
 if (!skb)
  return;

 skb_put_data(skb, hdr, sizeof(*hdr));
 if (len)
  skb_put_data(skb, buf, len);

 if (!hci_devcd_init(hdev, skb->len)) {
  hci_devcd_append(hdev, skb);
  hci_devcd_complete(hdev);
 } else {
  bt_dev_err(hdev, "RTL: Failed to generate devcoredump");
  kfree_skb(skb);
 }
}

static void btusb_rtl_reset(struct hci_dev *hdev)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct gpio_desc *reset_gpio = data->reset_gpio;
 struct rtk_dev_coredump_hdr hdr = {
  .type = RTK_DEVCOREDUMP_CODE_CMD_TIMEOUT,
 };

 btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);

 if (!reset_gpio) {
  btusb_reset(hdev);
  return;
 }

 /* Toggle the hard reset line. The Realtek device is going to
 * yank itself off the USB and then replug. The cleanup is handled
 * correctly on the way out (standard USB disconnect), and the new
 * device is detected cleanly and bound to the driver again like
 * it should be.
 */

 if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
  bt_dev_err(hdev, "last reset failed? Not resetting again");
  return;
 }

 bt_dev_err(hdev, "Reset Realtek device via gpio");
 gpiod_set_value_cansleep(reset_gpio, 1);
 msleep(200);
 gpiod_set_value_cansleep(reset_gpio, 0);
}

static void btusb_rtl_hw_error(struct hci_dev *hdev, u8 code)
{
 struct rtk_dev_coredump_hdr hdr = {
  .type = RTK_DEVCOREDUMP_CODE_HW_ERR,
  .code = code,
 };

 bt_dev_err(hdev, "RTL: hw err, trigger devcoredump (%d)", code);

 btusb_rtl_alloc_devcoredump(hdev, &hdr, NULL, 0);
}

static void btusb_qca_reset(struct hci_dev *hdev)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct gpio_desc *reset_gpio = data->reset_gpio;

 if (test_bit(BTUSB_HW_SSR_ACTIVE, &data->flags)) {
  bt_dev_info(hdev, "Ramdump in progress, defer reset");
  return;
 }

 if (reset_gpio) {
  bt_dev_err(hdev, "Reset qca device via bt_en gpio");

  /* Toggle the hard reset line. The qca bt device is going to
 * yank itself off the USB and then replug. The cleanup is handled
 * correctly on the way out (standard USB disconnect), and the new
 * device is detected cleanly and bound to the driver again like
 * it should be.
 */

  if (test_and_set_bit(BTUSB_HW_RESET_ACTIVE, &data->flags)) {
   bt_dev_err(hdev, "last reset failed? Not resetting again");
   return;
  }

  gpiod_set_value_cansleep(reset_gpio, 0);
  msleep(200);
  gpiod_set_value_cansleep(reset_gpio, 1);

  return;
 }

 btusb_reset(hdev);
}

static inline void btusb_free_frags(struct btusb_data *data)
{
 unsigned long flags;

 spin_lock_irqsave(&data->rxlock, flags);

 dev_kfree_skb_irq(data->evt_skb);
 data->evt_skb = NULL;

 dev_kfree_skb_irq(data->acl_skb);
 data->acl_skb = NULL;

 dev_kfree_skb_irq(data->sco_skb);
 data->sco_skb = NULL;

 spin_unlock_irqrestore(&data->rxlock, flags);
}

static int btusb_recv_event(struct btusb_data *data, struct sk_buff *skb)
{
 if (data->intr_interval) {
  /* Trigger dequeue immediately if an event is received */
  schedule_delayed_work(&data->rx_work, 0);
 }

 return data->recv_event(data->hdev, skb);
}

static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
{
 struct sk_buff *skb;
 unsigned long flags;
 int err = 0;

 spin_lock_irqsave(&data->rxlock, flags);
 skb = data->evt_skb;

 while (count) {
  int len;

  if (!skb) {
   skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, GFP_ATOMIC);
   if (!skb) {
    err = -ENOMEM;
    break;
   }

   hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
   hci_skb_expect(skb) = HCI_EVENT_HDR_SIZE;
  }

  len = min_t(uint, hci_skb_expect(skb), count);
  skb_put_data(skb, buffer, len);

  count -= len;
  buffer += len;
  hci_skb_expect(skb) -= len;

  if (skb->len == HCI_EVENT_HDR_SIZE) {
   /* Complete event header */
   hci_skb_expect(skb) = hci_event_hdr(skb)->plen;

   if (skb_tailroom(skb) < hci_skb_expect(skb)) {
    kfree_skb(skb);
    skb = NULL;

    err = -EILSEQ;
    break;
   }
  }

  if (!hci_skb_expect(skb)) {
   /* Each chunk should correspond to at least 1 or more
 * events so if there are still bytes left that doesn't
 * constitute a new event this is likely a bug in the
 * controller.
 */

   if (count && count < HCI_EVENT_HDR_SIZE) {
    bt_dev_warn(data->hdev,
     "Unexpected continuation: %d bytes",
     count);
    count = 0;
   }

   /* Complete frame */
   btusb_recv_event(data, skb);
   skb = NULL;
  }
 }

 data->evt_skb = skb;
 spin_unlock_irqrestore(&data->rxlock, flags);

 return err;
}

static int btusb_recv_acl(struct btusb_data *data, struct sk_buff *skb)
{
 /* Only queue ACL packet if intr_interval is set as it means
 * force_poll_sync has been enabled.
 */

 if (!data->intr_interval)
  return data->recv_acl(data->hdev, skb);

 skb_queue_tail(&data->acl_q, skb);
 schedule_delayed_work(&data->rx_work, data->intr_interval);

 return 0;
}

static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
{
 struct sk_buff *skb;
 unsigned long flags;
 int err = 0;

 spin_lock_irqsave(&data->rxlock, flags);
 skb = data->acl_skb;

 while (count) {
  int len;

  if (!skb) {
   skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
   if (!skb) {
    err = -ENOMEM;
    break;
   }

   hci_skb_pkt_type(skb) = HCI_ACLDATA_PKT;
   hci_skb_expect(skb) = HCI_ACL_HDR_SIZE;
  }

  len = min_t(uint, hci_skb_expect(skb), count);
  skb_put_data(skb, buffer, len);

  count -= len;
  buffer += len;
  hci_skb_expect(skb) -= len;

  if (skb->len == HCI_ACL_HDR_SIZE) {
   __le16 dlen = hci_acl_hdr(skb)->dlen;

   /* Complete ACL header */
   hci_skb_expect(skb) = __le16_to_cpu(dlen);

   if (skb_tailroom(skb) < hci_skb_expect(skb)) {
    kfree_skb(skb);
    skb = NULL;

    err = -EILSEQ;
    break;
   }
  }

  if (!hci_skb_expect(skb)) {
   /* Complete frame */
   btusb_recv_acl(data, skb);
   skb = NULL;
  }
 }

 data->acl_skb = skb;
 spin_unlock_irqrestore(&data->rxlock, flags);

 return err;
}

static bool btusb_validate_sco_handle(struct hci_dev *hdev,
          struct hci_sco_hdr *hdr)
{
 __u16 handle;

 if (hci_dev_test_flag(hdev, HCI_USER_CHANNEL))
  // Can't validate, userspace controls everything.
  return true;

 /*
 * USB isochronous transfers are not designed to be reliable and may
 * lose fragments.  When this happens, the next first fragment
 * encountered might actually be a continuation fragment.
 * Validate the handle to detect it and drop it, or else the upper
 * layer will get garbage for a while.
 */


 handle = hci_handle(__le16_to_cpu(hdr->handle));

 switch (hci_conn_lookup_type(hdev, handle)) {
 case SCO_LINK:
 case ESCO_LINK:
  return true;
 default:
  return false;
 }
}

static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
{
 struct sk_buff *skb;
 unsigned long flags;
 int err = 0;

 spin_lock_irqsave(&data->rxlock, flags);
 skb = data->sco_skb;

 while (count) {
  int len;

  if (!skb) {
   skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, GFP_ATOMIC);
   if (!skb) {
    err = -ENOMEM;
    break;
   }

   hci_skb_pkt_type(skb) = HCI_SCODATA_PKT;
   hci_skb_expect(skb) = HCI_SCO_HDR_SIZE;
  }

  len = min_t(uint, hci_skb_expect(skb), count);
  skb_put_data(skb, buffer, len);

  count -= len;
  buffer += len;
  hci_skb_expect(skb) -= len;

  if (skb->len == HCI_SCO_HDR_SIZE) {
   /* Complete SCO header */
   struct hci_sco_hdr *hdr = hci_sco_hdr(skb);

   hci_skb_expect(skb) = hdr->dlen;

   if (skb_tailroom(skb) < hci_skb_expect(skb) ||
       !btusb_validate_sco_handle(data->hdev, hdr)) {
    kfree_skb(skb);
    skb = NULL;

    err = -EILSEQ;
    break;
   }
  }

  if (!hci_skb_expect(skb)) {
   /* Complete frame */
   hci_recv_frame(data->hdev, skb);
   skb = NULL;
  }
 }

 data->sco_skb = skb;
 spin_unlock_irqrestore(&data->rxlock, flags);

 return err;
}

static void btusb_intr_complete(struct urb *urb)
{
 struct hci_dev *hdev = urb->context;
 struct btusb_data *data = hci_get_drvdata(hdev);
 int err;

 BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
        urb->actual_length);

 if (!test_bit(HCI_RUNNING, &hdev->flags))
  return;

 if (urb->status == 0) {
  hdev->stat.byte_rx += urb->actual_length;

  if (btusb_recv_intr(data, urb->transfer_buffer,
        urb->actual_length) < 0) {
   bt_dev_err(hdev, "corrupted event packet");
   hdev->stat.err_rx++;
  }
 } else if (urb->status == -ENOENT) {
  /* Avoid suspend failed when usb_kill_urb */
  return;
 }

 if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
  return;

 usb_mark_last_busy(data->udev);
 usb_anchor_urb(urb, &data->intr_anchor);

 err = usb_submit_urb(urb, GFP_ATOMIC);
 if (err < 0) {
  /* -EPERM: urb is being killed;
 * -ENODEV: device got disconnected
 */

  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
       urb, -err);
  if (err != -EPERM)
   hci_cmd_sync_cancel(hdev, -err);
  usb_unanchor_urb(urb);
 }
}

static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct urb *urb;
 unsigned char *buf;
 unsigned int pipe;
 int err, size;

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

 if (!data->intr_ep)
  return -ENODEV;

 urb = usb_alloc_urb(0, mem_flags);
 if (!urb)
  return -ENOMEM;

 if (le16_to_cpu(data->udev->descriptor.idVendor)  == 0x0a12 &&
     le16_to_cpu(data->udev->descriptor.idProduct) == 0x0001)
  /* Fake CSR devices don't seem to support sort-transter */
  size = le16_to_cpu(data->intr_ep->wMaxPacketSize);
 else
  /* Use maximum HCI Event size so the USB stack handles
 * ZPL/short-transfer automatically.
 */

  size = HCI_MAX_EVENT_SIZE;

 buf = kmalloc(size, mem_flags);
 if (!buf) {
  usb_free_urb(urb);
  return -ENOMEM;
 }

 pipe = usb_rcvintpipe(data->udev, data->intr_ep->bEndpointAddress);

 usb_fill_int_urb(urb, data->udev, pipe, buf, size,
    btusb_intr_complete, hdev, data->intr_ep->bInterval);

 urb->transfer_flags |= URB_FREE_BUFFER;

 usb_anchor_urb(urb, &data->intr_anchor);

 err = usb_submit_urb(urb, mem_flags);
 if (err < 0) {
  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p submission failed (%d)",
       urb, -err);
  if (err != -EPERM)
   hci_cmd_sync_cancel(hdev, -err);
  usb_unanchor_urb(urb);
 }

 /* Only initialize intr_interval if URB poll sync is enabled */
 if (!data->poll_sync)
  goto done;

 /* The units are frames (milliseconds) for full and low speed devices,
 * and microframes (1/8 millisecond) for highspeed and SuperSpeed
 * devices.
 *
 * This is done once on open/resume so it shouldn't change even if
 * force_poll_sync changes.
 */

 switch (urb->dev->speed) {
 case USB_SPEED_SUPER_PLUS:
 case USB_SPEED_SUPER: /* units are 125us */
  data->intr_interval = usecs_to_jiffies(urb->interval * 125);
  break;
 default:
  data->intr_interval = msecs_to_jiffies(urb->interval);
  break;
 }

done:
 usb_free_urb(urb);

 return err;
}

static void btusb_bulk_complete(struct urb *urb)
{
 struct hci_dev *hdev = urb->context;
 struct btusb_data *data = hci_get_drvdata(hdev);
 int err;

 BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
        urb->actual_length);

 if (!test_bit(HCI_RUNNING, &hdev->flags))
  return;

 if (urb->status == 0) {
  hdev->stat.byte_rx += urb->actual_length;

  if (data->recv_bulk(data, urb->transfer_buffer,
        urb->actual_length) < 0) {
   bt_dev_err(hdev, "corrupted ACL packet");
   hdev->stat.err_rx++;
  }
 } else if (urb->status == -ENOENT) {
  /* Avoid suspend failed when usb_kill_urb */
  return;
 }

 if (!test_bit(BTUSB_BULK_RUNNING, &data->flags))
  return;

 usb_anchor_urb(urb, &data->bulk_anchor);
 usb_mark_last_busy(data->udev);

 err = usb_submit_urb(urb, GFP_ATOMIC);
 if (err < 0) {
  /* -EPERM: urb is being killed;
 * -ENODEV: device got disconnected
 */

  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
       urb, -err);
  usb_unanchor_urb(urb);
 }
}

static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct urb *urb;
 unsigned char *buf;
 unsigned int pipe;
 int err, size = HCI_MAX_FRAME_SIZE;

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

 if (!data->bulk_rx_ep)
  return -ENODEV;

 urb = usb_alloc_urb(0, mem_flags);
 if (!urb)
  return -ENOMEM;

 buf = kmalloc(size, mem_flags);
 if (!buf) {
  usb_free_urb(urb);
  return -ENOMEM;
 }

 pipe = usb_rcvbulkpipe(data->udev, data->bulk_rx_ep->bEndpointAddress);

 usb_fill_bulk_urb(urb, data->udev, pipe, buf, size,
     btusb_bulk_complete, hdev);

 urb->transfer_flags |= URB_FREE_BUFFER;

 usb_mark_last_busy(data->udev);
 usb_anchor_urb(urb, &data->bulk_anchor);

 err = usb_submit_urb(urb, mem_flags);
 if (err < 0) {
  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p submission failed (%d)",
       urb, -err);
  usb_unanchor_urb(urb);
 }

 usb_free_urb(urb);

 return err;
}

static void btusb_isoc_complete(struct urb *urb)
{
 struct hci_dev *hdev = urb->context;
 struct btusb_data *data = hci_get_drvdata(hdev);
 int i, err;

 BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
        urb->actual_length);

 if (!test_bit(HCI_RUNNING, &hdev->flags))
  return;

 if (urb->status == 0) {
  for (i = 0; i < urb->number_of_packets; i++) {
   unsigned int offset = urb->iso_frame_desc[i].offset;
   unsigned int length = urb->iso_frame_desc[i].actual_length;

   if (urb->iso_frame_desc[i].status)
    continue;

   hdev->stat.byte_rx += length;

   if (btusb_recv_isoc(data, urb->transfer_buffer + offset,
         length) < 0) {
    bt_dev_err(hdev, "corrupted SCO packet");
    hdev->stat.err_rx++;
   }
  }
 } else if (urb->status == -ENOENT) {
  /* Avoid suspend failed when usb_kill_urb */
  return;
 }

 if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
  return;

 usb_anchor_urb(urb, &data->isoc_anchor);

 err = usb_submit_urb(urb, GFP_ATOMIC);
 if (err < 0) {
  /* -EPERM: urb is being killed;
 * -ENODEV: device got disconnected
 */

  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
       urb, -err);
  usb_unanchor_urb(urb);
 }
}

static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len,
            int mtu, struct btusb_data *data)
{
 int i = 0, offset = 0;
 unsigned int interval;

 BT_DBG("len %d mtu %d", len, mtu);

 /* For mSBC ALT 6 settings some chips need to transmit the data
 * continuously without the zero length of USB packets.
 */

 if (test_bit(BTUSB_ALT6_CONTINUOUS_TX, &data->flags))
  goto ignore_usb_alt6_packet_flow;

 /* For mSBC ALT 6 setting the host will send the packet at continuous
 * flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting
 * 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets.
 * To maintain the rate we send 63bytes of usb packets alternatively for
 * 7ms and 8ms to maintain the rate as 7.5ms.
 */

 if (data->usb_alt6_packet_flow) {
  interval = 7;
  data->usb_alt6_packet_flow = false;
 } else {
  interval = 6;
  data->usb_alt6_packet_flow = true;
 }

 for (i = 0; i < interval; i++) {
  urb->iso_frame_desc[i].offset = offset;
  urb->iso_frame_desc[i].length = offset;
 }

ignore_usb_alt6_packet_flow:
 if (len && i < BTUSB_MAX_ISOC_FRAMES) {
  urb->iso_frame_desc[i].offset = offset;
  urb->iso_frame_desc[i].length = len;
  i++;
 }

 urb->number_of_packets = i;
}

static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
{
 int i, offset = 0;

 BT_DBG("len %d mtu %d", len, mtu);

 for (i = 0; i < BTUSB_MAX_ISOC_FRAMES && len >= mtu;
     i++, offset += mtu, len -= mtu) {
  urb->iso_frame_desc[i].offset = offset;
  urb->iso_frame_desc[i].length = mtu;
 }

 if (len && i < BTUSB_MAX_ISOC_FRAMES) {
  urb->iso_frame_desc[i].offset = offset;
  urb->iso_frame_desc[i].length = len;
  i++;
 }

 urb->number_of_packets = i;
}

static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct urb *urb;
 unsigned char *buf;
 unsigned int pipe;
 int err, size;

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

 if (!data->isoc_rx_ep)
  return -ENODEV;

 urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, mem_flags);
 if (!urb)
  return -ENOMEM;

 size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) *
      BTUSB_MAX_ISOC_FRAMES;

 buf = kmalloc(size, mem_flags);
 if (!buf) {
  usb_free_urb(urb);
  return -ENOMEM;
 }

 pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);

 usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
    hdev, data->isoc_rx_ep->bInterval);

 urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;

 __fill_isoc_descriptor(urb, size,
          le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));

 usb_anchor_urb(urb, &data->isoc_anchor);

 err = usb_submit_urb(urb, mem_flags);
 if (err < 0) {
  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p submission failed (%d)",
       urb, -err);
  usb_unanchor_urb(urb);
 }

 usb_free_urb(urb);

 return err;
}

static void btusb_diag_complete(struct urb *urb)
{
 struct hci_dev *hdev = urb->context;
 struct btusb_data *data = hci_get_drvdata(hdev);
 int err;

 BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
        urb->actual_length);

 if (urb->status == 0) {
  struct sk_buff *skb;

  skb = bt_skb_alloc(urb->actual_length, GFP_ATOMIC);
  if (skb) {
   skb_put_data(skb, urb->transfer_buffer,
         urb->actual_length);
   hci_recv_diag(hdev, skb);
  }
 } else if (urb->status == -ENOENT) {
  /* Avoid suspend failed when usb_kill_urb */
  return;
 }

 if (!test_bit(BTUSB_DIAG_RUNNING, &data->flags))
  return;

 usb_anchor_urb(urb, &data->diag_anchor);
 usb_mark_last_busy(data->udev);

 err = usb_submit_urb(urb, GFP_ATOMIC);
 if (err < 0) {
  /* -EPERM: urb is being killed;
 * -ENODEV: device got disconnected
 */

  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p failed to resubmit (%d)",
       urb, -err);
  usb_unanchor_urb(urb);
 }
}

static int btusb_submit_diag_urb(struct hci_dev *hdev, gfp_t mem_flags)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct urb *urb;
 unsigned char *buf;
 unsigned int pipe;
 int err, size = HCI_MAX_FRAME_SIZE;

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

 if (!data->diag_rx_ep)
  return -ENODEV;

 urb = usb_alloc_urb(0, mem_flags);
 if (!urb)
  return -ENOMEM;

 buf = kmalloc(size, mem_flags);
 if (!buf) {
  usb_free_urb(urb);
  return -ENOMEM;
 }

 pipe = usb_rcvbulkpipe(data->udev, data->diag_rx_ep->bEndpointAddress);

 usb_fill_bulk_urb(urb, data->udev, pipe, buf, size,
     btusb_diag_complete, hdev);

 urb->transfer_flags |= URB_FREE_BUFFER;

 usb_mark_last_busy(data->udev);
 usb_anchor_urb(urb, &data->diag_anchor);

 err = usb_submit_urb(urb, mem_flags);
 if (err < 0) {
  if (err != -EPERM && err != -ENODEV)
   bt_dev_err(hdev, "urb %p submission failed (%d)",
       urb, -err);
  usb_unanchor_urb(urb);
 }

 usb_free_urb(urb);

 return err;
}

static void btusb_tx_complete(struct urb *urb)
{
 struct sk_buff *skb = urb->context;
 struct hci_dev *hdev = (struct hci_dev *)skb->dev;
 struct btusb_data *data = hci_get_drvdata(hdev);
 unsigned long flags;

 BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
        urb->actual_length);

 if (!test_bit(HCI_RUNNING, &hdev->flags))
  goto done;

 if (!urb->status) {
  hdev->stat.byte_tx += urb->transfer_buffer_length;
 } else {
  if (hci_skb_pkt_type(skb) == HCI_COMMAND_PKT)
   hci_cmd_sync_cancel(hdev, -urb->status);
  hdev->stat.err_tx++;
 }

done:
 spin_lock_irqsave(&data->txlock, flags);
 data->tx_in_flight--;
 spin_unlock_irqrestore(&data->txlock, flags);

 kfree(urb->setup_packet);

 kfree_skb(skb);
}

static void btusb_isoc_tx_complete(struct urb *urb)
{
 struct sk_buff *skb = urb->context;
 struct hci_dev *hdev = (struct hci_dev *)skb->dev;

 BT_DBG("%s urb %p status %d count %d", hdev->name, urb, urb->status,
        urb->actual_length);

 if (!test_bit(HCI_RUNNING, &hdev->flags))
  goto done;

 if (!urb->status)
  hdev->stat.byte_tx += urb->transfer_buffer_length;
 else
  hdev->stat.err_tx++;

done:
 kfree(urb->setup_packet);

 kfree_skb(skb);
}

static int btusb_open(struct hci_dev *hdev)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 int err;

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

 err = usb_autopm_get_interface(data->intf);
 if (err < 0)
  return err;

 /* Patching USB firmware files prior to starting any URBs of HCI path
 * It is more safe to use USB bulk channel for downloading USB patch
 */

 if (data->setup_on_usb) {
  err = data->setup_on_usb(hdev);
  if (err < 0)
   goto setup_fail;
 }

 data->intf->needs_remote_wakeup = 1;

 if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
  goto done;

 err = btusb_submit_intr_urb(hdev, GFP_KERNEL);
 if (err < 0)
  goto failed;

 err = btusb_submit_bulk_urb(hdev, GFP_KERNEL);
 if (err < 0) {
  usb_kill_anchored_urbs(&data->intr_anchor);
  goto failed;
 }

 set_bit(BTUSB_BULK_RUNNING, &data->flags);
 btusb_submit_bulk_urb(hdev, GFP_KERNEL);

 if (data->diag) {
  if (!btusb_submit_diag_urb(hdev, GFP_KERNEL))
   set_bit(BTUSB_DIAG_RUNNING, &data->flags);
 }

done:
 usb_autopm_put_interface(data->intf);
 return 0;

failed:
 clear_bit(BTUSB_INTR_RUNNING, &data->flags);
setup_fail:
 usb_autopm_put_interface(data->intf);
 return err;
}

static void btusb_stop_traffic(struct btusb_data *data)
{
 usb_kill_anchored_urbs(&data->intr_anchor);
 usb_kill_anchored_urbs(&data->bulk_anchor);
 usb_kill_anchored_urbs(&data->isoc_anchor);
 usb_kill_anchored_urbs(&data->diag_anchor);
 usb_kill_anchored_urbs(&data->ctrl_anchor);
}

static int btusb_close(struct hci_dev *hdev)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 int err;

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

 cancel_delayed_work(&data->rx_work);
 cancel_work_sync(&data->work);
 cancel_work_sync(&data->waker);

 skb_queue_purge(&data->acl_q);

 clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
 clear_bit(BTUSB_BULK_RUNNING, &data->flags);
 clear_bit(BTUSB_INTR_RUNNING, &data->flags);
 clear_bit(BTUSB_DIAG_RUNNING, &data->flags);

 btusb_stop_traffic(data);
 btusb_free_frags(data);

 err = usb_autopm_get_interface(data->intf);
 if (err < 0)
  goto failed;

 data->intf->needs_remote_wakeup = 0;

 /* Enable remote wake up for auto-suspend */
 if (test_bit(BTUSB_WAKEUP_AUTOSUSPEND, &data->flags))
  data->intf->needs_remote_wakeup = 1;

 usb_autopm_put_interface(data->intf);

failed:
 usb_scuttle_anchored_urbs(&data->deferred);
 return 0;
}

static int btusb_flush(struct hci_dev *hdev)
{
 struct btusb_data *data = hci_get_drvdata(hdev);

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

 cancel_delayed_work(&data->rx_work);

 skb_queue_purge(&data->acl_q);

 usb_kill_anchored_urbs(&data->tx_anchor);
 btusb_free_frags(data);

 return 0;
}

static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct usb_ctrlrequest *dr;
 struct urb *urb;
 unsigned int pipe;

 urb = usb_alloc_urb(0, GFP_KERNEL);
 if (!urb)
  return ERR_PTR(-ENOMEM);

 dr = kmalloc(sizeof(*dr), GFP_KERNEL);
 if (!dr) {
  usb_free_urb(urb);
  return ERR_PTR(-ENOMEM);
 }

 dr->bRequestType = data->cmdreq_type;
 dr->bRequest     = data->cmdreq;
 dr->wIndex       = 0;
 dr->wValue       = 0;
 dr->wLength      = __cpu_to_le16(skb->len);

 pipe = usb_sndctrlpipe(data->udev, 0x00);

 usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
        skb->data, skb->len, btusb_tx_complete, skb);

 skb->dev = (void *)hdev;

 return urb;
}

static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct urb *urb;
 unsigned int pipe;

 if (!data->bulk_tx_ep)
  return ERR_PTR(-ENODEV);

 urb = usb_alloc_urb(0, GFP_KERNEL);
 if (!urb)
  return ERR_PTR(-ENOMEM);

 pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);

 usb_fill_bulk_urb(urb, data->udev, pipe,
     skb->data, skb->len, btusb_tx_complete, skb);

 skb->dev = (void *)hdev;

 return urb;
}

static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
{
 struct btusb_data *data = hci_get_drvdata(hdev);
 struct urb *urb;
 unsigned int pipe;

 if (!data->isoc_tx_ep)
  return ERR_PTR(-ENODEV);

 urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
 if (!urb)
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=95 G=94

¤ Dauer der Verarbeitung: 0.17 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.