mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
bluetooth-next pull request for net-next:
- Add support for RTL8822C hci_ver 0x08 - Add support for RTL8852AE part 0bda:2852 - Fix WBS setting for Intel legacy ROM products - Enable SCO over I2S ib mt7921s - Increment management interface revision -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmH0VmcZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKciID/98aC7pDP9XpIVPRKNuEeev gukoNdcxmWo4IOMGJD7FzfEa5uHkhTWxgngohOJycT0ssTWShFnWezmyCgDaEvU6 s/swQrq+iGRXSDacuawh7lRrwNqJjl9AEw89asPzk9jFIETSfnGF0nqMinSayj5I zUPjkkg2KgsBKON0o3+W0MTpBexg9tU2mVPMxpgkYjbTi08vP47sRW7R3O7Z2agB EWf4+spZWjhPma2InrLj/+9h0jaU7y0p/9g5+Y5dpzAT0jXzYg2lDivSsjB6ry2R CX726zxTzygY0wyKYrLxQE5xsK7DFe7zhnRIY18cJtmlPwZ8SSc9kkLZQ33qWIKp Zo6ObumXxIqwOh6Yu13evQ12aZE3sMynhe+Se9QLwZ744EShkGEwFVd0XfkIQhe8 nI4x6ys0GDIV/dHHztbraz5QXgqML7TVzKymkdhfdncGSseLVTb0nm14kYNG+LYK yokzGWm3SoC/YXfBMZmaTI+Ch8ZftvBoReIYx4FJQuI195W7E+NB7wrQ+oArblnt Wy36Yj47TtZH4xSOlmZ/wNM/ry1q1QyRE3n32N0/mXc/8NgyPgWUbs/CSrUjBJmf wU/POZSJvL2K/EDySAZJNhWfML3LTT+1ZCWzHckVNHzFb/Q2D6llgUfptMlxfjFU m7s4R3xT3oAZgu1pocbHKw== =/KS7 -----END PGP SIGNATURE----- Merge tag 'for-net-next-2022-01-28' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next Luiz Augusto von Dentz says: ==================== bluetooth-next pull request for net-next: - Add support for RTL8822C hci_ver 0x08 - Add support for RTL8852AE part 0bda:2852 - Fix WBS setting for Intel legacy ROM products - Enable SCO over I2S ib mt7921s - Increment management interface revision * tag 'for-net-next-2022-01-28' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (30 commits) Bluetooth: Increment management interface revision Bluetooth: hci_sync: Fix queuing commands when HCI_UNREGISTER is set Bluetooth: hci_h5: Add power reset via gpio in h5_btrtl_open Bluetooth: btrtl: Add support for RTL8822C hci_ver 0x08 Bluetooth: hci_event: Fix HCI_EV_VENDOR max_len Bluetooth: hci_core: Rate limit the logging of invalid SCO handle Bluetooth: hci_event: Ignore multiple conn complete events Bluetooth: msft: fix null pointer deref on msft_monitor_device_evt Bluetooth: btmtksdio: mask out interrupt status Bluetooth: btmtksdio: run sleep mode by default Bluetooth: btmtksdio: lower log level in btmtksdio_runtime_[resume|suspend]() Bluetooth: mt7921s: fix btmtksdio_[drv|fw]_pmctrl() Bluetooth: mt7921s: fix bus hang with wrong privilege Bluetooth: btmtksdio: refactor btmtksdio_runtime_[suspend|resume]() Bluetooth: mt7921s: fix firmware coredump retrieve Bluetooth: hci_serdev: call init_rwsem() before p->open() Bluetooth: Remove kernel-doc style comment block Bluetooth: btusb: Whitespace fixes for btusb_setup_csr() Bluetooth: btusb: Add one more Bluetooth part for the Realtek RTL8852AE Bluetooth: btintel: Fix WBS setting for Intel legacy ROM products ... ==================== Link: https://lore.kernel.org/r/20220128205915.3995760-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
0a78117213
@ -2428,10 +2428,15 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
||||
|
||||
/* Apply the device specific HCI quirks
|
||||
*
|
||||
* WBS for SdP - SdP and Stp have a same hw_varaint but
|
||||
* different fw_variant
|
||||
* WBS for SdP - For the Legacy ROM products, only SdP
|
||||
* supports the WBS. But the version information is not
|
||||
* enough to use here because the StP2 and SdP have same
|
||||
* hw_variant and fw_variant. So, this flag is set by
|
||||
* the transport driver (btusb) based on the HW info
|
||||
* (idProduct)
|
||||
*/
|
||||
if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22)
|
||||
if (!btintel_test_flag(hdev,
|
||||
INTEL_ROM_LEGACY_NO_WBS_SUPPORT))
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
|
||||
&hdev->quirks);
|
||||
|
||||
|
@ -152,6 +152,7 @@ enum {
|
||||
INTEL_BROKEN_INITIAL_NCMD,
|
||||
INTEL_BROKEN_SHUTDOWN_LED,
|
||||
INTEL_ROM_LEGACY,
|
||||
INTEL_ROM_LEGACY_NO_WBS_SUPPORT,
|
||||
|
||||
__INTEL_NUM_FLAGS,
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Marvell Bluetooth driver: debugfs related functions
|
||||
*
|
||||
* Copyright (C) 2009, Marvell International Ltd.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* Marvell BT-over-SDIO driver: SDIO interface related functions.
|
||||
*
|
||||
* Copyright (C) 2009, Marvell International Ltd.
|
||||
|
@ -7,8 +7,12 @@
|
||||
|
||||
#define HCI_WMT_MAX_EVENT_SIZE 64
|
||||
|
||||
#define BTMTK_WMT_REG_WRITE 0x1
|
||||
#define BTMTK_WMT_REG_READ 0x2
|
||||
|
||||
#define MT7921_PINMUX_0 0x70005050
|
||||
#define MT7921_PINMUX_1 0x70005054
|
||||
|
||||
enum {
|
||||
BTMTK_WMT_PATCH_DWNLD = 0x1,
|
||||
BTMTK_WMT_TEST = 0x2,
|
||||
@ -68,6 +72,37 @@ struct btmtk_tci_sleep {
|
||||
u8 time_compensation;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_wakeon {
|
||||
u8 mode;
|
||||
u8 gpo;
|
||||
u8 active_high;
|
||||
__le16 enable_delay;
|
||||
__le16 wakeup_delay;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_sco {
|
||||
u8 clock_config;
|
||||
u8 transmit_format_config;
|
||||
u8 channel_format_config;
|
||||
u8 channel_select_config;
|
||||
} __packed;
|
||||
|
||||
struct reg_read_cmd {
|
||||
u8 type;
|
||||
u8 rsv;
|
||||
u8 num;
|
||||
__le32 addr;
|
||||
} __packed;
|
||||
|
||||
struct reg_write_cmd {
|
||||
u8 type;
|
||||
u8 rsv;
|
||||
u8 num;
|
||||
__le32 addr;
|
||||
__le32 data;
|
||||
__le32 mask;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_params {
|
||||
u8 op;
|
||||
u8 flag;
|
||||
|
@ -31,28 +31,32 @@
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
#define MTKBTSDIO_AUTOSUSPEND_DELAY 8000
|
||||
#define MTKBTSDIO_AUTOSUSPEND_DELAY 1000
|
||||
|
||||
static bool enable_autosuspend;
|
||||
static bool enable_autosuspend = true;
|
||||
|
||||
struct btmtksdio_data {
|
||||
const char *fwname;
|
||||
u16 chipid;
|
||||
bool lp_mbox_supported;
|
||||
};
|
||||
|
||||
static const struct btmtksdio_data mt7663_data = {
|
||||
.fwname = FIRMWARE_MT7663,
|
||||
.chipid = 0x7663,
|
||||
.lp_mbox_supported = false,
|
||||
};
|
||||
|
||||
static const struct btmtksdio_data mt7668_data = {
|
||||
.fwname = FIRMWARE_MT7668,
|
||||
.chipid = 0x7668,
|
||||
.lp_mbox_supported = false,
|
||||
};
|
||||
|
||||
static const struct btmtksdio_data mt7921_data = {
|
||||
.fwname = FIRMWARE_MT7961,
|
||||
.chipid = 0x7921,
|
||||
.lp_mbox_supported = true,
|
||||
};
|
||||
|
||||
static const struct sdio_device_id btmtksdio_table[] = {
|
||||
@ -87,8 +91,17 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
#define RX_DONE_INT BIT(1)
|
||||
#define TX_EMPTY BIT(2)
|
||||
#define TX_FIFO_OVERFLOW BIT(8)
|
||||
#define FW_MAILBOX_INT BIT(15)
|
||||
#define INT_MASK GENMASK(15, 0)
|
||||
#define RX_PKT_LEN GENMASK(31, 16)
|
||||
|
||||
#define MTK_REG_CSICR 0xc0
|
||||
#define CSICR_CLR_MBOX_ACK BIT(0)
|
||||
#define MTK_REG_PH2DSM0R 0xc4
|
||||
#define PH2DSM0R_DRIVER_OWN BIT(0)
|
||||
#define MTK_REG_PD2HRM0R 0xdc
|
||||
#define PD2HRM0R_DRV_OWN BIT(0)
|
||||
|
||||
#define MTK_REG_CTDR 0x18
|
||||
|
||||
#define MTK_REG_CRDR 0x1c
|
||||
@ -100,6 +113,7 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table);
|
||||
#define BTMTKSDIO_TX_WAIT_VND_EVT 1
|
||||
#define BTMTKSDIO_HW_TX_READY 2
|
||||
#define BTMTKSDIO_FUNC_ENABLED 3
|
||||
#define BTMTKSDIO_PATCH_ENABLED 4
|
||||
|
||||
struct mtkbtsdio_hdr {
|
||||
__le16 len;
|
||||
@ -278,6 +292,78 @@ static u32 btmtksdio_drv_own_query(struct btmtksdio_dev *bdev)
|
||||
return sdio_readl(bdev->func, MTK_REG_CHLPCR, NULL);
|
||||
}
|
||||
|
||||
static u32 btmtksdio_drv_own_query_79xx(struct btmtksdio_dev *bdev)
|
||||
{
|
||||
return sdio_readl(bdev->func, MTK_REG_PD2HRM0R, NULL);
|
||||
}
|
||||
|
||||
static int btmtksdio_fw_pmctrl(struct btmtksdio_dev *bdev)
|
||||
{
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
if (bdev->data->lp_mbox_supported &&
|
||||
test_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state)) {
|
||||
sdio_writel(bdev->func, CSICR_CLR_MBOX_ACK, MTK_REG_CSICR,
|
||||
&err);
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query_79xx, bdev,
|
||||
status, !(status & PD2HRM0R_DRV_OWN),
|
||||
2000, 1000000);
|
||||
if (err < 0) {
|
||||
bt_dev_err(bdev->hdev, "mailbox ACK not cleared");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return ownership to the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
!(status & C_COM_DRV_OWN), 2000, 1000000);
|
||||
|
||||
out:
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
if (err < 0)
|
||||
bt_dev_err(bdev->hdev, "Cannot return ownership to device");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_drv_pmctrl(struct btmtksdio_dev *bdev)
|
||||
{
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
/* Get ownership from the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
status & C_COM_DRV_OWN, 2000, 1000000);
|
||||
|
||||
if (!err && bdev->data->lp_mbox_supported &&
|
||||
test_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state))
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query_79xx, bdev,
|
||||
status, status & PD2HRM0R_DRV_OWN,
|
||||
2000, 1000000);
|
||||
|
||||
out:
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
if (err < 0)
|
||||
bt_dev_err(bdev->hdev, "Cannot get ownership from device");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
@ -480,6 +566,13 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
||||
* FIFO.
|
||||
*/
|
||||
sdio_writel(bdev->func, int_status, MTK_REG_CHISR, NULL);
|
||||
int_status &= INT_MASK;
|
||||
|
||||
if ((int_status & FW_MAILBOX_INT) &&
|
||||
bdev->data->chipid == 0x7921) {
|
||||
sdio_writel(bdev->func, PH2DSM0R_DRIVER_OWN,
|
||||
MTK_REG_PH2DSM0R, 0);
|
||||
}
|
||||
|
||||
if (int_status & FW_OWN_BACK_INT)
|
||||
bt_dev_dbg(bdev->hdev, "Get fw own back");
|
||||
@ -531,7 +624,7 @@ static void btmtksdio_interrupt(struct sdio_func *func)
|
||||
static int btmtksdio_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
u32 status, val;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
@ -542,18 +635,10 @@ static int btmtksdio_open(struct hci_dev *hdev)
|
||||
|
||||
set_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
|
||||
|
||||
/* Get ownership from the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);
|
||||
err = btmtksdio_drv_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
goto err_disable_func;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
status & C_COM_DRV_OWN, 2000, 1000000);
|
||||
if (err < 0) {
|
||||
bt_dev_err(bdev->hdev, "Cannot get ownership from device");
|
||||
goto err_disable_func;
|
||||
}
|
||||
|
||||
/* Disable interrupt & mask out all interrupt sources */
|
||||
sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
@ -623,8 +708,6 @@ err_release_host:
|
||||
static int btmtksdio_close(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
|
||||
@ -635,13 +718,7 @@ static int btmtksdio_close(struct hci_dev *hdev)
|
||||
|
||||
cancel_work_sync(&bdev->txrx_work);
|
||||
|
||||
/* Return ownership to the device */
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, NULL);
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
!(status & C_COM_DRV_OWN), 2000, 1000000);
|
||||
if (err < 0)
|
||||
bt_dev_err(bdev->hdev, "Cannot return ownership to device");
|
||||
btmtksdio_fw_pmctrl(bdev);
|
||||
|
||||
clear_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state);
|
||||
sdio_disable_func(bdev->func);
|
||||
@ -686,6 +763,7 @@ static int btmtksdio_func_query(struct hci_dev *hdev)
|
||||
|
||||
static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
struct btmtk_tci_sleep tci_sleep;
|
||||
struct sk_buff *skb;
|
||||
@ -746,6 +824,8 @@ ignore_setup_fw:
|
||||
return err;
|
||||
}
|
||||
|
||||
set_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state);
|
||||
|
||||
ignore_func_on:
|
||||
/* Apply the low power environment setup */
|
||||
tci_sleep.mode = 0x5;
|
||||
@ -768,6 +848,7 @@ ignore_func_on:
|
||||
|
||||
static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
u8 param = 0x1;
|
||||
int err;
|
||||
@ -793,19 +874,15 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
|
||||
|
||||
hci_set_msft_opcode(hdev, 0xFD30);
|
||||
hci_set_aosp_capable(hdev);
|
||||
set_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
static int btmtksdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
{
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
struct reg_read_cmd {
|
||||
u8 type;
|
||||
u8 rsv;
|
||||
u8 num;
|
||||
__le32 addr;
|
||||
} __packed reg_read = {
|
||||
struct reg_read_cmd reg_read = {
|
||||
.type = 1,
|
||||
.num = 1,
|
||||
};
|
||||
@ -821,7 +898,7 @@ static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to read reg(%d)", err);
|
||||
bt_dev_err(hdev, "Failed to read reg (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -830,6 +907,66 @@ static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_mtk_reg_write(struct hci_dev *hdev, u32 reg, u32 val, u32 mask)
|
||||
{
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
const struct reg_write_cmd reg_write = {
|
||||
.type = 1,
|
||||
.num = 1,
|
||||
.addr = cpu_to_le32(reg),
|
||||
.data = cpu_to_le32(val),
|
||||
.mask = cpu_to_le32(mask),
|
||||
};
|
||||
int err, status;
|
||||
|
||||
wmt_params.op = BTMTK_WMT_REGISTER;
|
||||
wmt_params.flag = BTMTK_WMT_REG_WRITE;
|
||||
wmt_params.dlen = sizeof(reg_write);
|
||||
wmt_params.data = ®_write;
|
||||
wmt_params.status = &status;
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0)
|
||||
bt_dev_err(hdev, "Failed to write reg (%d)", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_sco_setting(struct hci_dev *hdev)
|
||||
{
|
||||
const struct btmtk_sco sco_setting = {
|
||||
.clock_config = 0x49,
|
||||
.channel_format_config = 0x80,
|
||||
};
|
||||
struct sk_buff *skb;
|
||||
u32 val;
|
||||
int err;
|
||||
|
||||
/* Enable SCO over I2S/PCM for MediaTek chipset */
|
||||
skb = __hci_cmd_sync(hdev, 0xfc72, sizeof(sco_setting),
|
||||
&sco_setting, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
err = btmtksdio_mtk_reg_read(hdev, MT7921_PINMUX_0, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val |= 0x11000000;
|
||||
err = btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_0, val, ~0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_mtk_reg_read(hdev, MT7921_PINMUX_1, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val |= 0x00000101;
|
||||
return btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_1, val, ~0);
|
||||
}
|
||||
|
||||
static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
@ -844,13 +981,13 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
|
||||
switch (bdev->data->chipid) {
|
||||
case 0x7921:
|
||||
err = btsdio_mtk_reg_read(hdev, 0x70010200, &dev_id);
|
||||
err = btmtksdio_mtk_reg_read(hdev, 0x70010200, &dev_id);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to get device id (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = btsdio_mtk_reg_read(hdev, 0x80021004, &fw_version);
|
||||
err = btmtksdio_mtk_reg_read(hdev, 0x80021004, &fw_version);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to get fw version (%d)", err);
|
||||
return err;
|
||||
@ -862,6 +999,22 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
err = mt79xx_setup(hdev, fwname);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_fw_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_drv_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Enable SCO over I2S/PCM */
|
||||
err = btmtksdio_sco_setting(hdev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to enable SCO setting (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x7663:
|
||||
case 0x7668:
|
||||
@ -958,6 +1111,32 @@ static int btmtksdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool btmtksdio_sdio_wakeup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
bool may_wakeup = device_may_wakeup(bdev->dev);
|
||||
const struct btmtk_wakeon bt_awake = {
|
||||
.mode = 0x1,
|
||||
.gpo = 0,
|
||||
.active_high = 0x1,
|
||||
.enable_delay = cpu_to_le16(0xc80),
|
||||
.wakeup_delay = cpu_to_le16(0x20),
|
||||
};
|
||||
|
||||
if (may_wakeup && bdev->data->chipid == 0x7921) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc27, sizeof(bt_awake),
|
||||
&bt_awake, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb))
|
||||
may_wakeup = false;
|
||||
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
return may_wakeup;
|
||||
}
|
||||
|
||||
static int btmtksdio_probe(struct sdio_func *func,
|
||||
const struct sdio_device_id *id)
|
||||
{
|
||||
@ -997,6 +1176,7 @@ static int btmtksdio_probe(struct sdio_func *func,
|
||||
hdev->setup = btmtksdio_setup;
|
||||
hdev->shutdown = btmtksdio_shutdown;
|
||||
hdev->send = btmtksdio_send_frame;
|
||||
hdev->wakeup = btmtksdio_sdio_wakeup;
|
||||
hdev->set_bdaddr = btmtk_set_bdaddr;
|
||||
|
||||
SET_HCIDEV_DEV(hdev, &func->dev);
|
||||
@ -1032,7 +1212,11 @@ static int btmtksdio_probe(struct sdio_func *func,
|
||||
*/
|
||||
pm_runtime_put_noidle(bdev->dev);
|
||||
|
||||
return 0;
|
||||
err = device_init_wakeup(bdev->dev, true);
|
||||
if (err)
|
||||
bt_dev_err(hdev, "failed to initialize device wakeup");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void btmtksdio_remove(struct sdio_func *func)
|
||||
@ -1058,7 +1242,6 @@ static int btmtksdio_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct btmtksdio_dev *bdev;
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
bdev = sdio_get_drvdata(func);
|
||||
@ -1070,18 +1253,9 @@ static int btmtksdio_runtime_suspend(struct device *dev)
|
||||
|
||||
sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
err = btmtksdio_fw_pmctrl(bdev);
|
||||
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
!(status & C_COM_DRV_OWN), 2000, 1000000);
|
||||
out:
|
||||
bt_dev_info(bdev->hdev, "status (%d) return ownership to device", err);
|
||||
|
||||
sdio_release_host(bdev->func);
|
||||
bt_dev_dbg(bdev->hdev, "status (%d) return ownership to device", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -1090,7 +1264,6 @@ static int btmtksdio_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdio_func *func = dev_to_sdio_func(dev);
|
||||
struct btmtksdio_dev *bdev;
|
||||
u32 status;
|
||||
int err;
|
||||
|
||||
bdev = sdio_get_drvdata(func);
|
||||
@ -1100,18 +1273,9 @@ static int btmtksdio_runtime_resume(struct device *dev)
|
||||
if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state))
|
||||
return 0;
|
||||
|
||||
sdio_claim_host(bdev->func);
|
||||
err = btmtksdio_drv_pmctrl(bdev);
|
||||
|
||||
sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status,
|
||||
status & C_COM_DRV_OWN, 2000, 1000000);
|
||||
out:
|
||||
bt_dev_info(bdev->hdev, "status (%d) get ownership from device", err);
|
||||
|
||||
sdio_release_host(bdev->func);
|
||||
bt_dev_dbg(bdev->hdev, "status (%d) get ownership from device", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -148,6 +148,14 @@ static const struct id_table ic_id_table[] = {
|
||||
.fw_name = "rtl_bt/rtl8761bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8761bu_config" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART),
|
||||
.config_needed = true,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8822cs_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8822cs_config" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART),
|
||||
.config_needed = true,
|
||||
|
@ -62,6 +62,7 @@ static struct usb_driver btusb_driver;
|
||||
#define BTUSB_QCA_WCN6855 0x1000000
|
||||
#define BTUSB_INTEL_BROKEN_SHUTDOWN_LED 0x2000000
|
||||
#define BTUSB_INTEL_BROKEN_INITIAL_NCMD 0x4000000
|
||||
#define BTUSB_INTEL_NO_WBS_SUPPORT 0x8000000
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
@ -385,9 +386,11 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR },
|
||||
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
BTUSB_INTEL_NO_WBS_SUPPORT |
|
||||
BTUSB_INTEL_BROKEN_INITIAL_NCMD |
|
||||
BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
|
||||
{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
BTUSB_INTEL_NO_WBS_SUPPORT |
|
||||
BTUSB_INTEL_BROKEN_SHUTDOWN_LED },
|
||||
{ USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_COMBINED },
|
||||
{ USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED |
|
||||
@ -405,6 +408,8 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Realtek 8852AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0xc852), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0bda, 0x385a), .driver_info = BTUSB_REALTEK |
|
||||
@ -2057,10 +2062,10 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
||||
* These controllers are really messed-up.
|
||||
*
|
||||
* 1. Their bulk RX endpoint will never report any data unless
|
||||
* the device was suspended at least once (yes, really).
|
||||
* the device was suspended at least once (yes, really).
|
||||
* 2. They will not wakeup when autosuspended and receiving data
|
||||
* on their bulk RX endpoint from e.g. a keyboard or mouse
|
||||
* (IOW remote-wakeup support is broken for the bulk endpoint).
|
||||
* on their bulk RX endpoint from e.g. a keyboard or mouse
|
||||
* (IOW remote-wakeup support is broken for the bulk endpoint).
|
||||
*
|
||||
* To fix 1. enable runtime-suspend, force-suspend the
|
||||
* HCI and then wake-it up by disabling runtime-suspend.
|
||||
@ -3737,6 +3742,9 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->send = btusb_send_frame_intel;
|
||||
hdev->cmd_timeout = btusb_intel_cmd_timeout;
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL_NO_WBS_SUPPORT)
|
||||
btintel_set_flag(hdev, INTEL_ROM_LEGACY_NO_WBS_SUPPORT);
|
||||
|
||||
if (id->driver_info & BTUSB_INTEL_BROKEN_INITIAL_NCMD)
|
||||
btintel_set_flag(hdev, INTEL_BROKEN_INITIAL_NCMD);
|
||||
|
||||
|
@ -966,6 +966,11 @@ static void h5_btrtl_open(struct h5 *h5)
|
||||
pm_runtime_enable(&h5->hu->serdev->dev);
|
||||
}
|
||||
|
||||
/* The controller needs reset to startup */
|
||||
gpiod_set_value_cansleep(h5->enable_gpio, 0);
|
||||
gpiod_set_value_cansleep(h5->device_wake_gpio, 0);
|
||||
msleep(100);
|
||||
|
||||
/* The controller needs up to 500ms to wakeup */
|
||||
gpiod_set_value_cansleep(h5->enable_gpio, 1);
|
||||
gpiod_set_value_cansleep(h5->device_wake_gpio, 1);
|
||||
|
@ -509,7 +509,7 @@ static int send_command_from_firmware(struct ll_device *lldev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* download_firmware -
|
||||
* internal function which parses through the .bts firmware
|
||||
* script file intreprets SEND, DELAY actions only as of now
|
||||
|
@ -305,6 +305,8 @@ int hci_uart_register_device(struct hci_uart *hu,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
percpu_init_rwsem(&hu->proto_lock);
|
||||
|
||||
err = p->open(hu);
|
||||
if (err)
|
||||
goto err_open;
|
||||
@ -327,7 +329,6 @@ int hci_uart_register_device(struct hci_uart *hu,
|
||||
|
||||
INIT_WORK(&hu->init_ready, hci_uart_init_work);
|
||||
INIT_WORK(&hu->write_work, hci_uart_write_work);
|
||||
percpu_init_rwsem(&hu->proto_lock);
|
||||
|
||||
/* Only when vendor specific setup callback is provided, consider
|
||||
* the manufacturer information valid. This avoids filling in the
|
||||
|
@ -258,6 +258,15 @@ struct adv_info {
|
||||
|
||||
#define HCI_ADV_TX_POWER_NO_PREFERENCE 0x7F
|
||||
|
||||
struct monitored_device {
|
||||
struct list_head list;
|
||||
|
||||
bdaddr_t bdaddr;
|
||||
__u8 addr_type;
|
||||
__u16 handle;
|
||||
bool notified;
|
||||
};
|
||||
|
||||
struct adv_pattern {
|
||||
struct list_head list;
|
||||
__u8 ad_type;
|
||||
@ -294,6 +303,9 @@ struct adv_monitor {
|
||||
|
||||
#define HCI_MAX_SHORT_NAME_LENGTH 10
|
||||
|
||||
#define HCI_CONN_HANDLE_UNSET 0xffff
|
||||
#define HCI_CONN_HANDLE_MAX 0x0eff
|
||||
|
||||
/* Min encryption key size to match with SMP */
|
||||
#define HCI_MIN_ENC_KEY_SIZE 7
|
||||
|
||||
@ -591,6 +603,9 @@ struct hci_dev {
|
||||
|
||||
struct delayed_work interleave_scan;
|
||||
|
||||
struct list_head monitored_devices;
|
||||
bool advmon_pend_notify;
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_LEDS)
|
||||
struct led_trigger *power_led;
|
||||
#endif
|
||||
@ -1847,6 +1862,8 @@ void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle);
|
||||
int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip);
|
||||
int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status);
|
||||
int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status);
|
||||
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
|
||||
bdaddr_t *bdaddr, u8 addr_type);
|
||||
|
||||
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
|
||||
u16 to_multiplier);
|
||||
|
@ -1104,3 +1104,19 @@ struct mgmt_ev_controller_resume {
|
||||
#define MGMT_WAKE_REASON_NON_BT_WAKE 0x0
|
||||
#define MGMT_WAKE_REASON_UNEXPECTED 0x1
|
||||
#define MGMT_WAKE_REASON_REMOTE_WAKE 0x2
|
||||
|
||||
#define MGMT_EV_ADV_MONITOR_DEVICE_FOUND 0x002f
|
||||
struct mgmt_ev_adv_monitor_device_found {
|
||||
__le16 monitor_handle;
|
||||
struct mgmt_addr_info addr;
|
||||
__s8 rssi;
|
||||
__le32 flags;
|
||||
__le16 eir_len;
|
||||
__u8 eir[0];
|
||||
} __packed;
|
||||
|
||||
#define MGMT_EV_ADV_MONITOR_DEVICE_LOST 0x0030
|
||||
struct mgmt_ev_adv_monitor_device_lost {
|
||||
__le16 monitor_handle;
|
||||
struct mgmt_addr_info addr;
|
||||
} __packed;
|
||||
|
@ -689,6 +689,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
|
||||
bacpy(&conn->dst, dst);
|
||||
bacpy(&conn->src, &hdev->bdaddr);
|
||||
conn->handle = HCI_CONN_HANDLE_UNSET;
|
||||
conn->hdev = hdev;
|
||||
conn->type = type;
|
||||
conn->role = role;
|
||||
|
@ -2503,6 +2503,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
|
||||
INIT_LIST_HEAD(&hdev->conn_hash.list);
|
||||
INIT_LIST_HEAD(&hdev->adv_instances);
|
||||
INIT_LIST_HEAD(&hdev->blocked_keys);
|
||||
INIT_LIST_HEAD(&hdev->monitored_devices);
|
||||
|
||||
INIT_LIST_HEAD(&hdev->local_codecs);
|
||||
INIT_WORK(&hdev->rx_work, hci_rx_work);
|
||||
@ -3666,8 +3667,8 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
sco_recv_scodata(conn, skb);
|
||||
return;
|
||||
} else {
|
||||
bt_dev_err(hdev, "SCO packet for unknown connection handle %d",
|
||||
handle);
|
||||
bt_dev_err_ratelimited(hdev, "SCO packet for unknown connection handle %d",
|
||||
handle);
|
||||
}
|
||||
|
||||
kfree_skb(skb);
|
||||
|
@ -3068,6 +3068,11 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
struct hci_ev_conn_complete *ev = data;
|
||||
struct hci_conn *conn;
|
||||
|
||||
if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) {
|
||||
bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for invalid handle");
|
||||
return;
|
||||
}
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
@ -3106,6 +3111,17 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
}
|
||||
}
|
||||
|
||||
/* The HCI_Connection_Complete event is only sent once per connection.
|
||||
* Processing it more than once per connection can corrupt kernel memory.
|
||||
*
|
||||
* As the connection handle is set here for the first time, it indicates
|
||||
* whether the connection is already set up.
|
||||
*/
|
||||
if (conn->handle != HCI_CONN_HANDLE_UNSET) {
|
||||
bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!ev->status) {
|
||||
conn->handle = __le16_to_cpu(ev->handle);
|
||||
|
||||
@ -4534,7 +4550,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata,
|
||||
if (!info) {
|
||||
bt_dev_err(hdev, "Malformed HCI Event: 0x%2.2x",
|
||||
HCI_EV_INQUIRY_RESULT_WITH_RSSI);
|
||||
return;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
bacpy(&data.bdaddr, &info->bdaddr);
|
||||
@ -4565,7 +4581,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata,
|
||||
if (!info) {
|
||||
bt_dev_err(hdev, "Malformed HCI Event: 0x%2.2x",
|
||||
HCI_EV_INQUIRY_RESULT_WITH_RSSI);
|
||||
return;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
bacpy(&data.bdaddr, &info->bdaddr);
|
||||
@ -4587,7 +4603,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata,
|
||||
bt_dev_err(hdev, "Malformed HCI Event: 0x%2.2x",
|
||||
HCI_EV_INQUIRY_RESULT_WITH_RSSI);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
@ -4661,6 +4677,24 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
struct hci_ev_sync_conn_complete *ev = data;
|
||||
struct hci_conn *conn;
|
||||
|
||||
switch (ev->link_type) {
|
||||
case SCO_LINK:
|
||||
case ESCO_LINK:
|
||||
break;
|
||||
default:
|
||||
/* As per Core 5.3 Vol 4 Part E 7.7.35 (p.2219), Link_Type
|
||||
* for HCI_Synchronous_Connection_Complete is limited to
|
||||
* either SCO or eSCO
|
||||
*/
|
||||
bt_dev_err(hdev, "Ignoring connect complete event for invalid link type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) {
|
||||
bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete for invalid handle");
|
||||
return;
|
||||
}
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
@ -4684,23 +4718,19 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data,
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* The HCI_Synchronous_Connection_Complete event is only sent once per connection.
|
||||
* Processing it more than once per connection can corrupt kernel memory.
|
||||
*
|
||||
* As the connection handle is set here for the first time, it indicates
|
||||
* whether the connection is already set up.
|
||||
*/
|
||||
if (conn->handle != HCI_CONN_HANDLE_UNSET) {
|
||||
bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete event for existing connection");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
switch (ev->status) {
|
||||
case 0x00:
|
||||
/* The synchronous connection complete event should only be
|
||||
* sent once per new connection. Receiving a successful
|
||||
* complete event when the connection status is already
|
||||
* BT_CONNECTED means that the device is misbehaving and sent
|
||||
* multiple complete event packets for the same new connection.
|
||||
*
|
||||
* Registering the device more than once can corrupt kernel
|
||||
* memory, hence upon detecting this invalid event, we report
|
||||
* an error and ignore the packet.
|
||||
*/
|
||||
if (conn->state == BT_CONNECTED) {
|
||||
bt_dev_err(hdev, "Ignoring connect complete event for existing connection");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
conn->handle = __le16_to_cpu(ev->handle);
|
||||
conn->state = BT_CONNECTED;
|
||||
conn->type = ev->link_type;
|
||||
@ -5496,6 +5526,11 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||
struct smp_irk *irk;
|
||||
u8 addr_type;
|
||||
|
||||
if (handle > HCI_CONN_HANDLE_MAX) {
|
||||
bt_dev_err(hdev, "Ignoring HCI_LE_Connection_Complete for invalid handle");
|
||||
return;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* All controllers implicitly stop advertising in the event of a
|
||||
@ -5537,6 +5572,17 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||
cancel_delayed_work(&conn->le_conn_timeout);
|
||||
}
|
||||
|
||||
/* The HCI_LE_Connection_Complete event is only sent once per connection.
|
||||
* Processing it more than once per connection can corrupt kernel memory.
|
||||
*
|
||||
* As the connection handle is set here for the first time, it indicates
|
||||
* whether the connection is already set up.
|
||||
*/
|
||||
if (conn->handle != HCI_CONN_HANDLE_UNSET) {
|
||||
bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
le_conn_update_addr(conn, bdaddr, bdaddr_type, local_rpa);
|
||||
|
||||
/* Lookup the identity address from the stored connection
|
||||
@ -6798,7 +6844,7 @@ static const struct hci_ev {
|
||||
HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt,
|
||||
sizeof(struct hci_ev_num_comp_blocks)),
|
||||
/* [0xff = HCI_EV_VENDOR] */
|
||||
HCI_EV(HCI_EV_VENDOR, msft_vendor_evt, 0),
|
||||
HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE),
|
||||
};
|
||||
|
||||
static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb,
|
||||
@ -6823,8 +6869,9 @@ static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb,
|
||||
* decide if that is acceptable.
|
||||
*/
|
||||
if (skb->len > ev->max_len)
|
||||
bt_dev_warn(hdev, "unexpected event 0x%2.2x length: %u > %u",
|
||||
event, skb->len, ev->max_len);
|
||||
bt_dev_warn_ratelimited(hdev,
|
||||
"unexpected event 0x%2.2x length: %u > %u",
|
||||
event, skb->len, ev->max_len);
|
||||
|
||||
data = hci_ev_skb_pull(hdev, skb, event, ev->min_len);
|
||||
if (!data)
|
||||
|
@ -382,6 +382,9 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
|
||||
{
|
||||
struct hci_cmd_sync_work_entry *entry;
|
||||
|
||||
if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
|
||||
return -ENODEV;
|
||||
|
||||
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
@ -5140,8 +5143,8 @@ static void set_ext_conn_params(struct hci_conn *conn,
|
||||
p->max_ce_len = cpu_to_le16(0x0000);
|
||||
}
|
||||
|
||||
int hci_le_ext_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
u8 own_addr_type)
|
||||
static int hci_le_ext_create_conn_sync(struct hci_dev *hdev,
|
||||
struct hci_conn *conn, u8 own_addr_type)
|
||||
{
|
||||
struct hci_cp_le_ext_create_conn *cp;
|
||||
struct hci_cp_le_ext_conn_param *p;
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include "aosp.h"
|
||||
|
||||
#define MGMT_VERSION 1
|
||||
#define MGMT_REVISION 21
|
||||
#define MGMT_REVISION 22
|
||||
|
||||
static const u16 mgmt_commands[] = {
|
||||
MGMT_OP_READ_INDEX_LIST,
|
||||
@ -174,6 +174,8 @@ static const u16 mgmt_events[] = {
|
||||
MGMT_EV_ADV_MONITOR_REMOVED,
|
||||
MGMT_EV_CONTROLLER_SUSPEND,
|
||||
MGMT_EV_CONTROLLER_RESUME,
|
||||
MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
|
||||
MGMT_EV_ADV_MONITOR_DEVICE_LOST,
|
||||
};
|
||||
|
||||
static const u16 mgmt_untrusted_commands[] = {
|
||||
@ -9589,12 +9591,116 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir,
|
||||
return true;
|
||||
}
|
||||
|
||||
void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
|
||||
bdaddr_t *bdaddr, u8 addr_type)
|
||||
{
|
||||
struct mgmt_ev_adv_monitor_device_lost ev;
|
||||
|
||||
ev.monitor_handle = cpu_to_le16(handle);
|
||||
bacpy(&ev.addr.bdaddr, bdaddr);
|
||||
ev.addr.type = addr_type;
|
||||
|
||||
mgmt_event(MGMT_EV_ADV_MONITOR_DEVICE_LOST, hdev, &ev, sizeof(ev),
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void mgmt_adv_monitor_device_found(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, bool report_device,
|
||||
struct sk_buff *skb,
|
||||
struct sock *skip_sk)
|
||||
{
|
||||
struct sk_buff *advmon_skb;
|
||||
size_t advmon_skb_len;
|
||||
__le16 *monitor_handle;
|
||||
struct monitored_device *dev, *tmp;
|
||||
bool matched = false;
|
||||
bool notify = false;
|
||||
|
||||
/* We have received the Advertisement Report because:
|
||||
* 1. the kernel has initiated active discovery
|
||||
* 2. if not, we have pend_le_reports > 0 in which case we are doing
|
||||
* passive scanning
|
||||
* 3. if none of the above is true, we have one or more active
|
||||
* Advertisement Monitor
|
||||
*
|
||||
* For case 1 and 2, report all advertisements via MGMT_EV_DEVICE_FOUND
|
||||
* and report ONLY one advertisement per device for the matched Monitor
|
||||
* via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event.
|
||||
*
|
||||
* For case 3, since we are not active scanning and all advertisements
|
||||
* received are due to a matched Advertisement Monitor, report all
|
||||
* advertisements ONLY via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event.
|
||||
*/
|
||||
if (report_device && !hdev->advmon_pend_notify) {
|
||||
mgmt_event_skb(skb, skip_sk);
|
||||
return;
|
||||
}
|
||||
|
||||
advmon_skb_len = (sizeof(struct mgmt_ev_adv_monitor_device_found) -
|
||||
sizeof(struct mgmt_ev_device_found)) + skb->len;
|
||||
advmon_skb = mgmt_alloc_skb(hdev, MGMT_EV_ADV_MONITOR_DEVICE_FOUND,
|
||||
advmon_skb_len);
|
||||
if (!advmon_skb) {
|
||||
if (report_device)
|
||||
mgmt_event_skb(skb, skip_sk);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ADV_MONITOR_DEVICE_FOUND is similar to DEVICE_FOUND event except
|
||||
* that it also has 'monitor_handle'. Make a copy of DEVICE_FOUND and
|
||||
* store monitor_handle of the matched monitor.
|
||||
*/
|
||||
monitor_handle = skb_put(advmon_skb, sizeof(*monitor_handle));
|
||||
skb_put_data(advmon_skb, skb->data, skb->len);
|
||||
|
||||
hdev->advmon_pend_notify = false;
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) {
|
||||
if (!bacmp(&dev->bdaddr, bdaddr)) {
|
||||
matched = true;
|
||||
|
||||
if (!dev->notified) {
|
||||
*monitor_handle = cpu_to_le16(dev->handle);
|
||||
notify = true;
|
||||
dev->notified = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dev->notified)
|
||||
hdev->advmon_pend_notify = true;
|
||||
}
|
||||
|
||||
if (!report_device &&
|
||||
((matched && !notify) || !msft_monitor_supported(hdev))) {
|
||||
/* Handle 0 indicates that we are not active scanning and this
|
||||
* is a subsequent advertisement report for an already matched
|
||||
* Advertisement Monitor or the controller offloading support
|
||||
* is not available.
|
||||
*/
|
||||
*monitor_handle = 0;
|
||||
notify = true;
|
||||
}
|
||||
|
||||
if (report_device)
|
||||
mgmt_event_skb(skb, skip_sk);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
|
||||
if (notify)
|
||||
mgmt_event_skb(advmon_skb, skip_sk);
|
||||
else
|
||||
kfree_skb(advmon_skb);
|
||||
}
|
||||
|
||||
void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
u8 addr_type, u8 *dev_class, s8 rssi, u32 flags,
|
||||
u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct mgmt_ev_device_found *ev;
|
||||
bool report_device = hci_discovery_active(hdev);
|
||||
|
||||
/* Don't send events for a non-kernel initiated discovery. With
|
||||
* LE one exception is if we have pend_le_reports > 0 in which
|
||||
@ -9603,11 +9709,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
if (!hci_discovery_active(hdev)) {
|
||||
if (link_type == ACL_LINK)
|
||||
return;
|
||||
if (link_type == LE_LINK &&
|
||||
list_empty(&hdev->pend_le_reports) &&
|
||||
!hci_is_adv_monitoring(hdev)) {
|
||||
if (link_type == LE_LINK && !list_empty(&hdev->pend_le_reports))
|
||||
report_device = true;
|
||||
else if (!hci_is_adv_monitoring(hdev))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (hdev->discovery.result_filtering) {
|
||||
@ -9672,7 +9777,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
|
||||
ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len);
|
||||
|
||||
mgmt_event_skb(skb, NULL);
|
||||
mgmt_adv_monitor_device_found(hdev, bdaddr, report_device, skb, NULL);
|
||||
}
|
||||
|
||||
void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
|
@ -80,6 +80,14 @@ struct msft_rp_le_set_advertisement_filter_enable {
|
||||
__u8 sub_opcode;
|
||||
} __packed;
|
||||
|
||||
#define MSFT_EV_LE_MONITOR_DEVICE 0x02
|
||||
struct msft_ev_le_monitor_device {
|
||||
__u8 addr_type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 monitor_handle;
|
||||
__u8 monitor_state;
|
||||
} __packed;
|
||||
|
||||
struct msft_monitor_advertisement_handle_data {
|
||||
__u8 msft_handle;
|
||||
__u16 mgmt_handle;
|
||||
@ -204,6 +212,37 @@ static struct msft_monitor_advertisement_handle_data *msft_find_handle_data
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle,
|
||||
bdaddr_t *bdaddr, __u8 addr_type,
|
||||
bool notify)
|
||||
{
|
||||
struct monitored_device *dev, *tmp;
|
||||
int count = 0;
|
||||
|
||||
list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) {
|
||||
/* mgmt_handle == 0 indicates remove all devices, whereas,
|
||||
* bdaddr == NULL indicates remove all devices matching the
|
||||
* mgmt_handle.
|
||||
*/
|
||||
if ((!mgmt_handle || dev->handle == mgmt_handle) &&
|
||||
(!bdaddr || (!bacmp(bdaddr, &dev->bdaddr) &&
|
||||
addr_type == dev->addr_type))) {
|
||||
if (notify && dev->notified) {
|
||||
mgmt_adv_monitor_device_lost(hdev, dev->handle,
|
||||
&dev->bdaddr,
|
||||
dev->addr_type);
|
||||
}
|
||||
|
||||
list_del(&dev->list);
|
||||
kfree(dev);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev,
|
||||
u8 status, u16 opcode,
|
||||
struct sk_buff *skb)
|
||||
@ -294,6 +333,10 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
|
||||
if (monitor && !msft->suspending)
|
||||
hci_free_adv_monitor(hdev, monitor);
|
||||
|
||||
/* Clear any monitored devices by this Adv Monitor */
|
||||
msft_monitor_device_del(hdev, handle_data->mgmt_handle, NULL,
|
||||
0, false);
|
||||
|
||||
list_del(&handle_data->list);
|
||||
kfree(handle_data);
|
||||
}
|
||||
@ -557,6 +600,14 @@ void msft_do_close(struct hci_dev *hdev)
|
||||
list_del(&handle_data->list);
|
||||
kfree(handle_data);
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Clear any devices that are being monitored and notify device lost */
|
||||
hdev->advmon_pend_notify = false;
|
||||
msft_monitor_device_del(hdev, 0, NULL, 0, true);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
void msft_register(struct hci_dev *hdev)
|
||||
@ -590,10 +641,101 @@ void msft_unregister(struct hci_dev *hdev)
|
||||
kfree(msft);
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static void msft_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
__u8 addr_type, __u16 mgmt_handle)
|
||||
{
|
||||
struct monitored_device *dev;
|
||||
|
||||
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
bt_dev_err(hdev, "MSFT vendor event %u: no memory",
|
||||
MSFT_EV_LE_MONITOR_DEVICE);
|
||||
return;
|
||||
}
|
||||
|
||||
bacpy(&dev->bdaddr, bdaddr);
|
||||
dev->addr_type = addr_type;
|
||||
dev->handle = mgmt_handle;
|
||||
dev->notified = false;
|
||||
|
||||
INIT_LIST_HEAD(&dev->list);
|
||||
list_add(&dev->list, &hdev->monitored_devices);
|
||||
hdev->advmon_pend_notify = true;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
__u8 addr_type, __u16 mgmt_handle)
|
||||
{
|
||||
if (!msft_monitor_device_del(hdev, mgmt_handle, bdaddr, addr_type,
|
||||
true)) {
|
||||
bt_dev_err(hdev, "MSFT vendor event %u: dev %pMR not in list",
|
||||
MSFT_EV_LE_MONITOR_DEVICE, bdaddr);
|
||||
}
|
||||
}
|
||||
|
||||
static void *msft_skb_pull(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
u8 ev, size_t len)
|
||||
{
|
||||
void *data;
|
||||
|
||||
data = skb_pull_data(skb, len);
|
||||
if (!data)
|
||||
bt_dev_err(hdev, "Malformed MSFT vendor event: 0x%02x", ev);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct msft_ev_le_monitor_device *ev;
|
||||
struct msft_monitor_advertisement_handle_data *handle_data;
|
||||
u8 addr_type;
|
||||
|
||||
ev = msft_skb_pull(hdev, skb, MSFT_EV_LE_MONITOR_DEVICE, sizeof(*ev));
|
||||
if (!ev)
|
||||
return;
|
||||
|
||||
bt_dev_dbg(hdev,
|
||||
"MSFT vendor event 0x%02x: handle 0x%04x state %d addr %pMR",
|
||||
MSFT_EV_LE_MONITOR_DEVICE, ev->monitor_handle,
|
||||
ev->monitor_state, &ev->bdaddr);
|
||||
|
||||
handle_data = msft_find_handle_data(hdev, ev->monitor_handle, false);
|
||||
if (!handle_data)
|
||||
return;
|
||||
|
||||
switch (ev->addr_type) {
|
||||
case ADDR_LE_DEV_PUBLIC:
|
||||
addr_type = BDADDR_LE_PUBLIC;
|
||||
break;
|
||||
|
||||
case ADDR_LE_DEV_RANDOM:
|
||||
addr_type = BDADDR_LE_RANDOM;
|
||||
break;
|
||||
|
||||
default:
|
||||
bt_dev_err(hdev,
|
||||
"MSFT vendor event 0x%02x: unknown addr type 0x%02x",
|
||||
MSFT_EV_LE_MONITOR_DEVICE, ev->addr_type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev->monitor_state)
|
||||
msft_device_found(hdev, &ev->bdaddr, addr_type,
|
||||
handle_data->mgmt_handle);
|
||||
else
|
||||
msft_device_lost(hdev, &ev->bdaddr, addr_type,
|
||||
handle_data->mgmt_handle);
|
||||
}
|
||||
|
||||
void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
|
||||
{
|
||||
struct msft_data *msft = hdev->msft_data;
|
||||
u8 event;
|
||||
u8 *evt_prefix;
|
||||
u8 *evt;
|
||||
|
||||
if (!msft)
|
||||
return;
|
||||
@ -602,13 +744,12 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
|
||||
* matches, and otherwise just return.
|
||||
*/
|
||||
if (msft->evt_prefix_len > 0) {
|
||||
if (skb->len < msft->evt_prefix_len)
|
||||
evt_prefix = msft_skb_pull(hdev, skb, 0, msft->evt_prefix_len);
|
||||
if (!evt_prefix)
|
||||
return;
|
||||
|
||||
if (memcmp(skb->data, msft->evt_prefix, msft->evt_prefix_len))
|
||||
if (memcmp(evt_prefix, msft->evt_prefix, msft->evt_prefix_len))
|
||||
return;
|
||||
|
||||
skb_pull(skb, msft->evt_prefix_len);
|
||||
}
|
||||
|
||||
/* Every event starts at least with an event code and the rest of
|
||||
@ -617,10 +758,23 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb)
|
||||
if (skb->len < 1)
|
||||
return;
|
||||
|
||||
event = *skb->data;
|
||||
skb_pull(skb, 1);
|
||||
evt = msft_skb_pull(hdev, skb, 0, sizeof(*evt));
|
||||
if (!evt)
|
||||
return;
|
||||
|
||||
bt_dev_dbg(hdev, "MSFT vendor event %u", event);
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
switch (*evt) {
|
||||
case MSFT_EV_LE_MONITOR_DEVICE:
|
||||
msft_monitor_device_evt(hdev, skb);
|
||||
break;
|
||||
|
||||
default:
|
||||
bt_dev_dbg(hdev, "MSFT vendor event 0x%02x", *evt);
|
||||
break;
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
__u64 msft_get_features(struct hci_dev *hdev)
|
||||
|
Loading…
Reference in New Issue
Block a user