Commit e1be4b59 authored by David S. Miller's avatar David S. Miller

Merge branch 'for-upstream' of...

Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

Johan Hedberg says:

====================
pull request: bluetooth-next 2020-12-07

Here's the main bluetooth-next pull request for the 5.11 kernel.

 - Updated Bluetooth entries in MAINTAINERS to include Luiz von Dentz
 - Added support for Realtek 8822CE and 8852A devices
 - Added support for MediaTek MT7615E device
 - Improved workarounds for fake CSR devices
 - Fix Bluetooth qualification test case L2CAP/COS/CFD/BV-14-C
 - Fixes for LL Privacy support
 - Enforce 16 byte encryption key size for FIPS security level
 - Added new mgmt commands for extended advertising support
 - Multiple other smaller fixes & improvements

Please let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 97f8841e 02be5f13
...@@ -3194,8 +3194,9 @@ F: drivers/mtd/devices/block2mtd.c ...@@ -3194,8 +3194,9 @@ F: drivers/mtd/devices/block2mtd.c
BLUETOOTH DRIVERS BLUETOOTH DRIVERS
M: Marcel Holtmann <marcel@holtmann.org> M: Marcel Holtmann <marcel@holtmann.org>
M: Johan Hedberg <johan.hedberg@gmail.com> M: Johan Hedberg <johan.hedberg@gmail.com>
M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
L: linux-bluetooth@vger.kernel.org L: linux-bluetooth@vger.kernel.org
S: Maintained S: Supported
W: http://www.bluez.org/ W: http://www.bluez.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
...@@ -3204,8 +3205,9 @@ F: drivers/bluetooth/ ...@@ -3204,8 +3205,9 @@ F: drivers/bluetooth/
BLUETOOTH SUBSYSTEM BLUETOOTH SUBSYSTEM
M: Marcel Holtmann <marcel@holtmann.org> M: Marcel Holtmann <marcel@holtmann.org>
M: Johan Hedberg <johan.hedberg@gmail.com> M: Johan Hedberg <johan.hedberg@gmail.com>
M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
L: linux-bluetooth@vger.kernel.org L: linux-bluetooth@vger.kernel.org
S: Maintained S: Supported
W: http://www.bluez.org/ W: http://www.bluez.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git
......
...@@ -437,31 +437,38 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver ...@@ -437,31 +437,38 @@ int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver
tlv = (struct intel_tlv *)skb->data; tlv = (struct intel_tlv *)skb->data;
switch (tlv->type) { switch (tlv->type) {
case INTEL_TLV_CNVI_TOP: case INTEL_TLV_CNVI_TOP:
version->cnvi_top = get_unaligned_le32(tlv->val); version->cnvi_top =
__le32_to_cpu(get_unaligned_le32(tlv->val));
break; break;
case INTEL_TLV_CNVR_TOP: case INTEL_TLV_CNVR_TOP:
version->cnvr_top = get_unaligned_le32(tlv->val); version->cnvr_top =
__le32_to_cpu(get_unaligned_le32(tlv->val));
break; break;
case INTEL_TLV_CNVI_BT: case INTEL_TLV_CNVI_BT:
version->cnvi_bt = get_unaligned_le32(tlv->val); version->cnvi_bt =
__le32_to_cpu(get_unaligned_le32(tlv->val));
break; break;
case INTEL_TLV_CNVR_BT: case INTEL_TLV_CNVR_BT:
version->cnvr_bt = get_unaligned_le32(tlv->val); version->cnvr_bt =
__le32_to_cpu(get_unaligned_le32(tlv->val));
break; break;
case INTEL_TLV_DEV_REV_ID: case INTEL_TLV_DEV_REV_ID:
version->dev_rev_id = get_unaligned_le16(tlv->val); version->dev_rev_id =
__le16_to_cpu(get_unaligned_le16(tlv->val));
break; break;
case INTEL_TLV_IMAGE_TYPE: case INTEL_TLV_IMAGE_TYPE:
version->img_type = tlv->val[0]; version->img_type = tlv->val[0];
break; break;
case INTEL_TLV_TIME_STAMP: case INTEL_TLV_TIME_STAMP:
version->timestamp = get_unaligned_le16(tlv->val); version->timestamp =
__le16_to_cpu(get_unaligned_le16(tlv->val));
break; break;
case INTEL_TLV_BUILD_TYPE: case INTEL_TLV_BUILD_TYPE:
version->build_type = tlv->val[0]; version->build_type = tlv->val[0];
break; break;
case INTEL_TLV_BUILD_NUM: case INTEL_TLV_BUILD_NUM:
version->build_num = get_unaligned_le32(tlv->val); version->build_num =
__le32_to_cpu(get_unaligned_le32(tlv->val));
break; break;
case INTEL_TLV_SECURE_BOOT: case INTEL_TLV_SECURE_BOOT:
version->secure_boot = tlv->val[0]; version->secure_boot = tlv->val[0];
......
...@@ -132,6 +132,12 @@ struct intel_debug_features { ...@@ -132,6 +132,12 @@ struct intel_debug_features {
__u8 page1[16]; __u8 page1[16];
} __packed; } __packed;
#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
#define INTEL_CNVX_TOP_STEP(cnvx_top) (((cnvx_top) & 0x0f000000) >> 24)
#define INTEL_CNVX_TOP_PACK_SWAB(t, s) __swab16(((__u16)(((t) << 4) | (s))))
#if IS_ENABLED(CONFIG_BT_INTEL) #if IS_ENABLED(CONFIG_BT_INTEL)
int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_check_bdaddr(struct hci_dev *hdev);
......
...@@ -704,7 +704,7 @@ static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname) ...@@ -704,7 +704,7 @@ static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
err = mtk_hci_wmt_sync(hdev, &wmt_params); err = mtk_hci_wmt_sync(hdev, &wmt_params);
if (err < 0) { if (err < 0) {
bt_dev_err(hdev, "Failed to power on data RAM (%d)", err); bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
return err; goto free_fw;
} }
fw_ptr = fw->data; fw_ptr = fw->data;
......
...@@ -14,12 +14,11 @@ ...@@ -14,12 +14,11 @@
#define VERSION "0.1" #define VERSION "0.1"
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version, int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
enum qca_btsoc_type soc_type) enum qca_btsoc_type soc_type)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct edl_event_hdr *edl; struct edl_event_hdr *edl;
struct qca_btsoc_version *ver;
char cmd; char cmd;
int err = 0; int err = 0;
u8 event_type = HCI_EV_VENDOR; u8 event_type = HCI_EV_VENDOR;
...@@ -70,9 +69,9 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version, ...@@ -70,9 +69,9 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
} }
if (soc_type >= QCA_WCN3991) if (soc_type >= QCA_WCN3991)
memmove(&edl->data, &edl->data[1], sizeof(*ver)); memcpy(ver, edl->data + 1, sizeof(*ver));
else
ver = (struct qca_btsoc_version *)(edl->data); memcpy(ver, &edl->data, sizeof(*ver));
bt_dev_info(hdev, "QCA Product ID :0x%08x", bt_dev_info(hdev, "QCA Product ID :0x%08x",
le32_to_cpu(ver->product_id)); le32_to_cpu(ver->product_id));
...@@ -83,13 +82,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version, ...@@ -83,13 +82,7 @@ int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version,
bt_dev_info(hdev, "QCA Patch Version:0x%08x", bt_dev_info(hdev, "QCA Patch Version:0x%08x",
le16_to_cpu(ver->patch_ver)); le16_to_cpu(ver->patch_ver));
/* QCA chipset version can be decided by patch and SoC if (ver->soc_id == 0 || ver->rom_ver == 0)
* version, combination with upper 2 bytes from SoC
* and lower 2 bytes from patch will be used.
*/
*soc_version = (le32_to_cpu(ver->soc_id) << 16) |
(le16_to_cpu(ver->rom_ver) & 0x0000ffff);
if (*soc_version == 0)
err = -EILSEQ; err = -EILSEQ;
out: out:
...@@ -446,15 +439,20 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) ...@@ -446,15 +439,20 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome);
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
enum qca_btsoc_type soc_type, u32 soc_ver, enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
const char *firmware_name) const char *firmware_name)
{ {
struct qca_fw_config config; struct qca_fw_config config;
int err; int err;
u8 rom_ver = 0; u8 rom_ver = 0;
u32 soc_ver;
bt_dev_dbg(hdev, "QCA setup on UART"); bt_dev_dbg(hdev, "QCA setup on UART");
soc_ver = get_soc_ver(ver.soc_id, ver.rom_ver);
bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
config.user_baud_rate = baudrate; config.user_baud_rate = baudrate;
/* Download rampatch file */ /* Download rampatch file */
...@@ -491,9 +489,15 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, ...@@ -491,9 +489,15 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
if (firmware_name) if (firmware_name)
snprintf(config.fwname, sizeof(config.fwname), snprintf(config.fwname, sizeof(config.fwname),
"qca/%s", firmware_name); "qca/%s", firmware_name);
else if (qca_is_wcn399x(soc_type)) else if (qca_is_wcn399x(soc_type)) {
snprintf(config.fwname, sizeof(config.fwname), if (ver.soc_id == QCA_WCN3991_SOC_ID) {
"qca/crnv%02x.bin", rom_ver); snprintf(config.fwname, sizeof(config.fwname),
"qca/crnv%02xu.bin", rom_ver);
} else {
snprintf(config.fwname, sizeof(config.fwname),
"qca/crnv%02x.bin", rom_ver);
}
}
else if (soc_type == QCA_QCA6390) else if (soc_type == QCA_QCA6390)
snprintf(config.fwname, sizeof(config.fwname), snprintf(config.fwname, sizeof(config.fwname),
"qca/htnv%02x.bin", rom_ver); "qca/htnv%02x.bin", rom_ver);
......
...@@ -34,6 +34,18 @@ ...@@ -34,6 +34,18 @@
#define QCA_HCI_CC_OPCODE 0xFC00 #define QCA_HCI_CC_OPCODE 0xFC00
#define QCA_HCI_CC_SUCCESS 0x00 #define QCA_HCI_CC_SUCCESS 0x00
#define QCA_WCN3991_SOC_ID (0x40014320)
/* QCA chipset version can be decided by patch and SoC
* version, combination with upper 2 bytes from SoC
* and lower 2 bytes from patch will be used.
*/
#define get_soc_ver(soc_id, rom_ver) \
((le32_to_cpu(soc_id) << 16) | (le16_to_cpu(rom_ver)))
#define QCA_FW_BUILD_VER_LEN 255
enum qca_baudrate { enum qca_baudrate {
QCA_BAUDRATE_115200 = 0, QCA_BAUDRATE_115200 = 0,
QCA_BAUDRATE_57600, QCA_BAUDRATE_57600,
...@@ -136,9 +148,9 @@ enum qca_btsoc_type { ...@@ -136,9 +148,9 @@ enum qca_btsoc_type {
int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr); int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
enum qca_btsoc_type soc_type, u32 soc_ver, enum qca_btsoc_type soc_type, struct qca_btsoc_version ver,
const char *firmware_name); const char *firmware_name);
int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version, int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
enum qca_btsoc_type); enum qca_btsoc_type);
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev); int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
...@@ -155,13 +167,15 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad ...@@ -155,13 +167,15 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad
} }
static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
enum qca_btsoc_type soc_type, u32 soc_ver, enum qca_btsoc_type soc_type,
struct qca_btsoc_version ver,
const char *firmware_name) const char *firmware_name)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version, static inline int qca_read_soc_version(struct hci_dev *hdev,
struct qca_btsoc_version *ver,
enum qca_btsoc_type) enum qca_btsoc_type)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
......
...@@ -18,23 +18,25 @@ ...@@ -18,23 +18,25 @@
#define VERSION "0.1" #define VERSION "0.1"
#define RTL_EPATCH_SIGNATURE "Realtech" #define RTL_EPATCH_SIGNATURE "Realtech"
#define RTL_ROM_LMP_3499 0x3499
#define RTL_ROM_LMP_8723A 0x1200 #define RTL_ROM_LMP_8723A 0x1200
#define RTL_ROM_LMP_8723B 0x8723 #define RTL_ROM_LMP_8723B 0x8723
#define RTL_ROM_LMP_8723D 0x8873
#define RTL_ROM_LMP_8821A 0x8821 #define RTL_ROM_LMP_8821A 0x8821
#define RTL_ROM_LMP_8761A 0x8761 #define RTL_ROM_LMP_8761A 0x8761
#define RTL_ROM_LMP_8822B 0x8822 #define RTL_ROM_LMP_8822B 0x8822
#define RTL_ROM_LMP_8852A 0x8852
#define RTL_CONFIG_MAGIC 0x8723ab55 #define RTL_CONFIG_MAGIC 0x8723ab55
#define IC_MATCH_FL_LMPSUBV (1 << 0) #define IC_MATCH_FL_LMPSUBV (1 << 0)
#define IC_MATCH_FL_HCIREV (1 << 1) #define IC_MATCH_FL_HCIREV (1 << 1)
#define IC_MATCH_FL_HCIVER (1 << 2) #define IC_MATCH_FL_HCIVER (1 << 2)
#define IC_MATCH_FL_HCIBUS (1 << 3) #define IC_MATCH_FL_HCIBUS (1 << 3)
#define IC_INFO(lmps, hcir) \ #define IC_INFO(lmps, hcir, hciv, bus) \
.match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV, \ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | \
IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS, \
.lmp_subver = (lmps), \ .lmp_subver = (lmps), \
.hci_rev = (hcir) .hci_rev = (hcir), \
.hci_ver = (hciv), \
.hci_bus = (bus)
struct id_table { struct id_table {
__u16 match_flags; __u16 match_flags;
...@@ -55,119 +57,100 @@ struct btrtl_device_info { ...@@ -55,119 +57,100 @@ struct btrtl_device_info {
int fw_len; int fw_len;
u8 *cfg_data; u8 *cfg_data;
int cfg_len; int cfg_len;
bool drop_fw;
}; };
static const struct id_table ic_id_table[] = { static const struct id_table ic_id_table[] = {
{ IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8723A, 0x0, /* 8723A */
.config_needed = false, { IC_INFO(RTL_ROM_LMP_8723A, 0xb, 0x6, HCI_USB),
.has_rom_version = false,
.fw_name = "rtl_bt/rtl8723a_fw.bin",
.cfg_name = NULL },
{ IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_3499, 0x0,
.config_needed = false, .config_needed = false,
.has_rom_version = false, .has_rom_version = false,
.fw_name = "rtl_bt/rtl8723a_fw.bin", .fw_name = "rtl_bt/rtl8723a_fw.bin",
.cfg_name = NULL }, .cfg_name = NULL },
/* 8723BS */ /* 8723BS */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_UART),
IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS,
.lmp_subver = RTL_ROM_LMP_8723B,
.hci_rev = 0xb,
.hci_ver = 6,
.hci_bus = HCI_UART,
.config_needed = true, .config_needed = true,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8723bs_fw.bin", .fw_name = "rtl_bt/rtl8723bs_fw.bin",
.cfg_name = "rtl_bt/rtl8723bs_config" }, .cfg_name = "rtl_bt/rtl8723bs_config" },
/* 8723B */ /* 8723B */
{ IC_INFO(RTL_ROM_LMP_8723B, 0xb), { IC_INFO(RTL_ROM_LMP_8723B, 0xb, 0x6, HCI_USB),
.config_needed = false, .config_needed = false,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8723b_fw.bin", .fw_name = "rtl_bt/rtl8723b_fw.bin",
.cfg_name = "rtl_bt/rtl8723b_config" }, .cfg_name = "rtl_bt/rtl8723b_config" },
/* 8723D */ /* 8723D */
{ IC_INFO(RTL_ROM_LMP_8723B, 0xd), { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_USB),
.config_needed = true, .config_needed = true,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8723d_fw.bin", .fw_name = "rtl_bt/rtl8723d_fw.bin",
.cfg_name = "rtl_bt/rtl8723d_config" }, .cfg_name = "rtl_bt/rtl8723d_config" },
/* 8723DS */ /* 8723DS */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | { IC_INFO(RTL_ROM_LMP_8723B, 0xd, 0x8, HCI_UART),
IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS,
.lmp_subver = RTL_ROM_LMP_8723B,
.hci_rev = 0xd,
.hci_ver = 8,
.hci_bus = HCI_UART,
.config_needed = true, .config_needed = true,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8723ds_fw.bin", .fw_name = "rtl_bt/rtl8723ds_fw.bin",
.cfg_name = "rtl_bt/rtl8723ds_config" }, .cfg_name = "rtl_bt/rtl8723ds_config" },
/* 8723DU */
{ IC_INFO(RTL_ROM_LMP_8723D, 0x826C),
.config_needed = true,
.has_rom_version = true,
.fw_name = "rtl_bt/rtl8723d_fw.bin",
.cfg_name = "rtl_bt/rtl8723d_config" },
/* 8821A */ /* 8821A */
{ IC_INFO(RTL_ROM_LMP_8821A, 0xa), { IC_INFO(RTL_ROM_LMP_8821A, 0xa, 0x6, HCI_USB),
.config_needed = false, .config_needed = false,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8821a_fw.bin", .fw_name = "rtl_bt/rtl8821a_fw.bin",
.cfg_name = "rtl_bt/rtl8821a_config" }, .cfg_name = "rtl_bt/rtl8821a_config" },
/* 8821C */ /* 8821C */
{ IC_INFO(RTL_ROM_LMP_8821A, 0xc), { IC_INFO(RTL_ROM_LMP_8821A, 0xc, 0x8, HCI_USB),
.config_needed = false, .config_needed = false,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8821c_fw.bin", .fw_name = "rtl_bt/rtl8821c_fw.bin",
.cfg_name = "rtl_bt/rtl8821c_config" }, .cfg_name = "rtl_bt/rtl8821c_config" },
/* 8761A */ /* 8761A */
{ IC_INFO(RTL_ROM_LMP_8761A, 0xa), { IC_INFO(RTL_ROM_LMP_8761A, 0xa, 0x6, HCI_USB),
.config_needed = false, .config_needed = false,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8761a_fw.bin", .fw_name = "rtl_bt/rtl8761a_fw.bin",
.cfg_name = "rtl_bt/rtl8761a_config" }, .cfg_name = "rtl_bt/rtl8761a_config" },
/* 8761B */ /* 8761B */
{ IC_INFO(RTL_ROM_LMP_8761A, 0xb), { IC_INFO(RTL_ROM_LMP_8761A, 0xb, 0xa, HCI_USB),
.config_needed = false, .config_needed = false,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8761b_fw.bin", .fw_name = "rtl_bt/rtl8761b_fw.bin",
.cfg_name = "rtl_bt/rtl8761b_config" }, .cfg_name = "rtl_bt/rtl8761b_config" },
/* 8822C with UART interface */ /* 8822C with UART interface */
{ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
IC_MATCH_FL_HCIBUS,
.lmp_subver = RTL_ROM_LMP_8822B,
.hci_rev = 0x000c,
.hci_ver = 0x0a,
.hci_bus = HCI_UART,
.config_needed = true, .config_needed = true,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8822cs_fw.bin", .fw_name = "rtl_bt/rtl8822cs_fw.bin",
.cfg_name = "rtl_bt/rtl8822cs_config" }, .cfg_name = "rtl_bt/rtl8822cs_config" },
/* 8822C with USB interface */ /* 8822C with USB interface */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc), { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_USB),
.config_needed = false, .config_needed = false,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8822cu_fw.bin", .fw_name = "rtl_bt/rtl8822cu_fw.bin",
.cfg_name = "rtl_bt/rtl8822cu_config" }, .cfg_name = "rtl_bt/rtl8822cu_config" },
/* 8822B */ /* 8822B */
{ IC_INFO(RTL_ROM_LMP_8822B, 0xb), { IC_INFO(RTL_ROM_LMP_8822B, 0xb, 0x7, HCI_USB),
.config_needed = true, .config_needed = true,
.has_rom_version = true, .has_rom_version = true,
.fw_name = "rtl_bt/rtl8822b_fw.bin", .fw_name = "rtl_bt/rtl8822b_fw.bin",
.cfg_name = "rtl_bt/rtl8822b_config" }, .cfg_name = "rtl_bt/rtl8822b_config" },
/* 8852A */
{ IC_INFO(RTL_ROM_LMP_8852A, 0xa, 0xb, HCI_USB),
.config_needed = false,
.has_rom_version = true,
.fw_name = "rtl_bt/rtl8852au_fw.bin",
.cfg_name = "rtl_bt/rtl8852au_config" },
}; };
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev, static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
...@@ -275,6 +258,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, ...@@ -275,6 +258,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
{ RTL_ROM_LMP_8821A, 10 }, /* 8821C */ { RTL_ROM_LMP_8821A, 10 }, /* 8821C */
{ RTL_ROM_LMP_8822B, 13 }, /* 8822C */ { RTL_ROM_LMP_8822B, 13 }, /* 8822C */
{ RTL_ROM_LMP_8761A, 14 }, /* 8761B */ { RTL_ROM_LMP_8761A, 14 }, /* 8761B */
{ RTL_ROM_LMP_8852A, 18 }, /* 8852A */
}; };
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
...@@ -563,6 +547,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, ...@@ -563,6 +547,8 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
u16 hci_rev, lmp_subver; u16 hci_rev, lmp_subver;
u8 hci_ver; u8 hci_ver;
int ret; int ret;
u16 opcode;
u8 cmd[2];
btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL); btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
if (!btrtl_dev) { if (!btrtl_dev) {
...@@ -584,6 +570,49 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev, ...@@ -584,6 +570,49 @@ struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev,
hci_ver = resp->hci_ver; hci_ver = resp->hci_ver;
hci_rev = le16_to_cpu(resp->hci_rev); hci_rev = le16_to_cpu(resp->hci_rev);
lmp_subver = le16_to_cpu(resp->lmp_subver); lmp_subver = le16_to_cpu(resp->lmp_subver);
if (resp->hci_ver == 0x8 && le16_to_cpu(resp->hci_rev) == 0x826c &&
resp->lmp_ver == 0x8 && le16_to_cpu(resp->lmp_subver) == 0xa99e)
btrtl_dev->drop_fw = true;
if (btrtl_dev->drop_fw) {
opcode = hci_opcode_pack(0x3f, 0x66);
cmd[0] = opcode & 0xff;
cmd[1] = opcode >> 8;
skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL);
if (!skb)
goto out_free;
skb_put_data(skb, cmd, sizeof(cmd));
hci_skb_pkt_type(skb) = HCI_COMMAND_PKT;
hdev->send(hdev, skb);
/* Ensure the above vendor command is sent to controller and
* process has done.
*/
msleep(200);
/* Read the local version again. Expect to have the vanilla
* version as cold boot.
*/
skb = btrtl_read_local_version(hdev);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
goto err_free;
}
resp = (struct hci_rp_read_local_version *)skb->data;
rtl_dev_info(hdev, "examining hci_ver=%02x hci_rev=%04x lmp_ver=%02x lmp_subver=%04x",
resp->hci_ver, resp->hci_rev,
resp->lmp_ver, resp->lmp_subver);
hci_ver = resp->hci_ver;
hci_rev = le16_to_cpu(resp->hci_rev);
lmp_subver = le16_to_cpu(resp->lmp_subver);
}
out_free:
kfree_skb(skb); kfree_skb(skb);
btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver, btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev, hci_ver,
...@@ -654,12 +683,12 @@ int btrtl_download_firmware(struct hci_dev *hdev, ...@@ -654,12 +683,12 @@ int btrtl_download_firmware(struct hci_dev *hdev,
switch (btrtl_dev->ic_info->lmp_subver) { switch (btrtl_dev->ic_info->lmp_subver) {
case RTL_ROM_LMP_8723A: case RTL_ROM_LMP_8723A:
case RTL_ROM_LMP_3499:
return btrtl_setup_rtl8723a(hdev, btrtl_dev); return btrtl_setup_rtl8723a(hdev, btrtl_dev);
case RTL_ROM_LMP_8723B: case RTL_ROM_LMP_8723B:
case RTL_ROM_LMP_8821A: case RTL_ROM_LMP_8821A:
case RTL_ROM_LMP_8761A: case RTL_ROM_LMP_8761A:
case RTL_ROM_LMP_8822B: case RTL_ROM_LMP_8822B:
case RTL_ROM_LMP_8852A:
return btrtl_setup_rtl8723b(hdev, btrtl_dev); return btrtl_setup_rtl8723b(hdev, btrtl_dev);
default: default:
rtl_dev_info(hdev, "assuming no firmware upload needed"); rtl_dev_info(hdev, "assuming no firmware upload needed");
...@@ -835,3 +864,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8821a_fw.bin"); ...@@ -835,3 +864,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8821a_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8821a_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8821a_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822b_fw.bin"); MODULE_FIRMWARE("rtl_bt/rtl8822b_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8822b_config.bin"); MODULE_FIRMWARE("rtl_bt/rtl8822b_config.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852au_fw.bin");
MODULE_FIRMWARE("rtl_bt/rtl8852au_config.bin");
This diff is collapsed.
...@@ -245,6 +245,9 @@ static int h5_close(struct hci_uart *hu) ...@@ -245,6 +245,9 @@ static int h5_close(struct hci_uart *hu)
skb_queue_purge(&h5->rel); skb_queue_purge(&h5->rel);
skb_queue_purge(&h5->unrel); skb_queue_purge(&h5->unrel);
kfree_skb(h5->rx_skb);
h5->rx_skb = NULL;
if (h5->vnd && h5->vnd->close) if (h5->vnd && h5->vnd->close)
h5->vnd->close(h5); h5->vnd->close(h5);
...@@ -1001,6 +1004,7 @@ static struct h5_vnd rtl_vnd = { ...@@ -1001,6 +1004,7 @@ static struct h5_vnd rtl_vnd = {
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id h5_acpi_match[] = { static const struct acpi_device_id h5_acpi_match[] = {
#ifdef CONFIG_BT_HCIUART_RTL #ifdef CONFIG_BT_HCIUART_RTL
{ "OBDA0623", (kernel_ulong_t)&rtl_vnd },
{ "OBDA8723", (kernel_ulong_t)&rtl_vnd }, { "OBDA8723", (kernel_ulong_t)&rtl_vnd },
#endif #endif
{ }, { },
......
...@@ -626,6 +626,7 @@ static int ll_setup(struct hci_uart *hu) ...@@ -626,6 +626,7 @@ static int ll_setup(struct hci_uart *hu)
gpiod_set_value_cansleep(lldev->enable_gpio, 0); gpiod_set_value_cansleep(lldev->enable_gpio, 0);
msleep(5); msleep(5);
gpiod_set_value_cansleep(lldev->enable_gpio, 1); gpiod_set_value_cansleep(lldev->enable_gpio, 1);
mdelay(100);
err = serdev_device_wait_for_cts(serdev, true, 200); err = serdev_device_wait_for_cts(serdev, true, 200);
if (err) { if (err) {
bt_dev_err(hu->hdev, "Failed to get CTS"); bt_dev_err(hu->hdev, "Failed to get CTS");
......
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000 #define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000
#define CMD_TRANS_TIMEOUT_MS 100 #define CMD_TRANS_TIMEOUT_MS 100
#define MEMDUMP_TIMEOUT_MS 8000 #define MEMDUMP_TIMEOUT_MS 8000
#define IBS_DISABLE_SSR_TIMEOUT_MS (MEMDUMP_TIMEOUT_MS + 1000)
#define FW_DOWNLOAD_TIMEOUT_MS 3000
/* susclk rate */ /* susclk rate */
#define SUSCLK_RATE_32KHZ 32768 #define SUSCLK_RATE_32KHZ 32768
...@@ -68,16 +70,18 @@ ...@@ -68,16 +70,18 @@
#define QCA_MEMDUMP_BYTE 0xFB #define QCA_MEMDUMP_BYTE 0xFB
enum qca_flags { enum qca_flags {
QCA_IBS_ENABLED, QCA_IBS_DISABLED,
QCA_DROP_VENDOR_EVENT, QCA_DROP_VENDOR_EVENT,
QCA_SUSPENDING, QCA_SUSPENDING,
QCA_MEMDUMP_COLLECTION, QCA_MEMDUMP_COLLECTION,
QCA_HW_ERROR_EVENT, QCA_HW_ERROR_EVENT,
QCA_SSR_TRIGGERED QCA_SSR_TRIGGERED,
QCA_BT_OFF
}; };
enum qca_capabilities { enum qca_capabilities {
QCA_CAP_WIDEBAND_SPEECH = BIT(0), QCA_CAP_WIDEBAND_SPEECH = BIT(0),
QCA_CAP_VALID_LE_STATES = BIT(1),
}; };
/* HCI_IBS transmit side sleep protocol states */ /* HCI_IBS transmit side sleep protocol states */
...@@ -630,7 +634,7 @@ static void qca_debugfs_init(struct hci_dev *hdev) ...@@ -630,7 +634,7 @@ static void qca_debugfs_init(struct hci_dev *hdev)
ibs_dir = debugfs_create_dir("ibs", hdev->debugfs); ibs_dir = debugfs_create_dir("ibs", hdev->debugfs);
/* read only */ /* read only */
mode = S_IRUGO; mode = 0444;
debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state); debugfs_create_u8("tx_ibs_state", mode, ibs_dir, &qca->tx_ibs_state);
debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state); debugfs_create_u8("rx_ibs_state", mode, ibs_dir, &qca->rx_ibs_state);
debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir, debugfs_create_u64("ibs_sent_sleeps", mode, ibs_dir,
...@@ -657,7 +661,7 @@ static void qca_debugfs_init(struct hci_dev *hdev) ...@@ -657,7 +661,7 @@ static void qca_debugfs_init(struct hci_dev *hdev)
debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms); debugfs_create_u32("vote_off_ms", mode, ibs_dir, &qca->vote_off_ms);
/* read/write */ /* read/write */
mode = S_IRUGO | S_IWUSR; mode = 0644;
debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans); debugfs_create_u32("wake_retrans", mode, ibs_dir, &qca->wake_retrans);
debugfs_create_u32("tx_idle_delay", mode, ibs_dir, debugfs_create_u32("tx_idle_delay", mode, ibs_dir,
&qca->tx_idle_delay); &qca->tx_idle_delay);
...@@ -869,7 +873,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) ...@@ -869,7 +873,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
* Out-Of-Band(GPIOs control) sleep is selected. * Out-Of-Band(GPIOs control) sleep is selected.
* Don't wake the device up when suspending. * Don't wake the device up when suspending.
*/ */
if (!test_bit(QCA_IBS_ENABLED, &qca->flags) || if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
test_bit(QCA_SUSPENDING, &qca->flags)) { test_bit(QCA_SUSPENDING, &qca->flags)) {
skb_queue_tail(&qca->txq, skb); skb_queue_tail(&qca->txq, skb);
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
...@@ -1014,7 +1018,7 @@ static void qca_controller_memdump(struct work_struct *work) ...@@ -1014,7 +1018,7 @@ static void qca_controller_memdump(struct work_struct *work)
* the controller to send the dump is 8 seconds. let us * the controller to send the dump is 8 seconds. let us
* start timer to handle this asynchronous activity. * start timer to handle this asynchronous activity.
*/ */
clear_bit(QCA_IBS_ENABLED, &qca->flags); set_bit(QCA_IBS_DISABLED, &qca->flags);
set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
dump = (void *) skb->data; dump = (void *) skb->data;
dump_size = __le32_to_cpu(dump->dump_size); dump_size = __le32_to_cpu(dump->dump_size);
...@@ -1301,7 +1305,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate) ...@@ -1301,7 +1305,7 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
/* Give the controller time to process the request */ /* Give the controller time to process the request */
if (qca_is_wcn399x(qca_soc_type(hu))) if (qca_is_wcn399x(qca_soc_type(hu)))
msleep(10); usleep_range(1000, 10000);
else else
msleep(300); msleep(300);
...@@ -1349,7 +1353,7 @@ static int qca_send_power_pulse(struct hci_uart *hu, bool on) ...@@ -1349,7 +1353,7 @@ static int qca_send_power_pulse(struct hci_uart *hu, bool on)
if (on) if (on)
msleep(100); msleep(100);
else else
msleep(10); usleep_range(1000, 10000);
return 0; return 0;
} }
...@@ -1618,6 +1622,7 @@ static int qca_power_on(struct hci_dev *hdev) ...@@ -1618,6 +1622,7 @@ static int qca_power_on(struct hci_dev *hdev)
struct hci_uart *hu = hci_get_drvdata(hdev); struct hci_uart *hu = hci_get_drvdata(hdev);
enum qca_btsoc_type soc_type = qca_soc_type(hu); enum qca_btsoc_type soc_type = qca_soc_type(hu);
struct qca_serdev *qcadev; struct qca_serdev *qcadev;
struct qca_data *qca = hu->priv;
int ret = 0; int ret = 0;
/* Non-serdev device usually is powered by external power /* Non-serdev device usually is powered by external power
...@@ -1637,6 +1642,7 @@ static int qca_power_on(struct hci_dev *hdev) ...@@ -1637,6 +1642,7 @@ static int qca_power_on(struct hci_dev *hdev)
} }
} }
clear_bit(QCA_BT_OFF, &qca->flags);
return ret; return ret;
} }
...@@ -1649,14 +1655,14 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1649,14 +1655,14 @@ static int qca_setup(struct hci_uart *hu)
enum qca_btsoc_type soc_type = qca_soc_type(hu); enum qca_btsoc_type soc_type = qca_soc_type(hu);
const char *firmware_name = qca_get_firmware_name(hu); const char *firmware_name = qca_get_firmware_name(hu);
int ret; int ret;
int soc_ver = 0; struct qca_btsoc_version ver;
ret = qca_check_speeds(hu); ret = qca_check_speeds(hu);
if (ret) if (ret)
return ret; return ret;
/* Patch downloading has to be done without IBS mode */ /* Patch downloading has to be done without IBS mode */
clear_bit(QCA_IBS_ENABLED, &qca->flags); set_bit(QCA_IBS_DISABLED, &qca->flags);
/* Enable controller to do both LE scan and BR/EDR inquiry /* Enable controller to do both LE scan and BR/EDR inquiry
* simultaneously. * simultaneously.
...@@ -1671,16 +1677,16 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1671,16 +1677,16 @@ static int qca_setup(struct hci_uart *hu)
retry: retry:
ret = qca_power_on(hdev); ret = qca_power_on(hdev);
if (ret) if (ret)
return ret; goto out;
clear_bit(QCA_SSR_TRIGGERED, &qca->flags); clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
if (qca_is_wcn399x(soc_type)) { if (qca_is_wcn399x(soc_type)) {
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
ret = qca_read_soc_version(hdev, &soc_ver, soc_type); ret = qca_read_soc_version(hdev, &ver, soc_type);
if (ret) if (ret)
return ret; goto out;
} else { } else {
qca_set_speed(hu, QCA_INIT_SPEED); qca_set_speed(hu, QCA_INIT_SPEED);
} }
...@@ -1690,24 +1696,23 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1690,24 +1696,23 @@ static int qca_setup(struct hci_uart *hu)
if (speed) { if (speed) {
ret = qca_set_speed(hu, QCA_OPER_SPEED); ret = qca_set_speed(hu, QCA_OPER_SPEED);
if (ret) if (ret)
return ret; goto out;
qca_baudrate = qca_get_baudrate_value(speed); qca_baudrate = qca_get_baudrate_value(speed);
} }
if (!qca_is_wcn399x(soc_type)) { if (!qca_is_wcn399x(soc_type)) {
/* Get QCA version information */ /* Get QCA version information */
ret = qca_read_soc_version(hdev, &soc_ver, soc_type); ret = qca_read_soc_version(hdev, &ver, soc_type);
if (ret) if (ret)
return ret; goto out;
} }
bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver);
/* Setup patch / NVM configurations */ /* Setup patch / NVM configurations */
ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver, ret = qca_uart_setup(hdev, qca_baudrate, soc_type, ver,
firmware_name); firmware_name);
if (!ret) { if (!ret) {
set_bit(QCA_IBS_ENABLED, &qca->flags); clear_bit(QCA_IBS_DISABLED, &qca->flags);
qca_debugfs_init(hdev); qca_debugfs_init(hdev);
hu->hdev->hw_error = qca_hw_error; hu->hdev->hw_error = qca_hw_error;
hu->hdev->cmd_timeout = qca_cmd_timeout; hu->hdev->cmd_timeout = qca_cmd_timeout;
...@@ -1720,20 +1725,22 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1720,20 +1725,22 @@ static int qca_setup(struct hci_uart *hu)
* patch/nvm-config is found, so run with original fw/config. * patch/nvm-config is found, so run with original fw/config.
*/ */
ret = 0; ret = 0;
} else { }
if (retries < MAX_INIT_RETRIES) {
qca_power_shutdown(hu); out:
if (hu->serdev) { if (ret && retries < MAX_INIT_RETRIES) {
serdev_device_close(hu->serdev); bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
ret = serdev_device_open(hu->serdev); qca_power_shutdown(hu);
if (ret) { if (hu->serdev) {
bt_dev_err(hdev, "failed to open port"); serdev_device_close(hu->serdev);
return ret; ret = serdev_device_open(hu->serdev);
} if (ret) {
bt_dev_err(hdev, "failed to open port");
return ret;
} }
retries++;
goto retry;
} }
retries++;
goto retry;
} }
/* Setup bdaddr */ /* Setup bdaddr */
...@@ -1780,7 +1787,7 @@ static const struct qca_device_data qca_soc_data_wcn3991 = { ...@@ -1780,7 +1787,7 @@ static const struct qca_device_data qca_soc_data_wcn3991 = {
{ "vddch0", 450000 }, { "vddch0", 450000 },
}, },
.num_vregs = 4, .num_vregs = 4,
.capabilities = QCA_CAP_WIDEBAND_SPEECH, .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
}; };
static const struct qca_device_data qca_soc_data_wcn3998 = { static const struct qca_device_data qca_soc_data_wcn3998 = {
...@@ -1813,7 +1820,7 @@ static void qca_power_shutdown(struct hci_uart *hu) ...@@ -1813,7 +1820,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
* data in skb's. * data in skb's.
*/ */
spin_lock_irqsave(&qca->hci_ibs_lock, flags); spin_lock_irqsave(&qca->hci_ibs_lock, flags);
clear_bit(QCA_IBS_ENABLED, &qca->flags); set_bit(QCA_IBS_DISABLED, &qca->flags);
qca_flush(hu); qca_flush(hu);
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
...@@ -1830,6 +1837,8 @@ static void qca_power_shutdown(struct hci_uart *hu) ...@@ -1830,6 +1837,8 @@ static void qca_power_shutdown(struct hci_uart *hu)
} else if (qcadev->bt_en) { } else if (qcadev->bt_en) {
gpiod_set_value_cansleep(qcadev->bt_en, 0); gpiod_set_value_cansleep(qcadev->bt_en, 0);
} }
set_bit(QCA_BT_OFF, &qca->flags);
} }
static int qca_power_off(struct hci_dev *hdev) static int qca_power_off(struct hci_dev *hdev)
...@@ -2017,11 +2026,17 @@ static int qca_serdev_probe(struct serdev_device *serdev) ...@@ -2017,11 +2026,17 @@ static int qca_serdev_probe(struct serdev_device *serdev)
hdev->shutdown = qca_power_off; hdev->shutdown = qca_power_off;
} }
/* Wideband speech support must be set per driver since it can't be if (data) {
* queried via hci. /* Wideband speech support must be set per driver since it can't
*/ * be queried via hci. Same with the valid le states quirk.
if (data && (data->capabilities & QCA_CAP_WIDEBAND_SPEECH)) */
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); if (data->capabilities & QCA_CAP_WIDEBAND_SPEECH)
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
&hdev->quirks);
if (data->capabilities & QCA_CAP_VALID_LE_STATES)
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
}
return 0; return 0;
} }
...@@ -2081,11 +2096,34 @@ static int __maybe_unused qca_suspend(struct device *dev) ...@@ -2081,11 +2096,34 @@ static int __maybe_unused qca_suspend(struct device *dev)
bool tx_pending = false; bool tx_pending = false;
int ret = 0; int ret = 0;
u8 cmd; u8 cmd;
u32 wait_timeout = 0;
set_bit(QCA_SUSPENDING, &qca->flags); set_bit(QCA_SUSPENDING, &qca->flags);
/* Device is downloading patch or doesn't support in-band sleep. */ if (test_bit(QCA_BT_OFF, &qca->flags))
if (!test_bit(QCA_IBS_ENABLED, &qca->flags)) return 0;
if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
IBS_DISABLE_SSR_TIMEOUT_MS :
FW_DOWNLOAD_TIMEOUT_MS;
/* QCA_IBS_DISABLED flag is set to true, During FW download
* and during memory dump collection. It is reset to false,
* After FW download complete and after memory dump collections.
*/
wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
bt_dev_err(hu->hdev, "SSR or FW download time out");
ret = -ETIMEDOUT;
goto error;
}
}
/* After memory dump collection, Controller is powered off.*/
if (test_bit(QCA_BT_OFF, &qca->flags))
return 0; return 0;
cancel_work_sync(&qca->ws_awake_device); cancel_work_sync(&qca->ws_awake_device);
......
...@@ -1797,6 +1797,13 @@ struct hci_cp_le_set_adv_set_rand_addr { ...@@ -1797,6 +1797,13 @@ struct hci_cp_le_set_adv_set_rand_addr {
bdaddr_t bdaddr; bdaddr_t bdaddr;
} __packed; } __packed;
#define HCI_OP_LE_READ_TRANSMIT_POWER 0x204b
struct hci_rp_le_read_transmit_power {
__u8 status;
__s8 min_le_tx_power;
__s8 max_le_tx_power;
} __packed;
#define HCI_OP_LE_READ_BUFFER_SIZE_V2 0x2060 #define HCI_OP_LE_READ_BUFFER_SIZE_V2 0x2060
struct hci_rp_le_read_buffer_size_v2 { struct hci_rp_le_read_buffer_size_v2 {
__u8 status; __u8 status;
......
...@@ -230,6 +230,8 @@ struct adv_info { ...@@ -230,6 +230,8 @@ struct adv_info {
__u16 scan_rsp_len; __u16 scan_rsp_len;
__u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; __u8 scan_rsp_data[HCI_MAX_AD_LENGTH];
__s8 tx_power; __s8 tx_power;
__u32 min_interval;
__u32 max_interval;
bdaddr_t random_addr; bdaddr_t random_addr;
bool rpa_expired; bool rpa_expired;
struct delayed_work rpa_expired_cb; struct delayed_work rpa_expired_cb;
...@@ -238,6 +240,8 @@ struct adv_info { ...@@ -238,6 +240,8 @@ struct adv_info {
#define HCI_MAX_ADV_INSTANCES 5 #define HCI_MAX_ADV_INSTANCES 5
#define HCI_DEFAULT_ADV_DURATION 2 #define HCI_DEFAULT_ADV_DURATION 2
#define HCI_ADV_TX_POWER_NO_PREFERENCE 0x7F
struct adv_pattern { struct adv_pattern {
struct list_head list; struct list_head list;
__u8 ad_type; __u8 ad_type;
...@@ -361,6 +365,9 @@ struct hci_dev { ...@@ -361,6 +365,9 @@ struct hci_dev {
__u8 ssp_debug_mode; __u8 ssp_debug_mode;
__u8 hw_error_code; __u8 hw_error_code;
__u32 clock; __u32 clock;
__u16 advmon_allowlist_duration;
__u16 advmon_no_filter_duration;
__u8 enable_advmon_interleave_scan;
__u16 devid_source; __u16 devid_source;
__u16 devid_vendor; __u16 devid_vendor;
...@@ -377,6 +384,8 @@ struct hci_dev { ...@@ -377,6 +384,8 @@ struct hci_dev {
__u16 def_page_timeout; __u16 def_page_timeout;
__u16 def_multi_adv_rotation_duration; __u16 def_multi_adv_rotation_duration;
__u16 def_le_autoconnect_timeout; __u16 def_le_autoconnect_timeout;
__s8 min_le_tx_power;
__s8 max_le_tx_power;
__u16 pkt_type; __u16 pkt_type;
__u16 esco_type; __u16 esco_type;
...@@ -542,6 +551,14 @@ struct hci_dev { ...@@ -542,6 +551,14 @@ struct hci_dev {
struct delayed_work rpa_expired; struct delayed_work rpa_expired;
bdaddr_t rpa; bdaddr_t rpa;
enum {
INTERLEAVE_SCAN_NONE,
INTERLEAVE_SCAN_NO_FILTER,
INTERLEAVE_SCAN_ALLOWLIST
} interleave_scan_state;
struct delayed_work interleave_scan;
#if IS_ENABLED(CONFIG_BT_LEDS) #if IS_ENABLED(CONFIG_BT_LEDS)
struct led_trigger *power_led; struct led_trigger *power_led;
#endif #endif
...@@ -1290,7 +1307,11 @@ struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance); ...@@ -1290,7 +1307,11 @@ struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance);
int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
u16 adv_data_len, u8 *adv_data, u16 adv_data_len, u8 *adv_data,
u16 scan_rsp_len, u8 *scan_rsp_data, u16 scan_rsp_len, u8 *scan_rsp_data,
u16 timeout, u16 duration); u16 timeout, u16 duration, s8 tx_power,
u32 min_interval, u32 max_interval);
int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance,
u16 adv_data_len, u8 *adv_data,
u16 scan_rsp_len, u8 *scan_rsp_data);
int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance); int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance);
void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired); void hci_adv_instances_set_rpa_expired(struct hci_dev *hdev, bool rpa_expired);
......
...@@ -574,6 +574,10 @@ struct mgmt_rp_add_advertising { ...@@ -574,6 +574,10 @@ struct mgmt_rp_add_advertising {
#define MGMT_ADV_FLAG_SEC_CODED BIT(9) #define MGMT_ADV_FLAG_SEC_CODED BIT(9)
#define MGMT_ADV_FLAG_CAN_SET_TX_POWER BIT(10) #define MGMT_ADV_FLAG_CAN_SET_TX_POWER BIT(10)
#define MGMT_ADV_FLAG_HW_OFFLOAD BIT(11) #define MGMT_ADV_FLAG_HW_OFFLOAD BIT(11)
#define MGMT_ADV_PARAM_DURATION BIT(12)
#define MGMT_ADV_PARAM_TIMEOUT BIT(13)
#define MGMT_ADV_PARAM_INTERVALS BIT(14)
#define MGMT_ADV_PARAM_TX_POWER BIT(15)
#define MGMT_ADV_FLAG_SEC_MASK (MGMT_ADV_FLAG_SEC_1M | MGMT_ADV_FLAG_SEC_2M | \ #define MGMT_ADV_FLAG_SEC_MASK (MGMT_ADV_FLAG_SEC_1M | MGMT_ADV_FLAG_SEC_2M | \
MGMT_ADV_FLAG_SEC_CODED) MGMT_ADV_FLAG_SEC_CODED)
...@@ -621,7 +625,7 @@ struct mgmt_cp_set_appearance { ...@@ -621,7 +625,7 @@ struct mgmt_cp_set_appearance {
#define MGMT_SET_APPEARANCE_SIZE 2 #define MGMT_SET_APPEARANCE_SIZE 2
#define MGMT_OP_GET_PHY_CONFIGURATION 0x0044 #define MGMT_OP_GET_PHY_CONFIGURATION 0x0044
struct mgmt_rp_get_phy_confguration { struct mgmt_rp_get_phy_configuration {
__le32 supported_phys; __le32 supported_phys;
__le32 configurable_phys; __le32 configurable_phys;
__le32 selected_phys; __le32 selected_phys;
...@@ -658,7 +662,7 @@ struct mgmt_rp_get_phy_confguration { ...@@ -658,7 +662,7 @@ struct mgmt_rp_get_phy_confguration {
MGMT_PHY_LE_CODED_RX) MGMT_PHY_LE_CODED_RX)
#define MGMT_OP_SET_PHY_CONFIGURATION 0x0045 #define MGMT_OP_SET_PHY_CONFIGURATION 0x0045
struct mgmt_cp_set_phy_confguration { struct mgmt_cp_set_phy_configuration {
__le32 selected_phys; __le32 selected_phys;
} __packed; } __packed;
#define MGMT_SET_PHY_CONFIGURATION_SIZE 4 #define MGMT_SET_PHY_CONFIGURATION_SIZE 4
...@@ -682,11 +686,16 @@ struct mgmt_cp_set_blocked_keys { ...@@ -682,11 +686,16 @@ struct mgmt_cp_set_blocked_keys {
#define MGMT_OP_SET_WIDEBAND_SPEECH 0x0047 #define MGMT_OP_SET_WIDEBAND_SPEECH 0x0047
#define MGMT_OP_READ_SECURITY_INFO 0x0048 #define MGMT_CAP_SEC_FLAGS 0x01
#define MGMT_READ_SECURITY_INFO_SIZE 0 #define MGMT_CAP_MAX_ENC_KEY_SIZE 0x02
struct mgmt_rp_read_security_info { #define MGMT_CAP_SMP_MAX_ENC_KEY_SIZE 0x03
__le16 sec_len; #define MGMT_CAP_LE_TX_PWR 0x04
__u8 sec[];
#define MGMT_OP_READ_CONTROLLER_CAP 0x0048
#define MGMT_READ_CONTROLLER_CAP_SIZE 0
struct mgmt_rp_read_controller_cap {
__le16 cap_len;
__u8 cap[0];
} __packed; } __packed;
#define MGMT_OP_READ_EXP_FEATURES_INFO 0x0049 #define MGMT_OP_READ_EXP_FEATURES_INFO 0x0049
...@@ -782,6 +791,36 @@ struct mgmt_rp_remove_adv_monitor { ...@@ -782,6 +791,36 @@ struct mgmt_rp_remove_adv_monitor {
__le16 monitor_handle; __le16 monitor_handle;
} __packed; } __packed;
#define MGMT_OP_ADD_EXT_ADV_PARAMS 0x0054
struct mgmt_cp_add_ext_adv_params {
__u8 instance;
__le32 flags;
__le16 duration;
__le16 timeout;
__le32 min_interval;
__le32 max_interval;
__s8 tx_power;
} __packed;
#define MGMT_ADD_EXT_ADV_PARAMS_MIN_SIZE 18
struct mgmt_rp_add_ext_adv_params {
__u8 instance;
__s8 tx_power;
__u8 max_adv_data_len;
__u8 max_scan_rsp_len;
} __packed;
#define MGMT_OP_ADD_EXT_ADV_DATA 0x0055
struct mgmt_cp_add_ext_adv_data {
__u8 instance;
__u8 adv_data_len;
__u8 scan_rsp_len;
__u8 data[];
} __packed;
#define MGMT_ADD_EXT_ADV_DATA_SIZE 3
struct mgmt_rp_add_ext_adv_data {
__u8 instance;
} __packed;
#define MGMT_EV_CMD_COMPLETE 0x0001 #define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete { struct mgmt_ev_cmd_complete {
__le16 opcode; __le16 opcode;
......
...@@ -758,6 +758,9 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode) ...@@ -758,6 +758,9 @@ static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
conn = hci_lookup_le_connect(hdev); conn = hci_lookup_le_connect(hdev);
if (hdev->adv_instance_cnt)
hci_req_resume_adv_instances(hdev);
if (!status) { if (!status) {
hci_connect_le_scan_cleanup(conn); hci_connect_le_scan_cleanup(conn);
goto done; goto done;
...@@ -1067,10 +1070,11 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1067,10 +1070,11 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
* connections most controllers will refuse to connect if * connections most controllers will refuse to connect if
* advertising is enabled, and for slave role connections we * advertising is enabled, and for slave role connections we
* anyway have to disable it in order to start directed * anyway have to disable it in order to start directed
* advertising. * advertising. Any registered advertisements will be
* re-enabled after the connection attempt is finished.
*/ */
if (hci_dev_test_flag(hdev, HCI_LE_ADV)) if (hci_dev_test_flag(hdev, HCI_LE_ADV))
__hci_req_disable_advertising(&req); __hci_req_pause_adv_instances(&req);
/* If requested to connect as slave use directed advertising */ /* If requested to connect as slave use directed advertising */
if (conn->role == HCI_ROLE_SLAVE) { if (conn->role == HCI_ROLE_SLAVE) {
...@@ -1118,6 +1122,10 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, ...@@ -1118,6 +1122,10 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
err = hci_req_run(&req, create_le_conn_complete); err = hci_req_run(&req, create_le_conn_complete);
if (err) { if (err) {
hci_conn_del(conn); hci_conn_del(conn);
if (hdev->adv_instance_cnt)
hci_req_resume_adv_instances(hdev);
return ERR_PTR(err); return ERR_PTR(err);
} }
......
...@@ -741,6 +741,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt) ...@@ -741,6 +741,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL); hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
} }
if (hdev->commands[38] & 0x80) {
/* Read LE Min/Max Tx Power*/
hci_req_add(req, HCI_OP_LE_READ_TRANSMIT_POWER,
0, NULL);
}
if (hdev->commands[26] & 0x40) { if (hdev->commands[26] & 0x40) {
/* Read LE White List Size */ /* Read LE White List Size */
hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE,
...@@ -763,7 +769,7 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt) ...@@ -763,7 +769,7 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
hci_req_add(req, HCI_OP_LE_CLEAR_RESOLV_LIST, 0, NULL); hci_req_add(req, HCI_OP_LE_CLEAR_RESOLV_LIST, 0, NULL);
} }
if (hdev->commands[35] & 0x40) { if (hdev->commands[35] & 0x04) {
__le16 rpa_timeout = cpu_to_le16(hdev->rpa_timeout); __le16 rpa_timeout = cpu_to_le16(hdev->rpa_timeout);
/* Set RPA timeout */ /* Set RPA timeout */
...@@ -2951,7 +2957,8 @@ static void adv_instance_rpa_expired(struct work_struct *work) ...@@ -2951,7 +2957,8 @@ static void adv_instance_rpa_expired(struct work_struct *work)
int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
u16 adv_data_len, u8 *adv_data, u16 adv_data_len, u8 *adv_data,
u16 scan_rsp_len, u8 *scan_rsp_data, u16 scan_rsp_len, u8 *scan_rsp_data,
u16 timeout, u16 duration) u16 timeout, u16 duration, s8 tx_power,
u32 min_interval, u32 max_interval)
{ {
struct adv_info *adv_instance; struct adv_info *adv_instance;
...@@ -2979,6 +2986,9 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, ...@@ -2979,6 +2986,9 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
adv_instance->flags = flags; adv_instance->flags = flags;
adv_instance->adv_data_len = adv_data_len; adv_instance->adv_data_len = adv_data_len;
adv_instance->scan_rsp_len = scan_rsp_len; adv_instance->scan_rsp_len = scan_rsp_len;
adv_instance->min_interval = min_interval;
adv_instance->max_interval = max_interval;
adv_instance->tx_power = tx_power;
if (adv_data_len) if (adv_data_len)
memcpy(adv_instance->adv_data, adv_data, adv_data_len); memcpy(adv_instance->adv_data, adv_data, adv_data_len);
...@@ -2995,8 +3005,6 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, ...@@ -2995,8 +3005,6 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
else else
adv_instance->duration = duration; adv_instance->duration = duration;
adv_instance->tx_power = HCI_TX_POWER_INVALID;
INIT_DELAYED_WORK(&adv_instance->rpa_expired_cb, INIT_DELAYED_WORK(&adv_instance->rpa_expired_cb,
adv_instance_rpa_expired); adv_instance_rpa_expired);
...@@ -3005,6 +3013,37 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, ...@@ -3005,6 +3013,37 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
return 0; return 0;
} }
/* This function requires the caller holds hdev->lock */
int hci_set_adv_instance_data(struct hci_dev *hdev, u8 instance,
u16 adv_data_len, u8 *adv_data,
u16 scan_rsp_len, u8 *scan_rsp_data)
{
struct adv_info *adv_instance;
adv_instance = hci_find_adv_instance(hdev, instance);
/* If advertisement doesn't exist, we can't modify its data */
if (!adv_instance)
return -ENOENT;
if (adv_data_len) {
memset(adv_instance->adv_data, 0,
sizeof(adv_instance->adv_data));
memcpy(adv_instance->adv_data, adv_data, adv_data_len);
adv_instance->adv_data_len = adv_data_len;
}
if (scan_rsp_len) {
memset(adv_instance->scan_rsp_data, 0,
sizeof(adv_instance->scan_rsp_data));
memcpy(adv_instance->scan_rsp_data,
scan_rsp_data, scan_rsp_len);
adv_instance->scan_rsp_len = scan_rsp_len;
}
return 0;
}
/* This function requires the caller holds hdev->lock */ /* This function requires the caller holds hdev->lock */
void hci_adv_monitors_clear(struct hci_dev *hdev) void hci_adv_monitors_clear(struct hci_dev *hdev)
{ {
...@@ -3592,6 +3631,10 @@ struct hci_dev *hci_alloc_dev(void) ...@@ -3592,6 +3631,10 @@ struct hci_dev *hci_alloc_dev(void)
hdev->cur_adv_instance = 0x00; hdev->cur_adv_instance = 0x00;
hdev->adv_instance_timeout = 0; hdev->adv_instance_timeout = 0;
hdev->advmon_allowlist_duration = 300;
hdev->advmon_no_filter_duration = 500;
hdev->enable_advmon_interleave_scan = 0x00; /* Default to disable */
hdev->sniff_max_interval = 800; hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80; hdev->sniff_min_interval = 80;
...@@ -3623,6 +3666,8 @@ struct hci_dev *hci_alloc_dev(void) ...@@ -3623,6 +3666,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->le_num_of_adv_sets = HCI_MAX_ADV_INSTANCES; hdev->le_num_of_adv_sets = HCI_MAX_ADV_INSTANCES;
hdev->def_multi_adv_rotation_duration = HCI_DEFAULT_ADV_DURATION; hdev->def_multi_adv_rotation_duration = HCI_DEFAULT_ADV_DURATION;
hdev->def_le_autoconnect_timeout = HCI_LE_AUTOCONN_TIMEOUT; hdev->def_le_autoconnect_timeout = HCI_LE_AUTOCONN_TIMEOUT;
hdev->min_le_tx_power = HCI_TX_POWER_INVALID;
hdev->max_le_tx_power = HCI_TX_POWER_INVALID;
hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT; hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT;
hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT; hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT;
......
...@@ -494,6 +494,45 @@ static int auto_accept_delay_get(void *data, u64 *val) ...@@ -494,6 +494,45 @@ static int auto_accept_delay_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
auto_accept_delay_set, "%llu\n"); auto_accept_delay_set, "%llu\n");
static ssize_t force_bredr_smp_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP) ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t force_bredr_smp_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
bool enable;
int err;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
err = smp_force_bredr(hdev, enable);
if (err)
return err;
return count;
}
static const struct file_operations force_bredr_smp_fops = {
.open = simple_open,
.read = force_bredr_smp_read,
.write = force_bredr_smp_write,
.llseek = default_llseek,
};
static int idle_timeout_set(void *data, u64 val) static int idle_timeout_set(void *data, u64 val)
{ {
struct hci_dev *hdev = data; struct hci_dev *hdev = data;
...@@ -589,6 +628,17 @@ void hci_debugfs_create_bredr(struct hci_dev *hdev) ...@@ -589,6 +628,17 @@ void hci_debugfs_create_bredr(struct hci_dev *hdev)
debugfs_create_file("voice_setting", 0444, hdev->debugfs, hdev, debugfs_create_file("voice_setting", 0444, hdev->debugfs, hdev,
&voice_setting_fops); &voice_setting_fops);
/* If the controller does not support BR/EDR Secure Connections
* feature, then the BR/EDR SMP channel shall not be present.
*
* To test this with Bluetooth 4.0 controllers, create a debugfs
* switch that allows forcing BR/EDR SMP support and accepting
* cross-transport pairing on non-AES encrypted connections.
*/
if (!lmp_sc_capable(hdev))
debugfs_create_file("force_bredr_smp", 0644, hdev->debugfs,
hdev, &force_bredr_smp_fops);
if (lmp_ssp_capable(hdev)) { if (lmp_ssp_capable(hdev)) {
debugfs_create_file("ssp_debug_mode", 0444, hdev->debugfs, debugfs_create_file("ssp_debug_mode", 0444, hdev->debugfs,
hdev, &ssp_debug_mode_fops); hdev, &ssp_debug_mode_fops);
......
...@@ -1202,6 +1202,20 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev, ...@@ -1202,6 +1202,20 @@ static void hci_cc_le_set_adv_set_random_addr(struct hci_dev *hdev,
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
static void hci_cc_le_read_transmit_power(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_le_read_transmit_power *rp = (void *)skb->data;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
return;
hdev->min_le_tx_power = rp->min_le_tx_power;
hdev->max_le_tx_power = rp->max_le_tx_power;
}
static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb) static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
{ {
__u8 *sent, status = *((__u8 *) skb->data); __u8 *sent, status = *((__u8 *) skb->data);
...@@ -1752,6 +1766,7 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1752,6 +1766,7 @@ static void hci_cc_set_ext_adv_param(struct hci_dev *hdev, struct sk_buff *skb)
} }
/* Update adv data as tx power is known now */ /* Update adv data as tx power is known now */
hci_req_update_adv_data(hdev, hdev->cur_adv_instance); hci_req_update_adv_data(hdev, hdev->cur_adv_instance);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -3581,6 +3596,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb, ...@@ -3581,6 +3596,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cc_le_set_adv_set_random_addr(hdev, skb); hci_cc_le_set_adv_set_random_addr(hdev, skb);
break; break;
case HCI_OP_LE_READ_TRANSMIT_POWER:
hci_cc_le_read_transmit_power(hdev, skb);
break;
default: default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode); BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode);
break; break;
...@@ -4936,15 +4955,15 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev, ...@@ -4936,15 +4955,15 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev,
hci_dev_lock(hdev); hci_dev_lock(hdev);
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle); hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon) { if (!hcon)
hci_dev_unlock(hdev); goto unlock;
return;
} if (!hcon->amp_mgr)
goto unlock;
if (ev->status) { if (ev->status) {
hci_conn_del(hcon); hci_conn_del(hcon);
hci_dev_unlock(hdev); goto unlock;
return;
} }
bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon; bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon;
...@@ -4961,6 +4980,7 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev, ...@@ -4961,6 +4980,7 @@ static void hci_phy_link_complete_evt(struct hci_dev *hdev,
amp_physical_cfm(bredr_hcon, hcon); amp_physical_cfm(bredr_hcon, hcon);
unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -5868,21 +5888,19 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev, ...@@ -5868,21 +5888,19 @@ static void hci_le_direct_adv_report_evt(struct hci_dev *hdev,
struct sk_buff *skb) struct sk_buff *skb)
{ {
u8 num_reports = skb->data[0]; u8 num_reports = skb->data[0];
void *ptr = &skb->data[1]; struct hci_ev_le_direct_adv_info *ev = (void *)&skb->data[1];
hci_dev_lock(hdev); if (!num_reports || skb->len < num_reports * sizeof(*ev) + 1)
return;
while (num_reports--) { hci_dev_lock(hdev);
struct hci_ev_le_direct_adv_info *ev = ptr;
for (; num_reports; num_reports--, ev++)
process_adv_report(hdev, ev->evt_type, &ev->bdaddr, process_adv_report(hdev, ev->evt_type, &ev->bdaddr,
ev->bdaddr_type, &ev->direct_addr, ev->bdaddr_type, &ev->direct_addr,
ev->direct_addr_type, ev->rssi, NULL, 0, ev->direct_addr_type, ev->rssi, NULL, 0,
false); false);
ptr += sizeof(*ev);
}
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
......
This diff is collapsed.
...@@ -71,6 +71,8 @@ void hci_req_add_le_passive_scan(struct hci_request *req); ...@@ -71,6 +71,8 @@ void hci_req_add_le_passive_scan(struct hci_request *req);
void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next); void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next);
void hci_req_disable_address_resolution(struct hci_dev *hdev); void hci_req_disable_address_resolution(struct hci_dev *hdev);
void __hci_req_pause_adv_instances(struct hci_request *req);
int hci_req_resume_adv_instances(struct hci_dev *hdev);
void hci_req_reenable_advertising(struct hci_dev *hdev); void hci_req_reenable_advertising(struct hci_dev *hdev);
void __hci_req_enable_advertising(struct hci_request *req); void __hci_req_enable_advertising(struct hci_request *req);
void __hci_req_disable_advertising(struct hci_request *req); void __hci_req_disable_advertising(struct hci_request *req);
......
...@@ -1290,7 +1290,7 @@ static int hidp_session_thread(void *arg) ...@@ -1290,7 +1290,7 @@ static int hidp_session_thread(void *arg)
/* cleanup runtime environment */ /* cleanup runtime environment */
remove_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait); remove_wait_queue(sk_sleep(session->intr_sock->sk), &intr_wait);
remove_wait_queue(sk_sleep(session->intr_sock->sk), &ctrl_wait); remove_wait_queue(sk_sleep(session->ctrl_sock->sk), &ctrl_wait);
wake_up_interruptible(&session->report_queue); wake_up_interruptible(&session->report_queue);
hidp_del_timer(session); hidp_del_timer(session);
......
...@@ -1515,8 +1515,14 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon) ...@@ -1515,8 +1515,14 @@ static bool l2cap_check_enc_key_size(struct hci_conn *hcon)
* that have no key size requirements. Ensure that the link is * that have no key size requirements. Ensure that the link is
* actually encrypted before enforcing a key size. * actually encrypted before enforcing a key size.
*/ */
int min_key_size = hcon->hdev->min_enc_key_size;
/* On FIPS security level, key size must be 16 bytes */
if (hcon->sec_level == BT_SECURITY_FIPS)
min_key_size = 16;
return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) || return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
hcon->enc_key_size >= hcon->hdev->min_enc_key_size); hcon->enc_key_size >= min_key_size);
} }
static void l2cap_do_start(struct l2cap_chan *chan) static void l2cap_do_start(struct l2cap_chan *chan)
...@@ -3627,7 +3633,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data ...@@ -3627,7 +3633,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
if (hint) if (hint)
break; break;
result = L2CAP_CONF_UNKNOWN; result = L2CAP_CONF_UNKNOWN;
*((u8 *) ptr++) = type; l2cap_add_conf_opt(&ptr, (u8)type, sizeof(u8), type, endptr - ptr);
break; break;
} }
} }
......
This diff is collapsed.
...@@ -11,74 +11,119 @@ ...@@ -11,74 +11,119 @@
#include "mgmt_util.h" #include "mgmt_util.h"
#include "mgmt_config.h" #include "mgmt_config.h"
#define HDEV_PARAM_U16(_param_code_, _param_name_) \ #define HDEV_PARAM_U16(_param_name_) \
{ \ struct {\
{ cpu_to_le16(_param_code_), sizeof(__u16) }, \ struct mgmt_tlv entry; \
{ cpu_to_le16(hdev->_param_name_) } \ __le16 value; \
} } __packed _param_name_
#define HDEV_PARAM_U16_JIFFIES_TO_MSECS(_param_code_, _param_name_) \ #define HDEV_PARAM_U8(_param_name_) \
{ \ struct {\
{ cpu_to_le16(_param_code_), sizeof(__u16) }, \ struct mgmt_tlv entry; \
{ cpu_to_le16(jiffies_to_msecs(hdev->_param_name_)) } \ __u8 value; \
} } __packed _param_name_
#define TLV_SET_U16(_param_code_, _param_name_) \
{ \
{ cpu_to_le16(_param_code_), sizeof(__u16) }, \
cpu_to_le16(hdev->_param_name_) \
}
#define TLV_SET_U8(_param_code_, _param_name_) \
{ \
{ cpu_to_le16(_param_code_), sizeof(__u8) }, \
hdev->_param_name_ \
}
#define TLV_SET_U16_JIFFIES_TO_MSECS(_param_code_, _param_name_) \
{ \
{ cpu_to_le16(_param_code_), sizeof(__u16) }, \
cpu_to_le16(jiffies_to_msecs(hdev->_param_name_)) \
}
int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, int read_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len) u16 data_len)
{ {
struct { int ret;
struct mgmt_tlv entry; struct mgmt_rp_read_def_system_config {
union {
/* This is a simplification for now since all values
* are 16 bits. In the future, this code may need
* refactoring to account for variable length values
* and properly calculate the required buffer size.
*/
__le16 value;
};
} __packed params[] = {
/* Please see mgmt-api.txt for documentation of these values */ /* Please see mgmt-api.txt for documentation of these values */
HDEV_PARAM_U16(0x0000, def_page_scan_type), HDEV_PARAM_U16(def_page_scan_type);
HDEV_PARAM_U16(0x0001, def_page_scan_int), HDEV_PARAM_U16(def_page_scan_int);
HDEV_PARAM_U16(0x0002, def_page_scan_window), HDEV_PARAM_U16(def_page_scan_window);
HDEV_PARAM_U16(0x0003, def_inq_scan_type), HDEV_PARAM_U16(def_inq_scan_type);
HDEV_PARAM_U16(0x0004, def_inq_scan_int), HDEV_PARAM_U16(def_inq_scan_int);
HDEV_PARAM_U16(0x0005, def_inq_scan_window), HDEV_PARAM_U16(def_inq_scan_window);
HDEV_PARAM_U16(0x0006, def_br_lsto), HDEV_PARAM_U16(def_br_lsto);
HDEV_PARAM_U16(0x0007, def_page_timeout), HDEV_PARAM_U16(def_page_timeout);
HDEV_PARAM_U16(0x0008, sniff_min_interval), HDEV_PARAM_U16(sniff_min_interval);
HDEV_PARAM_U16(0x0009, sniff_max_interval), HDEV_PARAM_U16(sniff_max_interval);
HDEV_PARAM_U16(0x000a, le_adv_min_interval), HDEV_PARAM_U16(le_adv_min_interval);
HDEV_PARAM_U16(0x000b, le_adv_max_interval), HDEV_PARAM_U16(le_adv_max_interval);
HDEV_PARAM_U16(0x000c, def_multi_adv_rotation_duration), HDEV_PARAM_U16(def_multi_adv_rotation_duration);
HDEV_PARAM_U16(0x000d, le_scan_interval), HDEV_PARAM_U16(le_scan_interval);
HDEV_PARAM_U16(0x000e, le_scan_window), HDEV_PARAM_U16(le_scan_window);
HDEV_PARAM_U16(0x000f, le_scan_int_suspend), HDEV_PARAM_U16(le_scan_int_suspend);
HDEV_PARAM_U16(0x0010, le_scan_window_suspend), HDEV_PARAM_U16(le_scan_window_suspend);
HDEV_PARAM_U16(0x0011, le_scan_int_discovery), HDEV_PARAM_U16(le_scan_int_discovery);
HDEV_PARAM_U16(0x0012, le_scan_window_discovery), HDEV_PARAM_U16(le_scan_window_discovery);
HDEV_PARAM_U16(0x0013, le_scan_int_adv_monitor), HDEV_PARAM_U16(le_scan_int_adv_monitor);
HDEV_PARAM_U16(0x0014, le_scan_window_adv_monitor), HDEV_PARAM_U16(le_scan_window_adv_monitor);
HDEV_PARAM_U16(0x0015, le_scan_int_connect), HDEV_PARAM_U16(le_scan_int_connect);
HDEV_PARAM_U16(0x0016, le_scan_window_connect), HDEV_PARAM_U16(le_scan_window_connect);
HDEV_PARAM_U16(0x0017, le_conn_min_interval), HDEV_PARAM_U16(le_conn_min_interval);
HDEV_PARAM_U16(0x0018, le_conn_max_interval), HDEV_PARAM_U16(le_conn_max_interval);
HDEV_PARAM_U16(0x0019, le_conn_latency), HDEV_PARAM_U16(le_conn_latency);
HDEV_PARAM_U16(0x001a, le_supv_timeout), HDEV_PARAM_U16(le_supv_timeout);
HDEV_PARAM_U16_JIFFIES_TO_MSECS(0x001b, HDEV_PARAM_U16(def_le_autoconnect_timeout);
def_le_autoconnect_timeout), HDEV_PARAM_U16(advmon_allowlist_duration);
HDEV_PARAM_U16(advmon_no_filter_duration);
HDEV_PARAM_U8(enable_advmon_interleave_scan);
} __packed rp = {
TLV_SET_U16(0x0000, def_page_scan_type),
TLV_SET_U16(0x0001, def_page_scan_int),
TLV_SET_U16(0x0002, def_page_scan_window),
TLV_SET_U16(0x0003, def_inq_scan_type),
TLV_SET_U16(0x0004, def_inq_scan_int),
TLV_SET_U16(0x0005, def_inq_scan_window),
TLV_SET_U16(0x0006, def_br_lsto),
TLV_SET_U16(0x0007, def_page_timeout),
TLV_SET_U16(0x0008, sniff_min_interval),
TLV_SET_U16(0x0009, sniff_max_interval),
TLV_SET_U16(0x000a, le_adv_min_interval),
TLV_SET_U16(0x000b, le_adv_max_interval),
TLV_SET_U16(0x000c, def_multi_adv_rotation_duration),
TLV_SET_U16(0x000d, le_scan_interval),
TLV_SET_U16(0x000e, le_scan_window),
TLV_SET_U16(0x000f, le_scan_int_suspend),
TLV_SET_U16(0x0010, le_scan_window_suspend),
TLV_SET_U16(0x0011, le_scan_int_discovery),
TLV_SET_U16(0x0012, le_scan_window_discovery),
TLV_SET_U16(0x0013, le_scan_int_adv_monitor),
TLV_SET_U16(0x0014, le_scan_window_adv_monitor),
TLV_SET_U16(0x0015, le_scan_int_connect),
TLV_SET_U16(0x0016, le_scan_window_connect),
TLV_SET_U16(0x0017, le_conn_min_interval),
TLV_SET_U16(0x0018, le_conn_max_interval),
TLV_SET_U16(0x0019, le_conn_latency),
TLV_SET_U16(0x001a, le_supv_timeout),
TLV_SET_U16_JIFFIES_TO_MSECS(0x001b,
def_le_autoconnect_timeout),
TLV_SET_U16(0x001d, advmon_allowlist_duration),
TLV_SET_U16(0x001e, advmon_no_filter_duration),
TLV_SET_U8(0x001f, enable_advmon_interleave_scan),
}; };
struct mgmt_rp_read_def_system_config *rp = (void *)params;
bt_dev_dbg(hdev, "sock %p", sk); bt_dev_dbg(hdev, "sock %p", sk);
return mgmt_cmd_complete(sk, hdev->id, ret = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_READ_DEF_SYSTEM_CONFIG, MGMT_OP_READ_DEF_SYSTEM_CONFIG,
0, rp, sizeof(params)); 0, &rp, sizeof(rp));
return ret;
} }
#define TO_TLV(x) ((struct mgmt_tlv *)(x)) #define TO_TLV(x) ((struct mgmt_tlv *)(x))
#define TLV_GET_LE16(tlv) le16_to_cpu(*((__le16 *)(TO_TLV(tlv)->value))) #define TLV_GET_LE16(tlv) le16_to_cpu(*((__le16 *)(TO_TLV(tlv)->value)))
#define TLV_GET_U8(tlv) (*((__u8 *)(TO_TLV(tlv)->value)))
int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len) u16 data_len)
...@@ -95,6 +140,7 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -95,6 +140,7 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data,
/* First pass to validate the tlv */ /* First pass to validate the tlv */
while (buffer_left >= sizeof(struct mgmt_tlv)) { while (buffer_left >= sizeof(struct mgmt_tlv)) {
const u8 len = TO_TLV(buffer)->length; const u8 len = TO_TLV(buffer)->length;
size_t exp_type_len;
const u16 exp_len = sizeof(struct mgmt_tlv) + const u16 exp_len = sizeof(struct mgmt_tlv) +
len; len;
const u16 type = le16_to_cpu(TO_TLV(buffer)->type); const u16 type = le16_to_cpu(TO_TLV(buffer)->type);
...@@ -138,20 +184,28 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -138,20 +184,28 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data,
case 0x0019: case 0x0019:
case 0x001a: case 0x001a:
case 0x001b: case 0x001b:
if (len != sizeof(u16)) { case 0x001d:
bt_dev_warn(hdev, "invalid length %d, exp %zu for type %d", case 0x001e:
len, sizeof(u16), type); exp_type_len = sizeof(u16);
break;
return mgmt_cmd_status(sk, hdev->id, case 0x001f:
MGMT_OP_SET_DEF_SYSTEM_CONFIG, exp_type_len = sizeof(u8);
MGMT_STATUS_INVALID_PARAMS);
}
break; break;
default: default:
exp_type_len = 0;
bt_dev_warn(hdev, "unsupported parameter %u", type); bt_dev_warn(hdev, "unsupported parameter %u", type);
break; break;
} }
if (exp_type_len && len != exp_type_len) {
bt_dev_warn(hdev, "invalid length %d, exp %zu for type %d",
len, exp_type_len, type);
return mgmt_cmd_status(sk, hdev->id,
MGMT_OP_SET_DEF_SYSTEM_CONFIG,
MGMT_STATUS_INVALID_PARAMS);
}
buffer_left -= exp_len; buffer_left -= exp_len;
buffer += exp_len; buffer += exp_len;
} }
...@@ -251,6 +305,15 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data, ...@@ -251,6 +305,15 @@ int set_def_system_config(struct sock *sk, struct hci_dev *hdev, void *data,
hdev->def_le_autoconnect_timeout = hdev->def_le_autoconnect_timeout =
msecs_to_jiffies(TLV_GET_LE16(buffer)); msecs_to_jiffies(TLV_GET_LE16(buffer));
break; break;
case 0x0001d:
hdev->advmon_allowlist_duration = TLV_GET_LE16(buffer);
break;
case 0x0001e:
hdev->advmon_no_filter_duration = TLV_GET_LE16(buffer);
break;
case 0x0001f:
hdev->enable_advmon_interleave_scan = TLV_GET_U8(buffer);
break;
default: default:
bt_dev_warn(hdev, "unsupported parameter %u", type); bt_dev_warn(hdev, "unsupported parameter %u", type);
break; break;
......
...@@ -1003,6 +1003,11 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -1003,6 +1003,11 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
case BT_SNDMTU: case BT_SNDMTU:
case BT_RCVMTU: case BT_RCVMTU:
if (sk->sk_state != BT_CONNECTED) {
err = -ENOTCONN;
break;
}
if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval)) if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval))
err = -EFAULT; err = -EFAULT;
break; break;
......
...@@ -3353,31 +3353,8 @@ static void smp_del_chan(struct l2cap_chan *chan) ...@@ -3353,31 +3353,8 @@ static void smp_del_chan(struct l2cap_chan *chan)
l2cap_chan_put(chan); l2cap_chan_put(chan);
} }
static ssize_t force_bredr_smp_read(struct file *file, int smp_force_bredr(struct hci_dev *hdev, bool enable)
char __user *user_buf,
size_t count, loff_t *ppos)
{ {
struct hci_dev *hdev = file->private_data;
char buf[3];
buf[0] = hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP) ? 'Y': 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t force_bredr_smp_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct hci_dev *hdev = file->private_data;
bool enable;
int err;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
if (enable == hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) if (enable == hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP))
return -EALREADY; return -EALREADY;
...@@ -3399,16 +3376,9 @@ static ssize_t force_bredr_smp_write(struct file *file, ...@@ -3399,16 +3376,9 @@ static ssize_t force_bredr_smp_write(struct file *file,
hci_dev_change_flag(hdev, HCI_FORCE_BREDR_SMP); hci_dev_change_flag(hdev, HCI_FORCE_BREDR_SMP);
return count; return 0;
} }
static const struct file_operations force_bredr_smp_fops = {
.open = simple_open,
.read = force_bredr_smp_read,
.write = force_bredr_smp_write,
.llseek = default_llseek,
};
int smp_register(struct hci_dev *hdev) int smp_register(struct hci_dev *hdev)
{ {
struct l2cap_chan *chan; struct l2cap_chan *chan;
...@@ -3433,17 +3403,7 @@ int smp_register(struct hci_dev *hdev) ...@@ -3433,17 +3403,7 @@ int smp_register(struct hci_dev *hdev)
hdev->smp_data = chan; hdev->smp_data = chan;
/* If the controller does not support BR/EDR Secure Connections
* feature, then the BR/EDR SMP channel shall not be present.
*
* To test this with Bluetooth 4.0 controllers, create a debugfs
* switch that allows forcing BR/EDR SMP support and accepting
* cross-transport pairing on non-AES encrypted connections.
*/
if (!lmp_sc_capable(hdev)) { if (!lmp_sc_capable(hdev)) {
debugfs_create_file("force_bredr_smp", 0644, hdev->debugfs,
hdev, &force_bredr_smp_fops);
/* Flag can be already set here (due to power toggle) */ /* Flag can be already set here (due to power toggle) */
if (!hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP)) if (!hci_dev_test_flag(hdev, HCI_FORCE_BREDR_SMP))
return 0; return 0;
......
...@@ -193,6 +193,8 @@ bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16], ...@@ -193,6 +193,8 @@ bool smp_irk_matches(struct hci_dev *hdev, const u8 irk[16],
int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa); int smp_generate_rpa(struct hci_dev *hdev, const u8 irk[16], bdaddr_t *rpa);
int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]); int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16]);
int smp_force_bredr(struct hci_dev *hdev, bool enable);
int smp_register(struct hci_dev *hdev); int smp_register(struct hci_dev *hdev);
void smp_unregister(struct hci_dev *hdev); void smp_unregister(struct hci_dev *hdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment