All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
@ 2014-07-01 12:47 Daniel Drake
  2014-07-01 13:41 ` Marcel Holtmann
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Drake @ 2014-07-01 12:47 UTC (permalink / raw)
  To: marcel, gustavo, johan.hedberg; +Cc: linux-bluetooth, Larry.Finger

Realtek ship a variety of bluetooth USB devices that identify
themselves with standard USB Bluetooth device class values, but
require a special driver to actually work. Without that driver,
you never get any scan results.

More recently however, Realtek appear to have wisened up and simply
posted a firmware update that makes these devices comply with
normal btusb protocols. The firmware needs to be uploaded on each boot.

Based on Realtek code from https://github.com/lwfinger/rtl8723au_bt
('new' branch).

This enables bluetooth support in the Gigabyte Brix GB-BXBT-2807 which
has this RTL8723BE USB device:

T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  3 Spd=12   MxCh= 0
D:  Ver= 2.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=13d3 ProdID=3410 Rev= 2.00
S:  Manufacturer=Realtek
S:  Product=Bluetooth Radio
S:  SerialNumber=00e04c000001
C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms

There is no change to the USB descriptor after firmware update,
however the version read by HCI_OP_READ_LOCAL_VERSION changes from
0x8723 to 0x3083.

Signed-off-by: Daniel Drake <drake@endlessm.com>
---
 drivers/bluetooth/btusb.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 438 insertions(+)

v2:
 - share main blacklist table with other devices
 - epatch table parsing endian/alignment fixes
 - BT_INFO message to inform user
 - added missing kmalloc error check
 - fixed skb leak
 - style fixes

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 6250fc2..e6e7c23 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/firmware.h>
+#include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -50,6 +51,13 @@ static struct usb_driver btusb_driver;
 #define BTUSB_ATH3012		0x80
 #define BTUSB_INTEL		0x100
 #define BTUSB_BCM_PATCHRAM	0x200
+#define BTUSB_RTL8723A		0x400
+#define BTUSB_RTL8723B		0x800
+#define BTUSB_RTL8761AU		0x1000
+#define BTUSB_RTL8761AW_8192EU	0x2000
+#define BTUSB_RTL8761AU_8192EE	0x4000
+#define BTUSB_RTL8761AU_8812AE	0x8000
+#define BTUSB_RTL8821A		0x10000
 
 static const struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
@@ -237,6 +245,22 @@ static const struct usb_device_id blacklist_table[] = {
 	{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
 	{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
 
+	/* Realtek Bluetooth devices */
+	{ USB_DEVICE(0x0bda, 0xa761), .driver_info = BTUSB_RTL8761AU },
+	{ USB_DEVICE(0x0bda, 0x8760), .driver_info = BTUSB_RTL8761AU_8192EE },
+	{ USB_DEVICE(0x0bda, 0xb761), .driver_info = BTUSB_RTL8761AU_8192EE },
+	{ USB_DEVICE(0x0bda, 0x8761), .driver_info = BTUSB_RTL8761AU_8192EE },
+	{ USB_DEVICE(0x0bda, 0x8a60), .driver_info = BTUSB_RTL8761AU_8812AE },
+	{ USB_DEVICE(0x0bda, 0x818b), .driver_info = BTUSB_RTL8761AW_8192EU },
+	{ USB_DEVICE(0x0bda, 0x0821), .driver_info = BTUSB_RTL8821A },
+	{ USB_DEVICE(0x0bda, 0x8821), .driver_info = BTUSB_RTL8821A },
+	{ USB_DEVICE(0x0bda, 0x8723), .driver_info = BTUSB_RTL8723A },
+	{ USB_DEVICE(0x0bda, 0xb720), .driver_info = BTUSB_RTL8723B },
+	{ USB_DEVICE(0x0bda, 0xb72a), .driver_info = BTUSB_RTL8723B },
+	{ USB_DEVICE(0x0bda, 0xb728), .driver_info = BTUSB_RTL8723B },
+	{ USB_DEVICE(0x0bda, 0xb723), .driver_info = BTUSB_RTL8723B },
+	{ USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_RTL8723B },
+
 	{ }	/* Terminating entry */
 };
 
@@ -257,6 +281,7 @@ struct btusb_data {
 	spinlock_t lock;
 
 	unsigned long flags;
+	unsigned long driver_info;
 
 	struct work_struct work;
 	struct work_struct waker;
@@ -1382,6 +1407,411 @@ exit_mfg_deactivate:
 	return 0;
 }
 
+#define RTL_FRAG_LEN 252
+
+struct rtk_download_cmd {
+	uint8_t index;
+	uint8_t data[RTL_FRAG_LEN];
+} __packed;
+
+struct rtk_download_response {
+	uint8_t status;
+	uint8_t index;
+} __packed;
+
+struct rtk_eversion_evt {
+	uint8_t status;
+	uint8_t version;
+} __packed;
+
+struct rtk_epatch_header {
+	uint8_t signature[8];
+	uint32_t fm_version;
+	uint16_t num_patches;
+} __packed;
+
+static const uint8_t RTK_EPATCH_SIGNATURE[] = {
+	0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68
+};
+
+#define ROM_LMP_8723a	0x1200
+#define ROM_LMP_8723b	0x8723
+#define ROM_LMP_8821a	0x8821
+#define ROM_LMP_8761a	0x8761
+
+static const uint16_t project_id[] = {
+	ROM_LMP_8723a,
+	ROM_LMP_8723b,
+	ROM_LMP_8821a,
+	ROM_LMP_8761a
+};
+
+static const struct rtk_fw_info {
+	unsigned long variant; /* corresponds to .driver_info */
+	uint16_t lmp_sub;
+	const char *fw_name;
+	const char *config_name;
+} rtk_fw_table[] = {
+	{ BTUSB_RTL8723A, ROM_LMP_8723a, "rtl8723a_fw", "rtl8723a_config" },
+	{ BTUSB_RTL8723B, ROM_LMP_8723b, "rtl8723b_fw", "rtl8723b_config" },
+	{ BTUSB_RTL8761AU, ROM_LMP_8761a, "rtl8761au_fw", "rtl8761a_config" },
+	{ BTUSB_RTL8761AW_8192EU, ROM_LMP_8761a, "rtl8761aw8192eu_fw", "rtl8761a_config" },
+	{ BTUSB_RTL8761AU_8192EE, ROM_LMP_8761a, "rtl8761au8192ee_fw", "rtl8761a_config" },
+	{ BTUSB_RTL8761AU_8812AE, ROM_LMP_8761a, "rtl8761au8812ae_fw", "rtl8761a_config" },
+	{ BTUSB_RTL8821A, ROM_LMP_8821a, "rtl8821a_fw", "rtl8821a_config" },
+};
+
+static const struct rtk_fw_info *rtk_get_fw_info(struct hci_dev *hdev)
+{
+	struct btusb_data *data = dev_get_drvdata(&hdev->dev);
+	const struct rtk_fw_info *info;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rtk_fw_table); i++) {
+		info = &rtk_fw_table[i];
+		if (info->variant == data->driver_info)
+			return info;
+	}
+
+	return NULL;
+}
+
+static int rtk_read_eversion(struct hci_dev *hdev)
+{
+	struct rtk_eversion_evt *eversion;
+	struct sk_buff *skb;
+	int r;
+
+	/* Read RTK ROM version command */
+	skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
+	if (IS_ERR(skb)) {
+		BT_ERR("Read ROM version failed (%ld)", PTR_ERR(skb));
+		return PTR_ERR(skb);
+	}
+
+	if (skb->len != sizeof(*eversion)) {
+		BT_ERR("RTK version event length mismatch");
+		kfree_skb(skb);
+		return -EIO;
+	}
+
+	eversion = (struct rtk_eversion_evt *) skb->data;
+	BT_DBG("eversion status=%x version=%x",
+	       eversion->status, eversion->version);
+	if (eversion->status)
+		r = 0;
+	else
+		r = eversion->version;
+
+	kfree_skb(skb);
+	return r;
+}
+
+/* RTL8723A has a simple fw patch format */
+static int rtk_load_firmware_8723a(const struct firmware *epatch_fw,
+				   const struct firmware *config_fw,
+				   unsigned char **_buf)
+{
+	unsigned char *buf;
+	int len;
+
+	if (epatch_fw->size < 8)
+		return -EINVAL;
+
+	/* This might look odd, but it's how the Realtek driver does it:
+	 * Make sure we don't match the regular epatch signature. Maybe that
+	 * signature is only for the newer devices. */
+	if (memcmp(epatch_fw->data, RTK_EPATCH_SIGNATURE, 8) == 0) {
+		BT_ERR("8723a has EPATCH signature!");
+		return -EINVAL;
+	}
+
+	len = epatch_fw->size;
+	if (config_fw)
+		len += config_fw->size;
+
+	buf = kzalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	BT_DBG("8723a direct firmware copy\n");
+	memcpy(buf, epatch_fw->data, epatch_fw->size);
+	if (config_fw)
+		memcpy(buf + epatch_fw->size, config_fw->data, config_fw->size);
+
+	*_buf = buf;
+	return len;
+}
+
+/* RTL8723B and newer have a patch format which requires some parsing */
+static int rtk_load_firmware_8723b(const struct rtk_fw_info *fw_info,
+				   uint8_t eversion,
+				   const struct firmware *epatch_fw,
+				   const struct firmware *config_fw,
+				   unsigned char **_buf)
+{
+	const uint8_t extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
+	struct rtk_epatch_header *epatch_info;
+	u16 lmp_version = fw_info->lmp_sub;
+	unsigned char *buf;
+	int i, len;
+	size_t min_size;
+	uint8_t opcode, length, data;
+	unsigned char *tmp;
+	const unsigned char *fwptr;
+	const unsigned char *chip_id_base, *patch_length_base, *patch_offset_base;
+	u32 patch_offset = 0;
+	u16 patch_length;
+
+	BT_DBG("lmp_version=%x eversion=%x", lmp_version, eversion);
+
+	min_size = sizeof(struct rtk_epatch_header) + sizeof(extension_sig) + 3;
+	if (epatch_fw->size < min_size)
+		return -EINVAL;
+
+	fwptr = epatch_fw->data + epatch_fw->size - sizeof(extension_sig);
+	if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
+		BT_ERR("extension section signature mismatch");
+		return -EINVAL;
+	}
+
+	/* At this point the vendor driver has some confusing and dangerous
+	 * (probably broken) code that parses instructions backwards in a
+	 * loop starting from the end of the file.
+	 * In current firmware, the loop never executes because the instruction
+	 * needed is right at the end of the file.
+	 * For now, check for the same end-of-file data that the vendor driver
+	 * picks up with current firmware.
+	 */
+	opcode = *--fwptr;
+	length = *--fwptr;
+	data = *--fwptr;
+	BT_DBG("final instr op=%x len=%x data=%x", opcode, length, data);
+	if (opcode != 0 || length != 1) {
+		BT_ERR("failed to find version instruction");
+		return -EINVAL;
+	}
+
+	if (lmp_version != project_id[data]) {
+		BT_ERR("firmware is for %x but this is a %x",
+		       project_id[data], lmp_version);
+		return -EINVAL;
+	}
+
+	epatch_info = (struct rtk_epatch_header *) epatch_fw->data;
+	if (memcmp(epatch_info->signature, RTK_EPATCH_SIGNATURE, 8) != 0) {
+		BT_ERR("bad EPATCH signature");
+		return -EINVAL;
+	}
+
+	BT_DBG("fm_version=%x, num_patches=%d",
+	       epatch_info->fm_version, epatch_info->num_patches);
+
+	/* After the rtk_epatch_header there is a funky patch metadata section.
+	 * Assuming 2 patches, the layout is:
+	 * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
+	 *
+	 * Find the right patch for this chip. */
+	min_size += 8 * epatch_info->num_patches;
+	if (epatch_fw->size < min_size)
+		return -EINVAL;
+
+	chip_id_base = epatch_fw->data + sizeof(struct rtk_epatch_header);
+	patch_length_base = chip_id_base +
+			    (sizeof(u16) * epatch_info->num_patches);
+	patch_offset_base = patch_length_base +
+			    (sizeof(u16) * epatch_info->num_patches);
+	for (i = 0; i < epatch_info->num_patches; i++) {
+		u16 chip_id = get_unaligned_le16(chip_id_base +
+						 (i * sizeof(u16)));
+		if (chip_id == eversion + 1) {
+			patch_length = get_unaligned_le16(patch_length_base +
+							  (i * sizeof(u16)));
+			patch_offset = get_unaligned_le32(patch_offset_base +
+							  (i * sizeof(u32)));
+			break;
+		}
+	}
+
+	if (!patch_offset) {
+		BT_ERR("didn't find patch for chip id %d", eversion);
+		return -EINVAL;
+	}
+
+	BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
+	min_size = patch_offset + patch_length;
+	if (epatch_fw->size < min_size)
+		return -EINVAL;
+
+	len = patch_length;
+	if (config_fw)
+		len += config_fw->size;
+
+	buf = kzalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	memcpy(buf, epatch_fw->data + patch_offset, patch_length);
+	tmp = buf + patch_length;
+	memcpy(tmp - 4, &epatch_info->fm_version, 4);
+	if (config_fw)
+		memcpy(tmp, config_fw->data, config_fw->size);
+
+	*_buf = buf;
+	return len;
+}
+
+static int rtk_load_firmware(struct hci_dev *hdev, unsigned char **buf,
+			     const struct rtk_fw_info *fw_info,
+			     uint8_t eversion)
+{
+	struct btusb_data *data = dev_get_drvdata(&hdev->dev);
+	struct usb_device *udev = interface_to_usbdev(data->intf);
+	char fw_name[32];
+	const struct firmware *epatch_fw, *config_fw;
+	int ret;
+
+	snprintf(fw_name, sizeof(fw_name), "rtl_bt/%s.bin",
+		 fw_info->config_name);
+	ret = request_firmware(&config_fw, fw_name, &udev->dev);
+	if (ret < 0) {
+		BT_DBG("optional config blob %s not found", fw_name);
+		config_fw = NULL;
+	}
+
+	snprintf(fw_name, sizeof(fw_name), "rtl_bt/%s.bin",
+		 fw_info->fw_name);
+	ret = request_firmware(&epatch_fw, fw_name, &udev->dev);
+	if (ret < 0) {
+		BT_ERR("fw blob %s not found", fw_name);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (fw_info->lmp_sub == ROM_LMP_8723a)
+		ret = rtk_load_firmware_8723a(epatch_fw, config_fw, buf);
+	else
+		ret = rtk_load_firmware_8723b(fw_info, eversion, epatch_fw,
+					      config_fw, buf);
+
+out:
+	BT_DBG("return %d", ret);
+	release_firmware(config_fw);
+	release_firmware(epatch_fw);
+	return ret;
+}
+
+static bool rtk_fw_upload_needed(struct hci_dev *hdev,
+				 const struct rtk_fw_info *fw_info)
+{
+	struct hci_rp_read_local_version *resp;
+	u16 lmp_version = fw_info->lmp_sub;
+	struct sk_buff *skb;
+
+	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+			     HCI_INIT_TIMEOUT);
+	if (IS_ERR(skb)) {
+		BT_ERR("rtk fw version read command failed (%ld)",
+		       PTR_ERR(skb));
+		return PTR_ERR(skb);
+	}
+
+	if (skb->len != sizeof(*resp)) {
+		BT_ERR("rtk version event length mismatch");
+		kfree_skb(skb);
+		return -EIO;
+	}
+
+	resp = (struct hci_rp_read_local_version *) skb->data;
+	if (resp->status) {
+		BT_ERR("rtk fw version event failed (%02x)", resp->status);
+		kfree_skb(skb);
+		return bt_to_errno(resp->status);
+	}
+
+	BT_INFO("%s: rtk: lmp_subver=%x vs %x, firmware upload %sneeded",
+		hdev->name, resp->lmp_subver, lmp_version,
+		resp->lmp_subver == lmp_version ? "" : "not ");
+
+	/* Firmware upload is only needed when the running version matches the
+	 * one listed in the driver. If versions differ, we assume that no
+	 * firmware update is necessary. */
+	return resp->lmp_subver == lmp_version;
+}
+
+static int btusb_setup_rtk(struct hci_dev *hdev)
+{
+	struct rtk_download_cmd *dl_cmd;
+	unsigned char *fw_blob, *pcur;
+	int frag_num, frag_len;
+	int fw_len, i, eversion;
+	const struct rtk_fw_info *fw_info = rtk_get_fw_info(hdev);
+	int ret = -EIO;
+
+	BT_DBG("variant %lx", fw_info->variant);
+	if (!rtk_fw_upload_needed(hdev, fw_info))
+		return 0;
+
+	eversion = rtk_read_eversion(hdev);
+	if (eversion < 0)
+		return eversion;
+
+	fw_len = rtk_load_firmware(hdev, &fw_blob, fw_info, eversion);
+	if (fw_len < 0)
+		return fw_len;
+
+	pcur = fw_blob;
+	frag_num = fw_len / RTL_FRAG_LEN + 1;
+	frag_len = RTL_FRAG_LEN;
+	dl_cmd = kmalloc(sizeof(struct rtk_download_cmd), GFP_KERNEL);
+	if (!dl_cmd)
+		return -ENOMEM;
+
+	for (i = 0; i < frag_num; i++) {
+		struct rtk_download_response *dl_resp;
+		struct sk_buff *skb;
+
+		BT_DBG("download fw (%d/%d)", i, frag_num);
+		dl_cmd->index = i;
+		if (i == (frag_num - 1)) {
+			dl_cmd->index |= 0x80; /* data end */
+			frag_len = fw_len % RTL_FRAG_LEN;
+		}
+		memcpy(dl_cmd->data, pcur, frag_len);
+
+		/* Send download command */
+		skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
+				     HCI_INIT_TIMEOUT);
+		if (IS_ERR(skb)) {
+			BT_ERR("download fw command failed (%ld)",
+			       PTR_ERR(skb));
+			goto out;
+		}
+
+		if (skb->len != sizeof(*dl_resp)) {
+			BT_ERR("download fw event length mismatch");
+			kfree_skb(skb);
+			goto out;
+		}
+
+		dl_resp = (struct rtk_download_response *) skb->data;
+		if (dl_resp->status != 0) {
+			kfree_skb(skb);
+			goto out;
+		}
+
+		kfree_skb(skb);
+		pcur += RTL_FRAG_LEN;
+	}
+
+	ret = 0;
+
+out:
+	kfree(fw_blob);
+	kfree(dl_cmd);
+	return ret;
+}
+
 static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
 {
 	struct btusb_data *data = hci_get_drvdata(hdev);
@@ -1602,6 +2032,7 @@ static int btusb_probe(struct usb_interface *intf,
 
 	data->udev = interface_to_usbdev(intf);
 	data->intf = intf;
+	data->driver_info = id->driver_info;
 
 	spin_lock_init(&data->lock);
 
@@ -1641,6 +2072,13 @@ static int btusb_probe(struct usb_interface *intf,
 	if (id->driver_info & BTUSB_INTEL)
 		hdev->setup = btusb_setup_intel;
 
+	if (id->driver_info & (BTUSB_RTL8723A | BTUSB_RTL8723B |
+			       BTUSB_RTL8761AU |
+			       BTUSB_RTL8761AW_8192EU |
+			       BTUSB_RTL8761AU_8192EE |
+			       BTUSB_RTL8761AU_8812AE | BTUSB_RTL8821A))
+		hdev->setup = btusb_setup_rtk;
+
 	/* Interface numbers are hardcoded in the specification */
 	data->isoc = usb_ifnum_to_if(data->udev, 1);
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-01 12:47 [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support Daniel Drake
@ 2014-07-01 13:41 ` Marcel Holtmann
  2014-07-01 14:18   ` Daniel Drake
  0 siblings, 1 reply; 18+ messages in thread
From: Marcel Holtmann @ 2014-07-01 13:41 UTC (permalink / raw)
  To: Daniel Drake
  Cc: Gustavo F. Padovan, Johan Hedberg, Linux Bluetooth mailing list,
	Larry.Finger

Hi Daniel,

> Realtek ship a variety of bluetooth USB devices that identify
> themselves with standard USB Bluetooth device class values, but
> require a special driver to actually work. Without that driver,
> you never get any scan results.
> 
> More recently however, Realtek appear to have wisened up and simply
> posted a firmware update that makes these devices comply with
> normal btusb protocols. The firmware needs to be uploaded on each boot.
> 
> Based on Realtek code from https://github.com/lwfinger/rtl8723au_bt
> ('new' branch).
> 
> This enables bluetooth support in the Gigabyte Brix GB-BXBT-2807 which
> has this RTL8723BE USB device:
> 
> T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  3 Spd=12   MxCh= 0
> D:  Ver= 2.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs=  1
> P:  Vendor=13d3 ProdID=3410 Rev= 2.00
> S:  Manufacturer=Realtek
> S:  Product=Bluetooth Radio
> S:  SerialNumber=00e04c000001
> C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
> I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=81(I) Atr=03(Int.) MxPS=  16 Ivl=1ms
> E:  Ad=02(O) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
> I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   0 Ivl=1ms
> I:  If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=03(O) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> E:  Ad=83(I) Atr=01(Isoc) MxPS=   9 Ivl=1ms
> I:  If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  17 Ivl=1ms
> I:  If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  25 Ivl=1ms
> I:  If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  33 Ivl=1ms
> I:  If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
> E:  Ad=03(O) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> E:  Ad=83(I) Atr=01(Isoc) MxPS=  49 Ivl=1ms
> 
> There is no change to the USB descriptor after firmware update,
> however the version read by HCI_OP_READ_LOCAL_VERSION changes from
> 0x8723 to 0x3083.
> 
> Signed-off-by: Daniel Drake <drake@endlessm.com>
> ---
> drivers/bluetooth/btusb.c | 438 ++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 438 insertions(+)
> 
> v2:
> - share main blacklist table with other devices
> - epatch table parsing endian/alignment fixes
> - BT_INFO message to inform user
> - added missing kmalloc error check
> - fixed skb leak
> - style fixes
> 
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index 6250fc2..e6e7c23 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -24,6 +24,7 @@
> #include <linux/module.h>
> #include <linux/usb.h>
> #include <linux/firmware.h>
> +#include <asm/unaligned.h>
> 
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> @@ -50,6 +51,13 @@ static struct usb_driver btusb_driver;
> #define BTUSB_ATH3012		0x80
> #define BTUSB_INTEL		0x100
> #define BTUSB_BCM_PATCHRAM	0x200
> +#define BTUSB_RTL8723A		0x400
> +#define BTUSB_RTL8723B		0x800
> +#define BTUSB_RTL8761AU		0x1000
> +#define BTUSB_RTL8761AW_8192EU	0x2000
> +#define BTUSB_RTL8761AU_8192EE	0x4000
> +#define BTUSB_RTL8761AU_8812AE	0x8000
> +#define BTUSB_RTL8821A		0x10000

I would propose that you add BTUSB_RTK and then or the models into it.

> 
> static const struct usb_device_id btusb_table[] = {
> 	/* Generic Bluetooth USB device */
> @@ -237,6 +245,22 @@ static const struct usb_device_id blacklist_table[] = {
> 	{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
> 	{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
> 
> +	/* Realtek Bluetooth devices */
> +	{ USB_DEVICE(0x0bda, 0xa761), .driver_info = BTUSB_RTL8761AU },
> +	{ USB_DEVICE(0x0bda, 0x8760), .driver_info = BTUSB_RTL8761AU_8192EE },
> +	{ USB_DEVICE(0x0bda, 0xb761), .driver_info = BTUSB_RTL8761AU_8192EE },
> +	{ USB_DEVICE(0x0bda, 0x8761), .driver_info = BTUSB_RTL8761AU_8192EE },
> +	{ USB_DEVICE(0x0bda, 0x8a60), .driver_info = BTUSB_RTL8761AU_8812AE },
> +	{ USB_DEVICE(0x0bda, 0x818b), .driver_info = BTUSB_RTL8761AW_8192EU },
> +	{ USB_DEVICE(0x0bda, 0x0821), .driver_info = BTUSB_RTL8821A },
> +	{ USB_DEVICE(0x0bda, 0x8821), .driver_info = BTUSB_RTL8821A },
> +	{ USB_DEVICE(0x0bda, 0x8723), .driver_info = BTUSB_RTL8723A },
> +	{ USB_DEVICE(0x0bda, 0xb720), .driver_info = BTUSB_RTL8723B },
> +	{ USB_DEVICE(0x0bda, 0xb72a), .driver_info = BTUSB_RTL8723B },
> +	{ USB_DEVICE(0x0bda, 0xb728), .driver_info = BTUSB_RTL8723B },
> +	{ USB_DEVICE(0x0bda, 0xb723), .driver_info = BTUSB_RTL8723B },
> +	{ USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_RTL8723B },

	.driver_info = BTUSB_RTK | BTUSB_RTL...

The think with RTL vs RTK is now confusing me even more. So what are the official model numbers from Realtek anyway. Maybe we should start using them now and not bother carrying around some legacy from the Ethernet or WiFi drivers.

There is also no generic vendor command that we can run first to get the model information? Do we really need to use USB vendor and product ids to pick the right one. I personally hate using vendor and product ids.

> +
> 	{ }	/* Terminating entry */
> };
> 
> @@ -257,6 +281,7 @@ struct btusb_data {
> 	spinlock_t lock;
> 
> 	unsigned long flags;
> +	unsigned long driver_info;
> 
> 	struct work_struct work;
> 	struct work_struct waker;
> @@ -1382,6 +1407,411 @@ exit_mfg_deactivate:
> 	return 0;
> }
> 
> +#define RTL_FRAG_LEN 252
> +
> +struct rtk_download_cmd {
> +	uint8_t index;
> +	uint8_t data[RTL_FRAG_LEN];
> +} __packed;
> +
> +struct rtk_download_response {
> +	uint8_t status;
> +	uint8_t index;
> +} __packed;
> +
> +struct rtk_eversion_evt {
> +	uint8_t status;
> +	uint8_t version;
> +} __packed;
> +
> +struct rtk_epatch_header {
> +	uint8_t signature[8];
> +	uint32_t fm_version;
> +	uint16_t num_patches;
> +} __packed;
> +
> +static const uint8_t RTK_EPATCH_SIGNATURE[] = {
> +	0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68
> +};
> +
> +#define ROM_LMP_8723a	0x1200
> +#define ROM_LMP_8723b	0x8723
> +#define ROM_LMP_8821a	0x8821
> +#define ROM_LMP_8761a	0x8761
> +
> +static const uint16_t project_id[] = {
> +	ROM_LMP_8723a,
> +	ROM_LMP_8723b,
> +	ROM_LMP_8821a,
> +	ROM_LMP_8761a
> +};

Where is this table used now?

> +
> +static const struct rtk_fw_info {
> +	unsigned long variant; /* corresponds to .driver_info */
> +	uint16_t lmp_sub;

Use lmp_subver here so it matches other fields names.

> +	const char *fw_name;
> +	const char *config_name;
> +} rtk_fw_table[] = {
> +	{ BTUSB_RTL8723A, ROM_LMP_8723a, "rtl8723a_fw", "rtl8723a_config" },
> +	{ BTUSB_RTL8723B, ROM_LMP_8723b, "rtl8723b_fw", "rtl8723b_config" },
> +	{ BTUSB_RTL8761AU, ROM_LMP_8761a, "rtl8761au_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8761AW_8192EU, ROM_LMP_8761a, "rtl8761aw8192eu_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8761AU_8192EE, ROM_LMP_8761a, "rtl8761au8192ee_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8761AU_8812AE, ROM_LMP_8761a, "rtl8761au8812ae_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8821A, ROM_LMP_8821a, "rtl8821a_fw", "rtl8821a_config" },
> +};
> +
> +static const struct rtk_fw_info *rtk_get_fw_info(struct hci_dev *hdev)
> +{
> +	struct btusb_data *data = dev_get_drvdata(&hdev->dev);
> +	const struct rtk_fw_info *info;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(rtk_fw_table); i++) {
> +		info = &rtk_fw_table[i];
> +		if (info->variant == data->driver_info)
> +			return info;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int rtk_read_eversion(struct hci_dev *hdev)
> +{
> +	struct rtk_eversion_evt *eversion;
> +	struct sk_buff *skb;
> +	int r;
> +
> +	/* Read RTK ROM version command */
> +	skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
> +	if (IS_ERR(skb)) {
> +		BT_ERR("Read ROM version failed (%ld)", PTR_ERR(skb));
> +		return PTR_ERR(skb);
> +	}
> +
> +	if (skb->len != sizeof(*eversion)) {
> +		BT_ERR("RTK version event length mismatch");
> +		kfree_skb(skb);
> +		return -EIO;
> +	}
> +
> +	eversion = (struct rtk_eversion_evt *) skb->data;
> +	BT_DBG("eversion status=%x version=%x",
> +	       eversion->status, eversion->version);
> +	if (eversion->status)
> +		r = 0;
> +	else
> +		r = eversion->version;
> +
> +	kfree_skb(skb);
> +	return r;
> +}
> +
> +/* RTL8723A has a simple fw patch format */
> +static int rtk_load_firmware_8723a(const struct firmware *epatch_fw,
> +				   const struct firmware *config_fw,
> +				   unsigned char **_buf)
> +{
> +	unsigned char *buf;
> +	int len;
> +
> +	if (epatch_fw->size < 8)
> +		return -EINVAL;
> +
> +	/* This might look odd, but it's how the Realtek driver does it:
> +	 * Make sure we don't match the regular epatch signature. Maybe that
> +	 * signature is only for the newer devices. */
> +	if (memcmp(epatch_fw->data, RTK_EPATCH_SIGNATURE, 8) == 0) {
> +		BT_ERR("8723a has EPATCH signature!");
> +		return -EINVAL;
> +	}
> +
> +	len = epatch_fw->size;
> +	if (config_fw)
> +		len += config_fw->size;
> +
> +	buf = kzalloc(len, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	BT_DBG("8723a direct firmware copy\n");
> +	memcpy(buf, epatch_fw->data, epatch_fw->size);
> +	if (config_fw)
> +		memcpy(buf + epatch_fw->size, config_fw->data, config_fw->size);
> +
> +	*_buf = buf;
> +	return len;
> +}
> +
> +/* RTL8723B and newer have a patch format which requires some parsing */
> +static int rtk_load_firmware_8723b(const struct rtk_fw_info *fw_info,
> +				   uint8_t eversion,
> +				   const struct firmware *epatch_fw,
> +				   const struct firmware *config_fw,
> +				   unsigned char **_buf)
> +{
> +	const uint8_t extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
> +	struct rtk_epatch_header *epatch_info;
> +	u16 lmp_version = fw_info->lmp_sub;
> +	unsigned char *buf;
> +	int i, len;
> +	size_t min_size;
> +	uint8_t opcode, length, data;
> +	unsigned char *tmp;
> +	const unsigned char *fwptr;
> +	const unsigned char *chip_id_base, *patch_length_base, *patch_offset_base;
> +	u32 patch_offset = 0;
> +	u16 patch_length;
> +
> +	BT_DBG("lmp_version=%x eversion=%x", lmp_version, eversion);
> +
> +	min_size = sizeof(struct rtk_epatch_header) + sizeof(extension_sig) + 3;
> +	if (epatch_fw->size < min_size)
> +		return -EINVAL;
> +
> +	fwptr = epatch_fw->data + epatch_fw->size - sizeof(extension_sig);
> +	if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
> +		BT_ERR("extension section signature mismatch");
> +		return -EINVAL;
> +	}
> +
> +	/* At this point the vendor driver has some confusing and dangerous
> +	 * (probably broken) code that parses instructions backwards in a
> +	 * loop starting from the end of the file.
> +	 * In current firmware, the loop never executes because the instruction
> +	 * needed is right at the end of the file.
> +	 * For now, check for the same end-of-file data that the vendor driver
> +	 * picks up with current firmware.
> +	 */
> +	opcode = *--fwptr;
> +	length = *--fwptr;
> +	data = *--fwptr;
> +	BT_DBG("final instr op=%x len=%x data=%x", opcode, length, data);
> +	if (opcode != 0 || length != 1) {
> +		BT_ERR("failed to find version instruction");
> +		return -EINVAL;
> +	}
> +
> +	if (lmp_version != project_id[data]) {
> +		BT_ERR("firmware is for %x but this is a %x",
> +		       project_id[data], lmp_version);
> +		return -EINVAL;
> +	}

So here is the project_id. You need to check for an overrun of that array in case newer devices come along or they change things and not update the VID/PID.

However I get the feeling we have a bunch of these information duplicated. You do know that you can add individual hdev->setup function for each different firmware loading mechanism. They do not need to be all the same. I get the feeling you are trying too hard to push it all into a single entry point.

> +
> +	epatch_info = (struct rtk_epatch_header *) epatch_fw->data;
> +	if (memcmp(epatch_info->signature, RTK_EPATCH_SIGNATURE, 8) != 0) {
> +		BT_ERR("bad EPATCH signature");
> +		return -EINVAL;
> +	}
> +
> +	BT_DBG("fm_version=%x, num_patches=%d",
> +	       epatch_info->fm_version, epatch_info->num_patches);
> +
> +	/* After the rtk_epatch_header there is a funky patch metadata section.
> +	 * Assuming 2 patches, the layout is:
> +	 * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2
> +	 *
> +	 * Find the right patch for this chip. */
> +	min_size += 8 * epatch_info->num_patches;
> +	if (epatch_fw->size < min_size)
> +		return -EINVAL;
> +
> +	chip_id_base = epatch_fw->data + sizeof(struct rtk_epatch_header);
> +	patch_length_base = chip_id_base +
> +			    (sizeof(u16) * epatch_info->num_patches);
> +	patch_offset_base = patch_length_base +
> +			    (sizeof(u16) * epatch_info->num_patches);
> +	for (i = 0; i < epatch_info->num_patches; i++) {
> +		u16 chip_id = get_unaligned_le16(chip_id_base +
> +						 (i * sizeof(u16)));
> +		if (chip_id == eversion + 1) {
> +			patch_length = get_unaligned_le16(patch_length_base +
> +							  (i * sizeof(u16)));
> +			patch_offset = get_unaligned_le32(patch_offset_base +
> +							  (i * sizeof(u32)));
> +			break;
> +		}
> +	}
> +
> +	if (!patch_offset) {
> +		BT_ERR("didn't find patch for chip id %d", eversion);
> +		return -EINVAL;
> +	}
> +
> +	BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
> +	min_size = patch_offset + patch_length;
> +	if (epatch_fw->size < min_size)
> +		return -EINVAL;
> +
> +	len = patch_length;
> +	if (config_fw)
> +		len += config_fw->size;
> +
> +	buf = kzalloc(len, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	memcpy(buf, epatch_fw->data + patch_offset, patch_length);
> +	tmp = buf + patch_length;
> +	memcpy(tmp - 4, &epatch_info->fm_version, 4);
> +	if (config_fw)
> +		memcpy(tmp, config_fw->data, config_fw->size);
> +
> +	*_buf = buf;
> +	return len;
> +}
> +
> +static int rtk_load_firmware(struct hci_dev *hdev, unsigned char **buf,
> +			     const struct rtk_fw_info *fw_info,
> +			     uint8_t eversion)
> +{
> +	struct btusb_data *data = dev_get_drvdata(&hdev->dev);
> +	struct usb_device *udev = interface_to_usbdev(data->intf);
> +	char fw_name[32];
> +	const struct firmware *epatch_fw, *config_fw;
> +	int ret;
> +
> +	snprintf(fw_name, sizeof(fw_name), "rtl_bt/%s.bin",
> +		 fw_info->config_name);
> +	ret = request_firmware(&config_fw, fw_name, &udev->dev);
> +	if (ret < 0) {
> +		BT_DBG("optional config blob %s not found", fw_name);
> +		config_fw = NULL;
> +	}
> +
> +	snprintf(fw_name, sizeof(fw_name), "rtl_bt/%s.bin",
> +		 fw_info->fw_name);
> +	ret = request_firmware(&epatch_fw, fw_name, &udev->dev);
> +	if (ret < 0) {
> +		BT_ERR("fw blob %s not found", fw_name);
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +	if (fw_info->lmp_sub == ROM_LMP_8723a)
> +		ret = rtk_load_firmware_8723a(epatch_fw, config_fw, buf);
> +	else
> +		ret = rtk_load_firmware_8723b(fw_info, eversion, epatch_fw,
> +					      config_fw, buf);
> +
> +out:
> +	BT_DBG("return %d", ret);
> +	release_firmware(config_fw);
> +	release_firmware(epatch_fw);
> +	return ret;
> +}
> +
> +static bool rtk_fw_upload_needed(struct hci_dev *hdev,
> +				 const struct rtk_fw_info *fw_info)
> +{
> +	struct hci_rp_read_local_version *resp;
> +	u16 lmp_version = fw_info->lmp_sub;
> +	struct sk_buff *skb;
> +
> +	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
> +			     HCI_INIT_TIMEOUT);
> +	if (IS_ERR(skb)) {
> +		BT_ERR("rtk fw version read command failed (%ld)",
> +		       PTR_ERR(skb));
> +		return PTR_ERR(skb);
> +	}
> +
> +	if (skb->len != sizeof(*resp)) {
> +		BT_ERR("rtk version event length mismatch");
> +		kfree_skb(skb);
> +		return -EIO;
> +	}
> +
> +	resp = (struct hci_rp_read_local_version *) skb->data;
> +	if (resp->status) {
> +		BT_ERR("rtk fw version event failed (%02x)", resp->status);
> +		kfree_skb(skb);
> +		return bt_to_errno(resp->status);
> +	}
> +
> +	BT_INFO("%s: rtk: lmp_subver=%x vs %x, firmware upload %sneeded",
> +		hdev->name, resp->lmp_subver, lmp_version,
> +		resp->lmp_subver == lmp_version ? "" : "not ");
> +
> +	/* Firmware upload is only needed when the running version matches the
> +	 * one listed in the driver. If versions differ, we assume that no
> +	 * firmware update is necessary. */
> +	return resp->lmp_subver == lmp_version;
> +}
> +
> +static int btusb_setup_rtk(struct hci_dev *hdev)
> +{
> +	struct rtk_download_cmd *dl_cmd;
> +	unsigned char *fw_blob, *pcur;
> +	int frag_num, frag_len;
> +	int fw_len, i, eversion;
> +	const struct rtk_fw_info *fw_info = rtk_get_fw_info(hdev);
> +	int ret = -EIO;
> +
> +	BT_DBG("variant %lx", fw_info->variant);
> +	if (!rtk_fw_upload_needed(hdev, fw_info))
> +		return 0;
> +
> +	eversion = rtk_read_eversion(hdev);
> +	if (eversion < 0)
> +		return eversion;
> +
> +	fw_len = rtk_load_firmware(hdev, &fw_blob, fw_info, eversion);
> +	if (fw_len < 0)
> +		return fw_len;
> +
> +	pcur = fw_blob;
> +	frag_num = fw_len / RTL_FRAG_LEN + 1;
> +	frag_len = RTL_FRAG_LEN;
> +	dl_cmd = kmalloc(sizeof(struct rtk_download_cmd), GFP_KERNEL);
> +	if (!dl_cmd)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < frag_num; i++) {
> +		struct rtk_download_response *dl_resp;
> +		struct sk_buff *skb;
> +
> +		BT_DBG("download fw (%d/%d)", i, frag_num);
> +		dl_cmd->index = i;
> +		if (i == (frag_num - 1)) {
> +			dl_cmd->index |= 0x80; /* data end */
> +			frag_len = fw_len % RTL_FRAG_LEN;
> +		}
> +		memcpy(dl_cmd->data, pcur, frag_len);
> +
> +		/* Send download command */
> +		skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd,
> +				     HCI_INIT_TIMEOUT);
> +		if (IS_ERR(skb)) {
> +			BT_ERR("download fw command failed (%ld)",
> +			       PTR_ERR(skb));
> +			goto out;
> +		}
> +
> +		if (skb->len != sizeof(*dl_resp)) {
> +			BT_ERR("download fw event length mismatch");
> +			kfree_skb(skb);
> +			goto out;
> +		}
> +
> +		dl_resp = (struct rtk_download_response *) skb->data;
> +		if (dl_resp->status != 0) {
> +			kfree_skb(skb);
> +			goto out;
> +		}
> +
> +		kfree_skb(skb);
> +		pcur += RTL_FRAG_LEN;
> +	}
> +
> +	ret = 0;
> +
> +out:
> +	kfree(fw_blob);
> +	kfree(dl_cmd);
> +	return ret;
> +}
> +
> static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
> {
> 	struct btusb_data *data = hci_get_drvdata(hdev);
> @@ -1602,6 +2032,7 @@ static int btusb_probe(struct usb_interface *intf,
> 
> 	data->udev = interface_to_usbdev(intf);
> 	data->intf = intf;
> +	data->driver_info = id->driver_info;

Why is this one needed?

> 
> 	spin_lock_init(&data->lock);
> 
> @@ -1641,6 +2072,13 @@ static int btusb_probe(struct usb_interface *intf,
> 	if (id->driver_info & BTUSB_INTEL)
> 		hdev->setup = btusb_setup_intel;
> 
> +	if (id->driver_info & (BTUSB_RTL8723A | BTUSB_RTL8723B |
> +			       BTUSB_RTL8761AU |
> +			       BTUSB_RTL8761AW_8192EU |
> +			       BTUSB_RTL8761AU_8192EE |
> +			       BTUSB_RTL8761AU_8812AE | BTUSB_RTL8821A))
> +		hdev->setup = btusb_setup_rtk;
> +

	if (id->driver_info & BTUSB_RTK)
		hdev->setup = btusb_setup_rtk;

Or something like this:

	if (id->driver_info & BTUSB_RTK_ABC)
		hdev->setup = btusb_setup_rtk_abc;

	if (id->driver_info & BTUSB_RTK_XYZ)
		hdev->setup = btusb_setup_rtk_xyz;


> 	/* Interface numbers are hardcoded in the specification */
> 	data->isoc = usb_ifnum_to_if(data->udev, 1);

Regards

Marcel


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-01 13:41 ` Marcel Holtmann
@ 2014-07-01 14:18   ` Daniel Drake
  2014-07-01 15:18     ` Larry Finger
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Drake @ 2014-07-01 14:18 UTC (permalink / raw)
  To: Marcel Holtmann, Larry.Finger
  Cc: Gustavo F. Padovan, Johan Hedberg, Linux Bluetooth mailing list

