Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ab137bc authored by David S. Miller's avatar David S. Miller
Browse files


John W. Linville says:

====================
A few more stragglers intended for 3.10...

For the Bluetooth bits, Gustavo says:

"A few more patches intended for 3.10, the most important one is the support in
btusb for fw loading for the Intel Bluetooth device. Other than that we have
only fixes and clean ups."

For the iwlwifi bits, Johannes says:

"Here are a few more changes for the 3.10 stream, some bugfixes,
adjustments to some powersave parameters and a new device ID."

For the NFC bits, Samuel says:

"This pull request includes Marcel's Kconfig dependency fix on top of the LLCP
code move to net/nfc."

On top of that...Yogesh Ashok Powar provides a few PCI-related mwifiex
updates, Hauke Mehrtens provides a small ssb feature for spurious
tone avoidance on a specific chip, and Larry Finger provides a small
rtlwifi fix related to avoiding false detection of AP loss.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b807a3d6 17a2911f
Loading
Loading
Loading
Loading
+22 −244
Original line number Diff line number Diff line
@@ -29,20 +29,6 @@
struct btmrvl_debugfs_data {
	struct dentry *config_dir;
	struct dentry *status_dir;

	/* config */
	struct dentry *psmode;
	struct dentry *pscmd;
	struct dentry *hsmode;
	struct dentry *hscmd;
	struct dentry *gpiogap;
	struct dentry *hscfgcmd;

	/* status */
	struct dentry *curpsmode;
	struct dentry *hsstate;
	struct dentry *psstate;
	struct dentry *txdnldready;
};

static ssize_t btmrvl_hscfgcmd_write(struct file *file,
@@ -91,47 +77,6 @@ static const struct file_operations btmrvl_hscfgcmd_fops = {
	.llseek = default_llseek,
};

static ssize_t btmrvl_psmode_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 10, &result);
	if (ret)
		return ret;

	priv->btmrvl_dev.psmode = result;

	return count;
}

static ssize_t btmrvl_psmode_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
						priv->btmrvl_dev.psmode);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_psmode_fops = {
	.read	= btmrvl_psmode_read,
	.write	= btmrvl_psmode_write,
	.open	= simple_open,
	.llseek = default_llseek,
};

static ssize_t btmrvl_pscmd_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
@@ -178,47 +123,6 @@ static const struct file_operations btmrvl_pscmd_fops = {
	.llseek = default_llseek,
};

static ssize_t btmrvl_gpiogap_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 16, &result);
	if (ret)
		return ret;

	priv->btmrvl_dev.gpio_gap = result;

	return count;
}

static ssize_t btmrvl_gpiogap_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "0x%x\n",
						priv->btmrvl_dev.gpio_gap);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_gpiogap_fops = {
	.read	= btmrvl_gpiogap_read,
	.write	= btmrvl_gpiogap_write,
	.open	= simple_open,
	.llseek = default_llseek,
};

static ssize_t btmrvl_hscmd_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
@@ -263,119 +167,6 @@ static const struct file_operations btmrvl_hscmd_fops = {
	.llseek = default_llseek,
};

static ssize_t btmrvl_hsmode_write(struct file *file, const char __user *ubuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	long result, ret;

	memset(buf, 0, sizeof(buf));

	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
		return -EFAULT;

	ret = strict_strtol(buf, 10, &result);
	if (ret)
		return ret;

	priv->btmrvl_dev.hsmode = result;

	return count;
}

static ssize_t btmrvl_hsmode_read(struct file *file, char __user * userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->btmrvl_dev.hsmode);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_hsmode_fops = {
	.read	= btmrvl_hsmode_read,
	.write	= btmrvl_hsmode_write,
	.open	= simple_open,
	.llseek = default_llseek,
};

static ssize_t btmrvl_curpsmode_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->psmode);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_curpsmode_fops = {
	.read	= btmrvl_curpsmode_read,
	.open	= simple_open,
	.llseek = default_llseek,
};

static ssize_t btmrvl_psstate_read(struct file *file, char __user * userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->ps_state);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_psstate_fops = {
	.read	= btmrvl_psstate_read,
	.open	= simple_open,
	.llseek = default_llseek,
};

static ssize_t btmrvl_hsstate_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n", priv->adapter->hs_state);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_hsstate_fops = {
	.read	= btmrvl_hsstate_read,
	.open	= simple_open,
	.llseek = default_llseek,
};

static ssize_t btmrvl_txdnldready_read(struct file *file, char __user *userbuf,
						size_t count, loff_t *ppos)
{
	struct btmrvl_private *priv = file->private_data;
	char buf[16];
	int ret;

	ret = snprintf(buf, sizeof(buf) - 1, "%d\n",
					priv->btmrvl_dev.tx_dnld_rdy);

	return simple_read_from_buffer(userbuf, count, ppos, buf, ret);
}

static const struct file_operations btmrvl_txdnldready_fops = {
	.read	= btmrvl_txdnldready_read,
	.open	= simple_open,
	.llseek = default_llseek,
};

void btmrvl_debugfs_init(struct hci_dev *hdev)
{
	struct btmrvl_private *priv = hci_get_drvdata(hdev);
@@ -394,30 +185,28 @@ void btmrvl_debugfs_init(struct hci_dev *hdev)

	dbg->config_dir = debugfs_create_dir("config", hdev->debugfs);

	dbg->psmode = debugfs_create_file("psmode", 0644, dbg->config_dir,
					  priv, &btmrvl_psmode_fops);
	dbg->pscmd = debugfs_create_file("pscmd", 0644, dbg->config_dir,
	debugfs_create_u8("psmode", 0644, dbg->config_dir,
			  &priv->btmrvl_dev.psmode);
	debugfs_create_file("pscmd", 0644, dbg->config_dir,
			    priv, &btmrvl_pscmd_fops);
	dbg->gpiogap = debugfs_create_file("gpiogap", 0644, dbg->config_dir,
					   priv, &btmrvl_gpiogap_fops);
	dbg->hsmode =  debugfs_create_file("hsmode", 0644, dbg->config_dir,
					   priv, &btmrvl_hsmode_fops);
	dbg->hscmd = debugfs_create_file("hscmd", 0644, dbg->config_dir,
	debugfs_create_x16("gpiogap", 0644, dbg->config_dir,
			   &priv->btmrvl_dev.gpio_gap);
	debugfs_create_u8("hsmode", 0644, dbg->config_dir,
			  &priv->btmrvl_dev.hsmode);
	debugfs_create_file("hscmd", 0644, dbg->config_dir,
			    priv, &btmrvl_hscmd_fops);
	dbg->hscfgcmd = debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
	debugfs_create_file("hscfgcmd", 0644, dbg->config_dir,
			    priv, &btmrvl_hscfgcmd_fops);

	dbg->status_dir = debugfs_create_dir("status", hdev->debugfs);
	dbg->curpsmode = debugfs_create_file("curpsmode", 0444,
					     dbg->status_dir, priv,
					     &btmrvl_curpsmode_fops);
	dbg->psstate = debugfs_create_file("psstate", 0444, dbg->status_dir,
					   priv, &btmrvl_psstate_fops);
	dbg->hsstate = debugfs_create_file("hsstate", 0444, dbg->status_dir,
					   priv, &btmrvl_hsstate_fops);
	dbg->txdnldready = debugfs_create_file("txdnldready", 0444,
					       dbg->status_dir, priv,
					       &btmrvl_txdnldready_fops);
	debugfs_create_u8("curpsmode", 0444, dbg->status_dir,
			  &priv->adapter->psmode);
	debugfs_create_u8("psstate", 0444, dbg->status_dir,
			  &priv->adapter->ps_state);
	debugfs_create_u8("hsstate", 0444, dbg->status_dir,
			  &priv->adapter->hs_state);
	debugfs_create_u8("txdnldready", 0444, dbg->status_dir,
			  &priv->btmrvl_dev.tx_dnld_rdy);
}

void btmrvl_debugfs_remove(struct hci_dev *hdev)
@@ -428,19 +217,8 @@ void btmrvl_debugfs_remove(struct hci_dev *hdev)
	if (!dbg)
		return;

	debugfs_remove(dbg->psmode);
	debugfs_remove(dbg->pscmd);
	debugfs_remove(dbg->gpiogap);
	debugfs_remove(dbg->hsmode);
	debugfs_remove(dbg->hscmd);
	debugfs_remove(dbg->hscfgcmd);
	debugfs_remove(dbg->config_dir);

	debugfs_remove(dbg->curpsmode);
	debugfs_remove(dbg->psstate);
	debugfs_remove(dbg->hsstate);
	debugfs_remove(dbg->txdnldready);
	debugfs_remove(dbg->status_dir);
	debugfs_remove_recursive(dbg->config_dir);
	debugfs_remove_recursive(dbg->status_dir);

	kfree(dbg);
}
+23 −18
Original line number Diff line number Diff line
@@ -228,24 +228,24 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
static int btmrvl_sdio_verify_fw_download(struct btmrvl_sdio_card *card,
								int pollnum)
{
	int ret = -ETIMEDOUT;
	u16 firmwarestat;
	unsigned int tries;
	int tries, ret;

	 /* Wait for firmware to become ready */
	for (tries = 0; tries < pollnum; tries++) {
		if (btmrvl_sdio_read_fw_status(card, &firmwarestat) < 0)
		sdio_claim_host(card->func);
		ret = btmrvl_sdio_read_fw_status(card, &firmwarestat);
		sdio_release_host(card->func);
		if (ret < 0)
			continue;

		if (firmwarestat == FIRMWARE_READY) {
			ret = 0;
			break;
		} else {
		if (firmwarestat == FIRMWARE_READY)
			return 0;

		msleep(10);
	}
	}

	return ret;
	return -ETIMEDOUT;
}

static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
@@ -874,7 +874,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,

static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
{
	int ret = 0;
	int ret;
	u8 fws0;
	int pollnum = MAX_POLL_TRIES;

@@ -882,13 +882,14 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
		BT_ERR("card or function is NULL!");
		return -EINVAL;
	}
	sdio_claim_host(card->func);

	if (!btmrvl_sdio_verify_fw_download(card, 1)) {
		BT_DBG("Firmware already downloaded!");
		goto done;
		return 0;
	}

	sdio_claim_host(card->func);

	/* Check if other function driver is downloading the firmware */
	fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
	if (ret) {
@@ -918,15 +919,21 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
		}
	}

	sdio_release_host(card->func);

	/*
	 * winner or not, with this test the FW synchronizes when the
	 * module can continue its initialization
	 */
	if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
		BT_ERR("FW failed to be active in time!");
		ret = -ETIMEDOUT;
		goto done;
		return -ETIMEDOUT;
	}

	return 0;

