in btintel.c [2341:2569]
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.
*
* Regarding the INTEL_BROKEN_SHUTDOWN_LED flag, these devices maybe
* in the SW_RFKILL ON state as a workaround of fixing LED issue during
* the shutdown() procedure, and once the device is in SW_RFKILL ON
* state, the only way to exit out of it is sending the HCI_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
* 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);
/* 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
* 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);
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;
}
/* memset ver_tlv to start with clean state as few fields are exclusive
* to bootloader mode and are not populated in operational mode
*/
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;
}
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 starting from JfP,
* the operational firmware supports both old and TLV based
* HCI_Intel_Read_Version command based on the command
* parameter.
*
* For upgrading firmware case, the TLV based version cannot
* be used because the firmware filename for legacy bootloader
* is based on the old format.
*
* 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;
/* 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;
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;
}