On Tue, Jul 1, 2014 at 2:41 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
>         .driver_info = BTUSB_RTK | BTUSB_RTL...
>
> The think with RTL vs RTK is now confusing me even more. So what are the official model numbers from Realtek anyway. Maybe we should start using them now and not bother carrying around some legacy from the Ethernet or WiFi drivers.

The product codes are RTLxxxx so perhaps I will update it to use 'rtl'
instead of 'rtk' everywhere. That 'rtk' just came from the vendor
driver. Maybe Larry has some knowledge of the conventions here.

> There is also no generic vendor command that we can run first to get the model information? Do we really need to use USB vendor and product ids to pick the right one. I personally hate using vendor and product ids.

I'm no expert on this hardware, just happened to receive one instance,
and then found the vendor driver on Larry's github. The vendor driver
uses USB IDs for this purpose, and I don't have any extra insight (nor
access to other devices).

However, I just noticed that we only have 2 of the 7 main firmware
files available. Larry, do you have all of the ones mentioned in the
driver? e.g. ones like rtl8761aw8192eu_fw are missing from your repo.

Googling around, it looks like these other devices are really not
common, maybe we should just reduce it to RTL8723A and RTL8723B
support, especially if we don't have firmware for the others. There is
only 1 type of firmware for each variant there, the code would be
simpler, no need for VID/PID lookup. That would be enough to make me
happy, plus all the people filing issues on Larry's github.

