2023-09-05 Linux 蓝牙驱动匹配USB 蓝牙的过程简单分析,方法一通过接口描述:USB_INTERFACE_INFO 进行匹配;方法二:通过厂家ID 和device ID匹配。

一、我这个板子的WIFI蓝牙模块是RTL8821CU,这里简单分析一下系统识别模块和驱动加载的过程。主机控制接口(Host Controller Interface) HCI,即主机控制接口,属于蓝牙协议栈的一部分

二、使用 cat /sys/kernel/debug/usb/devices 命令查看USB 设备信息,请注意有这么一行Cls=e0(wlcon) Sub=01 Prot=01,分别代表:bInterfaceClass : 类型代码(由USB组织分配)。 bInterfaceSunClass : 子类型代码(由USB组织分配)。 bInterfaceProtocol : 协议代码(由USB组织分配)

三、驱动的idtable匹配方法有2种类型来匹配:

       3.1 方法一:通过接口描述:USB_INTERFACE_INFO(类,子类,协议) 完成device匹配
       3.2 方法二:通过厂家ID 和device ID:USB_DEVICE(厂家ID ,device ID) 完成device匹配
 

四、方法一:通过接口描述完成驱动匹配实例。

        4.1 usb 蓝牙驱动 kernel\drivers\bluetooth\btusb.c

/*
 *
 *  Generic Bluetooth USB driver
 *
 *  Copyright (C) 2005-2008  Marcel Holtmann <marcel@holtmann.org>
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/firmware.h>
#include <asm/unaligned.h>

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

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

#define VERSION "0.8"

static bool disable_scofix;
static bool force_scofix;

static bool reset = true;

static struct usb_driver btusb_driver;

#define BTUSB_IGNORE		0x01
#define BTUSB_DIGIANSWER	0x02
#define BTUSB_CSR		0x04
#define BTUSB_SNIFFER		0x08
#define BTUSB_BCM92035		0x10
#define BTUSB_BROKEN_ISOC	0x20
#define BTUSB_WRONG_SCO_MTU	0x40
#define BTUSB_ATH3012		0x80
#define BTUSB_INTEL		0x100
#define BTUSB_INTEL_BOOT	0x200
#define BTUSB_BCM_PATCHRAM	0x400
#define BTUSB_MARVELL		0x800
#define BTUSB_SWAVE		0x1000
#define BTUSB_INTEL_NEW		0x2000
#define BTUSB_AMP		0x4000
#define BTUSB_QCA_ROME		0x8000
#define BTUSB_BCM_APPLE		0x10000
#define BTUSB_REALTEK		0x20000
#define BTUSB_BCM2045		0x40000
#define BTUSB_IFNUM_2		0x80000

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 BCM20702A0 */
	{ USB_DEVICE(0x413c, 0x8197) },

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

	/* Broadcom BCM43142A0 (Foxconn/Lenovo) */
	{ USB_DEVICE(0x105b, 0xe065), .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 },

	/* 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 blacklist_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 },

	/* 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, 0xe007), .driver_info = BTUSB_QCA_ROME },
	{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
	{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },

	/* 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 },

	/* 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 },

	/* Intel Bluetooth devices */
	{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
	{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
	{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
	{ USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW },

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

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

	/* 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(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 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(0x0b05, 0x185c), .driver_info = BTUSB_REALTEK },

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

	{ }	/* Terminating entry */
};

#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

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

	unsigned long flags;

	struct work_struct work;
	struct work_struct waker;

	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;
	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;

	__u8 cmdreq_type;
	__u8 cmdreq;

	unsigned int sco_num;
	int isoc_altsetting;
	int suspend_count;

	int (*recv_event)(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);
};

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

	spin_lock_irqsave(&data->rxlock, flags);

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

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

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

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

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

	spin_lock(&data->rxlock);
	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;
			}

			bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
			bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE;
		}

		len = min_t(uint, bt_cb(skb)->expect, count);
		memcpy(skb_put(skb, len), buffer, len);

		count -= len;
		buffer += len;
		bt_cb(skb)->expect -= len;

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

			if (skb_tailroom(skb) < bt_cb(skb)->expect) {
				kfree_skb(skb);
				skb = NULL;

				err = -EILSEQ;
				break;
			}
		}

		if (bt_cb(skb)->expect == 0) {
			/* Complete frame */
			data->recv_event(data->hdev, skb);
			skb = NULL;
		}
	}

	data->evt_skb = skb;
	spin_unlock(&data->rxlock);

	return err;
}

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

	spin_lock(&data->rxlock);
	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;
			}

			bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
			bt_cb(skb)->expect = HCI_ACL_HDR_SIZE;
		}

		len = min_t(uint, bt_cb(skb)->expect, count);
		memcpy(skb_put(skb, len), buffer, len);

		count -= len;
		buffer += len;
		bt_cb(skb)->expect -= len;

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

			/* Complete ACL header */
			bt_cb(skb)->expect = __le16_to_cpu(dlen);

			if (skb_tailroom(skb) < bt_cb(skb)->expect) {
				kfree_skb(skb);
				skb = NULL;

				err = -EILSEQ;
				break;
			}
		}

		if (bt_cb(skb)->expect == 0) {
			/* Complete frame */
			hci_recv_frame(data->hdev, skb);
			skb = NULL;
		}
	}

	data->acl_skb = skb;
	spin_unlock(&data->rxlock);

	return err;
}

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

	spin_lock(&data->rxlock);
	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;
			}

			bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
			bt_cb(skb)->expect = HCI_SCO_HDR_SIZE;
		}

		len = min_t(uint, bt_cb(skb)->expect, count);
		memcpy(skb_put(skb, len), buffer, len);

		count -= len;
		buffer += len;
		bt_cb(skb)->expect -= len;

		if (skb->len == HCI_SCO_HDR_SIZE) {
			/* Complete SCO header */
			bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen;

			if (skb_tailroom(skb) < bt_cb(skb)->expect) {
				kfree_skb(skb);
				skb = NULL;

				err = -EILSEQ;
				break;
			}
		}

		if (bt_cb(skb)->expect == 0) {
			/* Complete frame */
			hci_recv_frame(data->hdev, skb);
			skb = NULL;
		}
	}

	data->sco_skb = skb;
	spin_unlock(&data->rxlock);

	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_ERR("%s corrupted event packet", hdev->name);
			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_ERR("%s urb %p failed to resubmit (%d)",
			       hdev->name, urb, -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;

	size = le16_to_cpu(data->intr_ep->wMaxPacketSize);

	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_ERR("%s urb %p submission failed (%d)",
			       hdev->name, urb, -err);
		usb_unanchor_urb(urb);
	}

	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_ERR("%s corrupted ACL packet", hdev->name);
			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_ERR("%s urb %p failed to resubmit (%d)",
			       hdev->name, 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_ERR("%s urb %p submission failed (%d)",
			       hdev->name, 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_ERR("%s corrupted SCO packet", hdev->name);
				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_ERR("%s urb %p failed to resubmit (%d)",
			       hdev->name, urb, -err);
		usb_unanchor_urb(urb);
	}
}

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_ERR("%s urb %p submission failed (%d)",
			       hdev->name, 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) {
			memcpy(skb_put(skb, urb->actual_length),
			       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_ERR("%s urb %p failed to resubmit (%d)",
			       hdev->name, 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_ERR("%s urb %p submission failed (%d)",
			       hdev->name, 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);

	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:
	spin_lock(&data->txlock);
	data->tx_in_flight--;
	spin_unlock(&data->txlock);

	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);

	/* 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)
			return err;
	}

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

	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);
	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);
}

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

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

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

	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;
	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);

	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)
		return ERR_PTR(-ENOMEM);

	pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);

	usb_fill_int_urb(urb, data->udev, pipe,
			 skb->data, skb->len, btusb_isoc_tx_complete,
			 skb, data->isoc_tx_ep->bInterval);

	urb->transfer_flags  = URB_ISO_ASAP;

	__fill_isoc_descriptor(urb, skb->len,
			       le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));

	skb->dev = (void *)hdev;

	return urb;
}

static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	int err;

	usb_anchor_urb(urb, &data->tx_anchor);

	err = usb_submit_urb(urb, GFP_KERNEL);
	if (err < 0) {
		if (err != -EPERM && err != -ENODEV)
			BT_ERR("%s urb %p submission failed (%d)",
			       hdev->name, urb, -err);
		kfree(urb->setup_packet);
		usb_unanchor_urb(urb);
	} else {
		usb_mark_last_busy(data->udev);
	}

	usb_free_urb(urb);
	return err;
}

static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	unsigned long flags;
	bool suspending;

	spin_lock_irqsave(&data->txlock, flags);
	suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
	if (!suspending)
		data->tx_in_flight++;
	spin_unlock_irqrestore(&data->txlock, flags);

	if (!suspending)
		return submit_tx_urb(hdev, urb);

	usb_anchor_urb(urb, &data->deferred);
	schedule_work(&data->waker);

	usb_free_urb(urb);
	return 0;
}

static int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct urb *urb;

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

	switch (bt_cb(skb)->pkt_type) {
	case HCI_COMMAND_PKT:
		urb = alloc_ctrl_urb(hdev, skb);
		if (IS_ERR(urb))
			return PTR_ERR(urb);

		hdev->stat.cmd_tx++;
		return submit_or_queue_tx_urb(hdev, urb);

	case HCI_ACLDATA_PKT:
		urb = alloc_bulk_urb(hdev, skb);
		if (IS_ERR(urb))
			return PTR_ERR(urb);

		hdev->stat.acl_tx++;
		return submit_or_queue_tx_urb(hdev, urb);

	case HCI_SCODATA_PKT:
		if (hci_conn_num(hdev, SCO_LINK) < 1)
			return -ENODEV;

		urb = alloc_isoc_urb(hdev, skb);
		if (IS_ERR(urb))
			return PTR_ERR(urb);

		hdev->stat.sco_tx++;
		return submit_tx_urb(hdev, urb);
	}

	return -EILSEQ;
}

static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
{
	struct btusb_data *data = hci_get_drvdata(hdev);

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

	if (hci_conn_num(hdev, SCO_LINK) != data->sco_num) {
		data->sco_num = hci_conn_num(hdev, SCO_LINK);
		schedule_work(&data->work);
	}
}

static inline int __set_isoc_interface(struct hci_dev *hdev, int altsetting)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	struct usb_interface *intf = data->isoc;
	struct usb_endpoint_descriptor *ep_desc;
	int i, err;

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

	err = usb_set_interface(data->udev, 1, altsetting);
	if (err < 0) {
		BT_ERR("%s setting interface failed (%d)", hdev->name, -err);
		return err;
	}

	data->isoc_altsetting = altsetting;

	data->isoc_tx_ep = NULL;
	data->isoc_rx_ep = NULL;

	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
		ep_desc = &intf->cur_altsetting->endpoint[i].desc;

		if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) {
			data->isoc_tx_ep = ep_desc;
			continue;
		}

		if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) {
			data->isoc_rx_ep = ep_desc;
			continue;
		}
	}

	if (!data->isoc_tx_ep || !data->isoc_rx_ep) {
		BT_ERR("%s invalid SCO descriptors", hdev->name);
		return -ENODEV;
	}

	return 0;
}

static void btusb_work(struct work_struct *work)
{
	struct btusb_data *data = container_of(work, struct btusb_data, work);
	struct hci_dev *hdev = data->hdev;
	int new_alts;
	int err;

	if (data->sco_num > 0) {
		if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) {
			err = usb_autopm_get_interface(data->isoc ? data->isoc : data->intf);
			if (err < 0) {
				clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
				usb_kill_anchored_urbs(&data->isoc_anchor);
				return;
			}

			set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
		}

		if (hdev->voice_setting & 0x0020) {
			static const int alts[3] = { 2, 4, 5 };

			new_alts = alts[data->sco_num - 1];
		} else {
			new_alts = data->sco_num;
		}

		if (data->isoc_altsetting != new_alts) {
			unsigned long flags;

			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
			usb_kill_anchored_urbs(&data->isoc_anchor);

			/* When isochronous alternate setting needs to be
			 * changed, because SCO connection has been added
			 * or removed, a packet fragment may be left in the
			 * reassembling state. This could lead to wrongly
			 * assembled fragments.
			 *
			 * Clear outstanding fragment when selecting a new
			 * alternate setting.
			 */
			spin_lock_irqsave(&data->rxlock, flags);
			kfree_skb(data->sco_skb);
			data->sco_skb = NULL;
			spin_unlock_irqrestore(&data->rxlock, flags);

			if (__set_isoc_interface(hdev, new_alts) < 0)
				return;
		}

		if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
			if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0)
				clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
			else
				btusb_submit_isoc_urb(hdev, GFP_KERNEL);
		}
	} else {
		clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
		usb_kill_anchored_urbs(&data->isoc_anchor);

		__set_isoc_interface(hdev, 0);
		if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags))
			usb_autopm_put_interface(data->isoc ? data->isoc : data->intf);
	}
}

static void btusb_waker(struct work_struct *work)
{
	struct btusb_data *data = container_of(work, struct btusb_data, waker);
	int err;

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

	usb_autopm_put_interface(data->intf);
}

static int btusb_setup_bcm92035(struct hci_dev *hdev)
{
	struct sk_buff *skb;
	u8 val = 0x00;

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

	skb = __hci_cmd_sync(hdev, 0xfc3b, 1, &val, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb))
		BT_ERR("BCM92035 command failed (%ld)", -PTR_ERR(skb));
	else
		kfree_skb(skb);

	return 0;
}

static int btusb_setup_csr(struct hci_dev *hdev)
{
	struct hci_rp_read_local_version *rp;
	struct sk_buff *skb;

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

	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
			     HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		int err = PTR_ERR(skb);
		BT_ERR("%s: CSR: Local version failed (%d)", hdev->name, err);
		return err;
	}

	if (skb->len != sizeof(struct hci_rp_read_local_version)) {
		BT_ERR("%s: CSR: Local version length mismatch", hdev->name);
		kfree_skb(skb);
		return -EIO;
	}

	rp = (struct hci_rp_read_local_version *)skb->data;

	/* Detect controllers which aren't real CSR ones. */
	if (le16_to_cpu(rp->manufacturer) != 10 ||
	    le16_to_cpu(rp->lmp_subver) == 0x0c5c) {
		/* Clear the reset quirk since this is not an actual
		 * early Bluetooth 1.1 device from CSR.
		 */
		clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);

		/* These fake CSR controllers have all a broken
		 * stored link key handling and so just disable it.
		 */
		set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
	}

	kfree_skb(skb);

	return 0;
}

static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
						       struct intel_version *ver)
{
	const struct firmware *fw;
	char fwname[64];
	int ret;

	snprintf(fwname, sizeof(fwname),
		 "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq",
		 ver->hw_platform, ver->hw_variant, ver->hw_revision,
		 ver->fw_variant,  ver->fw_revision, ver->fw_build_num,
		 ver->fw_build_ww, ver->fw_build_yy);

	ret = request_firmware(&fw, fwname, &hdev->dev);
	if (ret < 0) {
		if (ret == -EINVAL) {
			BT_ERR("%s Intel firmware file request failed (%d)",
			       hdev->name, ret);
			return NULL;
		}

		BT_ERR("%s failed to open Intel firmware file: %s(%d)",
		       hdev->name, fwname, ret);

		/* If the correct firmware patch file is not found, use the
		 * default firmware patch file instead
		 */
		snprintf(fwname, sizeof(fwname), "intel/ibt-hw-%x.%x.bseq",
			 ver->hw_platform, ver->hw_variant);
		if (request_firmware(&fw, fwname, &hdev->dev) < 0) {
			BT_ERR("%s failed to open default Intel fw file: %s",
			       hdev->name, fwname);
			return NULL;
		}
	}

	BT_INFO("%s: Intel Bluetooth firmware file: %s", hdev->name, fwname);

	return fw;
}

static int btusb_setup_intel_patching(struct hci_dev *hdev,
				      const struct firmware *fw,
				      const u8 **fw_ptr, int *disable_patch)
{
	struct sk_buff *skb;
	struct hci_command_hdr *cmd;
	const u8 *cmd_param;
	struct hci_event_hdr *evt = NULL;
	const u8 *evt_param = NULL;
	int remain = fw->size - (*fw_ptr - fw->data);

	/* The first byte indicates the types of the patch command or event.
	 * 0x01 means HCI command and 0x02 is HCI event. If the first bytes
	 * in the current firmware buffer doesn't start with 0x01 or
	 * the size of remain buffer is smaller than HCI command header,
	 * the firmware file is corrupted and it should stop the patching
	 * process.
	 */
	if (remain > HCI_COMMAND_HDR_SIZE && *fw_ptr[0] != 0x01) {
		BT_ERR("%s Intel fw corrupted: invalid cmd read", hdev->name);
		return -EINVAL;
	}
	(*fw_ptr)++;
	remain--;

	cmd = (struct hci_command_hdr *)(*fw_ptr);
	*fw_ptr += sizeof(*cmd);
	remain -= sizeof(*cmd);

	/* Ensure that the remain firmware data is long enough than the length
	 * of command parameter. If not, the firmware file is corrupted.
	 */
	if (remain < cmd->plen) {
		BT_ERR("%s Intel fw corrupted: invalid cmd len", hdev->name);
		return -EFAULT;
	}

	/* If there is a command that loads a patch in the firmware
	 * file, then enable the patch upon success, otherwise just
	 * disable the manufacturer mode, for example patch activation
	 * is not required when the default firmware patch file is used
	 * because there are no patch data to load.
	 */
	if (*disable_patch && le16_to_cpu(cmd->opcode) == 0xfc8e)
		*disable_patch = 0;

	cmd_param = *fw_ptr;
	*fw_ptr += cmd->plen;
	remain -= cmd->plen;

	/* This reads the expected events when the above command is sent to the
	 * device. Some vendor commands expects more than one events, for
	 * example command status event followed by vendor specific event.
	 * For this case, it only keeps the last expected event. so the command
	 * can be sent with __hci_cmd_sync_ev() which returns the sk_buff of
	 * last expected event.
	 */
	while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) {
		(*fw_ptr)++;
		remain--;

		evt = (struct hci_event_hdr *)(*fw_ptr);
		*fw_ptr += sizeof(*evt);
		remain -= sizeof(*evt);

		if (remain < evt->plen) {
			BT_ERR("%s Intel fw corrupted: invalid evt len",
			       hdev->name);
			return -EFAULT;
		}

		evt_param = *fw_ptr;
		*fw_ptr += evt->plen;
		remain -= evt->plen;
	}

	/* Every HCI commands in the firmware file has its correspond event.
	 * If event is not found or remain is smaller than zero, the firmware
	 * file is corrupted.
	 */
	if (!evt || !evt_param || remain < 0) {
		BT_ERR("%s Intel fw corrupted: invalid evt read", hdev->name);
		return -EFAULT;
	}

	skb = __hci_cmd_sync_ev(hdev, le16_to_cpu(cmd->opcode), cmd->plen,
				cmd_param, evt->evt, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)",
		       hdev->name, cmd->opcode, PTR_ERR(skb));
		return PTR_ERR(skb);
	}

	/* It ensures that the returned event matches the event data read from
	 * the firmware file. At fist, it checks the length and then
	 * the contents of the event.
	 */
	if (skb->len != evt->plen) {
		BT_ERR("%s mismatch event length (opcode 0x%4.4x)", hdev->name,
		       le16_to_cpu(cmd->opcode));
		kfree_skb(skb);
		return -EFAULT;
	}

	if (memcmp(skb->data, evt_param, evt->plen)) {
		BT_ERR("%s mismatch event parameter (opcode 0x%4.4x)",
		       hdev->name, le16_to_cpu(cmd->opcode));
		kfree_skb(skb);
		return -EFAULT;
	}
	kfree_skb(skb);

	return 0;
}

static int btusb_setup_intel(struct hci_dev *hdev)
{
	struct sk_buff *skb;
	const struct firmware *fw;
	const u8 *fw_ptr;
	int disable_patch;
	struct intel_version *ver;

	const u8 mfg_enable[] = { 0x01, 0x00 };
	const u8 mfg_disable[] = { 0x00, 0x00 };
	const u8 mfg_reset_deactivate[] = { 0x00, 0x01 };
	const u8 mfg_reset_activate[] = { 0x00, 0x02 };

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

	/* The controller has a bug with the first HCI command sent to it
	 * returning number of completed commands as zero. This would stall the
	 * command processing in the Bluetooth core.
	 *
	 * As a workaround, send HCI Reset command first which will reset the
	 * number of completed commands and allow normal command processing
	 * from now on.
	 */
	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s sending initial HCI reset command failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}
	kfree_skb(skb);

	/* Read Intel specific controller version first to allow selection of
	 * which firmware file to load.
	 *
	 * The returned information are hardware variant and revision plus
	 * firmware variant, revision and build number.
	 */
	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s reading Intel fw version command failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}

	if (skb->len != sizeof(*ver)) {
		BT_ERR("%s Intel version event length mismatch", hdev->name);
		kfree_skb(skb);
		return -EIO;
	}

	ver = (struct intel_version *)skb->data;

	BT_INFO("%s: read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x",
		hdev->name, ver->hw_platform, ver->hw_variant,
		ver->hw_revision, ver->fw_variant,  ver->fw_revision,
		ver->fw_build_num, ver->fw_build_ww, ver->fw_build_yy,
		ver->fw_patch_num);

	/* fw_patch_num indicates the version of patch the device currently
	 * have. If there is no patch data in the device, it is always 0x00.
	 * So, if it is other than 0x00, no need to patch the device again.
	 */
	if (ver->fw_patch_num) {
		BT_INFO("%s: Intel device is already patched. patch num: %02x",
			hdev->name, ver->fw_patch_num);
		kfree_skb(skb);
		goto complete;
	}

	/* Opens the firmware patch file based on the firmware version read
	 * from the controller. If it fails to open the matching firmware
	 * patch file, it tries to open the default firmware patch file.
	 * If no patch file is found, allow the device to operate without
	 * a patch.
	 */
	fw = btusb_setup_intel_get_fw(hdev, ver);
	if (!fw) {
		kfree_skb(skb);
		goto complete;
	}
	fw_ptr = fw->data;

	kfree_skb(skb);

	/* This Intel specific command enables the manufacturer mode of the
	 * controller.
	 *
	 * Only while this mode is enabled, the driver can download the
	 * firmware patch data and configuration parameters.
	 */
	skb = __hci_cmd_sync(hdev, 0xfc11, 2, mfg_enable, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s entering Intel manufacturer mode failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		release_firmware(fw);
		return PTR_ERR(skb);
	}

	kfree_skb(skb);

	disable_patch = 1;

	/* The firmware data file consists of list of Intel specific HCI
	 * commands and its expected events. The first byte indicates the
	 * type of the message, either HCI command or HCI event.
	 *
	 * It reads the command and its expected event from the firmware file,
	 * and send to the controller. Once __hci_cmd_sync_ev() returns,
	 * the returned event is compared with the event read from the firmware
	 * file and it will continue until all the messages are downloaded to
	 * the controller.
	 *
	 * Once the firmware patching is completed successfully,
	 * the manufacturer mode is disabled with reset and activating the
	 * downloaded patch.
	 *
	 * If the firmware patching fails, the manufacturer mode is
	 * disabled with reset and deactivating the patch.
	 *
	 * If the default patch file is used, no reset is done when disabling
	 * the manufacturer.
	 */
	while (fw->size > fw_ptr - fw->data) {
		int ret;

		ret = btusb_setup_intel_patching(hdev, fw, &fw_ptr,
						 &disable_patch);
		if (ret < 0)
			goto exit_mfg_deactivate;
	}

	release_firmware(fw);

	if (disable_patch)
		goto exit_mfg_disable;

	/* Patching completed successfully and disable the manufacturer mode
	 * with reset and activate the downloaded firmware patches.
	 */
	skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_activate),
			     mfg_reset_activate, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}
	kfree_skb(skb);

	BT_INFO("%s: Intel Bluetooth firmware patch completed and activated",
		hdev->name);

	goto complete;

exit_mfg_disable:
	/* Disable the manufacturer mode without reset */
	skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_disable), mfg_disable,
			     HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}
	kfree_skb(skb);

	BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name);

	goto complete;

exit_mfg_deactivate:
	release_firmware(fw);

	/* Patching failed. Disable the manufacturer mode with reset and
	 * deactivate the downloaded firmware patches.
	 */
	skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_deactivate),
			     mfg_reset_deactivate, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}
	kfree_skb(skb);

	BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated",
		hdev->name);

complete:
	/* Set the event mask for Intel specific vendor events. This enables
	 * a few extra events that are useful during general operation.
	 */
	btintel_set_event_mask_mfg(hdev, false);

	btintel_check_bdaddr(hdev);
	return 0;
}

static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode)
{
	struct sk_buff *skb;
	struct hci_event_hdr *hdr;
	struct hci_ev_cmd_complete *evt;

	skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_ATOMIC);
	if (!skb)
		return -ENOMEM;

	hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr));
	hdr->evt = HCI_EV_CMD_COMPLETE;
	hdr->plen = sizeof(*evt) + 1;

	evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt));
	evt->ncmd = 0x01;
	evt->opcode = cpu_to_le16(opcode);

	*skb_put(skb, 1) = 0x00;

	bt_cb(skb)->pkt_type = HCI_EVENT_PKT;

	return hci_recv_frame(hdev, skb);
}

static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer,
				 int count)
{
	/* When the device is in bootloader mode, then it can send
	 * events via the bulk endpoint. These events are treated the
	 * same way as the ones received from the interrupt endpoint.
	 */
	if (test_bit(BTUSB_BOOTLOADER, &data->flags))
		return btusb_recv_intr(data, buffer, count);

	return btusb_recv_bulk(data, buffer, count);
}

static void btusb_intel_bootup(struct btusb_data *data, const void *ptr,
			       unsigned int len)
{
	const struct intel_bootup *evt = ptr;

	if (len != sizeof(*evt))
		return;

	if (test_and_clear_bit(BTUSB_BOOTING, &data->flags)) {
		smp_mb__after_atomic();
		wake_up_bit(&data->flags, BTUSB_BOOTING);
	}
}

static void btusb_intel_secure_send_result(struct btusb_data *data,
					   const void *ptr, unsigned int len)
{
	const struct intel_secure_send_result *evt = ptr;

	if (len != sizeof(*evt))
		return;

	if (evt->result)
		set_bit(BTUSB_FIRMWARE_FAILED, &data->flags);

	if (test_and_clear_bit(BTUSB_DOWNLOADING, &data->flags) &&
	    test_bit(BTUSB_FIRMWARE_LOADED, &data->flags)) {
		smp_mb__after_atomic();
		wake_up_bit(&data->flags, BTUSB_DOWNLOADING);
	}
}

