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:
Jakub Kicinski 2022-01-28 13:39:04 -08:00
commit 0a78117213
19 changed files with 676 additions and 105 deletions

View file

@ -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);

View file

@ -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,
};

View file

@ -1,4 +1,4 @@
/**
/*
* Marvell Bluetooth driver: debugfs related functions
*
* Copyright (C) 2009, Marvell International Ltd.

View file

@ -1,4 +1,4 @@
/**
/*
* Marvell BT-over-SDIO driver: SDIO interface related functions.
*
* Copyright (C) 2009, Marvell International Ltd.

View file

@ -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;

View file

@ -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 @@ static int btmtksdio_open(struct hci_dev *hdev)
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 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
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 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname)
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 = &reg_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;
}

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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)

View file

@ -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;

View file

@ -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,

View file

@ -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)