1282 lines · 31.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * *  Bluetooth support for Intel devices * *  Copyright (C) 2015  Intel Corporation */ #include <linux/module.h>#include <linux/firmware.h>#include <linux/regmap.h>#include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h>#include <net/bluetooth/hci_core.h> #include "btintel.h" #define VERSION "0.1" #define BDADDR_INTEL		(&(bdaddr_t){{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})#define RSA_HEADER_LEN		644#define CSS_HEADER_OFFSET	8#define ECDSA_OFFSET		644#define ECDSA_HEADER_LEN	320 #define CMD_WRITE_BOOT_PARAMS	0xfc0estruct cmd_write_boot_params {	u32 boot_addr;	u8  fw_build_num;	u8  fw_build_ww;	u8  fw_build_yy;} __packed; int btintel_check_bdaddr(struct hci_dev *hdev){	struct hci_rp_read_bd_addr *bda;	struct sk_buff *skb; 	skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL,			     HCI_INIT_TIMEOUT);	if (IS_ERR(skb)) {		int err = PTR_ERR(skb);		bt_dev_err(hdev, "Reading Intel device address failed (%d)",			   err);		return err;	} 	if (skb->len != sizeof(*bda)) {		bt_dev_err(hdev, "Intel device address length mismatch");		kfree_skb(skb);		return -EIO;	} 	bda = (struct hci_rp_read_bd_addr *)skb->data; 	/* For some Intel based controllers, the default Bluetooth device	 * address 00:03:19:9E:8B:00 can be found. These controllers are	 * fully operational, but have the danger of duplicate addresses	 * and that in turn can cause problems with Bluetooth operation.	 */	if (!bacmp(&bda->bdaddr, BDADDR_INTEL)) {		bt_dev_err(hdev, "Found Intel default device address (%pMR)",			   &bda->bdaddr);		set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);	} 	kfree_skb(skb); 	return 0;}EXPORT_SYMBOL_GPL(btintel_check_bdaddr); int btintel_enter_mfg(struct hci_dev *hdev){	static const u8 param[] = { 0x01, 0x00 };	struct sk_buff *skb; 	skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT);	if (IS_ERR(skb)) {		bt_dev_err(hdev, "Entering manufacturer mode failed (%ld)",			   PTR_ERR(skb));		return PTR_ERR(skb);	}	kfree_skb(skb); 	return 0;}EXPORT_SYMBOL_GPL(btintel_enter_mfg); int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched){	u8 param[] = { 0x00, 0x00 };	struct sk_buff *skb; 	/* The 2nd command parameter specifies the manufacturing exit method:	 * 0x00: Just disable the manufacturing mode (0x00).	 * 0x01: Disable manufacturing mode and reset with patches deactivated.	 * 0x02: Disable manufacturing mode and reset with patches activated.	 */	if (reset)		param[1] |= patched ? 0x02 : 0x01; 	skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT);	if (IS_ERR(skb)) {		bt_dev_err(hdev, "Exiting manufacturer mode failed (%ld)",			   PTR_ERR(skb));		return PTR_ERR(skb);	}	kfree_skb(skb); 	return 0;}EXPORT_SYMBOL_GPL(btintel_exit_mfg); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr){	struct sk_buff *skb;	int err; 	skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT);	if (IS_ERR(skb)) {		err = PTR_ERR(skb);		bt_dev_err(hdev, "Changing Intel device address failed (%d)",			   err);		return err;	}	kfree_skb(skb); 	return 0;}EXPORT_SYMBOL_GPL(btintel_set_bdaddr); int btintel_set_diag(struct hci_dev *hdev, bool enable){	struct sk_buff *skb;	u8 param[3];	int err; 	if (enable) {		param[0] = 0x03;		param[1] = 0x03;		param[2] = 0x03;	} else {		param[0] = 0x00;		param[1] = 0x00;		param[2] = 0x00;	} 	skb = __hci_cmd_sync(hdev, 0xfc43, 3, param, HCI_INIT_TIMEOUT);	if (IS_ERR(skb)) {		err = PTR_ERR(skb);		if (err == -ENODATA)			goto done;		bt_dev_err(hdev, "Changing Intel diagnostic mode failed (%d)",			   err);		return err;	}	kfree_skb(skb); done:	btintel_set_event_mask(hdev, enable);	return 0;}EXPORT_SYMBOL_GPL(btintel_set_diag); int 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;}EXPORT_SYMBOL_GPL(btintel_set_diag_mfg); void btintel_hw_error(struct hci_dev *hdev, u8 code){	struct sk_buff *skb;	u8 type = 0x00; 	bt_dev_err(hdev, "Hardware error 0x%2.2x", code); 	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);	if (IS_ERR(skb)) {		bt_dev_err(hdev, "Reset after hardware error failed (%ld)",			   PTR_ERR(skb));		return;	}	kfree_skb(skb); 	skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);	if (IS_ERR(skb)) {		bt_dev_err(hdev, "Retrieving Intel exception info failed (%ld)",			   PTR_ERR(skb));		return;	} 	if (skb->len != 13) {		bt_dev_err(hdev, "Exception info size mismatch");		kfree_skb(skb);		return;	} 	bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1)); 	kfree_skb(skb);}EXPORT_SYMBOL_GPL(btintel_hw_error); int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver){	const char *variant; 	/* The hardware platform number has a fixed value of 0x37 and	 * for now only accept this single value.	 */	if (ver->hw_platform != 0x37) {		bt_dev_err(hdev, "Unsupported Intel hardware platform (%u)",			   ver->hw_platform);		return -EINVAL;	} 	/* 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 0x0b:      /* SfP */	case 0x0c:      /* WsP */	case 0x11:      /* JfP */	case 0x12:      /* ThP */	case 0x13:      /* HrP */	case 0x14:      /* CcP */		break;	default:		bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",			   ver->hw_variant);		return -EINVAL;	} 	switch (ver->fw_variant) {	case 0x06:		variant = "Bootloader";		break;	case 0x23:		variant = "Firmware";		break;	default:		bt_dev_err(hdev, "Unsupported firmware variant(%02x)", ver->fw_variant);		return -EINVAL;	} 	bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u",		    variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,		    ver->fw_build_num, ver->fw_build_ww,		    2000 + ver->fw_build_yy); 	return 0;}EXPORT_SYMBOL_GPL(btintel_version_info); int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,			const void *param){	while (plen > 0) {		struct sk_buff *skb;		u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; 		cmd_param[0] = fragment_type;		memcpy(cmd_param + 1, param, fragment_len); 		skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,				     cmd_param, HCI_INIT_TIMEOUT);		if (IS_ERR(skb))			return PTR_ERR(skb); 		kfree_skb(skb); 		plen -= fragment_len;		param += fragment_len;	} 	return 0;}EXPORT_SYMBOL_GPL(btintel_secure_send); int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name){	const struct firmware *fw;	struct sk_buff *skb;	const u8 *fw_ptr;	int err; 	err = request_firmware_direct(&fw, ddc_name, &hdev->dev);	if (err < 0) {		bt_dev_err(hdev, "Failed to load Intel DDC file %s (%d)",			   ddc_name, err);		return err;	} 	bt_dev_info(hdev, "Found Intel DDC parameters: %s", ddc_name); 	fw_ptr = fw->data; 	/* DDC file contains one or more DDC structure which has	 * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2).	 */	while (fw->size > fw_ptr - fw->data) {		u8 cmd_plen = fw_ptr[0] + sizeof(u8); 		skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr,				     HCI_INIT_TIMEOUT);		if (IS_ERR(skb)) {			bt_dev_err(hdev, "Failed to send Intel_Write_DDC (%ld)",				   PTR_ERR(skb));			release_firmware(fw);			return PTR_ERR(skb);		} 		fw_ptr += cmd_plen;		kfree_skb(skb);	} 	release_firmware(fw); 	bt_dev_info(hdev, "Applying Intel DDC parameters completed"); 	return 0;}EXPORT_SYMBOL_GPL(btintel_load_ddc_config); int btintel_set_event_mask(struct hci_dev *hdev, bool debug){	u8 mask[8] = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };	struct sk_buff *skb;	int err; 	if (debug)		mask[1] |= 0x62; 	skb = __hci_cmd_sync(hdev, 0xfc52, 8, mask, HCI_INIT_TIMEOUT);	if (IS_ERR(skb)) {		err = PTR_ERR(skb);		bt_dev_err(hdev, "Setting Intel event mask failed (%d)", err);		return err;	}	kfree_skb(skb); 	return 0;}EXPORT_SYMBOL_GPL(btintel_set_event_mask); int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug){	int err, ret; 	err = btintel_enter_mfg(hdev);	if (err)		return err; 	ret = btintel_set_event_mask(hdev, debug); 	err = btintel_exit_mfg(hdev, false, false);	if (err)		return err; 	return ret;}EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg); int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver){	struct sk_buff *skb; 	skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_CMD_TIMEOUT);	if (IS_ERR(skb)) {		bt_dev_err(hdev, "Reading Intel version information failed (%ld)",			   PTR_ERR(skb));		return PTR_ERR(skb);	} 	if (skb->len != sizeof(*ver)) {		bt_dev_err(hdev, "Intel version event size mismatch");		kfree_skb(skb);		return -EILSEQ;	} 	memcpy(ver, skb->data, sizeof(*ver)); 	kfree_skb(skb); 	return 0;}EXPORT_SYMBOL_GPL(btintel_read_version); int btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version){	const char *variant; 	/* The hardware platform number has a fixed value of 0x37 and	 * for now only accept this single value.	 */	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;	} 	/* 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(version->cnvi_bt)) {	case 0x17:	/* TyP */	case 0x18:	/* Slr */	case 0x19:	/* Slr-F */		break;	default:		bt_dev_err(hdev, "Unsupported Intel hardware variant (0x%x)",			   INTEL_HW_VARIANT(version->cnvi_bt));		return -EINVAL;	} 	switch (version->img_type) {	case 0x01:		variant = "Bootloader";		/* 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 (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",			    version->secure_boot ? "enabled" : "disabled");		bt_dev_info(hdev, "OTP lock is %s",			    version->otp_lock ? "enabled" : "disabled");		bt_dev_info(hdev, "API lock is %s",			    version->api_lock ? "enabled" : "disabled");		bt_dev_info(hdev, "Debug lock is %s",			    version->debug_lock ? "enabled" : "disabled");		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 0x03:		variant = "Firmware";		break;	default:		bt_dev_err(hdev, "Unsupported image type(%02x)", version->img_type);		return -EINVAL;	} 	bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,		    2000 + (version->timestamp >> 8), version->timestamp & 0xff,		    version->build_type, version->build_num); 	return 0;}EXPORT_SYMBOL_GPL(btintel_version_info_tlv); int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *version){	struct sk_buff *skb;	const u8 param[1] = { 0xFF }; 	if (!version)		return -EINVAL; 	skb = __hci_cmd_sync(hdev, 0xfc05, 1, param, HCI_CMD_TIMEOUT);	if (IS_ERR(skb)) {		bt_dev_err(hdev, "Reading Intel version information failed (%ld)",			   PTR_ERR(skb));		return PTR_ERR(skb);	} 

Lines 1–500 of 1282.