summaryrefslogtreecommitdiff
path: root/drivers/bluetooth/btintel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/btintel.c')
-rw-r--r--drivers/bluetooth/btintel.c725
1 files changed, 630 insertions, 95 deletions
diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 9e9fd2222294..8593b27b7c4a 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -631,90 +631,7 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
return -EIO;
}
- /* Consume Command Complete Status field */
- skb_pull(skb, 1);
-
- /* Event parameters contatin multiple TLVs. Read each of them
- * and only keep the required data. Also, it use existing legacy
- * version field like hw_platform, hw_variant, and fw_variant
- * to keep the existing setup flow
- */
- while (skb->len) {
- struct intel_tlv *tlv;
-
- tlv = (struct intel_tlv *)skb->data;
- switch (tlv->type) {
- case INTEL_TLV_CNVI_TOP:
- version->cnvi_top = get_unaligned_le32(tlv->val);
- break;
- case INTEL_TLV_CNVR_TOP:
- version->cnvr_top = get_unaligned_le32(tlv->val);
- break;
- case INTEL_TLV_CNVI_BT:
- version->cnvi_bt = get_unaligned_le32(tlv->val);
- break;
- case INTEL_TLV_CNVR_BT:
- version->cnvr_bt = get_unaligned_le32(tlv->val);
- break;
- case INTEL_TLV_DEV_REV_ID:
- version->dev_rev_id = get_unaligned_le16(tlv->val);
- break;
- case INTEL_TLV_IMAGE_TYPE:
- version->img_type = tlv->val[0];
- break;
- case INTEL_TLV_TIME_STAMP:
- /* If image type is Operational firmware (0x03), then
- * running FW Calendar Week and Year information can
- * be extracted from Timestamp information
- */
- version->min_fw_build_cw = tlv->val[0];
- version->min_fw_build_yy = tlv->val[1];
- version->timestamp = get_unaligned_le16(tlv->val);
- break;
- case INTEL_TLV_BUILD_TYPE:
- version->build_type = tlv->val[0];
- break;
- case INTEL_TLV_BUILD_NUM:
- /* If image type is Operational firmware (0x03), then
- * running FW build number can be extracted from the
- * Build information
- */
- version->min_fw_build_nn = tlv->val[0];
- version->build_num = get_unaligned_le32(tlv->val);
- break;
- case INTEL_TLV_SECURE_BOOT:
- version->secure_boot = tlv->val[0];
- break;
- case INTEL_TLV_OTP_LOCK:
- version->otp_lock = tlv->val[0];
- break;
- case INTEL_TLV_API_LOCK:
- version->api_lock = tlv->val[0];
- break;
- case INTEL_TLV_DEBUG_LOCK:
- version->debug_lock = tlv->val[0];
- break;
- case INTEL_TLV_MIN_FW:
- version->min_fw_build_nn = tlv->val[0];
- version->min_fw_build_cw = tlv->val[1];
- version->min_fw_build_yy = tlv->val[2];
- break;
- case INTEL_TLV_LIMITED_CCE:
- version->limited_cce = tlv->val[0];
- break;
- case INTEL_TLV_SBE_TYPE:
- version->sbe_type = tlv->val[0];
- break;
- case INTEL_TLV_OTP_BDADDR:
- memcpy(&version->otp_bd_addr, tlv->val, tlv->len);
- break;
- default:
- /* Ignore rest of information */
- break;
- }
- /* consume the current tlv and move to next*/
- skb_pull(skb, tlv->len + sizeof(*tlv));
- }
+ btintel_parse_version_tlv(hdev, version, skb);
kfree_skb(skb);
return 0;
@@ -1192,10 +1109,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;
@@ -1292,7 +1209,6 @@ 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)
{
@@ -1683,6 +1599,579 @@ complete:
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:
+ /* All Intel controllers that support the Microsoft vendor
+ * extension are using 0xFC1E for VsMsftOpCode.
+ */
+ switch (ver->hw_variant) {
+ case 0x11: /* JfP */
+ case 0x12: /* ThP */
+ case 0x13: /* HrP */
+ case 0x14: /* CcP */
+ hci_set_msft_opcode(hdev, 0xFC1E);
+ break;
+ }
+
+ /* 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 int btintel_setup_combined(struct hci_dev *hdev)
{
const u8 param[1] = { 0xFF };
@@ -1770,7 +2259,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
case 0x12: /* ThP */
case 0x13: /* HrP */
case 0x14: /* CcP */
- /* TODO: call setup routine for bootloader product */
+ err = btintel_bootloader_setup(hdev, &ver);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
@@ -1795,11 +2284,27 @@ static int btintel_setup_combined(struct hci_dev *hdev)
goto exit_error;
}
- /* Display version information of TLV type */
- btintel_version_info_tlv(hdev, &ver_tlv);
-
- /* TODO: Need to filter the device for new generation */
- /* TODO: call setup routine for tlv based bootloader product */
+ /* 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 0x17:
+ case 0x18:
+ case 0x19:
+ /* Display version information of TLV type */
+ btintel_version_info_tlv(hdev, &ver_tlv);
+
+ 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);
@@ -1846,6 +2351,7 @@ 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;
@@ -1853,6 +2359,35 @@ int btintel_configure_setup(struct hci_dev *hdev)
}
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);
MODULE_VERSION(VERSION);