done:
	sdio_release_host(card->func);

	return ret;
}

@@ -989,8 +996,6 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
		goto unreg_dev;
	}

	msleep(100);

	btmrvl_sdio_enable_host_int(card);

	priv = btmrvl_add_card(card);
+377 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

#include <linux/module.h>
#include <linux/usb.h>
#include <linux/firmware.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -47,6 +48,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_BROKEN_ISOC	0x20
#define BTUSB_WRONG_SCO_MTU	0x40
#define BTUSB_ATH3012		0x80
#define BTUSB_INTEL		0x100

static struct usb_device_id btusb_table[] = {
	/* Generic Bluetooth USB device */
@@ -207,6 +209,9 @@ static struct usb_device_id blacklist_table[] = {
	/* Frontline ComProbe Bluetooth Sniffer */
	{ USB_DEVICE(0x16d3, 0x0002), .driver_info = BTUSB_SNIFFER },

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

	{ }	/* Terminating entry */
};

@@ -943,6 +948,375 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev)
	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;
}

static int btusb_probe(struct usb_interface *intf,
				const struct usb_device_id *id)
{
@@ -1048,6 +1422,9 @@ static int btusb_probe(struct usb_interface *intf,
	if (id->driver_info & BTUSB_BCM92035)
		hdev->setup = btusb_setup_bcm92035;

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

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

+1 −0
Original line number Diff line number Diff line
@@ -336,6 +336,7 @@ static void brcms_remove(struct bcma_device *pdev)
	struct brcms_info *wl = hw->priv;

	if (wl->wlc) {
		brcms_led_unregister(wl);
		wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
		wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
		ieee80211_unregister_hw(hw);
+1 −1
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ int iwl_calib_set(struct iwl_priv *priv,
		  const struct iwl_calib_hdr *cmd, int len);
void iwl_calib_free_results(struct iwl_priv *priv);
int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
			    char **buf, bool display);
			    char **buf);
int iwlagn_hw_valid_rtc_data_addr(u32 addr);

/* lib */
Loading