static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
{
	struct btusb_data *data = hci_get_drvdata(hdev);

	if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
		struct hci_event_hdr *hdr = (void *)skb->data;

		if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff &&
		    hdr->plen > 0) {
			const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1;
			unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1;

			switch (skb->data[2]) {
			case 0x02:
				/* When switching to the operational firmware
				 * the device sends a vendor specific event
				 * indicating that the bootup completed.
				 */
				btusb_intel_bootup(data, ptr, len);
				break;
			case 0x06:
				/* When the firmware loading completes the
				 * device sends out a vendor specific event
				 * indicating the result of the firmware
				 * loading.
				 */
				btusb_intel_secure_send_result(data, ptr, len);
				break;
			}
		}
	}

	return hci_recv_frame(hdev, skb);
}

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

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

	switch (bt_cb(skb)->pkt_type) {
	case HCI_COMMAND_PKT:
		if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
			struct hci_command_hdr *cmd = (void *)skb->data;
			__u16 opcode = le16_to_cpu(cmd->opcode);

			/* When in bootloader mode and the command 0xfc09
			 * is received, it needs to be send down the
			 * bulk endpoint. So allocate a bulk URB instead.
			 */
			if (opcode == 0xfc09)
				urb = alloc_bulk_urb(hdev, skb);
			else
				urb = alloc_ctrl_urb(hdev, skb);

			/* When the 0xfc01 command is issued to boot into
			 * the operational firmware, it will actually not
			 * send a command complete event. To keep the flow
			 * control working inject that event here.
			 */
			if (opcode == 0xfc01)
				inject_cmd_complete(hdev, opcode);
		} else {
			urb = alloc_ctrl_urb(hdev, skb);
		}
		if (IS_ERR(urb))
			return PTR_ERR(urb);

		hdev->stat.cmd_tx++;
		return submit_or_queue_tx_urb(hdev, urb);

	case HCI_ACLDATA_PKT:
		urb = alloc_bulk_urb(hdev, skb);
		if (IS_ERR(urb))
			return PTR_ERR(urb);

		hdev->stat.acl_tx++;
		return submit_or_queue_tx_urb(hdev, urb);

	case HCI_SCODATA_PKT:
		if (hci_conn_num(hdev, SCO_LINK) < 1)
			return -ENODEV;

		urb = alloc_isoc_urb(hdev, skb);
		if (IS_ERR(urb))
			return PTR_ERR(urb);

		hdev->stat.sco_tx++;
		return submit_tx_urb(hdev, urb);
	}

	return -EILSEQ;
}

static int btusb_setup_intel_new(struct hci_dev *hdev)
{
	static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
					  0x00, 0x08, 0x04, 0x00 };
	struct btusb_data *data = hci_get_drvdata(hdev);
	struct sk_buff *skb;
	struct intel_version *ver;
	struct intel_boot_params *params;
	const struct firmware *fw;
	const u8 *fw_ptr;
	u32 frag_len;
	char fwname[64];
	ktime_t calltime, delta, rettime;
	unsigned long long duration;
	int err;

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

	calltime = ktime_get();

	/* Read the Intel version information to determine if the device
	 * is in bootloader mode or if it already has operational firmware
	 * loaded.
	 */
	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s: Reading Intel version information failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}

	if (skb->len != sizeof(*ver)) {
		BT_ERR("%s: Intel version event size mismatch", hdev->name);
		kfree_skb(skb);
		return -EILSEQ;
	}

	ver = (struct intel_version *)skb->data;

	/* The hardware platform number has a fixed value of 0x37 and
	 * for now only accept this single value.
	 */
	if (ver->hw_platform != 0x37) {
		BT_ERR("%s: Unsupported Intel hardware platform (%u)",
		       hdev->name, ver->hw_platform);
		kfree_skb(skb);
		return -EINVAL;
	}

	/* At the moment the iBT 3.0 hardware variants 0x0b (LnP/SfP)
	 * and 0x0c (WsP) are supported by this firmware loading method.
	 *
	 * This check has been put in place to ensure correct forward
	 * compatibility options when newer hardware variants come along.
	 */
	if (ver->hw_variant != 0x0b && ver->hw_variant != 0x0c) {
		BT_ERR("%s: Unsupported Intel hardware variant (%u)",
		       hdev->name, ver->hw_variant);
		kfree_skb(skb);
		return -EINVAL;
	}

	btintel_version_info(hdev, ver);

	/* The firmware variant determines if the device is in bootloader
	 * mode or is running operational firmware. The value 0x06 identifies
	 * the bootloader and the value 0x23 identifies the operational
	 * firmware.
	 *
	 * When the operational firmware is already present, then only
	 * the check for valid Bluetooth device address is needed. This
	 * determines if the device will be added as configured or
	 * unconfigured controller.
	 *
	 * It is not possible to use the Secure Boot Parameters in this
	 * case since that command is only available in bootloader mode.
	 */
	if (ver->fw_variant == 0x23) {
		kfree_skb(skb);
		clear_bit(BTUSB_BOOTLOADER, &data->flags);
		btintel_check_bdaddr(hdev);
		return 0;
	}

	/* If the device is not in bootloader mode, then the only possible
	 * choice is to return an error and abort the device initialization.
	 */
	if (ver->fw_variant != 0x06) {
		BT_ERR("%s: Unsupported Intel firmware variant (%u)",
		       hdev->name, ver->fw_variant);
		kfree_skb(skb);
		return -ENODEV;
	}

	kfree_skb(skb);

	/* Read the secure boot parameters to identify the operating
	 * details of the bootloader.
	 */
	skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s: Reading Intel boot parameters failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}

	if (skb->len != sizeof(*params)) {
		BT_ERR("%s: Intel boot parameters size mismatch", hdev->name);
		kfree_skb(skb);
		return -EILSEQ;
	}

	params = (struct intel_boot_params *)skb->data;

	BT_INFO("%s: Device revision is %u", hdev->name,
		le16_to_cpu(params->dev_revid));

	BT_INFO("%s: Secure boot is %s", hdev->name,
		params->secure_boot ? "enabled" : "disabled");

	BT_INFO("%s: OTP lock is %s", hdev->name,
		params->otp_lock ? "enabled" : "disabled");

	BT_INFO("%s: API lock is %s", hdev->name,
		params->api_lock ? "enabled" : "disabled");

	BT_INFO("%s: Debug lock is %s", hdev->name,
		params->debug_lock ? "enabled" : "disabled");

	BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name,
		params->min_fw_build_nn, params->min_fw_build_cw,
		2000 + params->min_fw_build_yy);

	/* It is required that every single firmware fragment is acknowledged
	 * with a command complete event. If the boot parameters indicate
	 * that this bootloader does not send them, then abort the setup.
	 */
	if (params->limited_cce != 0x00) {
		BT_ERR("%s: Unsupported Intel firmware loading method (%u)",
		       hdev->name, params->limited_cce);
		kfree_skb(skb);
		return -EINVAL;
	}

	/* If the OTP has no valid Bluetooth device address, then there will
	 * also be no valid address for the operational firmware.
	 */
	if (!bacmp(&params->otp_bdaddr, BDADDR_ANY)) {
		BT_INFO("%s: No device address configured", hdev->name);
		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
	}

	/* With this Intel bootloader only the hardware variant and device
	 * revision information are used to select the right firmware.
	 *
	 * Currently this bootloader support is limited to hardware variant
	 * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
	 */
	snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
		 le16_to_cpu(params->dev_revid));

	err = request_firmware(&fw, fwname, &hdev->dev);
	if (err < 0) {
		BT_ERR("%s: Failed to load Intel firmware file (%d)",
		       hdev->name, err);
		kfree_skb(skb);
		return err;
	}

	BT_INFO("%s: Found device firmware: %s", hdev->name, fwname);

	/* Save the DDC file name for later use to apply once the firmware
	 * downloading is done.
	 */
	snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.ddc",
		 le16_to_cpu(params->dev_revid));

	kfree_skb(skb);

	if (fw->size < 644) {
		BT_ERR("%s: Invalid size of firmware file (%zu)",
		       hdev->name, fw->size);
		err = -EBADF;
		goto done;
	}

	set_bit(BTUSB_DOWNLOADING, &data->flags);

	/* Start the firmware download transaction with the Init fragment
	 * represented by the 128 bytes of CSS header.
	 */
	err = btintel_secure_send(hdev, 0x00, 128, fw->data);
	if (err < 0) {
		BT_ERR("%s: Failed to send firmware header (%d)",
		       hdev->name, err);
		goto done;
	}

	/* Send the 256 bytes of public key information from the firmware
	 * as the PKey fragment.
	 */
	err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128);
	if (err < 0) {
		BT_ERR("%s: Failed to send firmware public key (%d)",
		       hdev->name, err);
		goto done;
	}

	/* Send the 256 bytes of signature information from the firmware
	 * as the Sign fragment.
	 */
	err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388);
	if (err < 0) {
		BT_ERR("%s: Failed to send firmware signature (%d)",
		       hdev->name, err);
		goto done;
	}

	fw_ptr = fw->data + 644;
	frag_len = 0;

	while (fw_ptr - fw->data < fw->size) {
		struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);

		frag_len += sizeof(*cmd) + cmd->plen;

		/* The parameter length of the secure send command requires
		 * a 4 byte alignment. It happens so that the firmware file
		 * contains proper Intel_NOP commands to align the fragments
		 * as needed.
		 *
		 * Send set of commands with 4 byte alignment from the
		 * firmware data buffer as a single Data fragement.
		 */
		if (!(frag_len % 4)) {
			err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr);
			if (err < 0) {
				BT_ERR("%s: Failed to send firmware data (%d)",
				       hdev->name, err);
				goto done;
			}

			fw_ptr += frag_len;
			frag_len = 0;
		}
	}

	set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);

	BT_INFO("%s: Waiting for firmware download to complete", hdev->name);

	/* Before switching the device into operational mode and with that
	 * booting the loaded firmware, wait for the bootloader notification
	 * that all fragments have been successfully received.
	 *
	 * When the event processing receives the notification, then the
	 * BTUSB_DOWNLOADING flag will be cleared.
	 *
	 * The firmware loading should not take longer than 5 seconds
	 * and thus just timeout if that happens and fail the setup
	 * of this device.
	 */
	err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
				  TASK_INTERRUPTIBLE,
				  msecs_to_jiffies(5000));
	if (err == 1) {
		BT_ERR("%s: Firmware loading interrupted", hdev->name);
		err = -EINTR;
		goto done;
	}

	if (err) {
		BT_ERR("%s: Firmware loading timeout", hdev->name);
		err = -ETIMEDOUT;
		goto done;
	}

	if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
		BT_ERR("%s: Firmware loading failed", hdev->name);
		err = -ENOEXEC;
		goto done;
	}

	rettime = ktime_get();
	delta = ktime_sub(rettime, calltime);
	duration = (unsigned long long) ktime_to_ns(delta) >> 10;

	BT_INFO("%s: Firmware loaded in %llu usecs", hdev->name, duration);

done:
	release_firmware(fw);

	if (err < 0)
		return err;

	calltime = ktime_get();

	set_bit(BTUSB_BOOTING, &data->flags);

	skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param,
			     HCI_INIT_TIMEOUT);
	if (IS_ERR(skb))
		return PTR_ERR(skb);

	kfree_skb(skb);

	/* The bootloader will not indicate when the device is ready. This
	 * is done by the operational firmware sending bootup notification.
	 *
	 * Booting into operational firmware should not take longer than
	 * 1 second. However if that happens, then just fail the setup
	 * since something went wrong.
	 */
	BT_INFO("%s: Waiting for device to boot", hdev->name);

	err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
				  TASK_INTERRUPTIBLE,
				  msecs_to_jiffies(1000));

	if (err == 1) {
		BT_ERR("%s: Device boot interrupted", hdev->name);
		return -EINTR;
	}

	if (err) {
		BT_ERR("%s: Device boot timeout", hdev->name);
		return -ETIMEDOUT;
	}

	rettime = ktime_get();
	delta = ktime_sub(rettime, calltime);
	duration = (unsigned long long) ktime_to_ns(delta) >> 10;

	BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration);

	clear_bit(BTUSB_BOOTLOADER, &data->flags);

	/* Once the device is running in operational mode, it needs to apply
	 * the device configuration (DDC) parameters.
	 *
	 * The device can work without DDC parameters, so even if it fails
	 * to load the file, no need to fail the setup.
	 */
	btintel_load_ddc_config(hdev, fwname);

	/* Set the event mask for Intel specific vendor events. This enables
	 * a few extra events that are useful during general operation. It
	 * does not enable any debugging related events.
	 *
	 * The device will function correctly without these events enabled
	 * and thus no need to fail the setup.
	 */
	btintel_set_event_mask(hdev, false);

	return 0;
}

static int btusb_shutdown_intel(struct hci_dev *hdev)
{
	struct sk_buff *skb;
	long ret;

	/* Some platforms have an issue with BT LED when the interface is
	 * down or BT radio is turned off, which takes 5 seconds to BT LED
	 * goes off. This command turns off the BT LED immediately.
	 */
	skb = __hci_cmd_sync(hdev, 0xfc3f, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: turning off Intel device LED failed (%ld)",
		       hdev->name, ret);
		return ret;
	}
	kfree_skb(skb);

	return 0;
}

static int btusb_set_bdaddr_marvell(struct hci_dev *hdev,
				    const bdaddr_t *bdaddr)
{
	struct sk_buff *skb;
	u8 buf[8];
	long ret;

	buf[0] = 0xfe;
	buf[1] = sizeof(bdaddr_t);
	memcpy(buf + 2, bdaddr, sizeof(bdaddr_t));

	skb = __hci_cmd_sync(hdev, 0xfc22, sizeof(buf), buf, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: changing Marvell device address failed (%ld)",
		       hdev->name, ret);
		return ret;
	}
	kfree_skb(skb);

	return 0;
}

static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
				    const bdaddr_t *bdaddr)
{
	struct sk_buff *skb;
	u8 buf[10];
	long ret;

	buf[0] = 0x01;
	buf[1] = 0x01;
	buf[2] = 0x00;
	buf[3] = sizeof(bdaddr_t);
	memcpy(buf + 4, bdaddr, sizeof(bdaddr_t));

	skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: Change address command failed (%ld)",
		       hdev->name, ret);
		return ret;
	}
	kfree_skb(skb);

	return 0;
}

#define QCA_DFU_PACKET_LEN	4096

#define QCA_GET_TARGET_VERSION	0x09
#define QCA_CHECK_STATUS	0x05
#define QCA_DFU_DOWNLOAD	0x01

#define QCA_SYSCFG_UPDATED	0x40
#define QCA_PATCH_UPDATED	0x80
#define QCA_DFU_TIMEOUT		3000

struct qca_version {
	__le32	rom_version;
	__le32	patch_version;
	__le32	ram_version;
	__le32	ref_clock;
	__u8	reserved[4];
} __packed;

struct qca_rampatch_version {
	__le16	rom_version;
	__le16	patch_version;
} __packed;

struct qca_device_info {
	u32	rom_version;
	u8	rampatch_hdr;	/* length of header in rampatch */
	u8	nvm_hdr;	/* length of header in NVM */
	u8	ver_offset;	/* offset of version structure in rampatch */
};

static const struct qca_device_info qca_devices_table[] = {
	{ 0x00000100, 20, 4, 10 }, /* Rome 1.0 */
	{ 0x00000101, 20, 4, 10 }, /* Rome 1.1 */
	{ 0x00000200, 28, 4, 18 }, /* Rome 2.0 */
	{ 0x00000201, 28, 4, 18 }, /* Rome 2.1 */
	{ 0x00000300, 28, 4, 18 }, /* Rome 3.0 */
	{ 0x00000302, 28, 4, 18 }, /* Rome 3.2 */
};

static int btusb_qca_send_vendor_req(struct hci_dev *hdev, u8 request,
				     void *data, u16 size)
{
	struct btusb_data *btdata = hci_get_drvdata(hdev);
	struct usb_device *udev = btdata->udev;
	int pipe, err;
	u8 *buf;

	buf = kmalloc(size, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	/* Found some of USB hosts have IOT issues with ours so that we should
	 * not wait until HCI layer is ready.
	 */
	pipe = usb_rcvctrlpipe(udev, 0);
	err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN,
			      0, 0, buf, size, USB_CTRL_SET_TIMEOUT);
	if (err < 0) {
		BT_ERR("%s: Failed to access otp area (%d)", hdev->name, err);
		goto done;
	}

	memcpy(data, buf, size);

done:
	kfree(buf);

	return err;
}

static int btusb_setup_qca_download_fw(struct hci_dev *hdev,
				       const struct firmware *firmware,
				       size_t hdr_size)
{
	struct btusb_data *btdata = hci_get_drvdata(hdev);
	struct usb_device *udev = btdata->udev;
	size_t count, size, sent = 0;
	int pipe, len, err;
	u8 *buf;

	buf = kmalloc(QCA_DFU_PACKET_LEN, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	count = firmware->size;

	size = min_t(size_t, count, hdr_size);
	memcpy(buf, firmware->data, size);

	/* USB patches should go down to controller through USB path
	 * because binary format fits to go down through USB channel.
	 * USB control path is for patching headers and USB bulk is for
	 * patch body.
	 */
	pipe = usb_sndctrlpipe(udev, 0);
	err = usb_control_msg(udev, pipe, QCA_DFU_DOWNLOAD, USB_TYPE_VENDOR,
			      0, 0, buf, size, USB_CTRL_SET_TIMEOUT);
	if (err < 0) {
		BT_ERR("%s: Failed to send headers (%d)", hdev->name, err);
		goto done;
	}

	sent += size;
	count -= size;

	while (count) {
		size = min_t(size_t, count, QCA_DFU_PACKET_LEN);

		memcpy(buf, firmware->data + sent, size);

		pipe = usb_sndbulkpipe(udev, 0x02);
		err = usb_bulk_msg(udev, pipe, buf, size, &len,
				   QCA_DFU_TIMEOUT);
		if (err < 0) {
			BT_ERR("%s: Failed to send body at %zd of %zd (%d)",
			       hdev->name, sent, firmware->size, err);
			break;
		}

		if (size != len) {
			BT_ERR("%s: Failed to get bulk buffer", hdev->name);
			err = -EILSEQ;
			break;
		}

		sent  += size;
		count -= size;
	}

done:
	kfree(buf);
	return err;
}

static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
					 struct qca_version *ver,
					 const struct qca_device_info *info)
{
	struct qca_rampatch_version *rver;
	const struct firmware *fw;
	u32 ver_rom, ver_patch;
	u16 rver_rom, rver_patch;
	char fwname[64];
	int err;

	ver_rom = le32_to_cpu(ver->rom_version);
	ver_patch = le32_to_cpu(ver->patch_version);

	snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", ver_rom);

	err = request_firmware(&fw, fwname, &hdev->dev);
	if (err) {
		BT_ERR("%s: failed to request rampatch file: %s (%d)",
		       hdev->name, fwname, err);
		return err;
	}

	BT_INFO("%s: using rampatch file: %s", hdev->name, fwname);

	rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset);
	rver_rom = le16_to_cpu(rver->rom_version);
	rver_patch = le16_to_cpu(rver->patch_version);

	BT_INFO("%s: QCA: patch rome 0x%x build 0x%x, firmware rome 0x%x "
		"build 0x%x", hdev->name, rver_rom, rver_patch, ver_rom,
		ver_patch);

	if (rver_rom != ver_rom || rver_patch <= ver_patch) {
		BT_ERR("%s: rampatch file version did not match with firmware",
		       hdev->name);
		err = -EINVAL;
		goto done;
	}

	err = btusb_setup_qca_download_fw(hdev, fw, info->rampatch_hdr);

done:
	release_firmware(fw);

	return err;
}

static int btusb_setup_qca_load_nvm(struct hci_dev *hdev,
				    struct qca_version *ver,
				    const struct qca_device_info *info)
{
	const struct firmware *fw;
	char fwname[64];
	int err;

	snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin",
		 le32_to_cpu(ver->rom_version));

	err = request_firmware(&fw, fwname, &hdev->dev);
	if (err) {
		BT_ERR("%s: failed to request NVM file: %s (%d)",
		       hdev->name, fwname, err);
		return err;
	}

	BT_INFO("%s: using NVM file: %s", hdev->name, fwname);

	err = btusb_setup_qca_download_fw(hdev, fw, info->nvm_hdr);

	release_firmware(fw);

	return err;
}

static int btusb_setup_qca(struct hci_dev *hdev)
{
	const struct qca_device_info *info = NULL;
	struct qca_version ver;
	u32 ver_rom;
	u8 status;
	int i, err;

	err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver,
					sizeof(ver));
	if (err < 0)
		return err;

	ver_rom = le32_to_cpu(ver.rom_version);
	for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) {
		if (ver_rom == qca_devices_table[i].rom_version)
			info = &qca_devices_table[i];
	}
	if (!info) {
		BT_ERR("%s: don't support firmware rome 0x%x", hdev->name,
		       ver_rom);
		return -ENODEV;
	}

	err = btusb_qca_send_vendor_req(hdev, QCA_CHECK_STATUS, &status,
					sizeof(status));
	if (err < 0)
		return err;

	if (!(status & QCA_PATCH_UPDATED)) {
		err = btusb_setup_qca_load_rampatch(hdev, &ver, info);
		if (err < 0)
			return err;
	}

	if (!(status & QCA_SYSCFG_UPDATED)) {
		err = btusb_setup_qca_load_nvm(hdev, &ver, info);
		if (err < 0)
			return err;
	}

	return 0;
}

#ifdef CONFIG_BT_HCIBTUSB_BCM
static inline int __set_diag_interface(struct hci_dev *hdev)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	struct usb_interface *intf = data->diag;
	int i;

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

	data->diag_tx_ep = NULL;
	data->diag_rx_ep = NULL;

	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
		struct usb_endpoint_descriptor *ep_desc;

		ep_desc = &intf->cur_altsetting->endpoint[i].desc;

		if (!data->diag_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
			data->diag_tx_ep = ep_desc;
			continue;
		}

		if (!data->diag_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
			data->diag_rx_ep = ep_desc;
			continue;
		}
	}

	if (!data->diag_tx_ep || !data->diag_rx_ep) {
		BT_ERR("%s invalid diagnostic descriptors", hdev->name);
		return -ENODEV;
	}

	return 0;
}

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

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

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

	skb = bt_skb_alloc(2, GFP_KERNEL);
	if (!skb) {
		usb_free_urb(urb);
		return ERR_PTR(-ENOMEM);
	}

	*skb_put(skb, 1) = 0xf0;
	*skb_put(skb, 1) = enable;

	pipe = usb_sndbulkpipe(data->udev, data->diag_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 int btusb_bcm_set_diag(struct hci_dev *hdev, bool enable)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	struct urb *urb;

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

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

	urb = alloc_diag_urb(hdev, enable);
	if (IS_ERR(urb))
		return PTR_ERR(urb);

	return submit_or_queue_tx_urb(hdev, urb);
}
#endif

static int btusb_probe(struct usb_interface *intf,
		       const struct usb_device_id *id)
{
	struct usb_endpoint_descriptor *ep_desc;
	struct btusb_data *data;
	struct hci_dev *hdev;
	unsigned ifnum_base;
	int i, err;

	BT_DBG("intf %p id %p", intf, id);
    printk("btusb_probe995522\n");
	/* interface numbers are hardcoded in the spec */
	if (intf->cur_altsetting->desc.bInterfaceNumber != 0) {
		if (!(id->driver_info & BTUSB_IFNUM_2))
			return -ENODEV;
		if (intf->cur_altsetting->desc.bInterfaceNumber != 2)
			return -ENODEV;
	}

	ifnum_base = intf->cur_altsetting->desc.bInterfaceNumber;

	if (!id->driver_info) {
		const struct usb_device_id *match;

		match = usb_match_id(intf, blacklist_table);
		if (match)
			id = match;
	}

	if (id->driver_info == BTUSB_IGNORE)
		return -ENODEV;

	if (id->driver_info & BTUSB_ATH3012) {
		struct usb_device *udev = interface_to_usbdev(intf);

		/* Old firmware would otherwise let ath3k driver load
		 * patch and sysconfig files */
		if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001)
			return -ENODEV;
	}

	data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
		ep_desc = &intf->cur_altsetting->endpoint[i].desc;

		if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) {
			data->intr_ep = ep_desc;
			continue;
		}

		if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
			data->bulk_tx_ep = ep_desc;
			continue;
		}

		if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
			data->bulk_rx_ep = ep_desc;
			continue;
		}
	}

	if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
		return -ENODEV;

	if (id->driver_info & BTUSB_AMP) {
		data->cmdreq_type = USB_TYPE_CLASS | 0x01;
		data->cmdreq = 0x2b;
	} else {
		data->cmdreq_type = USB_TYPE_CLASS;
		data->cmdreq = 0x00;
	}

	data->udev = interface_to_usbdev(intf);
	data->intf = intf;

	INIT_WORK(&data->work, btusb_work);
	INIT_WORK(&data->waker, btusb_waker);
	init_usb_anchor(&data->deferred);
	init_usb_anchor(&data->tx_anchor);
	spin_lock_init(&data->txlock);

	init_usb_anchor(&data->intr_anchor);
	init_usb_anchor(&data->bulk_anchor);
	init_usb_anchor(&data->isoc_anchor);
	init_usb_anchor(&data->diag_anchor);
	spin_lock_init(&data->rxlock);

	if (id->driver_info & BTUSB_INTEL_NEW) {
		data->recv_event = btusb_recv_event_intel;
		data->recv_bulk = btusb_recv_bulk_intel;
		set_bit(BTUSB_BOOTLOADER, &data->flags);
	} else {
		data->recv_event = hci_recv_frame;
		data->recv_bulk = btusb_recv_bulk;
	}

	hdev = hci_alloc_dev();
	if (!hdev)
		return -ENOMEM;

	hdev->bus = HCI_USB;
	hci_set_drvdata(hdev, data);

	if (id->driver_info & BTUSB_AMP)
		hdev->dev_type = HCI_AMP;
	else
		hdev->dev_type = HCI_BREDR;

	data->hdev = hdev;

	SET_HCIDEV_DEV(hdev, &intf->dev);

	hdev->open   = btusb_open;
	hdev->close  = btusb_close;
	hdev->flush  = btusb_flush;
	hdev->send   = btusb_send_frame;
	hdev->notify = btusb_notify;

	if (id->driver_info & BTUSB_BCM2045)
		set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);

	if (id->driver_info & BTUSB_BCM92035)
		hdev->setup = btusb_setup_bcm92035;

#ifdef CONFIG_BT_HCIBTUSB_BCM
	if (id->driver_info & BTUSB_BCM_PATCHRAM) {
		hdev->manufacturer = 15;
		hdev->setup = btbcm_setup_patchram;
		hdev->set_diag = btusb_bcm_set_diag;
		hdev->set_bdaddr = btbcm_set_bdaddr;

		/* Broadcom LM_DIAG Interface numbers are hardcoded */
		data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
	}

	if (id->driver_info & BTUSB_BCM_APPLE) {
		hdev->manufacturer = 15;
		hdev->setup = btbcm_setup_apple;
		hdev->set_diag = btusb_bcm_set_diag;

		/* Broadcom LM_DIAG Interface numbers are hardcoded */
		data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
	}
#endif

	if (id->driver_info & BTUSB_INTEL) {
		hdev->manufacturer = 2;
		hdev->setup = btusb_setup_intel;
		hdev->shutdown = btusb_shutdown_intel;
		hdev->set_diag = btintel_set_diag_mfg;
		hdev->set_bdaddr = btintel_set_bdaddr;
		set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
		set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
		set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
	}

	if (id->driver_info & BTUSB_INTEL_NEW) {
		hdev->manufacturer = 2;
		hdev->send = btusb_send_frame_intel;
		hdev->setup = btusb_setup_intel_new;
		hdev->hw_error = btintel_hw_error;
		hdev->set_diag = btintel_set_diag;
		hdev->set_bdaddr = btintel_set_bdaddr;
		set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
		set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
	}

	if (id->driver_info & BTUSB_MARVELL)
		hdev->set_bdaddr = btusb_set_bdaddr_marvell;

	if (id->driver_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) {
		hdev->manufacturer = 2;
		set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
	}

	if (id->driver_info & BTUSB_ATH3012) {
		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) {
		data->setup_on_usb = btusb_setup_qca;
		hdev->set_bdaddr = btusb_set_bdaddr_ath3012;

		/* QCA Rome devices lose their updated firmware over suspend,
		 * but the USB hub doesn't notice any status change.
		 * explicitly request a device reset on resume.
		 */
		interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
	}

