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:
Jakub Kicinski 2023-08-25 18:30:59 -07:00
commit 3db3474763
16 changed files with 818 additions and 307 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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