Bluetooth: btintel: Refactoring setup routine for legacy ROM sku
authorTedd Ho-Jeong An <tedd.an@intel.com>
Thu, 5 Aug 2021 00:32:10 +0000 (17:32 -0700)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 5 Aug 2021 14:03:29 +0000 (16:03 +0200)
This patch refactors the setup routines for legacy ROM product into
combined setup, and move the related functions from btusb to btintel.

Signed-off-by: Tedd Ho-Jeong An <tedd.an@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
drivers/bluetooth/btintel.c
drivers/bluetooth/btintel.h
drivers/bluetooth/btusb.c

index 2fac6ba..a6d75af 100644 (file)
@@ -164,7 +164,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,7 +180,6 @@ 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)
 {
@@ -1382,6 +1381,291 @@ int btintel_set_debug_features(struct hci_dev *hdev,
 }
 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_setup_combined(struct hci_dev *hdev)
 {
        const u8 param[1] = { 0xFF };
@@ -1433,7 +1717,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
                case 0x07:      /* WP */
                case 0x08:      /* StP */
                        /* Legacy ROM product */
-                       /* TODO: call setup routine for legacy rom product */
+                       err = btintel_legacy_rom_setup(hdev, &ver);
                        break;
                case 0x0b:      /* SfP */
                case 0x0c:      /* WsP */
@@ -1498,10 +1782,11 @@ static int btintel_shutdown_combined(struct hci_dev *hdev)
 
 int btintel_configure_setup(struct hci_dev *hdev)
 {
-       /* TODO: Setup hdev callback here */
        hdev->manufacturer = 2;
        hdev->setup = btintel_setup_combined;
        hdev->shutdown = btintel_shutdown_combined;
+       hdev->set_diag = btintel_set_diag_mfg;
+       hdev->set_bdaddr = btintel_set_bdaddr;
 
        return 0;
 }
index dda890d..2c87fd0 100644 (file)
@@ -145,7 +145,6 @@ int btintel_enter_mfg(struct hci_dev *hdev);
 int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched);
 int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
 int btintel_set_diag(struct hci_dev *hdev, bool enable);
-int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
 void btintel_hw_error(struct hci_dev *hdev, u8 code);
 
 int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
@@ -203,11 +202,6 @@ static inline int btintel_set_diag(struct hci_dev *hdev, bool enable)
        return -EOPNOTSUPP;
 }
 
-static inline int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
-{
-       return -EOPNOTSUPP;
-}
-
 static inline void btintel_hw_error(struct hci_dev *hdev, u8 code)
 {
 }
index 8c4e397..ce05085 100644 (file)
@@ -43,7 +43,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
+#define BTUSB_INTEL_COMBINED   0x100
 #define BTUSB_INTEL_BOOT       0x200
 #define BTUSB_BCM_PATCHRAM     0x400
 #define BTUSB_MARVELL          0x800
@@ -372,11 +372,11 @@ static const struct usb_device_id blacklist_table[] = {
                                                     BTUSB_WIDEBAND_SPEECH |
                                                     BTUSB_VALID_LE_STATES },
        { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
-       { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
-       { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
+       { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED },
+       { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED },
        { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW |
                                                     BTUSB_WIDEBAND_SPEECH },
-       { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL |
+       { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED |
                                                     BTUSB_WIDEBAND_SPEECH },
        { USB_DEVICE(0x8087, 0x0aaa), .driver_info = BTUSB_INTEL_NEW |
                                                     BTUSB_WIDEBAND_SPEECH |
@@ -1969,319 +1969,6 @@ static int btusb_setup_csr(struct hci_dev *hdev)
        return 0;
 }
 
-static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
-                                                      struct intel_version *ver)
-{
-       const struct firmware *fw;
-       char fwname[64];
-       int ret;
-
-       snprintf(fwname, sizeof(fwname),
-                "intel/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.bseq",
-                ver->hw_platform, ver->hw_variant, ver->hw_revision,
-                ver->fw_variant,  ver->fw_revision, ver->fw_build_num,
-                ver->fw_build_ww, ver->fw_build_yy);
-
-       ret = request_firmware(&fw, fwname, &hdev->dev);
-       if (ret < 0) {
-               if (ret == -EINVAL) {
-                       bt_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 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_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 btusb_setup_intel(struct hci_dev *hdev)
-{
-       struct sk_buff *skb;
-       const struct firmware *fw;
-       const u8 *fw_ptr;
-       int disable_patch, err;
-       struct intel_version ver;
-
-       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_dev_err(hdev, "sending initial HCI reset command failed (%ld)",
-                          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.
-        */
-       err = btintel_read_version(hdev, &ver);
-       if (err)
-               return err;
-
-       bt_dev_info(hdev, "read Intel version: %02x%02x%02x%02x%02x%02x%02x%02x%02x",
-                   ver.hw_platform, ver.hw_variant, ver.hw_revision,
-                   ver.fw_variant,  ver.fw_revision, ver.fw_build_num,
-                   ver.fw_build_ww, ver.fw_build_yy, ver.fw_patch_num);
-
-       /* fw_patch_num indicates the version of patch the device currently
-        * have. If there is no patch data in the device, it is always 0x00.
-        * So, if it is other than 0x00, no need to patch the device again.
-        */
-       if (ver.fw_patch_num) {
-               bt_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 = btusb_setup_intel_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 = 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.
-        */
-       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, &ver);
-       if (err)
-               return err;
-       bt_dev_info(hdev, "Intel BT fw patch 0x%02x completed & activated",
-                  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 inject_cmd_complete(struct hci_dev *hdev, __u16 opcode)
 {
        struct sk_buff *skb;
@@ -3060,41 +2747,6 @@ finish:
 
        return 0;
 }
-static int btusb_shutdown_intel(struct hci_dev *hdev)
-{
-       struct sk_buff *skb;
-       long ret;
-
-       /* In the shutdown sequence where Bluetooth is turned off followed
-        * by WiFi being turned off, turning WiFi back on causes issue with
-        * the RF calibration.
-        *
-        * To ensure that any RF activity has been stopped, issue HCI Reset
-        * command to clear all ongoing activity including advertising,
-        * scanning etc.
-        */
-       skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               ret = PTR_ERR(skb);
-               bt_dev_err(hdev, "HCI reset during shutdown failed");
-               return ret;
-       }
-       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.
-        */
-       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;
-}
 
 static int btusb_shutdown_intel_new(struct hci_dev *hdev)
 {
@@ -4818,13 +4470,15 @@ static int btusb_probe(struct usb_interface *intf,
                data->diag = usb_ifnum_to_if(data->udev, ifnum_base + 2);
        }
 
-       if (id->driver_info & BTUSB_INTEL) {
-               hdev->manufacturer = 2;
-               hdev->setup = btusb_setup_intel;
-               hdev->shutdown = btusb_shutdown_intel;
-               hdev->set_diag = btintel_set_diag_mfg;
-               hdev->set_bdaddr = btintel_set_bdaddr;
+       /* Combined Intel Device setup to support multiple setup routine */
+       if (id->driver_info & BTUSB_INTEL_COMBINED) {
+               err = btintel_configure_setup(hdev);
+               if (err)
+                       goto out_free_dev;
+
+               /* Transport specific configuration */
                hdev->cmd_timeout = btusb_intel_cmd_timeout;
+
                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);