Only caveat there is that someone might push us to return to the
RTL8761 mess (different firmware for different VID/PID) some day.

Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-01 14:18   ` Daniel Drake
@ 2014-07-01 15:18     ` Larry Finger
  2014-07-01 15:27       ` Marcel Holtmann
  0 siblings, 1 reply; 18+ messages in thread
From: Larry Finger @ 2014-07-01 15:18 UTC (permalink / raw)
  To: Daniel Drake
  Cc: Marcel Holtmann, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list, champion

On 07/01/2014 09:18 AM, Daniel Drake wrote:
> On Tue, Jul 1, 2014 at 2:41 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
>>          .driver_info = BTUSB_RTK | BTUSB_RTL...
>>
>> The think with RTL vs RTK is now confusing me even more. So what are the official model numbers from Realtek anyway. Maybe we should start using them now and not bother carrying around some legacy from the Ethernet or WiFi drivers.
>
> The product codes are RTLxxxx so perhaps I will update it to use 'rtl'
> instead of 'rtk' everywhere. That 'rtk' just came from the vendor
> driver. Maybe Larry has some knowledge of the conventions here.

The Realtek drivers for wifi devices all use "rtl" as the abbreviation. As I had 
not made many changes to the vendor-supplied driver for BT, I had not worried 
about such details; however, I do think that "rtl" should be used here.

>> There is also no generic vendor command that we can run first to get the model information? Do we really need to use USB vendor and product ids to pick the right one. I personally hate using vendor and product ids.
>
> I'm no expert on this hardware, just happened to receive one instance,
> and then found the vendor driver on Larry's github. The vendor driver
> uses USB IDs for this purpose, and I don't have any extra insight (nor
> access to other devices).

All I know about this issue is that the unmodified btusb will load when one  one 
of the Realtek BT devices is present, thus there is some generic recognition. 
The driver should should be able to use that; however, it will still need to be 
able to differentiate among the various Realtek devices. My vote is to keep the 
USB ID information.

> However, I just noticed that we only have 2 of the 7 main firmware
> files available. Larry, do you have all of the ones mentioned in the
> driver? e.g. ones like rtl8761aw8192eu_fw are missing from your repo.
>
> Googling around, it looks like these other devices are really not
> common, maybe we should just reduce it to RTL8723A and RTL8723B
> support, especially if we don't have firmware for the others. There is
> only 1 type of firmware for each variant there, the code would be
> simpler, no need for VID/PID lookup. That would be enough to make me
> happy, plus all the people filing issues on Larry's github.

Looking at the firmware table,

+} rtk_fw_table[] = {
+	{ BTUSB_RTL8723A, ROM_LMP_8723a, "rtl8723a_fw", "rtl8723a_config" },
+	{ BTUSB_RTL8723B, ROM_LMP_8723b, "rtl8723b_fw", "rtl8723b_config" },
+	{ BTUSB_RTL8761AU, ROM_LMP_8761a, "rtl8761au_fw", "rtl8761a_config" },
+	{ BTUSB_RTL8761AW_8192EU, ROM_LMP_8761a, "rtl8761aw8192eu_fw", 
"rtl8761a_config" },
+	{ BTUSB_RTL8761AU_8192EE, ROM_LMP_8761a, "rtl8761au8192ee_fw", 
"rtl8761a_config" },
+	{ BTUSB_RTL8761AU_8812AE, ROM_LMP_8761a, "rtl8761au8812ae_fw", 
"rtl8761a_config" },
+	{ BTUSB_RTL8821A, ROM_LMP_8821a, "rtl8821a_fw", "rtl8821a_config" },
+};

The RTL8812AE, RTL8821AE, and RTL8192EE devices are not that rare. The wifi 
drivers for those devices have been added in the last couple of kernel cycles. I 
will be contacting Realtek to get copies of those firmware files. I do not know 
about the RTL8192EU or the RTL8761AU. I have not run across those USB devices yet.

BTW, I added my contact at Realtek to the Cc list.

> Only caveat there is that someone might push us to return to the
> RTL8761 mess (different firmware for different VID/PID) some day.

I am certain that Realtek separated these devices for a reason, which is why I 
favor keeping VID/PID.

Please do not be hasty in posting new versions. You had V2 in my mailbox before 
I had even gotten a chance to see V1. Remember that we live in different time zones.

Larry

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-01 15:18     ` Larry Finger
@ 2014-07-01 15:27       ` Marcel Holtmann
  2014-07-03  9:28         ` 答复: " 陈艳萍
  0 siblings, 1 reply; 18+ messages in thread
From: Marcel Holtmann @ 2014-07-01 15:27 UTC (permalink / raw)
  To: Larry Finger
  Cc: Daniel Drake, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list, champion

Hi Larry,

