Merge tag 'defconfig-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / drivers / bluetooth / btintel.c
index e44b699..f1705b4 100644 (file)
@@ -131,6 +131,26 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 }
 EXPORT_SYMBOL_GPL(btintel_set_bdaddr);
 
+static int btintel_set_event_mask(struct hci_dev *hdev, bool debug)
+{
+       u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       struct sk_buff *skb;
+       int err;
+
+       if (debug)
+               mask[1] |= 0x62;
+
+       skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               err = PTR_ERR(skb);
+               bt_dev_err(hdev, "Setting Intel event mask failed (%d)", err);
+               return err;
+       }
+       kfree_skb(skb);
+
+       return 0;
+}
+
 int btintel_set_diag(struct hci_dev *hdev, bool enable)
 {
        struct sk_buff *skb;
@@ -164,7 +184,7 @@ done:
 }
 EXPORT_SYMBOL_GPL(btintel_set_diag);
 
-int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
+static int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
 {
        int err, ret;
 
@@ -180,9 +200,25 @@ int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(btintel_set_diag_mfg);
 
-void btintel_hw_error(struct hci_dev *hdev, u8 code)
+static int btintel_set_diag_combined(struct hci_dev *hdev, bool enable)
+{
+       int ret;
+
+       /* Legacy ROM device needs to be in the manufacturer mode to apply
+        * diagnostic setting
+        *
+        * This flag is set after reading the Intel version.
+        */
+       if (btintel_test_flag(hdev, INTEL_ROM_LEGACY))
+               ret = btintel_set_diag_mfg(hdev, enable);
+       else
+               ret = btintel_set_diag(hdev, enable);
+
+       return ret;
+}
+
+static void btintel_hw_error(struct hci_dev *hdev, u8 code)
 {
        struct sk_buff *skb;
        u8 type = 0x00;
@@ -214,7 +250,6 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code)
 
        kfree_skb(skb);
 }
-EXPORT_SYMBOL_GPL(btintel_hw_error);
 
 int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
 {
@@ -236,6 +271,8 @@ int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
         * compatibility options when newer hardware variants come along.
         */
        switch (ver->hw_variant) {
+       case 0x07:      /* WP - Legacy ROM */
+       case 0x08:      /* StP - Legacy ROM */
        case 0x0b:      /* SfP */
        case 0x0c:      /* WsP */
        case 0x11:      /* JfP */
@@ -250,9 +287,15 @@ int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
        }
 
        switch (ver->fw_variant) {
+       case 0x01:
+               variant = "Legacy ROM 2.5";
+               break;
        case 0x06:
                variant = "Bootloader";
                break;
+       case 0x22:
+               variant = "Legacy ROM 2.x";
+               break;
        case 0x23:
                variant = "Firmware";
                break;
@@ -270,8 +313,8 @@ int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
 }
 EXPORT_SYMBOL_GPL(btintel_version_info);
 
-int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
-                       const void *param)
+static int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
+                              const void *param)
 {
        while (plen > 0) {
                struct sk_buff *skb;
@@ -293,7 +336,6 @@ int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(btintel_secure_send);
 
 int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
 {
@@ -340,27 +382,6 @@ int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name)
 }
 EXPORT_SYMBOL_GPL(btintel_load_ddc_config);
 
-int btintel_set_event_mask(struct hci_dev *hdev, bool debug)
-{
-       u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-       struct sk_buff *skb;
-       int err;
-
-       if (debug)
-               mask[1] |= 0x62;
-
-       skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               bt_dev_err(hdev, "Setting Intel event mask failed (%d)", err);
-               return err;
-       }
-       kfree_skb(skb);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(btintel_set_event_mask);
-
 int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug)
 {
        int err, ret;
@@ -404,7 +425,8 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
 }
 EXPORT_SYMBOL_GPL(btintel_read_version);
 
-int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
+static int btintel_version_info_tlv(struct hci_dev *hdev,
+                                   struct intel_version_tlv *version)
 {
        const char *variant;
 
@@ -481,30 +503,11 @@ int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(btintel_version_info_tlv);
 
-int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
+static int btintel_parse_version_tlv(struct hci_dev *hdev,
+                                    struct intel_version_tlv *version,
+                                    struct sk_buff *skb)
 {
-       struct sk_buff *skb;
-       const u8 param[1] = { 0xFF };
-
-       if (!version)
-               return -EINVAL;
-
-       skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
-       if (IS_ERR(skb)) {
-               bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
-                          PTR_ERR(skb));
-               return PTR_ERR(skb);
-       }
-
-       if (skb->data[0]) {
-               bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
-                          skb->data[0]);
-               kfree_skb(skb);
-               return -EIO;
-       }
-
        /* Consume Command Complete Status field */
        skb_pull(skb, 1);
 
@@ -516,7 +519,16 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
        while (skb->len) {
                struct intel_tlv *tlv;
 
+               /* Make sure skb has a minimum length of the header */
+               if (skb->len < sizeof(*tlv))
+                       return -EINVAL;
+
                tlv = (struct intel_tlv *)skb->data;
+
+               /* Make sure skb has a enough data */
+               if (skb->len < tlv->len + sizeof(*tlv))
+                       return -EINVAL;
+
                switch (tlv->type) {
                case INTEL_TLV_CNVI_TOP:
                        version->cnvi_top = get_unaligned_le32(tlv->val);
@@ -580,7 +592,8 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
                        version->sbe_type = tlv->val[0];
                        break;
                case INTEL_TLV_OTP_BDADDR:
-                       memcpy(&version->otp_bd_addr, tlv->val, tlv->len);
+                       memcpy(&version->otp_bd_addr, tlv->val,
+                                                       sizeof(bdaddr_t));
                        break;
                default:
                        /* Ignore rest of information */
@@ -590,10 +603,37 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
                skb_pull(skb, tlv->len + sizeof(*tlv));
        }
 
+       return 0;
+}
+
+static int btintel_read_version_tlv(struct hci_dev *hdev,
+                                   struct intel_version_tlv *version)
+{
+       struct sk_buff *skb;
+       const u8 param[1] = { 0xFF };
+
+       if (!version)
+               return -EINVAL;
+
+       skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Reading Intel version information failed (%ld)",
+                          PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       if (skb->data[0]) {
+               bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
+                          skb->data[0]);
+               kfree_skb(skb);
+               return -EIO;
+       }
+
+       btintel_parse_version_tlv(hdev, version, skb);
+
        kfree_skb(skb);
        return 0;
 }
-EXPORT_SYMBOL_GPL(btintel_read_version_tlv);
 
 /* ------- REGMAP IBT SUPPORT ------- */
 
@@ -1066,10 +1106,10 @@ int btintel_download_firmware(struct hci_dev *hdev,
 }
 EXPORT_SYMBOL_GPL(btintel_download_firmware);
 
