4106 lines · 107.1 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 <linux/string_choices.h>#include <linux/acpi.h>#include <acpi/acpi_bus.h>#include <linux/unaligned.h>#include <linux/efi.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 BTINTEL_EFI_DSBR	L"UefiCnvCommonDSBR" enum {	DSM_SET_WDISABLE2_DELAY = 1,	DSM_SET_RESET_METHOD = 3,}; /* Hybrid ECDSA + LMS */#define BTINTEL_RSA_HEADER_VER		0x00010000#define BTINTEL_ECDSA_HEADER_VER	0x00020000#define BTINTEL_HYBRID_HEADER_VER	0x00069700#define BTINTEL_ECDSA_OFFSET		128#define BTINTEL_CSS_HEADER_SIZE		128#define BTINTEL_ECDSA_PUB_KEY_SIZE	96#define BTINTEL_ECDSA_SIG_SIZE		96#define BTINTEL_LMS_OFFSET		320#define BTINTEL_LMS_PUB_KEY_SIZE	52#define BTINTEL_LMS_SIG_SIZE		1744#define BTINTEL_CMD_BUFFER_OFFSET	2116 #define BTINTEL_BT_DOMAIN		0x12#define BTINTEL_SAR_LEGACY		0#define BTINTEL_SAR_INC_PWR		1#define BTINTEL_SAR_REV2		2#define BTINTEL_SAR_INC_PWR_SUPPORTED	0 #define CMD_WRITE_BOOT_PARAMS	0xfc0estruct cmd_write_boot_params {	__le32 boot_addr;	u8  fw_build_num;	u8  fw_build_ww;	u8  fw_build_yy;} __packed; static struct {	const char *driver_name;	u8         hw_variant;	u32        fw_build_num;} coredump_info; const guid_t btintel_guid_dsm =	GUID_INIT(0xaa10f4e0, 0x81ac, 0x4233,		  0xab, 0xf6, 0x3b, 0x2a, 0xc5, 0x0e, 0x28, 0xd9);EXPORT_SYMBOL_GPL(btintel_guid_dsm); 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);		hci_set_quirk(hdev, HCI_QUIRK_INVALID_BDADDR);	} 	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); static 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;} 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); static 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;} static int btintel_set_diag_combined(struct hci_dev *hdev, bool enable){	int ret; 	/* Legacy ROM device needs to be in the manufacturer mode to apply	 * diagnostic setting	 *	 * This flag is set after reading the Intel version.	 */	if (btintel_test_flag(hdev, INTEL_ROM_LEGACY))		ret = btintel_set_diag_mfg(hdev, enable);	else		ret = btintel_set_diag(hdev, enable); 	return ret;} 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); 	hci_req_sync_lock(hdev); 	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));		goto unlock;	}	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));		goto unlock;	} 	if (skb->len != 13) {		bt_dev_err(hdev, "Exception info size mismatch");		kfree_skb(skb);		goto unlock;	} 	bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1)); 	kfree_skb(skb); unlock:	hci_req_sync_unlock(hdev);}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 0x07:	/* WP - Legacy ROM */	case 0x08:	/* StP - Legacy ROM */	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 0x01:		variant = "Legacy ROM 2.5";		break;	case 0x06:		variant = "Bootloader";		break;	case 0x22:		variant = "Legacy ROM 2.x";		break;	case 0x23:		variant = "Firmware";		break;	default:		bt_dev_err(hdev, "Unsupported firmware variant(%02x)", ver->fw_variant);		return -EINVAL;	} 	coredump_info.hw_variant = ver->hw_variant;	coredump_info.fw_build_num = ver->fw_build_num; 	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); static 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;} 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_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 || 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 */

Lines 1–500 of 4106.