>>>         .driver_info = BTUSB_RTK | BTUSB_RTL...
>>> 
>>> The think with RTL vs RTK is now confusing me even more. So what are the official model numbers from Realtek anyway. Maybe we should start using them now and not bother carrying around some legacy from the Ethernet or WiFi drivers.
>> 
>> The product codes are RTLxxxx so perhaps I will update it to use 'rtl'
>> instead of 'rtk' everywhere. That 'rtk' just came from the vendor
>> driver. Maybe Larry has some knowledge of the conventions here.
> 
> The Realtek drivers for wifi devices all use "rtl" as the abbreviation. As I had not made many changes to the vendor-supplied driver for BT, I had not worried about such details; however, I do think that "rtl" should be used here.

that is fine with me as well. Lets just use "rtl" in the driver.

>>> There is also no generic vendor command that we can run first to get the model information? Do we really need to use USB vendor and product ids to pick the right one. I personally hate using vendor and product ids.
>> 
>> I'm no expert on this hardware, just happened to receive one instance,
>> and then found the vendor driver on Larry's github. The vendor driver
>> uses USB IDs for this purpose, and I don't have any extra insight (nor
>> access to other devices).
> 
> All I know about this issue is that the unmodified btusb will load when one  one of the Realtek BT devices is present, thus there is some generic recognition. The driver should should be able to use that; however, it will still need to be able to differentiate among the various Realtek devices. My vote is to keep the USB ID information.

The generic recognition is done on the interface level.

I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb

Bluetooth USB devices have a standard class descriptor for this. We allow for a setup stage that will be executed during initialization of the device. So that all works nicely. You just have to assign the right setup callback for this.

>> However, I just noticed that we only have 2 of the 7 main firmware
>> files available. Larry, do you have all of the ones mentioned in the
>> driver? e.g. ones like rtl8761aw8192eu_fw are missing from your repo.
>> 
>> Googling around, it looks like these other devices are really not
>> common, maybe we should just reduce it to RTL8723A and RTL8723B
>> support, especially if we don't have firmware for the others. There is
>> only 1 type of firmware for each variant there, the code would be
>> simpler, no need for VID/PID lookup. That would be enough to make me
>> happy, plus all the people filing issues on Larry's github.
> 
> Looking at the firmware table,
> 
> +} rtk_fw_table[] = {
> +	{ BTUSB_RTL8723A, ROM_LMP_8723a, "rtl8723a_fw", "rtl8723a_config" },
> +	{ BTUSB_RTL8723B, ROM_LMP_8723b, "rtl8723b_fw", "rtl8723b_config" },
> +	{ BTUSB_RTL8761AU, ROM_LMP_8761a, "rtl8761au_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8761AW_8192EU, ROM_LMP_8761a, "rtl8761aw8192eu_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8761AU_8192EE, ROM_LMP_8761a, "rtl8761au8192ee_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8761AU_8812AE, ROM_LMP_8761a, "rtl8761au8812ae_fw", "rtl8761a_config" },
> +	{ BTUSB_RTL8821A, ROM_LMP_8821a, "rtl8821a_fw", "rtl8821a_config" },
> +};
> 
> The RTL8812AE, RTL8821AE, and RTL8192EE devices are not that rare. The wifi drivers for those devices have been added in the last couple of kernel cycles. I will be contacting Realtek to get copies of those firmware files. I do not know about the RTL8192EU or the RTL8761AU. I have not run across those USB devices yet.
> 
> BTW, I added my contact at Realtek to the Cc list.

Can someone please send a copy (private if needed) of the Realtek vendor specific commands. I like to read through that one and see what we can do make this smooth.

>> Only caveat there is that someone might push us to return to the
>> RTL8761 mess (different firmware for different VID/PID) some day.
> 
> I am certain that Realtek separated these devices for a reason, which is why I favor keeping VID/PID.
> 
> Please do not be hasty in posting new versions. You had V2 in my mailbox before I had even gotten a chance to see V1. Remember that we live in different time zones.

We can even keep different setup callbacks for different models, but I first need to understand what the difference are. However I am all for the case that we do not have the firmware, we do not bother supporting it. Firmware should be in linux-firmware for all supported hardware.

Regards

Marcel


^ permalink raw reply	[flat|nested] 18+ messages in thread

* 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-01 15:27       ` Marcel Holtmann
@ 2014-07-03  9:28         ` 陈艳萍
  2014-07-03 18:12           ` Marcel Holtmann
  0 siblings, 1 reply; 18+ messages in thread
From: 陈艳萍 @ 2014-07-03  9:28 UTC (permalink / raw)
  To: Marcel Holtmann, Larry Finger
  Cc: Daniel Drake, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list


[-- Attachment #1.1: Type: text/plain, Size: 6202 bytes --]

Hi Larry,

1.  RTL vs RTK , it is ok to use "rtl " to comply with wifi drivers



2. firmware table, when module is powered on the default LMP versions are different. After download firmware ,the LMP version will change to firmware version.

[cid:image003.jpg@01CF96E4.434048B0]
module

LMP Subversion

HCI Revision

RTL8723A

0X1200

0X000B

RTL8723B

0X8723

0X000B

RTL8761A

0X8761

0X000A

RTL8821A

0X8821

0X000A


8723A/8723B/8821A are combo modules both with wifi and Bluetooth;
8761A is Bluetooth only chip, but can be used to with wifi 8812/8192, and will use different bluetooth firmware for each combination.
This can only be distinguished by pids.
I think it is OK to only support 8723A &8723B and leave others for next time driver update.


2.     I read the codes in kernel 3.13 , some companies such as Intel add setup function for their modules in general btusb driver ;  while some provide another driver and set BTUSB_IGNORE in btusb_probe, how can it work for their private driver only download firmware and do not call any functions of bluez hci layer ?







Champion

Ext:6325





-----邮件原件-----
发件人: Marcel Holtmann [mailto:marcel@holtmann.org]
发送时间: 2014年7月1日 23:27
收件人: Larry Finger
抄送: Daniel Drake; Gustavo F. Padovan; Johan Hedberg; Linux Bluetooth mailing list; 陈艳萍
主题: Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support



Hi Larry,



>>>         .driver_info = BTUSB_RTK | BTUSB_RTL...

>>>

>>> The think with RTL vs RTK is now confusing me even more. So what are the official model numbers from Realtek anyway. Maybe we should start using them now and not bother carrying around some legacy from the Ethernet or WiFi drivers.

>>

>> The product codes are RTLxxxx so perhaps I will update it to use 'rtl'

>> instead of 'rtk' everywhere. That 'rtk' just came from the vendor

>> driver. Maybe Larry has some knowledge of the conventions here.

>

> The Realtek drivers for wifi devices all use "rtl" as the abbreviation. As I had not made many changes to the vendor-supplied driver for BT, I had not worried about such details; however, I do think that "rtl" should be used here.



that is fine with me as well. Lets just use "rtl" in the driver.



>>> There is also no generic vendor command that we can run first to get the model information? Do we really need to use USB vendor and product ids to pick the right one. I personally hate using vendor and product ids.

>>

>> I'm no expert on this hardware, just happened to receive one

>> instance, and then found the vendor driver on Larry's github. The

>> vendor driver uses USB IDs for this purpose, and I don't have any

>> extra insight (nor access to other devices).

>

> All I know about this issue is that the unmodified btusb will load when one  one of the Realtek BT devices is present, thus there is some generic recognition. The driver should should be able to use that; however, it will still need to be able to differentiate among the various Realtek devices. My vote is to keep the USB ID information.



The generic recognition is done on the interface level.



I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb



Bluetooth USB devices have a standard class descriptor for this. We allow for a setup stage that will be executed during initialization of the device. So that all works nicely. You just have to assign the right setup callback for this.



>> However, I just noticed that we only have 2 of the 7 main firmware

>> files available. Larry, do you have all of the ones mentioned in the

>> driver? e.g. ones like rtl8761aw8192eu_fw are missing from your repo.

>>

>> Googling around, it looks like these other devices are really not

>> common, maybe we should just reduce it to RTL8723A and RTL8723B

>> support, especially if we don't have firmware for the others. There

>> is only 1 type of firmware for each variant there, the code would be

>> simpler, no need for VID/PID lookup. That would be enough to make me

>> happy, plus all the people filing issues on Larry's github.

>

> Looking at the firmware table,

>

> +} rtk_fw_table[] = {

> +   { BTUSB_RTL8723A, ROM_LMP_8723a, "rtl8723a_fw", "rtl8723a_config" },

> +   { BTUSB_RTL8723B, ROM_LMP_8723b, "rtl8723b_fw", "rtl8723b_config" },

> +   { BTUSB_RTL8761AU, ROM_LMP_8761a, "rtl8761au_fw", "rtl8761a_config" },

> +   { BTUSB_RTL8761AW_8192EU, ROM_LMP_8761a, "rtl8761aw8192eu_fw", "rtl8761a_config" },

> +   { BTUSB_RTL8761AU_8192EE, ROM_LMP_8761a, "rtl8761au8192ee_fw", "rtl8761a_config" },

> +   { BTUSB_RTL8761AU_8812AE, ROM_LMP_8761a, "rtl8761au8812ae_fw", "rtl8761a_config" },

> +   { BTUSB_RTL8821A, ROM_LMP_8821a, "rtl8821a_fw", "rtl8821a_config" },

> +};

>

> The RTL8812AE, RTL8821AE, and RTL8192EE devices are not that rare. The wifi drivers for those devices have been added in the last couple of kernel cycles. I will be contacting Realtek to get copies of those firmware files. I do not know about the RTL8192EU or the RTL8761AU. I have not run across those USB devices yet.

>

> BTW, I added my contact at Realtek to the Cc list.



Can someone please send a copy (private if needed) of the Realtek vendor specific commands. I like to read through that one and see what we can do make this smooth.



>> Only caveat there is that someone might push us to return to the

>> RTL8761 mess (different firmware for different VID/PID) some day.

>

> I am certain that Realtek separated these devices for a reason, which is why I favor keeping VID/PID.

>

> Please do not be hasty in posting new versions. You had V2 in my mailbox before I had even gotten a chance to see V1. Remember that we live in different time zones.



We can even keep different setup callbacks for different models, but I first need to understand what the difference are. However I am all for the case that we do not have the firmware, we do not bother supporting it. Firmware should be in linux-firmware for all supported hardware.



Regards



Marcel



[-- Attachment #1.2: Type: text/html, Size: 28987 bytes --]

[-- Attachment #2: image003.jpg --]
[-- Type: image/jpeg, Size: 12169 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-03  9:28         ` 答复: " 陈艳萍
@ 2014-07-03 18:12           ` Marcel Holtmann
  2014-07-04 10:11             ` 答复: " 陈艳萍
  0 siblings, 1 reply; 18+ messages in thread
From: Marcel Holtmann @ 2014-07-03 18:12 UTC (permalink / raw)
  To: 陈艳萍
  Cc: Larry Finger, Daniel Drake, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list

[-- Attachment #1: Type: text/plain, Size: 3105 bytes --]

Hi Champion,

> 1.  RTL vs RTK , it is ok to use "rtl " to comply with wifi drivers

lets be consistent and keep using rtl.
 
> 2. firmware table, when module is powered on the default LMP versions are different. After download firmware ,the LMP version will change to firmware version.
> <image003.jpg> 
> module
> LMP Subversion
> HCI Revision
> RTL8723A
> 0X1200
> 0X000B
> RTL8723B
> 0X8723
> 0X000B
> RTL8761A
> 0X8761
> 0X000A
> RTL8821A
> 0X8821
> 0X000A
>  
> 8723A/8723B/8821A are combo modules both with wifi and Bluetooth;
> 8761A is Bluetooth only chip, but can be used to with wifi 8812/8192, and will use different bluetooth firmware for each combination.
> This can only be distinguished by pids.
> I think it is OK to only support 8723A &8723B and leave others for next time driver update.

Can you share the Realtek HCI Vendor Command specification with me privately. The command above is Bluetooth standard, but we are also having at least the baud rate change for UART based controllers and the ROM version command. We most likely also need a vendor command to set the BD_ADDR in case it is not configured or an OEM wants to change it.

I also like to know what is the right procedure for loading the ROM patches and/or settings. Getting this nicely documented would be of great benefit. We have the Intel and Broadcom procedures nicely documented inside the code.
 
> 2.     I read the codes in kernel 3.13 , some companies such as Intel add setup function for their modules in general btusb driver ;  while some provide another driver and set BTUSB_IGNORE in btusb_probe, how can it work for their private driver only download firmware and do not call any functions of bluez hci layer ?

There are two ways current silicon vendors have done. Either have a special USB VID/PID or descriptors, attach the firmware loading driver and load the firmware. The device disconnects from USB and re-connects with its new identity. And then btusb driver takes over.

The second method is doing the setup stage all in the driver. So the Bluetooth core is actually providing a running transport that is driven by the transport driver (in this case btusb), but before it takes control it allows the driver to issue certain HCI commands. This is mostly used for firmware loading. You can see that for Intel and Broadcom.

If your firmware loading, setup, patching or whatever is done with HCI commands, you should go the setup callback broke since that way you do not have to deal with transport details. It will just work. If you speak a non-HCI protocol, then the method with a separate firmware loading driver is beneficial.

For Realtek it seems the setup stage like what we do with Intel and Broadcom silicon is exactly what you want.

Can you provide a list of USB/PID that match to modules which require the firmware loading or optionally support the firmware loading. That would make it easier to populate the matching table. The decision on the module can be easily done by reading the HCI Local Version Information first.

Regards

Marcel


[-- Attachment #2: Type: text/html, Size: 12962 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-03 18:12           ` Marcel Holtmann
@ 2014-07-04 10:11             ` 陈艳萍
  2014-07-08  7:57               ` Daniel Drake
  0 siblings, 1 reply; 18+ messages in thread
From: 陈艳萍 @ 2014-07-04 10:11 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Larry Finger, Daniel Drake, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list


[-- Attachment #1.1: Type: text/plain, Size: 3564 bytes --]

Hi Marcel,
         Attached file includes vendor commands of realtek Bluetooth modules in initialize procedure.
And btusb is example of add rtl setup callbacks (not finished)



Champion
Ext:6325

发件人: Marcel Holtmann [mailto:marcel@holtmann.org]
发送时间: 2014年7月4日 2:12
收件人: 陈艳萍
抄送: Larry Finger; Daniel Drake; Gustavo F. Padovan; Johan Hedberg; Linux Bluetooth mailing list
主题: Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support

Hi Champion,


1.  RTL vs RTK , it is ok to use "rtl " to comply with wifi drivers

lets be consistent and keep using rtl.


2. firmware table, when module is powered on the default LMP versions are different. After download firmware ,the LMP version will change to firmware version.
<image003.jpg>
module

LMP Subversion

HCI Revision

RTL8723A

0X1200

0X000B

RTL8723B

0X8723

0X000B

RTL8761A

0X8761

0X000A

RTL8821A

0X8821

0X000A


8723A/8723B/8821A are combo modules both with wifi and Bluetooth;
8761A is Bluetooth only chip, but can be used to with wifi 8812/8192, and will use different bluetooth firmware for each combination.
This can only be distinguished by pids.
I think it is OK to only support 8723A &8723B and leave others for next time driver update.

Can you share the Realtek HCI Vendor Command specification with me privately. The command above is Bluetooth standard, but we are also having at least the baud rate change for UART based controllers and the ROM version command. We most likely also need a vendor command to set the BD_ADDR in case it is not configured or an OEM wants to change it.

I also like to know what is the right procedure for loading the ROM patches and/or settings. Getting this nicely documented would be of great benefit. We have the Intel and Broadcom procedures nicely documented inside the code.

2.     I read the codes in kernel 3.13 , some companies such as Intel add setup function for their modules in general btusb driver ;  while some provide another driver and set BTUSB_IGNORE in btusb_probe, how can it work for their private driver only download firmware and do not call any functions of bluez hci layer ?

There are two ways current silicon vendors have done. Either have a special USB VID/PID or descriptors, attach the firmware loading driver and load the firmware. The device disconnects from USB and re-connects with its new identity. And then btusb driver takes over.

The second method is doing the setup stage all in the driver. So the Bluetooth core is actually providing a running transport that is driven by the transport driver (in this case btusb), but before it takes control it allows the driver to issue certain HCI commands. This is mostly used for firmware loading. You can see that for Intel and Broadcom.

If your firmware loading, setup, patching or whatever is done with HCI commands, you should go the setup callback broke since that way you do not have to deal with transport details. It will just work. If you speak a non-HCI protocol, then the method with a separate firmware loading driver is beneficial.

For Realtek it seems the setup stage like what we do with Intel and Broadcom silicon is exactly what you want.

Can you provide a list of USB/PID that match to modules which require the firmware loading or optionally support the firmware loading. That would make it easier to populate the matching table. The decision on the module can be easily done by reading the HCI Local Version Information first.

Regards

Marcel


[-- Attachment #1.2: Type: text/html, Size: 17451 bytes --]

[-- Attachment #2: btusb.c --]
[-- Type: text/plain, Size: 54716 bytes --]

/*
 *
 *  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/firmware.h>

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

#define VERSION "0.6"

static bool ignore_dga;
static bool ignore_csr;
static bool ignore_sniffer;
static bool disable_scofix;
static bool force_scofix;

static bool reset = 1;

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_RTL			0x200

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

	/* Apple-specific (Broadcom) devices */
	{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },

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

	/* 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(0x0b05, 0x17b5) },
	{ USB_DEVICE(0x0b05, 0x17cb) },
	{ USB_DEVICE(0x04ca, 0x2003) },
	{ USB_DEVICE(0x0489, 0xe042) },
	{ USB_DEVICE(0x413c, 0x8197) },

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

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

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

	/* Realtek bluetooth -generic modules*/
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01) },

	/* Realtek bluetooth -with vendor specific id*/
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0bd5, 0xe0, 0x01, 0x01) },

	/* Realtek bluetooth -with vendor specific id*/
	{ USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xe0, 0x01, 0x01) },

	/* Realtek bluetooth -with vendor specific id*/
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xe0, 0x01, 0x01) },
	

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

	/* Atheros 3011 with sflash firmware */
	{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
	{ USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE },
	{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
	{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
	{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
	{ USB_DEVICE(0x0489, 0xe027), .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(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, 0x817a), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x13d3, 0x3375), .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, 0x3008), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0cf3, 0xe003), .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, 0xe03c), .driver_info = BTUSB_ATH3012 },
	{ USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 },

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

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

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

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

	/* Intel Bluetooth device */
	{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },

	/* Realtek Bluetooth device */
	/*8723AE*/
	{ USB_DEVICE(0x0723, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x8723, 0x0bda), .driver_info = BTUSB_RTL }, 	
	{ USB_DEVICE(0x021d, 0x0930), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x3394, 0x13d3), .driver_info = BTUSB_RTL },
	/*8723AS_VAU*/	
	{ USB_DEVICE(0x0724, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x1724, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xa724, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x8725, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x872a, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x872b, 0x0bda), .driver_info = BTUSB_RTL },	
	/*8723BE*/
	{ USB_DEVICE(0xb728, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xb723, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xb72B, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xb001, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xb002, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xb003, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xb004, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xb005, 0x0bda), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x3410, 0x13d3), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x3416, 0x13d3), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0x3459, 0x13d3), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xe085, 0x0489), .driver_info = BTUSB_RTL },
	{ USB_DEVICE(0xe08b, 0x0489), .driver_info = BTUSB_RTL },
	/*8723BU*/
	{ USB_DEVICE(0xb720, 0x0bda), .driver_info = BTUSB_RTL},
	{ USB_DEVICE(0xb72a, 0x0bda), .driver_info = BTUSB_RTL},
	/*8821AE*/	
	{ USB_DEVICE(0x0821, 0x0bda), .driver_info = BTUSB_RTL},	
	{ USB_DEVICE(0x8821, 0x0bda), .driver_info = BTUSB_RTL},	
	{ USB_DEVICE(0x3414, 0x13d3), .driver_info = BTUSB_RTL},
	{ USB_DEVICE(0x3458, 0x13d3), .driver_info = BTUSB_RTL},
	{ USB_DEVICE(0x3461, 0x13d3), .driver_info = BTUSB_RTL},
	{ USB_DEVICE(0x3462, 0x13d3), .driver_info = BTUSB_RTL},	
	{ USB_DEVICE(0x17dc, 0x0b05), .driver_info = BTUSB_RTL},	
	/*8821AU*/
	{ USB_DEVICE(0x0823, 0x0bda), .driver_info = BTUSB_RTL},
	/*8761AU*/
	{ USB_DEVICE(0xA761, 0x0bda), .driver_info = BTUSB_RTL},

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

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

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

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 (hci_recv_fragment(hdev, HCI_EVENT_PKT,
						urb->transfer_buffer,
						urb->actual_length) < 0) {
			BT_ERR("%s corrupted event packet", hdev->name);
			hdev->stat.err_rx++;
		}
	}

	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 (hci_recv_fragment(hdev, HCI_ACLDATA_PKT,
						urb->transfer_buffer,
						urb->actual_length) < 0) {
			BT_ERR("%s corrupted ACL packet", hdev->name);
			hdev->stat.err_rx++;
		}
	}

	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 (hci_recv_fragment(hdev, HCI_SCODATA_PKT,
						urb->transfer_buffer + offset,
								length) < 0) {
				BT_ERR("%s corrupted SCO packet", hdev->name);
				hdev->stat.err_rx++;
			}
		}
	}

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

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

	data->intf->needs_remote_wakeup = 1;

	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) {
		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);
	return 0;

failed:
	clear_bit(BTUSB_INTR_RUNNING, &data->flags);
	clear_bit(HCI_RUNNING, &hdev->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);
}

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

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

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

	return 0;
}

static int btusb_send_frame(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;
	int err;

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

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

	skb->dev = (void *) hdev;

	switch (bt_cb(skb)->pkt_type) {
	case HCI_COMMAND_PKT:
		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:
		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:
		if (!data->isoc_tx_ep || hci_conn_num(hdev, SCO_LINK) < 1)
			return -ENODEV;

		urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_ATOMIC);
		if (!urb)
			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);

	err = usb_submit_urb(urb, GFP_ATOMIC);
	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);
	}

done:
	usb_free_urb(urb);
	return err;
}

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) {
			clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
			usb_kill_anchored_urbs(&data->isoc_anchor);

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

struct intel_version {
	u8 status;
	u8 hw_platform;
	u8 hw_variant;
	u8 hw_revision;
	u8 fw_variant;
	u8 fw_revision;
	u8 fw_build_num;
	u8 fw_build_ww;
	u8 fw_build_yy;
	u8 fw_patch_num;
} __packed;

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;
	if (ver->status) {
		BT_ERR("%s Intel fw version event failed (%02x)", hdev->name,
		       ver->status);
		kfree_skb(skb);
		return -bt_to_errno(ver->status);
	}

	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 deivce 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);
		return 0;
	}

	/* 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);
		return 0;
	}
	fw_ptr = fw->data;

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

	if (skb->data[0]) {
		u8 evt_status = skb->data[0];
		BT_ERR("%s enable Intel manufacturer mode event failed (%02x)",
		       hdev->name, evt_status);
		kfree_skb(skb);
		release_firmware(fw);
		return -bt_to_errno(evt_status);
	}
	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);

	return 0;

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

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

	return 0;
}

/* signature: Realtek */
const uint8_t RTK_EPATCH_SIGNATURE[8] = {0x52,0x65,0x61,0x6C,0x74,0x65,0x63,0x68};
/* Extension Section IGNATURE:0x77FD0451 */
const uint8_t EXTENSION_SECTION_SIGNATURE[4] = {0x51,0x04,0xFD,0x77};

#define ROM_LMP_8723A		 0x1200
#define ROM_LMP_8723B               0x8723
#define ROM_LMP_8821A               0X8821
#define ROM_LMP_8761A               0X8761
uint16_t project_id[] = {
	ROM_LMP_8723A ,
	ROM_LMP_8723B,
	ROM_LMP_8821A,
	ROM_LMP_8761A
};
struct rtl_rom_version_evt {
	uint8_t status;
	uint8_t version;
} __attribute__ ((packed));

struct rtk_epatch_entry {
	uint16_t chip_id;
	uint16_t patch_length;
	uint32_t start_offset;
	uint32_t coex_version;
	uint32_t svn_version;
	uint32_t fw_version;
} __attribute__ ((packed));

struct rtk_epatch {
	uint8_t signature[8];
	uint32_t fw_version;
	uint16_t number_of_total_patch;
	struct rtk_epatch_entry entry[0];
} __attribute__ ((packed));


static int btusb_setup_rtl_get_oldfw( struct firmware *fw,uint8_t **buff)
{
	uint8_t *buf = *buff;
	
	BT_INFO("%s: 8723a -> use old style patch", __func__);	
	/*check file length*/
	if(fw->size<8){
		BT_ERR("%s: file size %d error", __func__,fw->size);
		return -1;
	}
	/*check signature*/
	if (!memcmp( fw->data, RTK_EPATCH_SIGNATURE, 8)) {
			BT_ERR("%s: 8723a check signature error", __func__);
			return -1;
	} 
	if (!(buf = kzalloc(fw->size, GFP_KERNEL))) {
		BT_ERR("%s: Failed to allocate mem for fw&config", __func__);
		return -1;
	} 

	BT_DBG("%s: 8723a -> fw copy directly", __func__);
	memcpy(buf, fw->data, fw->size);	
	return 1;
}

static struct rtk_epatch_entry *get_fw_patch_entry(struct rtk_epatch *patch_info, uint16_t rom_ver)
{
	int patch_num = epatch_info->number_of_total_patch;
	uint8_t *patch_buf = (uint8_t *)patch_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 *)(patch_buf + 14 + 2*i) == rom_ver + 1) {
			p_entry = kzalloc(sizeof(*p_entry), GFP_KERNEL);
			if (!p_entry) {
				BT_ERR("%s: Failed to allocate mem for patch entry", __func__);
				return NULL;
			}
			p_entry->chip_id = rom_ver + 1;
			p_entry->patch_length = *(uint16_t*)(patch_buf + 14 + 2*patch_num + 2*i);
			p_entry->start_offset = *(uint32_t*)(patch_buf + 14 + 4*patch_num + 4*i);
			p_entry->coex_version = *(uint32_t*)(patch_buf + p_entry->start_offset + p_entry->patch_length - 12);
			p_entry->svn_version = *(uint32_t*)(patch_buf + p_entry->start_offset + p_entry->patch_length - 8);
			p_entry->fw_version = *(uint32_t*)(patch_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;

			BT_INFO("%s: chip id %d, patch length 0x%04x, patch offset 0x%08x, "
					"coex version 20%06d-0x%04x, svn version 0x%08x, fw version 0x%08x",
					__func__, p_entry->chip_id, p_entry->patch_length, p_entry->start_offset,
					coex_date, coex_ver, p_entry->svn_version, p_entry->fw_version);
			break;
		}
	}

	return p_entry;
}

static int btusb_setup_rtl_get_newfw( struct firmware *fw,uint8_t **buff,int lmp_version,,int rom_version)
{
	uint8_t *buf = *buff;
	struct sk_buff *skb;
	const u8 *fw_ptr;
	uint8_t *temp;
	uint8_t opcode,len;
	uint8_t data;
	struct rtk_epatch *patch_info = NULL;
	struct rtk_epatch_entry *patch_entry = NULL;
		
	fw_ptr = fw->data;
	BT_INFO("%s: use new style patch", __func__);
	/*check file length*/
	if(fw->size<20){
		BT_ERR("%s: file size %d error", __func__,fw->size);
		return -1;
	}	
	/*check Extension Section*/
	if (memcmp(fw_ptr + fw->size-4, EXTENSION_SECTION_SIGNATURE, 4)) {
			BT_ERR("%s: Failed to check extension section signature", __func__);
			return -1;
	} 
	
	temp = fw_ptr +fw->size - 5;
	while (*temp != 0xFF) {
		opcode = *temp;
		len = *(temp-1);
		data =*(temp -2);
		if (*temp == 0x00) {		
			if (lmp_version != project_id[data]) {
				BT_ERR("%s: Default lmp_version 0x%04x, project_id 0x%04x "
						"-> not match", __func__, lmp_version, project_id[data]);
				return -1;
			}
			BT_DBG("%s: opcode = 0x%x, length = 0x%x, data = 0x%x", __func__,
					opcode, len,data);
		}
		temp -= len+ 2;
	}
	/*check signature*/
	if (memcmp(fw_ptr, RTK_EPATCH_SIGNATURE, 8)) {
		BT_ERR("%s: Check signature error", __func__);
		return -1;
	}
	/* Get right epatch entry */
	patch_info = (struct rtk_epatch*)fw_ptr;
	BT_DBG("%s:fw_version 0x%x, number_of_total_patch %d", __func__,
			epatch_info->fw_version,	epatch_info->number_of_total_patch);
	
	patch_entry = get_fw_patch_entry(patch_info, rom_version);
	if (patch_entry == NULL) {
		bt_err("%s: Failed to get fw patch entry", __func__);
		return -1;
	}

	if (!(buf = kzalloc(patch_entry->patch_length, GFP_KERNEL))) {
		BT_ERR("%s: Can't alloc memory for  fw&config", __func__);
		return -1;
	} else {
		memcpy(buf, fw_ptr+patch_entry->start_offset, patch_entry->patch_length);
		memcpy(buf+patch_entry->patch_length-4, &patch_info->fw_version, 4);
		kfree(patch_entry);
		patch_entry =NULL;
	}
	kfree(patch_buf);
	patch_buf = NULL;

return 1;
}	
static int btusb_setup_rtl_get_fw(struct hci_dev *hdev,
			int lmp_version, int rom_version,uint8_t *buff)
{

	const struct firmware *fw;
	char fwname[64];
	int ret;
	uint8_t *epatch_buf = NULL;
	uint8_t *buf = *buff;
	int fw_len = 0,buf_len = -1;;
	uint8_t need_download_fw = 1;
	
	switch(lmp_version){
	case ROM_LMP_8723A:
		fwname="rtl8723a_fw";
	case ROM_LMP_8723B:
		fwname="rtl8723b_fw";
	case ROM_LMP_8821A:
		fwname="rtl8821a_fw";
	case ROM_LMP_8761A:
		fwname="rtl8761a_fw";
		}
	
	BT_INFO("%s: Realtek Bluetooth firmware file: %s", hdev->name, fwname);
	ret = request_firmware(&fw, fwname, &hdev->dev);
	if (ret < 0) {
		BT_ERR("%s failed to open Realtek firmware file: %s(%d)",
		       hdev->name, fwname, ret);	
		
		return ret;
	}	

	/*For 8723a, use old style patch*/
	if (lmp_version == ROM_LMP_8723A) 		
		ret =btusb_setup_rtl_get_oldfw(fw,buff);
	/*For other module, use new style patch*/
	else
		ret =btusb_setup_rtl_get_newfw(fw,buff,lmp_version,rom_version);

	release_firmware(fw);
	return ret;
}

#define PATCH_SEG_MAX	252
typedef struct {
	uint8_t index;
	uint8_t data[PATCH_SEG_MAX];
} __attribute__((packed)) download_cp;

typedef struct {
	uint8_t status;
	uint8_t index;
} __attribute__((packed)) download_rp;