#ifdef CONFIG_BT_HCIBTUSB_RTL
	if (id->driver_info & BTUSB_REALTEK) {
		hdev->setup = btrtl_setup_realtek;

		/* Realtek devices lose their updated firmware over suspend,
		 * but the USB hub doesn't notice any status change.
		 * Explicitly request a device reset on resume.
		 */
		interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
	}
#endif

	if (id->driver_info & BTUSB_AMP) {
		/* AMP controllers do not support SCO packets */
		data->isoc = NULL;
	} else {
		/* Interface orders are hardcoded in the specification */
		data->isoc = usb_ifnum_to_if(data->udev, ifnum_base + 1);
	}

	if (!reset)
		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);

	if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
		if (!disable_scofix)
			set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
	}

	if (id->driver_info & BTUSB_BROKEN_ISOC)
		data->isoc = NULL;

	if (id->driver_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);

		/* 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)
			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;

		/* New sniffer firmware has crippled HCI interface */
		if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
			set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
	}

	if (id->driver_info & BTUSB_INTEL_BOOT) {
		/* A bug in the bootloader causes that interrupt interface is
		 * only enabled after receiving SetInterface(0, AltSetting=0).
		 */
		err = usb_set_interface(data->udev, 0, 0);
		if (err < 0) {
			BT_ERR("failed to set interface 0, alt 0 %d", err);
			hci_free_dev(hdev);
			return err;
		}
	}

	if (data->isoc) {
		err = usb_driver_claim_interface(&btusb_driver,
						 data->isoc, data);
		if (err < 0) {
			hci_free_dev(hdev);
			return err;
		}
	}

#ifdef CONFIG_BT_HCIBTUSB_BCM
	if (data->diag) {
		if (!usb_driver_claim_interface(&btusb_driver,
						data->diag, data))
			__set_diag_interface(hdev);
		else
			data->diag = NULL;
	}
#endif

	err = hci_register_dev(hdev);
	if (err < 0) {
		hci_free_dev(hdev);
		return err;
	}

	usb_set_intfdata(intf, data);

	return 0;
}

static void btusb_disconnect(struct usb_interface *intf)
{
	struct btusb_data *data = usb_get_intfdata(intf);
	struct hci_dev *hdev;

	BT_DBG("intf %p", intf);

	if (!data)
		return;

	hdev = data->hdev;
	usb_set_intfdata(data->intf, NULL);

	if (data->isoc)
		usb_set_intfdata(data->isoc, NULL);

	if (data->diag)
		usb_set_intfdata(data->diag, NULL);

	hci_unregister_dev(hdev);

	if (intf == data->intf) {
		if (data->isoc)
			usb_driver_release_interface(&btusb_driver, data->isoc);
		if (data->diag)
			usb_driver_release_interface(&btusb_driver, data->diag);
	} else if (intf == data->isoc) {
		if (data->diag)
			usb_driver_release_interface(&btusb_driver, data->diag);
		usb_driver_release_interface(&btusb_driver, data->intf);
	} else if (intf == data->diag) {
		usb_driver_release_interface(&btusb_driver, data->intf);
		if (data->isoc)
			usb_driver_release_interface(&btusb_driver, data->isoc);
	}

	hci_free_dev(hdev);
}

#ifdef CONFIG_PM
static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
{
	struct btusb_data *data = usb_get_intfdata(intf);

	BT_DBG("intf %p", intf);

	if (data->suspend_count++)
		return 0;

	spin_lock_irq(&data->txlock);
	if (!(PMSG_IS_AUTO(message) && data->tx_in_flight)) {
		set_bit(BTUSB_SUSPENDING, &data->flags);
		spin_unlock_irq(&data->txlock);
	} else {
		spin_unlock_irq(&data->txlock);
		data->suspend_count--;
		return -EBUSY;
	}

	cancel_work_sync(&data->work);

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

	return 0;
}

static void play_deferred(struct btusb_data *data)
{
	struct urb *urb;
	int err;

	while ((urb = usb_get_from_anchor(&data->deferred))) {
		err = usb_submit_urb(urb, GFP_ATOMIC);
		if (err < 0)
			break;

		data->tx_in_flight++;
	}
	usb_scuttle_anchored_urbs(&data->deferred);
}

static int btusb_resume(struct usb_interface *intf)
{
	struct btusb_data *data = usb_get_intfdata(intf);
	struct hci_dev *hdev = data->hdev;
	int err = 0;

	BT_DBG("intf %p", intf);

	if (--data->suspend_count)
		return 0;

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

	if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) {
		err = btusb_submit_intr_urb(hdev, GFP_NOIO);
		if (err < 0) {
			clear_bit(BTUSB_INTR_RUNNING, &data->flags);
			goto failed;
		}
	}

	if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) {
		err = btusb_submit_bulk_urb(hdev, GFP_NOIO);
		if (err < 0) {
			clear_bit(BTUSB_BULK_RUNNING, &data->flags);
			goto failed;
		}

		btusb_submit_bulk_urb(hdev, GFP_NOIO);
	}

	if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
		if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0)
			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
		else
			btusb_submit_isoc_urb(hdev, GFP_NOIO);
	}

	spin_lock_irq(&data->txlock);
	play_deferred(data);
	clear_bit(BTUSB_SUSPENDING, &data->flags);
	spin_unlock_irq(&data->txlock);
	schedule_work(&data->work);

	return 0;

failed:
	usb_scuttle_anchored_urbs(&data->deferred);
done:
	spin_lock_irq(&data->txlock);
	clear_bit(BTUSB_SUSPENDING, &data->flags);
	spin_unlock_irq(&data->txlock);

	return err;
}
#endif

static struct usb_driver btusb_driver = {
	.name		= "btusb",
	.probe		= btusb_probe,
	.disconnect	= btusb_disconnect,
#ifdef CONFIG_PM
	.suspend	= btusb_suspend,
	.resume		= btusb_resume,
#endif
	.id_table	= btusb_table,
	.supports_autosuspend = 1,
	.disable_hub_initiated_lpm = 1,
};

module_usb_driver(btusb_driver);

module_param(disable_scofix, bool, 0644);
MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");

module_param(force_scofix, bool, 0644);
MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size");

module_param(reset, bool, 0644);
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");

MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Generic Bluetooth USB driver ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");

        4.2 声明 usb驱动 usb_driver btusb_driver

        4.3 0xe0, 0x01, 0x01 是通用的蓝牙接口描述信息。

        4.4 驱动匹配完成,进入probe函数。

五、方法二:通过厂家ID 和device ID:USB_DEVICE(厂家ID ,device ID) 完成device匹配实例

        5.1 kernel\drivers\bluetooth\rtk_btusb.c

/*
 *
 *  Realtek Bluetooth USB driver
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <linux/usb.h>

#include <linux/ioctl.h>
#include <linux/io.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/reboot.h>

#include "rtk_btusb.h"

#define RTKBT_RELEASE_NAME "20200318_BT_ANDROID_9.0"
#define VERSION "5.2.1"

#define SUSPNED_DW_FW 0
#define SET_WAKEUP_DEVICE 0


static DEFINE_SPINLOCK(queue_lock);
static DEFINE_SPINLOCK(running_flag_lock);
static volatile uint16_t    driver_state = 0;

#if SUSPNED_DW_FW
static firmware_info *fw_info_4_suspend = NULL;
#endif

static uint32_t usb_info;

static patch_info fw_patch_table[] = {
/* { vid, pid, lmp_sub_default, lmp_sub, everion, mp_fw_name, fw_name, config_name, fw_cache, fw_len, mac_offset } */
{ 0x0BDA, 0x1724, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723A */
{ 0x0BDA, 0x8723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE */
{ 0x0BDA, 0xA723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE for LI */
{ 0x0BDA, 0x0723, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE */
{ 0x13D3, 0x3394, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AE for Azurewave*/

{ 0x0BDA, 0x0724, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */
{ 0x0BDA, 0x8725, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */
{ 0x0BDA, 0x872A, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */
{ 0x0BDA, 0x872B, 0x1200, 0, 0, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* 8723AU */

{ 0x0BDA, 0xb720, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BU */
{ 0x0BDA, 0xb72A, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BU */
{ 0x0BDA, 0xb728, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for LC */
{ 0x0BDA, 0xb723, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
{ 0x0BDA, 0xb72B, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
{ 0x0BDA, 0xb001, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for HP */
{ 0x0BDA, 0xb002, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
{ 0x0BDA, 0xb003, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
{ 0x0BDA, 0xb004, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */
{ 0x0BDA, 0xb005, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE */

{ 0x13D3, 0x3410, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Azurewave */
{ 0x13D3, 0x3416, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Azurewave */
{ 0x13D3, 0x3459, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Azurewave */
{ 0x0489, 0xE085, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Foxconn */
{ 0x0489, 0xE08B, 0x8723, 0, 0, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8723BE for Foxconn */

{ 0x0BDA, 0x2850, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU */
{ 0x0BDA, 0xA761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU only */
{ 0x0BDA, 0x818B, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761aw8192eu_fw", "rtl8761aw8192eu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AW + 8192EU */
{ 0x0BDA, 0x818C, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761aw8192eu_fw", "rtl8761aw8192eu_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AW + 8192EU */
{ 0x0BDA, 0x8760, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU + 8192EE */
{ 0x0BDA, 0xB761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AUV only */
{ 0x0BDA, 0x8761, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU + 8192EE for LI */
{ 0x0BDA, 0x8A60, 0x8761, 0, 0, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8761AU + 8812AE */
{ 0x0BDA, 0x8771, 0x8761, 0, 0, "mp_rtl8761b_fw", "rtl8761b_fw", "rtl8761b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8761BU */
{ 0x0BDA, 0xa725, 0x8761, 0, 0, "mp_rtl8725a_fw", "rtl8725a_fw", "rtl8725a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8725AU */
{ 0x0BDA, 0xa72A, 0x8761, 0, 0, "mp_rtl8725a_fw", "rtl8725a_fw", "rtl8725a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8725AU BT only */

{ 0x0BDA, 0x8821, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
{ 0x0BDA, 0x0821, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
{ 0x0BDA, 0x0823, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AU */
{ 0x13D3, 0x3414, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
{ 0x13D3, 0x3458, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
{ 0x13D3, 0x3461, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */
{ 0x13D3, 0x3462, 0x8821, 0, 0, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_1_2, MAX_PATCH_SIZE_24K}, /* RTL8821AE */

{ 0x0BDA, 0xB822, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_25K}, /* RTL8822BE */
{ 0x0BDA, 0xB82C, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_25K}, /* RTL8822BU */
{ 0x0BDA, 0xB81D, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_25K}, /* RTL8822BU BT only */
{ 0x0BDA, 0xB82E, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_25K}, /* RTL8822BU-VN */
{ 0x0BDA, 0xB023, 0x8822, 0, 0, "mp_rtl8822b_fw", "rtl8822b_fw", "rtl8822b_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_25K}, /* RTL8822BE */
{ 0x0BDA, 0xB703, 0x8703, 0, 0, "mp_rtl8723c_fw", "rtl8723c_fw", "rtl8723c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_24K}, /* RTL8723CU */
/* todo: RTL8703BU */

{ 0x0BDA, 0xD723, 0x8723, 0, 0, "mp_rtl8723d_fw", "rtl8723d_fw", "rtl8723d_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8723DU */
{ 0x0BDA, 0xD72A, 0x8723, 0, 0, "mp_rtl8723d_fw", "rtl8723d_fw", "rtl8723d_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8723DU BT only */
{ 0x0BDA, 0xD720, 0x8723, 0, 0, "mp_rtl8723d_fw", "rtl8723d_fw", "rtl8723d_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8723DE */
{ 0x0BDA, 0xB820, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8821CU */
{ 0x0BDA, 0xC820, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8821CU */
{ 0x0BDA, 0xC82A, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8821CU BT only */
{ 0x0BDA, 0xC821, 0x8821, 0, 0, "mp_rtl8821c_fw", "rtl8821c_fw", "rtl8821c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_3PLUS, MAX_PATCH_SIZE_40K}, /* RTL8821CE */
/* todo: RTL8703CU */
{ 0x0BDA, 0xC82C, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CU */
{ 0x0BDA, 0xC82E, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CU-VN */
{ 0x0BDA, 0xC81D, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CU BT only */
{ 0x0BDA, 0xC82F, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CE-VS */
{ 0x0BDA, 0xC822, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CE */
{ 0x0BDA, 0xB00C, 0x8822, 0, 0, "mp_rtl8822c_fw", "rtl8822c_fw", "rtl8822c_config", NULL, 0 ,CONFIG_MAC_OFFSET_GEN_4PLUS, MAX_PATCH_SIZE_40K}, /* RTL8822CE */
/* NOTE: must append patch entries above the null entry */
{ 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, 0, 0, 0 }
};

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

    spinlock_t lock;

    unsigned long flags;

    struct work_struct work;
    struct work_struct waker;

    struct usb_anchor tx_anchor;
    struct usb_anchor intr_anchor;
    struct usb_anchor bulk_anchor;
    struct usb_anchor isoc_anchor;
    struct usb_anchor deferred;
    int tx_in_flight;
    spinlock_t txlock;

    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;

    __u8 cmdreq_type;

    unsigned int sco_num;
    int isoc_altsetting;
    int suspend_count;
    uint16_t sco_handle;
//#ifdef CONFIG_HAS_EARLYSUSPEND
#if 0
    struct early_suspend early_suspend;
#else
    struct notifier_block pm_notifier;
    struct notifier_block reboot_notifier;
#endif
    firmware_info *fw_info;

#ifdef CONFIG_SCO_OVER_HCI
    RTK_sco_card_t  *pSCOSnd;
#endif
};

int download_patch(firmware_info *fw_info, int cached);
int reset_controller(firmware_info* fw_info);


/********************************************************
**    this function first check the value, if true then set value
**
*********************************************************/
static inline bool check_set_driver_state_value(uint16_t check_value, uint16_t change_value)
{
    bool res;
    spin_lock(&running_flag_lock);
    if((driver_state & check_value) != check_value) {
        res = false;
    }
    else {
        driver_state |= change_value;
        res = true;
    }
    spin_unlock(&running_flag_lock);
    return res;
}

static inline uint16_t get_driver_state_value(void)
{
    uint16_t state;
    spin_lock(&running_flag_lock);
    state = driver_state;
    spin_unlock(&running_flag_lock);
    return state;
}

static inline void clear_driver_state(uint16_t clear_value)
{
    spin_lock(&running_flag_lock);
    driver_state &= (~clear_value);
    spin_unlock(&running_flag_lock);
}

static inline void set_driver_state_value(uint16_t change_value)
{
    spin_lock(&running_flag_lock);
    driver_state |= change_value;
    spin_unlock(&running_flag_lock);
}

#if SUSPNED_DW_FW
static int download_suspend_patch(firmware_info *fw_info, int cached);
#endif
#if SET_WAKEUP_DEVICE
static void set_wakeup_device_from_conf(firmware_info *fw_info);
int set_wakeup_device(firmware_info* fw_info, uint8_t* wakeup_bdaddr);
#endif

static void rtk_free( struct btusb_data *data)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 1)
    kfree(data);
#endif
    return;
}

static struct btusb_data *rtk_alloc(struct usb_interface *intf)
{
    struct btusb_data *data;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 1)
    data = kzalloc(sizeof(*data), GFP_KERNEL);
#else
    data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
#endif
    return data;
}

static void print_acl(struct sk_buff *skb, int direction)
{
#if PRINT_ACL_DATA
    uint wlength = skb->len;
    u16 *handle = (u16 *)(skb->data);
    u16 len = *(handle+1);
    u8 *acl_data = (u8 *)(skb->data);

    RTK_INFO("%s: direction %d, handle %04x, len %d",
            __func__, direction, *handle, len);
#endif
}

static void print_sco(struct sk_buff *skb, int direction)
{
#if PRINT_SCO_DATA
    uint wlength = skb->len;
    u16 *handle = (u16 *)(skb->data);
    u8 len = *(u8 *)(handle+1);
    u8 *sco_data =(u8 *)(skb->data);

    RTKBT_INFO("%s: direction %d, handle %04x, len %d",
            __func__, direction, *handle, len);
#endif
}

static void print_error_command(struct sk_buff *skb)
{
    uint wlength = skb->len;
    uint icount = 0;
    u16 *opcode = (u16*)(skb->data);
    u8 *cmd_data = (u8*)(skb->data);
    u8 len = *(cmd_data+2);

    switch (*opcode) {
    case HCI_OP_INQUIRY:
        printk("HCI_OP_INQUIRY");
        break;
    case HCI_OP_INQUIRY_CANCEL:
        printk("HCI_OP_INQUIRY_CANCEL");
        break;
    case HCI_OP_EXIT_PERIODIC_INQ:
        printk("HCI_OP_EXIT_PERIODIC_INQ");
        break;
    case HCI_OP_CREATE_CONN:
        printk("HCI_OP_CREATE_CONN");
        break;
    case HCI_OP_DISCONNECT:
        printk("HCI_OP_DISCONNECT");
        break;
    case HCI_OP_CREATE_CONN_CANCEL:
        printk("HCI_OP_CREATE_CONN_CANCEL");
        break;
    case HCI_OP_ACCEPT_CONN_REQ:
        printk("HCI_OP_ACCEPT_CONN_REQ");
        break;
    case HCI_OP_REJECT_CONN_REQ:
        printk("HCI_OP_REJECT_CONN_REQ");
        break;
    case HCI_OP_AUTH_REQUESTED:
        printk("HCI_OP_AUTH_REQUESTED");
        break;
    case HCI_OP_SET_CONN_ENCRYPT:
        printk("HCI_OP_SET_CONN_ENCRYPT");
        break;
    case HCI_OP_REMOTE_NAME_REQ:
        printk("HCI_OP_REMOTE_NAME_REQ");
        break;
    case HCI_OP_READ_REMOTE_FEATURES:
        printk("HCI_OP_READ_REMOTE_FEATURES");
        break;
    case HCI_OP_SNIFF_MODE:
        printk("HCI_OP_SNIFF_MODE");
        break;
    case HCI_OP_EXIT_SNIFF_MODE:
        printk("HCI_OP_EXIT_SNIFF_MODE");
        break;
    case HCI_OP_SWITCH_ROLE:
        printk("HCI_OP_SWITCH_ROLE");
        break;
    case HCI_OP_SNIFF_SUBRATE:
        printk("HCI_OP_SNIFF_SUBRATE");
        break;
    case HCI_OP_RESET:
        printk("HCI_OP_RESET");
        break;
    case HCI_OP_Write_Extended_Inquiry_Response:
        printk("HCI_Write_Extended_Inquiry_Response");
        break;

    default:
        printk("CMD");
        break;
    }
    printk(":%04x,len:%d,", *opcode,len);
    for (icount = 3; (icount < wlength) && (icount < 24); icount++)
        printk("%02x ", *(cmd_data+icount));
    printk("\n");
}

static void print_command(struct sk_buff *skb)
{
#if PRINT_CMD_EVENT
    print_error_command(skb);
#endif
}

#if CONFIG_BLUEDROID
/* Global parameters for bt usb char driver */
#define BT_CHAR_DEVICE_NAME "rtkbt_dev"
static struct sk_buff_head btchr_readq;
static wait_queue_head_t btchr_read_wait;
static wait_queue_head_t bt_drv_state_wait;
static dev_t bt_devid; /* bt char device number */
static struct cdev bt_char_dev; /* bt character device structure */
static struct class *bt_char_class; /* device class for usb char driver */
static int bt_reset = 0;
/* HCI device & lock */
DEFINE_RWLOCK(hci_dev_lock);
struct hci_dev *ghdev = NULL;

static void print_event(struct sk_buff *skb)
{
#if PRINT_CMD_EVENT
    uint wlength = skb->len;
    uint icount = 0;
    u8 *opcode = (u8*)(skb->data);
    u8 len = *(opcode+1);

    switch (*opcode) {
    case HCI_EV_INQUIRY_COMPLETE:
        printk("HCI_EV_INQUIRY_COMPLETE");
        break;
    case HCI_EV_INQUIRY_RESULT:
        printk("HCI_EV_INQUIRY_RESULT");
        break;
    case HCI_EV_CONN_COMPLETE:
        printk("HCI_EV_CONN_COMPLETE");
        break;
    case HCI_EV_CONN_REQUEST:
        printk("HCI_EV_CONN_REQUEST");
        break;
    case HCI_EV_DISCONN_COMPLETE:
        printk("HCI_EV_DISCONN_COMPLETE");
        break;
    case HCI_EV_AUTH_COMPLETE:
        printk("HCI_EV_AUTH_COMPLETE");
        break;
    case HCI_EV_REMOTE_NAME:
        printk("HCI_EV_REMOTE_NAME");
        break;
    case HCI_EV_ENCRYPT_CHANGE:
        printk("HCI_EV_ENCRYPT_CHANGE");
        break;
    case HCI_EV_CHANGE_LINK_KEY_COMPLETE:
        printk("HCI_EV_CHANGE_LINK_KEY_COMPLETE");
        break;
    case HCI_EV_REMOTE_FEATURES:
        printk("HCI_EV_REMOTE_FEATURES");
        break;
    case HCI_EV_REMOTE_VERSION:
        printk("HCI_EV_REMOTE_VERSION");
        break;
    case HCI_EV_QOS_SETUP_COMPLETE:
        printk("HCI_EV_QOS_SETUP_COMPLETE");
        break;
    case HCI_EV_CMD_COMPLETE:
        printk("HCI_EV_CMD_COMPLETE");
        break;
    case HCI_EV_CMD_STATUS:
        printk("HCI_EV_CMD_STATUS");
        break;
    case HCI_EV_ROLE_CHANGE:
        printk("HCI_EV_ROLE_CHANGE");
        break;
    case HCI_EV_NUM_COMP_PKTS:
        printk("HCI_EV_NUM_COMP_PKTS");
        break;
    case HCI_EV_MODE_CHANGE:
        printk("HCI_EV_MODE_CHANGE");
        break;
    case HCI_EV_PIN_CODE_REQ:
        printk("HCI_EV_PIN_CODE_REQ");
        break;
    case HCI_EV_LINK_KEY_REQ:
        printk("HCI_EV_LINK_KEY_REQ");
        break;
    case HCI_EV_LINK_KEY_NOTIFY:
        printk("HCI_EV_LINK_KEY_NOTIFY");
        break;
    case HCI_EV_CLOCK_OFFSET:
        printk("HCI_EV_CLOCK_OFFSET");
        break;
    case HCI_EV_PKT_TYPE_CHANGE:
        printk("HCI_EV_PKT_TYPE_CHANGE");
        break;
    case HCI_EV_PSCAN_REP_MODE:
        printk("HCI_EV_PSCAN_REP_MODE");
        break;
    case HCI_EV_INQUIRY_RESULT_WITH_RSSI:
        printk("HCI_EV_INQUIRY_RESULT_WITH_RSSI");
        break;
    case HCI_EV_REMOTE_EXT_FEATURES:
        printk("HCI_EV_REMOTE_EXT_FEATURES");
        break;
    case HCI_EV_SYNC_CONN_COMPLETE:
        printk("HCI_EV_SYNC_CONN_COMPLETE");
        break;
    case HCI_EV_SYNC_CONN_CHANGED:
        printk("HCI_EV_SYNC_CONN_CHANGED");
        break;
    case HCI_EV_SNIFF_SUBRATE:
        printk("HCI_EV_SNIFF_SUBRATE");
        break;
    case HCI_EV_EXTENDED_INQUIRY_RESULT:
        printk("HCI_EV_EXTENDED_INQUIRY_RESULT");
        break;
    case HCI_EV_IO_CAPA_REQUEST:
        printk("HCI_EV_IO_CAPA_REQUEST");
        break;
    case HCI_EV_SIMPLE_PAIR_COMPLETE:
        printk("HCI_EV_SIMPLE_PAIR_COMPLETE");
        break;
    case HCI_EV_REMOTE_HOST_FEATURES:
        printk("HCI_EV_REMOTE_HOST_FEATURES");
        break;
    default:
        printk("event");
        break;
    }
    printk(":%02x,len:%d,", *opcode,len);
    for (icount = 2; (icount < wlength) && (icount < 24); icount++)
        printk("%02x ", *(opcode+icount));
    printk("\n");
#endif
}

static inline ssize_t usb_put_user(struct sk_buff *skb,
        char __user *buf, int count)
{
    char __user *ptr = buf;
    int len = min_t(unsigned int, skb->len, count);

    if (copy_to_user(ptr, skb->data, len))
        return -EFAULT;

    return len;
}

static struct sk_buff *rtk_skb_queue[QUEUE_SIZE];
static int rtk_skb_queue_front = 0;
static int rtk_skb_queue_rear = 0;

static void rtk_enqueue(struct sk_buff *skb)
{
    unsigned long flags;
    spin_lock_irqsave(&queue_lock, flags);
    if (rtk_skb_queue_front == (rtk_skb_queue_rear + 1) % QUEUE_SIZE) {
        /*
         * If queue is full, current solution is to drop
         * the following entries.
         */
        RTKBT_WARN("%s: Queue is full, entry will be dropped", __func__);
    } else {
        rtk_skb_queue[rtk_skb_queue_rear] = skb;

        rtk_skb_queue_rear++;
        rtk_skb_queue_rear %= QUEUE_SIZE;

    }
    spin_unlock_irqrestore(&queue_lock, flags);
}

static struct sk_buff *rtk_dequeue_try(unsigned int deq_len)
{
    struct sk_buff *skb;
    struct sk_buff *skb_copy;

    if (rtk_skb_queue_front == rtk_skb_queue_rear) {
        RTKBT_WARN("%s: Queue is empty", __func__);
        return NULL;
    }

    skb = rtk_skb_queue[rtk_skb_queue_front];
    if (deq_len >= skb->len) {
        rtk_skb_queue[rtk_skb_queue_front] = NULL;
        rtk_skb_queue_front++;
        rtk_skb_queue_front %= QUEUE_SIZE;

        /*
         * Return skb addr to be dequeued, and the caller
         * should free the skb eventually.
         */
        return skb;
    } else {
        skb_copy = pskb_copy(skb, GFP_ATOMIC);
        skb_pull(skb, deq_len);
        /* Return its copy to be freed */
        return skb_copy;
    }
}

static inline int is_queue_empty(void)
{
    return (rtk_skb_queue_front == rtk_skb_queue_rear) ? 1 : 0;
}

static void rtk_clear_queue(void)
{
    struct sk_buff *skb;
    unsigned long flags;
    spin_lock_irqsave(&queue_lock, flags);
    while(!is_queue_empty()) {
        skb = rtk_skb_queue[rtk_skb_queue_front];
        rtk_skb_queue[rtk_skb_queue_front] = NULL;
        rtk_skb_queue_front++;
        rtk_skb_queue_front %= QUEUE_SIZE;
        if (skb) {
            kfree_skb(skb);
        }
    }
    spin_unlock_irqrestore(&queue_lock, flags);
}

/*
 * Realtek - Integrate from hci_core.c
 */

/* Get HCI device by index.
 * Device is held on return. */
static struct hci_dev *hci_dev_get(int index)
{
    if (index != 0)
        return NULL;

    return ghdev;
}

/* ---- HCI ioctl helpers ---- */
static int hci_dev_open(__u16 dev)
{
    struct hci_dev *hdev;
    int ret = 0;

    RTKBT_DBG("%s: dev %d", __func__, dev);

    hdev = hci_dev_get(dev);
    if (!hdev) {
        RTKBT_ERR("%s: Failed to get hci dev[Null]", __func__);
        return -ENODEV;
    }

    if (test_bit(HCI_UNREGISTER, &hdev->flags)) {
        ret = -ENODEV;
        goto done;
    }

    if (test_bit(HCI_UP, &hdev->flags)) {
        ret = -EALREADY;
        goto done;
    }

done:
    return ret;
}

static int hci_dev_do_close(struct hci_dev *hdev)
{
    if (hdev->flush)
        hdev->flush(hdev);
    /* After this point our queues are empty
     * and no tasks are scheduled. */
    hdev->close(hdev);
    /* Clear flags */
    hdev->flags = 0;
    memset(&hdev->conn_hash, 0, sizeof(struct hci_conn_hash));
    return 0;
}

static int hci_dev_close(__u16 dev)
{
    struct hci_dev *hdev;
    int err;
    hdev = hci_dev_get(dev);
    if (!hdev) {
        RTKBT_ERR("%s: failed to get hci dev[Null]", __func__);
        return -ENODEV;
    }

    err = hci_dev_do_close(hdev);

    return err;
}

static struct hci_dev *hci_alloc_dev(void)
{
    struct hci_dev *hdev;

    hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL);
    if (!hdev)
        return NULL;

    return hdev;
}

/* Free HCI device */
static void hci_free_dev(struct hci_dev *hdev)
{
    kfree(hdev);
}

/* Register HCI device */
static int hci_register_dev(struct hci_dev *hdev)
{
    int i, id;

    RTKBT_DBG("%s: %p name %s bus %d", __func__, hdev, hdev->name, hdev->bus);
    /* Do not allow HCI_AMP devices to register at index 0,
     * so the index can be used as the AMP controller ID.
     */
    id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;

    write_lock(&hci_dev_lock);

    sprintf(hdev->name, "hci%d", id);
    hdev->id = id;
    hdev->flags = 0;
    mutex_init(&hdev->lock);

    RTKBT_DBG("%s: id %d, name %s", __func__, hdev->id, hdev->name);


    for (i = 0; i < NUM_REASSEMBLY; i++)
        hdev->reassembly[i] = NULL;

    memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
    atomic_set(&hdev->promisc, 0);

    if (ghdev) {
        write_unlock(&hci_dev_lock);
        RTKBT_ERR("%s: Hci device has been registered already", __func__);
        return -1;
    } else
        ghdev = hdev;

    write_unlock(&hci_dev_lock);

    return id;
}

/* Unregister HCI device */
static void hci_unregister_dev(struct hci_dev *hdev)
{
    int i;

    RTKBT_DBG("%s: hdev %p name %s bus %d", __func__, hdev, hdev->name, hdev->bus);
    set_bit(HCI_UNREGISTER, &hdev->flags);

    write_lock(&hci_dev_lock);
    ghdev = NULL;
    write_unlock(&hci_dev_lock);

    hci_dev_do_close(hdev);
    for (i = 0; i < NUM_REASSEMBLY; i++)
        kfree_skb(hdev->reassembly[i]);
}


#ifdef CONFIG_SCO_OVER_HCI
/* copy data from the URB buffer into the ALSA ring buffer */
static bool rtk_copy_capture_data_to_alsa(struct btusb_data *data, uint8_t* p_data, unsigned int frames)
{
  	struct snd_pcm_runtime *runtime;
  	unsigned int frame_bytes, frames1;
  	u8 *dest;
    RTK_sco_card_t  *pSCOSnd = data->pSCOSnd;

  	runtime = pSCOSnd->capture.substream->runtime;
  	frame_bytes = 2;

  	dest = runtime->dma_area + pSCOSnd->capture.buffer_pos * frame_bytes;
  	if (pSCOSnd->capture.buffer_pos + frames <= runtime->buffer_size) {
  		memcpy(dest, p_data, frames * frame_bytes);
  	} else {
  		/* wrap around at end of ring buffer */
  		frames1 = runtime->buffer_size - pSCOSnd->capture.buffer_pos;
  		memcpy(dest, p_data, frames1 * frame_bytes);
  		memcpy(runtime->dma_area,
  		       p_data + frames1 * frame_bytes,
  		       (frames - frames1) * frame_bytes);
  	}

  	pSCOSnd->capture.buffer_pos += frames;
  	if (pSCOSnd->capture.buffer_pos >= runtime->buffer_size) {
  		pSCOSnd->capture.buffer_pos -= runtime->buffer_size;
  	}

    if((pSCOSnd->capture.buffer_pos%runtime->period_size) == 0) {
        snd_pcm_period_elapsed(pSCOSnd->capture.substream);
    }

  	return false;
}


static void hci_send_to_alsa_ringbuffer(struct hci_dev *hdev, struct sk_buff *skb)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    RTK_sco_card_t  *pSCOSnd = data->pSCOSnd;
    uint8_t* p_data;
    int sco_length = skb->len - HCI_SCO_HDR_SIZE;

    RTKBT_DBG("%s", __func__);

    if (!hdev) {
        RTKBT_ERR("%s: Frame for unknown HCI device", __func__);
        return;
    }

    if (!test_bit(ALSA_CAPTURE_RUNNING, &pSCOSnd->states)) {
        //RTKBT_WARN("%s: ALSA is not running", __func__);
        return;
    }

    p_data = (uint8_t *)skb->data + HCI_SCO_HDR_SIZE;
    rtk_copy_capture_data_to_alsa(data, p_data, sco_length/2);
}

#endif

static void hci_send_to_stack(struct hci_dev *hdev, struct sk_buff *skb)
{
    struct sk_buff *rtk_skb_copy = NULL;

    RTKBT_DBG("%s", __func__);

    if (!hdev) {
        RTKBT_ERR("%s: Frame for unknown HCI device", __func__);
        return;
    }

    if (!test_bit(HCI_RUNNING, &hdev->flags)) {
        RTKBT_ERR("%s: HCI not running", __func__);
        return;
    }

    rtk_skb_copy = pskb_copy(skb, GFP_ATOMIC);
    if (!rtk_skb_copy) {
        RTKBT_ERR("%s: Copy skb error", __func__);
        return;
    }

    memcpy(skb_push(rtk_skb_copy, 1), &bt_cb(skb)->pkt_type, 1);
    rtk_enqueue(rtk_skb_copy);

    /* Make sure bt char device existing before wakeup read queue */
    hdev = hci_dev_get(0);
    if (hdev) {
        RTKBT_DBG("%s: Try to wakeup read queue", __func__);
        wake_up_interruptible(&btchr_read_wait);
    }

    return;
}

/* Receive frame from HCI drivers */
static int hci_recv_frame(struct sk_buff *skb)
{
    struct hci_dev *hdev = (struct hci_dev *) skb->dev;

    if (!hdev || !test_bit(HCI_UP, &hdev->flags)) {
        kfree_skb(skb);
        return -ENXIO;
    }

    /* Incomming skb */
    bt_cb(skb)->incoming = 1;

    /* Time stamp */
    __net_timestamp(skb);

    if (atomic_read(&hdev->promisc)) {
#ifdef CONFIG_SCO_OVER_HCI
        if(bt_cb(skb)->pkt_type == HCI_SCODATA_PKT)
            hci_send_to_alsa_ringbuffer(hdev, skb);
#endif
        /* Send copy to the sockets */
        hci_send_to_stack(hdev, skb);
    }

    kfree_skb(skb);
    return 0;
}

/* Receive frame from HCI drivers */
static int hci_recv_sco_frame(struct sk_buff *skb)
{
    struct hci_dev *hdev = (struct hci_dev *) skb->dev;

    if (!hdev || !test_bit(HCI_UP, &hdev->flags)) {
        kfree_skb(skb);
        return -ENXIO;
    }

    /* Incomming skb */
    bt_cb(skb)->incoming = 1;

    /* Time stamp */
    __net_timestamp(skb);

    if (atomic_read(&hdev->promisc)) {
#ifdef CONFIG_SCO_OVER_HCI
        if(bt_cb(skb)->pkt_type == HCI_SCODATA_PKT)
            hci_send_to_alsa_ringbuffer(hdev, skb);
#endif
        /* Send copy to the sockets */
        hci_send_to_stack(hdev, skb);
    }

    kfree_skb(skb);
    return 0;
}

static int hci_reassembly(struct hci_dev *hdev, int type, void *data,
                          int count, __u8 index)
{
    int len = 0;
    int hlen = 0;
    int remain = count;
    struct sk_buff *skb;
    struct bt_skb_cb *scb;

    RTKBT_DBG("%s", __func__);

    if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) ||
            index >= NUM_REASSEMBLY)
        return -EILSEQ;

    skb = hdev->reassembly[index];

    if (!skb) {
        switch (type) {
        case HCI_ACLDATA_PKT:
            len = HCI_MAX_FRAME_SIZE;
            hlen = HCI_ACL_HDR_SIZE;
            break;
        case HCI_EVENT_PKT:
            len = HCI_MAX_EVENT_SIZE;
            hlen = HCI_EVENT_HDR_SIZE;
            break;
        case HCI_SCODATA_PKT:
            len = HCI_MAX_SCO_SIZE;
            hlen = HCI_SCO_HDR_SIZE;
            break;
        }

        skb = bt_skb_alloc(len, GFP_ATOMIC);
        if (!skb)
            return -ENOMEM;

        scb = (void *) skb->cb;
        scb->expect = hlen;
        scb->pkt_type = type;

        skb->dev = (void *) hdev;
        hdev->reassembly[index] = skb;

    }

    while (count) {
        scb = (void *) skb->cb;
        len = min_t(uint, scb->expect, count);

        memcpy(skb_put(skb, len), data, len);

        count -= len;
        data += len;
        scb->expect -= len;
        remain = count;

        switch (type) {
        case HCI_EVENT_PKT:
            if (skb->len == HCI_EVENT_HDR_SIZE) {
                struct hci_event_hdr *h = hci_event_hdr(skb);
                scb->expect = h->plen;

                if (skb_tailroom(skb) < scb->expect) {
                    kfree_skb(skb);
                    hdev->reassembly[index] = NULL;
                    return -ENOMEM;
                }
            }
            break;

        case HCI_ACLDATA_PKT:
            if (skb->len  == HCI_ACL_HDR_SIZE) {
                struct hci_acl_hdr *h = hci_acl_hdr(skb);
                scb->expect = __le16_to_cpu(h->dlen);

                if (skb_tailroom(skb) < scb->expect) {
                    kfree_skb(skb);
                    hdev->reassembly[index] = NULL;
                    return -ENOMEM;
                }
            }
            break;

        case HCI_SCODATA_PKT:
            if (skb->len == HCI_SCO_HDR_SIZE) {
                struct hci_sco_hdr *h = hci_sco_hdr(skb);
                scb->expect = h->dlen;

                if (skb_tailroom(skb) < scb->expect) {
                    kfree_skb(skb);
                    hdev->reassembly[index] = NULL;
                    return -ENOMEM;
                }
            }
            break;
        }

        if (scb->expect == 0) {
            /* Complete frame */
            if(HCI_ACLDATA_PKT == type)
                print_acl(skb,0);
            if(HCI_SCODATA_PKT == type)
                print_sco(skb,0);
            if(HCI_EVENT_PKT == type)
                print_event(skb);

            bt_cb(skb)->pkt_type = type;
            if(type == HCI_SCODATA_PKT) {
                hci_recv_sco_frame(skb);
            }
            else
                hci_recv_frame(skb);

            hdev->reassembly[index] = NULL;
            return remain;
        }
    }

    return remain;
}

static int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
{
    int rem = 0;

    if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
        return -EILSEQ;

    while (count) {
        rem = hci_reassembly(hdev, type, data, count, type - 1);
        if (rem < 0)
            return rem;

        data += (count - rem);
        count = rem;
    }

    return rem;
}

static void hci_hardware_error(void)
{
    struct sk_buff *rtk_skb_copy = NULL;
    int len = 4;
    uint8_t hardware_err_pkt[4] = {HCI_EVENT_PKT, 0x10, 0x01, HCI_VENDOR_USB_DISC_HARDWARE_ERROR};

    rtk_skb_copy = alloc_skb(len, GFP_ATOMIC);
    if (!rtk_skb_copy) {
        RTKBT_ERR("%s: Failed to allocate mem", __func__);
        return;
    }

    memcpy(skb_put(rtk_skb_copy, len), hardware_err_pkt, len);
    rtk_enqueue(rtk_skb_copy);

    wake_up_interruptible(&btchr_read_wait);
}

static int btchr_open(struct inode *inode_p, struct file  *file_p)
{
    struct btusb_data *data;
    struct hci_dev *hdev;
    struct sk_buff *skb;
    int i;

    RTKBT_INFO("%s: BT usb char device is opening", __func__);

    if(!check_set_driver_state_value(DEVICE_PROBED, CHAR_OPENED)) {
        RTKBT_ERR("%s: Device not probed", __func__);
        return -ENODEV;
    }


    hdev = hci_dev_get(0);
    if (!hdev) {
        RTKBT_ERR("%s: Failed to get hci dev[NULL]", __func__);
        return -ENODEV;
    }

    set_bit(HCI_UP, &hdev->flags);
    data = GET_DRV_DATA(hdev);

    atomic_inc(&hdev->promisc);
    /*
     * As bt device is not re-opened when hotplugged out, we cannot
     * trust on file's private data(may be null) when other file ops
     * are invoked.
     */
    file_p->private_data = data;

    hci_dev_open(0);
    rtk_clear_queue();
    for(i = 0; i < NUM_REASSEMBLY; i++) {
        skb = hdev->reassembly[i];
        if(skb) {
            hdev->reassembly[i] = NULL;
            kfree_skb(skb);
        }
    }
    return nonseekable_open(inode_p, file_p);
}

static int btchr_close(struct inode  *inode_p, struct file   *file_p)
{
    struct btusb_data *data;
    struct hci_dev *hdev;

    RTKBT_INFO("%s: BT usb char device is closing", __func__);

    data = file_p->private_data;
    file_p->private_data = NULL;

#if CONFIG_BLUEDROID
    /*
     * If the upper layer closes bt char interfaces, no reset
     * action required even bt device hotplugged out.
     */
    bt_reset = 0;
#endif


    hdev = hci_dev_get(0);
    if (hdev) {
        atomic_set(&hdev->promisc, 0);
        hci_dev_close(0);
        clear_bit(HCI_UP, &hdev->flags);
    }

    clear_driver_state(CHAR_OPENED);
    //if the state is not probed, the driver may be in the disconnecting state
    //and waitting for signal to wake up
    if((get_driver_state_value() & DEVICE_PROBED) == 0)
        wake_up_interruptible(&bt_drv_state_wait);
    return 0;
}

static ssize_t btchr_read(struct file *file_p,
        char __user *buf_p,
        size_t count,
        loff_t *pos_p)
{
    struct hci_dev *hdev;
    struct sk_buff *skb;
    ssize_t ret = 0;

    RTKBT_DBG("%s: BT usb char device is reading", __func__);

    while (count) {
        hdev = hci_dev_get(0);
        if (!hdev) {
            /*
             * Note: Only when BT device hotplugged out, we wil get
             * into such situation. In order to keep the upper layer
             * stack alive (blocking the read), we should never return
             * EFAULT or break the loop.
             */
            RTKBT_ERR("%s: Failed to get hci dev[Null]", __func__);
        }

        ret = wait_event_interruptible(btchr_read_wait, !is_queue_empty());
        if (ret < 0) {
            RTKBT_ERR("%s: wait event is signaled %zu", __func__, ret);
            break;
        }

        skb = rtk_dequeue_try(count);
        if (skb) {
            ret = usb_put_user(skb, buf_p, count);
            if (ret < 0)
                RTKBT_ERR("%s: Failed to put data to user space", __func__);
            kfree_skb(skb);
            break;
        }
    }

    return ret;
}

static ssize_t btchr_write(struct file *file_p,
        const char __user *buf_p,
        size_t count,
        loff_t *pos_p)
{
    struct btusb_data *data = file_p->private_data;
    struct hci_dev *hdev;
    struct sk_buff *skb;

    RTKBT_DBG("%s: BT usb char device is writing", __func__);

    if((get_driver_state_value() & DEVICE_PROBED) == 0) {
        RTKBT_ERR("%s: Device not probed", __func__);
        return POLLERR | POLLHUP;
    }

    hdev = hci_dev_get(0);
    if (!hdev) {
        RTKBT_WARN("%s: Failed to get hci dev[Null]", __func__);
        /*
         * Note: we bypass the data from the upper layer if bt device
         * is hotplugged out. Fortunatelly, H4 or H5 HCI stack does
         * NOT check btchr_write's return value. However, returning
         * count instead of EFAULT is preferable.
         */
        /* return -EFAULT; */
        return count;
    }

    /* Never trust on btusb_data, as bt device may be hotplugged out */
    data = GET_DRV_DATA(hdev);
    if (!data) {
        RTKBT_WARN("%s: Failed to get bt usb driver data[Null]", __func__);
        return count;
    }

    if (count > HCI_MAX_FRAME_SIZE)
        return -EINVAL;

    skb = bt_skb_alloc(count, GFP_ATOMIC);
    if (!skb)
        return -ENOMEM;
    skb_reserve(skb, -1); // Add this line

    if (copy_from_user(skb_put(skb, count), buf_p, count)) {
        RTKBT_ERR("%s: Failed to get data from user space", __func__);
        kfree_skb(skb);
        return -EFAULT;
    }

    skb->dev = (void *)hdev;
    bt_cb(skb)->pkt_type = *((__u8 *)skb->data);
    skb_pull(skb, 1);
    data->hdev->send(skb);

    return count;
}

static unsigned int btchr_poll(struct file *file_p, poll_table *wait)
{
    struct btusb_data *data = file_p->private_data;
    struct hci_dev *hdev;

    RTKBT_DBG("%s: BT usb char device is polling", __func__);

    if((get_driver_state_value() & DRIVER_ON) == 0 ||
          (get_driver_state_value() & DEVICE_PROBED) == 0) {
        RTKBT_ERR("%s: Device not probed", __func__);
        return POLLERR | POLLHUP;
    }

    poll_wait(file_p, &btchr_read_wait, wait);

    hdev = hci_dev_get(0);
    if (!hdev) {
        RTKBT_ERR("%s: Failed to get hci dev[Null]", __func__);
        mdelay(URB_CANCELING_DELAY_MS);
        return POLLOUT | POLLWRNORM;
    }

    /* Never trust on btusb_data, as bt device may be hotplugged out */
    data = GET_DRV_DATA(hdev);
    if (!data) {
        /*
         * When bt device is hotplugged out, btusb_data will
         * be freed in disconnect.
         */
        RTKBT_ERR("%s: Failed to get bt usb driver data[Null]", __func__);
        mdelay(URB_CANCELING_DELAY_MS);
        return POLLOUT | POLLWRNORM;
    }

    if (!is_queue_empty())
        return POLLIN | POLLRDNORM;

    return POLLOUT | POLLWRNORM;
}

static long btchr_ioctl(struct file *file_p, unsigned int cmd, unsigned long arg){
    int ret = 0;
    struct hci_dev *hdev;
    struct btusb_data *data;
    firmware_info *fw_info;

    if((get_driver_state_value() & DRIVER_ON) == 0 ||
          (get_driver_state_value() & DEVICE_PROBED) == 0) {
        RTKBT_ERR("%s bt controller is disconnect!", __func__);
        return -ENODEV;
    }

    hdev = hci_dev_get(0);
    if(!hdev) {
        RTKBT_ERR("%s device is NULL!", __func__);
        return 0;
    }
    data = GET_DRV_DATA(hdev);
    fw_info = data->fw_info;

    RTKBT_INFO(" btchr_ioctl with Cmd:%d",cmd);
    switch (cmd) {
        case DOWN_FW_CFG:
            ret = usb_autopm_get_interface(data->intf);
            if (ret < 0){
                goto failed;
            }

            ret = download_patch(fw_info,1);
            usb_autopm_put_interface(data->intf);
            if(ret < 0){
                RTKBT_ERR("%s:Failed in download_patch with ret:%d",__func__,ret);
                goto failed;
            }

            ret = hdev->open(hdev);
            if(ret < 0){
                RTKBT_ERR("%s:Failed in hdev->open(hdev):%d",__func__,ret);
                goto failed;
            }
            ret = 1;
            break;

#ifdef CONFIG_SCO_OVER_HCI
        case SET_ISO_CFG:
            if(get_user(hdev->voice_setting, (__u16 __user*)arg)) {
                ret = -EFAULT;
            }
            RTKBT_INFO(" voice settings = 0x%04x", hdev->voice_setting);
            break;
#endif

        case GET_USB_INFO:
            ret = hdev->open(hdev);
            if(ret < 0){
                RTKBT_ERR("%s:Failed in hdev->open(hdev):%d",__func__,ret);
                //goto done;
            }
            put_user(usb_info, (__u32 __user*)arg);
            ret = 1;
            break;
        case RESET_CONTROLLER:
            reset_controller(fw_info);
            ret = 1;
            break;

        case DWFW_CMPLT:
        {
            uint16_t lmp_sub = 0;
            if(get_user(lmp_sub, (__u16 __user*)arg)) {
                ret = -EFAULT;
            }
            else if(lmp_sub != 0) {
                fw_info->patch_entry->lmp_sub = lmp_sub;
            }
            RTKBT_INFO("%s lmp_sub = 0x%x, patch_entry->lmp_sub = 0x%x", __func__,
                          lmp_sub, fw_info->patch_entry->lmp_sub);
        }
            break;

        default:
            RTKBT_ERR("%s:Failed with wrong Cmd:%d",__func__,cmd);
            goto failed;
        }
failed:
        return ret;

}

#ifdef CONFIG_COMPAT
static long compat_btchr_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
{
    return btchr_ioctl(filp, cmd, (unsigned long) compat_ptr(arg));
}
#endif

static struct file_operations bt_chrdev_ops  = {
    open    :    btchr_open,
    release    :    btchr_close,
    read    :    btchr_read,
    write    :    btchr_write,
    poll    :    btchr_poll,
    unlocked_ioctl   :   btchr_ioctl,
#ifdef CONFIG_COMPAT
    compat_ioctl :  compat_btchr_ioctl,
#endif
};

static int btchr_init(void)
{
    int res = 0;
    struct device *dev;

    RTKBT_INFO("Register usb char device interface for BT driver");
    skb_queue_head_init(&btchr_readq);
    init_waitqueue_head(&btchr_read_wait);
    init_waitqueue_head(&bt_drv_state_wait);

    bt_char_class = class_create(THIS_MODULE, BT_CHAR_DEVICE_NAME);
    if (IS_ERR(bt_char_class)) {
        RTKBT_ERR("Failed to create bt char class");
        return PTR_ERR(bt_char_class);
    }

    res = alloc_chrdev_region(&bt_devid, 0, 1, BT_CHAR_DEVICE_NAME);
    if (res < 0) {
        RTKBT_ERR("Failed to allocate bt char device");
        goto err_alloc;
    }

    dev = device_create(bt_char_class, NULL, bt_devid, NULL, BT_CHAR_DEVICE_NAME);
    if (IS_ERR(dev)) {
        RTKBT_ERR("Failed to create bt char device");
        res = PTR_ERR(dev);
        goto err_create;
    }

    cdev_init(&bt_char_dev, &bt_chrdev_ops);
    res = cdev_add(&bt_char_dev, bt_devid, 1);
    if (res < 0) {
        RTKBT_ERR("Failed to add bt char device");
        goto err_add;
    }

    return 0;

err_add:
    device_destroy(bt_char_class, bt_devid);
err_create:
    unregister_chrdev_region(bt_devid, 1);
err_alloc:
    class_destroy(bt_char_class);
    return res;
}

static void btchr_exit(void)
{
    RTKBT_INFO("Unregister usb char device interface for BT driver");

    device_destroy(bt_char_class, bt_devid);
    cdev_del(&bt_char_dev);
    unregister_chrdev_region(bt_devid, 1);
    class_destroy(bt_char_class);

    return;
}
#endif

static int send_hci_cmd(firmware_info *fw_info)
{
   int i = 0;
   int ret_val = -1;
   while((ret_val<0)&&(i++<10))
   {
       ret_val = usb_control_msg(
          fw_info->udev, fw_info->pipe_out,
          0, USB_TYPE_CLASS, 0, 0,
          (void *)(fw_info->send_pkt),
          fw_info->pkt_len, MSG_TO);
   }
   return ret_val;
}

static int rcv_hci_evt(firmware_info *fw_info)
{
    int ret_len = 0, ret_val = 0;
    int i;

    while (1) {
        for(i = 0; i < 5; i++) {
        ret_val = usb_interrupt_msg(
            fw_info->udev, fw_info->pipe_in,
            (void *)(fw_info->rcv_pkt), PKT_LEN,
            &ret_len, MSG_TO);
            if (ret_val >= 0)
                break;
        }

        if (ret_val < 0)
            return ret_val;

        if (CMD_CMP_EVT == fw_info->evt_hdr->evt) {
            if (fw_info->cmd_hdr->opcode == fw_info->cmd_cmp->opcode)
                return ret_len;
        }
    }
}

static int set_bt_onoff(firmware_info *fw_info, uint8_t onoff)
{
    patch_info *patch_entry;
    int ret_val;

    RTKBT_INFO("%s: %s", __func__, onoff != 0 ? "on" : "off");

    patch_entry = fw_info->patch_entry;
    if (!patch_entry)
        return -1;

    fw_info->cmd_hdr->opcode = cpu_to_le16(BTOFF_OPCODE);
    fw_info->cmd_hdr->plen = 1;
    fw_info->pkt_len = CMD_HDR_LEN + 1;
    fw_info->send_pkt[CMD_HDR_LEN] = onoff;

    ret_val = send_hci_cmd(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send bt %s cmd, errno %d",
                __func__, onoff != 0 ? "on" : "off", ret_val);
        return ret_val;
    }

    ret_val = rcv_hci_evt(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to receive bt %s event, errno %d",
                __func__, onoff != 0 ? "on" : "off", ret_val);
        return ret_val;
    }

    return ret_val;
}

static patch_info *get_fw_table_entry(struct usb_device* udev)
{
    patch_info *patch_entry = fw_patch_table;
    uint16_t vid = le16_to_cpu(udev->descriptor.idVendor);
    uint16_t pid = le16_to_cpu(udev->descriptor.idProduct);
    uint32_t entry_size = sizeof(fw_patch_table) / sizeof(fw_patch_table[0]);
    uint32_t i;

    RTKBT_INFO("%s: Product id = 0x%04x, fw table entry size %d", __func__, pid, entry_size);
    usb_info = (uint32_t)(vid<<16) | pid;

    for (i = 0; i < entry_size; i++, patch_entry++) {
        if ((vid == patch_entry->vid)&&(pid == patch_entry->pid))
            break;
    }

    if (i == entry_size) {
        RTKBT_ERR("%s: No fw table entry found", __func__);
        return NULL;
    }

    return patch_entry;
}

#if SUSPNED_DW_FW
static patch_info *get_suspend_fw_table_entry(struct usb_device* udev)
{
    patch_info *patch_entry = fw_patch_table;
    patch_info *patch_entry_real = NULL;
    uint16_t vid = le16_to_cpu(udev->descriptor.idVendor);
    uint16_t pid = le16_to_cpu(udev->descriptor.idProduct);
    uint32_t entry_size = sizeof(fw_patch_table) / sizeof(fw_patch_table[0]);
    uint32_t i;

    RTKBT_INFO("%s: Product id = 0x%04x, fw table entry size %d", __func__, pid, entry_size);

    for (i = 0; i < entry_size; i++, patch_entry++) {
        if ((vid == patch_entry->vid)&&(pid == patch_entry->pid))
            break;
    }

    if (i == entry_size) {
        RTKBT_ERR("%s: No fw table entry found", __func__);
        return NULL;
    }
    patch_entry_real = kmalloc(sizeof(fw_patch_table[0]), GFP_KERNEL);
    if(!patch_entry_real)
        return NULL;
    memcpy(patch_entry_real, patch_entry, sizeof(fw_patch_table[0]));
    return patch_entry_real;
}
#endif

static struct rtk_epatch_entry *get_fw_patch_entry(struct rtk_epatch *epatch_info, uint16_t eco_ver)
{
    int patch_num = epatch_info->number_of_total_patch;
    uint8_t *epatch_buf = (uint8_t *)epatch_info;
    struct rtk_epatch_entry *p_entry = NULL;
    int coex_date;
    int coex_ver;
    int i;

    for (i = 0; i < patch_num; i++) {
        if (*(uint16_t *)(epatch_buf + 14 + 2*i) == eco_ver + 1) {
            p_entry = kzalloc(sizeof(*p_entry), GFP_KERNEL);
            if (!p_entry) {
                RTKBT_ERR("%s: Failed to allocate mem for patch entry", __func__);
                return NULL;
            }
            p_entry->chip_id = eco_ver + 1;
            p_entry->patch_length = *(uint16_t*)(epatch_buf + 14 + 2*patch_num + 2*i);
            p_entry->start_offset = *(uint32_t*)(epatch_buf + 14 + 4*patch_num + 4*i);
            p_entry->coex_version = *(uint32_t*)(epatch_buf + p_entry->start_offset + p_entry->patch_length - 12);
            p_entry->svn_version = *(uint32_t*)(epatch_buf + p_entry->start_offset + p_entry->patch_length - 8);
            p_entry->fw_version = *(uint32_t*)(epatch_buf + p_entry->start_offset + p_entry->patch_length - 4);

            coex_date = ((p_entry->coex_version >> 16) & 0x7ff) + ((p_entry->coex_version >> 27) * 10000);
            coex_ver = p_entry->coex_version & 0xffff;

            RTKBT_INFO("BTCOEX:20%06d-0x%04x svn version:0x%08x fw version:0x%08x rtk_btusb version:%s Cut:%d, patch length:0x%04x, patch offset:0x%08x\n", \
                    coex_date, coex_ver, p_entry->svn_version, p_entry->fw_version, VERSION, p_entry->chip_id, p_entry->patch_length, p_entry->start_offset);
            break;
        }
    }

    return p_entry;
}

/*reset_controller is aimed to reset_bt_fw before updata Fw patch*/
int reset_controller(firmware_info* fw_info)
{
    int ret_val;
    RTKBT_ERR("reset_controller");

    if (!fw_info)
        return -ENODEV;

    fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_FORCE_RESET_AND_PATCHABLE);
    fw_info->cmd_hdr->plen = 0;
    fw_info->pkt_len = CMD_HDR_LEN;
    ret_val = send_hci_cmd(fw_info);

    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send hci cmd 0x%04x, errno %d",
                __func__, fw_info->cmd_hdr->opcode, ret_val);
        return ret_val;
    }

    //sleep 1s for firmware reset.
    msleep(1000);
    RTKBT_INFO("%s: Wait fw reset for 1000ms",__func__);

    return ret_val;
}
/*reset_controller is aimed to reset_bt_fw before updata Fw patch*/

/*
 * check the return value
 * 1: need to download fw patch
 * 0: no need to download fw patch
 * <0: failed to check lmp version
 */
static int check_fw_version(firmware_info* fw_info, bool resume_check)
{
    struct hci_rp_read_local_version *read_ver_rsp;
    patch_info *patch_entry = NULL;
    int ret_val = -1, i, ret_len = 0;
    struct sk_buff *rtk_skb_copy = NULL;
    unsigned char pkt_type = HCI_EVENT_PKT;

    fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_OP_READ_LOCAL_VERSION);
    fw_info->cmd_hdr->plen = 0;
    fw_info->pkt_len = CMD_HDR_LEN;

    ret_val = send_hci_cmd(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send hci cmd 0x%04x, errno %d",
                __func__, fw_info->cmd_hdr->opcode, ret_val);
        return ret_val;
    }

    while (1) {
        for(i = 0; i < 5; i++) {
        ret_val = usb_interrupt_msg(
            fw_info->udev, fw_info->pipe_in,
            (void *)(fw_info->rcv_pkt), PKT_LEN,
            &ret_len, MSG_TO);
            if (ret_val >= 0)
                break;
        }

        if (ret_val < 0) {
            RTKBT_ERR("%s: Failed to receive hci event, errno %d",
                __func__, ret_val);
            return ret_val;
        }

        if ((CMD_CMP_EVT == fw_info->evt_hdr->evt) &&
              (fw_info->cmd_hdr->opcode == fw_info->cmd_cmp->opcode)) {
                break;
        }
        else if(resume_check) {
            rtk_skb_copy = bt_skb_alloc((ret_len), GFP_ATOMIC);
            if (!rtk_skb_copy) {
              RTKBT_ERR("%s: Failed to allocate mem", __func__);
              return 2;
            }

            memcpy(skb_put(rtk_skb_copy, ret_len), fw_info->rcv_pkt, ret_len);
            memcpy(skb_push(rtk_skb_copy, 1), &pkt_type, 1);
            rtk_enqueue(rtk_skb_copy);

            rtk_skb_copy = NULL;
            wake_up_interruptible(&btchr_read_wait);
        }
    }

    patch_entry = fw_info->patch_entry;
    read_ver_rsp = (struct hci_rp_read_local_version *)(fw_info->rsp_para);

    RTKBT_INFO("%s: Controller lmp = 0x%04x, patch lmp = 0x%04x, default patch lmp = 0x%04x",
            __func__, read_ver_rsp->lmp_subver, patch_entry->lmp_sub, patch_entry->lmp_sub_default);

    if (read_ver_rsp->lmp_subver == patch_entry->lmp_sub_default) {
        RTKBT_INFO("%s: Cold BT controller startup", __func__);

        return 2;

    } else if (read_ver_rsp->lmp_subver != patch_entry->lmp_sub) {
        RTKBT_INFO("%s: Warm BT controller startup with updated lmp", __func__);
        return 1;
    } else {
        RTKBT_INFO("%s: Warm BT controller startup with same lmp", __func__);
        return 0;
    }
}

#if SET_WAKEUP_DEVICE
int set_wakeup_device(firmware_info* fw_info, uint8_t* wakeup_bdaddr)
{
    struct rtk_eversion_evt *ever_evt;
    int ret_val;

    if (!fw_info)
        return -ENODEV;

    fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_ADD_WAKE_UP_DEVICE);
    fw_info->cmd_hdr->plen = 7;
    memcpy(fw_info->req_para, wakeup_bdaddr, 7);
    fw_info->pkt_len = CMD_HDR_LEN + 7;

    ret_val = send_hci_cmd(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send hci cmd 0x%04x, errno %d\n",
            __func__, fw_info->cmd_hdr->opcode, ret_val);
        return ret_val;
    }

    ret_val = rcv_hci_evt(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to receive hci event, errno %d\n",__func__, ret_val);
        return ret_val;
    }

    ever_evt = (struct rtk_eversion_evt *)(fw_info->rsp_para);

    RTKBT_DBG("%s: status %d, eversion %d", __func__, ever_evt->status, ever_evt->version);
    return ret_val;
}
#endif

/*reset_channel to recover the communication between wifi 8192eu with 8761 bt controller in case of geteversion error*/

static int reset_channel(firmware_info* fw_info)
{
    struct rtk_reset_evt *ever_evt;
    int ret_val;

    if (!fw_info)
        return -ENODEV;

    fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_RESET);
    fw_info->cmd_hdr->plen = 0;
    fw_info->pkt_len = CMD_HDR_LEN;

    ret_val = send_hci_cmd(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send  hci cmd 0x%04x, errno %d",
                __func__, fw_info->cmd_hdr->opcode, ret_val);
        return ret_val;
    }

    ret_val = rcv_hci_evt(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to receive  hci event, errno %d",
                __func__, ret_val);
        return ret_val;
    }

    ever_evt = (struct rtk_reset_evt *)(fw_info->rsp_para);

    RTKBT_INFO("%s: status %d ", __func__, ever_evt->status);

    //sleep 300ms for channel reset.
    msleep(300);
    RTKBT_INFO("%s: Wait channel reset for 300ms",__func__);

    return ret_val;
}


//sometimes the controller is in warm resume,and still send message to host
//we should reset controller and clean the hardware buffer
static bool reset_and_clean_hw_buffer(firmware_info* fw_info)
{
    int ret_val/*, i*/;
    int ret_len = 0;
    bool event_recv = false;

    if (!fw_info)
        return -ENODEV;

    fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_RESET);
    fw_info->cmd_hdr->plen = 0;
    fw_info->pkt_len = CMD_HDR_LEN;

    ret_val = send_hci_cmd(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send  hci cmd 0x%04x, errno %d",
                __func__, fw_info->cmd_hdr->opcode, ret_val);
        return ret_val;
    }

    //we need to clean the hardware buffer
    while (1) {
        ret_val = usb_interrupt_msg(
            fw_info->udev, fw_info->pipe_in,
            (void *)(fw_info->rcv_pkt), PKT_LEN,
            &ret_len, (MSG_TO/2));

        if(ret_val >= 0) {
          if(event_recv) {
            RTKBT_INFO("%s: clear hardware event", __func__);
            continue;
          }
        }
        else {
          return event_recv;
        }

        if (CMD_CMP_EVT == fw_info->evt_hdr->evt) {
            if (fw_info->cmd_hdr->opcode == fw_info->cmd_cmp->opcode) {
              event_recv = true;
            }
        }
    }
    return ret_val;
}
#if 0
static int read_localversion(firmware_info* fw_info)
{
    struct rtk_localversion_evt *ever_evt;
    int ret_val;

    if (!fw_info)
        return -ENODEV;

    fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_READ_LMP_VERISION);
    fw_info->cmd_hdr->plen = 0;
    fw_info->pkt_len = CMD_HDR_LEN;

    ret_val = send_hci_cmd(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send  hci cmd 0x%04x, errno %d",
                __func__, fw_info->cmd_hdr->opcode, ret_val);
        return ret_val;
    }

    ret_val = rcv_hci_evt(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to receive  hci event, errno %d",
                __func__, ret_val);
        return ret_val;
    }

    ever_evt = (struct rtk_localversion_evt *)(fw_info->rsp_para);

    RTKBT_INFO("%s: status %d ", __func__, ever_evt->status);
    RTKBT_INFO("%s: hci_version %d ", __func__, ever_evt->hci_version);
    RTKBT_INFO("%s: hci_revision %d ", __func__, ever_evt->hci_revision);
    RTKBT_INFO("%s: lmp_version %d ", __func__, ever_evt->lmp_version);
    RTKBT_INFO("%s: lmp_subversion %d ", __func__, ever_evt->lmp_subversion);
    RTKBT_INFO("%s: lmp_manufacture %d ", __func__, ever_evt->lmp_manufacture);
    //sleep 300ms for channel reset.
    msleep(300);
    RTKBT_INFO("%s: Wait channel reset for 300ms",__func__);

    return ret_val;
}
#endif
static int get_eversion(firmware_info* fw_info)
{
    struct rtk_eversion_evt *ever_evt;
    int ret_val;

    if (!fw_info)
        return -ENODEV;

    fw_info->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_READ_RTK_ROM_VERISION);
    fw_info->cmd_hdr->plen = 0;
    fw_info->pkt_len = CMD_HDR_LEN;

    ret_val = send_hci_cmd(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to send hci cmd 0x%04x, errno %d",
                __func__, fw_info->cmd_hdr->opcode, ret_val);
        return ret_val;
    }

    ret_val = rcv_hci_evt(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to receive hci event, errno %d",
                __func__, ret_val);
        return ret_val;
    }

    ever_evt = (struct rtk_eversion_evt *)(fw_info->rsp_para);

    RTKBT_INFO("%s: status %d, eversion %d", __func__, ever_evt->status, ever_evt->version);

    if (ever_evt->status)
        fw_info->patch_entry->eversion = 0;
    else
        fw_info->patch_entry->eversion = ever_evt->version;

    return ret_val;
}

static void rtk_update_altsettings(patch_info *patch_entry, const unsigned char* org_config_buf, int org_config_len, unsigned char ** new_config_buf_ptr, int *new_config_len_ptr)
{
    static unsigned char config_buf[1024];
    unsigned short offset[256];
    unsigned char val[256];

    struct rtk_bt_vendor_config* config = (struct rtk_bt_vendor_config*) config_buf;
    struct rtk_bt_vendor_config_entry* entry = config->entry;

    int count = 0,temp = 0, i = 0, j;

    memset(config_buf, 0, sizeof(config_buf));
    memset(offset, 0, sizeof(offset));
    memset(val, 0, sizeof(val));

    memcpy(config_buf, org_config_buf, org_config_len);
    *new_config_buf_ptr = config_buf;
    *new_config_len_ptr = org_config_len;

    count = getAltSettings(patch_entry, offset, sizeof(offset)/sizeof(unsigned short));
    if(count <= 0){
        RTKBT_INFO("rtk_update_altsettings: No AltSettings");
        return;
    }else{
        RTKBT_INFO("rtk_update_altsettings: %d AltSettings", count);
    }

    RTKBT_INFO("ORG Config len=%08x:\n", org_config_len);
    for(i=0;i<=org_config_len;i+=0x10)
    {
        RTKBT_INFO("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
            config_buf[i], config_buf[i+1], config_buf[i+2], config_buf[i+3], config_buf[i+4], config_buf[i+5], config_buf[i+6], config_buf[i+7], \
            config_buf[i+8], config_buf[i+9], config_buf[i+10], config_buf[i+11], config_buf[i+12], config_buf[i+13], config_buf[i+14], config_buf[i+15]);
    }

    if (config->data_len != org_config_len - sizeof(struct rtk_bt_vendor_config))
    {
        RTKBT_ERR("rtk_update_altsettings: config len(%x) is not right(%x)", (int)(config->data_len), (int)(org_config_len-sizeof(struct rtk_bt_vendor_config)));
        return;
    }

    for (i=0; i<config->data_len;)
    {
        for(j = 0; j < count;j++)
        {
            if(entry->offset == offset[j])
                offset[j] = 0;
        }
        if(getAltSettingVal(patch_entry, entry->offset, val) == entry->entry_len){
            RTKBT_INFO("rtk_update_altsettings: replace %04x[%02x]", entry->offset, entry->entry_len);
            memcpy(entry->entry_data, val, entry->entry_len);
        }
        temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
        i += temp;
        entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
    }
    for(j = 0; j < count;j++){
        if(offset[j] == 0)
            continue;
        entry->entry_len = getAltSettingVal(patch_entry, offset[j], val);
        if(entry->entry_len <= 0)
            continue;
        entry->offset = offset[j];
        memcpy(entry->entry_data, val, entry->entry_len);
        RTKBT_INFO("rtk_update_altsettings: add %04x[%02x]", entry->offset, entry->entry_len);
        temp = entry->entry_len + sizeof(struct rtk_bt_vendor_config_entry);
        i += temp;
        entry = (struct rtk_bt_vendor_config_entry*)((uint8_t*)entry + temp);
    }
    config->data_len = i;
    *new_config_buf_ptr = config_buf;
    *new_config_len_ptr = config->data_len+sizeof(struct rtk_bt_vendor_config);

    return;
}

static int load_firmware(firmware_info *fw_info, uint8_t **buff)
{
    const struct firmware *fw, *cfg;
    struct usb_device *udev;
    patch_info *patch_entry;
    char *config_name, *fw_name;
    int fw_len = 0;
    int ret_val;

    int config_len = 0, buf_len = -1;
    uint8_t *buf = *buff, *config_file_buf = NULL;
    uint8_t *epatch_buf = NULL;

    struct rtk_epatch *epatch_info = NULL;
    uint8_t need_download_fw = 1;
    struct rtk_extension_entry patch_lmp = {0};
    struct rtk_epatch_entry *p_epatch_entry = NULL;
    uint16_t lmp_version;
    //uint8_t use_mp_fw = 0;
    RTKBT_DBG("%s: start", __func__);

    udev = fw_info->udev;
    patch_entry = fw_info->patch_entry;
    lmp_version = patch_entry->lmp_sub_default;
    config_name = patch_entry->config_name;
/* 1 Mptool Fw; 0 Normal Fw */
    if(DRV_MP_MODE == mp_drv_mode){
        fw_name = patch_entry->mp_patch_name;
    }else{
        fw_name = patch_entry->patch_name;
    }

    RTKBT_INFO("%s: Default lmp version = 0x%04x, config file name[%s], "
            "fw file name[%s]", __func__, lmp_version,config_name, fw_name);

    ret_val = request_firmware(&cfg, config_name, &udev->dev);
    if (ret_val < 0)
        config_len = 0;
    else {
        int i;
        rtk_update_altsettings(patch_entry, cfg->data, cfg->size, &config_file_buf, &config_len);

        RTKBT_INFO("Final Config len=%08x:\n", config_len);
        for(i=0;i<=config_len;i+=0x10)
        {
            RTKBT_INFO("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
                config_file_buf[i], config_file_buf[i+1], config_file_buf[i+2], config_file_buf[i+3], config_file_buf[i+4], config_file_buf[i+5], config_file_buf[i+6], config_file_buf[i+7], \
                config_file_buf[i+8], config_file_buf[i+9], config_file_buf[i+10], config_file_buf[i+11], config_file_buf[i+12], config_file_buf[i+13], config_file_buf[i+14], config_file_buf[i+15]);
        }

        release_firmware(cfg);
    }

    ret_val = request_firmware(&fw, fw_name, &udev->dev);
    if (ret_val < 0)
        goto fw_fail;
    else {
        epatch_buf = vmalloc(fw->size);
        RTKBT_INFO("%s: epatch_buf = vmalloc(fw->size, GFP_KERNEL)", __func__);
        if (!epatch_buf) {
            release_firmware(fw);
            goto fw_fail;
        }
        memcpy(epatch_buf, fw->data, fw->size);
        fw_len = fw->size;
        buf_len = fw_len + config_len;
        release_firmware(fw);
    }

    if (lmp_version == ROM_LMP_8723a) {
        RTKBT_DBG("%s: 8723a -> use old style patch", __func__);
        if (!memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8)) {
            RTKBT_ERR("%s: 8723a check signature error", __func__);
            need_download_fw = 0;
        } else {
            if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
                RTKBT_ERR("%s: Failed to allocate mem for fw&config", __func__);
                buf_len = -1;
            } else {
                RTKBT_DBG("%s: 8723a -> fw copy directly", __func__);
                memcpy(buf, epatch_buf, buf_len);
                patch_entry->lmp_sub = *(uint16_t *)(buf + buf_len - config_len - 4);
                RTKBT_DBG("%s: Config lmp version = 0x%04x", __func__,
                        patch_entry->lmp_sub);
                vfree(epatch_buf);
                RTKBT_INFO("%s:ROM_LMP_8723a vfree(epatch_buf)", __func__);
                epatch_buf = NULL;
                if (config_len)
                    memcpy(buf + buf_len - config_len, config_file_buf, config_len);
            }
        }
    } else {
        RTKBT_DBG("%s: Not 8723a -> use new style patch", __func__);

        RTKBT_DBG("%s: reset_channel before get_eversion from bt controller", __func__);
        ret_val = reset_channel(fw_info);
        if (ret_val < 0) {
            RTKBT_ERR("%s: Failed to reset_channel, errno %d", __func__, ret_val);
            goto fw_fail;
        }
//        read_localversion(fw_info);
        RTKBT_DBG("%s: get_eversion from bt controller", __func__);

        ret_val = get_eversion(fw_info);
        if (ret_val < 0) {
            RTKBT_ERR("%s: Failed to get eversion, errno %d", __func__, ret_val);
            goto fw_fail;
        }
        RTKBT_DBG("%s: Get eversion =%d", __func__, patch_entry->eversion);
        if (memcmp(epatch_buf + buf_len - config_len - 4 , EXTENSION_SECTION_SIGNATURE, 4)) {
            RTKBT_ERR("%s: Failed to check extension section signature", __func__);
            need_download_fw = 0;
        } else {
            uint8_t *temp;
            temp = epatch_buf+buf_len-config_len - 5;
            do {
                if (*temp == 0x00) {
                    patch_lmp.opcode = *temp;
                    patch_lmp.length = *(temp-1);
                    if ((patch_lmp.data = kzalloc(patch_lmp.length, GFP_KERNEL))) {
                        int k;
                        for (k = 0; k < patch_lmp.length; k++) {
                            *(patch_lmp.data+k) = *(temp-2-k);
                            RTKBT_DBG("data = 0x%x", *(patch_lmp.data+k));
                        }
                    }
                    RTKBT_DBG("%s: opcode = 0x%x, length = 0x%x, data = 0x%x", __func__,
                            patch_lmp.opcode, patch_lmp.length, *(patch_lmp.data));
                    break;
                }
                temp -= *(temp-1) + 2;
            } while (*temp != 0xFF);

            if (patch_lmp.data && lmp_version != project_id[*(patch_lmp.data)]) {
                RTKBT_ERR("%s: Default lmp_version 0x%04x, project_id[%d] 0x%04x "
                        "-> not match", __func__, lmp_version, *(patch_lmp.data),project_id[*(patch_lmp.data)]);
                if (patch_lmp.data)
                    kfree(patch_lmp.data);
                need_download_fw = 0;
            } else {
                if (patch_lmp.data) {
                    RTKBT_INFO("%s: Default lmp_version 0x%04x, project_id[%d] 0x%04x "
                            "-> match", __func__, lmp_version, *(patch_lmp.data), project_id[*(patch_lmp.data)]);
                }
                if (patch_lmp.data)
                    kfree(patch_lmp.data);
                if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8)) {
                    RTKBT_ERR("%s: Check signature error", __func__);
                    need_download_fw = 0;
                } else {
                    epatch_info = (struct rtk_epatch*)epatch_buf;
                    patch_entry->lmp_sub = (uint16_t)epatch_info->fw_version;

                    RTKBT_DBG("%s: lmp version 0x%04x, fw_version 0x%x, "
                            "number_of_total_patch %d", __func__,
                            patch_entry->lmp_sub, epatch_info->fw_version,
                            epatch_info->number_of_total_patch);

                    /* Get right epatch entry */
                    p_epatch_entry = get_fw_patch_entry(epatch_info, patch_entry->eversion);
                    if (p_epatch_entry == NULL) {
                        RTKBT_WARN("%s: Failed to get fw patch entry", __func__);
                        ret_val = -1;
                        goto fw_fail ;
                    }

                    buf_len = p_epatch_entry->patch_length + config_len;
                    RTKBT_DBG("buf_len = 0x%x", buf_len);

                    if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
                        RTKBT_ERR("%s: Can't alloc memory for  fw&config", __func__);
                        buf_len = -1;
                        kfree(p_epatch_entry);
                    } else {
                        memcpy(buf, &epatch_buf[p_epatch_entry->start_offset], p_epatch_entry->patch_length);
                        memcpy(&buf[p_epatch_entry->patch_length-4], &epatch_info->fw_version, 4);
                        kfree(p_epatch_entry);
                    }
                    vfree(epatch_buf);
                    RTKBT_INFO("%s: vfree(epatch_buf)", __func__);
                    epatch_buf = NULL;

                    if (buf && config_len)
                        memcpy(&buf[buf_len - config_len], config_file_buf, config_len);
                }
            }
        }
    }

    RTKBT_INFO("%s: fw%s exists, config file%s exists", __func__,
            (buf_len > 0) ? "" : " not", (config_len > 0) ? "":" not");

    if (buf && buf_len > 0 && need_download_fw)
        *buff = buf;

    RTKBT_DBG("%s: done", __func__);

    return buf_len;

fw_fail:
    return ret_val;
}

static void load_firmware_info(firmware_info *fw_info)
{
    const struct firmware *fw/*, *cfg*/;
    struct usb_device *udev;
    patch_info *patch_entry;
    char *fw_name;
    int ret_val;

    int buf_len = -1;
    uint8_t *epatch_buf = NULL;

    struct rtk_epatch *epatch_info = NULL;
    struct rtk_extension_entry patch_lmp = {0};
    uint16_t lmp_version;
    RTKBT_DBG("%s: start", __func__);

    udev = fw_info->udev;
    patch_entry = fw_info->patch_entry;
    lmp_version = patch_entry->lmp_sub_default;

    if(DRV_MP_MODE == mp_drv_mode){
        fw_name = patch_entry->mp_patch_name;
    } else {
        fw_name = patch_entry->patch_name;
    }

    RTKBT_INFO("%s: Default lmp version = 0x%04x, fw file name[%s]", __func__, lmp_version, fw_name);

    ret_val = request_firmware(&fw, fw_name, &udev->dev);
    if (ret_val < 0)
        goto fw_fail;
    else {
        epatch_buf = vmalloc(fw->size);
        RTKBT_INFO("%s: epatch_buf = vmalloc(fw->size, GFP_KERNEL)", __func__);
        if (!epatch_buf) {
            release_firmware(fw);
            goto fw_fail;
        }
        memcpy(epatch_buf, fw->data, fw->size);
        buf_len = fw->size;
        release_firmware(fw);
    }

    ret_val = reset_and_clean_hw_buffer(fw_info);

    if (lmp_version != ROM_LMP_8723a) {
        RTKBT_DBG("%s: Not 8723a -> use new style patch", __func__);
        ret_val = get_eversion(fw_info);
        if (ret_val < 0) {
            RTKBT_ERR("%s: Failed to get eversion, errno %d", __func__, ret_val);
            goto fw_fail;
        }
        RTKBT_DBG("%s: Get eversion =%d", __func__, patch_entry->eversion);
        if (memcmp(epatch_buf + buf_len - 4 , EXTENSION_SECTION_SIGNATURE, 4)) {
            RTKBT_ERR("%s: Failed to check extension section signature", __func__);
        } else {
            uint8_t *temp;
            temp = epatch_buf + buf_len - 5;
            do {
                if (*temp == 0x00) {
                    patch_lmp.opcode = *temp;
                    patch_lmp.length = *(temp-1);
                    if ((patch_lmp.data = vmalloc(patch_lmp.length))) {
                        int k;
                        for (k = 0; k < patch_lmp.length; k++) {
                            *(patch_lmp.data+k) = *(temp-2-k);
                            RTKBT_DBG("data = 0x%x", *(patch_lmp.data+k));
                        }
                    }
                    else
                      goto fw_fail;
                    RTKBT_DBG("%s: opcode = 0x%x, length = 0x%x, data = 0x%x", __func__,
                            patch_lmp.opcode, patch_lmp.length, *(patch_lmp.data));
                    break;
                }
                temp -= *(temp-1) + 2;
            } while (*temp != 0xFF);

            if (patch_lmp.data && lmp_version != project_id[*(patch_lmp.data)]) {
                RTKBT_ERR("%s: Default lmp_version 0x%04x, project_id[%d] 0x%04x "
                        "-> not match", __func__, lmp_version, *(patch_lmp.data),project_id[*(patch_lmp.data)]);
            } else {
                if (patch_lmp.data) {
                RTKBT_INFO("%s: Default lmp_version 0x%04x, project_id[%d] 0x%04x "
                        "-> match", __func__, lmp_version, *(patch_lmp.data), project_id[*(patch_lmp.data)]);
                }
                if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8)) {
                    RTKBT_ERR("%s: Check signature error", __func__);
                } else {
                    epatch_info = (struct rtk_epatch*)epatch_buf;
                    patch_entry->lmp_sub = (uint16_t)epatch_info->fw_version;

                    RTKBT_DBG("%s: lmp version 0x%04x, fw_version 0x%x, "
                            "number_of_total_patch %d", __func__,
                            patch_entry->lmp_sub, epatch_info->fw_version,
                            epatch_info->number_of_total_patch);
                }
            }
        }
    }

    RTKBT_DBG("%s: done", __func__);
fw_fail:
    if(epatch_buf)
        vfree(epatch_buf);
    if (patch_lmp.data)
        vfree(patch_lmp.data);
}

#if SUSPNED_DW_FW
static int load_suspend_firmware(firmware_info *fw_info, uint8_t **buff)
{
    const struct firmware *fw, *cfg;
    struct usb_device *udev;
    patch_info *patch_entry;
    char config_name[100] = {0};
    char fw_name[100] = {0};
    int fw_len = 0;
    int ret_val;

    int config_len = 0, buf_len = -1;
    uint8_t *buf = *buff, *config_file_buf = NULL;
    uint8_t *epatch_buf = NULL;

    struct rtk_epatch *epatch_info = NULL;
    uint8_t need_download_fw = 1;
    struct rtk_extension_entry patch_lmp = {0};
    struct rtk_epatch_entry *p_epatch_entry = NULL;
    uint16_t lmp_version;
    RTKBT_DBG("%s: start", __func__);

    udev = fw_info->udev;
    patch_entry = fw_info->patch_entry;
    lmp_version = patch_entry->lmp_sub_default;
    sprintf(config_name, "%s_suspend", patch_entry->config_name);
    sprintf(fw_name, "%s_suspend", patch_entry->patch_name);

    RTKBT_INFO("%s: Default lmp version = 0x%04x, config file name[%s], "
            "fw file name[%s]", __func__, lmp_version,config_name, fw_name);

    ret_val = request_firmware(&cfg, config_name, &udev->dev);
    if (ret_val < 0)
        config_len = 0;
    else {
        int i;
        rtk_update_altsettings(patch_entry, cfg->data, cfg->size, &config_file_buf, &config_len);

        RTKBT_INFO("Final Config len=%08x:\n", config_len);
        for(i=0;i<=config_len;i+=0x10)
        {
            RTKBT_INFO("%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, \
                config_file_buf[i], config_file_buf[i+1], config_file_buf[i+2], config_file_buf[i+3], config_file_buf[i+4], config_file_buf[i+5], config_file_buf[i+6], config_file_buf[i+7], \
                config_file_buf[i+8], config_file_buf[i+9], config_file_buf[i+10], config_file_buf[i+11], config_file_buf[i+12], config_file_buf[i+13], config_file_buf[i+14], config_file_buf[i+15]);
        }

        release_firmware(cfg);
    }

    ret_val = request_firmware(&fw, fw_name, &udev->dev);
    if (ret_val < 0)
        goto fw_fail;
    else {
        epatch_buf = vmalloc(fw->size);
        RTKBT_INFO("%s: epatch_buf = vmalloc(fw->size, GFP_KERNEL)", __func__);
        if (!epatch_buf) {
            release_firmware(fw);
            goto fw_fail;
        }
        memcpy(epatch_buf, fw->data, fw->size);
        fw_len = fw->size;
        buf_len = fw_len + config_len;
        release_firmware(fw);
    }

    RTKBT_DBG("%s: Not 8723a -> use new style patch", __func__);

    RTKBT_DBG("%s: get_eversion from bt controller", __func__);

    ret_val = get_eversion(fw_info);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to get eversion, errno %d", __func__, ret_val);
        goto fw_fail;
    }
    RTKBT_DBG("%s: Get eversion =%d", __func__, patch_entry->eversion);
    if (memcmp(epatch_buf + buf_len - config_len - 4 , EXTENSION_SECTION_SIGNATURE, 4)) {
        RTKBT_ERR("%s: Failed to check extension section signature", __func__);
        need_download_fw = 0;
    } else {
        uint8_t *temp;
        temp = epatch_buf+buf_len-config_len - 5;
        do {
            if (*temp == 0x00) {
                patch_lmp.opcode = *temp;
                patch_lmp.length = *(temp-1);
                if ((patch_lmp.data = kzalloc(patch_lmp.length, GFP_KERNEL))) {
                    int k;
                    for (k = 0; k < patch_lmp.length; k++) {
                        *(patch_lmp.data+k) = *(temp-2-k);
                        RTKBT_DBG("data = 0x%x", *(patch_lmp.data+k));
                    }
                }
                RTKBT_DBG("%s: opcode = 0x%x, length = 0x%x, data = 0x%x", __func__,
                    patch_lmp.opcode, patch_lmp.length, *(patch_lmp.data));
                break;
            }
            temp -= *(temp-1) + 2;
        } while (*temp != 0xFF);

        if (lmp_version != project_id[*(patch_lmp.data)]) {
            RTKBT_ERR("%s: Default lmp_version 0x%04x, project_id[%d] 0x%04x "
                "-> not match", __func__, lmp_version, *(patch_lmp.data),project_id[*(patch_lmp.data)]);
            if (patch_lmp.data)
                kfree(patch_lmp.data);
            need_download_fw = 0;
        } else {
            RTKBT_INFO("%s: Default lmp_version 0x%04x, project_id[%d] 0x%04x "
                "-> match", __func__, lmp_version, *(patch_lmp.data), project_id[*(patch_lmp.data)]);
            if (patch_lmp.data)
                kfree(patch_lmp.data);
            if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8)) {
                RTKBT_ERR("%s: Check signature error", __func__);
                need_download_fw = 0;
            } else {
                epatch_info = (struct rtk_epatch*)epatch_buf;
                patch_entry->lmp_sub = (uint16_t)epatch_info->fw_version;

                RTKBT_DBG("%s: lmp version 0x%04x, fw_version 0x%x, "
                    "number_of_total_patch %d", __func__,
                    patch_entry->lmp_sub, epatch_info->fw_version,
                    epatch_info->number_of_total_patch);

             /* Get right epatch entry */
                p_epatch_entry = get_fw_patch_entry(epatch_info, patch_entry->eversion);
                if (p_epatch_entry == NULL) {
                    RTKBT_WARN("%s: Failed to get fw patch entry", __func__);
                    ret_val = -1;
                    goto fw_fail ;
                }

                buf_len = p_epatch_entry->patch_length + config_len;
                RTKBT_DBG("buf_len = 0x%x", buf_len);

                if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
                    RTKBT_ERR("%s: Can't alloc memory for  fw&config", __func__);
                    buf_len = -1;
                    kfree(p_epatch_entry);
                } else {
                    memcpy(buf, &epatch_buf[p_epatch_entry->start_offset], p_epatch_entry->patch_length);
                    memcpy(&buf[p_epatch_entry->patch_length-4], &epatch_info->fw_version, 4);
                    kfree(p_epatch_entry);
                }
                vfree(epatch_buf);
                RTKBT_INFO("%s: vfree(epatch_buf)", __func__);
                epatch_buf = NULL;

                if (config_len)
                    memcpy(&buf[buf_len - config_len], config_file_buf, config_len);
            }
        }
    }

    RTKBT_INFO("%s: fw%s exists, config file%s exists", __func__,
            (buf_len > 0) ? "" : " not", (config_len > 0) ? "":" not");

    if (buf && buf_len > 0 && need_download_fw)
        *buff = buf;

    RTKBT_DBG("%s: done", __func__);

    return buf_len;

fw_fail:
    return ret_val;
}
#endif

static int get_firmware(firmware_info *fw_info, int cached)
{
    patch_info *patch_entry = fw_info->patch_entry;

    RTKBT_INFO("%s: start, cached %d,patch_entry->fw_len= %d", __func__, cached,patch_entry->fw_len);

    if (cached > 0) {
        if (patch_entry->fw_len > 0) {
            fw_info->fw_data = kzalloc(patch_entry->fw_len, GFP_KERNEL);
            if (!fw_info->fw_data)
                return -ENOMEM;
            memcpy(fw_info->fw_data, patch_entry->fw_cache, patch_entry->fw_len);
            fw_info->fw_len = patch_entry->fw_len;
        } else {
            fw_info->fw_len = load_firmware(fw_info, &fw_info->fw_data);
            if (fw_info->fw_len <= 0)
                return -1;
        }
    } else {
        fw_info->fw_len = load_firmware(fw_info, &fw_info->fw_data);
        if (fw_info->fw_len <= 0)
            return -1;
    }

    return 0;
}

#if SUSPNED_DW_FW
static int get_suspend_firmware(firmware_info *fw_info, int cached)
{
    patch_info *patch_entry = fw_info->patch_entry;

    RTKBT_INFO("%s: start, cached %d,patch_entry->fw_len= %d", __func__, cached,patch_entry->fw_len);

    if (cached > 0) {
        if (patch_entry->fw_len > 0) {
            fw_info->fw_data = kzalloc(patch_entry->fw_len, GFP_KERNEL);
            if (!fw_info->fw_data)
                return -ENOMEM;
            memcpy(fw_info->fw_data, patch_entry->fw_cache, patch_entry->fw_len);
            fw_info->fw_len = patch_entry->fw_len;
        } else {
            fw_info->fw_len = load_suspend_firmware(fw_info, &fw_info->fw_data);
            if (fw_info->fw_len <= 0)
                return -1;
        }
    } else {
        fw_info->fw_len = load_suspend_firmware(fw_info, &fw_info->fw_data);
        if (fw_info->fw_len <= 0)
            return -1;
    }

    return 0;
}
#endif

/*
 * Open the log message only if in debugging,
 * or it will decelerate download procedure.
 */
static int download_data(firmware_info *fw_info)
{
    download_cp *cmd_para;
    download_rp *evt_para;
    uint8_t *pcur;
    int pkt_len, frag_num, frag_len;
    int i, ret_val;
    int ncmd = 1, step = 1;

    RTKBT_DBG("%s: start", __func__);

    cmd_para = (download_cp *)fw_info->req_para;
    evt_para = (download_rp *)fw_info->rsp_para;
    pcur = fw_info->fw_data;
    pkt_len = CMD_HDR_LEN + sizeof(download_cp);
    frag_num = fw_info->fw_len / PATCH_SEG_MAX + 1;
    frag_len = PATCH_SEG_MAX;

    for (i = 0; i < frag_num; i++) {
        cmd_para->index = i?((i-1)%0x7f+1):0;
        if (i == (frag_num - 1)) {
            cmd_para->index |= DATA_END;
            frag_len = fw_info->fw_len % PATCH_SEG_MAX;
            pkt_len -= (PATCH_SEG_MAX - frag_len);
        }
        fw_info->cmd_hdr->opcode = cpu_to_le16(DOWNLOAD_OPCODE);
        fw_info->cmd_hdr->plen = sizeof(uint8_t) + frag_len;
        fw_info->pkt_len = pkt_len;
        memcpy(cmd_para->data, pcur, frag_len);

        if (step > 0) {
            ret_val = send_hci_cmd(fw_info);
            if (ret_val < 0) {
                RTKBT_DBG("%s: Failed to send frag num %d", __func__, cmd_para->index);
                return ret_val;
            } else
                RTKBT_DBG("%s: Send frag num %d", __func__, cmd_para->index);

            if (--step > 0 && i < frag_num - 1) {
                RTKBT_DBG("%s: Continue to send frag num %d", __func__, cmd_para->index + 1);
                pcur += PATCH_SEG_MAX;
                continue;
            }
        }

        while (ncmd > 0) {
            ret_val = rcv_hci_evt(fw_info);
            if (ret_val < 0) {
                RTKBT_ERR("%s: rcv_hci_evt err %d", __func__, ret_val);
                return ret_val;
            } else {
                RTKBT_DBG("%s: Receive acked frag num %d", __func__, evt_para->index);
                ncmd--;
            }

            if (0 != evt_para->status) {
                RTKBT_ERR("%s: Receive acked frag num %d, err status %d",
                        __func__, ret_val, evt_para->status);
                return -1;
            }

            if ((evt_para->index & DATA_END) || (evt_para->index == frag_num - 1)) {
                RTKBT_DBG("%s: Receive last acked index %d", __func__, evt_para->index);
                goto end;
            }
        }

        ncmd = step = fw_info->cmd_cmp->ncmd;
        pcur += PATCH_SEG_MAX;
        RTKBT_DBG("%s: HCI command packet num %d", __func__, ncmd);
    }

    /*
     * It is tricky that Host cannot receive DATA_END index from BT
     * controller, at least for 8723au. We are doomed if failed.
     */
#if 0
    /* Continue to receive the responsed events until last index occurs */
    if (i == frag_num) {
        RTKBT_DBG("%s: total frag count %d", __func__, frag_num);
        while (!(evt_para->index & DATA_END)) {
            ret_val = rcv_hci_evt(fw_info);
            if (ret_val < 0) {
                RTKBT_ERR("%s: rcv_hci_evt err %d", __func__, ret_val);
                return ret_val;
            }
            if (0 != evt_para->status)
                return -1;
            RTKBT_DBG("%s: continue to receive acked frag num %d", __func__, evt_para->index);
        }
    }
#endif
end:
    RTKBT_INFO("%s: done, sent %d frag pkts, received %d frag events",
            __func__, cmd_para->index, evt_para->index);
    return fw_info->fw_len;
}

int download_patch(firmware_info *fw_info, int cached)
{
    int ret_val = 0;

    RTKBT_DBG("%s: Download fw patch start, cached %d", __func__, cached);

    if (!fw_info || !fw_info->patch_entry) {
        RTKBT_ERR("%s: No patch entry exists(fw_info %p)", __func__, fw_info);
        ret_val = -1;
        goto end;
    }

    /*
     * step1: get local firmware if existed
     * step2: check firmware version
     * step3: download firmware if updated
     */
    ret_val = get_firmware(fw_info, cached);
    if (ret_val < 0) {
        RTKBT_ERR("%s: Failed to get firmware", __func__);
        goto end;
    }

#if SUSPNED_DW_FW
    if(fw_info_4_suspend) {
        RTKBT_DBG("%s: get suspend fw first cached %d", __func__, cached);
        ret_val = get_suspend_firmware(fw_info_4_suspend, cached);
        if (ret_val < 0) {
            RTKBT_ERR("%s: Failed to get suspend firmware", __func__);
            goto end;
        }
    }
#endif

    /*check the length of fw to be download*/
    RTKBT_DBG("%s: Check fw_info->fw_len:%d max_patch_size %d", __func__, fw_info->fw_len, fw_info->patch_entry->max_patch_size);
    if (fw_info->fw_len > fw_info->patch_entry->max_patch_size) {
        RTKBT_ERR("%s: Total length of fw&config(%08x) larger than max_patch_size 0x%08x", __func__, fw_info->fw_len, fw_info->patch_entry->max_patch_size);
        ret_val = -1;
        goto free;
    }

    ret_val = check_fw_version(fw_info, false);

    if (2 == ret_val) {
        RTKBT_ERR("%s: Cold reset bt chip only download", __func__);
        ret_val = download_data(fw_info);
        if (ret_val > 0)
            RTKBT_ERR("%s: Download fw patch done, fw len %d", __func__, ret_val);
    } else if(1 == ret_val){
        //   reset bt chip to update Fw patch
        ret_val = reset_controller(fw_info);
        RTKBT_ERR("%s: reset bt chip to update Fw patch, fw len %d", __func__, ret_val);
        ret_val = download_data(fw_info);
        if (ret_val > 0)
                RTKBT_ERR("%s: Download fw patch done, fw len %d", __func__, ret_val);
    }


free:
    /* Free fw data after download finished */
    kfree(fw_info->fw_data);
    fw_info->fw_data = NULL;

end:
    return ret_val;
}

#if SUSPNED_DW_FW
static int download_suspend_patch(firmware_info *fw_info, int cached)
{
    int ret_val = 0;

    RTKBT_DBG("%s: Download fw patch start, cached %d", __func__, cached);

    if (!fw_info || !fw_info->patch_entry) {
        RTKBT_ERR("%s: No patch entry exists(fw_info %p)", __func__, fw_info);
        ret_val = -1;
        goto end;
    }

    /*check the length of fw to be download*/
    RTKBT_DBG("%s:Check RTK_PATCH_LENGTH fw_info->fw_len:%d", __func__,fw_info->fw_len);
    if (fw_info->fw_len > fw_info->patch_entry->max_patch_size || fw_info->fw_len == 0) {
        RTKBT_ERR("%s: Total length of fw&config(%08x) larger than max_patch_size 0x%08x", __func__, fw_info->fw_len, fw_info->patch_entry->max_patch_size);
        ret_val = -1;
        goto free;
    }

    ret_val = check_fw_version(fw_info, false);

    if (2 == ret_val) {
        RTKBT_ERR("%s: Cold reset bt chip only download", __func__);
        ret_val = download_data(fw_info);
        if (ret_val > 0)
            RTKBT_ERR("%s: Download fw patch done, fw len %d", __func__, ret_val);
    } else if(1 == ret_val){
        //   reset bt chip to update Fw patch
        ret_val = reset_controller(fw_info);
        RTKBT_ERR("%s: reset bt chip to update Fw patch, fw len %d", __func__, ret_val);
        ret_val = download_data(fw_info);
        if (ret_val > 0)
                RTKBT_ERR("%s: Download fw patch done, fw len %d", __func__, ret_val);
    }


free:
    /* Free fw data after download finished */
    kfree(fw_info->fw_data);
    fw_info->fw_data = NULL;

end:
    return ret_val;
}

static void suspend_firmware_info_init(firmware_info *fw_info)
{
    RTKBT_DBG("%s: start", __func__);
    if(!fw_info)
        return;

    fw_info_4_suspend= kzalloc(sizeof(*fw_info), GFP_KERNEL);
    if (!fw_info_4_suspend)
        goto error;

    fw_info_4_suspend->send_pkt = kzalloc(PKT_LEN, GFP_KERNEL);
    if (!fw_info_4_suspend->send_pkt) {
        kfree(fw_info_4_suspend);
        goto error;
    }

    fw_info_4_suspend->rcv_pkt = kzalloc(PKT_LEN, GFP_KERNEL);
    if (!fw_info_4_suspend->rcv_pkt) {
        kfree(fw_info_4_suspend->send_pkt);
        kfree(fw_info_4_suspend);
        goto error;
    }

    fw_info_4_suspend->patch_entry = get_suspend_fw_table_entry(fw_info->udev);
    if (!fw_info_4_suspend->patch_entry) {
        kfree(fw_info_4_suspend->rcv_pkt);
        kfree(fw_info_4_suspend->send_pkt);
        kfree(fw_info_4_suspend);
        goto error;
    }

    fw_info_4_suspend->intf = fw_info->intf;
    fw_info_4_suspend->udev = fw_info->udev;
    fw_info_4_suspend->cmd_hdr = (struct hci_command_hdr *)(fw_info_4_suspend->send_pkt);
    fw_info_4_suspend->evt_hdr = (struct hci_event_hdr *)(fw_info_4_suspend->rcv_pkt);
    fw_info_4_suspend->cmd_cmp = (struct hci_ev_cmd_complete *)(fw_info_4_suspend->rcv_pkt + EVT_HDR_LEN);
    fw_info_4_suspend->req_para = fw_info_4_suspend->send_pkt + CMD_HDR_LEN;
    fw_info_4_suspend->rsp_para = fw_info_4_suspend->rcv_pkt + EVT_HDR_LEN + CMD_CMP_LEN;
    fw_info_4_suspend->pipe_in = fw_info->pipe_in;
    fw_info_4_suspend->pipe_out = fw_info->pipe_out;

    return;
error:
    RTKBT_DBG("%s: fail !", __func__);
    fw_info_4_suspend = NULL;
    return;
}
#endif

#if SET_WAKEUP_DEVICE
static void set_wakeup_device_from_conf(firmware_info *fw_info)
{
    uint8_t paired_wakeup_bdaddr[7];
    uint8_t num = 0;
    int i;
    struct file *fp;
    mm_segment_t fs;
    loff_t pos;

    memset(paired_wakeup_bdaddr, 0, 7);
    fp = filp_open(SET_WAKEUP_DEVICE_CONF, O_RDWR, 0);
    if (!IS_ERR(fp)) {
        fs = get_fs();
        set_fs(KERNEL_DS);
        pos = 0;
        //read number
        vfs_read(fp, &num, 1, &pos);
        RTKBT_DBG("read number = %d", num);
        if(num) {
            for(i = 0; i < num; i++) {
            vfs_read(fp, paired_wakeup_bdaddr, 7, &pos);
            RTKBT_DBG("paired_wakeup_bdaddr: 0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
                paired_wakeup_bdaddr[1],paired_wakeup_bdaddr[2],paired_wakeup_bdaddr[3],
                paired_wakeup_bdaddr[4],paired_wakeup_bdaddr[5],paired_wakeup_bdaddr[6]);
            set_wakeup_device(fw_info, paired_wakeup_bdaddr);
            }
        }
        filp_close(fp, NULL);
        set_fs(fs);
    }
    else {
        RTKBT_ERR("open wakeup config file fail! errno = %ld", PTR_ERR(fp));
    }
}
#endif

static firmware_info *firmware_info_init(struct usb_interface *intf)
{
    struct usb_device *udev = interface_to_usbdev(intf);
    firmware_info *fw_info;

    RTKBT_DBG("%s: start", __func__);

    fw_info = kzalloc(sizeof(*fw_info), GFP_KERNEL);
    if (!fw_info)
        return NULL;

    fw_info->send_pkt = kzalloc(PKT_LEN, GFP_KERNEL);
    if (!fw_info->send_pkt) {
        kfree(fw_info);
        return NULL;
    }

    fw_info->rcv_pkt = kzalloc(PKT_LEN, GFP_KERNEL);
    if (!fw_info->rcv_pkt) {
        kfree(fw_info->send_pkt);
        kfree(fw_info);
        return NULL;
    }

    fw_info->patch_entry = get_fw_table_entry(udev);
    if (!fw_info->patch_entry) {
        kfree(fw_info->rcv_pkt);
        kfree(fw_info->send_pkt);
        kfree(fw_info);
        return NULL;
    }

    fw_info->intf = intf;
    fw_info->udev = udev;
    fw_info->pipe_in = usb_rcvintpipe(fw_info->udev, INTR_EP);
    fw_info->pipe_out = usb_sndctrlpipe(fw_info->udev, CTRL_EP);
    fw_info->cmd_hdr = (struct hci_command_hdr *)(fw_info->send_pkt);
    fw_info->evt_hdr = (struct hci_event_hdr *)(fw_info->rcv_pkt);
    fw_info->cmd_cmp = (struct hci_ev_cmd_complete *)(fw_info->rcv_pkt + EVT_HDR_LEN);
    fw_info->req_para = fw_info->send_pkt + CMD_HDR_LEN;
    fw_info->rsp_para = fw_info->rcv_pkt + EVT_HDR_LEN + CMD_CMP_LEN;

#if SUSPNED_DW_FW
    suspend_firmware_info_init(fw_info);
#endif

#if BTUSB_RPM
    RTKBT_INFO("%s: Auto suspend is enabled", __func__);
    usb_enable_autosuspend(udev);
    pm_runtime_set_autosuspend_delay(&(udev->dev), 2000);
#else
    RTKBT_INFO("%s: Auto suspend is disabled", __func__);
    usb_disable_autosuspend(udev);
#endif

#if BTUSB_WAKEUP_HOST
    device_wakeup_enable(&udev->dev);
#endif

    return fw_info;
}

static void firmware_info_destroy(struct usb_interface *intf)
{
    firmware_info *fw_info;
    struct usb_device *udev;
    struct btusb_data *data;

    udev = interface_to_usbdev(intf);
    data = usb_get_intfdata(intf);

    fw_info = data->fw_info;
    if (!fw_info)
        return;

#if BTUSB_RPM
    usb_disable_autosuspend(udev);
#endif

    /*
     * In order to reclaim fw data mem, we free fw_data immediately
     * after download patch finished instead of here.
     */
    kfree(fw_info->rcv_pkt);
    kfree(fw_info->send_pkt);
    kfree(fw_info);

#if SUSPNED_DW_FW
    if (!fw_info_4_suspend)
        return;

    kfree(fw_info_4_suspend->rcv_pkt);
    kfree(fw_info_4_suspend->send_pkt);
    kfree(fw_info_4_suspend->patch_entry);
    kfree(fw_info_4_suspend);
    fw_info_4_suspend = NULL;
#endif
}

static struct usb_driver btusb_driver;

static struct usb_device_id btusb_table[] = {
    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
                     USB_DEVICE_ID_MATCH_INT_INFO,
      .idVendor = 0x0bda,
      .bInterfaceClass = 0xe0,
      .bInterfaceSubClass = 0x01,
      .bInterfaceProtocol = 0x01 },

    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
                     USB_DEVICE_ID_MATCH_INT_INFO,
      .idVendor = 0x13d3,
      .bInterfaceClass = 0xe0,
      .bInterfaceSubClass = 0x01,
      .bInterfaceProtocol = 0x01 },

    { }
};

MODULE_DEVICE_TABLE(usb, btusb_table);

static int inc_tx(struct btusb_data *data)
{
    unsigned long flags;
    int rv;

    spin_lock_irqsave(&data->txlock, flags);
    rv = test_bit(BTUSB_SUSPENDING, &data->flags);
    if (!rv)
        data->tx_in_flight++;
    spin_unlock_irqrestore(&data->txlock, flags);

    return rv;
}

#ifdef CONFIG_SCO_OVER_HCI
static void check_sco_event(struct urb *urb)
{
    u8* opcode = (u8*)(urb->transfer_buffer);
    u8 status;
    uint16_t handle;
    struct hci_dev *hdev = urb->context;
    struct btusb_data *data = GET_DRV_DATA(hdev);

    switch (*opcode) {
    case HCI_EV_SYNC_CONN_COMPLETE:
        RTKBT_INFO("%s: HCI_EV_SYNC_CONN_COMPLETE(0x%02x)", __func__, *opcode);
        status = *(opcode + 2);
        data->sco_handle = *(opcode + 3) | *(opcode + 4) << 8;
        //hdev->voice_setting = *(uint16_t*)&opcode[15];
        if (status == 0) {
            hdev->conn_hash.sco_num++;
            hdev->notify(hdev, 0);
        }
        break;
    case HCI_EV_DISCONN_COMPLETE:
        status = *(opcode + 2);
        handle = *(opcode + 3) | *(opcode + 4) << 8;
        if (status == 0 && data->sco_handle == handle) {
            RTKBT_INFO("%s: SCO HCI_EV_DISCONN_COMPLETE(0x%02x)", __func__, *opcode);
            hdev->conn_hash.sco_num--;
            hdev->notify(hdev, 0);
            data->sco_handle = 0;
        }
        break;
    default:
        RTKBT_DBG("%s: event 0x%02x", __func__, *opcode);
        break;
    }
}
#endif
static void btusb_intr_complete(struct urb *urb)
{
    struct hci_dev *hdev = urb->context;
    struct btusb_data *data = GET_DRV_DATA(hdev);
    int err;

    RTKBT_DBG("%s: urb %p status %d count %d ", __func__,
            urb, urb->status, urb->actual_length);

#ifdef CONFIG_SCO_OVER_HCI
    check_sco_event(urb);
#endif

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


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

        if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
                        urb->transfer_buffer,
                        urb->actual_length) < 0) {
            RTKBT_ERR("%s: Corrupted event packet", __func__);
            hdev->stat.err_rx++;
        }
    }
    /* Avoid suspend failed when usb_kill_urb */
    else if(urb->status == -ENOENT)    {
        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)
            RTKBT_ERR("%s: Failed to re-submit urb %p, err %d",
                    __func__, urb, err);
        usb_unanchor_urb(urb);
    }
}

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

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

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

    size = le16_to_cpu(data->intr_ep->wMaxPacketSize);

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

    RTKBT_DBG("%s: mMaxPacketSize %d, bEndpointAddress 0x%02x",
            __func__, size, data->intr_ep->bEndpointAddress);

    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) {
        RTKBT_ERR("%s: Failed to submit urb %p, err %d",
                __func__, urb, err);
        usb_unanchor_urb(urb);
    }

    usb_free_urb(urb);

    return err;
}

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

    RTKBT_DBG("%s: urb %p status %d count %d",
            __func__, 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 (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
                        urb->transfer_buffer,
                        urb->actual_length) < 0) {
            RTKBT_ERR("%s: Corrupted ACL packet", __func__);
            hdev->stat.err_rx++;
        }
    }
    /* Avoid suspend failed when usb_kill_urb */
    else if(urb->status == -ENOENT)    {
        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)
            RTKBT_ERR("btusb_bulk_complete %s urb %p failed to resubmit (%d)",
                        hdev->name, urb, -err);
        usb_unanchor_urb(urb);
    }
}

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

    RTKBT_DBG("%s: hdev name %s", __func__, 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) {
        RTKBT_ERR("%s: Failed to submit urb %p, err %d", __func__, 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 = GET_DRV_DATA(hdev);
    int i, err;


    RTKBT_DBG("%s: urb %p status %d count %d",
            __func__, urb, urb->status, urb->actual_length);

    if (!test_bit(HCI_RUNNING, &hdev->flags) || !test_bit(BTUSB_ISOC_RUNNING, &data->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 (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
                        urb->transfer_buffer + offset,
                                length) < 0) {
                RTKBT_ERR("%s: Corrupted SCO packet", __func__);
                hdev->stat.err_rx++;
            }
        }
    }
    /* Avoid suspend failed when usb_kill_urb */
    else if(urb->status == -ENOENT)    {
        return;
    }

    usb_anchor_urb(urb, &data->isoc_anchor);
    i = 0;
retry:
    err = usb_submit_urb(urb, GFP_ATOMIC);
    if (err < 0) {
        /* -EPERM: urb is being killed;
         * -ENODEV: device got disconnected */
        if (err != -EPERM && err != -ENODEV)
            RTKBT_ERR("%s: Failed to re-sumbit urb %p, retry %d, err %d",
                    __func__, urb, i, err);
        if (i < 10) {
            i++;
            mdelay(1);
            goto retry;
        }

        usb_unanchor_urb(urb);
    }
}

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

    RTKBT_DBG("%s: len %d mtu %d", __func__, 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 = GET_DRV_DATA(hdev);
    struct urb *urb;
    unsigned char *buf;
    unsigned int pipe;
    int err, size;

    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);

    urb->dev      = data->udev;
    urb->pipe     = pipe;
    urb->context  = hdev;
    urb->complete = btusb_isoc_complete;
    urb->interval = data->isoc_rx_ep->bInterval;

    urb->transfer_flags  = URB_FREE_BUFFER | URB_ISO_ASAP;
    urb->transfer_buffer = buf;
    urb->transfer_buffer_length = size;

    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) {
        RTKBT_ERR("%s: Failed to submit urb %p, err %d", __func__, 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 = GET_DRV_DATA(hdev);

    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:
    spin_lock(&data->txlock);
    data->tx_in_flight--;
    spin_unlock(&data->txlock);

    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;

    RTKBT_DBG("%s: urb %p status %d count %d",
            __func__, urb, urb->status, urb->actual_length);

    if (skb && hdev) {
        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++;
    } else
        RTKBT_ERR("%s: skb 0x%p hdev 0x%p", __func__, skb, hdev);

done:
    kfree(urb->setup_packet);

    kfree_skb(skb);
}

static int btusb_open(struct hci_dev *hdev)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    int i, err = 0;

    RTKBT_INFO("%s: Start, PM usage count %d", __func__,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
          atomic_read(&data->intf->dev.power.usage_count)
#else
          0
#endif
    );

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

    data->intf->needs_remote_wakeup = 1;
    for (i = 0; i < NUM_REASSEMBLY; i++) {
        if (hdev->reassembly[i]) {
            RTKBT_DBG("%s: free ressembly[%d]", __func__, i);
            kfree_skb(hdev->reassembly[i]);
            hdev->reassembly[i] = NULL;
        }
    }

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

    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) {
        mdelay(URB_CANCELING_DELAY_MS);
        usb_kill_anchored_urbs(&data->intr_anchor);
        goto failed;
    }

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

done:
    usb_autopm_put_interface(data->intf);

    RTKBT_INFO("%s: End, PM usage count %d", __func__,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
          atomic_read(&data->intf->dev.power.usage_count)
#else
          0
#endif
     );
    return 0;

failed:
    clear_bit(BTUSB_INTR_RUNNING, &data->flags);
    clear_bit(HCI_RUNNING, &hdev->flags);
    usb_autopm_put_interface(data->intf);

    RTKBT_ERR("%s: Failed, PM usage count %d", __func__,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
          atomic_read(&data->intf->dev.power.usage_count)
#else
          0
#endif
        );
    return err;
}

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

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

    RTKBT_INFO("%s: hci running %lu", __func__, hdev->flags & HCI_RUNNING);

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

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

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

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

    data->intf->needs_remote_wakeup = 0;
    usb_autopm_put_interface(data->intf);

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

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

    RTKBT_DBG("%s", __func__);

    mdelay(URB_CANCELING_DELAY_MS);
    usb_kill_anchored_urbs(&data->tx_anchor);

    return 0;
}

#ifdef CONFIG_SCO_OVER_HCI
static void btusb_isoc_snd_tx_complete(struct urb *urb);

static int snd_send_sco_frame(struct sk_buff *skb)
{
    struct hci_dev *hdev = (struct hci_dev *) skb->dev;

    struct btusb_data *data = GET_DRV_DATA(hdev);
    //struct usb_ctrlrequest *dr;
    struct urb *urb;
    unsigned int pipe;
    int err;

    RTKBT_DBG("%s:pkt type %d, packet_len : %d",
            __func__,bt_cb(skb)->pkt_type, skb->len);

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

    if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1) {
        kfree(skb);
        return -ENODEV;
    }

    urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC);
    if (!urb) {
        RTKBT_ERR("%s: Failed to allocate mem for sco pkts", __func__);
        kfree(skb);
        return -ENOMEM;
    }

    pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);

    usb_fill_int_urb(urb, data->udev, pipe,
            skb->data, skb->len, btusb_isoc_snd_tx_complete,
            skb, data->isoc_tx_ep->bInterval);

    urb->transfer_flags  = URB_ISO_ASAP;

    fill_isoc_descriptor(urb, skb->len,
            le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));

    hdev->stat.sco_tx++;

    usb_anchor_urb(urb, &data->tx_anchor);

    err = usb_submit_urb(urb, GFP_ATOMIC);
    if (err < 0) {
        RTKBT_ERR("%s: Failed to submit urb %p, pkt type %d, err %d",
                __func__, urb, bt_cb(skb)->pkt_type, err);
        kfree(urb->setup_packet);
        usb_unanchor_urb(urb);
    } else
        usb_mark_last_busy(data->udev);
    usb_free_urb(urb);

    return err;

}

static bool snd_copy_send_sco_data( RTK_sco_card_t *pSCOSnd)
{
    struct snd_pcm_runtime *runtime = pSCOSnd->playback.substream->runtime;
  	unsigned int frame_bytes = 2, frames1;
    const u8 *source;

    snd_pcm_uframes_t period_size = runtime->period_size;
    int i, count;
    u8 buffer[period_size * 3];
    int sco_packet_bytes = pSCOSnd->playback.sco_packet_bytes;
    struct sk_buff *skb;

    count = frames_to_bytes(runtime, period_size)/sco_packet_bytes;
    skb = bt_skb_alloc(((sco_packet_bytes + HCI_SCO_HDR_SIZE) * count), GFP_ATOMIC);
    skb->dev = (void *)hci_dev_get(0);
    bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
    skb_put(skb, ((sco_packet_bytes + HCI_SCO_HDR_SIZE) * count));
    if(!skb)
        return false;

    RTKBT_DBG("%s, buffer_pos: %d", __FUNCTION__, pSCOSnd->playback.buffer_pos);

    source = runtime->dma_area + pSCOSnd->playback.buffer_pos * frame_bytes;

    if (pSCOSnd->playback.buffer_pos + period_size <= runtime->buffer_size) {
      memcpy(buffer, source, period_size * frame_bytes);
    } else {
      /* wrap around at end of ring buffer */
      frames1 = runtime->buffer_size - pSCOSnd->playback.buffer_pos;
      memcpy(buffer, source, frames1 * frame_bytes);
      memcpy(&buffer[frames1 * frame_bytes],
             runtime->dma_area, (period_size - frames1) * frame_bytes);
    }

    pSCOSnd->playback.buffer_pos += period_size;
    if ( pSCOSnd->playback.buffer_pos >= runtime->buffer_size)
       pSCOSnd->playback.buffer_pos -= runtime->buffer_size;

    for(i = 0; i < count; i++) {
        *((__u16 *)(skb->data + i * (sco_packet_bytes + HCI_SCO_HDR_SIZE))) = pSCOSnd->usb_data->sco_handle;
        *((__u8 *)(skb->data + i*(sco_packet_bytes + HCI_SCO_HDR_SIZE) + 2)) = sco_packet_bytes;
        memcpy((skb->data + i * (sco_packet_bytes + HCI_SCO_HDR_SIZE) + HCI_SCO_HDR_SIZE),
          &buffer[sco_packet_bytes * i], sco_packet_bytes);
    }

    if(test_bit(ALSA_PLAYBACK_RUNNING, &pSCOSnd->states)) {
        snd_pcm_period_elapsed(pSCOSnd->playback.substream);
    }
    snd_send_sco_frame(skb);
    return true;
}

static void btusb_isoc_snd_tx_complete(struct urb *urb)
{
    struct sk_buff *skb = urb->context;
    struct hci_dev *hdev = (struct hci_dev *) skb->dev;
    struct btusb_data *data = GET_DRV_DATA(hdev);
    RTK_sco_card_t  *pSCOSnd = data->pSCOSnd;

    RTKBT_DBG("%s: status %d count %d",
            __func__,urb->status, urb->actual_length);

    if (skb && hdev) {
        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++;
    } else
        RTKBT_ERR("%s: skb 0x%p hdev 0x%p", __func__, skb, hdev);

done:
    kfree(urb->setup_packet);
    kfree_skb(skb);
    if(test_bit(ALSA_PLAYBACK_RUNNING, &pSCOSnd->states)){
        snd_copy_send_sco_data(pSCOSnd);
        //schedule_work(&pSCOSnd->send_sco_work);
    }
}

static void playback_work(struct work_struct *work)
{
    RTK_sco_card_t *pSCOSnd = container_of(work, RTK_sco_card_t, send_sco_work);

    snd_copy_send_sco_data(pSCOSnd);
}

#endif

static int btusb_send_frame(struct sk_buff *skb)
{
    struct hci_dev *hdev = (struct hci_dev *) skb->dev;

    struct btusb_data *data = GET_DRV_DATA(hdev);
    struct usb_ctrlrequest *dr;
    struct urb *urb;
    unsigned int pipe;
    int err;
    int retries = 0;

    RTKBT_DBG("%s: hdev %p, btusb data %p, pkt type %d",
            __func__, hdev, data, bt_cb(skb)->pkt_type);

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

    switch (bt_cb(skb)->pkt_type) {
    case HCI_COMMAND_PKT:
        print_command(skb);
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb)
            return -ENOMEM;

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

        dr->bRequestType = data->cmdreq_type;
        dr->bRequest     = 0;
        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);

        hdev->stat.cmd_tx++;
        break;

    case HCI_ACLDATA_PKT:
        print_acl(skb, 1);
        if (!data->bulk_tx_ep)
            return -ENODEV;

        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb)
            return -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);

        hdev->stat.acl_tx++;
        break;

    case HCI_SCODATA_PKT:
        print_sco(skb, 1);
        if (!data->isoc_tx_ep || hdev->conn_hash.sco_num < 1) {
            kfree(skb);
            return -ENODEV;
        }

        urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC);
        if (!urb) {
            RTKBT_ERR("%s: Failed to allocate mem for sco pkts", __func__);
            kfree(skb);
            return -ENOMEM;
        }

        pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);

        usb_fill_int_urb(urb, data->udev, pipe,
                skb->data, skb->len, btusb_isoc_tx_complete,
                skb, data->isoc_tx_ep->bInterval);

        urb->transfer_flags  = URB_ISO_ASAP;

        fill_isoc_descriptor(urb, skb->len,
                le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));

        hdev->stat.sco_tx++;
        goto skip_waking;

    default:
        return -EILSEQ;
    }

    err = inc_tx(data);
    if (err) {
        usb_anchor_urb(urb, &data->deferred);
        schedule_work(&data->waker);
        err = 0;
        goto done;
    }

