/* For some Intel based controllers, the default Bluetooth device *address00:03:19:9E:8B:00canbefound.Thesecontrollersare *fullyoperational,buthavethedangerofduplicateaddresses *andthatinturncancauseproblemswithBluetoothoperation.
*/ if (!bacmp(&bda->bdaddr, BDADDR_INTEL)) {
bt_dev_err(hdev, "Found Intel default device address (%pMR)",
&bda->bdaddr);
hci_set_quirk(hdev, HCI_QUIRK_INVALID_BDADDR);
}
staticint btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
{ int err, ret;
err = btintel_enter_mfg(hdev); if (err) return err;
ret = btintel_set_diag(hdev, enable);
err = btintel_exit_mfg(hdev, false, false); if (err) return err;
return ret;
}
staticint btintel_set_diag_combined(struct hci_dev *hdev, bool enable)
{ int ret;
/* Legacy ROM device needs to be in the manufacturer mode to apply *diagnosticsetting * *ThisflagissetafterreadingtheIntelversion.
*/ if (btintel_test_flag(hdev, INTEL_ROM_LEGACY))
ret = btintel_set_diag_mfg(hdev, enable); else
ret = btintel_set_diag(hdev, enable);
int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
{ constchar *variant;
/* The hardware platform number has a fixed value of 0x37 and *fornowonlyacceptthissinglevalue.
*/ if (ver->hw_platform != 0x37) {
bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",
ver->hw_platform); return -EINVAL;
}
/* DDC file contains one or more DDC structure which has *Length(1byte),DDCID(2bytes),andDDCvalue(Length-2).
*/ while (fw->size > fw_ptr - fw->data) {
u8 cmd_plen = fw_ptr[0] + sizeof(u8);
int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
{ constchar *variant;
/* The hardware platform number has a fixed value of 0x37 and *fornowonlyacceptthissinglevalue.
*/ if (INTEL_HW_PLATFORM(version->cnvi_bt) != 0x37) {
bt_dev_err(hdev, "Unsupported Intel hardware platform (0x%2x)",
INTEL_HW_PLATFORM(version->cnvi_bt)); return -EINVAL;
}
switch (version->img_type) { case BTINTEL_IMG_BOOTLOADER:
variant = "Bootloader"; /* It is required that every single firmware fragment is acknowledged *withacommandcompleteevent.Ifthebootparametersindicate *thatthisbootloaderdoesnotsendthem,thenabortthesetup.
*/ if (version->limited_cce != 0x00) {
bt_dev_err(hdev, "Unsupported Intel firmware loading method (0x%x)",
version->limited_cce); return -EINVAL;
}
/* Secure boot engine type should be either 1 (ECDSA) or 0 (RSA) */ if (version->sbe_type > 0x01) {
bt_dev_err(hdev, "Unsupported Intel secure boot engine type (0x%x)",
version->sbe_type); return -EINVAL;
}
bt_dev_info(hdev, "Device revision is %u", version->dev_rev_id);
bt_dev_info(hdev, "Secure boot is %s",
str_enabled_disabled(version->secure_boot));
bt_dev_info(hdev, "OTP lock is %s",
str_enabled_disabled(version->otp_lock));
bt_dev_info(hdev, "API lock is %s",
str_enabled_disabled(version->api_lock));
bt_dev_info(hdev, "Debug lock is %s",
str_enabled_disabled(version->debug_lock));
bt_dev_info(hdev, "Minimum firmware build %u week %u %u",
version->min_fw_build_nn, version->min_fw_build_cw, 2000 + version->min_fw_build_yy); break; case BTINTEL_IMG_IML:
variant = "Intermediate loader"; break; case BTINTEL_IMG_OP:
variant = "Firmware"; break; default:
bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type); return -EINVAL;
}
int btintel_parse_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version, struct sk_buff *skb)
{ /* Consume Command Complete Status field */
skb_pull(skb, 1);
/* Event parameters contain multiple TLVs. Read each of them *andonlykeeptherequireddata.Also,ituseexistinglegacy *versionfieldlikehw_platform,hw_variant,andfw_variant *tokeeptheexistingsetupflow
*/ 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); 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 *runningFWCalendarWeekandYearinformationcan *beextractedfromTimestampinformation
*/
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 *runningFWbuildnumbercanbeextractedfromthe *Buildinformation
*/
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, sizeof(bdaddr_t)); break; case INTEL_TLV_GIT_SHA1:
version->git_sha1 = get_unaligned_le32(tlv->val); break; case INTEL_TLV_FW_ID:
snprintf(version->fw_id, sizeof(version->fw_id), "%s", tlv->val); break; default: /* Ignore rest of information */ break;
} /* consume the current tlv and move to next*/
skb_pull(skb, tlv->len + sizeof(*tlv));
}
staticint regmap_ibt_write(void *context, constvoid *data, size_t count)
{ /* data contains register+value, since we only support 32bit addr, *minimumdatasizeis4bytes.
*/ if (WARN_ONCE(count < 4, "Invalid register access")) return -EINVAL;
/* Config is the same for all register regions */ staticconststruct regmap_config regmap_ibt_cfg = {
.name = "btintel_regmap",
.reg_bits = 32,
.val_bits = 32,
};
staticint btintel_sfi_rsa_header_secure_send(struct hci_dev *hdev, conststruct firmware *fw)
{ int err;
/* Start the firmware download transaction with the Init fragment *representedbythe128bytesofCSSheader.
*/
err = btintel_secure_send(hdev, 0x00, 128, fw->data); if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware header (%d)", err); goto done;
}
/* Send the 256 bytes of public key information from the firmware *asthePKeyfragment.
*/
err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err); goto done;
}
/* Send the 256 bytes of signature information from the firmware *astheSignfragment.
*/
err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware signature (%d)", err); goto done;
}
done: return err;
}
staticint btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev, conststruct firmware *fw)
{ int err;
/* Start the firmware download transaction with the Init fragment *representedbythe128bytesofCSSheader.
*/
err = btintel_secure_send(hdev, 0x00, 128, fw->data + 644); if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware header (%d)", err); return err;
}
/* Send the 96 bytes of public key information from the firmware *asthePKeyfragment.
*/
err = btintel_secure_send(hdev, 0x03, 96, fw->data + 644 + 128); if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err); return err;
}
/* Send the 96 bytes of signature information from the firmware *astheSignfragment
*/
err = btintel_secure_send(hdev, 0x02, 96, fw->data + 644 + 224); if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware signature (%d)",
err); return err;
} return0;
}
/* Each SKU has a different reset parameter to use in the *HCI_Intel_Resetcommandanditisembeddedinthefirmware *data.So,insteadofusingstaticvalueperSKU,check *thefirmwaredataandsaveitforlateruse.
*/ if (le16_to_cpu(cmd->opcode) == CMD_WRITE_BOOT_PARAMS) { struct cmd_write_boot_params *params;
int btintel_download_firmware(struct hci_dev *hdev, struct intel_version *ver, conststruct firmware *fw,
u32 *boot_param)
{ int err;
/* SfP and WsP don't seem to update the firmware version on file *soversioncheckingiscurrentlynotpossible.
*/ switch (ver->hw_variant) { case0x0b: /* SfP */ case0x0c: /* WsP */ /* Skip version checking */ break; default:
/* Skip download if firmware has the same version */ if (btintel_firmware_version(hdev, ver->fw_build_num,
ver->fw_build_ww, ver->fw_build_yy,
fw, boot_param)) {
bt_dev_info(hdev, "Firmware already loaded"); /* Return -EALREADY to indicate that the firmware has *alreadybeenloaded.
*/ return -EALREADY;
}
}
/* The firmware variant determines if the device is in bootloader *modeorisrunningoperationalfirmware.Thevalue0x06identifies *thebootloaderandthevalue0x23identifiestheoperational *firmware. * *Ifthefirmwareversionhaschangedthatmeansitneedstobereset *tobootloaderwhenoperationalsothenewfirmwarecanbeloaded.
*/ if (ver->fw_variant == 0x23) return -EINVAL;
err = btintel_sfi_rsa_header_secure_send(hdev, fw); if (err) return err;
/* Skip download if firmware has the same version */ if (btintel_firmware_version(hdev, ver->min_fw_build_nn,
ver->min_fw_build_cw,
ver->min_fw_build_yy,
fw, boot_param)) {
bt_dev_info(hdev, "Firmware already loaded"); /* Return -EALREADY to indicate that firmware has *alreadybeenloaded.
*/ return -EALREADY;
}
/* The firmware variant determines if the device is in bootloader *modeorisrunningoperationalfirmware.Thevalue0x01identifies *thebootloaderandthevalue0x03identifiestheoperational *firmware. * *Ifthefirmwareversionhaschangedthatmeansitneedstobereset *tobootloaderwhenoperationalsothenewfirmwarecanbeloaded.
*/ if (ver->img_type == BTINTEL_IMG_OP) return -EINVAL;
skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params),
¶ms, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) {
bt_dev_err(hdev, "FW download error recovery failed (%ld)",
PTR_ERR(skb)); return;
}
bt_dev_info(hdev, "Intel reset sent to retry FW download");
kfree_skb(skb);
/* Current Intel BT controllers(ThP/JfP) hold the USB reset *linesfor2mswhenitreceivesIntelResetinbootloadermode. *Whereas,theupcomingIntelBTcontrollerswillholdUSBreset *for150ms.Tokeepthedelaygeneric,150msischosenhere.
*/
msleep(150);
}
int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
{ struct intel_debug_features features; int err;
bt_dev_dbg(hdev, "enable %d", enable);
/* Read the Intel supported features and if new exception formats *supported,needtoloadtheadditionalDDCconfigtoenable.
*/
err = btintel_read_debug_features(hdev, &features); if (err) return err;
/* Set or reset the debug features. */ if (enable)
err = btintel_set_debug_features(hdev, &features); else
err = btintel_reset_debug_features(hdev, &features);
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 *defaultfirmwarepatchfileinstead
*/
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);
/* Ensure that the remain firmware data is long enough than the length *ofcommandparameter.Ifnot,thefirmwarefileiscorrupted.
*/ 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,thenenablethepatchuponsuccess,otherwisejust *disablethemanufacturermode,forexamplepatchactivation *isnotrequiredwhenthedefaultfirmwarepatchfileisused *becausetherearenopatchdatatoload.
*/ if (*disable_patch && le16_to_cpu(cmd->opcode) == 0xfc8e)
*disable_patch = 0;
/* This reads the expected events when the above command is sent to the *device.Somevendorcommandsexpectsmorethanoneevents,for *examplecommandstatuseventfollowedbyvendorspecificevent. *Forthiscase,itonlykeepsthelastexpectedevent.sothecommand *canbesentwith__hci_cmd_sync_ev()whichreturnsthesk_buffof *lastexpectedevent.
*/ while (remain > HCI_EVENT_HDR_SIZE && *fw_ptr[0] == 0x02) {
(*fw_ptr)++;
remain--;
/* It ensures that the returned event matches the event data read from *thefirmwarefile.Atfist,itchecksthelengthandthen *thecontentsoftheevent.
*/ 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;
}
/* fw_patch_num indicates the version of patch the device currently *have.Ifthereisnopatchdatainthedevice,itisalways0x00. *So,ifitisotherthan0x00,noneedtopatchthedeviceagain.
*/ 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 *fromthecontroller.Ifitfailstoopenthematchingfirmware *patchfile,ittriestoopenthedefaultfirmwarepatchfile. *Ifnopatchfileisfound,allowthedevicetooperatewithout *apatch.
*/
fw = btintel_legacy_rom_get_fw(hdev, ver); if (!fw) goto complete;
fw_ptr = fw->data;
/* Enable the manufacturer mode of the controller. *Onlywhilethismodeisenabled,thedrivercandownloadthe *firmwarepatchdataandconfigurationparameters.
*/
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 *commandsanditsexpectedevents.Thefirstbyteindicatesthe *typeofthemessage,eitherHCIcommandorHCIevent. * *Itreadsthecommandanditsexpectedeventfromthefirmwarefile, *andsendtothecontroller.Once__hci_cmd_sync_ev()returns, *thereturnedeventiscomparedwiththeeventreadfromthefirmware *fileanditwillcontinueuntilallthemessagesaredownloadedto *thecontroller. * *Oncethefirmwarepatchingiscompletedsuccessfully, *themanufacturermodeisdisabledwithresetandactivatingthe *downloadedpatch. * *Ifthefirmwarepatchingfails,themanufacturermodeis *disabledwithresetanddeactivatingthepatch. * *Ifthedefaultpatchfileisused,noresetisdonewhendisabling *themanufacturer.
*/ 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 *withresetandactivatethedownloadedfirmwarepatches.
*/
err = btintel_exit_mfg(hdev, true, true); if (err) return err;
/* Need build number for downloaded fw patches in *everypower-onboot
*/
err = btintel_read_version(hdev, &new_ver); if (err) return err;
/* Patching failed. Disable the manufacturer mode with reset and *deactivatethedownloadedfirmwarepatches.
*/
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 *afewextraeventsthatareusefulduringgeneraloperation.
*/
btintel_set_event_mask_mfg(hdev, false);
btintel_check_bdaddr(hdev);
return0;
}
staticint btintel_download_wait(struct hci_dev *hdev, ktime_t calltime, int msec)
{
ktime_t delta, rettime; unsignedlonglong duration; int err;
btintel_set_flag(hdev, INTEL_FIRMWARE_LOADED);
bt_dev_info(hdev, "Waiting for firmware download to complete");
/* The bootloader will not indicate when the device is ready. This *isdonebytheoperationalfirmwaresendingbootupnotification. * *Bootingintooperationalfirmwareshouldnottakelongerthan *5second.Howeverifthathappens,thenjustfailthesetup *sincesomethingwentwrong.
*/
err = btintel_boot_wait(hdev, calltime, 5000); if (err == -ETIMEDOUT) {
btintel_reset_to_bootloader(hdev); goto exit_error;
}
if (hdev->bus == HCI_PCI) { /* In case of PCIe, after receiving bootup event, driver performs *D0entrybywriting0tosleepcontrolregister(check *btintel_pcie_recv_event()) *Firmwareackswithaliveinterruptindicatinghostisfullreadyto *performBToperation.LetswaitheretillINTEL_WAIT_FOR_D0 *bitiscleared.
*/
calltime = ktime_get();
err = btintel_boot_wait_d0(hdev, calltime, 2000);
}
/* The firmware variant determines if the device is in bootloader *modeorisrunningoperationalfirmware.Thevalue0x06identifies *thebootloaderandthevalue0x23identifiestheoperational *firmware. * *Whentheoperationalfirmwareisalreadypresent,thenonly *thecheckforvalidBluetoothdeviceaddressisneeded.This *determinesifthedevicewillbeaddedasconfiguredor *unconfiguredcontroller. * *ItisnotpossibletousetheSecureBootParametersinthis *casesincethatcommandisonlyavailableinbootloadermode.
*/ 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 *soversioncheckingiscurrentlypossible.
*/ switch (ver->hw_variant) { case0x0b: /* SfP */ case0x0c: /* WsP */ return0;
}
/* Proceed to download to check if the version matches */ goto download;
}
/* Read the secure boot parameters to identify the operating *detailsofthebootloader.
*/
err = btintel_read_boot_params(hdev, params); if (err) return err;
/* It is required that every single firmware fragment is acknowledged *withacommandcompleteevent.Ifthebootparametersindicate *thatthisbootloaderdoesnotsendthem,thenabortthesetup.
*/ 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 *alsobenovalidaddressfortheoperationalfirmware.
*/ if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) {
bt_dev_info(hdev, "No device address configured");
hci_set_quirk(hdev, HCI_QUIRK_INVALID_BDADDR);
}
download: /* With this Intel bootloader only the hardware variant and device *revisioninformationareusedtoselecttherightfirmwareforSfP *andWsP. * *Thefirmwarefilenameisibt-<hw_variant>-<dev_revid>.sfi. * *Currentlythesupportedhardwarevariantsare: *11(0x0b)foriBT3.0(LnP/SfP) *12(0x0c)foriBT3.5(WsP) * *ForThP/JfPandforfutureSKU's,theFWnamevariesbasedonHW *variant,HWrevisionandFWrevision,asthesearedependentonCNVi *andRFCombination. * *17(0x11)foriBT3.5(JfP) *18(0x12)foriBT3.5(ThP) * *Thefirmwarefilenameforthesewillbe *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); return0;
}
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 *FWdownload.
*/
btintel_reset_to_bootloader(hdev); goto done;
}
/* Before switching the device into operational mode and with that *bootingtheloadedfirmware,waitforthebootloadernotification *thatallfragmentshavebeensuccessfullyreceived. * *Whentheeventprocessingreceivesthenotification,thenthe *INTEL_DOWNLOADINGflagwillbecleared. * *Thefirmwareloadingshouldnottakelongerthan5seconds *andthusjusttimeoutifthathappensandfailthesetup *ofthisdevice.
*/
err = btintel_download_wait(hdev, calltime, 5000); if (err == -ETIMEDOUT)
btintel_reset_to_bootloader(hdev);
/* Set the default boot parameter to 0x0 and it is updated to *SKUspecificbootparameterafterreadingIntel_Write_Boot_Params *commandwhiledownloadingthefirmware.
*/
boot_param = 0x00000000;
btintel_set_flag(hdev, INTEL_BOOTLOADER);
err = btintel_download_fw(hdev, ver, ¶ms, &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;
if (err < 0) {
bt_dev_err(hdev, "Unsupported Intel firmware naming");
} else { /* Once the device is running in operational mode, it needs to *applythedeviceconfiguration(DDC)parameters. * *ThedevicecanworkwithoutDDCparameters,soevenifit *failstoloadthefile,noneedtofailthesetup.
*/
btintel_load_ddc_config(hdev, ddcname);
}
hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
/* 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 *afewextraeventsthatareusefulduringgeneraloperation.It *doesnotenableanydebuggingrelatedevents. * *Thedevicewillfunctioncorrectlywithouttheseeventsenabled *andthusnoneedtofailthesetup.
*/
btintel_set_event_mask(hdev, false);
/* Only Blazar product supports downloading of intermediate loader *image
*/ if (INTEL_HW_VARIANT(ver->cnvi_bt) >= 0x1e) {
u8 zero[BTINTEL_FWID_MAXLEN];
if (ver->img_type == BTINTEL_IMG_BOOTLOADER) {
format = "intel/ibt-%04x-%04x-iml.%s";
snprintf(fw_name, len, format, cnvi, cnvr, suffix); return;
}
memset(zero, 0, sizeof(zero));
/* ibt-<cnvi_top type+cnvi_top step>-<cnvr_top type+cnvr_top step-fw_id> */ if (memcmp(ver->fw_id, zero, sizeof(zero))) {
format = "intel/ibt-%04x-%04x-%s.%s";
snprintf(fw_name, len, format, cnvi, cnvr,
ver->fw_id, suffix); return;
} /* If firmware id is not present, fallback to legacy naming *convention
*/
} /* Fallback to legacy naming convention for other controllers *ibt-<cnvi_toptype+cnvi_topstep>-<cnvr_toptype+cnvr_topstep>
*/
format = "intel/ibt-%04x-%04x.%s";
snprintf(fw_name, len, format, cnvi, cnvr, suffix);
}
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 *FWdownload.
*/
btintel_reset_to_bootloader(hdev); goto done;
}
/* Before switching the device into operational mode and with that *bootingtheloadedfirmware,waitforthebootloadernotification *thatallfragmentshavebeensuccessfullyreceived. * *Whentheeventprocessingreceivesthenotification,thenthe *BTUSB_DOWNLOADINGflagwillbecleared. * *Thefirmwareloadingshouldnottakelongerthan5seconds *andthusjusttimeoutifthathappensandfailthesetup *ofthisdevice.
*/
err = btintel_download_wait(hdev, calltime, 5000); if (err == -ETIMEDOUT)
btintel_reset_to_bootloader(hdev);
staticint btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
{ /* Intel uses 1 as data path id for all the usecases */
*data_path_id = 1; return0;
}
staticint btintel_acpi_reset_method(struct hci_dev *hdev)
{ int ret = 0;
acpi_status status; union acpi_object *p, *ref; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
status = acpi_evaluate_object(ACPI_HANDLE(GET_HCIDEV_DEV(hdev)), "_PRR", NULL, &buffer); if (ACPI_FAILURE(status)) {
bt_dev_err(hdev, "Failed to run _PRR method");
ret = -ENODEV; return ret;
}
p = buffer.pointer;
if (p->package.count != 1 || p->type != ACPI_TYPE_PACKAGE) {
bt_dev_err(hdev, "Invalid arguments");
ret = -EINVAL; goto exit_on_error;
}
ref = &p->package.elements[0]; if (ref->type != ACPI_TYPE_LOCAL_REFERENCE) {
bt_dev_err(hdev, "Invalid object type: 0x%x", ref->type);
ret = -EINVAL; goto exit_on_error;
}
status = acpi_evaluate_object(ref->reference.handle, "_RST", NULL, NULL); if (ACPI_FAILURE(status)) {
bt_dev_err(hdev, "Failed to run_RST method");
ret = -ENODEV; goto exit_on_error;
}
if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
BIT(DSM_SET_WDISABLE2_DELAY))) {
bt_dev_err(hdev, "No dsm support to set reset delay"); return;
}
argv4.integer.type = ACPI_TYPE_INTEGER; /* delay required to toggle BT power */
argv4.integer.value = 160;
obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
DSM_SET_WDISABLE2_DELAY, &argv4); if (!obj) {
bt_dev_err(hdev, "Failed to call dsm to set reset delay"); return;
}
ACPI_FREE(obj);
}
if (!acpi_check_dsm(handle, &btintel_guid_dsm, 0,
DSM_SET_RESET_METHOD)) {
bt_dev_warn(hdev, "No support for dsm to set reset method"); return;
}
argv4.buffer.type = ACPI_TYPE_BUFFER;
argv4.buffer.length = sizeof(reset_payload);
argv4.buffer.pointer = reset_payload;
obj = acpi_evaluate_dsm(handle, &btintel_guid_dsm, 0,
DSM_SET_RESET_METHOD, &argv4); if (!obj) {
bt_dev_err(hdev, "Failed to call dsm to set reset method"); return;
}
ACPI_FREE(obj);
data->acpi_reset_method = btintel_acpi_reset_method;
}
cnvi = ver->cnvi_top & 0xfff; /* DSBR command needs to be sent for, *1.BlazarIorBlazarIW+B0stepproductinIMLimage. *2.GalePeak2orBlazarUinOPimage. *3.ScorpiousPeakinIMLimage.
*/
switch (cnvi) { case BTINTEL_CNVI_BLAZARI: case BTINTEL_CNVI_BLAZARIW: if (ver->img_type == BTINTEL_IMG_IML &&
INTEL_CNVX_TOP_STEP(ver->cnvi_top) == 0x01) break; return0; case BTINTEL_CNVI_GAP: case BTINTEL_CNVI_BLAZARU: if (ver->img_type == BTINTEL_IMG_OP &&
hdev->bus == HCI_USB) break; return0; case BTINTEL_CNVI_SCP: if (ver->img_type == BTINTEL_IMG_IML) break; return0; default: return0;
}
/* Apply only if it is enabled in BIOS */ if (sar.bt_sar_bios != 1) {
bt_dev_dbg(hdev, "Bluetooth SAR is not enabled");
ret = -EOPNOTSUPP; goto error;
}
int btintel_bootloader_setup_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver)
{
u32 boot_param; char ddcname[64]; int err; struct intel_version_tlv new_ver;
bt_dev_dbg(hdev, "");
/* Set the default boot parameter to 0x0 and it is updated to *SKUspecificbootparameterafterreadingIntel_Write_Boot_Params *commandwhiledownloadingthefirmware.
*/
boot_param = 0x00000000;
/* In case of PCIe, this function might get called multiple times with *samehdevinstanceifthereisanyerroronfirmwaredownload. *Needtoclearstalebitsofpreviousfirmwaredownloadattempt.
*/ for (int i = 0; i < __INTEL_NUM_FLAGS; i++)
btintel_clear_flag(hdev, i);
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 == BTINTEL_IMG_OP) goto finish;
err = btintel_boot(hdev, boot_param); if (err) return err;
err = btintel_read_version_tlv(hdev, ver); if (err) return err;
/* set drive strength of BRI response */
err = btintel_set_dsbr(hdev, ver); if (err) {
bt_dev_err(hdev, "Failed to send dsbr command (%d)", err); return err;
}
/* If image type returned is BTINTEL_IMG_IML, then controller supports *intermediateloaderimage
*/ if (ver->img_type == BTINTEL_IMG_IML) {
err = btintel_prepare_fw_download_tlv(hdev, ver, &boot_param); if (err) return err;
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 *applythedeviceconfiguration(DDC)parameters. * *ThedevicecanworkwithoutDDCparameters,soevenifit *failstoloadthefile,noneedtofailthesetup.
*/
btintel_load_ddc_config(hdev, ddcname);
/* Read supported use cases and set callbacks to fetch datapath id */
btintel_configure_offload(hdev);
hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);
/* Send sar values to controller */
btintel_set_specific_absorption_rate(hdev, ver);
/* Set PPAG feature */
btintel_set_ppag(hdev, ver);
/* 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 *afewextraeventsthatareusefulduringgeneraloperation.It *doesnotenableanydebuggingrelatedevents. * *Thedevicewillfunctioncorrectlywithouttheseeventsenabled *andthusnoneedtofailthesetup.
*/
btintel_set_event_mask(hdev, false);
/* The some controllers have a bug with the first HCI command sent to it *returningnumberofcompletedcommandsaszero.Thiswouldstallthe *commandprocessingintheBluetoothcore. * *Asaworkaround,sendHCIResetcommandfirstwhichwillresetthe *numberofcompletedcommandsandallownormalcommandprocessing *fromnowon. * *RegardingtheINTEL_BROKEN_SHUTDOWN_LEDflag,thesedevicesmaybe *intheSW_RFKILLONstateasaworkaroundoffixingLEDissueduring *theshutdown()procedure,andoncethedeviceisinSW_RFKILLON *state,theonlywaytoexitoutofitissendingtheHCI_Reset *command.
*/ if (btintel_test_flag(hdev, INTEL_BROKEN_INITIAL_NCMD) ||
btintel_test_flag(hdev, INTEL_BROKEN_SHUTDOWN_LED)) {
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 *changedeventhoughtheOCFforHCI_Intel_Read_Versioncommand *remainssame.Thelegacydevicescanhandleevenifthe *commandhasaparameterandreturnsacorrectversioninformation. *So,itusesnewformattosupportbothlegacyandnewformat.
*/
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 */
hci_set_quirk(hdev, HCI_QUIRK_STRICT_DUPLICATE_FILTER);
hci_set_quirk(hdev, HCI_QUIRK_SIMULTANEOUS_DISCOVERY);
hci_set_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_DIAG);
/* Set up the quality report callback for Intel devices */
hdev->set_quality_report = btintel_set_quality_report;
/* 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 *loadingmethod. * *Thischeckhasbeenputinplacetoensurecorrectforward *compatibilityoptionswhennewerhardwarevariantscome *along.
*/ switch (ver.hw_variant) { case0x07: /* WP */ case0x08: /* StP */ /* Legacy ROM product */
btintel_set_flag(hdev, INTEL_ROM_LEGACY);
/* Apply the device specific HCI quirks * *WBSforSdP-FortheLegacyROMproducts,onlySdP *supportstheWBS.Buttheversioninformationisnot *enoughtouseherebecausetheStP2andSdPhavesame *hw_variantandfw_variant.So,thisflagissetby *thetransportdriver(btusb)basedontheHWinfo *(idProduct)
*/ if (!btintel_test_flag(hdev,
INTEL_ROM_LEGACY_NO_WBS_SUPPORT))
hci_set_quirk(hdev,
HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED);
/* memset ver_tlv to start with clean state as few fields are exclusive *tobootloadermodeandarenotpopulatedinoperationalmode
*/
memset(&ver_tlv, 0, sizeof(ver_tlv)); /* 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;
}
/* Apply the device specific HCI quirks * *AllLegacybootloaderdevicessupportWBS
*/
hci_set_quirk(hdev, HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED);
/* These variants don't seem to support LE Coded PHY */
hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_CODED);
/* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev, ver.hw_variant);
err = btintel_bootloader_setup(hdev, &ver);
btintel_register_devcoredump_support(hdev); break; case0x18: /* GfP2 */ case0x1c: /* GaP */ /* Re-classify packet type for controllers with LE audio */
hdev->classify_pkt_type = btintel_classify_pkt_type;
fallthrough; case0x17: case0x19: case0x1b: case0x1d: case0x1e: case0x1f: case0x22: /* Display version information of TLV type */
btintel_version_info_tlv(hdev, &ver_tlv);
/* Apply the device specific HCI quirks for TLV based devices * *AllTLVbaseddevicessupportWBS
*/
hci_set_quirk(hdev, HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED);
/* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev,
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
btintel_set_dsm_reset_method(hdev, &ver_tlv);
err = btintel_bootloader_setup_tlv(hdev, &ver_tlv); if (err) goto exit_error;
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 *weretriggered.Thiswillhelptosavepowerandmaintainthe *syncb/wHostandcontroller
*/
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 *downorBTradioisturnedoff,whichtakes5secondstoBTLED *goesoff.Asaworkaround,sendsHCI_Intel_SW_RFKILLtoputthe *deviceintheRFKILLONstatewhichturnsofftheBTLEDimmediately.
*/ if (btintel_test_flag(hdev, INTEL_BROKEN_SHUTDOWN_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);
}
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);
MODULE_LICENSE("GPL");
MODULE_FIRMWARE("intel/ibt-11-5.sfi");
MODULE_FIRMWARE("intel/ibt-11-5.ddc");
MODULE_FIRMWARE("intel/ibt-12-16.sfi");
MODULE_FIRMWARE("intel/ibt-12-16.ddc");
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.74Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.