mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
bluetooth-next pull request for net-next:
- Introduce HCI_QUIRK_BROKEN_LE_CODED - Add support for PA/BIG sync - Add support for NXP IW624 chipset - Add support for Qualcomm WCN7850 -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmTnua4ZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKZtPD/4i+sYW1vmJi1VRr13Im1D+ 8RTcipgiM3Wehyc+aGx5sli2L/uHm5JXQBPb2SpMtLa7HoXdMxD/g6cxPGT8I4nZ 8JmPQzklEYw3xCs/6AUm/LmIl5XAmmpvP6Ky9DifYoGgZxbY2iY3eGLp9qY5MQ0P rZTN4hqy0887F8iG/jC4dkID0h7m2WjjIp6GbT+klpwZQCO8PTaGk8NWYxVbkdrD 4sH+X4/DSzsYOokI2zZSXgrHtkA+OEowNu9T0ItyzcG7X5f9lz4154KeeFFUoZ6/ 83A7c5YcQY6Kg+xQDtHb1Im7St8JEHgMjTGjQEme9HZkdf/KMxWQVcFvCVIpgU/B CQmaxaUIUTcMyZ8UDwpxHvJf2DT3IYHjqP3kNjUNPgrt4V1eBIpqod39M126lV37 CSLqALpLCXRez5GuCDX2NcoPjPZqu7gkARZrIz5q9v83QaYhQiohpYAkrjdkrIWT rg3iNbjYx+0okOPe81hhAKjV8iARorGUty8aOjyfDLW0F5GMowp/UYefXs3GVXvI LmY7uVoDXHLriuzcMJ1LbjaxEzpgVr3FuDEhnCx050l1TU0kg7ks6dSxdf4dpt3l zFR4YR6zBDOyxRJay4srhZYTLfq6ENxDHRpJR/TuO7gsZyOXnHRlSMiCra+xnZnD LNnXwZBJdxpo7ZBQG/25iA== =bt6N -----END PGP SIGNATURE----- Merge tag 'for-net-next-2023-08-24' 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: - Introduce HCI_QUIRK_BROKEN_LE_CODED - Add support for PA/BIG sync - Add support for NXP IW624 chipset - Add support for Qualcomm WCN7850 * tag 'for-net-next-2023-08-24' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: Bluetooth: btusb: Do not call kfree_skb() under spin_lock_irqsave() Bluetooth: btusb: Fix quirks table naming Bluetooth: HCI: Introduce HCI_QUIRK_BROKEN_LE_CODED Bluetooth: btintel: Send new command for PPAG Bluetooth: ISO: Add support for periodic adv reports processing Bluetooth: hci_conn: fail SCO/ISO via hci_conn_failed if ACL gone early Bluetooth: hci_core: Fix missing instances using HCI_MAX_AD_LENGTH Bluetooth: ISO: Use defer setup to separate PA sync and BIG sync Bluetooth: qca: add support for WCN7850 Bluetooth: qca: use switch case for soc type behavior dt-bindings: net: bluetooth: qualcomm: document WCN7850 chipset Bluetooth: hci_conn: Fix sending BT_HCI_CMD_LE_CREATE_CONN_CANCEL Bluetooth: hci_sync: Fix UAF in hci_disconnect_all_sync Bluetooth: btnxpuart: Improve inband Independent Reset handling Bluetooth: btnxpuart: Add support for IW624 chipset Bluetooth: btnxpuart: Remove check for CTS low after FW download ==================== Link: https://lore.kernel.org/r/20230824201458.2577-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
3db3474763
@ -26,6 +26,7 @@ properties:
|
||||
- qcom,qca6390-bt
|
||||
- qcom,wcn6750-bt
|
||||
- qcom,wcn6855-bt
|
||||
- qcom,wcn7850-bt
|
||||
|
||||
enable-gpios:
|
||||
maxItems: 1
|
||||
@ -58,6 +59,9 @@ properties:
|
||||
vddaon-supply:
|
||||
description: VDD_AON supply regulator handle
|
||||
|
||||
vdddig-supply:
|
||||
description: VDD_DIG supply regulator handle
|
||||
|
||||
vddbtcxmx-supply:
|
||||
description: VDD_BT_CXMX supply regulator handle
|
||||
|
||||
@ -73,6 +77,9 @@ properties:
|
||||
vddrfa1p2-supply:
|
||||
description: VDD_RFA_1P2 supply regulator handle
|
||||
|
||||
vddrfa1p9-supply:
|
||||
description: VDD_RFA_1P9 supply regulator handle
|
||||
|
||||
vddrfa2p2-supply:
|
||||
description: VDD_RFA_2P2 supply regulator handle
|
||||
|
||||
@ -157,6 +164,22 @@ allOf:
|
||||
- vddrfa0p8-supply
|
||||
- vddrfa1p2-supply
|
||||
- vddrfa1p7-supply
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,wcn7850-bt
|
||||
then:
|
||||
required:
|
||||
- enable-gpios
|
||||
- swctrl-gpios
|
||||
- vddio-supply
|
||||
- vddaon-supply
|
||||
- vdddig-supply
|
||||
- vddrfa0p8-supply
|
||||
- vddrfa1p2-supply
|
||||
- vddrfa1p9-supply
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
@ -2401,7 +2401,7 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
{
|
||||
struct btintel_ppag ppag;
|
||||
struct sk_buff *skb;
|
||||
struct btintel_loc_aware_reg ppag_cmd;
|
||||
struct hci_ppag_enable_cmd ppag_cmd;
|
||||
acpi_handle handle;
|
||||
|
||||
/* PPAG is not supported if CRF is HrP2, Jfp2, JfP1 */
|
||||
@ -2409,6 +2409,8 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
case 0x504: /* Hrp2 */
|
||||
case 0x202: /* Jfp2 */
|
||||
case 0x201: /* Jfp1 */
|
||||
bt_dev_dbg(hdev, "PPAG not supported for Intel CNVr (0x%3x)",
|
||||
ver->cnvr_top & 0xFFF);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2434,24 +2436,29 @@ static void btintel_set_ppag(struct hci_dev *hdev, struct intel_version_tlv *ver
|
||||
}
|
||||
|
||||
if (ppag.domain != 0x12) {
|
||||
bt_dev_warn(hdev, "PPAG-BT: domain is not bluetooth");
|
||||
bt_dev_dbg(hdev, "PPAG-BT: Bluetooth domain is disabled in ACPI firmware");
|
||||
return;
|
||||
}
|
||||
|
||||
/* PPAG mode, BIT0 = 0 Disabled, BIT0 = 1 Enabled */
|
||||
if (!(ppag.mode & BIT(0))) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: disabled");
|
||||
/* PPAG mode
|
||||
* BIT 0 : 0 Disabled in EU
|
||||
* 1 Enabled in EU
|
||||
* BIT 1 : 0 Disabled in China
|
||||
* 1 Enabled in China
|
||||
*/
|
||||
if ((ppag.mode & 0x01) != BIT(0) && (ppag.mode & 0x02) != BIT(1)) {
|
||||
bt_dev_dbg(hdev, "PPAG-BT: EU, China mode are disabled in CB/BIOS");
|
||||
return;
|
||||
}
|
||||
|
||||
ppag_cmd.mcc = cpu_to_le32(0);
|
||||
ppag_cmd.sel = cpu_to_le32(0); /* 0 - Enable , 1 - Disable, 2 - Testing mode */
|
||||
ppag_cmd.delta = cpu_to_le32(0);
|
||||
skb = __hci_cmd_sync(hdev, 0xfe19, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
|
||||
ppag_cmd.ppag_enable_flags = cpu_to_le32(ppag.mode);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, INTEL_OP_PPAG_CMD, sizeof(ppag_cmd), &ppag_cmd, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_warn(hdev, "Failed to send PPAG Enable (%ld)", PTR_ERR(skb));
|
||||
return;
|
||||
}
|
||||
bt_dev_info(hdev, "PPAG-BT: Enabled (Mode %d)", ppag.mode);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
@ -2780,6 +2787,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED,
|
||||
&hdev->quirks);
|
||||
|
||||
/* These variants don't seem to support LE Coded PHY */
|
||||
set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
|
||||
|
||||
/* Setup MSFT Extension support */
|
||||
btintel_set_msft_opcode(hdev, ver.hw_variant);
|
||||
|
||||
@ -2851,6 +2861,9 @@ static int btintel_setup_combined(struct hci_dev *hdev)
|
||||
*/
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
|
||||
/* These variants don't seem to support LE Coded PHY */
|
||||
set_bit(HCI_QUIRK_BROKEN_LE_CODED, &hdev->quirks);
|
||||
|
||||
/* Set Valid LE States quirk */
|
||||
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
|
||||
|
||||
|
@ -137,10 +137,9 @@ struct intel_offload_use_cases {
|
||||
__u8 preset[8];
|
||||
} __packed;
|
||||
|
||||
struct btintel_loc_aware_reg {
|
||||
__le32 mcc;
|
||||
__le32 sel;
|
||||
__le32 delta;
|
||||
#define INTEL_OP_PPAG_CMD 0xFE0B
|
||||
struct hci_ppag_enable_cmd {
|
||||
__le32 ppag_enable_flags;
|
||||
} __packed;
|
||||
|
||||
#define INTEL_TLV_TYPE_ID 0x01
|
||||
|
@ -28,12 +28,18 @@
|
||||
#define BTNXPUART_FW_DOWNLOADING 2
|
||||
#define BTNXPUART_CHECK_BOOT_SIGNATURE 3
|
||||
#define BTNXPUART_SERDEV_OPEN 4
|
||||
#define BTNXPUART_IR_IN_PROGRESS 5
|
||||
|
||||
/* NXP HW err codes */
|
||||
#define BTNXPUART_IR_HW_ERR 0xb0
|
||||
|
||||
#define FIRMWARE_W8987 "nxp/uartuart8987_bt.bin"
|
||||
#define FIRMWARE_W8997 "nxp/uartuart8997_bt_v4.bin"
|
||||
#define FIRMWARE_W9098 "nxp/uartuart9098_bt_v1.bin"
|
||||
#define FIRMWARE_IW416 "nxp/uartiw416_bt_v0.bin"
|
||||
#define FIRMWARE_IW612 "nxp/uartspi_n61x_v1.bin.se"
|
||||
#define FIRMWARE_IW624 "nxp/uartiw624_bt.bin"
|
||||
#define FIRMWARE_SECURE_IW624 "nxp/uartiw624_bt.bin.se"
|
||||
#define FIRMWARE_AW693 "nxp/uartaw693_bt.bin"
|
||||
#define FIRMWARE_SECURE_AW693 "nxp/uartaw693_bt.bin.se"
|
||||
#define FIRMWARE_HELPER "nxp/helper_uart_3000000.bin"
|
||||
@ -41,6 +47,8 @@
|
||||
#define CHIP_ID_W9098 0x5c03
|
||||
#define CHIP_ID_IW416 0x7201
|
||||
#define CHIP_ID_IW612 0x7601
|
||||
#define CHIP_ID_IW624a 0x8000
|
||||
#define CHIP_ID_IW624c 0x8001
|
||||
#define CHIP_ID_AW693 0x8200
|
||||
|
||||
#define FW_SECURE_MASK 0xc0
|
||||
@ -152,6 +160,7 @@ struct btnxpuart_dev {
|
||||
u32 fw_v1_sent_bytes;
|
||||
u32 fw_v3_offset_correction;
|
||||
u32 fw_v1_expected_len;
|
||||
u32 boot_reg_offset;
|
||||
wait_queue_head_t fw_dnld_done_wait_q;
|
||||
wait_queue_head_t check_boot_sign_wait_q;
|
||||
|
||||
@ -375,39 +384,13 @@ static void ps_timeout_func(struct timer_list *t)
|
||||
}
|
||||
}
|
||||
|
||||
static int ps_init_work(struct hci_dev *hdev)
|
||||
static void ps_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
|
||||
psdata->ps_state = PS_STATE_AWAKE;
|
||||
psdata->target_ps_mode = DEFAULT_PS_MODE;
|
||||
psdata->hdev = hdev;
|
||||
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
|
||||
psdata->c2h_wakeup_gpio = 0xff;
|
||||
|
||||
switch (DEFAULT_H2C_WAKEUP_MODE) {
|
||||
case WAKEUP_METHOD_DTR:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
|
||||
break;
|
||||
case WAKEUP_METHOD_BREAK:
|
||||
default:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
|
||||
break;
|
||||
}
|
||||
psdata->cur_psmode = PS_MODE_DISABLE;
|
||||
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
|
||||
INIT_WORK(&psdata->work, ps_work_func);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ps_init_timer(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
timer_setup(&psdata->ps_timer, ps_timeout_func, 0);
|
||||
}
|
||||
|
||||
@ -510,19 +493,31 @@ static void ps_init(struct hci_dev *hdev)
|
||||
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_RTS, 0);
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
switch (psdata->h2c_wakeupmode) {
|
||||
psdata->ps_state = PS_STATE_AWAKE;
|
||||
psdata->c2h_wakeupmode = BT_HOST_WAKEUP_METHOD_NONE;
|
||||
psdata->c2h_wakeup_gpio = 0xff;
|
||||
|
||||
psdata->cur_h2c_wakeupmode = WAKEUP_METHOD_INVALID;
|
||||
psdata->h2c_ps_interval = PS_DEFAULT_TIMEOUT_PERIOD_MS;
|
||||
switch (DEFAULT_H2C_WAKEUP_MODE) {
|
||||
case WAKEUP_METHOD_DTR:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_DTR;
|
||||
serdev_device_set_tiocm(nxpdev->serdev, 0, TIOCM_DTR);
|
||||
serdev_device_set_tiocm(nxpdev->serdev, TIOCM_DTR, 0);
|
||||
break;
|
||||
case WAKEUP_METHOD_BREAK:
|
||||
default:
|
||||
psdata->h2c_wakeupmode = WAKEUP_METHOD_BREAK;
|
||||
serdev_device_break_ctl(nxpdev->serdev, -1);
|
||||
usleep_range(5000, 10000);
|
||||
serdev_device_break_ctl(nxpdev->serdev, 0);
|
||||
usleep_range(5000, 10000);
|
||||
break;
|
||||
}
|
||||
|
||||
psdata->cur_psmode = PS_MODE_DISABLE;
|
||||
psdata->target_ps_mode = DEFAULT_PS_MODE;
|
||||
|
||||
if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode)
|
||||
hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
|
||||
if (psdata->cur_psmode != psdata->target_ps_mode)
|
||||
@ -538,6 +533,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
||||
nxpdev->fw_dnld_v1_offset = 0;
|
||||
nxpdev->fw_v1_sent_bytes = 0;
|
||||
nxpdev->fw_v1_expected_len = HDR_LEN;
|
||||
nxpdev->boot_reg_offset = 0;
|
||||
nxpdev->fw_v3_offset_correction = 0;
|
||||
nxpdev->baudrate_changed = false;
|
||||
nxpdev->timeout_changed = false;
|
||||
@ -547,7 +543,7 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
||||
serdev_device_set_flow_control(nxpdev->serdev, false);
|
||||
nxpdev->current_baudrate = HCI_NXP_PRI_BAUDRATE;
|
||||
|
||||
/* Wait till FW is downloaded and CTS becomes low */
|
||||
/* Wait till FW is downloaded */
|
||||
err = wait_event_interruptible_timeout(nxpdev->fw_dnld_done_wait_q,
|
||||
!test_bit(BTNXPUART_FW_DOWNLOADING,
|
||||
&nxpdev->tx_state),
|
||||
@ -558,16 +554,11 @@ static int nxp_download_firmware(struct hci_dev *hdev)
|
||||
}
|
||||
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
err = serdev_device_wait_for_cts(nxpdev->serdev, 1, 60000);
|
||||
if (err < 0) {
|
||||
bt_dev_err(hdev, "CTS is still high. FW Download failed.");
|
||||
return err;
|
||||
}
|
||||
release_firmware(nxpdev->fw);
|
||||
memset(nxpdev->fw_name, 0, sizeof(nxpdev->fw_name));
|
||||
|
||||
/* Allow the downloaded FW to initialize */
|
||||
usleep_range(800 * USEC_PER_MSEC, 1 * USEC_PER_SEC);
|
||||
msleep(1200);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -591,6 +582,12 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct nxp_bootloader_cmd nxp_cmd5;
|
||||
struct uart_config uart_config;
|
||||
u32 clkdivaddr = CLKDIVADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartdivaddr = UARTDIVADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartmcraddr = UARTMCRADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartreinitaddr = UARTREINITADDR - nxpdev->boot_reg_offset;
|
||||
u32 uarticraddr = UARTICRADDR - nxpdev->boot_reg_offset;
|
||||
u32 uartfcraddr = UARTFCRADDR - nxpdev->boot_reg_offset;
|
||||
|
||||
if (req_len == sizeof(nxp_cmd5)) {
|
||||
nxp_cmd5.header = __cpu_to_le32(5);
|
||||
@ -603,17 +600,17 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
|
||||
serdev_device_write_buf(nxpdev->serdev, (u8 *)&nxp_cmd5, sizeof(nxp_cmd5));
|
||||
nxpdev->fw_v3_offset_correction += req_len;
|
||||
} else if (req_len == sizeof(uart_config)) {
|
||||
uart_config.clkdiv.address = __cpu_to_le32(CLKDIVADDR);
|
||||
uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr);
|
||||
uart_config.clkdiv.value = __cpu_to_le32(0x00c00000);
|
||||
uart_config.uartdiv.address = __cpu_to_le32(UARTDIVADDR);
|
||||
uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr);
|
||||
uart_config.uartdiv.value = __cpu_to_le32(1);
|
||||
uart_config.mcr.address = __cpu_to_le32(UARTMCRADDR);
|
||||
uart_config.mcr.address = __cpu_to_le32(uartmcraddr);
|
||||
uart_config.mcr.value = __cpu_to_le32(MCR);
|
||||
uart_config.re_init.address = __cpu_to_le32(UARTREINITADDR);
|
||||
uart_config.re_init.address = __cpu_to_le32(uartreinitaddr);
|
||||
uart_config.re_init.value = __cpu_to_le32(INIT);
|
||||
uart_config.icr.address = __cpu_to_le32(UARTICRADDR);
|
||||
uart_config.icr.address = __cpu_to_le32(uarticraddr);
|
||||
uart_config.icr.value = __cpu_to_le32(ICR);
|
||||
uart_config.fcr.address = __cpu_to_le32(UARTFCRADDR);
|
||||
uart_config.fcr.address = __cpu_to_le32(uartfcraddr);
|
||||
uart_config.fcr.value = __cpu_to_le32(FCR);
|
||||
/* FW expects swapped CRC bytes */
|
||||
uart_config.crc = __cpu_to_be32(crc32_be(0UL, (char *)&uart_config,
|
||||
@ -702,7 +699,7 @@ static int nxp_recv_chip_ver_v1(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
goto free_skb;
|
||||
|
||||
chip_id = le16_to_cpu(req->chip_id ^ req->chip_id_comp);
|
||||
if (chip_id == 0xffff) {
|
||||
if (chip_id == 0xffff && nxpdev->fw_dnld_v1_offset) {
|
||||
nxpdev->fw_dnld_v1_offset = 0;
|
||||
nxpdev->fw_v1_sent_bytes = 0;
|
||||
nxpdev->fw_v1_expected_len = HDR_LEN;
|
||||
@ -827,6 +824,7 @@ free_skb:
|
||||
static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
|
||||
u8 loader_ver)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
char *fw_name = NULL;
|
||||
|
||||
switch (chipid) {
|
||||
@ -839,6 +837,16 @@ static char *nxp_get_fw_name_from_chipid(struct hci_dev *hdev, u16 chipid,
|
||||
case CHIP_ID_IW612:
|
||||
fw_name = FIRMWARE_IW612;
|
||||
break;
|
||||
case CHIP_ID_IW624a:
|
||||
case CHIP_ID_IW624c:
|
||||
nxpdev->boot_reg_offset = 1;
|
||||
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
|
||||
fw_name = FIRMWARE_IW624;
|
||||
else if ((loader_ver & FW_SECURE_MASK) != FW_AUTH_ILLEGAL)
|
||||
fw_name = FIRMWARE_SECURE_IW624;
|
||||
else
|
||||
bt_dev_err(hdev, "Illegal loader version %02x", loader_ver);
|
||||
break;
|
||||
case CHIP_ID_AW693:
|
||||
if ((loader_ver & FW_SECURE_MASK) == FW_OPEN)
|
||||
fw_name = FIRMWARE_AW693;
|
||||
@ -969,45 +977,13 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct sk_buff *skb;
|
||||
u8 *status;
|
||||
u8 pcmd = 0;
|
||||
int err = 0;
|
||||
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
status = skb_pull_data(skb, 1);
|
||||
if (!status || *status)
|
||||
goto free_skb;
|
||||
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
err = nxp_download_firmware(hdev);
|
||||
if (err < 0)
|
||||
goto free_skb;
|
||||
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
|
||||
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
|
||||
if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) {
|
||||
nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE;
|
||||
nxp_set_baudrate_cmd(hdev, NULL);
|
||||
}
|
||||
hci_cmd_sync_queue(hdev, send_wakeup_method_cmd, NULL, NULL);
|
||||
hci_cmd_sync_queue(hdev, send_ps_cmd, NULL, NULL);
|
||||
|
||||
free_skb:
|
||||
kfree_skb(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* NXP protocol */
|
||||
static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
|
||||
{
|
||||
serdev_device_set_baudrate(nxpdev->serdev, HCI_NXP_PRI_BAUDRATE);
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
|
||||
serdev_device_set_flow_control(nxpdev->serdev, false);
|
||||
else
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
set_bit(BTNXPUART_CHECK_BOOT_SIGNATURE, &nxpdev->tx_state);
|
||||
|
||||
return wait_event_interruptible_timeout(nxpdev->check_boot_sign_wait_q,
|
||||
@ -1016,15 +992,29 @@ static int nxp_check_boot_sign(struct btnxpuart_dev *nxpdev)
|
||||
msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static int nxp_set_ind_reset(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
static const u8 ir_hw_err[] = { HCI_EV_HARDWARE_ERROR,
|
||||
0x01, BTNXPUART_IR_HW_ERR };
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = bt_skb_alloc(3, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
|
||||
skb_put_data(skb, ir_hw_err, 3);
|
||||
|
||||
/* Inject Hardware Error to upper stack */
|
||||
return hci_recv_frame(hdev, skb);
|
||||
}
|
||||
|
||||
/* NXP protocol */
|
||||
static int nxp_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
int err = 0;
|
||||
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
|
||||
init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
|
||||
|
||||
if (nxp_check_boot_sign(nxpdev)) {
|
||||
bt_dev_dbg(hdev, "Need FW Download.");
|
||||
err = nxp_download_firmware(hdev);
|
||||
@ -1035,10 +1025,6 @@ static int nxp_setup(struct hci_dev *hdev)
|
||||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
}
|
||||
|
||||
device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
|
||||
&nxpdev->fw_init_baudrate);
|
||||
if (!nxpdev->fw_init_baudrate)
|
||||
nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
|
||||
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
|
||||
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
|
||||
|
||||
@ -1049,6 +1035,46 @@ static int nxp_setup(struct hci_dev *hdev)
|
||||
|
||||
ps_init(hdev);
|
||||
|
||||
if (test_and_clear_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state))
|
||||
hci_dev_clear_flag(hdev, HCI_SETUP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nxp_hw_err(struct hci_dev *hdev, u8 code)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
|
||||
switch (code) {
|
||||
case BTNXPUART_IR_HW_ERR:
|
||||
set_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state);
|
||||
hci_dev_set_flag(hdev, HCI_SETUP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int nxp_shutdown(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct sk_buff *skb;
|
||||
u8 *status;
|
||||
u8 pcmd = 0;
|
||||
|
||||
if (test_bit(BTNXPUART_IR_IN_PROGRESS, &nxpdev->tx_state)) {
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
status = skb_pull_data(skb, 1);
|
||||
if (status) {
|
||||
serdev_device_set_flow_control(nxpdev->serdev, false);
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1256,7 +1282,8 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data,
|
||||
nxpdev->rx_skb = NULL;
|
||||
return err;
|
||||
}
|
||||
nxpdev->hdev->stat.byte_rx += count;
|
||||
if (!is_fw_downloading(nxpdev))
|
||||
nxpdev->hdev->stat.byte_rx += count;
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -1289,6 +1316,16 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
||||
INIT_WORK(&nxpdev->tx_work, btnxpuart_tx_work);
|
||||
skb_queue_head_init(&nxpdev->txq);
|
||||
|
||||
init_waitqueue_head(&nxpdev->fw_dnld_done_wait_q);
|
||||
init_waitqueue_head(&nxpdev->check_boot_sign_wait_q);
|
||||
|
||||
device_property_read_u32(&nxpdev->serdev->dev, "fw-init-baudrate",
|
||||
&nxpdev->fw_init_baudrate);
|
||||
if (!nxpdev->fw_init_baudrate)
|
||||
nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
|
||||
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
|
||||
crc8_populate_msb(crc8_table, POLYNOMIAL8);
|
||||
|
||||
/* Initialize and register HCI device */
|
||||
@ -1309,6 +1346,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
||||
hdev->flush = btnxpuart_flush;
|
||||
hdev->setup = nxp_setup;
|
||||
hdev->send = nxp_enqueue;
|
||||
hdev->hw_error = nxp_hw_err;
|
||||
hdev->shutdown = nxp_shutdown;
|
||||
SET_HCIDEV_DEV(hdev, &serdev->dev);
|
||||
|
||||
if (hci_register_dev(hdev) < 0) {
|
||||
@ -1317,8 +1356,7 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ps_init_work(hdev);
|
||||
ps_init_timer(hdev);
|
||||
ps_setup(hdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -604,26 +604,38 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
|
||||
/* Download rampatch file */
|
||||
config.type = TLV_TYPE_PATCH;
|
||||
if (soc_type == QCA_WCN3988) {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apbtfw%02x.tlv", rom_ver);
|
||||
} else if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crbtfw%02x.tlv", rom_ver);
|
||||
} else if (soc_type == QCA_QCA6390) {
|
||||
break;
|
||||
case QCA_WCN3988:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htbtfw%02x.tlv", rom_ver);
|
||||
} else if (soc_type == QCA_WCN6750) {
|
||||
break;
|
||||
case QCA_WCN6750:
|
||||
/* Choose mbn file by default.If mbn file is not found
|
||||
* then choose tlv file
|
||||
*/
|
||||
config.type = ELF_TYPE_PATCH;
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/msbtfw%02x.mbn", rom_ver);
|
||||
} else if (soc_type == QCA_WCN6855) {
|
||||
break;
|
||||
case QCA_WCN6855:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpbtfw%02x.tlv", rom_ver);
|
||||
} else {
|
||||
break;
|
||||
case QCA_WCN7850:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hmtbtfw%02x.tlv", rom_ver);
|
||||
break;
|
||||
default:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/rampatch_%08x.bin", soc_ver);
|
||||
}
|
||||
@ -639,33 +651,48 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
|
||||
/* Download NVM configuration */
|
||||
config.type = TLV_TYPE_NVM;
|
||||
if (firmware_name)
|
||||
if (firmware_name) {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/%s", firmware_name);
|
||||
else if (soc_type == QCA_WCN3988)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/apnv%02x.bin", rom_ver);
|
||||
else if (qca_is_wcn399x(soc_type)) {
|
||||
if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
|
||||
} else {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
if (le32_to_cpu(ver.soc_id) == QCA_WCN3991_SOC_ID) {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02xu.bin", rom_ver);
|
||||
} else {
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02x.bin", rom_ver);
|
||||
}
|
||||
break;
|
||||
case QCA_WCN3988:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02xu.bin", rom_ver);
|
||||
} else {
|
||||
"qca/apnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_QCA6390:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/crnv%02x.bin", rom_ver);
|
||||
"qca/htnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_WCN6750:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/msnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_WCN6855:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpnv%02x.bin", rom_ver);
|
||||
break;
|
||||
case QCA_WCN7850:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hmtnv%02x.bin", rom_ver);
|
||||
break;
|
||||
|
||||
default:
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/nvm_%08x.bin", soc_ver);
|
||||
}
|
||||
}
|
||||
else if (soc_type == QCA_QCA6390)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/htnv%02x.bin", rom_ver);
|
||||
else if (soc_type == QCA_WCN6750)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/msnv%02x.bin", rom_ver);
|
||||
else if (soc_type == QCA_WCN6855)
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/hpnv%02x.bin", rom_ver);
|
||||
else
|
||||
snprintf(config.fwname, sizeof(config.fwname),
|
||||
"qca/nvm_%08x.bin", soc_ver);
|
||||
|
||||
err = qca_download_firmware(hdev, &config, soc_type, rom_ver);
|
||||
if (err < 0) {
|
||||
@ -673,16 +700,25 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (soc_type >= QCA_WCN3991) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3991:
|
||||
case QCA_QCA6390:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
err = qca_disable_soc_logging(hdev);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* WCN399x and WCN6750 supports the Microsoft vendor extension with 0xFD70 as the
|
||||
* VsMsftOpCode.
|
||||
*/
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
@ -704,6 +740,7 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
/* get fw build info */
|
||||
err = qca_read_fw_build_info(hdev);
|
||||
if (err < 0)
|
||||
|
@ -149,6 +149,7 @@ enum qca_btsoc_type {
|
||||
QCA_QCA6390,
|
||||
QCA_WCN6750,
|
||||
QCA_WCN6855,
|
||||
QCA_WCN7850,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_BT_QCA)
|
||||
@ -161,27 +162,6 @@ int qca_read_soc_version(struct hci_dev *hdev, struct qca_btsoc_version *ver,
|
||||
enum qca_btsoc_type);
|
||||
int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
|
||||
int qca_send_pre_shutdown_cmd(struct hci_dev *hdev);
|
||||
static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return soc_type == QCA_WCN6750;
|
||||
}
|
||||
static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return soc_type == QCA_WCN6855;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
@ -209,21 +189,6 @@ static inline int qca_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline bool qca_is_wcn399x(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -175,7 +175,7 @@ static const struct usb_device_id btusb_table[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, btusb_table);
|
||||
|
||||
static const struct usb_device_id blacklist_table[] = {
|
||||
static const struct usb_device_id quirks_table[] = {
|
||||
/* CSR BlueCore devices */
|
||||
{ USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR },
|
||||
|
||||
@ -2162,7 +2162,7 @@ static int btusb_switch_alt_setting(struct hci_dev *hdev, int new_alts)
|
||||
* alternate setting.
|
||||
*/
|
||||
spin_lock_irqsave(&data->rxlock, flags);
|
||||
kfree_skb(data->sco_skb);
|
||||
dev_kfree_skb_irq(data->sco_skb);
|
||||
data->sco_skb = NULL;
|
||||
spin_unlock_irqrestore(&data->rxlock, flags);
|
||||
|
||||
@ -4194,7 +4194,7 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
if (!id->driver_info) {
|
||||
const struct usb_device_id *match;
|
||||
|
||||
match = usb_match_id(intf, blacklist_table);
|
||||
match = usb_match_id(intf, quirks_table);
|
||||
if (match)
|
||||
id = match;
|
||||
}
|
||||
|
@ -607,9 +607,18 @@ static int qca_open(struct hci_uart *hu)
|
||||
if (hu->serdev) {
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
|
||||
if (qca_is_wcn399x(qcadev->btsoc_type) ||
|
||||
qca_is_wcn6750(qcadev->btsoc_type))
|
||||
switch (qcadev->btsoc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
hu->init_speed = qcadev->init_speed;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (qcadev->oper_speed)
|
||||
hu->oper_speed = qcadev->oper_speed;
|
||||
@ -1341,12 +1350,20 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
|
||||
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
|
||||
|
||||
/* Give the controller time to process the request */
|
||||
if (qca_is_wcn399x(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6750(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6855(qca_soc_type(hu)))
|
||||
switch (qca_soc_type(hu)) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
usleep_range(1000, 10000);
|
||||
else
|
||||
break;
|
||||
|
||||
default:
|
||||
msleep(300);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1419,13 +1436,20 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
|
||||
|
||||
static int qca_check_speeds(struct hci_uart *hu)
|
||||
{
|
||||
if (qca_is_wcn399x(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6750(qca_soc_type(hu)) ||
|
||||
qca_is_wcn6855(qca_soc_type(hu))) {
|
||||
switch (qca_soc_type(hu)) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
|
||||
!qca_get_speed(hu, QCA_OPER_SPEED))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!qca_get_speed(hu, QCA_INIT_SPEED) ||
|
||||
!qca_get_speed(hu, QCA_OPER_SPEED))
|
||||
return -EINVAL;
|
||||
@ -1454,14 +1478,29 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
||||
/* Disable flow control for wcn3990 to deassert RTS while
|
||||
* changing the baudrate of chip and host.
|
||||
*/
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type))
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
hci_uart_set_flow_control(hu, true);
|
||||
break;
|
||||
|
||||
if (soc_type == QCA_WCN3990) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
reinit_completion(&qca->drop_ev_comp);
|
||||
set_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
qca_baudrate = qca_get_baudrate_value(speed);
|
||||
@ -1473,12 +1512,23 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
|
||||
host_set_baudrate(hu, speed);
|
||||
|
||||
error:
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type))
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
hci_uart_set_flow_control(hu, false);
|
||||
break;
|
||||
|
||||
if (soc_type == QCA_WCN3990) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3990:
|
||||
/* Wait for the controller to send the vendor event
|
||||
* for the baudrate change command.
|
||||
*/
|
||||
@ -1490,6 +1540,10 @@ error:
|
||||
}
|
||||
|
||||
clear_bit(QCA_DROP_VENDOR_EVENT, &qca->flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1651,12 +1705,20 @@ static int qca_regulator_init(struct hci_uart *hu)
|
||||
}
|
||||
}
|
||||
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
/* Forcefully enable wcn399x to enter in to boot mode. */
|
||||
host_set_baudrate(hu, 2400);
|
||||
ret = qca_send_power_pulse(hu, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* For wcn6750 need to enable gpio bt_en */
|
||||
@ -1673,10 +1735,18 @@ static int qca_regulator_init(struct hci_uart *hu)
|
||||
|
||||
qca_set_speed(hu, QCA_INIT_SPEED);
|
||||
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
ret = qca_send_power_pulse(hu, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Now the device is in ready state to communicate with host.
|
||||
@ -1710,11 +1780,18 @@ static int qca_power_on(struct hci_dev *hdev)
|
||||
if (!hu->serdev)
|
||||
return 0;
|
||||
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
ret = qca_regulator_init(hu);
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
if (qcadev->bt_en) {
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 1);
|
||||
@ -1748,6 +1825,7 @@ static int qca_setup(struct hci_uart *hu)
|
||||
const char *firmware_name = qca_get_firmware_name(hu);
|
||||
int ret;
|
||||
struct qca_btsoc_version ver;
|
||||
const char *soc_name;
|
||||
|
||||
ret = qca_check_speeds(hu);
|
||||
if (ret)
|
||||
@ -1762,10 +1840,30 @@ static int qca_setup(struct hci_uart *hu)
|
||||
*/
|
||||
set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks);
|
||||
|
||||
bt_dev_info(hdev, "setting up %s",
|
||||
qca_is_wcn399x(soc_type) ? "wcn399x" :
|
||||
(soc_type == QCA_WCN6750) ? "wcn6750" :
|
||||
(soc_type == QCA_WCN6855) ? "wcn6855" : "ROME/QCA6390");
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
soc_name = "wcn399x";
|
||||
break;
|
||||
|
||||
case QCA_WCN6750:
|
||||
soc_name = "wcn6750";
|
||||
break;
|
||||
|
||||
case QCA_WCN6855:
|
||||
soc_name = "wcn6855";
|
||||
break;
|
||||
|
||||
case QCA_WCN7850:
|
||||
soc_name = "wcn7850";
|
||||
break;
|
||||
|
||||
default:
|
||||
soc_name = "ROME/QCA6390";
|
||||
}
|
||||
bt_dev_info(hdev, "setting up %s", soc_name);
|
||||
|
||||
qca->memdump_state = QCA_MEMDUMP_IDLE;
|
||||
|
||||
@ -1776,16 +1874,23 @@ retry:
|
||||
|
||||
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
|
||||
|
||||
if (qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
|
||||
hci_set_aosp_capable(hdev);
|
||||
|
||||
ret = qca_read_soc_version(hdev, &ver, soc_type);
|
||||
if (ret)
|
||||
goto out;
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
qca_set_speed(hu, QCA_INIT_SPEED);
|
||||
}
|
||||
|
||||
@ -1799,9 +1904,17 @@ retry:
|
||||
qca_baudrate = qca_get_baudrate_value(speed);
|
||||
}
|
||||
|
||||
if (!(qca_is_wcn399x(soc_type) ||
|
||||
qca_is_wcn6750(soc_type) ||
|
||||
qca_is_wcn6855(soc_type))) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Get QCA version information */
|
||||
ret = qca_read_soc_version(hdev, &ver, soc_type);
|
||||
if (ret)
|
||||
@ -1955,6 +2068,20 @@ static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = {
|
||||
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
|
||||
};
|
||||
|
||||
static const struct qca_device_data qca_soc_data_wcn7850 __maybe_unused = {
|
||||
.soc_type = QCA_WCN7850,
|
||||
.vregs = (struct qca_vreg []) {
|
||||
{ "vddio", 5000 },
|
||||
{ "vddaon", 26000 },
|
||||
{ "vdddig", 126000 },
|
||||
{ "vddrfa0p8", 102000 },
|
||||
{ "vddrfa1p2", 257000 },
|
||||
{ "vddrfa1p9", 302000 },
|
||||
},
|
||||
.num_vregs = 6,
|
||||
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
|
||||
};
|
||||
|
||||
static void qca_power_shutdown(struct hci_uart *hu)
|
||||
{
|
||||
struct qca_serdev *qcadev;
|
||||
@ -1980,11 +2107,18 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
||||
|
||||
qcadev = serdev_device_get_drvdata(hu->serdev);
|
||||
|
||||
if (qca_is_wcn399x(soc_type)) {
|
||||
switch (soc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
host_set_baudrate(hu, 2400);
|
||||
qca_send_power_pulse(hu, false);
|
||||
qca_regulator_disable(qcadev);
|
||||
} else if (soc_type == QCA_WCN6750 || soc_type == QCA_WCN6855) {
|
||||
break;
|
||||
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||
msleep(100);
|
||||
qca_regulator_disable(qcadev);
|
||||
@ -1992,7 +2126,9 @@ static void qca_power_shutdown(struct hci_uart *hu)
|
||||
sw_ctrl_state = gpiod_get_value_cansleep(qcadev->sw_ctrl);
|
||||
bt_dev_dbg(hu->hdev, "SW_CTRL is %d", sw_ctrl_state);
|
||||
}
|
||||
} else if (qcadev->bt_en) {
|
||||
break;
|
||||
|
||||
default:
|
||||
gpiod_set_value_cansleep(qcadev->bt_en, 0);
|
||||
}
|
||||
|
||||
@ -2117,11 +2253,19 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
if (!qcadev->oper_speed)
|
||||
BT_DBG("UART will pick default operating speed");
|
||||
|
||||
if (data &&
|
||||
(qca_is_wcn399x(data->soc_type) ||
|
||||
qca_is_wcn6750(data->soc_type) ||
|
||||
qca_is_wcn6855(data->soc_type))) {
|
||||
if (data)
|
||||
qcadev->btsoc_type = data->soc_type;
|
||||
else
|
||||
qcadev->btsoc_type = QCA_ROME;
|
||||
|
||||
switch (qcadev->btsoc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
qcadev->bt_power = devm_kzalloc(&serdev->dev,
|
||||
sizeof(struct qca_power),
|
||||
GFP_KERNEL);
|
||||
@ -2151,7 +2295,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
GPIOD_IN);
|
||||
if (IS_ERR_OR_NULL(qcadev->sw_ctrl) &&
|
||||
(data->soc_type == QCA_WCN6750 ||
|
||||
data->soc_type == QCA_WCN6855))
|
||||
data->soc_type == QCA_WCN6855 ||
|
||||
data->soc_type == QCA_WCN7850))
|
||||
dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
|
||||
|
||||
qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
|
||||
@ -2165,12 +2310,9 @@ static int qca_serdev_probe(struct serdev_device *serdev)
|
||||
BT_ERR("wcn3990 serdev registration failed");
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
if (data)
|
||||
qcadev->btsoc_type = data->soc_type;
|
||||
else
|
||||
qcadev->btsoc_type = QCA_ROME;
|
||||
break;
|
||||
|
||||
default:
|
||||
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR_OR_NULL(qcadev->bt_en)) {
|
||||
@ -2226,13 +2368,24 @@ static void qca_serdev_remove(struct serdev_device *serdev)
|
||||
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
|
||||
struct qca_power *power = qcadev->bt_power;
|
||||
|
||||
if ((qca_is_wcn399x(qcadev->btsoc_type) ||
|
||||
qca_is_wcn6750(qcadev->btsoc_type) ||
|
||||
qca_is_wcn6855(qcadev->btsoc_type)) &&
|
||||
power->vregs_on)
|
||||
qca_power_shutdown(&qcadev->serdev_hu);
|
||||
else if (qcadev->susclk)
|
||||
clk_disable_unprepare(qcadev->susclk);
|
||||
switch (qcadev->btsoc_type) {
|
||||
case QCA_WCN3988:
|
||||
case QCA_WCN3990:
|
||||
case QCA_WCN3991:
|
||||
case QCA_WCN3998:
|
||||
case QCA_WCN6750:
|
||||
case QCA_WCN6855:
|
||||
case QCA_WCN7850:
|
||||
if (power->vregs_on) {
|
||||
qca_power_shutdown(&qcadev->serdev_hu);
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
default:
|
||||
if (qcadev->susclk)
|
||||
clk_disable_unprepare(qcadev->susclk);
|
||||
}
|
||||
|
||||
hci_uart_unregister_device(&qcadev->serdev_hu);
|
||||
}
|
||||
@ -2415,6 +2568,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
|
||||
{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
|
||||
{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
|
||||
{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
|
||||
{ .compatible = "qcom,wcn7850-bt", .data = &qca_soc_data_wcn7850},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
|
||||
|
@ -319,6 +319,16 @@ enum {
|
||||
* This quirk must be set before hci_register_dev is called.
|
||||
*/
|
||||
HCI_QUIRK_USE_MSFT_EXT_ADDRESS_FILTER,
|
||||
|
||||
/*
|
||||
* When this quirk is set, LE Coded PHY shall not be used. This is
|
||||
* required for some Intel controllers which erroneously claim to
|
||||
* support it but it causes problems with extended scanning.
|
||||
*
|
||||
* This quirk can be set before hci_register_dev is called or
|
||||
* during the hdev->setup vendor callback.
|
||||
*/
|
||||
HCI_QUIRK_BROKEN_LE_CODED,
|
||||
};
|
||||
|
||||
/* HCI device flags */
|
||||
@ -2771,6 +2781,17 @@ struct hci_ev_le_enh_conn_complete {
|
||||
__u8 clk_accurancy;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_PER_ADV_REPORT 0x0f
|
||||
struct hci_ev_le_per_adv_report {
|
||||
__le16 sync_handle;
|
||||
__u8 tx_power;
|
||||
__u8 rssi;
|
||||
__u8 cte_type;
|
||||
__u8 data_status;
|
||||
__u8 length;
|
||||
__u8 data[];
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_EXT_ADV_SET_TERM 0x12
|
||||
struct hci_evt_le_ext_adv_set_term {
|
||||
__u8 status;
|
||||
|
@ -83,7 +83,7 @@ struct discovery_state {
|
||||
u8 last_adv_addr_type;
|
||||
s8 last_adv_rssi;
|
||||
u32 last_adv_flags;
|
||||
u8 last_adv_data[HCI_MAX_AD_LENGTH];
|
||||
u8 last_adv_data[HCI_MAX_EXT_AD_LENGTH];
|
||||
u8 last_adv_data_len;
|
||||
bool report_invalid_rssi;
|
||||
bool result_filtering;
|
||||
@ -290,7 +290,7 @@ struct adv_pattern {
|
||||
__u8 ad_type;
|
||||
__u8 offset;
|
||||
__u8 length;
|
||||
__u8 value[HCI_MAX_AD_LENGTH];
|
||||
__u8 value[HCI_MAX_EXT_AD_LENGTH];
|
||||
};
|
||||
|
||||
struct adv_rssi_thresholds {
|
||||
@ -726,7 +726,7 @@ struct hci_conn {
|
||||
__u16 le_conn_interval;
|
||||
__u16 le_conn_latency;
|
||||
__u16 le_supv_timeout;
|
||||
__u8 le_adv_data[HCI_MAX_AD_LENGTH];
|
||||
__u8 le_adv_data[HCI_MAX_EXT_AD_LENGTH];
|
||||
__u8 le_adv_data_len;
|
||||
__u8 le_per_adv_data[HCI_MAX_PER_AD_LENGTH];
|
||||
__u8 le_per_adv_data_len;
|
||||
@ -978,6 +978,8 @@ enum {
|
||||
HCI_CONN_CREATE_CIS,
|
||||
HCI_CONN_BIG_SYNC,
|
||||
HCI_CONN_BIG_SYNC_FAILED,
|
||||
HCI_CONN_PA_SYNC,
|
||||
HCI_CONN_PA_SYNC_FAILED,
|
||||
};
|
||||
|
||||
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
|
||||
@ -1300,7 +1302,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *
|
||||
if (c->type != ISO_LINK)
|
||||
continue;
|
||||
|
||||
if (handle == c->iso_qos.bcast.big) {
|
||||
if (handle != BT_ISO_QOS_BIG_UNSET && handle == c->iso_qos.bcast.big) {
|
||||
rcu_read_unlock();
|
||||
return c;
|
||||
}
|
||||
@ -1311,6 +1313,29 @@ static inline struct hci_conn *hci_conn_hash_lookup_big_any_dst(struct hci_dev *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *
|
||||
hci_conn_hash_lookup_pa_sync(struct hci_dev *hdev, __u8 big)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type != ISO_LINK ||
|
||||
!test_bit(HCI_CONN_PA_SYNC, &c->flags))
|
||||
continue;
|
||||
|
||||
if (c->iso_qos.bcast.big == big) {
|
||||
rcu_read_unlock();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
|
||||
__u8 type, __u16 state)
|
||||
{
|
||||
@ -1435,7 +1460,8 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
__u8 data_len, __u8 *data);
|
||||
int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
|
||||
__u8 sid, struct bt_iso_qos *qos);
|
||||
int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos,
|
||||
int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
|
||||
struct bt_iso_qos *qos,
|
||||
__u16 sync_handle, __u8 num_bis, __u8 bis[]);
|
||||
int hci_conn_check_link_mode(struct hci_conn *conn);
|
||||
int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
|
||||
@ -1791,7 +1817,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
||||
#define scan_2m(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_2M) || \
|
||||
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_2M))
|
||||
|
||||
#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED))
|
||||
#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED) && \
|
||||
!test_bit(HCI_QUIRK_BROKEN_LE_CODED, \
|
||||
&(dev)->quirks))
|
||||
|
||||
#define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \
|
||||
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED))
|
||||
|
@ -33,7 +33,7 @@ u8 eir_append_local_name(struct hci_dev *hdev, u8 *ptr, u8 ad_len)
|
||||
size_t complete_len;
|
||||
|
||||
/* no space left for name (+ NULL + type + len) */
|
||||
if ((HCI_MAX_AD_LENGTH - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3)
|
||||
if ((max_adv_len(hdev) - ad_len) < HCI_MAX_SHORT_NAME_LENGTH + 3)
|
||||
return ad_len;
|
||||
|
||||
/* use complete name if present and fits */
|
||||
|
@ -734,6 +734,7 @@ struct iso_list_data {
|
||||
};
|
||||
int count;
|
||||
bool big_term;
|
||||
bool pa_sync_term;
|
||||
bool big_sync_term;
|
||||
};
|
||||
|
||||
@ -807,7 +808,10 @@ static int big_terminate_sync(struct hci_dev *hdev, void *data)
|
||||
if (d->big_sync_term)
|
||||
hci_le_big_terminate_sync(hdev, d->big);
|
||||
|
||||
return hci_le_pa_terminate_sync(hdev, d->sync_handle);
|
||||
if (d->pa_sync_term)
|
||||
return hci_le_pa_terminate_sync(hdev, d->sync_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *conn)
|
||||
@ -823,6 +827,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
|
||||
|
||||
d->big = big;
|
||||
d->sync_handle = conn->sync_handle;
|
||||
d->pa_sync_term = test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags);
|
||||
d->big_sync_term = test_and_clear_bit(HCI_CONN_BIG_SYNC, &conn->flags);
|
||||
|
||||
ret = hci_cmd_sync_queue(hdev, big_terminate_sync, d,
|
||||
@ -1039,6 +1044,29 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
return conn;
|
||||
}
|
||||
|
||||
static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
|
||||
{
|
||||
if (!reason)
|
||||
reason = HCI_ERROR_REMOTE_USER_TERM;
|
||||
|
||||
/* Due to race, SCO/ISO conn might be not established yet at this point,
|
||||
* and nothing else will clean it up. In other cases it is done via HCI
|
||||
* events.
|
||||
*/
|
||||
switch (conn->type) {
|
||||
case SCO_LINK:
|
||||
case ESCO_LINK:
|
||||
if (HCI_CONN_HANDLE_UNSET(conn->handle))
|
||||
hci_conn_failed(conn, reason);
|
||||
break;
|
||||
case ISO_LINK:
|
||||
if (conn->state != BT_CONNECTED &&
|
||||
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags))
|
||||
hci_conn_failed(conn, reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hci_conn_unlink(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
@ -1061,14 +1089,7 @@ static void hci_conn_unlink(struct hci_conn *conn)
|
||||
if (!test_bit(HCI_UP, &hdev->flags))
|
||||
continue;
|
||||
|
||||
/* Due to race, SCO connection might be not established
|
||||
* yet at this point. Delete it now, otherwise it is
|
||||
* possible for it to be stuck and can't be deleted.
|
||||
*/
|
||||
if ((child->type == SCO_LINK ||
|
||||
child->type == ESCO_LINK) &&
|
||||
HCI_CONN_HANDLE_UNSET(child->handle))
|
||||
hci_conn_del(child);
|
||||
hci_conn_cleanup_child(child, conn->abort_reason);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1299,6 +1320,7 @@ static int hci_connect_le_sync(struct hci_dev *hdev, void *data)
|
||||
|
||||
bt_dev_dbg(hdev, "conn %p", conn);
|
||||
|
||||
clear_bit(HCI_CONN_SCANNING, &conn->flags);
|
||||
conn->state = BT_CONNECT;
|
||||
|
||||
return hci_le_create_conn_sync(hdev, conn);
|
||||
@ -1370,8 +1392,6 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->conn_timeout = conn_timeout;
|
||||
|
||||
clear_bit(HCI_CONN_SCANNING, &conn->flags);
|
||||
|
||||
err = hci_cmd_sync_queue(hdev, hci_connect_le_sync,
|
||||
UINT_PTR(conn->handle),
|
||||
create_le_conn_complete);
|
||||
@ -2100,7 +2120,8 @@ int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
|
||||
return hci_cmd_sync_queue(hdev, create_pa_sync, cp, create_pa_complete);
|
||||
}
|
||||
|
||||
int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos,
|
||||
int hci_le_big_create_sync(struct hci_dev *hdev, struct hci_conn *hcon,
|
||||
struct bt_iso_qos *qos,
|
||||
__u16 sync_handle, __u8 num_bis, __u8 bis[])
|
||||
{
|
||||
struct _packed {
|
||||
@ -2116,6 +2137,9 @@ int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (hcon)
|
||||
hcon->iso_qos.bcast.big = qos->bcast.big;
|
||||
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.cp.handle = qos->bcast.big;
|
||||
pdu.cp.sync_handle = cpu_to_le16(sync_handle);
|
||||
|
@ -6581,19 +6581,56 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
|
||||
struct hci_ev_le_pa_sync_established *ev = data;
|
||||
int mask = hdev->link_mode;
|
||||
__u8 flags = 0;
|
||||
struct hci_conn *bis;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
if (ev->status)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ISO_LINK, &flags);
|
||||
if (!(mask & HCI_LM_ACCEPT))
|
||||
if (!(mask & HCI_LM_ACCEPT)) {
|
||||
hci_le_pa_term_sync(hdev, ev->handle);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!(flags & HCI_PROTO_DEFER))
|
||||
goto unlock;
|
||||
|
||||
/* Add connection to indicate the PA sync event */
|
||||
bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (!bis)
|
||||
goto unlock;
|
||||
|
||||
if (ev->status)
|
||||
set_bit(HCI_CONN_PA_SYNC_FAILED, &bis->flags);
|
||||
else
|
||||
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
|
||||
|
||||
/* Notify connection to iso layer */
|
||||
hci_connect_cfm(bis, ev->status);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_per_adv_report *ev = data;
|
||||
int mask = hdev->link_mode;
|
||||
__u8 flags = 0;
|
||||
|
||||
bt_dev_dbg(hdev, "sync_handle 0x%4.4x", le16_to_cpu(ev->sync_handle));
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, ISO_LINK, &flags);
|
||||
if (!(mask & HCI_LM_ACCEPT))
|
||||
hci_le_pa_term_sync(hdev, ev->sync_handle);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
@ -7045,6 +7082,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
{
|
||||
struct hci_evt_le_big_sync_estabilished *ev = data;
|
||||
struct hci_conn *bis;
|
||||
struct hci_conn *pa_sync;
|
||||
int i;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
@ -7055,6 +7093,15 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!ev->status) {
|
||||
pa_sync = hci_conn_hash_lookup_pa_sync(hdev, ev->handle);
|
||||
if (pa_sync)
|
||||
/* Also mark the BIG sync established event on the
|
||||
* associated PA sync hcon
|
||||
*/
|
||||
set_bit(HCI_CONN_BIG_SYNC, &pa_sync->flags);
|
||||
}
|
||||
|
||||
for (i = 0; i < ev->num_bis; i++) {
|
||||
u16 handle = le16_to_cpu(ev->bis[i]);
|
||||
__le32 interval;
|
||||
@ -7068,6 +7115,10 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
bis->handle = handle;
|
||||
}
|
||||
|
||||
if (ev->status != 0x42)
|
||||
/* Mark PA sync as established */
|
||||
set_bit(HCI_CONN_PA_SYNC, &bis->flags);
|
||||
|
||||
bis->iso_qos.bcast.big = ev->handle;
|
||||
memset(&interval, 0, sizeof(interval));
|
||||
memcpy(&interval, ev->latency, sizeof(ev->latency));
|
||||
@ -7180,6 +7231,11 @@ static const struct hci_le_ev {
|
||||
HCI_LE_EV(HCI_EV_LE_PA_SYNC_ESTABLISHED,
|
||||
hci_le_pa_sync_estabilished_evt,
|
||||
sizeof(struct hci_ev_le_pa_sync_established)),
|
||||
/* [0x0f = HCI_EV_LE_PER_ADV_REPORT] */
|
||||
HCI_LE_EV_VL(HCI_EV_LE_PER_ADV_REPORT,
|
||||
hci_le_per_adv_report_evt,
|
||||
sizeof(struct hci_ev_le_per_adv_report),
|
||||
HCI_MAX_EVENT_SIZE),
|
||||
/* [0x12 = HCI_EV_LE_EXT_ADV_SET_TERM] */
|
||||
HCI_LE_EV(HCI_EV_LE_EXT_ADV_SET_TERM, hci_le_ext_adv_term_evt,
|
||||
sizeof(struct hci_evt_le_ext_adv_set_term)),
|
||||
|
@ -4668,7 +4668,10 @@ static const struct {
|
||||
"advertised, but not supported."),
|
||||
HCI_QUIRK_BROKEN(SET_RPA_TIMEOUT,
|
||||
"HCI LE Set Random Private Address Timeout command is "
|
||||
"advertised, but not supported.")
|
||||
"advertised, but not supported."),
|
||||
HCI_QUIRK_BROKEN(LE_CODED,
|
||||
"HCI LE Coded PHY feature bit is set, "
|
||||
"but its usage is not supported.")
|
||||
};
|
||||
|
||||
/* This function handles hdev setup stage:
|
||||
@ -5370,6 +5373,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
|
||||
{
|
||||
int err = 0;
|
||||
u16 handle = conn->handle;
|
||||
struct hci_conn *c;
|
||||
|
||||
switch (conn->state) {
|
||||
case BT_CONNECTED:
|
||||
@ -5383,49 +5387,78 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
|
||||
err = hci_reject_conn_sync(hdev, conn, reason);
|
||||
break;
|
||||
case BT_OPEN:
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Cleanup bis or pa sync connections */
|
||||
if (test_and_clear_bit(HCI_CONN_BIG_SYNC_FAILED, &conn->flags) ||
|
||||
test_and_clear_bit(HCI_CONN_PA_SYNC_FAILED, &conn->flags)) {
|
||||
hci_conn_failed(conn, reason);
|
||||
} else if (test_bit(HCI_CONN_PA_SYNC, &conn->flags) ||
|
||||
test_bit(HCI_CONN_BIG_SYNC, &conn->flags)) {
|
||||
conn->state = BT_CLOSED;
|
||||
hci_disconn_cfm(conn, reason);
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
return 0;
|
||||
case BT_BOUND:
|
||||
hci_dev_lock(hdev);
|
||||
hci_conn_failed(conn, reason);
|
||||
hci_dev_unlock(hdev);
|
||||
return 0;
|
||||
default:
|
||||
hci_dev_lock(hdev);
|
||||
conn->state = BT_CLOSED;
|
||||
hci_disconn_cfm(conn, reason);
|
||||
hci_conn_del(conn);
|
||||
hci_dev_unlock(hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Check if the connection hasn't been cleanup while waiting
|
||||
* commands to complete.
|
||||
*/
|
||||
c = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (!c || c != conn) {
|
||||
err = 0;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Cleanup hci_conn object if it cannot be cancelled as it
|
||||
* likelly means the controller and host stack are out of sync
|
||||
* or in case of LE it was still scanning so it can be cleanup
|
||||
* safely.
|
||||
*/
|
||||
if (err) {
|
||||
struct hci_conn *c;
|
||||
|
||||
/* Check if the connection hasn't been cleanup while waiting
|
||||
* commands to complete.
|
||||
*/
|
||||
c = hci_conn_hash_lookup_handle(hdev, handle);
|
||||
if (!c || c != conn)
|
||||
return 0;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
hci_conn_failed(conn, err);
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
hci_conn_failed(conn, reason);
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hci_disconnect_all_sync(struct hci_dev *hdev, u8 reason)
|
||||
{
|
||||
struct hci_conn *conn, *tmp;
|
||||
int err;
|
||||
struct list_head *head = &hdev->conn_hash.list;
|
||||
struct hci_conn *conn;
|
||||
|
||||
list_for_each_entry_safe(conn, tmp, &hdev->conn_hash.list, list) {
|
||||
err = hci_abort_conn_sync(hdev, conn, reason);
|
||||
if (err)
|
||||
return err;
|
||||
rcu_read_lock();
|
||||
while ((conn = list_first_or_null_rcu(head, struct hci_conn, list))) {
|
||||
/* Make sure the connection is not freed while unlocking */
|
||||
conn = hci_conn_get(conn);
|
||||
rcu_read_unlock();
|
||||
/* Disregard possible errors since hci_conn_del shall have been
|
||||
* called even in case of errors had occurred since it would
|
||||
* then cause hci_conn_failed to be called which calls
|
||||
* hci_conn_del internally.
|
||||
*/
|
||||
hci_abort_conn_sync(hdev, conn, reason);
|
||||
hci_conn_put(conn);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ static void iso_sock_kill(struct sock *sk);
|
||||
/* iso_pinfo flags values */
|
||||
enum {
|
||||
BT_SK_BIG_SYNC,
|
||||
BT_SK_PA_SYNC,
|
||||
};
|
||||
|
||||
struct iso_pinfo {
|
||||
@ -75,6 +76,8 @@ static struct bt_iso_qos default_qos;
|
||||
|
||||
static bool check_ucast_qos(struct bt_iso_qos *qos);
|
||||
static bool check_bcast_qos(struct bt_iso_qos *qos);
|
||||
static bool iso_match_sid(struct sock *sk, void *data);
|
||||
static void iso_sock_disconn(struct sock *sk);
|
||||
|
||||
/* ---- ISO timers ---- */
|
||||
#define ISO_CONN_TIMEOUT (HZ * 40)
|
||||
@ -598,6 +601,15 @@ static void iso_sock_cleanup_listen(struct sock *parent)
|
||||
iso_sock_kill(sk);
|
||||
}
|
||||
|
||||
/* If listening socket stands for a PA sync connection,
|
||||
* properly disconnect the hcon and socket.
|
||||
*/
|
||||
if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon &&
|
||||
test_bit(HCI_CONN_PA_SYNC, &iso_pi(parent)->conn->hcon->flags)) {
|
||||
iso_sock_disconn(parent);
|
||||
return;
|
||||
}
|
||||
|
||||
parent->sk_state = BT_CLOSED;
|
||||
sock_set_flag(parent, SOCK_ZAPPED);
|
||||
}
|
||||
@ -619,6 +631,16 @@ static void iso_sock_kill(struct sock *sk)
|
||||
sock_put(sk);
|
||||
}
|
||||
|
||||
static void iso_sock_disconn(struct sock *sk)
|
||||
{
|
||||
sk->sk_state = BT_DISCONN;
|
||||
iso_sock_set_timer(sk, ISO_DISCONN_TIMEOUT);
|
||||
iso_conn_lock(iso_pi(sk)->conn);
|
||||
hci_conn_drop(iso_pi(sk)->conn->hcon);
|
||||
iso_pi(sk)->conn->hcon = NULL;
|
||||
iso_conn_unlock(iso_pi(sk)->conn);
|
||||
}
|
||||
|
||||
static void __iso_sock_close(struct sock *sk)
|
||||
{
|
||||
BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
|
||||
@ -631,20 +653,19 @@ static void __iso_sock_close(struct sock *sk)
|
||||
case BT_CONNECT:
|
||||
case BT_CONNECTED:
|
||||
case BT_CONFIG:
|
||||
if (iso_pi(sk)->conn->hcon) {
|
||||
sk->sk_state = BT_DISCONN;
|
||||
iso_sock_set_timer(sk, ISO_DISCONN_TIMEOUT);
|
||||
iso_conn_lock(iso_pi(sk)->conn);
|
||||
hci_conn_drop(iso_pi(sk)->conn->hcon);
|
||||
iso_pi(sk)->conn->hcon = NULL;
|
||||
iso_conn_unlock(iso_pi(sk)->conn);
|
||||
} else {
|
||||
if (iso_pi(sk)->conn->hcon)
|
||||
iso_sock_disconn(sk);
|
||||
else
|
||||
iso_chan_del(sk, ECONNRESET);
|
||||
}
|
||||
break;
|
||||
|
||||
case BT_CONNECT2:
|
||||
iso_chan_del(sk, ECONNRESET);
|
||||
if (iso_pi(sk)->conn->hcon &&
|
||||
(test_bit(HCI_CONN_PA_SYNC, &iso_pi(sk)->conn->hcon->flags) ||
|
||||
test_bit(HCI_CONN_PA_SYNC_FAILED, &iso_pi(sk)->conn->hcon->flags)))
|
||||
iso_sock_disconn(sk);
|
||||
else
|
||||
iso_chan_del(sk, ECONNRESET);
|
||||
break;
|
||||
case BT_DISCONN:
|
||||
iso_chan_del(sk, ECONNRESET);
|
||||
@ -1139,6 +1160,29 @@ static void iso_conn_defer_accept(struct hci_conn *conn)
|
||||
hci_send_cmd(hdev, HCI_OP_LE_ACCEPT_CIS, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void iso_conn_big_sync(struct sock *sk)
|
||||
{
|
||||
int err;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
hdev = hci_get_route(&iso_pi(sk)->dst, &iso_pi(sk)->src,
|
||||
iso_pi(sk)->src_type);
|
||||
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
|
||||
err = hci_le_big_create_sync(hdev, iso_pi(sk)->conn->hcon,
|
||||
&iso_pi(sk)->qos,
|
||||
iso_pi(sk)->sync_handle,
|
||||
iso_pi(sk)->bc_num_bis,
|
||||
iso_pi(sk)->bc_bis);
|
||||
if (err)
|
||||
bt_dev_err(hdev, "hci_le_big_create_sync: %d",
|
||||
err);
|
||||
}
|
||||
}
|
||||
|
||||
static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||
size_t len, int flags)
|
||||
{
|
||||
@ -1151,8 +1195,15 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg,
|
||||
lock_sock(sk);
|
||||
switch (sk->sk_state) {
|
||||
case BT_CONNECT2:
|
||||
iso_conn_defer_accept(pi->conn->hcon);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
if (pi->conn->hcon &&
|
||||
test_bit(HCI_CONN_PA_SYNC, &pi->conn->hcon->flags)) {
|
||||
iso_conn_big_sync(sk);
|
||||
sk->sk_state = BT_LISTEN;
|
||||
set_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags);
|
||||
} else {
|
||||
iso_conn_defer_accept(pi->conn->hcon);
|
||||
sk->sk_state = BT_CONFIG;
|
||||
}
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
case BT_CONNECT:
|
||||
@ -1395,7 +1446,8 @@ static int iso_sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
break;
|
||||
|
||||
case BT_ISO_BASE:
|
||||
if (sk->sk_state == BT_CONNECTED) {
|
||||
if (sk->sk_state == BT_CONNECTED &&
|
||||
!bacmp(&iso_pi(sk)->dst, BDADDR_ANY)) {
|
||||
base_len = iso_pi(sk)->conn->hcon->le_per_adv_data_len;
|
||||
base = iso_pi(sk)->conn->hcon->le_per_adv_data;
|
||||
} else {
|
||||
@ -1513,11 +1565,17 @@ static bool iso_match_big(struct sock *sk, void *data)
|
||||
return ev->handle == iso_pi(sk)->qos.bcast.big;
|
||||
}
|
||||
|
||||
static bool iso_match_pa_sync_flag(struct sock *sk, void *data)
|
||||
{
|
||||
return test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags);
|
||||
}
|
||||
|
||||
static void iso_conn_ready(struct iso_conn *conn)
|
||||
{
|
||||
struct sock *parent;
|
||||
struct sock *parent = NULL;
|
||||
struct sock *sk = conn->sk;
|
||||
struct hci_ev_le_big_sync_estabilished *ev;
|
||||
struct hci_ev_le_big_sync_estabilished *ev = NULL;
|
||||
struct hci_ev_le_pa_sync_established *ev2 = NULL;
|
||||
struct hci_conn *hcon;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
@ -1529,15 +1587,32 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
if (!hcon)
|
||||
return;
|
||||
|
||||
ev = hci_recv_event_data(hcon->hdev,
|
||||
HCI_EVT_LE_BIG_SYNC_ESTABILISHED);
|
||||
if (ev)
|
||||
if (test_bit(HCI_CONN_BIG_SYNC, &hcon->flags) ||
|
||||
test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
|
||||
ev = hci_recv_event_data(hcon->hdev,
|
||||
HCI_EVT_LE_BIG_SYNC_ESTABILISHED);
|
||||
|
||||
/* Get reference to PA sync parent socket, if it exists */
|
||||
parent = iso_get_sock_listen(&hcon->src,
|
||||
&hcon->dst,
|
||||
iso_match_big, ev);
|
||||
else
|
||||
iso_match_pa_sync_flag, NULL);
|
||||
if (!parent && ev)
|
||||
parent = iso_get_sock_listen(&hcon->src,
|
||||
&hcon->dst,
|
||||
iso_match_big, ev);
|
||||
} else if (test_bit(HCI_CONN_PA_SYNC, &hcon->flags) ||
|
||||
test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) {
|
||||
ev2 = hci_recv_event_data(hcon->hdev,
|
||||
HCI_EV_LE_PA_SYNC_ESTABLISHED);
|
||||
if (ev2)
|
||||
parent = iso_get_sock_listen(&hcon->src,
|
||||
&hcon->dst,
|
||||
iso_match_sid, ev2);
|
||||
}
|
||||
|
||||
if (!parent)
|
||||
parent = iso_get_sock_listen(&hcon->src,
|
||||
BDADDR_ANY, NULL, NULL);
|
||||
BDADDR_ANY, NULL, NULL);
|
||||
|
||||
if (!parent)
|
||||
return;
|
||||
@ -1554,11 +1629,17 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
iso_sock_init(sk, parent);
|
||||
|
||||
bacpy(&iso_pi(sk)->src, &hcon->src);
|
||||
iso_pi(sk)->src_type = hcon->src_type;
|
||||
|
||||
/* Convert from HCI to three-value type */
|
||||
if (hcon->src_type == ADDR_LE_DEV_PUBLIC)
|
||||
iso_pi(sk)->src_type = BDADDR_LE_PUBLIC;
|
||||
else
|
||||
iso_pi(sk)->src_type = BDADDR_LE_RANDOM;
|
||||
|
||||
/* If hcon has no destination address (BDADDR_ANY) it means it
|
||||
* was created by HCI_EV_LE_BIG_SYNC_ESTABILISHED so we need to
|
||||
* initialize using the parent socket destination address.
|
||||
* was created by HCI_EV_LE_BIG_SYNC_ESTABILISHED or
|
||||
* HCI_EV_LE_PA_SYNC_ESTABLISHED so we need to initialize using
|
||||
* the parent socket destination address.
|
||||
*/
|
||||
if (!bacmp(&hcon->dst, BDADDR_ANY)) {
|
||||
bacpy(&hcon->dst, &iso_pi(parent)->dst);
|
||||
@ -1566,13 +1647,24 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
hcon->sync_handle = iso_pi(parent)->sync_handle;
|
||||
}
|
||||
|
||||
if (ev2 && !ev2->status) {
|
||||
iso_pi(sk)->sync_handle = iso_pi(parent)->sync_handle;
|
||||
iso_pi(sk)->qos = iso_pi(parent)->qos;
|
||||
iso_pi(sk)->bc_num_bis = iso_pi(parent)->bc_num_bis;
|
||||
memcpy(iso_pi(sk)->bc_bis, iso_pi(parent)->bc_bis, ISO_MAX_NUM_BIS);
|
||||
}
|
||||
|
||||
bacpy(&iso_pi(sk)->dst, &hcon->dst);
|
||||
iso_pi(sk)->dst_type = hcon->dst_type;
|
||||
iso_pi(sk)->sync_handle = iso_pi(parent)->sync_handle;
|
||||
memcpy(iso_pi(sk)->base, iso_pi(parent)->base, iso_pi(parent)->base_len);
|
||||
iso_pi(sk)->base_len = iso_pi(parent)->base_len;
|
||||
|
||||
hci_conn_hold(hcon);
|
||||
iso_chan_add(conn, sk, parent);
|
||||
|
||||
if (ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) {
|
||||
if ((ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) ||
|
||||
(ev2 && ev2->status)) {
|
||||
/* Trigger error signal on child socket */
|
||||
sk->sk_err = ECONNREFUSED;
|
||||
sk->sk_error_report(sk);
|
||||
@ -1604,12 +1696,20 @@ static bool iso_match_sync_handle(struct sock *sk, void *data)
|
||||
return le16_to_cpu(ev->sync_handle) == iso_pi(sk)->sync_handle;
|
||||
}
|
||||
|
||||
static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data)
|
||||
{
|
||||
struct hci_ev_le_per_adv_report *ev = data;
|
||||
|
||||
return le16_to_cpu(ev->sync_handle) == iso_pi(sk)->sync_handle;
|
||||
}
|
||||
|
||||
/* ----- ISO interface with lower layer (HCI) ----- */
|
||||
|
||||
int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
{
|
||||
struct hci_ev_le_pa_sync_established *ev1;
|
||||
struct hci_evt_le_big_info_adv_report *ev2;
|
||||
struct hci_ev_le_per_adv_report *ev3;
|
||||
struct sock *sk;
|
||||
int lm = 0;
|
||||
|
||||
@ -1625,12 +1725,15 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
* 2. HCI_EVT_LE_BIG_INFO_ADV_REPORT: When connect_ind is triggered by a
|
||||
* a BIG Info it attempts to check if there any listening socket with
|
||||
* the same sync_handle and if it does then attempt to create a sync.
|
||||
* 3. HCI_EV_LE_PER_ADV_REPORT: When a PA report is received, it is stored
|
||||
* in iso_pi(sk)->base so it can be passed up to user, in the case of a
|
||||
* broadcast sink.
|
||||
*/
|
||||
ev1 = hci_recv_event_data(hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED);
|
||||
if (ev1) {
|
||||
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr, iso_match_sid,
|
||||
ev1);
|
||||
if (sk)
|
||||
if (sk && !ev1->status)
|
||||
iso_pi(sk)->sync_handle = le16_to_cpu(ev1->handle);
|
||||
|
||||
goto done;
|
||||
@ -1638,16 +1741,21 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
|
||||
ev2 = hci_recv_event_data(hdev, HCI_EVT_LE_BIG_INFO_ADV_REPORT);
|
||||
if (ev2) {
|
||||
/* Try to get PA sync listening socket, if it exists */
|
||||
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
|
||||
iso_match_sync_handle, ev2);
|
||||
iso_match_pa_sync_flag, NULL);
|
||||
if (!sk)
|
||||
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
|
||||
iso_match_sync_handle, ev2);
|
||||
if (sk) {
|
||||
int err;
|
||||
|
||||
if (ev2->num_bis < iso_pi(sk)->bc_num_bis)
|
||||
iso_pi(sk)->bc_num_bis = ev2->num_bis;
|
||||
|
||||
if (!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
|
||||
err = hci_le_big_create_sync(hdev,
|
||||
if (!test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags) &&
|
||||
!test_and_set_bit(BT_SK_BIG_SYNC, &iso_pi(sk)->flags)) {
|
||||
err = hci_le_big_create_sync(hdev, NULL,
|
||||
&iso_pi(sk)->qos,
|
||||
iso_pi(sk)->sync_handle,
|
||||
iso_pi(sk)->bc_num_bis,
|
||||
@ -1659,6 +1767,17 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ev3 = hci_recv_event_data(hdev, HCI_EV_LE_PER_ADV_REPORT);
|
||||
if (ev3) {
|
||||
sk = iso_get_sock_listen(&hdev->bdaddr, bdaddr,
|
||||
iso_match_sync_handle_pa_report, ev3);
|
||||
|
||||
if (sk) {
|
||||
memcpy(iso_pi(sk)->base, ev3->data, ev3->length);
|
||||
iso_pi(sk)->base_len = ev3->length;
|
||||
}
|
||||
} else {
|
||||
sk = iso_get_sock_listen(&hdev->bdaddr, BDADDR_ANY, NULL, NULL);
|
||||
}
|
||||
@ -1699,12 +1818,13 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
|
||||
BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
|
||||
|
||||
/* Similar to the success case, if HCI_CONN_BIG_SYNC_FAILED is set,
|
||||
* queue the failed bis connection into the accept queue of the
|
||||
* listening socket and wake up userspace, to inform the user about
|
||||
* the BIG sync failed event.
|
||||
/* Similar to the success case, if HCI_CONN_BIG_SYNC_FAILED or
|
||||
* HCI_CONN_PA_SYNC_FAILED is set, queue the failed connection
|
||||
* into the accept queue of the listening socket and wake up
|
||||
* userspace, to inform the user about the event.
|
||||
*/
|
||||
if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
|
||||
if (!status || test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags) ||
|
||||
test_bit(HCI_CONN_PA_SYNC_FAILED, &hcon->flags)) {
|
||||
struct iso_conn *conn;
|
||||
|
||||
conn = iso_conn_add(hcon);
|
||||
|
@ -5381,9 +5381,9 @@ static u8 parse_adv_monitor_pattern(struct adv_monitor *m, u8 pattern_count,
|
||||
for (i = 0; i < pattern_count; i++) {
|
||||
offset = patterns[i].offset;
|
||||
length = patterns[i].length;
|
||||
if (offset >= HCI_MAX_AD_LENGTH ||
|
||||
length > HCI_MAX_AD_LENGTH ||
|
||||
(offset + length) > HCI_MAX_AD_LENGTH)
|
||||
if (offset >= HCI_MAX_EXT_AD_LENGTH ||
|
||||
length > HCI_MAX_EXT_AD_LENGTH ||
|
||||
(offset + length) > HCI_MAX_EXT_AD_LENGTH)
|
||||
return MGMT_STATUS_INVALID_PARAMS;
|
||||
|
||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
|
Loading…
Reference in New Issue
Block a user