Loading drivers/bluetooth/btmrvl_debugfs.c +22 −244 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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) Loading @@ -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); } drivers/bluetooth/btmrvl_sdio.c +23 −18 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; } Loading Loading @@ -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); Loading drivers/bluetooth/btusb.c +377 −0 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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 */ Loading Loading @@ -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 */ }; Loading Loading @@ -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) { Loading Loading @@ -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); Loading drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading drivers/net/wireless/iwlwifi/dvm/agn.h +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/bluetooth/btmrvl_debugfs.c +22 −244 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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); Loading @@ -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) Loading @@ -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); }
drivers/bluetooth/btmrvl_sdio.c +23 −18 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; } Loading Loading @@ -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); Loading
drivers/bluetooth/btusb.c +377 −0 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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 */ Loading Loading @@ -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 */ }; Loading Loading @@ -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) { Loading Loading @@ -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); Loading
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +1 −0 Original line number Diff line number Diff line Loading @@ -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); Loading
drivers/net/wireless/iwlwifi/dvm/agn.h +1 −1 Original line number Diff line number Diff line Loading @@ -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