bluetooth-next pull request for net-next:
- Add support for Asus TF103C - Add support for Realtek RTL8852B - Add support for Realtek RTL8723BE - Add WBS support to mt7921s -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmI1C18ZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKcd3D/938E8HOcntzWJJ42TE0UNY 5jJzHRKabMJRpEim8F/14bqk+2ZvTZKioe5GHxXcgYET0rfvqKuIlRiD/R0Qd9bu A/d422Egup5pJsBlNsjSEit7dPtY4P70/gQbeBwFmJahe91uXkhiygvfU+peot+u Gt/BOINmfjjCv1IWT3KMmadHIVARfWf6sJeiNxqb704JtUd81Q4AW9bkexMGX2rg 9E4YN9tK83ojiPcF67bhgrxyToTJTI6T6DAVFSbWBbPfBP7aZeYlcaMUmKAmy0QN g0J8NYndeH48gCDLbSu1MjK+oopDZeUoiGgCbF/ZEcUk1b0JpEjFNRavRwstN9ju FIAchh0sA8/R+Pxck/kWvPjag3nar8J7NeX6Z7YPocuUVyHiw1+jAzGzt6Fy7YXV wMLNbYgWb7jrPOT08d1TxMLuBYZ2gC2w9rRtMGawTRNGJM1dxCI3OxTt9x6TLmw9 /fkpWszu4NwSvB/qaqJ+O06EH+CnMzlvnl4b4+CfYZRrTFL91DHWOUQujWp1/HWW 4FSONIBmXv13N7f3IlnAIfVsHfo/zqsXRB052j2+qmrd+FAC0ZhttZzTIL+aDMTu 9ZjZsnHdhh2cRyotNlGNat4xfJzNaPZ/8JsxNuHDF82jaxjztIUw2T0xwgbDL+Ax WsNDYjLAWn8s14LtvyKpUA== =MQEf -----END PGP SIGNATURE----- Merge tag 'for-net-next-2022-03-18' 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 Asus TF103C - Add support for Realtek RTL8852B - Add support for Realtek RTL8723BE - Add WBS support to mt7921s * tag 'for-net-next-2022-03-18' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (24 commits) Bluetooth: ath3k: remove superfluous header files Bluetooth: bcm203x: remove superfluous header files Bluetooth: hci_bcm: Add the Asus TF103C to the bcm_broken_irq_dmi_table Bluetooth: mt7921s: Add WBS support Bluetooth: mt7921s: Add .btmtk_get_codec_config_data Bluetooth: mt7921s: Add .get_data_path_id Bluetooth: mt7921s: Set HCI_QUIRK_VALID_LE_STATES Bluetooth: btmtksdio: Fix kernel oops in btmtksdio_interrupt Bluetooth: btmtkuart: fix error handling in mtk_hci_wmt_sync() Bluetooth: call hci_le_conn_failed with hdev lock in hci_le_conn_failed Bluetooth: Send AdvMonitor Dev Found for all matched devices Bluetooth: msft: Clear tracked devices on resume Bluetooth: fix incorrect nonblock bitmask in bt_sock_wait_ready() Bluetooth: Don't assign twice the same value Bluetooth: btrtl: Add support for RTL8852B Bluetooth: hci_uart: add missing NULL check in h5_enqueue Bluetooth: Fix use after free in hci_send_acl Bluetooth: btusb: Use quirk to skip HCI_FLT_CLEAR_ALL on fake CSR controllers Bluetooth: hci_sync: Add a new quirk to skip HCI_FLT_CLEAR_ALL Bluetooth: btmtkuart: fix the conflict between mtk and msft vendor event ... ==================== Link: https://lore.kernel.org/r/20220318224752.1477292-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
53fb430e20
|
@ -400,6 +400,7 @@ config BT_MTKSDIO
|
|||
config BT_MTKUART
|
||||
tristate "MediaTek HCI UART driver"
|
||||
depends on SERIAL_DEV_BUS
|
||||
select BT_MTK
|
||||
help
|
||||
MediaTek Bluetooth HCI UART driver.
|
||||
This driver is required if you want to use MediaTek Bluetooth
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/usb.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
@ -285,6 +285,7 @@ MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
|
|||
MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7622);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7663);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7668);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7961);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: ISC */
|
||||
/* Copyright (C) 2021 MediaTek Inc. */
|
||||
|
||||
#define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin"
|
||||
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
|
||||
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
|
||||
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
|
||||
|
|
|
@ -936,6 +936,62 @@ static int btmtksdio_mtk_reg_write(struct hci_dev *hdev, u32 reg, u32 val, u32 m
|
|||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
|
||||
{
|
||||
/* uses 1 as data path id for all the usecases */
|
||||
*data_path_id = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btmtksdio_get_codec_config_data(struct hci_dev *hdev,
|
||||
__u8 link, struct bt_codec *codec,
|
||||
__u8 *ven_len, __u8 **ven_data)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!ven_data || !ven_len)
|
||||
return -EINVAL;
|
||||
|
||||
*ven_len = 0;
|
||||
*ven_data = NULL;
|
||||
|
||||
if (link != ESCO_LINK) {
|
||||
bt_dev_err(hdev, "Invalid link type(%u)", link);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*ven_data = kmalloc(sizeof(__u8), GFP_KERNEL);
|
||||
if (!ven_data) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* supports only CVSD and mSBC offload codecs */
|
||||
switch (codec->id) {
|
||||
case 0x02:
|
||||
**ven_data = 0x00;
|
||||
break;
|
||||
case 0x05:
|
||||
**ven_data = 0x01;
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
bt_dev_err(hdev, "Invalid codec id(%u)", codec->id);
|
||||
goto error;
|
||||
}
|
||||
/* codec and its capabilities are pre-defined to ids
|
||||
* preset id = 0x00 represents CVSD codec with sampling rate 8K
|
||||
* preset id = 0x01 represents mSBC codec with sampling rate 16K
|
||||
*/
|
||||
*ven_len = sizeof(__u8);
|
||||
return err;
|
||||
|
||||
error:
|
||||
kfree(*ven_data);
|
||||
*ven_data = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_sco_setting(struct hci_dev *hdev)
|
||||
{
|
||||
const struct btmtk_sco sco_setting = {
|
||||
|
@ -968,7 +1024,14 @@ static int btmtksdio_sco_setting(struct hci_dev *hdev)
|
|||
return err;
|
||||
|
||||
val |= 0x00000101;
|
||||
return btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_1, val, ~0);
|
||||
err = btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_1, val, ~0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
hdev->get_data_path_id = btmtksdio_get_data_path_id;
|
||||
hdev->get_codec_config_data = btmtksdio_get_codec_config_data;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtksdio_reset_setting(struct hci_dev *hdev)
|
||||
|
@ -1060,6 +1123,9 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Enable WBS with mSBC codec */
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
|
||||
/* Enable GPIO reset mechanism */
|
||||
if (bdev->reset) {
|
||||
err = btmtksdio_reset_setting(hdev);
|
||||
|
@ -1070,6 +1136,9 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
|||
}
|
||||
}
|
||||
|
||||
/* Valid LE States quirk for MediaTek 7921 */
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
|
||||
break;
|
||||
case 0x7663:
|
||||
case 0x7668:
|
||||
|
@ -1281,6 +1350,8 @@ static int btmtksdio_probe(struct sdio_func *func,
|
|||
hdev->manufacturer = 70;
|
||||
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
|
||||
|
||||
sdio_set_drvdata(func, bdev);
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
dev_err(&func->dev, "Can't register HCI device\n");
|
||||
|
@ -1288,8 +1359,6 @@ static int btmtksdio_probe(struct sdio_func *func,
|
|||
return err;
|
||||
}
|
||||
|
||||
sdio_set_drvdata(func, bdev);
|
||||
|
||||
/* pm_runtime_enable would be done after the firmware is being
|
||||
* downloaded because the core layer probably already enables
|
||||
* runtime PM for this func such as the case host->caps &
|
||||
|
|
|
@ -28,13 +28,10 @@
|
|||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
#include "h4_recv.h"
|
||||
#include "btmtk.h"
|
||||
|
||||
#define VERSION "0.2"
|
||||
|
||||
#define FIRMWARE_MT7622 "mediatek/mt7622pr2h.bin"
|
||||
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
|
||||
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
|
||||
|
||||
#define MTK_STP_TLR_SIZE 2
|
||||
|
||||
#define BTMTKUART_TX_STATE_ACTIVE 1
|
||||
|
@ -44,25 +41,6 @@
|
|||
|
||||
#define BTMTKUART_FLAG_STANDALONE_HW BIT(0)
|
||||
|
||||
enum {
|
||||
MTK_WMT_PATCH_DWNLD = 0x1,
|
||||
MTK_WMT_TEST = 0x2,
|
||||
MTK_WMT_WAKEUP = 0x3,
|
||||
MTK_WMT_HIF = 0x4,
|
||||
MTK_WMT_FUNC_CTRL = 0x6,
|
||||
MTK_WMT_RST = 0x7,
|
||||
MTK_WMT_SEMAPHORE = 0x17,
|
||||
};
|
||||
|
||||
enum {
|
||||
BTMTK_WMT_INVALID,
|
||||
BTMTK_WMT_PATCH_UNDONE,
|
||||
BTMTK_WMT_PATCH_DONE,
|
||||
BTMTK_WMT_ON_UNDONE,
|
||||
BTMTK_WMT_ON_DONE,
|
||||
BTMTK_WMT_ON_PROGRESS,
|
||||
};
|
||||
|
||||
struct mtk_stp_hdr {
|
||||
u8 prefix;
|
||||
__be16 dlen;
|
||||
|
@ -74,44 +52,6 @@ struct btmtkuart_data {
|
|||
const char *fwname;
|
||||
};
|
||||
|
||||
struct mtk_wmt_hdr {
|
||||
u8 dir;
|
||||
u8 op;
|
||||
__le16 dlen;
|
||||
u8 flag;
|
||||
} __packed;
|
||||
|
||||
struct mtk_hci_wmt_cmd {
|
||||
struct mtk_wmt_hdr hdr;
|
||||
u8 data[256];
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_evt {
|
||||
struct hci_event_hdr hhdr;
|
||||
struct mtk_wmt_hdr whdr;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_evt_funcc {
|
||||
struct btmtk_hci_wmt_evt hwhdr;
|
||||
__be16 status;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_tci_sleep {
|
||||
u8 mode;
|
||||
__le16 duration;
|
||||
__le16 host_duration;
|
||||
u8 host_wakeup_pin;
|
||||
u8 time_compensation;
|
||||
} __packed;
|
||||
|
||||
struct btmtk_hci_wmt_params {
|
||||
u8 op;
|
||||
u8 flag;
|
||||
u16 dlen;
|
||||
const void *data;
|
||||
u32 *status;
|
||||
};
|
||||
|
||||
struct btmtkuart_dev {
|
||||
struct hci_dev *hdev;
|
||||
struct serdev_device *serdev;
|
||||
|
@ -153,29 +93,36 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
struct btmtk_hci_wmt_evt_funcc *wmt_evt_funcc;
|
||||
u32 hlen, status = BTMTK_WMT_INVALID;
|
||||
struct btmtk_hci_wmt_evt *wmt_evt;
|
||||
struct mtk_hci_wmt_cmd wc;
|
||||
struct mtk_wmt_hdr *hdr;
|
||||
struct btmtk_hci_wmt_cmd *wc;
|
||||
struct btmtk_wmt_hdr *hdr;
|
||||
int err;
|
||||
|
||||
/* Send the WMT command and wait until the WMT event returns */
|
||||
hlen = sizeof(*hdr) + wmt_params->dlen;
|
||||
if (hlen > 255) {
|
||||
err = -EINVAL;
|
||||
goto err_free_skb;
|
||||
}
|
||||
|
||||
hdr = (struct mtk_wmt_hdr *)&wc;
|
||||
wc = kzalloc(hlen, GFP_KERNEL);
|
||||
if (!wc) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_skb;
|
||||
}
|
||||
|
||||
hdr = &wc->hdr;
|
||||
hdr->dir = 1;
|
||||
hdr->op = wmt_params->op;
|
||||
hdr->dlen = cpu_to_le16(wmt_params->dlen + 1);
|
||||
hdr->flag = wmt_params->flag;
|
||||
memcpy(wc.data, wmt_params->data, wmt_params->dlen);
|
||||
memcpy(wc->data, wmt_params->data, wmt_params->dlen);
|
||||
|
||||
set_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
|
||||
err = __hci_cmd_send(hdev, 0xfc6f, hlen, &wc);
|
||||
err = __hci_cmd_send(hdev, 0xfc6f, hlen, wc);
|
||||
if (err < 0) {
|
||||
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
/* The vendor specific WMT commands are all answered by a vendor
|
||||
|
@ -192,14 +139,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
if (err == -EINTR) {
|
||||
bt_dev_err(hdev, "Execution of wmt command interrupted");
|
||||
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
bt_dev_err(hdev, "Execution of wmt command timed out");
|
||||
clear_bit(BTMTKUART_TX_WAIT_VND_EVT, &bdev->tx_state);
|
||||
err = -ETIMEDOUT;
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
/* Parse and handle the return WMT event */
|
||||
|
@ -208,17 +155,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
bt_dev_err(hdev, "Wrong op received %d expected %d",
|
||||
wmt_evt->whdr.op, hdr->op);
|
||||
err = -EIO;
|
||||
goto err_free_skb;
|
||||
goto err_free_wc;
|
||||
}
|
||||
|
||||
switch (wmt_evt->whdr.op) {
|
||||
case MTK_WMT_SEMAPHORE:
|
||||
case BTMTK_WMT_SEMAPHORE:
|
||||
if (wmt_evt->whdr.flag == 2)
|
||||
status = BTMTK_WMT_PATCH_UNDONE;
|
||||
else
|
||||
status = BTMTK_WMT_PATCH_DONE;
|
||||
break;
|
||||
case MTK_WMT_FUNC_CTRL:
|
||||
case BTMTK_WMT_FUNC_CTRL:
|
||||
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
|
||||
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
|
||||
status = BTMTK_WMT_ON_DONE;
|
||||
|
@ -232,6 +179,8 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
|
|||
if (wmt_params->status)
|
||||
*wmt_params->status = status;
|
||||
|
||||
err_free_wc:
|
||||
kfree(wc);
|
||||
err_free_skb:
|
||||
kfree_skb(bdev->evt_skb);
|
||||
bdev->evt_skb = NULL;
|
||||
|
@ -239,95 +188,12 @@ err_free_skb:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int mtk_setup_firmware(struct hci_dev *hdev, const char *fwname)
|
||||
{
|
||||
struct btmtk_hci_wmt_params wmt_params;
|
||||
const struct firmware *fw;
|
||||
const u8 *fw_ptr;
|
||||
size_t fw_size;
|
||||
int err, dlen;
|
||||
u8 flag;
|
||||
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
fw_ptr = fw->data;
|
||||
fw_size = fw->size;
|
||||
|
||||
/* The size of patch header is 30 bytes, should be skip */
|
||||
if (fw_size < 30) {
|
||||
err = -EINVAL;
|
||||
goto free_fw;
|
||||
}
|
||||
|
||||
fw_size -= 30;
|
||||
fw_ptr += 30;
|
||||
flag = 1;
|
||||
|
||||
wmt_params.op = MTK_WMT_PATCH_DWNLD;
|
||||
wmt_params.status = NULL;
|
||||
|
||||
while (fw_size > 0) {
|
||||
dlen = min_t(int, 250, fw_size);
|
||||
|
||||
/* Tell device the position in sequence */
|
||||
if (fw_size - dlen <= 0)
|
||||
flag = 3;
|
||||
else if (fw_size < fw->size - 30)
|
||||
flag = 2;
|
||||
|
||||
wmt_params.flag = flag;
|
||||
wmt_params.dlen = dlen;
|
||||
wmt_params.data = fw_ptr;
|
||||
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
|
||||
err);
|
||||
goto free_fw;
|
||||
}
|
||||
|
||||
fw_size -= dlen;
|
||||
fw_ptr += dlen;
|
||||
}
|
||||
|
||||
wmt_params.op = MTK_WMT_RST;
|
||||
wmt_params.flag = 4;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
wmt_params.status = NULL;
|
||||
|
||||
/* Activate funciton the firmware providing to */
|
||||
err = mtk_hci_wmt_sync(hdev, &wmt_params);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
|
||||
goto free_fw;
|
||||
}
|
||||
|
||||
/* Wait a few moments for firmware activation done */
|
||||
usleep_range(10000, 12000);
|
||||
|
||||
free_fw:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmtkuart_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct hci_event_hdr *hdr = (void *)skb->data;
|
||||
int err;
|
||||
|
||||
/* Fix up the vendor event id with 0xff for vendor specific instead
|
||||
* of 0xe4 so that event send via monitoring socket can be parsed
|
||||
* properly.
|
||||
*/
|
||||
if (hdr->evt == 0xe4)
|
||||
hdr->evt = HCI_EV_VENDOR;
|
||||
|
||||
/* When someone waits for the WMT event, the skb is being cloned
|
||||
* and being processed the events from there then.
|
||||
*/
|
||||
|
@ -343,7 +209,7 @@ static int btmtkuart_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
if (err < 0)
|
||||
goto err_free_skb;
|
||||
|
||||
if (hdr->evt == HCI_EV_VENDOR) {
|
||||
if (hdr->evt == HCI_EV_WMT) {
|
||||
if (test_and_clear_bit(BTMTKUART_TX_WAIT_VND_EVT,
|
||||
&bdev->tx_state)) {
|
||||
/* Barrier to sync with other CPUs */
|
||||
|
@ -645,7 +511,7 @@ static int btmtkuart_func_query(struct hci_dev *hdev)
|
|||
u8 param = 0;
|
||||
|
||||
/* Query whether the function is enabled */
|
||||
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 4;
|
||||
wmt_params.dlen = sizeof(param);
|
||||
wmt_params.data = ¶m;
|
||||
|
@ -672,7 +538,7 @@ static int btmtkuart_change_baudrate(struct hci_dev *hdev)
|
|||
* ready to change a new baudrate.
|
||||
*/
|
||||
baudrate = cpu_to_le32(bdev->desired_speed);
|
||||
wmt_params.op = MTK_WMT_HIF;
|
||||
wmt_params.op = BTMTK_WMT_HIF;
|
||||
wmt_params.flag = 1;
|
||||
wmt_params.dlen = 4;
|
||||
wmt_params.data = &baudrate;
|
||||
|
@ -706,7 +572,7 @@ static int btmtkuart_change_baudrate(struct hci_dev *hdev)
|
|||
usleep_range(20000, 22000);
|
||||
|
||||
/* Test the new baudrate */
|
||||
wmt_params.op = MTK_WMT_TEST;
|
||||
wmt_params.op = BTMTK_WMT_TEST;
|
||||
wmt_params.flag = 7;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
|
@ -741,7 +607,7 @@ static int btmtkuart_setup(struct hci_dev *hdev)
|
|||
* do any setups.
|
||||
*/
|
||||
if (test_bit(BTMTKUART_REQUIRED_WAKEUP, &bdev->tx_state)) {
|
||||
wmt_params.op = MTK_WMT_WAKEUP;
|
||||
wmt_params.op = BTMTK_WMT_WAKEUP;
|
||||
wmt_params.flag = 3;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
|
@ -760,7 +626,7 @@ static int btmtkuart_setup(struct hci_dev *hdev)
|
|||
btmtkuart_change_baudrate(hdev);
|
||||
|
||||
/* Query whether the firmware is already download */
|
||||
wmt_params.op = MTK_WMT_SEMAPHORE;
|
||||
wmt_params.op = BTMTK_WMT_SEMAPHORE;
|
||||
wmt_params.flag = 1;
|
||||
wmt_params.dlen = 0;
|
||||
wmt_params.data = NULL;
|
||||
|
@ -778,7 +644,7 @@ static int btmtkuart_setup(struct hci_dev *hdev)
|
|||
}
|
||||
|
||||
/* Setup a firmware which the device definitely requires */
|
||||
err = mtk_setup_firmware(hdev, bdev->data->fwname);
|
||||
err = btmtk_setup_firmware(hdev, bdev->data->fwname, mtk_hci_wmt_sync);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -801,7 +667,7 @@ ignore_setup_fw:
|
|||
}
|
||||
|
||||
/* Enable Bluetooth protocol */
|
||||
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 0;
|
||||
wmt_params.dlen = sizeof(param);
|
||||
wmt_params.data = ¶m;
|
||||
|
@ -846,7 +712,7 @@ static int btmtkuart_shutdown(struct hci_dev *hdev)
|
|||
int err;
|
||||
|
||||
/* Disable the device */
|
||||
wmt_params.op = MTK_WMT_FUNC_CTRL;
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 0;
|
||||
wmt_params.dlen = sizeof(param);
|
||||
wmt_params.data = ¶m;
|
||||
|
@ -1007,6 +873,7 @@ static int btmtkuart_probe(struct serdev_device *serdev)
|
|||
hdev->setup = btmtkuart_setup;
|
||||
hdev->shutdown = btmtkuart_shutdown;
|
||||
hdev->send = btmtkuart_send_frame;
|
||||
hdev->set_bdaddr = btmtk_set_bdaddr;
|
||||
SET_HCIDEV_DEV(hdev, &serdev->dev);
|
||||
|
||||
hdev->manufacturer = 70;
|
||||
|
@ -1131,6 +998,3 @@ MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
|
|||
MODULE_DESCRIPTION("MediaTek Bluetooth Serial driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7622);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7663);
|
||||
MODULE_FIRMWARE(FIRMWARE_MT7668);
|
||||
|
|
|
@ -49,6 +49,7 @@ enum btrtl_chip_id {
|
|||
CHIP_ID_8822C = 13,
|
||||
CHIP_ID_8761B,
|
||||
CHIP_ID_8852A = 18,
|
||||
CHIP_ID_8852B = 20,
|
||||
};
|
||||
|
||||
struct id_table {
|
||||
|
@ -187,6 +188,14 @@ static const struct id_table ic_id_table[] = {
|
|||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852au_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852au_config" },
|
||||
|
||||
/* 8852B */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xb, 0xb, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852bu_config" },
|
||||
};
|
||||
|
||||
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
|
||||
|
@ -295,6 +304,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
|||
{ RTL_ROM_LMP_8822B, 13 }, /* 8822C */
|
||||
{ RTL_ROM_LMP_8761A, 14 }, /* 8761B */
|
||||
{ RTL_ROM_LMP_8852A, 18 }, /* 8852A */
|
||||
{ RTL_ROM_LMP_8852A, 20 }, /* 8852B */
|
||||
};
|
||||
|
||||
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
|
||||
|
@ -757,6 +767,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
|
|||
switch (btrtl_dev->project_id) {
|
||||
case CHIP_ID_8822C:
|
||||
case CHIP_ID_8852A:
|
||||
case CHIP_ID_8852B:
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
hci_set_aosp_capable(hdev);
|
||||
|
@ -934,3 +945,5 @@ MODULE_FIRMWARE("rtl_bt/rtl8822b_fw.bin");
|
|||
MODULE_FIRMWARE("rtl_bt/rtl8822b_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852au_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852au_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852bu_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852bu_config.bin");
|
||||
|
|
|
@ -477,6 +477,7 @@ static const struct usb_device_id blacklist_table[] = {
|
|||
/* Additional Realtek 8723BE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0489, 0xe085), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x0489, 0xe08b), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x04f2, 0xb49f), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3410), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3416), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3459), .driver_info = BTUSB_REALTEK },
|
||||
|
@ -2057,6 +2058,8 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
|||
*/
|
||||
set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks);
|
||||
|
||||
/* Clear the reset quirk since this is not an actual
|
||||
* early Bluetooth 1.1 device from CSR.
|
||||
|
@ -2067,7 +2070,7 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
|||
/*
|
||||
* Special workaround for these BT 4.0 chip clones, and potentially more:
|
||||
*
|
||||
* - 0x0134: a Barrot 8041a02 (HCI rev: 0x1012 sub: 0x0810)
|
||||
* - 0x0134: a Barrot 8041a02 (HCI rev: 0x0810 sub: 0x1012)
|
||||
* - 0x7558: IC markings FR3191AHAL 749H15143 (HCI rev/sub-version: 0x0709)
|
||||
*
|
||||
* These controllers are really messed-up.
|
||||
|
@ -2096,7 +2099,7 @@ static int btusb_setup_csr(struct hci_dev *hdev)
|
|||
if (ret >= 0)
|
||||
msleep(200);
|
||||
else
|
||||
bt_dev_err(hdev, "CSR: Failed to suspend the device for our Barrot 8041a02 receive-issue workaround");
|
||||
bt_dev_warn(hdev, "CSR: Couldn't suspend the device for our Barrot 8041a02 receive-issue workaround");
|
||||
|
||||
pm_runtime_forbid(&data->udev->dev);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dmi.h>
|
||||
|
@ -870,7 +871,23 @@ unlock:
|
|||
#endif
|
||||
|
||||
/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */
|
||||
static struct gpiod_lookup_table asus_tf103c_irq_gpios = {
|
||||
.dev_id = "serial0-0",
|
||||
.table = {
|
||||
GPIO_LOOKUP("INT33FC:02", 17, "host-wakeup-alt", GPIO_ACTIVE_HIGH),
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static const struct dmi_system_id bcm_broken_irq_dmi_table[] = {
|
||||
{
|
||||
.ident = "Asus TF103C",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"),
|
||||
},
|
||||
.driver_data = &asus_tf103c_irq_gpios,
|
||||
},
|
||||
{
|
||||
.ident = "Meegopad T08",
|
||||
.matches = {
|
||||
|
@ -1027,7 +1044,8 @@ static struct clk *bcm_get_txco(struct device *dev)
|
|||
|
||||
static int bcm_get_resources(struct bcm_device *dev)
|
||||
{
|
||||
const struct dmi_system_id *dmi_id;
|
||||
const struct dmi_system_id *broken_irq_dmi_id;
|
||||
const char *irq_con_id = "host-wakeup";
|
||||
int err;
|
||||
|
||||
dev->name = dev_name(dev->dev);
|
||||
|
@ -1083,23 +1101,33 @@ static int bcm_get_resources(struct bcm_device *dev)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
broken_irq_dmi_id = dmi_first_match(bcm_broken_irq_dmi_table);
|
||||
if (broken_irq_dmi_id && broken_irq_dmi_id->driver_data) {
|
||||
gpiod_add_lookup_table(broken_irq_dmi_id->driver_data);
|
||||
irq_con_id = "host-wakeup-alt";
|
||||
dev->irq_active_low = false;
|
||||
dev->irq = 0;
|
||||
}
|
||||
|
||||
/* IRQ can be declared in ACPI table as Interrupt or GpioInt */
|
||||
if (dev->irq <= 0) {
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
gpio = devm_gpiod_get_optional(dev->dev, "host-wakeup",
|
||||
GPIOD_IN);
|
||||
gpio = devm_gpiod_get_optional(dev->dev, irq_con_id, GPIOD_IN);
|
||||
if (IS_ERR(gpio))
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
dev->irq = gpiod_to_irq(gpio);
|
||||
}
|
||||
|
||||
dmi_id = dmi_first_match(bcm_broken_irq_dmi_table);
|
||||
if (dmi_id) {
|
||||
dev_info(dev->dev, "%s: Has a broken IRQ config, disabling IRQ support / runtime-pm\n",
|
||||
dmi_id->ident);
|
||||
dev->irq = 0;
|
||||
if (broken_irq_dmi_id) {
|
||||
if (broken_irq_dmi_id->driver_data) {
|
||||
gpiod_remove_lookup_table(broken_irq_dmi_id->driver_data);
|
||||
} else {
|
||||
dev_info(dev->dev, "%s: Has a broken IRQ config, disabling IRQ support / runtime-pm\n",
|
||||
broken_irq_dmi_id->ident);
|
||||
dev->irq = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(dev->dev, "BCM irq: %d\n", dev->irq);
|
||||
|
|
|
@ -629,9 +629,11 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
break;
|
||||
}
|
||||
|
||||
pm_runtime_get_sync(&hu->serdev->dev);
|
||||
pm_runtime_mark_last_busy(&hu->serdev->dev);
|
||||
pm_runtime_put_autosuspend(&hu->serdev->dev);
|
||||
if (hu->serdev) {
|
||||
pm_runtime_get_sync(&hu->serdev->dev);
|
||||
pm_runtime_mark_last_busy(&hu->serdev->dev);
|
||||
pm_runtime_put_autosuspend(&hu->serdev->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -345,7 +345,7 @@ int bt_sock_stream_recvmsg(struct socket *sock, struct msghdr *msg,
|
|||
__poll_t bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
|
||||
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
|
||||
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
|
||||
int bt_sock_wait_ready(struct sock *sk, unsigned long flags);
|
||||
int bt_sock_wait_ready(struct sock *sk, unsigned int msg_flags);
|
||||
|
||||
void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh);
|
||||
void bt_accept_unlink(struct sock *sk);
|
||||
|
|
|
@ -255,6 +255,16 @@ enum {
|
|||
* during the hdev->setup vendor callback.
|
||||
*/
|
||||
HCI_QUIRK_BROKEN_READ_TRANSMIT_POWER,
|
||||
|
||||
/* When this quirk is set, HCI_OP_SET_EVENT_FLT requests with
|
||||
* HCI_FLT_CLEAR_ALL are ignored and event filtering is
|
||||
* completely avoided. A subset of the CSR controller
|
||||
* clones struggle with this and instantly lock up.
|
||||
*
|
||||
* Note that devices using this must (separately) disable
|
||||
* runtime suspend, because event filtering takes place there.
|
||||
*/
|
||||
HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL,
|
||||
};
|
||||
|
||||
/* HCI device flags */
|
||||
|
|
|
@ -568,7 +568,7 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
|
|||
EXPORT_SYMBOL(bt_sock_wait_state);
|
||||
|
||||
/* This function expects the sk lock to be held when called */
|
||||
int bt_sock_wait_ready(struct sock *sk, unsigned long flags)
|
||||
int bt_sock_wait_ready(struct sock *sk, unsigned int msg_flags)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
unsigned long timeo;
|
||||
|
@ -576,7 +576,7 @@ int bt_sock_wait_ready(struct sock *sk, unsigned long flags)
|
|||
|
||||
BT_DBG("sk %p", sk);
|
||||
|
||||
timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
|
||||
timeo = sock_sndtimeo(sk, !!(msg_flags & MSG_DONTWAIT));
|
||||
|
||||
add_wait_queue(sk_sleep(sk), &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
|
|
@ -669,7 +669,9 @@ static void le_conn_timeout(struct work_struct *work)
|
|||
if (conn->role == HCI_ROLE_SLAVE) {
|
||||
/* Disable LE Advertising */
|
||||
le_disable_advertising(hdev);
|
||||
hci_dev_lock(hdev);
|
||||
hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT);
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -5453,8 +5453,9 @@ static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev, void *data,
|
|||
hci_dev_lock(hdev);
|
||||
|
||||
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
|
||||
if (hcon) {
|
||||
if (hcon && hcon->type == AMP_LINK) {
|
||||
hcon->state = BT_CLOSED;
|
||||
hci_disconn_cfm(hcon, ev->reason);
|
||||
hci_conn_del(hcon);
|
||||
}
|
||||
|
||||
|
|
|
@ -2809,6 +2809,9 @@ static int hci_set_event_filter_sync(struct hci_dev *hdev, u8 flt_type,
|
|||
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
|
||||
return 0;
|
||||
|
||||
if (test_bit(HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL, &hdev->quirks))
|
||||
return 0;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.flt_type = flt_type;
|
||||
|
||||
|
@ -2829,6 +2832,13 @@ static int hci_clear_event_filter_sync(struct hci_dev *hdev)
|
|||
if (!hci_dev_test_flag(hdev, HCI_EVENT_FILTER_CONFIGURED))
|
||||
return 0;
|
||||
|
||||
/* In theory the state machine should not reach here unless
|
||||
* a hci_set_event_filter_sync() call succeeds, but we do
|
||||
* the check both for parity and as a future reminder.
|
||||
*/
|
||||
if (test_bit(HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL, &hdev->quirks))
|
||||
return 0;
|
||||
|
||||
return hci_set_event_filter_sync(hdev, HCI_FLT_CLEAR_ALL, 0x00,
|
||||
BDADDR_ANY, 0x00);
|
||||
}
|
||||
|
@ -4828,6 +4838,12 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
|
|||
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
|
||||
return 0;
|
||||
|
||||
/* Some fake CSR controllers lock up after setting this type of
|
||||
* filter, so avoid sending the request altogether.
|
||||
*/
|
||||
if (test_bit(HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL, &hdev->quirks))
|
||||
return 0;
|
||||
|
||||
/* Always clear event filter when starting */
|
||||
hci_clear_event_filter_sync(hdev);
|
||||
|
||||
|
|
|
@ -1444,7 +1444,6 @@ static void l2cap_ecred_connect(struct l2cap_chan *chan)
|
|||
data.pdu.scid[0] = cpu_to_le16(chan->scid);
|
||||
|
||||
chan->ident = l2cap_get_ident(conn);
|
||||
data.pid = chan->ops->get_peer_pid(chan);
|
||||
|
||||
data.count = 1;
|
||||
data.chan = chan;
|
||||
|
|
|
@ -7955,7 +7955,7 @@ static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data,
|
|||
return false;
|
||||
|
||||
/* Make sure that the data is correctly formatted. */
|
||||
for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) {
|
||||
for (i = 0; i < len; i += (cur_len + 1)) {
|
||||
cur_len = data[i];
|
||||
|
||||
if (!cur_len)
|
||||
|
@ -9628,17 +9628,44 @@ void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle,
|
|||
NULL);
|
||||
}
|
||||
|
||||
static void mgmt_send_adv_monitor_device_found(struct hci_dev *hdev,
|
||||
struct sk_buff *skb,
|
||||
struct sock *skip_sk,
|
||||
u16 handle)
|
||||
{
|
||||
struct sk_buff *advmon_skb;
|
||||
size_t advmon_skb_len;
|
||||
__le16 *monitor_handle;
|
||||
|
||||
if (!skb)
|
||||
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)
|
||||
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));
|
||||
*monitor_handle = cpu_to_le16(handle);
|
||||
skb_put_data(advmon_skb, skb->data, skb->len);
|
||||
|
||||
mgmt_event_skb(advmon_skb, skip_sk);
|
||||
}
|
||||
|
||||
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;
|
||||
bool notified = false;
|
||||
|
||||
/* We have received the Advertisement Report because:
|
||||
* 1. the kernel has initiated active discovery
|
||||
|
@ -9660,25 +9687,6 @@ static void mgmt_adv_monitor_device_found(struct hci_dev *hdev,
|
|||
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) {
|
||||
|
@ -9686,8 +9694,10 @@ static void mgmt_adv_monitor_device_found(struct hci_dev *hdev,
|
|||
matched = true;
|
||||
|
||||
if (!dev->notified) {
|
||||
*monitor_handle = cpu_to_le16(dev->handle);
|
||||
notify = true;
|
||||
mgmt_send_adv_monitor_device_found(hdev, skb,
|
||||
skip_sk,
|
||||
dev->handle);
|
||||
notified = true;
|
||||
dev->notified = true;
|
||||
}
|
||||
}
|
||||
|
@ -9697,25 +9707,19 @@ static void mgmt_adv_monitor_device_found(struct hci_dev *hdev,
|
|||
}
|
||||
|
||||
if (!report_device &&
|
||||
((matched && !notify) || !msft_monitor_supported(hdev))) {
|
||||
((matched && !notified) || !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;
|
||||
mgmt_send_adv_monitor_device_found(hdev, skb, skip_sk, 0);
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -330,12 +330,13 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
|
|||
/* Do not free the monitor if it is being removed due to
|
||||
* suspend. It will be re-monitored on resume.
|
||||
*/
|
||||
if (monitor && !msft->suspending)
|
||||
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);
|
||||
/* 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);
|
||||
|
@ -522,6 +523,16 @@ int msft_resume_sync(struct hci_dev *hdev)
|
|||
if (!msft || !msft_monitor_supported(hdev))
|
||||
return 0;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Clear already tracked devices on resume. Once the monitors are
|
||||
* reregistered, devices in range will be found again after resume.
|
||||
*/
|
||||
hdev->advmon_pend_notify = false;
|
||||
msft_monitor_device_del(hdev, 0, NULL, 0, true);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
msft->resuming = true;
|
||||
|
||||
while (1) {
|
||||
|
|
Loading…
Reference in New Issue