skip_waking:
    usb_anchor_urb(urb, &data->tx_anchor);
retry:
    err = usb_submit_urb(urb, GFP_ATOMIC);
    if (err < 0) {
        RTKBT_ERR("%s: Failed to submit urb %p, pkt type %d, err %d, retries %d",
                __func__, urb, bt_cb(skb)->pkt_type, err, retries);
        if ((bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) && (retries < 10)) {
            mdelay(1);

            if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT)
                print_error_command(skb);
            retries++;
            goto retry;
        }
        kfree(urb->setup_packet);
        usb_unanchor_urb(urb);
    } else
        usb_mark_last_busy(data->udev);
    usb_free_urb(urb);

done:
    return err;
}

#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0)
static void btusb_destruct(struct hci_dev *hdev)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);

    RTKBT_DBG("%s: name %s", __func__, hdev->name);

    kfree(data);
}
#endif

static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);

    RTKBT_DBG("%s: name %s, evt %d", __func__, hdev->name, evt);

    RTKBT_INFO("%s: hdev->conn_hash.sco_num= %d, data->sco_num = %d", __func__, hdev->conn_hash.sco_num,
      data->sco_num);
    if (hdev->conn_hash.sco_num != data->sco_num) {
        data->sco_num = hdev->conn_hash.sco_num;
        schedule_work(&data->work);
    }
}

static inline int set_isoc_interface(struct hci_dev *hdev, int altsetting)
{
    struct btusb_data *data = GET_DRV_DATA(hdev);
    struct usb_interface *intf = data->isoc;
    struct usb_endpoint_descriptor *ep_desc;
    int i, err;

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

    err = usb_set_interface(data->udev, 1, altsetting);
    if (err < 0) {
        RTKBT_ERR("%s: Failed to set interface, altsetting %d, err %d",
                __func__, altsetting, err);
        return err;
    }

    data->isoc_altsetting = altsetting;

    data->isoc_tx_ep = NULL;
    data->isoc_rx_ep = NULL;

    for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
        ep_desc = &intf->cur_altsetting->endpoint[i].desc;

        if (!data->isoc_tx_ep && usb_endpoint_is_isoc_out(ep_desc)) {
            data->isoc_tx_ep = ep_desc;
            continue;
        }

        if (!data->isoc_rx_ep && usb_endpoint_is_isoc_in(ep_desc)) {
            data->isoc_rx_ep = ep_desc;
            continue;
        }
    }

    if (!data->isoc_tx_ep || !data->isoc_rx_ep) {
        RTKBT_ERR("%s: Invalid SCO descriptors", __func__);
        return -ENODEV;
    }

    return 0;
}

static int check_controller_support_msbc( struct usb_device *udev)
{
    //fix this in the future,when new card support msbc decode and encode
    RTKBT_INFO("%s:pid = 0x%02x, vid = 0x%02x",__func__,udev->descriptor.idProduct, udev->descriptor.idVendor);
    switch (udev->descriptor.idProduct) {

        default:
          return 0;
    }
    return 0;
}

static void btusb_work(struct work_struct *work)
{
    struct btusb_data *data = container_of(work, struct btusb_data, work);
    struct hci_dev *hdev = data->hdev;
    struct sk_buff *skb;

    int err;
    int new_alts;
    if (data->sco_num > 0) {
        if (!test_bit(BTUSB_DID_ISO_RESUME, &data->flags)) {
            err = usb_autopm_get_interface(data->isoc ? data->isoc : data->intf);
            if (err < 0) {
                clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
                mdelay(URB_CANCELING_DELAY_MS);
                usb_kill_anchored_urbs(&data->isoc_anchor);
                return;
            }

            set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
        }

        RTKBT_INFO("%s voice settings = 0x%04x", __func__, hdev->voice_setting);
        if (!(hdev->voice_setting & 0x0003)) {
            if(data->sco_num == 1)
                new_alts = 2;
            else {
              RTKBT_ERR("%s: we don't support mutiple sco link for cvsd", __func__);
              return;
            }
        } else{
            if(check_controller_support_msbc(data->udev)) {
                if(data->sco_num == 1)
                    new_alts = 4;
                else {
                    RTKBT_ERR("%s: we don't support mutiple sco link for msbc", __func__);
                    return;
                }
            } else {
                new_alts = 2;
            }
        }
        if (data->isoc_altsetting != new_alts) {

            clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
            mdelay(URB_CANCELING_DELAY_MS);
            usb_kill_anchored_urbs(&data->isoc_anchor);

            if(hdev->reassembly[HCI_SCODATA_PKT - 1]) {
                skb = hdev->reassembly[HCI_SCODATA_PKT - 1];
                hdev->reassembly[HCI_SCODATA_PKT - 1] = NULL;
                kfree_skb(skb);
            }
            if (set_isoc_interface(hdev, new_alts) < 0)
                return;
        }

        if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
            if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0)
                clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
            else
                btusb_submit_isoc_urb(hdev, GFP_KERNEL);
        }
#ifdef CONFIG_SCO_OVER_HCI
        if(test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
            set_bit(USB_CAPTURE_RUNNING, &data->pSCOSnd->states);
            set_bit(USB_PLAYBACK_RUNNING, &data->pSCOSnd->states);
        }
#endif
    } else {
        clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
#ifdef CONFIG_SCO_OVER_HCI
        clear_bit(USB_CAPTURE_RUNNING, &data->pSCOSnd->states);
        clear_bit(USB_PLAYBACK_RUNNING, &data->pSCOSnd->states);
#endif
        mdelay(URB_CANCELING_DELAY_MS);
        usb_kill_anchored_urbs(&data->isoc_anchor);

        set_isoc_interface(hdev, 0);

        if (test_and_clear_bit(BTUSB_DID_ISO_RESUME, &data->flags))
            usb_autopm_put_interface(data->isoc ? data->isoc : data->intf);
    }
}

static void btusb_waker(struct work_struct *work)
{
    struct btusb_data *data = container_of(work, struct btusb_data, waker);
    int err;

    RTKBT_DBG("%s: PM usage count %d", __func__,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
          atomic_read(&data->intf->pm_usage_cnt)
#else
          0
#endif
    );

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

    usb_autopm_put_interface(data->intf);
}


//#ifdef CONFIG_HAS_EARLYSUSPEND
#if 0
static void btusb_early_suspend(struct early_suspend *h)
{
    struct btusb_data *data;
    firmware_info *fw_info;
    patch_info *patch_entry;

    RTKBT_INFO("%s", __func__);

    data = container_of(h, struct btusb_data, early_suspend);
    fw_info = data->fw_info;
    patch_entry = fw_info->patch_entry;

    patch_entry->fw_len = load_firmware(fw_info, &patch_entry->fw_cache);
    if (patch_entry->fw_len <= 0) {
        /* We may encount failure in loading firmware, just give a warning */
        RTKBT_WARN("%s: Failed to load firmware", __func__);
    }
}

static void btusb_late_resume(struct early_suspend *h)
{
    struct btusb_data *data;
    firmware_info *fw_info;
    patch_info *patch_entry;

    RTKBT_INFO("%s", __func__);

    data = container_of(h, struct btusb_data, early_suspend);
    fw_info = data->fw_info;
    patch_entry = fw_info->patch_entry;

    /* Reclaim fw buffer when bt usb resumed */
    if (patch_entry->fw_len > 0) {
        kfree(patch_entry->fw_cache);
        patch_entry->fw_cache = NULL;
        patch_entry->fw_len = 0;
    }
}
#else
static int bt_pm_notify(struct notifier_block *notifier, ulong pm_event, void *unused)
{
    struct btusb_data *data;
    firmware_info *fw_info;
    patch_info *patch_entry;
    struct usb_device *udev;

    RTKBT_INFO("%s: pm event %ld", __func__, pm_event);

    data = container_of(notifier, struct btusb_data, pm_notifier);
    fw_info = data->fw_info;
    patch_entry = fw_info->patch_entry;
    udev = fw_info->udev;

    switch (pm_event) {
    case PM_SUSPEND_PREPARE:
    case PM_HIBERNATION_PREPARE:
#if 0
        patch_entry->fw_len = load_firmware(fw_info, &patch_entry->fw_cache);
        if (patch_entry->fw_len <= 0) {
        /* We may encount failure in loading firmware, just give a warning */
            RTKBT_WARN("%s: Failed to load firmware", __func__);
        }
#endif
        if (!device_may_wakeup(&udev->dev)) {
#if (CONFIG_RESET_RESUME || CONFIG_BLUEDROID)
            RTKBT_INFO("%s:remote wakeup not supported, reset resume supported", __func__);
#else
            fw_info->intf->needs_binding = 1;
            RTKBT_INFO("%s:remote wakeup not supported, binding needed", __func__);
#endif
        }
        break;

    case PM_POST_SUSPEND:
    case PM_POST_HIBERNATION:
    case PM_POST_RESTORE:
#if 0
        /* Reclaim fw buffer when bt usb resumed */
        if (patch_entry->fw_len > 0) {
            kfree(patch_entry->fw_cache);
            patch_entry->fw_cache = NULL;
            patch_entry->fw_len = 0;
        }
#endif

#if BTUSB_RPM
        usb_disable_autosuspend(udev);
        usb_enable_autosuspend(udev);
        pm_runtime_set_autosuspend_delay(&(udev->dev), 2000);
#endif
        break;

    default:
        break;
    }

    return NOTIFY_DONE;
}

static int bt_reboot_notify(struct notifier_block *notifier, ulong pm_event, void *unused)
{
    struct btusb_data *data;
    firmware_info *fw_info;
    patch_info *patch_entry;
    struct usb_device *udev;

    RTKBT_INFO("%s: pm event %ld", __func__, pm_event);

    data = container_of(notifier, struct btusb_data, reboot_notifier);
    fw_info = data->fw_info;
    patch_entry = fw_info->patch_entry;
    udev = fw_info->udev;

    switch (pm_event) {
    case SYS_DOWN:
        RTKBT_DBG("%s:system down or restart", __func__);
    break;

    case SYS_HALT:
    case SYS_POWER_OFF:
#if SUSPNED_DW_FW
        cancel_work_sync(&data->work);

        btusb_stop_traffic(data);
        mdelay(URB_CANCELING_DELAY_MS);
        usb_kill_anchored_urbs(&data->tx_anchor);


        if(fw_info_4_suspend) {
            download_suspend_patch(fw_info_4_suspend,1);
        }
	    else
		    RTKBT_ERR("%s: Failed to download suspend fw", __func__);
#endif

#if SET_WAKEUP_DEVICE
        set_wakeup_device_from_conf(fw_info_4_suspend);
#endif
        RTKBT_DBG("%s:system halt or power off", __func__);
    break;

    default:
        break;
    }

    return NOTIFY_DONE;
}

#endif

#ifdef CONFIG_SCO_OVER_HCI
static const struct snd_pcm_hardware snd_card_sco_capture_default =
{
    .info               = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_NONINTERLEAVED |
                            SNDRV_PCM_ACCESS_RW_INTERLEAVED | SNDRV_PCM_INFO_FIFO_IN_FRAMES),
    .formats            = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
    .rates              = (SNDRV_PCM_RATE_8000),
    .rate_min           = 8000,
    .rate_max           = 8000,
    .channels_min       = 1,
    .channels_max       = 1,
    .buffer_bytes_max   = 8 * 768,
    .period_bytes_min   = 48,
    .period_bytes_max   = 768,
    .periods_min        = 1,
    .periods_max        = 8,
    .fifo_size          = 8,

};

static int snd_sco_capture_pcm_open(struct snd_pcm_substream * substream)
{
    RTK_sco_card_t  *pSCOSnd = substream->private_data;

    RTKBT_INFO("%s", __FUNCTION__);
    pSCOSnd->capture.substream = substream;

    memcpy(&substream->runtime->hw, &snd_card_sco_capture_default, sizeof(struct snd_pcm_hardware));

    if(check_controller_support_msbc(pSCOSnd->dev)) {
        substream->runtime->hw.rates |= SNDRV_PCM_RATE_16000;
        substream->runtime->hw.rate_max = 16000;
        substream->runtime->hw.period_bytes_min = 96;
        substream->runtime->hw.period_bytes_max = 16 * 96;
        substream->runtime->hw.buffer_bytes_max = 8 * 16 * 96;
    }
    set_bit(ALSA_CAPTURE_OPEN, &pSCOSnd->states);
    return 0;
}

static int snd_sco_capture_pcm_close(struct snd_pcm_substream *substream)
{
	RTK_sco_card_t *pSCOSnd = substream->private_data;

	clear_bit(ALSA_CAPTURE_OPEN, &pSCOSnd->states);
	return 0;
}

static int snd_sco_capture_ioctl(struct snd_pcm_substream *substream,  unsigned int cmd, void *arg)
{
    RTKBT_DBG("%s, cmd = %d", __FUNCTION__, cmd);
    switch (cmd)
    {
        default:
            return snd_pcm_lib_ioctl(substream, cmd, arg);
    }
    return 0;
}

static int snd_sco_capture_pcm_hw_params(struct snd_pcm_substream * substream, struct snd_pcm_hw_params * hw_params)
{

    int err;
    struct snd_pcm_runtime *runtime = substream->runtime;
    err = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params));
    RTKBT_INFO("%s,err : %d,  runtime state : %d", __FUNCTION__, err, runtime->status->state);
    return err;
}

static int snd_sco_capture_pcm_hw_free(struct snd_pcm_substream * substream)
{
    RTKBT_DBG("%s", __FUNCTION__);
    return snd_pcm_lib_free_vmalloc_buffer(substream);;
}

static int snd_sco_capture_pcm_prepare(struct snd_pcm_substream *substream)
{
    RTK_sco_card_t *pSCOSnd = substream->private_data;
    struct snd_pcm_runtime *runtime = substream->runtime;

    RTKBT_INFO("%s", __FUNCTION__);
    if (test_bit(DISCONNECTED, &pSCOSnd->states))
		    return -ENODEV;
	  if (!test_bit(USB_CAPTURE_RUNNING, &pSCOSnd->states))
		    return -EIO;

    if(runtime->rate == 8000) {
        if(pSCOSnd->usb_data->isoc_altsetting != 2)
            return -ENOEXEC;
        pSCOSnd->capture.sco_packet_bytes = 48;
    }
    else if(runtime->rate == 16000 && check_controller_support_msbc(pSCOSnd->dev)) {
        if(pSCOSnd->usb_data->isoc_altsetting != 4)
            return -ENOEXEC;
        pSCOSnd->capture.sco_packet_bytes = 96;
    }
    else if(pSCOSnd->usb_data->isoc_altsetting == 2) {
        pSCOSnd->capture.sco_packet_bytes = 48;
    }
    else if(pSCOSnd->usb_data->isoc_altsetting == 1) {
        pSCOSnd->capture.sco_packet_bytes = 24;
    }
    return 0;
}

static int snd_sco_capture_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	  RTK_sco_card_t *pSCOSnd = substream->private_data;
    RTKBT_INFO("%s, cmd : %d", __FUNCTION__, cmd);

	  switch (cmd) {
	    case SNDRV_PCM_TRIGGER_START:
		      if (!test_bit(USB_CAPTURE_RUNNING, &pSCOSnd->states))
			      return -EIO;
		      set_bit(ALSA_CAPTURE_RUNNING, &pSCOSnd->states);
		      return 0;
	    case SNDRV_PCM_TRIGGER_STOP:
		      clear_bit(ALSA_CAPTURE_RUNNING, &pSCOSnd->states);
		      return 0;
	    default:
		      return -EINVAL;
	  }
}