static int btusb_setup_rtl_download(struct hci_dev *hdev,
				     uint8_t *buff )
{
	uint8_t *pcur;
	int pkt_len, frag_num, frag_len;
	int i, ret_val, index;
	int ncmd = 1, step = 1;
	
	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;

	/*not finished*/
}
static int btusb_setup_rtl(struct hci_dev *hdev)
{
	struct sk_buff *skb;
	const struct firmware *fw;
	const u8 *fw_ptr;
	int ret;
	struct hci_rp_read_local_version *ver;
	struct rtl_rom_version_evt *rom_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",  __func__);

	/*read local version to check module type and whether patched or not*/
	skb = __hci_cmd_sync(hdev, 0x1001, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s reading Realtek fw version command failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}
	if (skb->len != sizeof(*ver)) {
		BT_ERR("%s Realtek version event length mismatch", hdev->name);
		kfree_skb(skb);
		return -EIO;
	}

	ver = (struct hci_rp_read_local_version *)skb->data;
	if (ver->status) {
		BT_ERR("%s RTL fw version event failed (%02x)", hdev->name,
		       ver->status);
		kfree_skb(skb);
		return -bt_to_errno(ver->status);
	}
	BT_INFO("%s: read local version: %04x%04x%04x%04X%04X",
		hdev->name, ver->hci_rev,ver->hci_ver,
		ver->lmp_subver,ver->lmp_ver,
		ver->manufacturer);

	if (ver->lmp_subver != ROM_LMP_8723A && ver->lmp_subver != ROM_LMP_8723A &&
		ver->lmp_subver != ROM_LMP_8821A &&ver->lmp_subver != ROM_LMP_8761A ) {
		BT_INFO("%s: Realtek device is already patched. ")
		kfree_skb(skb);
		return 0;
	}

	/*read rom version*/
	skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		BT_ERR("%s reading Realtek rom version command failed (%ld)",
		       hdev->name, PTR_ERR(skb));
		return PTR_ERR(skb);
	}
	if (skb->len != sizeof(*rom_ver)) {
		BT_ERR("%s Realtek rom version event length mismatch", hdev->name);
		kfree_skb(skb);
		return -EIO;
	}

	rom_ver = (struct rtl_rom_version_evt *)skb->data;
	if (rom_ver->status) {
		BT_ERR("%s RTL fw version event failed (%02x)", hdev->name,
		       ver->status);
		kfree_skb(skb);
		rom_ver->version = 0;
	}
	BT_INFO("%s: read rom version: %04x",
		hdev->name, rom_ver->version);

	/*get firmware patch according to local version*/
	ret =btusb_setup_rtl_get_fw(hdev, ver->lmp_subver,rom_ver->version);
	if (ret<0) {
		return ret;
	}

	/**/
	

}

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;
	int i, err;

	BT_DBG("intf %p id %p", intf, id);

	/* interface numbers are hardcoded in the spec */
	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
		return -ENODEV;

	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 (ignore_dga && id->driver_info & BTUSB_DIGIANSWER)
		return -ENODEV;

	if (ignore_csr && id->driver_info & BTUSB_CSR)
		return -ENODEV;

	if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER)
		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;

	data->cmdreq_type = USB_TYPE_CLASS;

	data->udev = interface_to_usbdev(intf);
	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);

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

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

	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_BCM92035)
		hdev->setup = btusb_setup_bcm92035;

	if (id->driver_info & BTUSB_INTEL)
		hdev->setup = btusb_setup_intel;

	if (id->driver_info & BTUSB_RTL)
		hdev->setup = btusb_setup_rtl;

	/* Interface numbers are hardcoded in the specification */
	data->isoc = usb_ifnum_to_if(data->udev, 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;

		/* Old firmware would otherwise execute USB reset */
		if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
			set_bit(HCI_QUIRK_RESET_ON_CLOSE, &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);

		data->isoc = NULL;
	}

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

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

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

	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(ignore_dga, bool, 0644);
MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001");

module_param(ignore_csr, bool, 0644);
MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");

module_param(ignore_sniffer, bool, 0644);
MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002");

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

[-- Attachment #3: realtek bluetooth vendor commands.docx --]
[-- Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document, Size: 352030 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-04 10:11             ` 答复: " 陈艳萍
@ 2014-07-08  7:57               ` Daniel Drake
  2014-07-11  8:44                 ` 答复: " 陈艳萍
  2014-09-04  3:34                 ` 答复: 答复: " 陈艳萍
  0 siblings, 2 replies; 18+ messages in thread
From: Daniel Drake @ 2014-07-08  7:57 UTC (permalink / raw)
  To: 陈艳萍
  Cc: Marcel Holtmann, Larry Finger, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list

Hi Champion,

On Fri, Jul 4, 2014 at 11:11 AM, =E9=99=88=E8=89=B3=E8=90=8D <champion_chen=
@realsil.com.cn> wrote:
>          Attached file includes vendor commands of realtek Bluetooth modu=
les in initialize procedure.
>
> And btusb is example of add rtl setup callbacks (not finished)

Thanks a lot for providing this information!

The btusb example you attached also the USB-ID-to-firmware-name lookup
table that Marcel was not so happy about. Instead it reads the version
info from the device and uses that to decide which of the firmware
files to use (e.g. rtl8723a_fw). It can do this because it drops
support for the following "problematic" RTL8761-based devices which
need a special firmware for each variant of the card:

    { 0x818B, 0x8761, "rtl8761aw8192eu_fw", "rtl8761a_config", NULL, 0
}, //Rtl8761Aw + 8192EU
    { 0x8760, 0x8761, "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0
}, //Rtl8761AU + 8192EE
    { 0xB761, 0x8761, "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0
}, //Rtl8761AU + 8192EE
    { 0x8761, 0x8761, "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0
}, //Rtl8761AU + 8192EE for LI
    { 0x8A60, 0x8761, "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0
}, //Rtl8761AU + 8812AE
(from https://github.com/lwfinger/rtl8723au_bt/blob/new/rtk_btusb.c#L1450 )

If these particular devices are not common then indeed maybe we can
not worry about supporting them for now.

However, your new code also drops usage of the config firmware files
e.g. rtl8723b_config.
Can you explain what these files are for, and if they are safe to
ignore like your new code does?

Your new code references 2 firmware files that we don't have:
rtl8821a_fw and rtl8761a_fw. Please could you send them over, and
confirm that they are redistributable?

Please also confirm that we have the latest versions of the other 2 files:

rtl8723a_fw: 24356 bytes
md5sum b4a329212ab150b88c3c6ff4c42c51d6

rtl8723b_fw: 38976 bytes
md5sum ebf894b7b91cbebce8aeb5ba63c22914

These can be found at https://github.com/lwfinger/rtl8723au_bt/tree/new

Thanks
Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-08  7:57               ` Daniel Drake
@ 2014-07-11  8:44                 ` 陈艳萍
  2014-07-11  9:11                   ` Daniel Drake
  2014-09-04  3:34                 ` 答复: 答复: " 陈艳萍
  1 sibling, 1 reply; 18+ messages in thread
From: 陈艳萍 @ 2014-07-11  8:44 UTC (permalink / raw)
  To: Daniel Drake
  Cc: Marcel Holtmann, Larry Finger, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list

SGkgRGFuaWVsLA0KCVRoZSA4NzYxIG1vZHVsZSB1c2VkIHdpdGggZGlmZmVyZW50IHdpZmkgY2hp
cCBjYW4gb25seSBiZSBkaXN0aW5ndWlzaGVkIGJ5IHBpZCwgYW5kIGRvIG5vdCBzdXBwb3J0IHZl
bmRvciBjb21tYW5kIHRvIGdldCBpbmZvcm1hdGlvbiBmcm9tIHJvbSBjb2RlLg0KVGhlIHNldHVw
IGZ1bmN0aW9uIG9ubHkgaGFzIGhjaV9kZXYgcGFyYW1ldGVyIC4gDQp3ZSBjYW4gYWRkIGRyaXZl
cl9pbmZvIGFuZCBzZXQgZGlmZmVyZW50IHNldHVwIGZ1bmNpdG9ucy4gV2lsbCB0aGlzIGJlIGFj
Y2VwdGFibGUgb3IgZG8geW91IGhhdmUgb3RoZXIgc3VnZ2VzdGlvbnM/IA0KCQ0KKDEpDQojZGVm
aW5lIEJUVVNCX1JUTAkJCTB4MjAwDQojZGVmaW5lIEJUVVNCX1JUTDg3NjFBVzgxOTJFVQkweDQw
MA0KI2RlZmluZSBCVFVTQl9SVEw4NzYxQVU4MTkyRUUJMHg4MDANCiNkZWZpbmUgQlRVU0JfUlRM
ODc2MUFVODgxMkFFCTB4MTAwMA0KDQooMikNCmJsYWNrbGlzdF90YWJsZVtdID0gew0KLi4uLi4N
CgkvKlJUTDg3NjFBVyArIDgxOTJFVSovDQoJeyBVU0JfREVWSUNFKDB4ODE4QiwgMHgwYmRhKSwg
LmRyaXZlcl9pbmZvID0gQlRVU0JfUlRMODc2MUFXODE5MkVVfSwNCgl7IFVTQl9ERVZJQ0UoMHg4
MThjLCAweDBiZGEpLCAuZHJpdmVyX2luZm8gPSBCVFVTQl9SVEw4NzYxQVc4MTkyRVV9LA0KCS8q
UnRsODc2MUFVICsgODE5MkVFKi8NCgl7IFVTQl9ERVZJQ0UoMHg4NzYwLCAweDBiZGEpLCAuZHJp
dmVyX2luZm8gPSBCVFVTQl9SVEw4NzYxQVU4MTkyRUV9LA0KCXsgVVNCX0RFVklDRSgweDg3NjEs
IDB4MGJkYSksIC5kcml2ZXJfaW5mbyA9IEJUVVNCX1JUTDg3NjFBVTgxOTJFRX0sDQoJeyBVU0Jf
REVWSUNFKDB4Qjc2MSwgMHgwYmRhKSwgLmRyaXZlcl9pbmZvID0gQlRVU0JfUlRMODc2MUFVODE5
MkVFfSwNCgkvKlJUTDg3NjFBVSArIDg4MTJBRSovDQoJeyBVU0JfREVWSUNFKDB4OEE2MCwgMHgw
YmRhKSwgLmRyaXZlcl9pbmZvID0gQlRVU0JfUlRMODc2MUFVODgxMkFFfSwNCg0KKDMpIA0KYnR1
c2JfcHJvYmUoKXsNCglpZiAoaWQtPmRyaXZlcl9pbmZvICYgQlRVU0JfUlRMKQ0KCQloZGV2LT5z
ZXR1cCA9IGJ0dXNiX3NldHVwX3J0bDsNCglpZiAoaWQtPmRyaXZlcl9pbmZvICYgQlRVU0JfUlRM
ODc2MUFXODE5MkVVKQ0KCQloZGV2LT5zZXR1cCA9IGJ0dXNiX3NldHVwX3J0bDg3NjFhdzgxOTJl
dTsNCglpZiAoaWQtPmRyaXZlcl9pbmZvICYgQlRVU0JfUlRMODc2MUFVODE5MkVFKQ0KCQloZGV2
LT5zZXR1cCA9IGJ0dXNiX3NldHVwX3J0bDg3NjFhdTgxOTJlZTsNCglpZiAoaWQtPmRyaXZlcl9p
bmZvICYgQlRVU0JfUlRMODc2MUFVODgxMkFFKQ0KCQloZGV2LT5zZXR1cCA9IGJ0dXNiX3NldHVw
X3J0bDg3NjFhdTg4MTJhZTsNCg0KRm9yIHRoZXNlIHNwZWNpYWwgY2FzZXMsIHdlIGFyZSBzdGls
bCB1bmRlciBkZXZlbG9wICwgSSB0aGluayB3ZSBjYW4gdXBkYXRlIG5leHQgdGltZS4NCg0KIiBI
b3dldmVyLCB5b3VyIG5ldyBjb2RlIGFsc28gZHJvcHMgdXNhZ2Ugb2YgdGhlIGNvbmZpZyBmaXJt
d2FyZSBmaWxlcyBlLmcuIHJ0bDg3MjNiX2NvbmZpZy4NCkNhbiB5b3UgZXhwbGFpbiB3aGF0IHRo
ZXNlIGZpbGVzIGFyZSBmb3IsIGFuZCBpZiB0aGV5IGFyZSBzYWZlIHRvIGlnbm9yZSBsaWtlIHlv
dXIgbmV3IGNvZGUgZG9lcz8iIA0KRm9yIGVhY2ggbW9kdWxlLCB0aGVyZSBtYXkgYmUgdXNlZCBh
cyBvbmUgYW50ZW5uYSBvciB0d28gYW50ZW5uYSAuIENvbmZpZyBmaWxlIGNhbiBiZSB1c2VkIHRv
IGNoYW5nZSB0aGUgYW50ZW5uYSBzZXR0aW5ncyBhbmQgb3RoZXIgZmVhdHVyZSBzdWNoIGFzIGJ0
IGFkZHJlc3MgYW5kIHBvd2VyLiBJZiBjb25maWcgZmlsZSBpcyBub3QgcHJvdmlkZWQgLG1vZHVs
ZXMgd2lsbCB1c2UgdGhlIGRlZmF1bHQgc2V0dGluZ3MuDQpJIHdpbGwgYWRkIHRoZSBjb25maWcg
ZmlsZSBpbiBkcml2ZXIgLg0KDQoNCkNoYW1waW9uDQpFeHQ6NjMyNQ0KDQoNCi0tLS0t6YKu5Lu2
5Y6f5Lu2LS0tLS0NCuWPkeS7tuS6ujogRGFuaWVsIERyYWtlIFttYWlsdG86ZHJha2VAZW5kbGVz
c20uY29tXSANCuWPkemAgeaXtumXtDogMjAxNOW5tDfmnIg45pelIDE1OjU3DQrmlLbku7bkuro6
IOmZiOiJs+iQjQ0K5oqE6YCBOiBNYXJjZWwgSG9sdG1hbm47IExhcnJ5IEZpbmdlcjsgR3VzdGF2
byBGLiBQYWRvdmFuOyBKb2hhbiBIZWRiZXJnOyBMaW51eCBCbHVldG9vdGggbWFpbGluZyBsaXN0
DQrkuLvpopg6IFJlOiDnrZTlpI06IFtQQVRDSCB2Ml0gQmx1ZXRvb3RoOiBidHVzYjogQWRkIFJl
YWx0ZWsgODcyMy84NzYxIHN1cHBvcnQNCg0KSGkgQ2hhbXBpb24sDQoNCk9uIEZyaSwgSnVsIDQs
IDIwMTQgYXQgMTE6MTEgQU0sIOmZiOiJs+iQjSA8Y2hhbXBpb25fY2hlbkByZWFsc2lsLmNvbS5j
bj4gd3JvdGU6DQo+ICAgICAgICAgIEF0dGFjaGVkIGZpbGUgaW5jbHVkZXMgdmVuZG9yIGNvbW1h
bmRzIG9mIHJlYWx0ZWsgQmx1ZXRvb3RoIG1vZHVsZXMgaW4gaW5pdGlhbGl6ZSBwcm9jZWR1cmUu
DQo+DQo+IEFuZCBidHVzYiBpcyBleGFtcGxlIG9mIGFkZCBydGwgc2V0dXAgY2FsbGJhY2tzIChu
b3QgZmluaXNoZWQpDQoNClRoYW5rcyBhIGxvdCBmb3IgcHJvdmlkaW5nIHRoaXMgaW5mb3JtYXRp
b24hDQoNClRoZSBidHVzYiBleGFtcGxlIHlvdSBhdHRhY2hlZCBhbHNvIHRoZSBVU0ItSUQtdG8t
ZmlybXdhcmUtbmFtZSBsb29rdXAgdGFibGUgdGhhdCBNYXJjZWwgd2FzIG5vdCBzbyBoYXBweSBh
Ym91dC4gSW5zdGVhZCBpdCByZWFkcyB0aGUgdmVyc2lvbiBpbmZvIGZyb20gdGhlIGRldmljZSBh
bmQgdXNlcyB0aGF0IHRvIGRlY2lkZSB3aGljaCBvZiB0aGUgZmlybXdhcmUgZmlsZXMgdG8gdXNl
IChlLmcuIHJ0bDg3MjNhX2Z3KS4gSXQgY2FuIGRvIHRoaXMgYmVjYXVzZSBpdCBkcm9wcyBzdXBw
b3J0IGZvciB0aGUgZm9sbG93aW5nICJwcm9ibGVtYXRpYyIgUlRMODc2MS1iYXNlZCBkZXZpY2Vz
IHdoaWNoIG5lZWQgYSBzcGVjaWFsIGZpcm13YXJlIGZvciBlYWNoIHZhcmlhbnQgb2YgdGhlIGNh
cmQ6DQoNCiAgICB7IDB4ODE4QiwgMHg4NzYxLCAicnRsODc2MWF3ODE5MmV1X2Z3IiwgInJ0bDg3
NjFhX2NvbmZpZyIsIE5VTEwsIDAgfSwgLy9SdGw4NzYxQXcgKyA4MTkyRVUNCiAgICB7IDB4ODc2
MCwgMHg4NzYxLCAicnRsODc2MWF1ODE5MmVlX2Z3IiwgInJ0bDg3NjFhX2NvbmZpZyIsIE5VTEws
IDAgfSwgLy9SdGw4NzYxQVUgKyA4MTkyRUUNCiAgICB7IDB4Qjc2MSwgMHg4NzYxLCAicnRsODc2
MWF1ODE5MmVlX2Z3IiwgInJ0bDg3NjFhX2NvbmZpZyIsIE5VTEwsIDAgfSwgLy9SdGw4NzYxQVUg
KyA4MTkyRUUNCiAgICB7IDB4ODc2MSwgMHg4NzYxLCAicnRsODc2MWF1ODE5MmVlX2Z3IiwgInJ0
bDg3NjFhX2NvbmZpZyIsIE5VTEwsIDAgfSwgLy9SdGw4NzYxQVUgKyA4MTkyRUUgZm9yIExJDQog
ICAgeyAweDhBNjAsIDB4ODc2MSwgInJ0bDg3NjFhdTg4MTJhZV9mdyIsICJydGw4NzYxYV9jb25m
aWciLCBOVUxMLCAwIH0sIC8vUnRsODc2MUFVICsgODgxMkFFIChmcm9tIGh0dHBzOi8vZ2l0aHVi
LmNvbS9sd2Zpbmdlci9ydGw4NzIzYXVfYnQvYmxvYi9uZXcvcnRrX2J0dXNiLmMjTDE0NTAgKQ0K
DQpJZiB0aGVzZSBwYXJ0aWN1bGFyIGRldmljZXMgYXJlIG5vdCBjb21tb24gdGhlbiBpbmRlZWQg
bWF5YmUgd2UgY2FuIG5vdCB3b3JyeSBhYm91dCBzdXBwb3J0aW5nIHRoZW0gZm9yIG5vdy4NCg0K
SG93ZXZlciwgeW91ciBuZXcgY29kZSBhbHNvIGRyb3BzIHVzYWdlIG9mIHRoZSBjb25maWcgZmly
bXdhcmUgZmlsZXMgZS5nLiBydGw4NzIzYl9jb25maWcuDQpDYW4geW91IGV4cGxhaW4gd2hhdCB0
aGVzZSBmaWxlcyBhcmUgZm9yLCBhbmQgaWYgdGhleSBhcmUgc2FmZSB0byBpZ25vcmUgbGlrZSB5
b3VyIG5ldyBjb2RlIGRvZXM/DQoNCllvdXIgbmV3IGNvZGUgcmVmZXJlbmNlcyAyIGZpcm13YXJl
IGZpbGVzIHRoYXQgd2UgZG9uJ3QgaGF2ZToNCnJ0bDg4MjFhX2Z3IGFuZCBydGw4NzYxYV9mdy4g
UGxlYXNlIGNvdWxkIHlvdSBzZW5kIHRoZW0gb3ZlciwgYW5kIGNvbmZpcm0gdGhhdCB0aGV5IGFy
ZSByZWRpc3RyaWJ1dGFibGU/DQoNClBsZWFzZSBhbHNvIGNvbmZpcm0gdGhhdCB3ZSBoYXZlIHRo
ZSBsYXRlc3QgdmVyc2lvbnMgb2YgdGhlIG90aGVyIDIgZmlsZXM6DQoNCnJ0bDg3MjNhX2Z3OiAy
NDM1NiBieXRlcw0KbWQ1c3VtIGI0YTMyOTIxMmFiMTUwYjg4YzNjNmZmNGM0MmM1MWQ2DQoNCnJ0
bDg3MjNiX2Z3OiAzODk3NiBieXRlcw0KbWQ1c3VtIGViZjg5NGI3YjkxY2JlYmNlOGFlYjViYTYz
YzIyOTE0DQoNClRoZXNlIGNhbiBiZSBmb3VuZCBhdCBodHRwczovL2dpdGh1Yi5jb20vbHdmaW5n
ZXIvcnRsODcyM2F1X2J0L3RyZWUvbmV3DQoNClRoYW5rcw0KRGFuaWVsDQo=

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-11  8:44                 ` 答复: " 陈艳萍
@ 2014-07-11  9:11                   ` Daniel Drake
  2014-07-11  9:58                     ` 答复: " 陈艳萍
  0 siblings, 1 reply; 18+ messages in thread
From: Daniel Drake @ 2014-07-11  9:11 UTC (permalink / raw)
  To: 陈艳萍
  Cc: Marcel Holtmann, Larry Finger, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list

Hi Champion,

Thanks for the response - the situation is becoming clearer.

On Fri, Jul 11, 2014 at 9:44 AM, =E9=99=88=E8=89=B3=E8=90=8D <champion_chen=
@realsil.com.cn> wrote:
> Hi Daniel,
>         The 8761 module used with different wifi chip can only be disting=
uished by pid, and do not support vendor command to get information from ro=
m code.
> The setup function only has hci_dev parameter .
> we can add driver_info and set different setup funcitons. Will this be ac=
ceptable or do you have other suggestions?

I will have to discuss this with Marcel. He was not so keen on this
approach, but given that you have now clarified exactly what the
situation is (thanks!), we will have to revisit.

However, what is clear is that we will not add support for any
hardware where we do not also submit the firmware to the
linux-firmware git repository. At the moment we only have rtl8723a and
8723b firmware and configs:

rtl8723a_fw: 24356 bytes
md5sum b4a329212ab150b88c3c6ff4c42c51d6

rtl8723b_fw: 38976 bytes
md5sum ebf894b7b91cbebce8aeb5ba63c22914

These can be found at https://github.com/lwfinger/rtl8723au_bt/tree/new

We are missing all of the following:
rtl8821a_fw
rtl8761a_fw
rtl8761au_fw
rtl8761aw8192eu_fw
rtl8761au8192ee_fw
rtl8761au8812ae_fw
rtl8761a_config
rtl8821a_config

Please could you send them over, and confirm that all are redistributable?

About the config files, I am still not really clear if they are
necessary. You say the hardware will use default settings if they are
not provided. My RTL8723B does work fine without the config. What is
the advantage of uploading these config files then, have you
changed/improve the settings since production?

Thanks
Daniel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* 答复: 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-11  9:11                   ` Daniel Drake
@ 2014-07-11  9:58                     ` 陈艳萍
  2014-07-11 11:19                       ` Marcel Holtmann
  0 siblings, 1 reply; 18+ messages in thread
From: 陈艳萍 @ 2014-07-11  9:58 UTC (permalink / raw)
  To: Daniel Drake
  Cc: Marcel Holtmann, Larry Finger, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list

SGkgRGFuaWVsLA0KCVRoZSBzZXR1cCBmdW5jdGlvbiBpcyBwcm92aWRlZCBpbiBrZXJuZWwgdjMu
MTIgLCBiZWZvcmUgdGhpcyB2ZXJzaW9uIHdlIGRvIG5vdCBoYXZlIHdheXMgdG8gYWRkIGluIGJ0
dXNiLmMgYW5kIHdlIGRvIG5vdCB3YW50IHRvIGNoYW5nZSB0aGUgZ2VuZXJpYyBkcml2ZXIgdG9v
IG11Y2ggc28gd2UgcmV3cml0ZSBydGtfYnR1c2IuYy4gDQoJSWYgdGhlIHNldHVwIGZ1bmN0aW9u
IGlzIHRoZSB3YXkgeW91IHByZWZlcnJlZCwgd2Ugd2lsbCBkZXZlbG9wIGJhc2VkIG9uIGdlbmVy
aWMgZHJpdmVyLiBUaGlzIHNlZW1zIG1ha2UgYnR1c2IuYyBtb3JlIGNvbXBsZXguIFdlIHdpbGwg
cHJvdmlkZSB5b3UgYWxsIHRoZSBmaXJtd2FyZSBhZnRlciBjb21wbGV0ZSB0ZXN0IC4gSWYgeW91
IHdhbnQgdG8gZ2V0IHRoZW0gYmVmb3JlIHRlc3QgY29tcGxldGUgSSB3aWxsIHNlbmQgbGF0ZXIu
DQoJTW9zdCBtb2R1bGVzIGNhbiB3b3JrIHByb3Blcmx5IHdpdGhvdXQgY29uZmlnIGZpbGUsIGJ1
dCBzb21lIGN1c3RvbWVycyBtYXkgd2FudCBhIHNwZWNpYWwgd2F5IGZvciBleGFtcGxlIHRoZXkg
d2FudCB0byB1c2Ugb3duIGJ0IE1BQyBhZGRyZXNzIHJhdGhlciB0aGFuIHRoZSBvbmUgaW4gbW9k
dWxlcy4gVGhlIGNvbmZpZyBmaWxlIHByb3ZpZGUgYSBmbGV4IHNvZnR3YXJlIHdheSBpbnN0ZWFk
IG9mIHJld3JpdGUgZWZmdXNlIHNldHRpbmcgaW4gbW9kdWxlcy4gVGhlIGNvbmZpZyBmaWxlIGhl
cmUgaXMgYW4gZXhhbXBsZSBhbmQgY3VzdG9tZXJzIG1heSBjaGFuZ2UgaXQgaWYgdGhleSBuZWVk
LiBUaGlzIGRlcGVuZCBvbiBjdXN0b21lciAsIG1vc3Qgbm90ZWJvb2sgcHJvZHVjdHMgbWF5IG5v
dCBuZWVkICwgYnV0IHNtYXJ0IHBob25lIG9yIHRhYmxldCBtYXkgdXNlIGl0LiBJIHRoaW5rIHdl
IGNhbm5vdCBjb3ZlciBhbGwgdGhlIHNpdHVhdGlvbnMgYW5kIGp1c3QgcHJvdmlkZSB0aGUgbW9z
dCBjb21tb24gc2V0dGluZ3MuDQoNCg0KQ2hhbXBpb24NCkV4dDo2MzI1DQoNCg0KLS0tLS3pgq7k
u7bljp/ku7YtLS0tLQ0K5Y+R5Lu25Lq6OiBEYW5pZWwgRHJha2UgW21haWx0bzpkcmFrZUBlbmRs
ZXNzbS5jb21dIA0K5Y+R6YCB5pe26Ze0OiAyMDE05bm0N+aciDEx5pelIDE3OjEyDQrmlLbku7bk
uro6IOmZiOiJs+iQjQ0K5oqE6YCBOiBNYXJjZWwgSG9sdG1hbm47IExhcnJ5IEZpbmdlcjsgR3Vz
dGF2byBGLiBQYWRvdmFuOyBKb2hhbiBIZWRiZXJnOyBMaW51eCBCbHVldG9vdGggbWFpbGluZyBs
aXN0DQrkuLvpopg6IFJlOiDnrZTlpI06IOetlOWkjTogW1BBVENIIHYyXSBCbHVldG9vdGg6IGJ0
dXNiOiBBZGQgUmVhbHRlayA4NzIzLzg3NjEgc3VwcG9ydA0KDQpIaSBDaGFtcGlvbiwNCg0KVGhh
bmtzIGZvciB0aGUgcmVzcG9uc2UgLSB0aGUgc2l0dWF0aW9uIGlzIGJlY29taW5nIGNsZWFyZXIu
DQoNCk9uIEZyaSwgSnVsIDExLCAyMDE0IGF0IDk6NDQgQU0sIOmZiOiJs+iQjSA8Y2hhbXBpb25f
Y2hlbkByZWFsc2lsLmNvbS5jbj4gd3JvdGU6DQo+IEhpIERhbmllbCwNCj4gICAgICAgICBUaGUg
ODc2MSBtb2R1bGUgdXNlZCB3aXRoIGRpZmZlcmVudCB3aWZpIGNoaXAgY2FuIG9ubHkgYmUgZGlz
dGluZ3Vpc2hlZCBieSBwaWQsIGFuZCBkbyBub3Qgc3VwcG9ydCB2ZW5kb3IgY29tbWFuZCB0byBn
ZXQgaW5mb3JtYXRpb24gZnJvbSByb20gY29kZS4NCj4gVGhlIHNldHVwIGZ1bmN0aW9uIG9ubHkg
aGFzIGhjaV9kZXYgcGFyYW1ldGVyIC4NCj4gd2UgY2FuIGFkZCBkcml2ZXJfaW5mbyBhbmQgc2V0
IGRpZmZlcmVudCBzZXR1cCBmdW5jaXRvbnMuIFdpbGwgdGhpcyBiZSBhY2NlcHRhYmxlIG9yIGRv
IHlvdSBoYXZlIG90aGVyIHN1Z2dlc3Rpb25zPw0KDQpJIHdpbGwgaGF2ZSB0byBkaXNjdXNzIHRo
aXMgd2l0aCBNYXJjZWwuIEhlIHdhcyBub3Qgc28ga2VlbiBvbiB0aGlzIGFwcHJvYWNoLCBidXQg
Z2l2ZW4gdGhhdCB5b3UgaGF2ZSBub3cgY2xhcmlmaWVkIGV4YWN0bHkgd2hhdCB0aGUgc2l0dWF0
aW9uIGlzICh0aGFua3MhKSwgd2Ugd2lsbCBoYXZlIHRvIHJldmlzaXQuDQoNCkhvd2V2ZXIsIHdo
YXQgaXMgY2xlYXIgaXMgdGhhdCB3ZSB3aWxsIG5vdCBhZGQgc3VwcG9ydCBmb3IgYW55IGhhcmR3
YXJlIHdoZXJlIHdlIGRvIG5vdCBhbHNvIHN1Ym1pdCB0aGUgZmlybXdhcmUgdG8gdGhlIGxpbnV4
LWZpcm13YXJlIGdpdCByZXBvc2l0b3J5LiBBdCB0aGUgbW9tZW50IHdlIG9ubHkgaGF2ZSBydGw4
NzIzYSBhbmQgODcyM2IgZmlybXdhcmUgYW5kIGNvbmZpZ3M6DQoNCnJ0bDg3MjNhX2Z3OiAyNDM1
NiBieXRlcw0KbWQ1c3VtIGI0YTMyOTIxMmFiMTUwYjg4YzNjNmZmNGM0MmM1MWQ2DQoNCnJ0bDg3
MjNiX2Z3OiAzODk3NiBieXRlcw0KbWQ1c3VtIGViZjg5NGI3YjkxY2JlYmNlOGFlYjViYTYzYzIy
OTE0DQoNClRoZXNlIGNhbiBiZSBmb3VuZCBhdCBodHRwczovL2dpdGh1Yi5jb20vbHdmaW5nZXIv
cnRsODcyM2F1X2J0L3RyZWUvbmV3DQoNCldlIGFyZSBtaXNzaW5nIGFsbCBvZiB0aGUgZm9sbG93
aW5nOg0KcnRsODgyMWFfZncNCnJ0bDg3NjFhX2Z3DQpydGw4NzYxYXVfZncNCnJ0bDg3NjFhdzgx
OTJldV9mdw0KcnRsODc2MWF1ODE5MmVlX2Z3DQpydGw4NzYxYXU4ODEyYWVfZncNCnJ0bDg3NjFh
X2NvbmZpZw0KcnRsODgyMWFfY29uZmlnDQoNClBsZWFzZSBjb3VsZCB5b3Ugc2VuZCB0aGVtIG92
ZXIsIGFuZCBjb25maXJtIHRoYXQgYWxsIGFyZSByZWRpc3RyaWJ1dGFibGU/DQoNCkFib3V0IHRo
ZSBjb25maWcgZmlsZXMsIEkgYW0gc3RpbGwgbm90IHJlYWxseSBjbGVhciBpZiB0aGV5IGFyZSBu
ZWNlc3NhcnkuIFlvdSBzYXkgdGhlIGhhcmR3YXJlIHdpbGwgdXNlIGRlZmF1bHQgc2V0dGluZ3Mg
aWYgdGhleSBhcmUgbm90IHByb3ZpZGVkLiBNeSBSVEw4NzIzQiBkb2VzIHdvcmsgZmluZSB3aXRo
b3V0IHRoZSBjb25maWcuIFdoYXQgaXMgdGhlIGFkdmFudGFnZSBvZiB1cGxvYWRpbmcgdGhlc2Ug
Y29uZmlnIGZpbGVzIHRoZW4sIGhhdmUgeW91IGNoYW5nZWQvaW1wcm92ZSB0aGUgc2V0dGluZ3Mg
c2luY2UgcHJvZHVjdGlvbj8NCg0KVGhhbmtzDQpEYW5pZWwNCg==

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-11  9:58                     ` 答复: " 陈艳萍
@ 2014-07-11 11:19                       ` Marcel Holtmann
  0 siblings, 0 replies; 18+ messages in thread
From: Marcel Holtmann @ 2014-07-11 11:19 UTC (permalink / raw)
  To: 陈艳萍
  Cc: Daniel Drake, Larry Finger, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list

Hi Champion,

> 	The setup function is provided in kernel v3.12 , before this version we do not have ways to add in btusb.c and we do not want to change the generic driver too much so we rewrite rtk_btusb.c. 
> 	If the setup function is the way you preferred, we will develop based on generic driver. This seems make btusb.c more complex. We will provide you all the firmware after complete test . If you want to get them before test complete I will send later.

the hdev->setup function is the preferred way since I do not want to duplicate any HCI USB transport logic in any driver.

> 	Most modules can work properly without config file, but some customers may want a special way for example they want to use own bt MAC address rather than the one in modules. The config file provide a flex software way instead of rewrite effuse setting in modules. The config file here is an example and customers may change it if they need. This depend on customer , most notebook products may not need , but smart phone or tablet may use it. I think we cannot cover all the situations and just provide the most common settings.

The case with using an OEM specific BD_ADDR is solved. You just need to add support for hdev->set_bdaddr driver callback and you can modify your Bluetooth public device address. We have a whole set of APIs that just deal with configuring this. The only requirement is that it uses HCI transport.

We also fully integrate chips that have no valid BD_ADDR. Then you just set HCI_QUIRK_INVALID_BDADDR and the kernel keeps the device in unconfigured state until Set Public Address management command is used.

I send details about this to the mailing list. This is tested with chips from Intel and Broadcom in all combinations and works nicely.

Regards

Marcel


^ permalink raw reply	[flat|nested] 18+ messages in thread

* 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-07-08  7:57               ` Daniel Drake
  2014-07-11  8:44                 ` 答复: " 陈艳萍
@ 2014-09-04  3:34                 ` 陈艳萍
  2014-09-04 12:34                   ` Daniel Drake
  2014-09-04 16:42                   ` Larry Finger
  1 sibling, 2 replies; 18+ messages in thread
From: 陈艳萍 @ 2014-09-04  3:34 UTC (permalink / raw)
  To: Daniel Drake
  Cc: Marcel Holtmann, Larry Finger, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list, 许凯凯

[-- Attachment #1: Type: text/plain, Size: 2542 bytes --]

Hi Daniel,
	Attached file is btusb driver add realtek Bluetooth support with firmware, we have tested under Ubuntu 14.04.


Champion
Ext:6325

-----邮件原件-----
发件人: Daniel Drake [mailto:drake@endlessm.com] 
发送时间: 2014年7月8日 15:57
收件人: 陈艳萍
抄送: Marcel Holtmann; Larry Finger; Gustavo F. Padovan; Johan Hedberg; Linux Bluetooth mailing list
主题: Re: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support

Hi Champion,

On Fri, Jul 4, 2014 at 11:11 AM, 陈艳萍 <champion_chen@realsil.com.cn> wrote:
>          Attached file includes vendor commands of realtek Bluetooth modules in initialize procedure.
>
> And btusb is example of add rtl setup callbacks (not finished)

Thanks a lot for providing this information!

The btusb example you attached also the USB-ID-to-firmware-name lookup table that Marcel was not so happy about. Instead it reads the version info from the device and uses that to decide which of the firmware files to use (e.g. rtl8723a_fw). It can do this because it drops support for the following "problematic" RTL8761-based devices which need a special firmware for each variant of the card:

    { 0x818B, 0x8761, "rtl8761aw8192eu_fw", "rtl8761a_config", NULL, 0 }, //Rtl8761Aw + 8192EU
    { 0x8760, 0x8761, "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 }, //Rtl8761AU + 8192EE
    { 0xB761, 0x8761, "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 }, //Rtl8761AU + 8192EE
    { 0x8761, 0x8761, "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0 }, //Rtl8761AU + 8192EE for LI
    { 0x8A60, 0x8761, "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0 }, //Rtl8761AU + 8812AE (from https://github.com/lwfinger/rtl8723au_bt/blob/new/rtk_btusb.c#L1450 )

If these particular devices are not common then indeed maybe we can not worry about supporting them for now.

However, your new code also drops usage of the config firmware files e.g. rtl8723b_config.
Can you explain what these files are for, and if they are safe to ignore like your new code does?

Your new code references 2 firmware files that we don't have:
rtl8821a_fw and rtl8761a_fw. Please could you send them over, and confirm that they are redistributable?

Please also confirm that we have the latest versions of the other 2 files:

rtl8723a_fw: 24356 bytes
md5sum b4a329212ab150b88c3c6ff4c42c51d6

rtl8723b_fw: 38976 bytes
md5sum ebf894b7b91cbebce8aeb5ba63c22914

These can be found at https://github.com/lwfinger/rtl8723au_bt/tree/new

Thanks
Daniel

[-- Attachment #2: btusb_rtk_support_20140904.rar --]
[-- Type: application/octet-stream, Size: 116992 bytes --]

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-09-04  3:34                 ` 答复: 答复: " 陈艳萍
@ 2014-09-04 12:34                   ` Daniel Drake
  2014-09-04 16:42                   ` Larry Finger
  1 sibling, 0 replies; 18+ messages in thread
From: Daniel Drake @ 2014-09-04 12:34 UTC (permalink / raw)
  To: 陈艳萍
  Cc: Marcel Holtmann, Larry Finger, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list, 许凯凯

Thank you very much for this! I'm still planning on completing the
process on getting this device support into mainline Linux, but I've
been a bit sidetracked with other work. I'll be back on this as soon
as I can.

cheers
Daniel



On Wed, Sep 3, 2014 at 9:34 PM, =E9=99=88=E8=89=B3=E8=90=8D <champion_chen@=
realsil.com.cn> wrote:
>
> Hi Daniel,
>         Attached file is btusb driver add realtek Bluetooth support with =
firmware, we have tested under Ubuntu 14.04.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-09-04  3:34                 ` 答复: 答复: " 陈艳萍
  2014-09-04 12:34                   ` Daniel Drake
@ 2014-09-04 16:42                   ` Larry Finger
  2014-09-05  3:30                     ` 答复: " 陈艳萍
  1 sibling, 1 reply; 18+ messages in thread
From: Larry Finger @ 2014-09-04 16:42 UTC (permalink / raw)
  To: 陈艳萍, Daniel Drake
  Cc: Marcel Holtmann, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list, 许凯凯

[-- Attachment #1: Type: text/plain, Size: 621 bytes --]

On 09/03/2014 10:34 PM, 陈艳萍 wrote:
> Hi Daniel,
> 	Attached file is btusb driver add realtek Bluetooth support with firmware, we have tested under Ubuntu 14.04.

Champion,

Thanks for the new driver. I pushed the new code to
http://github.com/lwfinger/rtl8723au_bt/new. Using it, I was able to connect to
a BT mouse using an RTL8723AE module.

Your version had a few compilation warnings, some of which were due to using a
64-bit system. A patch file to fix those is attached.

One other problem is that the rar file contains a file named rlt8723a_fw. I am
sure that you should rename that to rtl8723a_fw.

Larry



[-- Attachment #2: patch --]
[-- Type: text/plain, Size: 2766 bytes --]

--- a/btusb.c	2014-09-03 11:06:46.000000000 -0500
+++ b/btusb.c	2014-09-04 09:46:49.639096299 -0500
@@ -718,7 +718,7 @@ static int btusb_open(struct hci_dev *hd
 	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
 		goto done;
 
-	BT_DBG(" %s test_and_set :hdev->flags = 0x%x \n",__func__,hdev->flags);
+	BT_DBG(" %s test_and_set :hdev->flags = 0x%x \n",__func__, (int)hdev->flags);
 
 	if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags))
 		goto done;
@@ -737,7 +737,7 @@ static int btusb_open(struct hci_dev *hd
 	btusb_submit_bulk_urb(hdev, GFP_KERNEL);
 
 done:
-	BT_DBG(" %s done :hdev->flags = 0x%x \n",__func__,hdev->flags);
+	BT_DBG(" %s done :hdev->flags = 0x%x \n",__func__, (int)hdev->flags);
 	usb_autopm_put_interface(data->intf);
 	return 0;
 
@@ -806,6 +806,7 @@ static int btusb_send_frame(struct hci_d
 	struct urb *urb;
 	unsigned int pipe;
 	int err;
+	u16 *opcode;
 
 	//BT_DBG("%s", hdev->name);
 	//BT_DBG("%s hdev->flags=0x%x",__func__,hdev->flags);
@@ -837,7 +838,7 @@ static int btusb_send_frame(struct hci_d
 
 		pipe = usb_sndctrlpipe(data->udev, 0x00);
 
-		u16 *opcode = (u16*)(skb->data);
+		opcode = (u16*)(skb->data);
 	//	BT_DBG("dr->wLength =%d,opcode=0x%04x",dr->wLength,*opcode);
 		usb_fill_control_urb(urb, data->udev, pipe, (void *) dr,
 				skb->data, skb->len, btusb_tx_complete, skb);
@@ -1466,7 +1467,7 @@ static int btusb_setup_rtl_get_oldfw( co
 	BT_INFO("%s", __func__);	
 	/*check file length*/
 	if(fw->size<8){
-		BT_ERR("%s: file size %d error", __func__,fw->size);
+		BT_ERR("%s: file size %d error", __func__, (int)fw->size);
 		return -1;
 	}
 	/*check signature*/
@@ -1527,7 +1528,7 @@ static int btusb_setup_rtl_get_newfw ( s
 
 	struct sk_buff *skb;
 	uint16_t rom_ver;
-	uint8_t *temp;
+	const uint8_t *temp;
 	uint8_t opcode,len;
 	uint8_t data;	
 	struct rtk_epatch *patch_info = NULL;
@@ -1561,7 +1562,7 @@ static int btusb_setup_rtl_get_newfw ( s
 	
 	/*check file length*/
 	if(fw->size<20){
-		BT_ERR("%s: file size %d error", __func__,fw->size);
+		BT_ERR("%s: file size %d error", __func__, (int)fw->size);
 		return -1;
 	}	
 	/*check signature*/
@@ -1686,7 +1687,7 @@ static int btusb_setup_rtl_patching(stru
 			return -EIO;
 		}
 
-		evt_para = (struct hci_rp_read_local_version *)skb->data;
+		evt_para = (struct download_rp *)skb->data;
 		if (evt_para->status) {
 			BT_ERR("Realtek patch event failed (%02x)",evt_para->status);
 			kfree_skb(skb);
@@ -1768,7 +1769,8 @@ static int btusb_setup_rtl(struct hci_de
 		       fwname, ret);			
 		return ret;
 	}
-	BT_DBG("%s fw->data=%p fw->size= %d ",__func__,fw->data,fw->size);
+	BT_DBG("%s fw->data=%p fw->size= %d ", __func__, fw->data,
+	       (int)fw->size);
 	
 	/*For 8723a, use old style patch*/
 	if (lmp_version== ROM_LMP_8723A) 		

^ permalink raw reply	[flat|nested] 18+ messages in thread

* 答复: 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-09-04 16:42                   ` Larry Finger
@ 2014-09-05  3:30                     ` 陈艳萍
  2014-09-05  7:56                       ` Johan Hedberg
  0 siblings, 1 reply; 18+ messages in thread
From: 陈艳萍 @ 2014-09-05  3:30 UTC (permalink / raw)
  To: Larry Finger, Daniel Drake
  Cc: Marcel Holtmann, Gustavo F. Padovan, Johan Hedberg,
	Linux Bluetooth mailing list, 许凯凯

[-- Attachment #1: Type: text/plain, Size: 1408 bytes --]

Hi Larry,
	We found there was chance suspend failed in some platform.
This is because btusb_suspend==> btusb_stop_traffic ==> usb_kill_anchored_urbs,

btusb_bulk_complete sometimes returns before system suspend and resubmit an urb, this will avoid system enter suspend state.
I don't know whether this is the platform issue, there is a method to fix this by attached file. 


Champion
Ext:6325

-----邮件原件-----
发件人: Larry Finger [mailto:larry.finger@gmail.com] 代表 Larry Finger
发送时间: 2014年9月5日 0:42
收件人: 陈艳萍; Daniel Drake
抄送: Marcel Holtmann; Gustavo F. Padovan; Johan Hedberg; Linux Bluetooth mailing list; 许凯凯
主题: Re: 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support

On 09/03/2014 10:34 PM, 陈艳萍 wrote:
> Hi Daniel,
> 	Attached file is btusb driver add realtek Bluetooth support with firmware, we have tested under Ubuntu 14.04.

Champion,

Thanks for the new driver. I pushed the new code to http://github.com/lwfinger/rtl8723au_bt/new. Using it, I was able to connect to a BT mouse using an RTL8723AE module.

Your version had a few compilation warnings, some of which were due to using a 64-bit system. A patch file to fix those is attached.

One other problem is that the rar file contains a file named rlt8723a_fw. I am sure that you should rename that to rtl8723a_fw.

Larry



[-- Attachment #2: complete.patch --]
[-- Type: application/octet-stream, Size: 865 bytes --]

--- btusb.c.bak	2014-09-05 09:51:26.688842800 +0800
+++ btusb.c	2014-09-05 10:18:40.418442800 +0800
@@ -380,7 +380,11 @@ static void btusb_intr_complete(struct u
 			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;
 
@@ -468,7 +472,11 @@ static void btusb_bulk_complete(struct u
 			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;
 
@@ -562,6 +570,10 @@ static void btusb_isoc_complete(struct u
 			}
 		}
 	}
+	/* Avoid suspend failed when usb_kill_urb */
+	else if(urb->status == -ENOENT)	{
+		return;
+	}
 
 	if (!test_bit(BTUSB_ISOC_RUNNING, &data->flags))
 		return;

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: 答复: 答复: 答复: [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support
  2014-09-05  3:30                     ` 答复: " 陈艳萍
@ 2014-09-05  7:56                       ` Johan Hedberg
  0 siblings, 0 replies; 18+ messages in thread
From: Johan Hedberg @ 2014-09-05  7:56 UTC (permalink / raw)
  To: 陈艳萍
  Cc: Larry Finger, Daniel Drake, Marcel Holtmann, Gustavo F. Padovan,
	Linux Bluetooth mailing list, 许凯凯

Hi Champion,

On Fri, Sep 05, 2014, 陈艳萍 wrote:
> 	We found there was chance suspend failed in some platform.
> This is because btusb_suspend==> btusb_stop_traffic ==> usb_kill_anchored_urbs,
> 
> btusb_bulk_complete sometimes returns before system suspend and
> resubmit an urb, this will avoid system enter suspend state.
> I don't know whether this is the platform issue, there is a method to
> fix this by attached file.

This looks like a potentially good fix for btusb, however could you
please provide your patches in the format expected by upstream, i.e.
what you get with proper commits/commit messages and then sending the
patches using git format-patch and git send-email? The same applies for
any other patches you have for upstream inclusion. You'll also want to
ensure that the coding style is correct by reading
Documentation/CodingStyle and running scripts/checkpatch.pl on your
patches.

Johan

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2014-09-05  7:56 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-01 12:47 [PATCH v2] Bluetooth: btusb: Add Realtek 8723/8761 support Daniel Drake
2014-07-01 13:41 ` Marcel Holtmann
2014-07-01 14:18   ` Daniel Drake
2014-07-01 15:18     ` Larry Finger
2014-07-01 15:27       ` Marcel Holtmann
2014-07-03  9:28         ` 答复: " 陈艳萍
2014-07-03 18:12           ` Marcel Holtmann
2014-07-04 10:11             ` 答复: " 陈艳萍
2014-07-08  7:57               ` Daniel Drake
2014-07-11  8:44                 ` 答复: " 陈艳萍
2014-07-11  9:11                   ` Daniel Drake
2014-07-11  9:58                     ` 答复: " 陈艳萍
2014-07-11 11:19                       ` Marcel Holtmann
2014-09-04  3:34                 ` 答复: 答复: " 陈艳萍
2014-09-04 12:34                   ` Daniel Drake
2014-09-04 16:42                   ` Larry Finger
2014-09-05  3:30                     ` 答复: " 陈艳萍
2014-09-05  7:56                       ` Johan Hedberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.