bluetooth-next pull request for net-next:
- Add support for Realtek 8761BUV - Add HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN quirk - Add support for RTL8852C - Add a new PID/VID 0489/e0c8 for MT7921 - Add support for Qualcomm WCN785x -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmKL8N4ZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKfy6EACPSdWECxGv+20lpBmgRbfF 1Ahu2rFfEtK5iDaTiFLqBOczGkaYnhjq9/Er4VsYHMH1DVedOKoTskzfa2V68j0L xyCU44E0x314YI/B2sWoMAYejkPX265r0292KzZUpXM2s+S0Doh3Z52glMrjh13C GbaTfukocBZ6HNIiXp8xQLIaD6MbKGhs2VSWuoXLQqASujrixm1ucglsHNbjfL6e huSL/SoxKukX8qhlO19pJniROLKq0aC5tQSk66ihvhHWlNBTNJYkg6HoJ8vrB81d lBjVjPjElbTljQIC+PeOSCSeOn+ELizsUdGgWxiZ2fgzgQvko0fDSnGSnpRSCnNH zxSBs/pn3cgVS6rSIIzFXsnhdBgAoiwqqhwy+bKsi3nnIXGriZMn82Dpr7z/+QWB di2wKlZSXw8LEhDaBxi8espe1NkdhgSYWI8c2hh40PLkydBpGXwag9FBkMM4cgsU 4p/riOd776EEVtwXI+lDcAdMFcbMLTf094qZWi1of93VUgDPoy8TSy3ZdshupZah 8UQyeKKYb3lxXIXd/i6C/jhYgPvo/8ZWv+OwysPpAzvvyhAagEKS1czSGJ01yjsy 1k+ebPY4CIHBBT23UFYKxD6Tgn9SAiqKtf0XtbYzCV2UD+QtUadc8MeGFtYb+0j1 ybtkiTT++lU3M9KfAMtH8A== =XFUz -----END PGP SIGNATURE----- Merge tag 'for-net-next-2022-05-23' 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 Realtek 8761BUV - Add HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN quirk - Add support for RTL8852C - Add a new PID/VID 0489/e0c8 for MT7921 - Add support for Qualcomm WCN785x * tag 'for-net-next-2022-05-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (26 commits) Bluetooth: hci_sync: use hci_skb_event() helper Bluetooth: eir: Add helpers for managing service data Bluetooth: hci_sync: Fix attempting to suspend with unfiltered passive scan Bluetooth: MGMT: Add conditions for setting HCI_CONN_FLAG_REMOTE_WAKEUP Bluetooth: btmtksdio: fix the reset takes too long Bluetooth: btmtksdio: fix possible FW initialization failure Bluetooth: btmtksdio: fix use-after-free at btmtksdio_recv_event Bluetooth: btbcm: Add entry for BCM4373A0 UART Bluetooth Bluetooth: btusb: Add a new PID/VID 0489/e0c8 for MT7921 Bluetooth: btusb: Add 0x0bda:0x8771 Realtek 8761BUV devices Bluetooth: btusb: Set HCI_QUIRK_BROKEN_ERR_DATA_REPORTING for QCA Bluetooth: core: Fix missing power_on work cancel on HCI close Bluetooth: btusb: add support for Qualcomm WCN785x Bluetooth: protect le accept and resolv lists with hdev->lock Bluetooth: use hdev lock for accept_list and reject_list in conn req Bluetooth: use hdev lock in activate_scan for hci_is_adv_monitoring Bluetooth: btrtl: Add support for RTL8852C Bluetooth: btusb: Set HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN for QCA Bluetooth: Print broken quirks Bluetooth: HCI: Add HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN quirk ... ==================== Link: https://lore.kernel.org/r/20220523204151.3327345-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
b1e6738a21
@ -9,6 +9,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
@ -29,7 +30,7 @@
|
||||
#define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}})
|
||||
|
||||
#define BCM_FW_NAME_LEN 64
|
||||
#define BCM_FW_NAME_COUNT_MAX 2
|
||||
#define BCM_FW_NAME_COUNT_MAX 4
|
||||
/* For kmalloc-ing the fw-name array instead of putting it on the stack */
|
||||
typedef char bcm_fw_name[BCM_FW_NAME_LEN];
|
||||
|
||||
@ -457,6 +458,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = {
|
||||
{ 0x6106, "BCM4359C0" }, /* 003.001.006 */
|
||||
{ 0x4106, "BCM4335A0" }, /* 002.001.006 */
|
||||
{ 0x410c, "BCM43430B0" }, /* 002.001.012 */
|
||||
{ 0x2119, "BCM4373A0" }, /* 001.001.025 */
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -476,6 +478,42 @@ static const struct bcm_subver_table bcm_usb_subver_table[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* This currently only looks up the device tree board appendix,
|
||||
* but can be expanded to other mechanisms.
|
||||
*/
|
||||
static const char *btbcm_get_board_name(struct device *dev)
|
||||
{
|
||||
#ifdef CONFIG_OF
|
||||
struct device_node *root;
|
||||
char *board_type;
|
||||
const char *tmp;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
root = of_find_node_by_path("/");
|
||||
if (!root)
|
||||
return NULL;
|
||||
|
||||
if (of_property_read_string_index(root, "compatible", 0, &tmp))
|
||||
return NULL;
|
||||
|
||||
/* get rid of any '/' in the compatible string */
|
||||
len = strlen(tmp) + 1;
|
||||
board_type = devm_kzalloc(dev, len, GFP_KERNEL);
|
||||
strscpy(board_type, tmp, len);
|
||||
for (i = 0; i < board_type[i]; i++) {
|
||||
if (board_type[i] == '/')
|
||||
board_type[i] = '-';
|
||||
}
|
||||
of_node_put(root);
|
||||
|
||||
return board_type;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
|
||||
{
|
||||
u16 subver, rev, pid, vid;
|
||||
@ -483,12 +521,15 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
|
||||
struct hci_rp_read_local_version *ver;
|
||||
const struct bcm_subver_table *bcm_subver_table;
|
||||
const char *hw_name = NULL;
|
||||
const char *board_name;
|
||||
char postfix[16] = "";
|
||||
int fw_name_count = 0;
|
||||
bcm_fw_name *fw_name;
|
||||
const struct firmware *fw;
|
||||
int i, err;
|
||||
|
||||
board_name = btbcm_get_board_name(&hdev->dev);
|
||||
|
||||
/* Reset */
|
||||
err = btbcm_reset(hdev);
|
||||
if (err)
|
||||
@ -549,11 +590,21 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done)
|
||||
return -ENOMEM;
|
||||
|
||||
if (hw_name) {
|
||||
if (board_name) {
|
||||
snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
|
||||
"brcm/%s%s.%s.hcd", hw_name, postfix, board_name);
|
||||
fw_name_count++;
|
||||
}
|
||||
snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
|
||||
"brcm/%s%s.hcd", hw_name, postfix);
|
||||
fw_name_count++;
|
||||
}
|
||||
|
||||
if (board_name) {
|
||||
snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
|
||||
"brcm/BCM%s.%s.hcd", postfix, board_name);
|
||||
fw_name_count++;
|
||||
}
|
||||
snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN,
|
||||
"brcm/BCM%s.hcd", postfix);
|
||||
fw_name_count++;
|
||||
|
@ -794,7 +794,7 @@ static void regmap_ibt_free_context(void *context)
|
||||
kfree(context);
|
||||
}
|
||||
|
||||
static struct regmap_bus regmap_ibt = {
|
||||
static const struct regmap_bus regmap_ibt = {
|
||||
.read = regmap_ibt_read,
|
||||
.write = regmap_ibt_write,
|
||||
.gather_write = regmap_ibt_gather_write,
|
||||
|
@ -379,6 +379,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btmtksdio_dev *bdev = hci_get_drvdata(hdev);
|
||||
struct hci_event_hdr *hdr = (void *)skb->data;
|
||||
u8 evt = hdr->evt;
|
||||
int err;
|
||||
|
||||
/* When someone waits for the WMT event, the skb is being cloned
|
||||
@ -396,7 +397,7 @@ static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
if (err < 0)
|
||||
goto err_free_skb;
|
||||
|
||||
if (hdr->evt == HCI_EV_WMT) {
|
||||
if (evt == HCI_EV_WMT) {
|
||||
if (test_and_clear_bit(BTMTKSDIO_TX_WAIT_VND_EVT,
|
||||
&bdev->tx_state)) {
|
||||
/* Barrier to sync with other CPUs */
|
||||
@ -863,6 +864,14 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = btmtksdio_fw_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = btmtksdio_drv_pmctrl(bdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Enable Bluetooth protocol */
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 0;
|
||||
@ -961,7 +970,7 @@ static int btmtksdio_get_codec_config_data(struct hci_dev *hdev,
|
||||
}
|
||||
|
||||
*ven_data = kmalloc(sizeof(__u8), GFP_KERNEL);
|
||||
if (!ven_data) {
|
||||
if (!*ven_data) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
@ -1108,14 +1117,6 @@ static int btmtksdio_setup(struct hci_dev *hdev)
|
||||
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) {
|
||||
@ -1188,6 +1189,10 @@ static int btmtksdio_shutdown(struct hci_dev *hdev)
|
||||
*/
|
||||
pm_runtime_get_sync(bdev->dev);
|
||||
|
||||
/* wmt command only works until the reset is complete */
|
||||
if (test_bit(BTMTKSDIO_HW_RESET_ACTIVE, &bdev->tx_state))
|
||||
goto ignore_wmt_cmd;
|
||||
|
||||
/* Disable the device */
|
||||
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
|
||||
wmt_params.flag = 0;
|
||||
@ -1201,6 +1206,7 @@ static int btmtksdio_shutdown(struct hci_dev *hdev)
|
||||
return err;
|
||||
}
|
||||
|
||||
ignore_wmt_cmd:
|
||||
pm_runtime_put_noidle(bdev->dev);
|
||||
pm_runtime_disable(bdev->dev);
|
||||
|
||||
|
@ -50,6 +50,7 @@ enum btrtl_chip_id {
|
||||
CHIP_ID_8761B,
|
||||
CHIP_ID_8852A = 18,
|
||||
CHIP_ID_8852B = 20,
|
||||
CHIP_ID_8852C = 25,
|
||||
};
|
||||
|
||||
struct id_table {
|
||||
@ -196,6 +197,14 @@ static const struct id_table ic_id_table[] = {
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852bu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852bu_config" },
|
||||
|
||||
/* 8852C */
|
||||
{ IC_INFO(RTL_ROM_LMP_8852A, 0xc, 0xc, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.has_msft_ext = true,
|
||||
.fw_name = "rtl_bt/rtl8852cu_fw.bin",
|
||||
.cfg_name = "rtl_bt/rtl8852cu_config" },
|
||||
};
|
||||
|
||||
static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
|
||||
@ -305,6 +314,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
||||
{ RTL_ROM_LMP_8761A, 14 }, /* 8761B */
|
||||
{ RTL_ROM_LMP_8852A, 18 }, /* 8852A */
|
||||
{ RTL_ROM_LMP_8852A, 20 }, /* 8852B */
|
||||
{ RTL_ROM_LMP_8852A, 25 }, /* 8852C */
|
||||
};
|
||||
|
||||
min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
|
||||
@ -768,6 +778,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
|
||||
case CHIP_ID_8822C:
|
||||
case CHIP_ID_8852A:
|
||||
case CHIP_ID_8852B:
|
||||
case CHIP_ID_8852C:
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
hci_set_aosp_capable(hdev);
|
||||
@ -947,3 +958,5 @@ 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");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852cu_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8852cu_config.bin");
|
||||
|
@ -317,6 +317,11 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* QCA WCN785x chipset */
|
||||
{ USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Broadcom BCM2035 */
|
||||
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 },
|
||||
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
|
||||
@ -446,6 +451,9 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
BTUSB_VALID_LE_STATES },
|
||||
|
||||
/* Additional MediaTek MT7921 Bluetooth devices */
|
||||
{ USB_DEVICE(0x0489, 0xe0c8), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
{ USB_DEVICE(0x04ca, 0x3802), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH |
|
||||
BTUSB_VALID_LE_STATES },
|
||||
@ -500,6 +508,10 @@ static const struct usb_device_id blacklist_table[] = {
|
||||
{ USB_DEVICE(0x2550, 0x8761), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Additional Realtek 8761BUV Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0x8771), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Additional Realtek 8821AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3414), .driver_info = BTUSB_REALTEK },
|
||||
@ -3037,6 +3049,7 @@ static const struct qca_device_info qca_devices_table[] = {
|
||||
{ 0x00130100, 40, 4, 16 }, /* WCN6855 1.0 */
|
||||
{ 0x00130200, 40, 4, 16 }, /* WCN6855 2.0 */
|
||||
{ 0x00130201, 40, 4, 16 }, /* WCN6855 2.1 */
|
||||
{ 0x00190200, 40, 4, 16 }, /* WCN785x 2.0 */
|
||||
};
|
||||
|
||||
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
|
||||
@ -3327,14 +3340,20 @@ static int btusb_setup_qca(struct hci_dev *hdev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* WCN6855 2.1 will reset to apply firmware downloaded here, so
|
||||
/* WCN6855 2.1 and later will reset to apply firmware downloaded here, so
|
||||
* wait ~100ms for reset Done then go ahead, otherwise, it maybe
|
||||
* cause potential enable failure.
|
||||
*/
|
||||
if (info->rom_version == 0x00130201)
|
||||
if (info->rom_version >= 0x00130201)
|
||||
msleep(QCA_BT_RESET_WAIT_MS);
|
||||
}
|
||||
|
||||
/* Mark HCI_OP_ENHANCED_SETUP_SYNC_CONN as broken as it doesn't seem to
|
||||
* work with the likes of HSP/HFP mSBC.
|
||||
*/
|
||||
set_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_BROKEN_ERR_DATA_REPORTING, &hdev->quirks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -696,9 +696,9 @@ static int qca_close(struct hci_uart *hu)
|
||||
skb_queue_purge(&qca->tx_wait_q);
|
||||
skb_queue_purge(&qca->txq);
|
||||
skb_queue_purge(&qca->rx_memdump_q);
|
||||
del_timer(&qca->tx_idle_timer);
|
||||
del_timer(&qca->wake_retrans_timer);
|
||||
destroy_workqueue(qca->workqueue);
|
||||
del_timer_sync(&qca->tx_idle_timer);
|
||||
del_timer_sync(&qca->wake_retrans_timer);
|
||||
qca->hu = NULL;
|
||||
|
||||
kfree_skb(qca->rx_skb);
|
||||
|
@ -265,6 +265,15 @@ enum {
|
||||
* runtime suspend, because event filtering takes place there.
|
||||
*/
|
||||
HCI_QUIRK_BROKEN_FILTER_CLEAR_ALL,
|
||||
|
||||
/*
|
||||
* When this quirk is set, disables the use of
|
||||
* HCI_OP_ENHANCED_SETUP_SYNC_CONN command to setup SCO connections.
|
||||
*
|
||||
* This quirk can be set before hci_register_dev is called or
|
||||
* during the hdev->setup vendor callback.
|
||||
*/
|
||||
HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN,
|
||||
};
|
||||
|
||||
/* HCI device flags */
|
||||
@ -616,6 +625,7 @@ enum {
|
||||
#define EIR_SSP_RAND_R192 0x0F /* Simple Pairing Randomizer R-192 */
|
||||
#define EIR_DEVICE_ID 0x10 /* device ID */
|
||||
#define EIR_APPEARANCE 0x19 /* Device appearance */
|
||||
#define EIR_SERVICE_DATA 0x16 /* Service Data */
|
||||
#define EIR_LE_BDADDR 0x1B /* LE Bluetooth device address */
|
||||
#define EIR_LE_ROLE 0x1C /* LE role */
|
||||
#define EIR_SSP_HASH_C256 0x1D /* Simple Pairing Hash C-256 */
|
||||
|
@ -1495,8 +1495,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
||||
#define privacy_mode_capable(dev) (use_ll_privacy(dev) && \
|
||||
(hdev->commands[39] & 0x04))
|
||||
|
||||
/* Use enhanced synchronous connection if command is supported */
|
||||
#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
|
||||
/* Use enhanced synchronous connection if command is supported and its quirk
|
||||
* has not been set.
|
||||
*/
|
||||
#define enhanced_sync_conn_capable(dev) \
|
||||
(((dev)->commands[29] & 0x08) && \
|
||||
!test_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &(dev)->quirks))
|
||||
|
||||
/* Use ext scanning if set ext scan param and ext scan enable is supported */
|
||||
#define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
|
||||
|
@ -55,6 +55,19 @@ u8 eir_append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
|
||||
return eir_append_le16(ptr, ad_len, EIR_APPEARANCE, hdev->appearance);
|
||||
}
|
||||
|
||||
u8 eir_append_service_data(u8 *eir, u16 eir_len, u16 uuid, u8 *data,
|
||||
u8 data_len)
|
||||
{
|
||||
eir[eir_len++] = sizeof(u8) + sizeof(uuid) + data_len;
|
||||
eir[eir_len++] = EIR_SERVICE_DATA;
|
||||
put_unaligned_le16(uuid, &eir[eir_len]);
|
||||
eir_len += sizeof(uuid);
|
||||
memcpy(&eir[eir_len], data, data_len);
|
||||
eir_len += data_len;
|
||||
|
||||
return eir_len;
|
||||
}
|
||||
|
||||
static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
|
||||
{
|
||||
u8 *ptr = data, *uuids_start = NULL;
|
||||
@ -333,3 +346,21 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr)
|
||||
|
||||
return scan_rsp_len;
|
||||
}
|
||||
|
||||
void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len)
|
||||
{
|
||||
while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, len))) {
|
||||
u16 value = get_unaligned_le16(eir);
|
||||
|
||||
if (uuid == value) {
|
||||
if (len)
|
||||
*len -= 2;
|
||||
return &eir[2];
|
||||
}
|
||||
|
||||
eir += *len;
|
||||
eir_len -= *len;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr);
|
||||
|
||||
u8 eir_append_local_name(struct hci_dev *hdev, u8 *eir, u8 ad_len);
|
||||
u8 eir_append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len);
|
||||
u8 eir_append_service_data(u8 *eir, u16 eir_len, u16 uuid, u8 *data,
|
||||
u8 data_len);
|
||||
|
||||
static inline u16 eir_precalc_len(u8 data_len)
|
||||
{
|
||||
@ -92,3 +94,5 @@ static inline void *eir_get_data(u8 *eir, size_t eir_len, u8 type,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len);
|
||||
|
@ -481,7 +481,7 @@ static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
|
||||
|
||||
bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
||||
{
|
||||
if (enhanced_sco_capable(conn->hdev))
|
||||
if (enhanced_sync_conn_capable(conn->hdev))
|
||||
return hci_enhanced_setup_sync_conn(conn, handle);
|
||||
|
||||
return hci_setup_sync_conn(conn, handle);
|
||||
|
@ -2675,8 +2675,6 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
||||
list_del(&hdev->list);
|
||||
write_unlock(&hci_dev_list_lock);
|
||||
|
||||
cancel_work_sync(&hdev->power_on);
|
||||
|
||||
hci_cmd_sync_clear(hdev);
|
||||
|
||||
if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
|
||||
|
@ -1835,7 +1835,9 @@ static u8 hci_cc_le_clear_accept_list(struct hci_dev *hdev, void *data,
|
||||
if (rp->status)
|
||||
return rp->status;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_bdaddr_list_clear(&hdev->le_accept_list);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return rp->status;
|
||||
}
|
||||
@ -1855,8 +1857,10 @@ static u8 hci_cc_le_add_to_accept_list(struct hci_dev *hdev, void *data,
|
||||
if (!sent)
|
||||
return rp->status;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_bdaddr_list_add(&hdev->le_accept_list, &sent->bdaddr,
|
||||
sent->bdaddr_type);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return rp->status;
|
||||
}
|
||||
@ -1876,8 +1880,10 @@ static u8 hci_cc_le_del_from_accept_list(struct hci_dev *hdev, void *data,
|
||||
if (!sent)
|
||||
return rp->status;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_bdaddr_list_del(&hdev->le_accept_list, &sent->bdaddr,
|
||||
sent->bdaddr_type);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return rp->status;
|
||||
}
|
||||
@ -1949,9 +1955,11 @@ static u8 hci_cc_le_add_to_resolv_list(struct hci_dev *hdev, void *data,
|
||||
if (!sent)
|
||||
return rp->status;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
|
||||
sent->bdaddr_type, sent->peer_irk,
|
||||
sent->local_irk);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return rp->status;
|
||||
}
|
||||
@ -1971,8 +1979,10 @@ static u8 hci_cc_le_del_from_resolv_list(struct hci_dev *hdev, void *data,
|
||||
if (!sent)
|
||||
return rp->status;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
|
||||
sent->bdaddr_type);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return rp->status;
|
||||
}
|
||||
@ -1987,7 +1997,9 @@ static u8 hci_cc_le_clear_resolv_list(struct hci_dev *hdev, void *data,
|
||||
if (rp->status)
|
||||
return rp->status;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_bdaddr_list_clear(&hdev->le_resolv_list);
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return rp->status;
|
||||
}
|
||||
@ -3225,10 +3237,12 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
||||
return;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (hci_bdaddr_list_lookup(&hdev->reject_list, &ev->bdaddr,
|
||||
BDADDR_BREDR)) {
|
||||
hci_reject_conn(hdev, &ev->bdaddr);
|
||||
return;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Require HCI_CONNECTABLE or an accept list entry to accept the
|
||||
@ -3240,13 +3254,11 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
||||
!hci_bdaddr_list_lookup_with_flags(&hdev->accept_list, &ev->bdaddr,
|
||||
BDADDR_BREDR)) {
|
||||
hci_reject_conn(hdev, &ev->bdaddr);
|
||||
return;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Connection accepted */
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
|
||||
if (ie)
|
||||
memcpy(ie->data.dev_class, ev->dev_class, 3);
|
||||
@ -3258,8 +3270,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
||||
HCI_ROLE_SLAVE);
|
||||
if (!conn) {
|
||||
bt_dev_err(hdev, "no memory for new connection");
|
||||
hci_dev_unlock(hdev);
|
||||
return;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3299,6 +3310,10 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
||||
conn->state = BT_CONNECT2;
|
||||
hci_connect_cfm(conn, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static u8 hci_to_mgmt_reason(u8 err)
|
||||
|
@ -261,7 +261,7 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
|
||||
if (skb_queue_empty(&req->cmd_q))
|
||||
bt_cb(skb)->hci.req_flags |= HCI_REQ_START;
|
||||
|
||||
bt_cb(skb)->hci.req_event = event;
|
||||
hci_skb_event(skb) = event;
|
||||
|
||||
skb_queue_tail(&req->cmd_q, skb);
|
||||
}
|
||||
@ -2260,6 +2260,7 @@ static int active_scan(struct hci_request *req, unsigned long opt)
|
||||
if (err < 0)
|
||||
own_addr_type = ADDR_LE_DEV_PUBLIC;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
if (hci_is_adv_monitoring(hdev)) {
|
||||
/* Duplicate filter should be disabled when some advertisement
|
||||
* monitor is activated, otherwise AdvMon can only receive one
|
||||
@ -2276,6 +2277,7 @@ static int active_scan(struct hci_request *req, unsigned long opt)
|
||||
*/
|
||||
filter_dup = LE_SCAN_FILTER_DUP_DISABLE;
|
||||
}
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
hci_req_start_scan(req, LE_SCAN_ACTIVE, interval,
|
||||
hdev->le_scan_window_discovery, own_addr_type,
|
||||
|
@ -1664,20 +1664,19 @@ static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
|
||||
struct hci_cp_le_add_to_accept_list cp;
|
||||
int err;
|
||||
|
||||
/* During suspend, only wakeable devices can be in acceptlist */
|
||||
if (hdev->suspended &&
|
||||
!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags))
|
||||
return 0;
|
||||
|
||||
/* Select filter policy to accept all advertising */
|
||||
if (*num_entries >= hdev->le_accept_list_size)
|
||||
return -ENOSPC;
|
||||
|
||||
/* Accept list can not be used with RPAs */
|
||||
if (!use_ll_privacy(hdev) &&
|
||||
hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type)) {
|
||||
hci_find_irk_by_addr(hdev, ¶ms->addr, params->addr_type))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* During suspend, only wakeable devices can be in acceptlist */
|
||||
if (hdev->suspended &&
|
||||
!test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, params->flags))
|
||||
return 0;
|
||||
|
||||
/* Attempt to program the device in the resolving list first to avoid
|
||||
* having to rollback in case it fails since the resolving list is
|
||||
@ -3825,6 +3824,30 @@ static int hci_init_sync(struct hci_dev *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HCI_QUIRK_BROKEN(_quirk, _desc) { HCI_QUIRK_BROKEN_##_quirk, _desc }
|
||||
|
||||
static const struct {
|
||||
unsigned long quirk;
|
||||
const char *desc;
|
||||
} hci_broken_table[] = {
|
||||
HCI_QUIRK_BROKEN(LOCAL_COMMANDS,
|
||||
"HCI Read Local Supported Commands not supported"),
|
||||
HCI_QUIRK_BROKEN(STORED_LINK_KEY,
|
||||
"HCI Delete Stored Link Key command is advertised, "
|
||||
"but not supported."),
|
||||
HCI_QUIRK_BROKEN(ERR_DATA_REPORTING,
|
||||
"HCI Read Default Erroneous Data Reporting command is "
|
||||
"advertised, but not supported."),
|
||||
HCI_QUIRK_BROKEN(READ_TRANSMIT_POWER,
|
||||
"HCI Read Transmit Power Level command is advertised, "
|
||||
"but not supported."),
|
||||
HCI_QUIRK_BROKEN(FILTER_CLEAR_ALL,
|
||||
"HCI Set Event Filter command not supported."),
|
||||
HCI_QUIRK_BROKEN(ENHANCED_SETUP_SYNC_CONN,
|
||||
"HCI Enhanced Setup Synchronous Connection command is "
|
||||
"advertised, but not supported.")
|
||||
};
|
||||
|
||||
int hci_dev_open_sync(struct hci_dev *hdev)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -3886,12 +3909,19 @@ int hci_dev_open_sync(struct hci_dev *hdev)
|
||||
if (hci_dev_test_flag(hdev, HCI_SETUP) ||
|
||||
test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) {
|
||||
bool invalid_bdaddr;
|
||||
size_t i;
|
||||
|
||||
hci_sock_dev_event(hdev, HCI_DEV_SETUP);
|
||||
|
||||
if (hdev->setup)
|
||||
ret = hdev->setup(hdev);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hci_broken_table); i++) {
|
||||
if (test_bit(hci_broken_table[i].quirk, &hdev->quirks))
|
||||
bt_dev_warn(hdev, "%s",
|
||||
hci_broken_table[i].desc);
|
||||
}
|
||||
|
||||
/* The transport driver can set the quirk to mark the
|
||||
* BD_ADDR invalid before creating the HCI device or in
|
||||
* its setup callback.
|
||||
@ -4058,6 +4088,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
|
||||
|
||||
bt_dev_dbg(hdev, "");
|
||||
|
||||
cancel_work_sync(&hdev->power_on);
|
||||
cancel_delayed_work(&hdev->power_off);
|
||||
cancel_delayed_work(&hdev->ncmd_timer);
|
||||
|
||||
@ -4881,10 +4912,28 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function disables scan (BR and LE) and mark it as paused */
|
||||
static int hci_pause_scan_sync(struct hci_dev *hdev)
|
||||
{
|
||||
if (hdev->scanning_paused)
|
||||
return 0;
|
||||
|
||||
/* Disable page scan if enabled */
|
||||
if (test_bit(HCI_PSCAN, &hdev->flags))
|
||||
hci_write_scan_enable_sync(hdev, SCAN_DISABLED);
|
||||
|
||||
hci_scan_disable_sync(hdev);
|
||||
|
||||
hdev->scanning_paused = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function performs the HCI suspend procedures in the follow order:
|
||||
*
|
||||
* Pause discovery (active scanning/inquiry)
|
||||
* Pause Directed Advertising/Advertising
|
||||
* Pause Scanning (passive scanning in case discovery was not active)
|
||||
* Disconnect all connections
|
||||
* Set suspend_status to BT_SUSPEND_DISCONNECT if hdev cannot wakeup
|
||||
* otherwise:
|
||||
@ -4910,15 +4959,11 @@ int hci_suspend_sync(struct hci_dev *hdev)
|
||||
/* Pause other advertisements */
|
||||
hci_pause_advertising_sync(hdev);
|
||||
|
||||
/* Disable page scan if enabled */
|
||||
if (test_bit(HCI_PSCAN, &hdev->flags))
|
||||
hci_write_scan_enable_sync(hdev, SCAN_DISABLED);
|
||||
|
||||
/* Suspend monitor filters */
|
||||
hci_suspend_monitor_sync(hdev);
|
||||
|
||||
/* Prevent disconnects from causing scanning to be re-enabled */
|
||||
hdev->scanning_paused = true;
|
||||
hci_pause_scan_sync(hdev);
|
||||
|
||||
/* Soft disconnect everything (power off) */
|
||||
err = hci_disconnect_all_sync(hdev, HCI_ERROR_REMOTE_POWER_OFF);
|
||||
@ -4989,6 +5034,22 @@ static void hci_resume_monitor_sync(struct hci_dev *hdev)
|
||||
}
|
||||
}
|
||||
|
||||
/* This function resume scan and reset paused flag */
|
||||
static int hci_resume_scan_sync(struct hci_dev *hdev)
|
||||
{
|
||||
if (!hdev->scanning_paused)
|
||||
return 0;
|
||||
|
||||
hci_update_scan_sync(hdev);
|
||||
|
||||
/* Reset passive scanning to normal */
|
||||
hci_update_passive_scan_sync(hdev);
|
||||
|
||||
hdev->scanning_paused = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function performs the HCI suspend procedures in the follow order:
|
||||
*
|
||||
* Restore event mask
|
||||
@ -5011,10 +5072,9 @@ int hci_resume_sync(struct hci_dev *hdev)
|
||||
|
||||
/* Clear any event filters and restore scan state */
|
||||
hci_clear_event_filter_sync(hdev);
|
||||
hci_update_scan_sync(hdev);
|
||||
|
||||
/* Reset passive scanning to normal */
|
||||
hci_update_passive_scan_sync(hdev);
|
||||
/* Resume scanning */
|
||||
hci_resume_scan_sync(hdev);
|
||||
|
||||
/* Resume monitor filters */
|
||||
hci_resume_monitor_sync(hdev);
|
||||
|
@ -4529,6 +4529,23 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
|
||||
le_addr_type(cp->addr.type));
|
||||
if (params) {
|
||||
DECLARE_BITMAP(flags, __HCI_CONN_NUM_FLAGS);
|
||||
|
||||
bitmap_from_u64(flags, current_flags);
|
||||
|
||||
/* Devices using RPAs can only be programmed in the
|
||||
* acceptlist LL Privacy has been enable otherwise they
|
||||
* cannot mark HCI_CONN_FLAG_REMOTE_WAKEUP.
|
||||
*/
|
||||
if (test_bit(HCI_CONN_FLAG_REMOTE_WAKEUP, flags) &&
|
||||
!use_ll_privacy(hdev) &&
|
||||
hci_find_irk_by_addr(hdev, ¶ms->addr,
|
||||
params->addr_type)) {
|
||||
bt_dev_warn(hdev,
|
||||
"Cannot set wakeable for RPA");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
bitmap_from_u64(params->flags, current_flags);
|
||||
status = MGMT_STATUS_SUCCESS;
|
||||
|
||||
@ -4545,6 +4562,7 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
}
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
done:
|
||||
|
@ -297,7 +297,7 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
|
||||
if (!cmd)
|
||||
return NULL;
|
||||
|
||||
list_add(&cmd->list, &hdev->mgmt_pending);
|
||||
list_add_tail(&cmd->list, &hdev->mgmt_pending);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
@ -574,19 +574,24 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
|
||||
addr->sa_family != AF_BLUETOOTH)
|
||||
return -EINVAL;
|
||||
|
||||
if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
|
||||
return -EBADFD;
|
||||
lock_sock(sk);
|
||||
if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) {
|
||||
err = -EBADFD;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (sk->sk_type != SOCK_SEQPACKET)
|
||||
return -EINVAL;
|
||||
if (sk->sk_type != SOCK_SEQPACKET) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
hdev = hci_get_route(&sa->sco_bdaddr, &sco_pi(sk)->src, BDADDR_BREDR);
|
||||
if (!hdev)
|
||||
return -EHOSTUNREACH;
|
||||
if (!hdev) {
|
||||
err = -EHOSTUNREACH;
|
||||
goto done;
|
||||
}
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
/* Set destination address and psm */
|
||||
bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
|
||||
|
||||
@ -885,7 +890,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
err = -EBADFD;
|
||||
break;
|
||||
}
|
||||
if (enhanced_sco_capable(hdev) &&
|
||||
if (enhanced_sync_conn_capable(hdev) &&
|
||||
voice.setting == BT_VOICE_TRANSPARENT)
|
||||
sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
|
||||
hci_dev_put(hdev);
|
||||
|
Loading…
Reference in New Issue
Block a user