Commit 2bd056f5 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-09-29

Here's the main bluetooth-next pull request for 5.10:

 - Multiple fixes to suspend/resume handling
 - Added mgmt events for controller suspend/resume state
 - Improved extended advertising support
 - btintel: Enhanced support for next generation controllers
 - Added Qualcomm Bluetooth SoC WCN6855 support
 - Several other smaller fixes & improvements
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fe38d95b b40f58b9
......@@ -18,7 +18,11 @@
#define VERSION "0.1"
#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}})
#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
int btintel_check_bdaddr(struct hci_dev *hdev)
{
......@@ -360,6 +364,144 @@ int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver)
}
EXPORT_SYMBOL_GPL(btintel_read_version);
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version)
{
const char *variant;
switch (version->img_type) {
case 0x01:
variant = "Bootloader";
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);
goto done;
}
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);
done:
return;
}
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);
}
if (skb->data[0]) {
bt_dev_err(hdev, "Intel Read Version command failed (%02x)",
skb->data[0]);
kfree_skb(skb);
return -EIO;
}
/* Consume Command Complete Status field */
skb_pull(skb, 1);
/* Event parameters contatin multiple TLVs. Read each of them
* and only keep the required data. Also, it use existing legacy
* version field like hw_platform, hw_variant, and fw_variant
* to keep the existing setup flow
*/
while (skb->len) {
struct intel_tlv *tlv;
tlv = (struct intel_tlv *)skb->data;
switch (tlv->type) {
case INTEL_TLV_CNVI_TOP:
version->cnvi_top = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_CNVR_TOP:
version->cnvr_top = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_CNVI_BT:
version->cnvi_bt = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_CNVR_BT:
version->cnvr_bt = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_DEV_REV_ID:
version->dev_rev_id = get_unaligned_le16(tlv->val);
break;
case INTEL_TLV_IMAGE_TYPE:
version->img_type = tlv->val[0];
break;
case INTEL_TLV_TIME_STAMP:
version->timestamp = get_unaligned_le16(tlv->val);
break;
case INTEL_TLV_BUILD_TYPE:
version->build_type = tlv->val[0];
break;
case INTEL_TLV_BUILD_NUM:
version->build_num = get_unaligned_le32(tlv->val);
break;
case INTEL_TLV_SECURE_BOOT:
version->secure_boot = tlv->val[0];
break;
case INTEL_TLV_OTP_LOCK:
version->otp_lock = tlv->val[0];
break;
case INTEL_TLV_API_LOCK:
version->api_lock = tlv->val[0];
break;
case INTEL_TLV_DEBUG_LOCK:
version->debug_lock = tlv->val[0];
break;
case INTEL_TLV_MIN_FW:
version->min_fw_build_nn = tlv->val[0];
version->min_fw_build_cw = tlv->val[1];
version->min_fw_build_yy = tlv->val[2];
break;
case INTEL_TLV_LIMITED_CCE:
version->limited_cce = tlv->val[0];
break;
case INTEL_TLV_SBE_TYPE:
version->sbe_type = tlv->val[0];
break;
case INTEL_TLV_OTP_BDADDR:
memcpy(&version->otp_bd_addr, tlv->val, tlv->len);
break;
default:
/* Ignore rest of information */
break;
}
/* consume the current tlv and move to next*/
skb_pull(skb, tlv->len + sizeof(*tlv));
}
kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(btintel_read_version_tlv);
/* ------- REGMAP IBT SUPPORT ------- */
#define IBT_REG_MODE_8BIT 0x00
......@@ -626,12 +768,10 @@ int btintel_read_boot_params(struct hci_dev *hdev,
}
EXPORT_SYMBOL_GPL(btintel_read_boot_params);
int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
u32 *boot_param)
static int btintel_sfi_rsa_header_secure_send(struct hci_dev *hdev,
const struct firmware *fw)
{
int err;
const u8 *fw_ptr;
u32 frag_len;
/* Start the firmware download transaction with the Init fragment
* represented by the 128 bytes of CSS header.
......@@ -660,8 +800,56 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
goto done;
}
fw_ptr = fw->data + 644;
done:
return err;
}
static int btintel_sfi_ecdsa_header_secure_send(struct hci_dev *hdev,
const struct firmware *fw)
{
int err;
/* Start the firmware download transaction with the Init fragment
* represented by the 128 bytes of CSS header.
*/
err = btintel_secure_send(hdev, 0x00, 128, fw->data + 644);
if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware header (%d)", err);
return err;
}
/* Send the 96 bytes of public key information from the firmware
* as the PKey fragment.
*/
err = btintel_secure_send(hdev, 0x03, 96, fw->data + 644 + 128);
if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware pkey (%d)", err);
return err;
}
/* Send the 96 bytes of signature information from the firmware
* as the Sign fragment
*/
err = btintel_secure_send(hdev, 0x02, 96, fw->data + 644 + 224);
if (err < 0) {
bt_dev_err(hdev, "Failed to send firmware signature (%d)",
err);
return err;
}
return 0;
}
static int btintel_download_firmware_payload(struct hci_dev *hdev,
const struct firmware *fw,
u32 *boot_param, size_t offset)
{
int err;
const u8 *fw_ptr;
u32 frag_len;
fw_ptr = fw->data + offset;
frag_len = 0;
err = -EINVAL;
while (fw_ptr - fw->data < fw->size) {
struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len);
......@@ -707,8 +895,99 @@ int btintel_download_firmware(struct hci_dev *hdev, const struct firmware *fw,
done:
return err;
}
int btintel_download_firmware(struct hci_dev *hdev,
const struct firmware *fw,
u32 *boot_param)
{
int err;
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
if (err)
return err;
return btintel_download_firmware_payload(hdev, fw, boot_param,
RSA_HEADER_LEN);
}
EXPORT_SYMBOL_GPL(btintel_download_firmware);
int btintel_download_firmware_newgen(struct hci_dev *hdev,
const struct firmware *fw, u32 *boot_param,
u8 hw_variant, u8 sbe_type)
{
int err;
u32 css_header_ver;
/* iBT hardware variants 0x0b, 0x0c, 0x11, 0x12, 0x13, 0x14 support
* only RSA secure boot engine. Hence, the corresponding sfi file will
* have RSA header of 644 bytes followed by Command Buffer.
*
* iBT hardware variants 0x17, 0x18 onwards support both RSA and ECDSA
* secure boot engine. As a result, the corresponding sfi file will
* have RSA header of 644, ECDSA header of 320 bytes followed by
* Command Buffer.
*
* CSS Header byte positions 0x08 to 0x0B represent the CSS Header
* version: RSA(0x00010000) , ECDSA (0x00020000)
*/
css_header_ver = get_unaligned_le32(fw->data + CSS_HEADER_OFFSET);
if (css_header_ver != 0x00010000) {
bt_dev_err(hdev, "Invalid CSS Header version");
return -EINVAL;
}
if (hw_variant <= 0x14) {
if (sbe_type != 0x00) {
bt_dev_err(hdev, "Invalid SBE type for hardware variant (%d)",
hw_variant);
return -EINVAL;
}
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
if (err)
return err;
err = btintel_download_firmware_payload(hdev, fw, boot_param, RSA_HEADER_LEN);
if (err)
return err;
} else if (hw_variant >= 0x17) {
/* Check if CSS header for ECDSA follows the RSA header */
if (fw->data[ECDSA_OFFSET] != 0x06)
return -EINVAL;
/* Check if the CSS Header version is ECDSA(0x00020000) */
css_header_ver = get_unaligned_le32(fw->data + ECDSA_OFFSET + CSS_HEADER_OFFSET);
if (css_header_ver != 0x00020000) {
bt_dev_err(hdev, "Invalid CSS Header version");
return -EINVAL;
}
if (sbe_type == 0x00) {
err = btintel_sfi_rsa_header_secure_send(hdev, fw);
if (err)
return err;
err = btintel_download_firmware_payload(hdev, fw,
boot_param,
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
if (err)
return err;
} else if (sbe_type == 0x01) {
err = btintel_sfi_ecdsa_header_secure_send(hdev, fw);
if (err)
return err;
err = btintel_download_firmware_payload(hdev, fw,
boot_param,
RSA_HEADER_LEN + ECDSA_HEADER_LEN);
if (err)
return err;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(btintel_download_firmware_newgen);
void btintel_reset_to_bootloader(struct hci_dev *hdev)
{
struct intel_reset params;
......
......@@ -6,6 +6,72 @@
* Copyright (C) 2015 Intel Corporation
*/
/* List of tlv type */
enum {
INTEL_TLV_CNVI_TOP = 0x10,
INTEL_TLV_CNVR_TOP,
INTEL_TLV_CNVI_BT,
INTEL_TLV_CNVR_BT,
INTEL_TLV_CNVI_OTP,
INTEL_TLV_CNVR_OTP,
INTEL_TLV_DEV_REV_ID,
INTEL_TLV_USB_VENDOR_ID,
INTEL_TLV_USB_PRODUCT_ID,
INTEL_TLV_PCIE_VENDOR_ID,
INTEL_TLV_PCIE_DEVICE_ID,
INTEL_TLV_PCIE_SUBSYSTEM_ID,
INTEL_TLV_IMAGE_TYPE,
INTEL_TLV_TIME_STAMP,
INTEL_TLV_BUILD_TYPE,
INTEL_TLV_BUILD_NUM,
INTEL_TLV_FW_BUILD_PRODUCT,
INTEL_TLV_FW_BUILD_HW,
INTEL_TLV_FW_STEP,
INTEL_TLV_BT_SPEC,
INTEL_TLV_MFG_NAME,
INTEL_TLV_HCI_REV,
INTEL_TLV_LMP_SUBVER,
INTEL_TLV_OTP_PATCH_VER,
INTEL_TLV_SECURE_BOOT,
INTEL_TLV_KEY_FROM_HDR,
INTEL_TLV_OTP_LOCK,
INTEL_TLV_API_LOCK,
INTEL_TLV_DEBUG_LOCK,
INTEL_TLV_MIN_FW,
INTEL_TLV_LIMITED_CCE,
INTEL_TLV_SBE_TYPE,
INTEL_TLV_OTP_BDADDR,
INTEL_TLV_UNLOCKED_STATE
};
struct intel_tlv {
u8 type;
u8 len;
u8 val[0];
} __packed;
struct intel_version_tlv {
u32 cnvi_top;
u32 cnvr_top;
u32 cnvi_bt;
u32 cnvr_bt;
u16 dev_rev_id;
u8 img_type;
u16 timestamp;
u8 build_type;
u32 build_num;
u8 secure_boot;
u8 otp_lock;
u8 api_lock;
u8 debug_lock;
u8 min_fw_build_nn;
u8 min_fw_build_cw;
u8 min_fw_build_yy;
u8 limited_cce;
u8 sbe_type;
bdaddr_t otp_bd_addr;
};
struct intel_version {
u8 status;
u8 hw_platform;
......@@ -77,12 +143,14 @@ int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
void btintel_hw_error(struct hci_dev *hdev, u8 code);
void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver);
void btintel_version_info_tlv(struct hci_dev *hdev, struct intel_version_tlv *version);
int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen,
const void *param);
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name);
int btintel_set_event_mask(struct hci_dev *hdev, bool debug);
int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug);
int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver);
int btintel_read_version_tlv(struct hci_dev *hdev, struct intel_version_tlv *ver);
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,
u16 opcode_write);
......@@ -91,6 +159,10 @@ int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params);
int btintel_download_firmware(struct hci_dev *dev, const struct firmware *fw,
u32 *boot_param);
int btintel_download_firmware_newgen(struct hci_dev *hdev,
const struct firmware *fw,
u32 *boot_param, u8 hw_variant,
u8 sbe_type);
void btintel_reset_to_bootloader(struct hci_dev *hdev);
int btintel_read_debug_features(struct hci_dev *hdev,
struct intel_debug_features *features);
......@@ -137,6 +209,11 @@ static inline void btintel_version_info(struct hci_dev *hdev,
{
}
static inline void btintel_version_info_tlv(struct hci_dev *hdev,
struct intel_version_tlv *version)
{
}
static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type,
u32 plen, const void *param)
{
......@@ -165,6 +242,12 @@ static inline int btintel_read_version(struct hci_dev *hdev,
return -EOPNOTSUPP;
}
static inline int btintel_read_version_tlv(struct hci_dev *hdev,
struct intel_version_tlv *ver)
{
return -EOPNOTSUPP;
}
static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,
u16 opcode_read,
u16 opcode_write)
......@@ -191,6 +274,14 @@ static inline int btintel_download_firmware(struct hci_dev *dev,
return -EOPNOTSUPP;
}
static inline int btintel_download_firmware_newgen(struct hci_dev *hdev,
const struct firmware *fw,
u32 *boot_param,
u8 hw_variant, u8 sbe_type)
{
return -EOPNOTSUPP;
}
static inline void btintel_reset_to_bootloader(struct hci_dev *hdev)
{
}
......
......@@ -215,30 +215,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
.fw_dump_end = 0xea,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_8977 = {
.cfg = 0x00,
.host_int_mask = 0x08,
.host_intstatus = 0x0c,
.card_status = 0x5c,
.sq_read_base_addr_a0 = 0xf8,
.sq_read_base_addr_a1 = 0xf9,
.card_revision = 0xc8,
.card_fw_status0 = 0xe8,
.card_fw_status1 = 0xe9,
.card_rx_len = 0xea,
.card_rx_unit = 0xeb,
.io_port_0 = 0xe4,
.io_port_1 = 0xe5,
.io_port_2 = 0xe6,
.int_read_to_clear = true,
.host_int_rsr = 0x04,
.card_misc_cfg = 0xD8,
.fw_dump_ctrl = 0xf0,
.fw_dump_start = 0xf1,
.fw_dump_end = 0xf8,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_8987 = {
static const struct btmrvl_sdio_card_reg btmrvl_reg_89xx = {
.cfg = 0x00,
.host_int_mask = 0x08,
.host_intstatus = 0x0c,
......@@ -261,29 +238,6 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8987 = {
.fw_dump_end = 0xf8,
};
static const struct btmrvl_sdio_card_reg btmrvl_reg_8997 = {
.cfg = 0x00,
.host_int_mask = 0x08,
.host_intstatus = 0x0c,
.card_status = 0x5c,
.sq_read_base_addr_a0 = 0xf8,
.sq_read_base_addr_a1 = 0xf9,
.card_revision = 0xc8,
.card_fw_status0 = 0xe8,
.card_fw_status1 = 0xe9,
.card_rx_len = 0xea,
.card_rx_unit = 0xeb,
.io_port_0 = 0xe4,
.io_port_1 = 0xe5,
.io_port_2 = 0xe6,
.int_read_to_clear = true,
.host_int_rsr = 0x04,
.card_misc_cfg = 0xD8,
.fw_dump_ctrl = 0xf0,
.fw_dump_start = 0xf1,
.fw_dump_end = 0xf8,
};
static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = {
.helper = "mrvl/sd8688_helper.bin",
.firmware = "mrvl/sd8688.bin",
......@@ -332,7 +286,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
.helper = NULL,
.firmware = "mrvl/sdsd8977_combo_v2.bin",
.reg = &btmrvl_reg_8977,
.reg = &btmrvl_reg_89xx,
.support_pscan_win_report = true,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = true,
......@@ -341,7 +295,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8977 = {
static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = {
.helper = NULL,
.firmware = "mrvl/sd8987_uapsta.bin",
.reg = &btmrvl_reg_8987,
.reg = &btmrvl_reg_89xx,
.support_pscan_win_report = true,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = true,
......@@ -350,7 +304,7 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8987 = {
static const struct btmrvl_sdio_device btmrvl_sdio_sd8997 = {
.helper = NULL,
.firmware = "mrvl/sdsd8997_combo_v4.bin",
.reg = &btmrvl_reg_8997,
.reg = &btmrvl_reg_89xx,
.support_pscan_win_report = true,
.sd_blksz_fw_dl = 256,
.supports_fw_dump = true,
......
......@@ -496,7 +496,7 @@ static void btmtksdio_interrupt(struct sdio_func *func)
sdio_claim_host(bdev->func);
/* Disable interrupt */
sdio_writel(func, C_INT_EN_CLR, MTK_REG_CHLPCR, 0);
sdio_writel(func, C_INT_EN_CLR, MTK_REG_CHLPCR, NULL);
int_status = sdio_readl(func, MTK_REG_CHISR, NULL);
......@@ -530,7 +530,7 @@ static void btmtksdio_interrupt(struct sdio_func *func)
}
/* Enable interrupt */
sdio_writel(func, C_INT_EN_SET, MTK_REG_CHLPCR, 0);
sdio_writel(func, C_INT_EN_SET, MTK_REG_CHLPCR, NULL);
pm_runtime_mark_last_busy(bdev->dev);
pm_runtime_put_autosuspend(bdev->dev);
......
......@@ -59,6 +59,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_MEDIATEK 0x200000
#define BTUSB_WIDEBAND_SPEECH 0x400000
#define BTUSB_VALID_LE_STATES 0x800000
#define BTUSB_QCA_WCN6855 0x1000000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
......@@ -254,24 +255,46 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
/* QCA ROME chipset */
{ USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x04ca, 0x3021), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME },
{ USB_DEVICE(0x0cf3, 0x535b), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cf3, 0xe301), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe092), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe09f), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x0489, 0xe0a2), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3011), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3015), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3016), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x301a), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x04ca, 0x3021), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3491), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3496), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
{ USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME |
BTUSB_WIDEBAND_SPEECH },
/* QCA WCN6855 chipset */
{ USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 |
BTUSB_WIDEBAND_SPEECH },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
......@@ -2338,10 +2361,10 @@ static bool btusb_setup_intel_new_get_fw_name(struct intel_version *ver,
static int btusb_intel_download_firmware(struct hci_dev *hdev,
struct intel_version *ver,
struct intel_boot_params *params)
struct intel_boot_params *params,
u32 *boot_param)
{
const struct firmware *fw;
u32 boot_param;
char fwname[64];
int err;
struct btusb_data *data = hci_get_drvdata(hdev);
......@@ -2479,7 +2502,7 @@ static int btusb_intel_download_firmware(struct hci_dev *hdev,
set_bit(BTUSB_DOWNLOADING, &data->flags);
/* Start firmware downloading and get boot parameter */
err = btintel_download_firmware(hdev, fw, &boot_param);
err = btintel_download_firmware(hdev, fw, boot_param);
if (err < 0) {
/* When FW download fails, send Intel Reset to retry
* FW download.
......@@ -2561,7 +2584,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev)
return err;
}
err = btusb_intel_download_firmware(hdev, &ver, &params);
err = btusb_intel_download_firmware(hdev, &ver, &params, &boot_param);
if (err)
return err;
......@@ -2896,6 +2919,7 @@ static int btusb_mtk_submit_wmt_recv_urb(struct hci_dev *hdev)
buf = kmalloc(size, GFP_KERNEL);
if (!buf) {
kfree(dr);
usb_free_urb(urb);
return -ENOMEM;
}
......@@ -3390,6 +3414,27 @@ static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
return 0;
}
static int btusb_set_bdaddr_wcn6855(struct hci_dev *hdev,
const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
u8 buf[6];
long ret;
memcpy(buf, bdaddr, sizeof(bdaddr_t));
skb = __hci_cmd_sync_ev(hdev, 0xfc14, sizeof(buf), buf,
HCI_EV_CMD_COMPLETE, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
bt_dev_err(hdev, "Change address command failed (%ld)", ret);
return ret;
}
kfree_skb(skb);
return 0;
}
#define QCA_DFU_PACKET_LEN 4096
#define QCA_GET_TARGET_VERSION 0x09
......@@ -3409,7 +3454,8 @@ struct qca_version {
} __packed;
struct qca_rampatch_version {
__le16 rom_version;
__le16 rom_version_high;
__le16 rom_version_low;
__le16 patch_version;
} __packed;
......@@ -3421,12 +3467,14 @@ struct qca_device_info {
};
static const struct qca_device_info qca_devices_table[] = {
{ 0x00000100, 20, 4, 10 }, /* Rome 1.0 */
{ 0x00000101, 20, 4, 10 }, /* Rome 1.1 */
{ 0x00000200, 28, 4, 18 }, /* Rome 2.0 */
{ 0x00000201, 28, 4, 18 }, /* Rome 2.1 */
{ 0x00000300, 28, 4, 18 }, /* Rome 3.0 */
{ 0x00000302, 28, 4, 18 }, /* Rome 3.2 */
{ 0x00000100, 20, 4, 8 }, /* Rome 1.0 */
{ 0x00000101, 20, 4, 8 }, /* Rome 1.1 */
{ 0x00000200, 28, 4, 16 }, /* Rome 2.0 */
{ 0x00000201, 28, 4, 16 }, /* Rome 2.1 */
{ 0x00000300, 28, 4, 16 }, /* Rome 3.0 */
{ 0x00000302, 28, 4, 16 }, /* Rome 3.2 */
{ 0x00130100, 40, 4, 16 }, /* WCN6855 1.0 */
{ 0x00130200, 40, 4, 16 }, /* WCN6855 2.0 */
};
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
......@@ -3528,8 +3576,8 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
{
struct qca_rampatch_version *rver;
const struct firmware *fw;
u32 ver_rom, ver_patch;
u16 rver_rom, rver_patch;
u32 ver_rom, ver_patch, rver_rom;
u16 rver_rom_low, rver_rom_high, rver_patch;
char fwname[64];
int err;
......@@ -3548,9 +3596,16 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
bt_dev_info(hdev, "using rampatch file: %s", fwname);
rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset);
rver_rom = le16_to_cpu(rver->rom_version);
rver_rom_low = le16_to_cpu(rver->rom_version_low);
rver_patch = le16_to_cpu(rver->patch_version);
if (ver_rom & ~0xffffU) {
rver_rom_high = le16_to_cpu(rver->rom_version_high);
rver_rom = le32_to_cpu(rver_rom_high << 16 | rver_rom_low);
} else {
rver_rom = rver_rom_low;
}
bt_dev_info(hdev, "QCA: patch rome 0x%x build 0x%x, "
"firmware rome 0x%x build 0x%x",
rver_rom, rver_patch, ver_rom, ver_patch);
......@@ -3624,9 +3679,6 @@ static int btusb_setup_qca(struct hci_dev *hdev)
return err;
ver_rom = le32_to_cpu(ver.rom_version);
/* Don't care about high ROM versions */
if (ver_rom & ~0xffffU)
return 0;
for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) {
if (ver_rom == qca_devices_table[i].rom_version)
......@@ -4062,6 +4114,13 @@ static int btusb_probe(struct usb_interface *intf,
btusb_check_needs_reset_resume(intf);
}
if (id->driver_info & BTUSB_QCA_WCN6855) {
data->setup_on_usb = btusb_setup_qca;
hdev->set_bdaddr = btusb_set_bdaddr_wcn6855;
hdev->cmd_timeout = btusb_qca_cmd_timeout;
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
}
if (id->driver_info & BTUSB_AMP) {
/* AMP controllers do not support SCO packets */
data->isoc = NULL;
......
......@@ -793,8 +793,6 @@ static int h5_serdev_probe(struct serdev_device *serdev)
if (!h5)
return -ENOMEM;
set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.hdev_flags);
h5->hu = &h5->serdev_hu;
h5->serdev_hu.serdev = serdev;
serdev_device_set_drvdata(serdev, h5);
......
......@@ -288,7 +288,7 @@ static irqreturn_t intel_irq(int irq, void *dev_id)
static int intel_set_power(struct hci_uart *hu, bool powered)
{
struct list_head *p;
struct intel_device *idev;
int err = -ENODEV;
if (!hu->tty->dev)
......@@ -296,10 +296,7 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *idev = list_entry(p, struct intel_device,
list);
list_for_each_entry(idev, &intel_device_list, list) {
/* tty device and pdev device should share the same parent
* which is the UART port.
*/
......@@ -362,19 +359,16 @@ static int intel_set_power(struct hci_uart *hu, bool powered)
static void intel_busy_work(struct work_struct *work)
{
struct list_head *p;
struct intel_data *intel = container_of(work, struct intel_data,
busy_work);
struct intel_device *idev;
if (!intel->hu->tty->dev)
return;
/* Link is busy, delay the suspend */
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *idev = list_entry(p, struct intel_device,
list);
list_for_each_entry(idev, &intel_device_list, list) {
if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) {
pm_runtime_get(&idev->pdev->dev);
pm_runtime_mark_last_busy(&idev->pdev->dev);
......@@ -533,7 +527,7 @@ static int intel_setup(struct hci_uart *hu)
struct sk_buff *skb;
struct intel_version ver;
struct intel_boot_params params;
struct list_head *p;
struct intel_device *idev;
const struct firmware *fw;
char fwname[64];
u32 boot_param;
......@@ -693,14 +687,11 @@ static int intel_setup(struct hci_uart *hu)
case 0x0b: /* SfP */
case 0x0c: /* WsP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.sfi",
le16_to_cpu(ver.hw_variant),
le16_to_cpu(params.dev_revid));
ver.hw_variant, le16_to_cpu(params.dev_revid));
break;
case 0x12: /* ThP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.sfi",
le16_to_cpu(ver.hw_variant),
le16_to_cpu(ver.hw_revision),
le16_to_cpu(ver.fw_revision));
ver.hw_variant, ver.hw_revision, ver.fw_revision);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
......@@ -722,14 +713,11 @@ static int intel_setup(struct hci_uart *hu)
case 0x0b: /* SfP */
case 0x0c: /* WsP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u.ddc",
le16_to_cpu(ver.hw_variant),
le16_to_cpu(params.dev_revid));
ver.hw_variant, le16_to_cpu(params.dev_revid));
break;
case 0x12: /* ThP */
snprintf(fwname, sizeof(fwname), "intel/ibt-%u-%u-%u.ddc",
le16_to_cpu(ver.hw_variant),
le16_to_cpu(ver.hw_revision),
le16_to_cpu(ver.fw_revision));
ver.hw_variant, ver.hw_revision, ver.fw_revision);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hardware variant (%u)",
......@@ -839,13 +827,11 @@ static int intel_setup(struct hci_uart *hu)
* until further LPM TX notification.
*/
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *dev = list_entry(p, struct intel_device,
list);
list_for_each_entry(idev, &intel_device_list, list) {
if (!hu->tty->dev)
break;
if (hu->tty->dev->parent == dev->pdev->dev.parent) {
if (device_may_wakeup(&dev->pdev->dev)) {
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
if (device_may_wakeup(&idev->pdev->dev)) {
set_bit(STATE_LPM_ENABLED, &intel->flags);
set_bit(STATE_TX_ACTIVE, &intel->flags);
}
......@@ -999,7 +985,7 @@ static int intel_recv(struct hci_uart *hu, const void *data, int count)
static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
{
struct intel_data *intel = hu->priv;
struct list_head *p;
struct intel_device *idev;
BT_DBG("hu %p skb %p", hu, skb);
......@@ -1010,10 +996,7 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
* completed before enqueuing any packet.
*/
mutex_lock(&intel_device_list_lock);
list_for_each(p, &intel_device_list) {
struct intel_device *idev = list_entry(p, struct intel_device,
list);
list_for_each_entry(idev, &intel_device_list, list) {
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
pm_runtime_get_sync(&idev->pdev->dev);
pm_runtime_mark_last_busy(&idev->pdev->dev);
......@@ -1076,7 +1059,8 @@ static const struct hci_uart_proto intel_proto = {
#ifdef CONFIG_ACPI
static const struct acpi_device_id intel_acpi_match[] = {
{ "INT33E1", 0 },
{ },
{ "INT33E3", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, intel_acpi_match);
#endif
......@@ -1138,9 +1122,9 @@ static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params host_wake_gpios = { 1, 0, false };
static const struct acpi_gpio_mapping acpi_hci_intel_gpios[] = {
{ "reset-gpios", &reset_gpios, 1 },
{ "host-wake-gpios", &host_wake_gpios, 1 },
{ },
{ "reset-gpios", &reset_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ "host-wake-gpios", &host_wake_gpios, 1, ACPI_GPIO_QUIRK_ONLY_GPIOIO },
{ }
};
static int intel_probe(struct platform_device *pdev)
......
......@@ -538,6 +538,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
percpu_up_write(&hu->proto_lock);
cancel_work_sync(&hu->init_ready);
cancel_work_sync(&hu->write_work);
if (hdev) {
......
......@@ -693,8 +693,6 @@ static int qca_close(struct hci_uart *hu)
destroy_workqueue(qca->workqueue);
qca->hu = NULL;
qca_power_shutdown(hu);
kfree_skb(qca->rx_skb);
hu->priv = NULL;
......@@ -2007,8 +2005,7 @@ static int qca_serdev_probe(struct serdev_device *serdev)
err = hci_uart_register_device(&qcadev->serdev_hu, &qca_proto);
if (err) {
BT_ERR("Rome serdev registration failed");
if (qcadev->susclk)
clk_disable_unprepare(qcadev->susclk);
clk_disable_unprepare(qcadev->susclk);
return err;
}
}
......@@ -2032,8 +2029,9 @@ static int qca_serdev_probe(struct serdev_device *serdev)
static void qca_serdev_remove(struct serdev_device *serdev)
{
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
struct qca_power *power = qcadev->bt_power;
if (qca_is_wcn399x(qcadev->btsoc_type))
if (qca_is_wcn399x(qcadev->btsoc_type) && power->vregs_on)
qca_power_shutdown(&qcadev->serdev_hu);
else if (qcadev->susclk)
clk_disable_unprepare(qcadev->susclk);
......
......@@ -113,8 +113,22 @@ static int hci_uart_flush(struct hci_dev *hdev)
/* Initialize device */
static int hci_uart_open(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
int err;
BT_DBG("%s %p", hdev->name, hdev);
/* When Quirk HCI_QUIRK_NON_PERSISTENT_SETUP is set by
* driver, BT SoC is completely turned OFF during
* BT OFF. Upon next BT ON UART port should be opened.
*/
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
err = serdev_device_open(hu->serdev);
if (err)
return err;
set_bit(HCI_UART_PROTO_READY, &hu->flags);
}
/* Undo clearing this from hci_uart_close() */
hdev->flush = hci_uart_flush;
......@@ -124,11 +138,25 @@ static int hci_uart_open(struct hci_dev *hdev)
/* Close device */
static int hci_uart_close(struct hci_dev *hdev)
{
struct hci_uart *hu = hci_get_drvdata(hdev);
BT_DBG("hdev %p", hdev);
if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
return 0;
hci_uart_flush(hdev);
hdev->flush = NULL;
/* When QUIRK HCI_QUIRK_NON_PERSISTENT_SETUP is set by driver,
* BT SOC is completely powered OFF during BT OFF, holding port
* open may drain the battery.
*/
if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) {
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
serdev_device_close(hu->serdev);
}
return 0;
}
......@@ -354,7 +382,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
{
struct hci_dev *hdev = hu->hdev;
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
cancel_work_sync(&hu->init_ready);
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
hci_unregister_dev(hdev);
hci_free_dev(hdev);
......@@ -362,6 +390,10 @@ void hci_uart_unregister_device(struct hci_uart *hu)
cancel_work_sync(&hu->write_work);
hu->proto->close(hu);
serdev_device_close(hu->serdev);
if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
clear_bit(HCI_UART_PROTO_READY, &hu->flags);
serdev_device_close(hu->serdev);
}
}
EXPORT_SYMBOL_GPL(hci_uart_unregister_device);
......@@ -484,6 +484,9 @@ struct hci_dev {
enum suspended_state suspend_state;
bool scanning_paused;
bool suspended;
u8 wake_reason;
bdaddr_t wake_addr;
u8 wake_addr_type;
wait_queue_head_t suspend_wait_q;
DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS);
......@@ -1750,6 +1753,9 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, s8 rssi, u8 *name, u8 name_len);
void mgmt_discovering(struct hci_dev *hdev, u8 discovering);
void mgmt_suspending(struct hci_dev *hdev, u8 state);
void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
u8 addr_type);
bool mgmt_powering_down(struct hci_dev *hdev);
void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, bool persistent);
void mgmt_new_irk(struct hci_dev *hdev, struct smp_irk *irk, bool persistent);
......
......@@ -665,6 +665,8 @@ struct l2cap_ops {
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
unsigned long hdr_len,
unsigned long len, int nb);
int (*filter) (struct l2cap_chan * chan,
struct sk_buff *skb);
};
struct l2cap_conn {
......
......@@ -572,6 +572,8 @@ struct mgmt_rp_add_advertising {
#define MGMT_ADV_FLAG_SEC_1M BIT(7)
#define MGMT_ADV_FLAG_SEC_2M BIT(8)
#define MGMT_ADV_FLAG_SEC_CODED BIT(9)
#define MGMT_ADV_FLAG_CAN_SET_TX_POWER BIT(10)
#define MGMT_ADV_FLAG_HW_OFFLOAD BIT(11)
#define MGMT_ADV_FLAG_SEC_MASK (MGMT_ADV_FLAG_SEC_1M | MGMT_ADV_FLAG_SEC_2M | \
MGMT_ADV_FLAG_SEC_CODED)
......@@ -840,6 +842,7 @@ struct mgmt_ev_device_connected {
#define MGMT_DEV_DISCONN_LOCAL_HOST 0x02
#define MGMT_DEV_DISCONN_REMOTE 0x03
#define MGMT_DEV_DISCONN_AUTH_FAILURE 0x04
#define MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND 0x05
#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
struct mgmt_ev_device_disconnected {
......@@ -1028,3 +1031,18 @@ struct mgmt_ev_adv_monitor_added {
struct mgmt_ev_adv_monitor_removed {
__le16 monitor_handle;
} __packed;
#define MGMT_EV_CONTROLLER_SUSPEND 0x002d
struct mgmt_ev_controller_suspend {
__u8 suspend_state;
} __packed;
#define MGMT_EV_CONTROLLER_RESUME 0x002e
struct mgmt_ev_controller_resume {
__u8 wake_reason;
struct mgmt_addr_info addr;
} __packed;
#define MGMT_WAKE_REASON_NON_BT_WAKE 0x0
#define MGMT_WAKE_REASON_UNEXPECTED 0x1
#define MGMT_WAKE_REASON_REMOTE_WAKE 0x2
......@@ -64,7 +64,6 @@ source "net/bluetooth/hidp/Kconfig"
config BT_HS
bool "Bluetooth High Speed (HS) features"
depends on BT_BREDR
default y
help
Bluetooth High Speed includes support for off-loading
Bluetooth connections via 802.11 (wifi) physical layer
......
......@@ -226,6 +226,9 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_info_req req;
found = true;
memset(&req, 0, sizeof(req));
req.id = cl->id;
a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr),
sizeof(req), &req);
......@@ -305,6 +308,8 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
if (!hdev || hdev->dev_type != HCI_AMP) {
struct a2mp_info_rsp rsp;
memset(&rsp, 0, sizeof(rsp));
rsp.id = req->id;
rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
......@@ -348,6 +353,8 @@ static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
if (!ctrl)
return -ENOMEM;
memset(&req, 0, sizeof(req));
req.id = rsp->id;
a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req),
&req);
......@@ -376,6 +383,8 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_amp_assoc_rsp rsp;
rsp.id = req->id;
memset(&rsp, 0, sizeof(rsp));
if (tmp) {
rsp.status = A2MP_STATUS_COLLISION_OCCURED;
amp_mgr_put(tmp);
......@@ -464,7 +473,6 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
struct a2mp_physlink_req *req = (void *) skb->data;
struct a2mp_physlink_rsp rsp;
struct hci_dev *hdev;
struct hci_conn *hcon;
......@@ -475,6 +483,8 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
memset(&rsp, 0, sizeof(rsp));
rsp.local_id = req->remote_id;
rsp.remote_id = req->local_id;
......@@ -553,6 +563,8 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
memset(&rsp, 0, sizeof(rsp));
rsp.local_id = req->remote_id;
rsp.remote_id = req->local_id;
rsp.status = A2MP_STATUS_SUCCESS;
......@@ -675,6 +687,8 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
if (err) {
struct a2mp_cmd_rej rej;
memset(&rej, 0, sizeof(rej));
rej.reason = cpu_to_le16(0);
hdr = (void *) skb->data;
......@@ -898,6 +912,8 @@ void a2mp_send_getinfo_rsp(struct hci_dev *hdev)
BT_DBG("%s mgr %p", hdev->name, mgr);
memset(&rsp, 0, sizeof(rsp));
rsp.id = hdev->id;
rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
......@@ -995,6 +1011,8 @@ void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status)
if (!mgr)
return;
memset(&rsp, 0, sizeof(rsp));
hs_hcon = hci_conn_hash_lookup_state(hdev, AMP_LINK, BT_CONNECT);
if (!hs_hcon) {
rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
......@@ -1027,6 +1045,8 @@ void a2mp_discover_amp(struct l2cap_chan *chan)
mgr->bredr_chan = chan;
memset(&req, 0, sizeof(req));
req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
req.ext_feat = 0;
a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
......
......@@ -2963,7 +2963,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
sizeof(adv_instance->scan_rsp_data));
} else {
if (hdev->adv_instance_cnt >= hdev->le_num_of_adv_sets ||
instance < 1 || instance > HCI_MAX_ADV_INSTANCES)
instance < 1 || instance > hdev->le_num_of_adv_sets)
return -EOVERFLOW;
adv_instance = kzalloc(sizeof(*adv_instance), GFP_KERNEL);
......@@ -3061,6 +3061,7 @@ static int free_adv_monitor(int id, void *ptr, void *data)
idr_remove(&hdev->adv_monitors_idr, monitor->handle);
hci_free_adv_monitor(monitor);
hdev->adv_monitors_cnt--;
return 0;
}
......@@ -3077,6 +3078,7 @@ int hci_remove_adv_monitor(struct hci_dev *hdev, u16 handle)
idr_remove(&hdev->adv_monitors_idr, monitor->handle);
hci_free_adv_monitor(monitor);
hdev->adv_monitors_cnt--;
} else {
/* Remove all monitors if handle is 0. */
idr_for_each(&hdev->adv_monitors_idr, &free_adv_monitor, hdev);
......@@ -3442,6 +3444,16 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
}
}
static void hci_suspend_clear_tasks(struct hci_dev *hdev)
{
int i;
for (i = 0; i < __SUSPEND_NUM_TASKS; i++)
clear_bit(i, hdev->suspend_tasks);
wake_up(&hdev->suspend_wait_q);
}
static int hci_suspend_wait_event(struct hci_dev *hdev)
{
#define WAKE_COND \
......@@ -3487,12 +3499,24 @@ static int hci_change_suspend_state(struct hci_dev *hdev,
return hci_suspend_wait_event(hdev);
}
static void hci_clear_wake_reason(struct hci_dev *hdev)
{
hci_dev_lock(hdev);
hdev->wake_reason = 0;
bacpy(&hdev->wake_addr, BDADDR_ANY);
hdev->wake_addr_type = 0;
hci_dev_unlock(hdev);
}
static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
void *data)
{
struct hci_dev *hdev =
container_of(nb, struct hci_dev, suspend_notifier);
int ret = 0;
u8 state = BT_RUNNING;
/* If powering down, wait for completion. */
if (mgmt_powering_down(hdev)) {
......@@ -3513,15 +3537,27 @@ static int hci_suspend_notifier(struct notifier_block *nb, unsigned long action,
* - Second, program event filter/whitelist and enable scan
*/
ret = hci_change_suspend_state(hdev, BT_SUSPEND_DISCONNECT);
if (!ret)
state = BT_SUSPEND_DISCONNECT;
/* Only configure whitelist if disconnect succeeded and wake
* isn't being prevented.
*/
if (!ret && !(hdev->prevent_wake && hdev->prevent_wake(hdev)))
if (!ret && !(hdev->prevent_wake && hdev->prevent_wake(hdev))) {
ret = hci_change_suspend_state(hdev,
BT_SUSPEND_CONFIGURE_WAKE);
if (!ret)
state = BT_SUSPEND_CONFIGURE_WAKE;
}
hci_clear_wake_reason(hdev);
mgmt_suspending(hdev, state);
} else if (action == PM_POST_SUSPEND) {
ret = hci_change_suspend_state(hdev, BT_RUNNING);
mgmt_resuming(hdev, hdev->wake_reason, &hdev->wake_addr,
hdev->wake_addr_type);
}
done:
......@@ -3784,6 +3820,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
cancel_work_sync(&hdev->power_on);
hci_suspend_clear_tasks(hdev);
unregister_pm_notifier(&hdev->suspend_notifier);
cancel_work_sync(&hdev->suspend_prepare);
......
......@@ -2569,7 +2569,6 @@ static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_conn_complete *ev = (void *) skb->data;
struct inquiry_entry *ie;
struct hci_conn *conn;
BT_DBG("%s", hdev->name);
......@@ -2578,13 +2577,19 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
if (!conn) {
/* Connection may not exist if auto-connected. Check the inquiry
* cache to see if we've already discovered this bdaddr before.
* If found and link is an ACL type, create a connection class
/* Connection may not exist if auto-connected. Check the bredr
* allowlist to see if this device is allowed to auto connect.
* If link is an ACL type, create a connection class
* automatically.
*
* Auto-connect will only occur if the event filter is
* programmed with a given address. Right now, event filter is
* only used during suspend.
*/
ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
if (ie && ev->link_type == ACL_LINK) {
if (ev->link_type == ACL_LINK &&
hci_bdaddr_list_lookup_with_flags(&hdev->whitelist,
&ev->bdaddr,
BDADDR_BREDR)) {
conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr,
HCI_ROLE_SLAVE);
if (!conn) {
......@@ -6012,6 +6017,75 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode,
return true;
}
static void hci_store_wake_reason(struct hci_dev *hdev, u8 event,
struct sk_buff *skb)
{
struct hci_ev_le_advertising_info *adv;
struct hci_ev_le_direct_adv_info *direct_adv;
struct hci_ev_le_ext_adv_report *ext_adv;
const struct hci_ev_conn_complete *conn_complete = (void *)skb->data;
const struct hci_ev_conn_request *conn_request = (void *)skb->data;
hci_dev_lock(hdev);
/* If we are currently suspended and this is the first BT event seen,
* save the wake reason associated with the event.
*/
if (!hdev->suspended || hdev->wake_reason)
goto unlock;
/* Default to remote wake. Values for wake_reason are documented in the
* Bluez mgmt api docs.
*/
hdev->wake_reason = MGMT_WAKE_REASON_REMOTE_WAKE;
/* Once configured for remote wakeup, we should only wake up for
* reconnections. It's useful to see which device is waking us up so
* keep track of the bdaddr of the connection event that woke us up.
*/
if (event == HCI_EV_CONN_REQUEST) {
bacpy(&hdev->wake_addr, &conn_complete->bdaddr);
hdev->wake_addr_type = BDADDR_BREDR;
} else if (event == HCI_EV_CONN_COMPLETE) {
bacpy(&hdev->wake_addr, &conn_request->bdaddr);
hdev->wake_addr_type = BDADDR_BREDR;
} else if (event == HCI_EV_LE_META) {
struct hci_ev_le_meta *le_ev = (void *)skb->data;
u8 subevent = le_ev->subevent;
u8 *ptr = &skb->data[sizeof(*le_ev)];
u8 num_reports = *ptr;
if ((subevent == HCI_EV_LE_ADVERTISING_REPORT ||
subevent == HCI_EV_LE_DIRECT_ADV_REPORT ||
subevent == HCI_EV_LE_EXT_ADV_REPORT) &&
num_reports) {
adv = (void *)(ptr + 1);
direct_adv = (void *)(ptr + 1);
ext_adv = (void *)(ptr + 1);
switch (subevent) {
case HCI_EV_LE_ADVERTISING_REPORT:
bacpy(&hdev->wake_addr, &adv->bdaddr);
hdev->wake_addr_type = adv->bdaddr_type;
break;
case HCI_EV_LE_DIRECT_ADV_REPORT:
bacpy(&hdev->wake_addr, &direct_adv->bdaddr);
hdev->wake_addr_type = direct_adv->bdaddr_type;
break;
case HCI_EV_LE_EXT_ADV_REPORT:
bacpy(&hdev->wake_addr, &ext_adv->bdaddr);
hdev->wake_addr_type = ext_adv->bdaddr_type;
break;
}
}
} else {
hdev->wake_reason = MGMT_WAKE_REASON_UNEXPECTED;
}
unlock:
hci_dev_unlock(hdev);
}
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_event_hdr *hdr = (void *) skb->data;
......@@ -6045,6 +6119,9 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
skb_pull(skb, HCI_EVENT_HDR_SIZE);
/* Store wake reason if we're suspended */
hci_store_wake_reason(hdev, event, skb);
switch (event) {
case HCI_EV_INQUIRY_COMPLETE:
hci_inquiry_complete_evt(hdev, skb);
......
......@@ -1027,6 +1027,9 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
} else if (hci_is_le_conn_scanning(hdev)) {
window = hdev->le_scan_window_connect;
interval = hdev->le_scan_int_connect;
} else if (hci_is_adv_monitoring(hdev)) {
window = hdev->le_scan_window_adv_monitor;
interval = hdev->le_scan_int_adv_monitor;
} else {
window = hdev->le_scan_window;
interval = hdev->le_scan_interval;
......@@ -1111,6 +1114,53 @@ static void hci_req_config_le_suspend_scan(struct hci_request *req)
set_bit(SUSPEND_SCAN_ENABLE, req->hdev->suspend_tasks);
}
static void cancel_adv_timeout(struct hci_dev *hdev)
{
if (hdev->adv_instance_timeout) {
hdev->adv_instance_timeout = 0;
cancel_delayed_work(&hdev->adv_instance_expire);
}
}
/* This function requires the caller holds hdev->lock */
static void hci_suspend_adv_instances(struct hci_request *req)
{
bt_dev_dbg(req->hdev, "Suspending advertising instances");
/* Call to disable any advertisements active on the controller.
* This will succeed even if no advertisements are configured.
*/
__hci_req_disable_advertising(req);
/* If we are using software rotation, pause the loop */
if (!ext_adv_capable(req->hdev))
cancel_adv_timeout(req->hdev);
}
/* This function requires the caller holds hdev->lock */
static void hci_resume_adv_instances(struct hci_request *req)
{
struct adv_info *adv;
bt_dev_dbg(req->hdev, "Resuming advertising instances");
if (ext_adv_capable(req->hdev)) {
/* Call for each tracked instance to be re-enabled */
list_for_each_entry(adv, &req->hdev->adv_instances, list) {
__hci_req_enable_ext_advertising(req,
adv->instance);
}
} else {
/* Schedule for most recent instance to be restarted and begin
* the software rotation loop
*/
__hci_req_schedule_adv_instance(req,
req->hdev->cur_adv_instance,
true);
}
}
static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode)
{
bt_dev_dbg(hdev, "Request complete opcode=0x%x, status=0x%x", opcode,
......@@ -1153,7 +1203,7 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
hdev->discovery_paused = true;
hdev->discovery_old_state = old_state;
/* Stop advertising */
/* Stop directed advertising */
old_state = hci_dev_test_flag(hdev, HCI_ADVERTISING);
if (old_state) {
set_bit(SUSPEND_PAUSE_ADVERTISING, hdev->suspend_tasks);
......@@ -1162,6 +1212,10 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
&hdev->discov_off, 0);
}
/* Pause other advertisements */
if (hdev->adv_instance_cnt)
hci_suspend_adv_instances(&req);
hdev->advertising_paused = true;
hdev->advertising_old_state = old_state;
/* Disable page scan */
......@@ -1212,7 +1266,7 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
/* Reset passive/background scanning to normal */
hci_req_config_le_suspend_scan(&req);
/* Unpause advertising */
/* Unpause directed advertising */
hdev->advertising_paused = false;
if (hdev->advertising_old_state) {
set_bit(SUSPEND_UNPAUSE_ADVERTISING,
......@@ -1223,6 +1277,10 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
hdev->advertising_old_state = 0;
}
/* Resume other advertisements */
if (hdev->adv_instance_cnt)
hci_resume_adv_instances(&req);
/* Unpause discovery */
hdev->discovery_paused = false;
if (hdev->discovery_old_state != DISCOVERY_STOPPED &&
......@@ -1533,11 +1591,14 @@ void __hci_req_update_scan_rsp_data(struct hci_request *req, u8 instance)
memset(&cp, 0, sizeof(cp));
if (instance)
/* Extended scan response data doesn't allow a response to be
* set if the instance isn't scannable.
*/
if (get_adv_instance_scan_rsp_len(hdev, instance))
len = create_instance_scan_rsp_data(hdev, instance,
cp.data);
else
len = create_default_scan_rsp_data(hdev, cp.data);
len = 0;
if (hdev->scan_rsp_data_len == len &&
!memcmp(cp.data, hdev->scan_rsp_data, len))
......@@ -1824,7 +1885,13 @@ int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
if (use_rpa) {
int to;
*own_addr_type = ADDR_LE_DEV_RANDOM;
/* If Controller supports LL Privacy use own address type is
* 0x03
*/
if (use_ll_privacy(hdev))
*own_addr_type = ADDR_LE_DEV_RANDOM_RESOLVED;
else
*own_addr_type = ADDR_LE_DEV_RANDOM;
if (adv_instance) {
if (!adv_instance->rpa_expired &&
......@@ -2183,14 +2250,6 @@ int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
return 0;
}
static void cancel_adv_timeout(struct hci_dev *hdev)
{
if (hdev->adv_instance_timeout) {
hdev->adv_instance_timeout = 0;
cancel_delayed_work(&hdev->adv_instance_expire);
}
}
/* For a single instance:
* - force == true: The instance will be removed even when its remaining
* lifetime is not zero.
......
......@@ -7301,9 +7301,10 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
goto drop;
}
if ((chan->mode == L2CAP_MODE_ERTM ||
chan->mode == L2CAP_MODE_STREAMING) && sk_filter(chan->data, skb))
goto drop;
if (chan->ops->filter) {
if (chan->ops->filter(chan, skb))
goto drop;
}
if (!control->sframe) {
int err;
......
......@@ -1521,8 +1521,6 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
parent = bt_sk(sk)->parent;
sock_set_flag(sk, SOCK_ZAPPED);
switch (chan->state) {
case BT_OPEN:
case BT_BOUND:
......@@ -1549,8 +1547,11 @@ static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
break;
}
release_sock(sk);
/* Only zap after cleanup to avoid use after free race */
sock_set_flag(sk, SOCK_ZAPPED);
}
static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state,
......@@ -1663,6 +1664,19 @@ static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
sk->sk_state_change(sk);
}
static int l2cap_sock_filter(struct l2cap_chan *chan, struct sk_buff *skb)
{
struct sock *sk = chan->data;
switch (chan->mode) {
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
return sk_filter(sk, skb);
}
return 0;
}
static const struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
......@@ -1678,6 +1692,7 @@ static const struct l2cap_ops l2cap_chan_ops = {
.get_sndtimeo = l2cap_sock_get_sndtimeo_cb,
.get_peer_pid = l2cap_sock_get_peer_pid_cb,
.alloc_skb = l2cap_sock_alloc_skb_cb,
.filter = l2cap_sock_filter,
};
static void l2cap_sock_destruct(struct sock *sk)
......
......@@ -163,6 +163,8 @@ static const u16 mgmt_events[] = {
MGMT_EV_PHY_CONFIGURATION_CHANGED,
MGMT_EV_EXP_FEATURE_CHANGED,
MGMT_EV_DEVICE_FLAGS_CHANGED,
MGMT_EV_CONTROLLER_SUSPEND,
MGMT_EV_CONTROLLER_RESUME,
};
static const u16 mgmt_untrusted_commands[] = {
......@@ -782,7 +784,8 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (lmp_ssp_capable(hdev)) {
settings |= MGMT_SETTING_SSP;
settings |= MGMT_SETTING_HS;
if (IS_ENABLED(CONFIG_BT_HS))
settings |= MGMT_SETTING_HS;
}
if (lmp_sc_capable(hdev))
......@@ -1815,6 +1818,10 @@ static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
bt_dev_dbg(hdev, "sock %p", sk);
if (!IS_ENABLED(CONFIG_BT_HS))
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
MGMT_STATUS_NOT_SUPPORTED);
status = mgmt_bredr_support(hdev);
if (status)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
......@@ -4157,7 +4164,7 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
{
struct adv_monitor *monitor = NULL;
struct mgmt_rp_read_adv_monitor_features *rp = NULL;
int handle;
int handle, err;
size_t rp_size = 0;
__u32 supported = 0;
__u16 num_handles = 0;
......@@ -4192,9 +4199,13 @@ static int read_adv_mon_features(struct sock *sk, struct hci_dev *hdev,
if (num_handles)
memcpy(&rp->handles, &handles, (num_handles * sizeof(u16)));
return mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_READ_ADV_MONITOR_FEATURES,
MGMT_STATUS_SUCCESS, rp, rp_size);
err = mgmt_cmd_complete(sk, hdev->id,
MGMT_OP_READ_ADV_MONITOR_FEATURES,
MGMT_STATUS_SUCCESS, rp, rp_size);
kfree(rp);
return err;
}
static int add_adv_patterns_monitor(struct sock *sk, struct hci_dev *hdev,
......@@ -7202,6 +7213,8 @@ static u32 get_supported_adv_flags(struct hci_dev *hdev)
if (ext_adv_capable(hdev)) {
flags |= MGMT_ADV_FLAG_SEC_1M;
flags |= MGMT_ADV_FLAG_HW_OFFLOAD;
flags |= MGMT_ADV_FLAG_CAN_SET_TX_POWER;
if (hdev->le_features[1] & HCI_LE_PHY_2M)
flags |= MGMT_ADV_FLAG_SEC_2M;
......@@ -7250,7 +7263,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev,
rp->supported_flags = cpu_to_le32(supported_flags);
rp->max_adv_data_len = HCI_MAX_AD_LENGTH;
rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH;
rp->max_instances = HCI_MAX_ADV_INSTANCES;
rp->max_instances = hdev->le_num_of_adv_sets;
rp->num_instances = hdev->adv_instance_cnt;
instance = rp->instance;
......@@ -7446,7 +7459,7 @@ static int add_advertising(struct sock *sk, struct hci_dev *hdev,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
MGMT_STATUS_NOT_SUPPORTED);
if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING,
MGMT_STATUS_INVALID_PARAMS);
......@@ -7699,7 +7712,7 @@ static int get_adv_size_info(struct sock *sk, struct hci_dev *hdev,
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_STATUS_REJECTED);
if (cp->instance < 1 || cp->instance > HCI_MAX_ADV_INSTANCES)
if (cp->instance < 1 || cp->instance > hdev->le_num_of_adv_sets)
return mgmt_cmd_status(sk, hdev->id, MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_STATUS_INVALID_PARAMS);
......@@ -8262,6 +8275,10 @@ void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
ev.addr.type = link_to_bdaddr(link_type, addr_type);
ev.reason = reason;
/* Report disconnects due to suspend */
if (hdev->suspended)
ev.reason = MGMT_DEV_DISCONN_LOCAL_HOST_SUSPEND;
mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
if (sk)
......@@ -8868,6 +8885,30 @@ void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
}
void mgmt_suspending(struct hci_dev *hdev, u8 state)
{
struct mgmt_ev_controller_suspend ev;
ev.suspend_state = state;
mgmt_event(MGMT_EV_CONTROLLER_SUSPEND, hdev, &ev, sizeof(ev), NULL);
}
void mgmt_resuming(struct hci_dev *hdev, u8 reason, bdaddr_t *bdaddr,
u8 addr_type)
{
struct mgmt_ev_controller_resume ev;
ev.wake_reason = reason;
if (bdaddr) {
bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = addr_type;
} else {
memset(&ev.addr, 0, sizeof(ev.addr));
}
mgmt_event(MGMT_EV_CONTROLLER_RESUME, hdev, &ev, sizeof(ev), NULL);
}
static struct hci_mgmt_chan chan = {
.channel = HCI_CHANNEL_CONTROL,
.handler_count = ARRAY_SIZE(mgmt_handlers),
......
......@@ -1001,6 +1001,12 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
err = -EFAULT;
break;
case BT_SNDMTU:
case BT_RCVMTU:
if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval))
err = -EFAULT;
break;
default:
err = -ENOPROTOOPT;
break;
......
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