static snd_pcm_uframes_t snd_sco_capture_pcm_pointer(struct snd_pcm_substream *substream)
{
	  RTK_sco_card_t *pSCOSnd = substream->private_data;

	  return pSCOSnd->capture.buffer_pos;
}


static struct snd_pcm_ops snd_sco_capture_pcm_ops = {
	.open =         snd_sco_capture_pcm_open,
	.close =        snd_sco_capture_pcm_close,
	.ioctl =        snd_sco_capture_ioctl,
	.hw_params =    snd_sco_capture_pcm_hw_params,
	.hw_free =      snd_sco_capture_pcm_hw_free,
	.prepare =      snd_sco_capture_pcm_prepare,
	.trigger =      snd_sco_capture_pcm_trigger,
	.pointer =      snd_sco_capture_pcm_pointer,
};


static const struct snd_pcm_hardware snd_card_sco_playback_default =
{
    .info               = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_NONINTERLEAVED |
                            SNDRV_PCM_ACCESS_RW_INTERLEAVED | SNDRV_PCM_INFO_FIFO_IN_FRAMES),
    .formats            = SNDRV_PCM_FMTBIT_S16_LE,
    .rates              = (SNDRV_PCM_RATE_8000),
    .rate_min           = 8000,
    .rate_max           = 8000,
    .channels_min       = 1,
    .channels_max       = 1,
    .buffer_bytes_max   = 8 * 768,
    .period_bytes_min   = 48,
    .period_bytes_max   = 768,
    .periods_min        = 1,
    .periods_max        = 8,
    .fifo_size          = 8,
};

static int snd_sco_playback_pcm_open(struct snd_pcm_substream * substream)
{
    RTK_sco_card_t *pSCOSnd = substream->private_data;
    int err = 0;

    RTKBT_INFO("%s, rate : %d", __FUNCTION__, substream->runtime->rate);
    memcpy(&substream->runtime->hw, &snd_card_sco_playback_default, sizeof(struct snd_pcm_hardware));
    if(check_controller_support_msbc(pSCOSnd->dev)) {
        substream->runtime->hw.rates |= SNDRV_PCM_RATE_16000;
        substream->runtime->hw.rate_max = 16000;
        substream->runtime->hw.period_bytes_min = 96;
        substream->runtime->hw.period_bytes_max = 16 * 96;
        substream->runtime->hw.buffer_bytes_max = 8 * 16 * 96;
    }
    pSCOSnd->playback.substream = substream;
    set_bit(ALSA_PLAYBACK_OPEN, &pSCOSnd->states);

    return err;
}

static int snd_sco_playback_pcm_close(struct snd_pcm_substream *substream)
{
    RTK_sco_card_t *pSCOSnd = substream->private_data;

	  clear_bit(ALSA_PLAYBACK_OPEN, &pSCOSnd->states);
    cancel_work_sync(&pSCOSnd->send_sco_work);
	  return 0;
}

static int snd_sco_playback_ioctl(struct snd_pcm_substream *substream,  unsigned int cmd, void *arg)
{
    RTKBT_DBG("%s, cmd : %d", __FUNCTION__, cmd);
    switch (cmd)
    {
        default:
            return snd_pcm_lib_ioctl(substream, cmd, arg);
            break;
    }
    return 0;
}

static int snd_sco_playback_pcm_hw_params(struct snd_pcm_substream * substream, struct snd_pcm_hw_params * hw_params)
{
    int err;
    err = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params));
    return err;
}

static int snd_sco_palyback_pcm_hw_free(struct snd_pcm_substream * substream)
{
    RTKBT_DBG("%s", __FUNCTION__);
    return snd_pcm_lib_free_vmalloc_buffer(substream);
}

static int snd_sco_playback_pcm_prepare(struct snd_pcm_substream *substream)
{
	  RTK_sco_card_t *pSCOSnd = substream->private_data;
    struct snd_pcm_runtime *runtime = substream->runtime;

    RTKBT_INFO("%s, bound_rate = %d", __FUNCTION__, runtime->rate);

	  if (test_bit(DISCONNECTED, &pSCOSnd->states))
		    return -ENODEV;
	  if (!test_bit(USB_PLAYBACK_RUNNING, &pSCOSnd->states))
		    return -EIO;

    if(runtime->rate == 8000) {
        if(pSCOSnd->usb_data->isoc_altsetting != 2)
            return -ENOEXEC;
        pSCOSnd->playback.sco_packet_bytes = 48;
    }
    else if(runtime->rate == 16000) {
        if(pSCOSnd->usb_data->isoc_altsetting != 4)
            return -ENOEXEC;
        pSCOSnd->playback.sco_packet_bytes = 96;
    }

  	return 0;
}

static int snd_sco_playback_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
  	RTK_sco_card_t *pSCOSnd = substream->private_data;

    RTKBT_INFO("%s, cmd = %d", __FUNCTION__, cmd);
  	switch (cmd) {
      	case SNDRV_PCM_TRIGGER_START:
      		if (!test_bit(USB_PLAYBACK_RUNNING, &pSCOSnd->states))
      			return -EIO;
      		set_bit(ALSA_PLAYBACK_RUNNING, &pSCOSnd->states);
          schedule_work(&pSCOSnd->send_sco_work);
      		return 0;
      	case SNDRV_PCM_TRIGGER_STOP:
      		clear_bit(ALSA_PLAYBACK_RUNNING, &pSCOSnd->states);
      		return 0;
      	default:
      		return -EINVAL;
  	}
}

static snd_pcm_uframes_t snd_sco_playback_pcm_pointer(struct snd_pcm_substream *substream)
{
  	RTK_sco_card_t *pSCOSnd = substream->private_data;

  	return pSCOSnd->playback.buffer_pos;
}


static struct snd_pcm_ops snd_sco_playback_pcm_ops = {
	.open =         snd_sco_playback_pcm_open,
	.close =        snd_sco_playback_pcm_close,
	.ioctl =        snd_sco_playback_ioctl,
	.hw_params =    snd_sco_playback_pcm_hw_params,
	.hw_free =      snd_sco_palyback_pcm_hw_free,
	.prepare =      snd_sco_playback_pcm_prepare,
	.trigger =      snd_sco_playback_pcm_trigger,
	.pointer =      snd_sco_playback_pcm_pointer,
};


static RTK_sco_card_t* btusb_snd_init(struct usb_interface *intf, const struct usb_device_id *id, struct btusb_data *data)
{
    struct snd_card *card;
    RTK_sco_card_t  *pSCOSnd;
    int err=0;
    RTKBT_INFO("%s", __func__);
    err = snd_card_new(&intf->dev,
     -1, RTK_SCO_ID, THIS_MODULE,
     sizeof(RTK_sco_card_t), &card);
    if (err < 0) {
        RTKBT_ERR("%s: sco snd card create fail", __func__);
        return NULL;
    }
    // private data
    pSCOSnd = (RTK_sco_card_t *)card->private_data;
    pSCOSnd->card = card;
    pSCOSnd->dev = interface_to_usbdev(intf);
    pSCOSnd->usb_data = data;

    strcpy(card->driver, RTK_SCO_ID);
    strcpy(card->shortname, "Realtek sco snd");
    sprintf(card->longname, "Realtek sco over hci: VID:0x%04x, PID:0x%04x",
        id->idVendor, pSCOSnd->dev->descriptor.idProduct);

    err = snd_pcm_new(card, RTK_SCO_ID, 0, 1, 1, &pSCOSnd->pcm);
    if (err < 0) {
        RTKBT_ERR("%s: sco snd card new pcm fail", __func__);
        snd_card_free(card);
        return NULL;
    }
    pSCOSnd->pcm->private_data = pSCOSnd;
    sprintf(pSCOSnd->pcm->name, "sco_pcm:VID:0x%04x, PID:0x%04x",
      id->idVendor, pSCOSnd->dev->descriptor.idProduct);

    snd_pcm_set_ops(pSCOSnd->pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sco_playback_pcm_ops);
    snd_pcm_set_ops(pSCOSnd->pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sco_capture_pcm_ops);

    err = snd_card_register(card);
    if (err < 0) {
        RTKBT_ERR("%s: sco snd card register card fail", __func__);
        snd_card_free(card);
        return NULL;
    }

    spin_lock_init(&pSCOSnd->capture_lock);
    spin_lock_init(&pSCOSnd->playback_lock);
    INIT_WORK(&pSCOSnd->send_sco_work, playback_work);
    return pSCOSnd;
}

static void btusb_snd_remove(RTK_sco_card_t  *pSCOSnd)
{
    if(!pSCOSnd) {
        RTKBT_ERR("%s: sco private data is null", __func__);
        return;
    }
    set_bit(DISCONNECTED, &pSCOSnd->states);
    snd_card_disconnect(pSCOSnd->card);
    snd_card_free_when_closed(pSCOSnd->card);
}
#endif

static int btusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
    struct usb_device *udev = interface_to_usbdev(intf);
    struct usb_endpoint_descriptor *ep_desc;
    struct btusb_data *data;
    struct hci_dev *hdev;
    firmware_info *fw_info;
    int i, err=0;

    RTKBT_INFO("%s: usb_interface11111111 %p, bInterfaceNumber %d, idVendor 0x%04x, "
            "idProduct 0x%04x", __func__, intf,
            intf->cur_altsetting->desc.bInterfaceNumber,
            id->idVendor, id->idProduct);

    /* interface numbers are hardcoded in the spec */
    if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
        return -ENODEV;

    RTKBT_DBG("%s: can wakeup = %x, may wakeup = %x", __func__,
            device_can_wakeup(&udev->dev), device_may_wakeup(&udev->dev));

    data = rtk_alloc(intf);
    if (!data)
        return -ENOMEM;

    for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
        ep_desc = &intf->cur_altsetting->endpoint[i].desc;

        if (!data->intr_ep && usb_endpoint_is_int_in(ep_desc)) {
            data->intr_ep = ep_desc;
            continue;
        }

        if (!data->bulk_tx_ep && usb_endpoint_is_bulk_out(ep_desc)) {
            data->bulk_tx_ep = ep_desc;
            continue;
        }

        if (!data->bulk_rx_ep && usb_endpoint_is_bulk_in(ep_desc)) {
            data->bulk_rx_ep = ep_desc;
            continue;
        }
    }

    if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
        rtk_free(data);
        return -ENODEV;
    }

    data->cmdreq_type = USB_TYPE_CLASS;

    data->udev = udev;
    data->intf = intf;

    spin_lock_init(&data->lock);

    INIT_WORK(&data->work, btusb_work);
    INIT_WORK(&data->waker, btusb_waker);
    spin_lock_init(&data->txlock);

    init_usb_anchor(&data->tx_anchor);
    init_usb_anchor(&data->intr_anchor);
    init_usb_anchor(&data->bulk_anchor);
    init_usb_anchor(&data->isoc_anchor);
    init_usb_anchor(&data->deferred);

    fw_info = firmware_info_init(intf);
    if (fw_info)
        data->fw_info = fw_info;
    else {
        RTKBT_WARN("%s: Failed to initialize fw info", __func__);
        /* Skip download patch */
        goto end;
    }

    hdev = hci_alloc_dev();
    if (!hdev) {
        rtk_free(data);
        data = NULL;
        return -ENOMEM;
    }

    HDEV_BUS = HCI_USB;

    data->hdev = hdev;

    SET_HCIDEV_DEV(hdev, &intf->dev);

    hdev->open     = btusb_open;
    hdev->close    = btusb_close;
    hdev->flush    = btusb_flush;
    hdev->send     = btusb_send_frame;
    hdev->notify   = btusb_notify;

#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 0)
    hci_set_drvdata(hdev, data);
#else
    hdev->driver_data = data;
    hdev->destruct = btusb_destruct;
    hdev->owner = THIS_MODULE;
#endif

    /* Interface numbers are hardcoded in the specification */
    data->isoc = usb_ifnum_to_if(data->udev, 1);
    if (data->isoc) {
        err = usb_driver_claim_interface(&btusb_driver,
                            data->isoc, data);
        if (err < 0) {
            hci_free_dev(hdev);
            hdev = NULL;
            rtk_free(data);
            data = NULL;
            return err;
        }
#ifdef CONFIG_SCO_OVER_HCI
        data->pSCOSnd = btusb_snd_init(intf, id, data);
#endif
    }

    err = hci_register_dev(hdev);
    if (err < 0) {
        hci_free_dev(hdev);
        hdev = NULL;
        rtk_free(data);
        data = NULL;
        return err;
    }

    usb_set_intfdata(intf, data);

//#ifdef CONFIG_HAS_EARLYSUSPEND
#if 0
    data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
    data->early_suspend.suspend = btusb_early_suspend;
    data->early_suspend.resume = btusb_late_resume;
    register_early_suspend(&data->early_suspend);
#else
    data->pm_notifier.notifier_call = bt_pm_notify;
    data->reboot_notifier.notifier_call = bt_reboot_notify;
    register_pm_notifier(&data->pm_notifier);
    register_reboot_notifier(&data->reboot_notifier);
#endif

#if CONFIG_BLUEDROID
    RTKBT_INFO("%s: Check bt reset flag %d", __func__, bt_reset);
    /* Report hci hardware error after everthing is ready,
     * especially hci register is completed. Or, btchr_poll
     * will get null hci dev when hotplug in.
     */
    if (bt_reset == 1) {
        hci_hardware_error();
        bt_reset = 0;
    } else
        bt_reset = 0; /* Clear and reset it anyway */
#endif

    load_firmware_info(fw_info);

end:
    set_driver_state_value(DEVICE_PROBED);
    return 0;
}

static void btusb_disconnect(struct usb_interface *intf)
{
    struct btusb_data *data;
    struct hci_dev *hdev = NULL;

    if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
        return;

    clear_driver_state(DEVICE_PROBED);
    if((get_driver_state_value() & CHAR_OPENED) == CHAR_OPENED)
        wake_up_interruptible(&btchr_read_wait);

    wait_event_interruptible(bt_drv_state_wait, ((get_driver_state_value() & CHAR_OPENED) == 0));

    RTKBT_INFO("%s: usb_interface %p, bInterfaceNumber %d",
            __func__, intf, intf->cur_altsetting->desc.bInterfaceNumber);

    data = usb_get_intfdata(intf);

    if (data)
        hdev = data->hdev;
    else {
        RTKBT_WARN("%s: Failed to get bt usb data[Null]", __func__);
        return;
    }

#ifdef CONFIG_SCO_OVER_HCI
    if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
        RTK_sco_card_t *pSCOSnd = data->pSCOSnd;
        btusb_snd_remove(pSCOSnd);
    }
#endif

//#ifdef CONFIG_HAS_EARLYSUSPEND
#if 0
    unregister_early_suspend(&data->early_suspend);
#else
    unregister_pm_notifier(&data->pm_notifier);
    unregister_reboot_notifier(&data->reboot_notifier);
#endif

    firmware_info_destroy(intf);

#if CONFIG_BLUEDROID
    if (test_bit(HCI_RUNNING, &hdev->flags)) {
        RTKBT_INFO("%s: Set BT reset flag", __func__);
        bt_reset = 1;
    }
#endif

    usb_set_intfdata(data->intf, NULL);

    if (data->isoc)
        usb_set_intfdata(data->isoc, NULL);

    hci_unregister_dev(hdev);

    if (intf == data->isoc)
        usb_driver_release_interface(&btusb_driver, data->intf);
    else if (data->isoc)
        usb_driver_release_interface(&btusb_driver, data->isoc);

#if !CONFIG_BLUEDROID
#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 4, 0)
    __hci_dev_put(hdev);
#endif
#endif

    hci_free_dev(hdev);
    rtk_free(data);
    data = NULL;
    set_driver_state_value(0);
}

#ifdef CONFIG_PM
static int btusb_suspend(struct usb_interface *intf, pm_message_t message)
{
    struct btusb_data *data = usb_get_intfdata(intf);
    firmware_info *fw_info = data->fw_info;

    RTKBT_INFO("%s: event 0x%x, suspend count %d", __func__,
            message.event, data->suspend_count);

    if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
        return 0;

    if (!test_bit(HCI_RUNNING, &data->hdev->flags))
        set_bt_onoff(fw_info, 1);

    if (data->suspend_count++)
        return 0;

    spin_lock_irq(&data->txlock);
    if (!((message.event & PM_EVENT_AUTO) && data->tx_in_flight)) {
        set_bit(BTUSB_SUSPENDING, &data->flags);
        spin_unlock_irq(&data->txlock);
    } else {
        spin_unlock_irq(&data->txlock);
        data->suspend_count--;
        RTKBT_ERR("%s: Failed to enter suspend", __func__);
        return -EBUSY;
    }

    cancel_work_sync(&data->work);

    btusb_stop_traffic(data);
    mdelay(URB_CANCELING_DELAY_MS);
    usb_kill_anchored_urbs(&data->tx_anchor);

#if SUSPNED_DW_FW
    if(fw_info_4_suspend) {
        download_suspend_patch(fw_info_4_suspend,1);
    }
    else
        RTKBT_ERR("%s: Failed to download suspend fw", __func__);
#endif

#if SET_WAKEUP_DEVICE
    set_wakeup_device_from_conf(fw_info_4_suspend);
#endif

    return 0;
}

static void play_deferred(struct btusb_data *data)
{
    struct urb *urb;
    int err;

    while ((urb = usb_get_from_anchor(&data->deferred))) {
        usb_anchor_urb(urb, &data->tx_anchor);
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
            RTKBT_ERR("%s: Failed to submit urb %p, err %d",
                    __func__, urb, err);
            kfree(urb->setup_packet);
            usb_unanchor_urb(urb);
        } else {
            usb_mark_last_busy(data->udev);
        }
        usb_free_urb(urb);

        data->tx_in_flight++;
    }
    mdelay(URB_CANCELING_DELAY_MS);
    usb_scuttle_anchored_urbs(&data->deferred);
}

static int btusb_resume(struct usb_interface *intf)
{
    struct btusb_data *data = usb_get_intfdata(intf);
    struct hci_dev *hdev = data->hdev;
    firmware_info *fw_info = data->fw_info;
    int err = 0;

    RTKBT_INFO("%s: Suspend count %d", __func__, data->suspend_count);

    if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
        return 0;

    if (--data->suspend_count)
        return 0;

    /*check_fw_version to check the status of the BT Controller after USB Resume*/
    err = check_fw_version(fw_info, true);
    if (err !=0)
    {
        RTKBT_INFO("%s: BT Controller Power OFF And Return hci_hardware_error:%d", __func__, err);
        hci_hardware_error();
    }


    if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) {
        err = btusb_submit_intr_urb(hdev, GFP_NOIO);
        if (err < 0) {
            clear_bit(BTUSB_INTR_RUNNING, &data->flags);
            goto failed;
        }
    }

    if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) {
        err = btusb_submit_bulk_urb(hdev, GFP_NOIO);
        if (err < 0) {
            clear_bit(BTUSB_BULK_RUNNING, &data->flags);
            goto failed;
        }

        btusb_submit_bulk_urb(hdev, GFP_NOIO);
    }

    if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) {
        if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0)
            clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
        else
            btusb_submit_isoc_urb(hdev, GFP_NOIO);
    }

    spin_lock_irq(&data->txlock);
    play_deferred(data);
    clear_bit(BTUSB_SUSPENDING, &data->flags);
    spin_unlock_irq(&data->txlock);
    schedule_work(&data->work);

    return 0;

failed:
    mdelay(URB_CANCELING_DELAY_MS);
    usb_scuttle_anchored_urbs(&data->deferred);
    spin_lock_irq(&data->txlock);
    clear_bit(BTUSB_SUSPENDING, &data->flags);
    spin_unlock_irq(&data->txlock);

    return err;
}
#endif

static struct usb_driver btusb_driver = {
    .name        = "rtk_btusb",
    .probe        = btusb_probe,
    .disconnect    = btusb_disconnect,
#ifdef CONFIG_PM
    .suspend    = btusb_suspend,
    .resume        = btusb_resume,
#endif
#if CONFIG_RESET_RESUME
    .reset_resume    = btusb_resume,
#endif
    .id_table    = btusb_table,
    .supports_autosuspend = 1,
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 1)
    .disable_hub_initiated_lpm = 1,
#endif
};

static int __init btusb_init(void)
{
    int err;

    RTKBT_INFO("RTKBT_RELEASE_NAME: %s",RTKBT_RELEASE_NAME);
    RTKBT_INFO("Realtek Bluetooth USB driver module init, version %s", VERSION);
    driver_state = 0;
#if CONFIG_BLUEDROID
    err = btchr_init();
    if (err < 0) {
        /* usb register will go on, even bt char register failed */
        RTKBT_ERR("Failed to register usb char device interfaces");
    }
    else
      set_driver_state_value(DRIVER_ON);
#endif
    err = usb_register(&btusb_driver);
    if (err < 0)
        RTKBT_ERR("Failed to register RTK bluetooth USB driver");
    return err;
}

static void __exit btusb_exit(void)
{
    struct hci_dev *hdev;
    RTKBT_INFO("Realtek Bluetooth USB driver module exit");
#if CONFIG_BLUEDROID
    clear_driver_state(DRIVER_ON);
    hdev = hci_dev_get(0);
    while(hdev && atomic_read(&hdev->promisc)) {
        RTKBT_ERR("%s: rtkbt driver is being removed, but application is still running!", __func__);
        RTKBT_ERR("%s: wait bt application to stop, or the driver can't be removed", __func__);
        mdelay(100);
    }
    btchr_exit();
#endif
    usb_deregister(&btusb_driver);
}

module_init(btusb_init);
module_exit(btusb_exit);


module_param(mp_drv_mode, int, 0644);
MODULE_PARM_DESC(mp_drv_mode, "0: NORMAL; 1: MP MODE");


MODULE_AUTHOR("Realtek Corporation");
MODULE_DESCRIPTION("Realtek Bluetooth USB driver version");
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");

        5.2 通过vid 匹配

        5.3 驱动加载成功。

六、实际测试发现,如果上面两个驱动都打开,有个驱动无法匹配,不能进入probe函数,原因就是两个驱动都是识别同样类型的usb设备,要特别留意这点。我在后来调试一个蓝牙模块的时候又认识到一点,就算模块执行的时候没有识别到对应的usb设备,后面识别到的usb设备的时候也会进入probe函数。

七、参考文章

USB描述符_usb 描述符类型_Ink bone的博客-CSDN博客

USB设备创建过程与驱动学习笔记_hello_ludy的博客-CSDN博客

摘 要:基于对Linux蓝牙协议栈BlueZ 源代码的分析,给出BlueZ的组织结构特点。分析蓝牙USB 传输驱动机制数据处理过程, 给出实现蓝牙设备驱动的重要数据结构流程,并总结Linux 下开发蓝牙USB 设备驱动的一般方法关键技术。 关键词:Linux 系统;蓝牙协议栈;设备驱动 USB Device Driver for Linux Bluetooth Stack LIANG Jun-xue, YU Bin (Institute of Electronic Technology, PLA Information Engineering University, Zhengzhou 450004) 【Abstract】This paper depicts the structure and characteristics of BlueZ based on analyzing the source code of Linux bluetooth stack BlueZ. It analyzes the implementation of bluetooth USB transport driver scheme and data processing procedure in detail, and gives the key data structure and implementation of bluetooth device driver. It summarizes the approach of developing Linux bluetooth USB device driver and the key technology. 【Key words】Linux system; bluetooth stack; device driver 计 算 机 工 程 Computer Engineering 第 34 卷 第 9 期 Vol.34 No.9 2008 年 5 月 May 2008 &middot;开发研究与设计技术&middot; 文章编号:1000—3428(2008)09—0273—03 文献标识码:A 中图分类号:TP391 1 概述 蓝牙技术是开放式通信规范,而 Linux 是开放源码的操 作系统。廉价设备与免费软件的结合,促进了蓝牙技术 Linux 的发展与融合。 Linux最早的蓝牙协议栈是由Axis Communication Inc在 1999 年发布的 OpenBT 协议栈。 随后, IBM 发布了 BlueDrekar 协议栈,但没有公开其源码。Qualcomm Incorporated 在 2001 年发布的 BlueZ 协议栈被接纳为 2.4.6 内核的一部分。此外, Rappore Technology 及 Nokia 的 Affix Bluetooth Stack 都是 Linux 系统下的蓝牙协议栈,应用在不同的设备领域中。 BlueZ 是 Linux 的官方蓝牙协议栈,也是目前应用最广 泛的协议栈,几乎支持所有已通过认证的蓝牙设备。对于基 于主机的蓝牙应用,目前常见的硬件接口有 UART, USB PC 卡等,USB 作为 PC 的标准外设接口,具有连接方便、兼 容性好支持高速设备等特点,已广泛应用于蓝牙设备。 目前对 LinuxUSB 设备驱动的研究已较为广泛而深 入[1-4] ,但对 Linux 下的蓝牙设备驱动还没有专门的研究。本 文在分析 USB 设备驱动蓝牙协议栈的基础上,总结了 Linux 下开发蓝牙 USB 驱动程序的一般方法,并深入剖析了 其关键技术。 2 Linux 蓝牙协议栈 BlueZ 简介 BlueZ 目前已成为一个开放性的源码工程。它可以很好 地在 Linux 支持的各种体系的硬件平台下运行,包括各种单 处理器平台、多处理器平台及超线程系统。 BlueZ 由多个独立的模块组成,内核空间主要包括设备 驱动层、蓝牙核心及 HCI 层、L2CAP 与 SCO 音频层、 RFCOMM, BNEP, CMTP 与 HIDP 层、通用蓝牙 SDP 库后 台服务及面向所有层的标准套接字接口;在用户空间提供了 蓝牙配置、测试及协议分析等工具。其组织结构如图 1 所示, BlueZ 没有实现专门的 SDP 层,而是将其实现为运行在后台 的蓝牙服务库例程(图 1 没有描述该后台服务)。 RFOMM 层支 持标准的套接口,并提供了串行仿真 TTY 接口,这使串行端 口应用程序协议可以不加更改地运行在蓝牙设备上,例如 通过点对点协议 PPP 可实现基于 TCP/IP 协议簇的所有网络 应用。BNEP 层实现了蓝牙的以太网仿真,TCP/IP 可以直接 运行于其上。 USB设备驱动 (hci_usb.o) L2CAP层(l2cap.o) RFCOMM层 (rfcomm.o) BNEP层 (bnep.o) CMTP层 (cmtp.o) 串口设备驱动 (hci_uart.o) 虚拟串口设备驱动 (hci_vhci.o) 音频 socket RFCOMM socket BNEP socket CMTP socket L2CAP socket HCI socket 内核 空间 用户 空间 串口设备 CAPI设备 输入设备 网络设备 HDIP socket 音频设备 AF_BLUETOOTH socket 音频层(sco.o) PPP TCP/IP AF_INET socket BNEP层 (bnep.o) 其他设备驱动 (bluecard_cs.o等) BlueZ工具实用程序 HDIP层 (hdip.o) BlueZ核心 及HCI层(bluez.o/bluetooth.o) 图 1 BlueZ 组织结构 3 蓝牙 USB 设备驱动 设备驱动程序在 Linux 内核中起着重要作用,它使某个 硬件能响应一个定义良好的内部编程接口。这些接口隐藏了 设备的工作细节,用户通过一组独立于特定驱动程序的标准 调用来操作设备。而将这些调用映射到作用于实际硬件设备 的特有操作上,则是驱动程序的任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值