-int btintel_download_firmware_newgen(struct hci_dev *hdev,
-                                    struct intel_version_tlv *ver,
-                                    const struct firmware *fw, u32 *boot_param,
-                                    u8 hw_variant, u8 sbe_type)
+static int btintel_download_fw_tlv(struct hci_dev *hdev,
+                                  struct intel_version_tlv *ver,
+                                  const struct firmware *fw, u32 *boot_param,
+                                  u8 hw_variant, u8 sbe_type)
 {
        int err;
        u32 css_header_ver;
@@ -1166,9 +1206,8 @@ int btintel_download_firmware_newgen(struct hci_dev *hdev,
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(btintel_download_firmware_newgen);
 
-void btintel_reset_to_bootloader(struct hci_dev *hdev)
+static void btintel_reset_to_bootloader(struct hci_dev *hdev)
 {
        struct intel_reset params;
        struct sk_buff *skb;
@@ -1211,10 +1250,9 @@ void btintel_reset_to_bootloader(struct hci_dev *hdev)
         */
        msleep(150);
 }
-EXPORT_SYMBOL_GPL(btintel_reset_to_bootloader);
 
-int btintel_read_debug_features(struct hci_dev *hdev,
-                               struct intel_debug_features *features)
+static int btintel_read_debug_features(struct hci_dev *hdev,
+                                      struct intel_debug_features *features)
 {
        struct sk_buff *skb;
        u8 page_no = 1;
@@ -1243,9 +1281,8 @@ int btintel_read_debug_features(struct hci_dev *hdev,
        kfree_skb(skb);
        return 0;
 }
-EXPORT_SYMBOL_GPL(btintel_read_debug_features);
 
-int btintel_set_debug_features(struct hci_dev *hdev,
+static int btintel_set_debug_features(struct hci_dev *hdev,
                               const struct intel_debug_features *features)
 {
        u8 mask[11] = { 0x0a, 0x92, 0x02, 0x07, 0x00, 0x00, 0x00, 0x00,
@@ -1270,7 +1307,1154 @@ int btintel_set_debug_features(struct hci_dev *hdev,
        kfree_skb(skb);
        return 0;
 }
-EXPORT_SYMBOL_GPL(btintel_set_debug_features);
+
+static const struct firmware *btintel_legacy_rom_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_dev_err(hdev, "Intel firmware file request failed (%d)",
+                                  ret);
+                       return NULL;
+               }
+
+               bt_dev_err(hdev, "failed to open Intel firmware file: %s (%d)",
+                          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_dev_err(hdev, "failed to open default fw file: %s",
+                                  fwname);
+                       return NULL;
+               }
+       }
+
+       bt_dev_info(hdev, "Intel Bluetooth firmware file: %s", fwname);
+
+       return fw;
+}
+
+static int btintel_legacy_rom_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_dev_err(hdev, "Intel fw corrupted: invalid cmd read");
+               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_dev_err(hdev, "Intel fw corrupted: invalid cmd len");
+               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_dev_err(hdev, "Intel fw corrupted: invalid evt len");
+                       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_dev_err(hdev, "Intel fw corrupted: invalid evt read");
+               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_dev_err(hdev, "sending Intel patch command (0x%4.4x) failed (%ld)",
+                          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_dev_err(hdev, "mismatch event length (opcode 0x%4.4x)",
+                          le16_to_cpu(cmd->opcode));
+               kfree_skb(skb);
+               return -EFAULT;
+       }
+
+       if (memcmp(skb->data, evt_param, evt->plen)) {
+               bt_dev_err(hdev, "mismatch event parameter (opcode 0x%4.4x)",
+                          le16_to_cpu(cmd->opcode));
+               kfree_skb(skb);
+               return -EFAULT;
+       }
+       kfree_skb(skb);
+
+       return 0;
+}
+
+static int btintel_legacy_rom_setup(struct hci_dev *hdev,
+                                   struct intel_version *ver)
+{
+       const struct firmware *fw;
+       const u8 *fw_ptr;
+       int disable_patch, err;
+       struct intel_version new_ver;
+
+       BT_DBG("%s", hdev->name);
+
+       /* fw_patch_num indicates the version of patch the device currently
+        * have. If there is no patch data in the device, it is always 0x00.
+        * So, if it is other than 0x00, no need to patch the device again.
+        */
+       if (ver->fw_patch_num) {
+               bt_dev_info(hdev,
+                           "Intel device is already patched. patch num: %02x",
+                           ver->fw_patch_num);
+               goto complete;
+       }
+
+       /* Opens the firmware patch file based on the firmware version read
+        * from the controller. If it fails to open the matching firmware
+        * patch file, it tries to open the default firmware patch file.
+        * If no patch file is found, allow the device to operate without
+        * a patch.
+        */
+       fw = btintel_legacy_rom_get_fw(hdev, ver);
+       if (!fw)
+               goto complete;
+       fw_ptr = fw->data;
+
+       /* Enable the manufacturer mode of the controller.
+        * Only while this mode is enabled, the driver can download the
+        * firmware patch data and configuration parameters.
+        */
+       err = btintel_enter_mfg(hdev);
+       if (err) {
+               release_firmware(fw);
+               return err;
+       }
+
+       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 = btintel_legacy_rom_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.
+        */
+       err = btintel_exit_mfg(hdev, true, true);
+       if (err)
+               return err;
+
+       /* Need build number for downloaded fw patches in
+        * every power-on boot
+        */
+       err = btintel_read_version(hdev, &new_ver);
+       if (err)
+               return err;
+
+       bt_dev_info(hdev, "Intel BT fw patch 0x%02x completed & activated",
+                   new_ver.fw_patch_num);
+
+       goto complete;
+
+exit_mfg_disable:
+       /* Disable the manufacturer mode without reset */
+       err = btintel_exit_mfg(hdev, false, false);
+       if (err)
+               return err;
+
+       bt_dev_info(hdev, "Intel firmware patch completed");
+
+       goto complete;
+
+exit_mfg_deactivate:
+       release_firmware(fw);
+
+       /* Patching failed. Disable the manufacturer mode with reset and
+        * deactivate the downloaded firmware patches.
+        */
+       err = btintel_exit_mfg(hdev, true, false);
+       if (err)
+               return err;
+
+       bt_dev_info(hdev, "Intel firmware patch completed and deactivated");
+
+complete:
+       /* Set the event mask for Intel specific vendor events. This enables
+        * a few extra events that are useful during general operation.
+        */
+       btintel_set_event_mask_mfg(hdev, false);
+
+       btintel_check_bdaddr(hdev);
+
+       return 0;
+}
+
+static int btintel_download_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
+{
+       ktime_t delta, rettime;
+       unsigned long long duration;
+       int err;
+
+       btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
+
+       bt_dev_info(hdev, "Waiting for firmware download to complete");
+
+       err = btintel_wait_on_flag_timeout(hdev, INTEL_DOWNLOADING,
+                                          TASK_INTERRUPTIBLE,
+                                          msecs_to_jiffies(msec));
+       if (err == -EINTR) {
+               bt_dev_err(hdev, "Firmware loading interrupted");
+               return err;
+       }
+
+       if (err) {
+               bt_dev_err(hdev, "Firmware loading timeout");
+               return -ETIMEDOUT;
+       }
+
+       if (btintel_test_flag(hdev, INTEL_FIRMWARE_FAILED)) {
+               bt_dev_err(hdev, "Firmware loading failed");
+               return -ENOEXEC;
+       }
+
+       rettime = ktime_get();
+       delta = ktime_sub(rettime, calltime);
+       duration = (unsigned long long)ktime_to_ns(delta) >> 10;
+
+       bt_dev_info(hdev, "Firmware loaded in %llu usecs", duration);
+
+       return 0;
+}
+
+static int btintel_boot_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
+{
+       ktime_t delta, rettime;
+       unsigned long long duration;
+       int err;
+
+       bt_dev_info(hdev, "Waiting for device to boot");
+
+       err = btintel_wait_on_flag_timeout(hdev, INTEL_BOOTING,
+                                          TASK_INTERRUPTIBLE,
+                                          msecs_to_jiffies(msec));
+       if (err == -EINTR) {
+               bt_dev_err(hdev, "Device boot interrupted");
+               return -EINTR;
+       }
+
+       if (err) {
+               bt_dev_err(hdev, "Device boot timeout");
+               return -ETIMEDOUT;
+       }
+
+       rettime = ktime_get();
+       delta = ktime_sub(rettime, calltime);
+       duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+
+       bt_dev_info(hdev, "Device booted in %llu usecs", duration);
+
+       return 0;
+}
+
+static int btintel_boot(struct hci_dev *hdev, u32 boot_addr)
+{
+       ktime_t calltime;
+       int err;
+
+       calltime = ktime_get();
+
+       btintel_set_flag(hdev, INTEL_BOOTING);
+
+       err = btintel_send_intel_reset(hdev, boot_addr);
+       if (err) {
+               bt_dev_err(hdev, "Intel Soft Reset failed (%d)", err);
+               btintel_reset_to_bootloader(hdev);
+               return err;
+       }
+
+       /* The bootloader will not indicate when the device is ready. This
+        * is done by the operational firmware sending bootup notification.
+        *
+        * Booting into operational firmware should not take longer than
+        * 1 second. However if that happens, then just fail the setup
+        * since something went wrong.
+        */
+       err = btintel_boot_wait(hdev, calltime, 1000);
+       if (err == -ETIMEDOUT)
+               btintel_reset_to_bootloader(hdev);
+
+       return err;
+}
+
+static int btintel_get_fw_name(struct intel_version *ver,
+                                            struct intel_boot_params *params,
+                                            char *fw_name, size_t len,
+                                            const char *suffix)
+{
+       switch (ver->hw_variant) {
+       case 0x0b:      /* SfP */
+       case 0x0c:      /* WsP */
+               snprintf(fw_name, len, "intel/ibt-%u-%u.%s",
+                       le16_to_cpu(ver->hw_variant),
+                       le16_to_cpu(params->dev_revid),
+                       suffix);
+               break;
+       case 0x11:      /* JfP */
+       case 0x12:      /* ThP */
+       case 0x13:      /* HrP */
+       case 0x14:      /* CcP */
+               snprintf(fw_name, len, "intel/ibt-%u-%u-%u.%s",
+                       le16_to_cpu(ver->hw_variant),
+                       le16_to_cpu(ver->hw_revision),
+                       le16_to_cpu(ver->fw_revision),
+                       suffix);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int btintel_download_fw(struct hci_dev *hdev,
+                                        struct intel_version *ver,
+                                        struct intel_boot_params *params,
+                                        u32 *boot_param)
+{
+       const struct firmware *fw;
+       char fwname[64];
+       int err;
+       ktime_t calltime;
+
+       if (!ver || !params)
+               return -EINVAL;
+
+       /* The firmware variant determines if the device is in bootloader
+        * mode or is running operational firmware. The value 0x06 identifies
+        * the bootloader and the value 0x23 identifies the operational
+        * firmware.
+        *
+        * When the operational firmware is already present, then only
+        * the check for valid Bluetooth device address is needed. This
+        * determines if the device will be added as configured or
+        * unconfigured controller.
+        *
+        * It is not possible to use the Secure Boot Parameters in this
+        * case since that command is only available in bootloader mode.
+        */
+       if (ver->fw_variant == 0x23) {
+               btintel_clear_flag(hdev, INTEL_BOOTLOADER);
+               btintel_check_bdaddr(hdev);
+
+               /* SfP and WsP don't seem to update the firmware version on file
+                * so version checking is currently possible.
+                */
+               switch (ver->hw_variant) {
+               case 0x0b:      /* SfP */
+               case 0x0c:      /* WsP */
+                       return 0;
+               }
+
+               /* Proceed to download to check if the version matches */
+               goto download;
+       }
+
+       /* Read the secure boot parameters to identify the operating
+        * details of the bootloader.
+        */
+       err = btintel_read_boot_params(hdev, params);
+       if (err)
+               return err;
+
+       /* It is required that every single firmware fragment is acknowledged
+        * with a command complete event. If the boot parameters indicate
+        * that this bootloader does not send them, then abort the setup.
+        */
+       if (params->limited_cce != 0x00) {
+               bt_dev_err(hdev, "Unsupported Intel firmware loading method (%u)",
+                          params->limited_cce);
+               return -EINVAL;
+       }
+
+       /* If the OTP has no valid Bluetooth device address, then there will
+        * also be no valid address for the operational firmware.
+        */
+       if (!bacmp(&params->otp_bdaddr, BDADDR_ANY)) {
+               bt_dev_info(hdev, "No device address configured");
+               set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+       }
+
+download:
+       /* With this Intel bootloader only the hardware variant and device
+        * revision information are used to select the right firmware for SfP
+        * and WsP.
+        *
+        * The firmware filename is ibt-<hw_variant>-<dev_revid>.sfi.
+        *
+        * Currently the supported hardware variants are:
+        *   11 (0x0b) for iBT3.0 (LnP/SfP)
+        *   12 (0x0c) for iBT3.5 (WsP)
+        *
+        * For ThP/JfP and for future SKU's, the FW name varies based on HW
+        * variant, HW revision and FW revision, as these are dependent on CNVi
+        * and RF Combination.
+        *
+        *   17 (0x11) for iBT3.5 (JfP)
+        *   18 (0x12) for iBT3.5 (ThP)
+        *
+        * The firmware file name for these will be
+        * ibt-<hw_variant>-<hw_revision>-<fw_revision>.sfi.
+        *
+        */
+       err = btintel_get_fw_name(ver, params, fwname, sizeof(fwname), "sfi");
+       if (err < 0) {
+               if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
+                       /* Firmware has already been loaded */
+                       btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
+                       return 0;
+               }
+
+               bt_dev_err(hdev, "Unsupported Intel firmware naming");
+               return -EINVAL;
+       }
+
+       err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
+       if (err < 0) {
+               if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
+                       /* Firmware has already been loaded */
+                       btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
+                       return 0;
+               }
+
+               bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
+                          fwname, err);
+               return err;
+       }
+
+       bt_dev_info(hdev, "Found device firmware: %s", fwname);
+
+       if (fw->size < 644) {
+               bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
+                          fw->size);
+               err = -EBADF;
+               goto done;
+       }
+
+       calltime = ktime_get();
+
+       btintel_set_flag(hdev, INTEL_DOWNLOADING);
+
+       /* Start firmware downloading and get boot parameter */
+       err = btintel_download_firmware(hdev, ver, fw, boot_param);
+       if (err < 0) {
+               if (err == -EALREADY) {
+                       /* Firmware has already been loaded */
+                       btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
+                       err = 0;
+                       goto done;
+               }
+
+               /* When FW download fails, send Intel Reset to retry
+                * FW download.
+                */
+               btintel_reset_to_bootloader(hdev);
+               goto done;
+       }
+
+       /* Before switching the device into operational mode and with that
+        * booting the loaded firmware, wait for the bootloader notification
+        * that all fragments have been successfully received.
+        *
+        * When the event processing receives the notification, then the
+        * INTEL_DOWNLOADING flag will be cleared.
+        *
+        * The firmware loading should not take longer than 5 seconds
+        * and thus just timeout if that happens and fail the setup
+        * of this device.
+        */
+       err = btintel_download_wait(hdev, calltime, 5000);
+       if (err == -ETIMEDOUT)
+               btintel_reset_to_bootloader(hdev);
+
+done:
+       release_firmware(fw);
+       return err;
+}
+
+static int btintel_bootloader_setup(struct hci_dev *hdev,
+                                   struct intel_version *ver)
+{
+       struct intel_version new_ver;
+       struct intel_boot_params params;
+       u32 boot_param;
+       char ddcname[64];
+       int err;
+       struct intel_debug_features features;
+
+       BT_DBG("%s", hdev->name);
+
+       /* Set the default boot parameter to 0x0 and it is updated to
+        * SKU specific boot parameter after reading Intel_Write_Boot_Params
+        * command while downloading the firmware.
+        */
+       boot_param = 0x00000000;
+
+       btintel_set_flag(hdev, INTEL_BOOTLOADER);
+
+       err = btintel_download_fw(hdev, ver, &params, &boot_param);
+       if (err)
+               return err;
+
+       /* controller is already having an operational firmware */
+       if (ver->fw_variant == 0x23)
+               goto finish;
+
+       err = btintel_boot(hdev, boot_param);
+       if (err)
+               return err;
+
+       btintel_clear_flag(hdev, INTEL_BOOTLOADER);
+
+       err = btintel_get_fw_name(ver, &params, ddcname,
+                                               sizeof(ddcname), "ddc");
+
+       if (err < 0) {
+               bt_dev_err(hdev, "Unsupported Intel firmware naming");
+       } else {
+               /* Once the device is running in operational mode, it needs to
+                * apply the device configuration (DDC) parameters.
+                *
+                * The device can work without DDC parameters, so even if it
+                * fails to load the file, no need to fail the setup.
+                */
+               btintel_load_ddc_config(hdev, ddcname);
+       }
+
+       /* Read the Intel supported features and if new exception formats
+        * supported, need to load the additional DDC config to enable.
+        */
+       err = btintel_read_debug_features(hdev, &features);
+       if (!err) {
+               /* Set DDC mask for available debug features */
+               btintel_set_debug_features(hdev, &features);
+       }
+
+       /* Read the Intel version information after loading the FW  */
+       err = btintel_read_version(hdev, &new_ver);
+       if (err)
+               return err;
+
+       btintel_version_info(hdev, &new_ver);
+
+finish:
+       /* Set the event mask for Intel specific vendor events. This enables
+        * a few extra events that are useful during general operation. It
+        * does not enable any debugging related events.
+        *
+        * The device will function correctly without these events enabled
+        * and thus no need to fail the setup.
+        */
+       btintel_set_event_mask(hdev, false);
+
+       return 0;
+}
+
+static void btintel_get_fw_name_tlv(const struct intel_version_tlv *ver,
+                                   char *fw_name, size_t len,
+                                   const char *suffix)
+{
+       /* The firmware file name for new generation controllers will be
+        * ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step>
+        */
+       snprintf(fw_name, len, "intel/ibt-%04x-%04x.%s",
+                INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvi_top),
+                                         INTEL_CNVX_TOP_STEP(ver->cnvi_top)),
+                INTEL_CNVX_TOP_PACK_SWAB(INTEL_CNVX_TOP_TYPE(ver->cnvr_top),
+                                         INTEL_CNVX_TOP_STEP(ver->cnvr_top)),
+                suffix);
+}
+
+static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
+                                          struct intel_version_tlv *ver,
+                                          u32 *boot_param)
+{
+       const struct firmware *fw;
+       char fwname[64];
+       int err;
+       ktime_t calltime;
+
+       if (!ver || !boot_param)
+               return -EINVAL;
+
+       /* The firmware variant determines if the device is in bootloader
+        * mode or is running operational firmware. The value 0x03 identifies
+        * the bootloader and the value 0x23 identifies the operational
+        * firmware.
+        *
+        * When the operational firmware is already present, then only
+        * the check for valid Bluetooth device address is needed. This
+        * determines if the device will be added as configured or
+        * unconfigured controller.
+        *
+        * It is not possible to use the Secure Boot Parameters in this
+        * case since that command is only available in bootloader mode.
+        */
+       if (ver->img_type == 0x03) {
+               btintel_clear_flag(hdev, INTEL_BOOTLOADER);
+               btintel_check_bdaddr(hdev);
+       }
+
+       /* If the OTP has no valid Bluetooth device address, then there will
+        * also be no valid address for the operational firmware.
+        */
+       if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) {
+               bt_dev_info(hdev, "No device address configured");
+               set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+       }
+
+       btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
+       err = firmware_request_nowarn(&fw, fwname, &hdev->dev);
+       if (err < 0) {
+               if (!btintel_test_flag(hdev, INTEL_BOOTLOADER)) {
+                       /* Firmware has already been loaded */
+                       btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
+                       return 0;
+               }
+
+               bt_dev_err(hdev, "Failed to load Intel firmware file %s (%d)",
+                          fwname, err);
+
+               return err;
+       }
+
+       bt_dev_info(hdev, "Found device firmware: %s", fwname);
+
+       if (fw->size < 644) {
+               bt_dev_err(hdev, "Invalid size of firmware file (%zu)",
+                          fw->size);
+               err = -EBADF;
+               goto done;
+       }
+
+       calltime = ktime_get();
+
+       btintel_set_flag(hdev, INTEL_DOWNLOADING);
+
+       /* Start firmware downloading and get boot parameter */
+       err = btintel_download_fw_tlv(hdev, ver, fw, boot_param,
+                                              INTEL_HW_VARIANT(ver->cnvi_bt),
+                                              ver->sbe_type);
+       if (err < 0) {
+               if (err == -EALREADY) {
+                       /* Firmware has already been loaded */
+                       btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
+                       err = 0;
+                       goto done;
+               }
+
+               /* When FW download fails, send Intel Reset to retry
+                * FW download.
+                */
+               btintel_reset_to_bootloader(hdev);
+               goto done;
+       }
+
+       /* Before switching the device into operational mode and with that
+        * booting the loaded firmware, wait for the bootloader notification
+        * that all fragments have been successfully received.
+        *
+        * When the event processing receives the notification, then the
+        * BTUSB_DOWNLOADING flag will be cleared.
+        *
+        * The firmware loading should not take longer than 5 seconds
+        * and thus just timeout if that happens and fail the setup
+        * of this device.
+        */
+       err = btintel_download_wait(hdev, calltime, 5000);
+       if (err == -ETIMEDOUT)
+               btintel_reset_to_bootloader(hdev);
+
+done:
+       release_firmware(fw);
+       return err;
+}
+
+static int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
+                                       struct intel_version_tlv *ver)
+{
+       u32 boot_param;
+       char ddcname[64];
+       int err;
+       struct intel_debug_features features;
+       struct intel_version_tlv new_ver;
+
+       bt_dev_dbg(hdev, "");
+
+       /* Set the default boot parameter to 0x0 and it is updated to
+        * SKU specific boot parameter after reading Intel_Write_Boot_Params
+        * command while downloading the firmware.
+        */
+       boot_param = 0x00000000;
+
+       btintel_set_flag(hdev, INTEL_BOOTLOADER);
+
+       err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param);
+       if (err)
+               return err;
+
+       /* check if controller is already having an operational firmware */
+       if (ver->img_type == 0x03)
+               goto finish;
+
+       err = btintel_boot(hdev, boot_param);
+       if (err)
+               return err;
+
+       btintel_clear_flag(hdev, INTEL_BOOTLOADER);
+
+       btintel_get_fw_name_tlv(ver, ddcname, sizeof(ddcname), "ddc");
+       /* Once the device is running in operational mode, it needs to
+        * apply the device configuration (DDC) parameters.
+        *
+        * The device can work without DDC parameters, so even if it
+        * fails to load the file, no need to fail the setup.
+        */
+       btintel_load_ddc_config(hdev, ddcname);
+
+       /* Read the Intel supported features and if new exception formats
+        * supported, need to load the additional DDC config to enable.
+        */
+       err = btintel_read_debug_features(hdev, &features);
+       if (!err) {
+               /* Set DDC mask for available debug features */
+               btintel_set_debug_features(hdev, &features);
+       }
+
+       /* Read the Intel version information after loading the FW  */
+       err = btintel_read_version_tlv(hdev, &new_ver);
+       if (err)
+               return err;
+
+       btintel_version_info_tlv(hdev, &new_ver);
+
+finish:
+       /* Set the event mask for Intel specific vendor events. This enables
+        * a few extra events that are useful during general operation. It
+        * does not enable any debugging related events.
+        *
+        * The device will function correctly without these events enabled
+        * and thus no need to fail the setup.
+        */
+       btintel_set_event_mask(hdev, false);
+
+       return 0;
+}
+
+static void btintel_set_msft_opcode(struct hci_dev *hdev, u8 hw_variant)
+{
+       switch (hw_variant) {
+       /* Legacy bootloader devices that supports MSFT Extension */
+       case 0x11:      /* JfP */
+       case 0x12:      /* ThP */
+       case 0x13:      /* HrP */
+       case 0x14:      /* CcP */
+       /* All Intel new genration controllers support the Microsoft vendor
+        * extension are using 0xFC1E for VsMsftOpCode.
+        */
+       case 0x17:
+       case 0x18:
+       case 0x19:
+               hci_set_msft_opcode(hdev, 0xFC1E);
+               break;
+       default:
+               /* Not supported */
+               break;
+       }
+}
+
+static int btintel_setup_combined(struct hci_dev *hdev)
+{
+       const u8 param[1] = { 0xFF };
+       struct intel_version ver;
+       struct intel_version_tlv ver_tlv;
+       struct sk_buff *skb;
+       int err;
+
+       BT_DBG("%s", hdev->name);
+
+       /* The some controllers have 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.
+        */
+       if (btintel_test_flag(hdev, INTEL_BROKEN_INITIAL_NCMD)) {
+               skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL,
+                                    HCI_INIT_TIMEOUT);
+               if (IS_ERR(skb)) {
+                       bt_dev_err(hdev,
+                                  "sending initial HCI reset failed (%ld)",
+                                  PTR_ERR(skb));
+                       return PTR_ERR(skb);
+               }
+               kfree_skb(skb);
+       }
+
+       /* Starting from TyP device, the command parameter and response are
+        * changed even though the OCF for HCI_Intel_Read_Version command
+        * remains same. The legacy devices can handle even if the
+        * command has a parameter and returns a correct version information.
+        * So, it uses new format to support both legacy and new format.
+        */
+       skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Reading Intel version command failed (%ld)",
+                          PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+
+       /* Check the status */
+       if (skb->data[0]) {
+               bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
+                          skb->data[0]);
+               err = -EIO;
+               goto exit_error;
+       }
+
+       /* Apply the common HCI quirks for Intel device */
+       set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+       set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
+       set_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks);
+
+       /* For Legacy device, check the HW platform value and size */
+       if (skb->len == sizeof(ver) && skb->data[1] == 0x37) {
+               bt_dev_dbg(hdev, "Read the legacy Intel version information");
+
+               memcpy(&ver, skb->data, sizeof(ver));
+
+               /* Display version information */
+               btintel_version_info(hdev, &ver);
+
+               /* Check for supported iBT hardware variants of this firmware
+                * loading method.
+                *
+                * This check has been put in place to ensure correct forward
+                * compatibility options when newer hardware variants come
+                * along.
+                */
+               switch (ver.hw_variant) {
+               case 0x07:      /* WP */
+               case 0x08:      /* StP */
+                       /* Legacy ROM product */
+                       btintel_set_flag(hdev, INTEL_ROM_LEGACY);
+
+                       /* Apply the device specific HCI quirks
+                        *
+                        * WBS for SdP - SdP and Stp have a same hw_varaint but
+                        * different fw_variant
+                        */
+                       if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22)
+                               set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
+                                       &hdev->quirks);
+
+                       /* These devices have an issue with LED which doesn't
+                        * go off immediately during shutdown. Set the flag
+                        * here to send the LED OFF command during shutdown.
+                        */
+                       btintel_set_flag(hdev, INTEL_BROKEN_LED);
+
+                       err = btintel_legacy_rom_setup(hdev, &ver);
+                       break;
+               case 0x0b:      /* SfP */
+               case 0x0c:      /* WsP */
+               case 0x11:      /* JfP */
+               case 0x12:      /* ThP */
+               case 0x13:      /* HrP */
+               case 0x14:      /* CcP */
+                       /* Apply the device specific HCI quirks
+                        *
+                        * All Legacy bootloader devices support WBS
+                        */
+                       set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
+                               &hdev->quirks);
+
+                       /* Valid LE States quirk for JfP/ThP familiy */
+                       if (ver.hw_variant == 0x11 || ver.hw_variant == 0x12)
+                               set_bit(HCI_QUIRK_VALID_LE_STATES,
+                                       &hdev->quirks);
+
+                       /* Setup MSFT Extension support */
+                       btintel_set_msft_opcode(hdev, ver.hw_variant);
+
+                       err = btintel_bootloader_setup(hdev, &ver);
+                       break;
+               default:
+                       bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
+                                  ver.hw_variant);
+                       err = -EINVAL;
+               }
+
+               goto exit_error;
+       }
+
+       /* For TLV type device, parse the tlv data */
+       err = btintel_parse_version_tlv(hdev, &ver_tlv, skb);
+       if (err) {
+               bt_dev_err(hdev, "Failed to parse TLV version information");
+               goto exit_error;
+       }
+
+       if (INTEL_HW_PLATFORM(ver_tlv.cnvi_bt) != 0x37) {
+               bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
+                          INTEL_HW_PLATFORM(ver_tlv.cnvi_bt));
+               err = -EINVAL;
+               goto exit_error;
+       }
+
+       /* Check for supported iBT hardware variants of this firmware
+        * loading method.
+        *
+        * This check has been put in place to ensure correct forward
+        * compatibility options when newer hardware variants come
+        * along.
+        */
+       switch (INTEL_HW_VARIANT(ver_tlv.cnvi_bt)) {
+       case 0x11:      /* JfP */
+       case 0x12:      /* ThP */
+       case 0x13:      /* HrP */
+       case 0x14:      /* CcP */
+               /* Some legacy bootloader devices from JfP supports both old
+                * and TLV based HCI_Intel_Read_Version command. But we don't
+                * want to use the TLV based setup routines for those legacy
+                * bootloader device.
+                *
+                * Also, it is not easy to convert TLV based version from the
+                * legacy version format.
+                *
+                * So, as a workaround for those devices, use the legacy
+                * HCI_Intel_Read_Version to get the version information and
+                * run the legacy bootloader setup.
+                */
+               err = btintel_read_version(hdev, &ver);
+               if (err)
+                       return err;
+               err = btintel_bootloader_setup(hdev, &ver);
+               break;
+       case 0x17:
+       case 0x18:
+       case 0x19:
+               /* Display version information of TLV type */
+               btintel_version_info_tlv(hdev, &ver_tlv);
+
+               /* Apply the device specific HCI quirks for TLV based devices
+                *
+                * All TLV based devices support WBS
+                */
+               set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
+
+               /* Valid LE States quirk for GfP */
+               if (INTEL_HW_VARIANT(ver_tlv.cnvi_bt) == 0x18)
+                       set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
+
+               /* Setup MSFT Extension support */
+               btintel_set_msft_opcode(hdev,
+                                       INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
+
+               err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
+               break;
+       default:
+               bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
+                          INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
+               return -EINVAL;
+       }
+
+exit_error:
+       kfree_skb(skb);
+
+       return err;
+}
+
+static int btintel_shutdown_combined(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+       int ret;
+
+       /* Send HCI Reset to the controller to stop any BT activity which
+        * were triggered. This will help to save power and maintain the
+        * sync b/w Host and controller
+        */
+       skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "HCI reset during shutdown failed");
+               return PTR_ERR(skb);
+       }
+       kfree_skb(skb);
+
+
+       /* Some platforms have an issue with BT LED when the interface is
+        * down or BT radio is turned off, which takes 5 seconds to BT LED
+        * goes off. This command turns off the BT LED immediately.
+        */
+       if (btintel_test_flag(hdev, INTEL_BROKEN_LED)) {
+               skb = __hci_cmd_sync(hdev, 0xfc3f, 0, NULL, HCI_INIT_TIMEOUT);
+               if (IS_ERR(skb)) {
+                       ret = PTR_ERR(skb);
+                       bt_dev_err(hdev, "turning off Intel device LED failed");
+                       return ret;
+               }
+               kfree_skb(skb);
+       }
+
+       return 0;
+}
+
+int btintel_configure_setup(struct hci_dev *hdev)
+{
+       hdev->manufacturer = 2;
+       hdev->setup = btintel_setup_combined;
+       hdev->shutdown = btintel_shutdown_combined;
+       hdev->hw_error = btintel_hw_error;
+       hdev->set_diag = btintel_set_diag_combined;
+       hdev->set_bdaddr = btintel_set_bdaddr;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(btintel_configure_setup);
+
+void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len)
+{
+       const struct intel_bootup *evt = ptr;
+
+       if (len != sizeof(*evt))
+               return;
+
+       if (btintel_test_and_clear_flag(hdev, INTEL_BOOTING))
+               btintel_wake_up_flag(hdev, INTEL_BOOTING);
+}
+EXPORT_SYMBOL_GPL(btintel_bootup);
+
+void btintel_secure_send_result(struct hci_dev *hdev,
+                               const void *ptr, unsigned int len)
+{
+       const struct intel_secure_send_result *evt = ptr;
+
+       if (len != sizeof(*evt))
+               return;
+
+       if (evt->result)
+               btintel_set_flag(hdev, INTEL_FIRMWARE_FAILED);
+
+       if (btintel_test_and_clear_flag(hdev, INTEL_DOWNLOADING) &&
+           btintel_test_flag(hdev, INTEL_FIRMWARE_LOADED))
+               btintel_wake_up_flag(hdev, INTEL_DOWNLOADING);
+}
+EXPORT_SYMBOL_GPL(btintel_secure_send_result);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION);