mirror of https://github.com/torvalds/linux.git
bluetooth-next pull request for net-next:
core: - HCI: Add initial support for PAST - hci_core: Introduce HCI_CONN_FLAG_PAST - ISO: Add support to bind to trigger PAST - HCI: Always use the identity address when initializing a connection - ISO: Attempt to resolve broadcast address - MGMT: Allow use of Set Device Flags without Add Device - ISO: Fix not updating BIS sender source address - HCI: Add support for LL Extended Feature Set driver: - btusb: Add new VID/PID 2b89/6275 for RTL8761BUV - btusb: MT7920: Add VID/PID 0489/e135 - btusb: MT7922: Add VID/PID 0489/e170 - btusb: Add new VID/PID 13d3/3533 for RTL8821CE - btusb: Add new VID/PID 0x0489/0xE12F for RTL8852BE-VT - btusb: Add new VID/PID 0x13d3/0x3618 for RTL8852BE-VT - btusb: Add new VID/PID 0x13d3/0x3619 for RTL8852BE-VT - btusb: Reclassify Qualcomm WCN6855 debug packets - btintel_pcie: Introduce HCI Driver protocol - btintel_pcie: Support for S4 (Hibernate) - btintel_pcie: Suspend/Resume: Controller doorbell interrupt handling - dt-bindings: net: Convert Marvell 8897/8997 bindings to DT schema - btbcm: Use kmalloc_array() to prevent overflow - btrtl: Add the support for RTL8761CUV - hci_h5: avoid sending two SYNC messages - hci_h5: implement CRC data integrity MAINTAINERS: - Add Bartosz Golaszewski as Qualcomm hci_qca maintainer -----BEGIN PGP SIGNATURE----- iQJNBAABCgA3FiEE7E6oRXp8w05ovYr/9JCA4xAyCykFAmkuCjwZHGx1aXoudm9u LmRlbnR6QGludGVsLmNvbQAKCRD0kIDjEDILKdOvD/9ReyEoUaUZ6aKC7TO66fT0 eo/sga036O3k9oeeECsEBOOgwOy86gbR7uGol/vV6mocm/Duql/pNqMrgC28Cxhy u+aGX7sf3s8Pc/e82Syx6u+QPKa6xz3Hnx1UdCM/HXb0nOkJUm3VHFmshFxmXE9g xyMWKtLp1DrXOZNLauR/p8fgAEhGQs8muICuWT/SrEbXZ4+coQoz2h6279IA9FGZ 2qj/pcLIBFk0qePkiaZ5LJGjF0P0+S9uX9XlhF9yIsLIckH8qAbPsHpD1+RsbkId R4WYxIBTVeeUhvWQezodsZJa8HRFQendCeBq8QhOo6fEcprpxrb4/8NS6hipblfy rTeyKUoPmPZ/5/nvx9pbRSqqdVOVT/pEOzD5o66bppX7s7Xq3k/WIRqCKpM4znIp iZyUlaoX6J5R+SHaOLVzRun6oUzXnIHbIGbWopfQBtMgpDajTcxQJpsTWdFQW4El RP+N9xoF+OBa4pKumKCe11pzUJOkBislDIAjNvp8wmevfSfkmo8CbqK5WwfL0rar VeBDlkfPYLVNiJ30WKwmLC4ymRvzAFhC0R6LoDPw8OWTZ7VBc7ReCcHDp8GBWbew pKe7jMWCCOo1q9zx0KBAwghQ6ZbABnK6N6Fg/Wpb/kfz7YkqnsRWRJkI2BTotEdu +bIZ2MwuJ59ROnfPy0tNBw== =ndah -----END PGP SIGNATURE----- Merge tag 'for-net-next-2025-12-01' 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: core: - HCI: Add initial support for PAST - hci_core: Introduce HCI_CONN_FLAG_PAST - ISO: Add support to bind to trigger PAST - HCI: Always use the identity address when initializing a connection - ISO: Attempt to resolve broadcast address - MGMT: Allow use of Set Device Flags without Add Device - ISO: Fix not updating BIS sender source address - HCI: Add support for LL Extended Feature Set driver: - btusb: Add new VID/PID 2b89/6275 for RTL8761BUV - btusb: MT7920: Add VID/PID 0489/e135 - btusb: MT7922: Add VID/PID 0489/e170 - btusb: Add new VID/PID 13d3/3533 for RTL8821CE - btusb: Add new VID/PID 0x0489/0xE12F for RTL8852BE-VT - btusb: Add new VID/PID 0x13d3/0x3618 for RTL8852BE-VT - btusb: Add new VID/PID 0x13d3/0x3619 for RTL8852BE-VT - btusb: Reclassify Qualcomm WCN6855 debug packets - btintel_pcie: Introduce HCI Driver protocol - btintel_pcie: Support for S4 (Hibernate) - btintel_pcie: Suspend/Resume: Controller doorbell interrupt handling - dt-bindings: net: Convert Marvell 8897/8997 bindings to DT schema - btbcm: Use kmalloc_array() to prevent overflow - btrtl: Add the support for RTL8761CUV - hci_h5: avoid sending two SYNC messages - hci_h5: implement CRC data integrity MAINTAINERS: - Add Bartosz Golaszewski as Qualcomm hci_qca maintainer * tag 'for-net-next-2025-12-01' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (29 commits) Bluetooth: btusb: Add new VID/PID 13d3/3533 for RTL8821CE Bluetooth: HCI: Add support for LL Extended Feature Set drivers/bluetooth: btbcm: Use kmalloc_array() to prevent overflow Bluetooth: btintel_pcie: Introduce HCI Driver protocol Bluetooth: btusb: add new custom firmwares Bluetooth: btusb: Add new VID/PID 0x13d3/0x3619 for RTL8852BE-VT Bluetooth: btusb: Add new VID/PID 0x13d3/0x3618 for RTL8852BE-VT Bluetooth: btusb: Add new VID/PID 0x0489/0xE12F for RTL8852BE-VT Bluetooth: iso: fix socket matching ambiguity between BIS and CIS Bluetooth: MAINTAINERS: Add Bartosz Golaszewski as Qualcomm hci_qca maintainer Bluetooth: btrtl: Add the support for RTL8761CUV Bluetooth: Remove redundant pm_runtime_mark_last_busy() calls dt-bindings: net: Convert Marvell 8897/8997 bindings to DT schema Bluetooth: btusb: Reclassify Qualcomm WCN6855 debug packets Bluetooth: btusb: Add new VID/PID 2b89/6275 for RTL8761BUV Bluetooth: btintel_pcie: Suspend/Resume: Controller doorbell interrupt handling Bluetooth: btintel_pcie: Support for S4 (Hibernate) Bluetooth: btusb: MT7922: Add VID/PID 0489/e170 Bluetooth: btusb: MT7920: Add VID/PID 0489/e135 Bluetooth: ISO: Fix not updating BIS sender source address ... ==================== Link: https://patch.msgid.link/20251201213818.97249-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
4a18b6cd7c
|
|
@ -0,0 +1,79 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/bluetooth/marvell,sd8897-bt.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Marvell 8897/8997 (sd8897/sd8997) bluetooth devices (SDIO)
|
||||
|
||||
maintainers:
|
||||
- Ariel D'Alessandro <ariel.dalessandro@collabora.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/net/bluetooth/bluetooth-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- marvell,sd8897-bt
|
||||
- marvell,sd8997-bt
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
marvell,cal-data:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-array
|
||||
description:
|
||||
Calibration data downloaded to the device during initialization.
|
||||
maxItems: 28
|
||||
|
||||
marvell,wakeup-pin:
|
||||
$ref: /schemas/types.yaml#/definitions/uint16
|
||||
description:
|
||||
Wakeup pin number of the bluetooth chip. Used by firmware to wakeup host
|
||||
system.
|
||||
|
||||
marvell,wakeup-gap-ms:
|
||||
$ref: /schemas/types.yaml#/definitions/uint16
|
||||
description:
|
||||
Wakeup latency of the host platform. Required by the chip sleep feature.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
mmc {
|
||||
vmmc-supply = <&wlan_en_reg>;
|
||||
bus-width = <4>;
|
||||
cap-power-off-card;
|
||||
keep-power-in-suspend;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
bluetooth@2 {
|
||||
compatible = "marvell,sd8897-bt";
|
||||
reg = <2>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <119 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
marvell,cal-data = /bits/ 8 <
|
||||
0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
|
||||
0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
|
||||
0x00 0x00 0xf0 0x00>;
|
||||
marvell,wakeup-pin = /bits/ 16 <0x0d>;
|
||||
marvell,wakeup-gap-ms = /bits/ 16 <0x64>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -14,7 +14,7 @@ Required properties:
|
|||
|
||||
|
||||
Also, vendors that use btusb may have device additional properties, e.g:
|
||||
Documentation/devicetree/bindings/net/marvell-bt-8xxx.txt
|
||||
Documentation/devicetree/bindings/net/bluetooth/marvell,sd8897-bt.yaml
|
||||
|
||||
Optional properties:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
Marvell 8897/8997 (sd8897/sd8997) bluetooth devices (SDIO or USB based)
|
||||
------
|
||||
The 8997 devices supports multiple interfaces. When used on SDIO interfaces,
|
||||
the btmrvl driver is used and when used on USB interface, the btusb driver is
|
||||
used.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be one of the following:
|
||||
* "marvell,sd8897-bt" (for SDIO)
|
||||
* "marvell,sd8997-bt" (for SDIO)
|
||||
* "usb1286,204e" (for USB)
|
||||
|
||||
Optional properties:
|
||||
|
||||
- marvell,cal-data: Calibration data downloaded to the device during
|
||||
initialization. This is an array of 28 values(u8).
|
||||
This is only applicable to SDIO devices.
|
||||
|
||||
- marvell,wakeup-pin: It represents wakeup pin number of the bluetooth chip.
|
||||
firmware will use the pin to wakeup host system (u16).
|
||||
- marvell,wakeup-gap-ms: wakeup gap represents wakeup latency of the host
|
||||
platform. The value will be configured to firmware. This
|
||||
is needed to work chip's sleep feature as expected (u16).
|
||||
- interrupt-names: Used only for USB based devices (See below)
|
||||
- interrupts : specifies the interrupt pin number to the cpu. For SDIO, the
|
||||
driver will use the first interrupt specified in the interrupt
|
||||
array. For USB based devices, the driver will use the interrupt
|
||||
named "wakeup" from the interrupt-names and interrupt arrays.
|
||||
The driver will request an irq based on this interrupt number.
|
||||
During system suspend, the irq will be enabled so that the
|
||||
bluetooth chip can wakeup host platform under certain
|
||||
conditions. During system resume, the irq will be disabled
|
||||
to make sure unnecessary interrupt is not received.
|
||||
|
||||
Example:
|
||||
|
||||
IRQ pin 119 is used as system wakeup source interrupt.
|
||||
wakeup pin 13 and gap 100ms are configured so that firmware can wakeup host
|
||||
using this device side pin and wakeup latency.
|
||||
|
||||
Example for SDIO device follows (calibration data is also available in
|
||||
below example).
|
||||
|
||||
&mmc3 {
|
||||
vmmc-supply = <&wlan_en_reg>;
|
||||
bus-width = <4>;
|
||||
cap-power-off-card;
|
||||
keep-power-in-suspend;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
btmrvl: bluetooth@2 {
|
||||
compatible = "marvell,sd8897-bt";
|
||||
reg = <2>;
|
||||
interrupt-parent = <&pio>;
|
||||
interrupts = <119 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
marvell,cal-data = /bits/ 8 <
|
||||
0x37 0x01 0x1c 0x00 0xff 0xff 0xff 0xff 0x01 0x7f 0x04 0x02
|
||||
0x00 0x00 0xba 0xce 0xc0 0xc6 0x2d 0x00 0x00 0x00 0x00 0x00
|
||||
0x00 0x00 0xf0 0x00>;
|
||||
marvell,wakeup-pin = /bits/ 16 <0x0d>;
|
||||
marvell,wakeup-gap-ms = /bits/ 16 <0x64>;
|
||||
};
|
||||
};
|
||||
|
||||
Example for USB device:
|
||||
|
||||
&usb_host1_ohci {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
mvl_bt1: bt@1 {
|
||||
compatible = "usb1286,204e";
|
||||
reg = <1>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupt-names = "wakeup";
|
||||
interrupts = <119 IRQ_TYPE_LEVEL_LOW>;
|
||||
marvell,wakeup-pin = /bits/ 16 <0x0d>;
|
||||
marvell,wakeup-gap-ms = /bits/ 16 <0x64>;
|
||||
};
|
||||
};
|
||||
|
|
@ -21071,6 +21071,7 @@ F: Documentation/devicetree/bindings/net/qcom,bam-dmux.yaml
|
|||
F: drivers/net/wwan/qcom_bam_dmux.c
|
||||
|
||||
QUALCOMM BLUETOOTH DRIVER
|
||||
M: Bartosz Golaszewski <brgl@bgdev.pl>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/bluetooth/btqca.[ch]
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ config BT_HCIUART_3WIRE
|
|||
bool "Three-wire UART (H5) protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
select CRC_CCITT
|
||||
help
|
||||
The HCI Three-wire UART Transport Layer makes it possible to
|
||||
user the Bluetooth HCI over a serial port interface. The HCI
|
||||
|
|
|
|||
|
|
@ -642,7 +642,9 @@ int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done, bool use_autobaud
|
|||
snprintf(postfix, sizeof(postfix), "-%4.4x-%4.4x", vid, pid);
|
||||
}
|
||||
|
||||
fw_name = kmalloc(BCM_FW_NAME_COUNT_MAX * BCM_FW_NAME_LEN, GFP_KERNEL);
|
||||
fw_name = kmalloc_array(BCM_FW_NAME_COUNT_MAX,
|
||||
sizeof(*fw_name),
|
||||
GFP_KERNEL);
|
||||
if (!fw_name)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/hci_drv.h>
|
||||
|
||||
#include "btintel.h"
|
||||
#include "btintel_pcie.h"
|
||||
|
|
@ -825,6 +826,11 @@ static inline bool btintel_pcie_in_d0(struct btintel_pcie_data *data)
|
|||
return !(data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY);
|
||||
}
|
||||
|
||||
static inline bool btintel_pcie_in_device_halt(struct btintel_pcie_data *data)
|
||||
{
|
||||
return data->boot_stage_cache & BTINTEL_PCIE_CSR_BOOT_STAGE_DEVICE_HALTED;
|
||||
}
|
||||
|
||||
static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data,
|
||||
u32 dxstate)
|
||||
{
|
||||
|
|
@ -2355,6 +2361,63 @@ static bool btintel_pcie_wakeup(struct hci_dev *hdev)
|
|||
return device_may_wakeup(&data->pdev->dev);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
u16 opcode;
|
||||
const char *desc;
|
||||
} btintel_pcie_hci_drv_supported_commands[] = {
|
||||
/* Common commands */
|
||||
{ HCI_DRV_OP_READ_INFO, "Read Info" },
|
||||
};
|
||||
|
||||
static int btintel_pcie_hci_drv_read_info(struct hci_dev *hdev, void *data,
|
||||
u16 data_len)
|
||||
{
|
||||
struct hci_drv_rp_read_info *rp;
|
||||
size_t rp_size;
|
||||
int err, i;
|
||||
u16 opcode, num_supported_commands =
|
||||
ARRAY_SIZE(btintel_pcie_hci_drv_supported_commands);
|
||||
|
||||
rp_size = sizeof(*rp) + num_supported_commands * 2;
|
||||
|
||||
rp = kmalloc(rp_size, GFP_KERNEL);
|
||||
if (!rp)
|
||||
return -ENOMEM;
|
||||
|
||||
strscpy_pad(rp->driver_name, KBUILD_MODNAME);
|
||||
|
||||
rp->num_supported_commands = cpu_to_le16(num_supported_commands);
|
||||
for (i = 0; i < num_supported_commands; i++) {
|
||||
opcode = btintel_pcie_hci_drv_supported_commands[i].opcode;
|
||||
bt_dev_dbg(hdev,
|
||||
"Supported HCI Drv command (0x%02x|0x%04x): %s",
|
||||
hci_opcode_ogf(opcode),
|
||||
hci_opcode_ocf(opcode),
|
||||
btintel_pcie_hci_drv_supported_commands[i].desc);
|
||||
rp->supported_commands[i] = cpu_to_le16(opcode);
|
||||
}
|
||||
|
||||
err = hci_drv_cmd_complete(hdev, HCI_DRV_OP_READ_INFO,
|
||||
HCI_DRV_STATUS_SUCCESS,
|
||||
rp, rp_size);
|
||||
|
||||
kfree(rp);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct hci_drv_handler btintel_pcie_hci_drv_common_handlers[] = {
|
||||
{ btintel_pcie_hci_drv_read_info, HCI_DRV_READ_INFO_SIZE },
|
||||
};
|
||||
|
||||
static const struct hci_drv_handler btintel_pcie_hci_drv_specific_handlers[] = {};
|
||||
|
||||
static struct hci_drv btintel_pcie_hci_drv = {
|
||||
.common_handler_count = ARRAY_SIZE(btintel_pcie_hci_drv_common_handlers),
|
||||
.common_handlers = btintel_pcie_hci_drv_common_handlers,
|
||||
.specific_handler_count = ARRAY_SIZE(btintel_pcie_hci_drv_specific_handlers),
|
||||
.specific_handlers = btintel_pcie_hci_drv_specific_handlers,
|
||||
};
|
||||
|
||||
static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
|
||||
{
|
||||
int err;
|
||||
|
|
@ -2381,6 +2444,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
|
|||
hdev->set_bdaddr = btintel_set_bdaddr;
|
||||
hdev->reset = btintel_pcie_reset;
|
||||
hdev->wakeup = btintel_pcie_wakeup;
|
||||
hdev->hci_drv = &btintel_pcie_hci_drv;
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
|
|
@ -2519,6 +2583,48 @@ static void btintel_pcie_coredump(struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate)
|
||||
{
|
||||
int retry = 0, status;
|
||||
u32 dx_intr_timeout_ms = 200;
|
||||
|
||||
do {
|
||||
data->gp0_received = false;
|
||||
|
||||
btintel_pcie_wr_sleep_cntrl(data, dxstate);
|
||||
|
||||
status = wait_event_timeout(data->gp0_wait_q, data->gp0_received,
|
||||
msecs_to_jiffies(dx_intr_timeout_ms));
|
||||
|
||||
if (status)
|
||||
return 0;
|
||||
|
||||
bt_dev_warn(data->hdev,
|
||||
"Timeout (%u ms) on alive interrupt for D%d entry, retry count %d",
|
||||
dx_intr_timeout_ms, dxstate, retry);
|
||||
|
||||
/* clear gp0 cause */
|
||||
btintel_pcie_clr_reg_bits(data,
|
||||
BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES,
|
||||
BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0);
|
||||
|
||||
/* A hardware bug may cause the alive interrupt to be missed.
|
||||
* Check if the controller reached the expected state and retry
|
||||
* the operation only if it hasn't.
|
||||
*/
|
||||
if (dxstate == BTINTEL_PCIE_STATE_D0) {
|
||||
if (btintel_pcie_in_d0(data))
|
||||
return 0;
|
||||
} else {
|
||||
if (btintel_pcie_in_d3(data))
|
||||
return 0;
|
||||
}
|
||||
|
||||
} while (++retry < BTINTEL_PCIE_DX_TRANSITION_MAX_RETRIES);
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
|
|
@ -2532,26 +2638,20 @@ static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg)
|
|||
dxstate = (mesg.event == PM_EVENT_SUSPEND ?
|
||||
BTINTEL_PCIE_STATE_D3_HOT : BTINTEL_PCIE_STATE_D3_COLD);
|
||||
|
||||
data->gp0_received = false;
|
||||
data->pm_sx_event = mesg.event;
|
||||
|
||||
start = ktime_get();
|
||||
|
||||
/* Refer: 6.4.11.7 -> Platform power management */
|
||||
btintel_pcie_wr_sleep_cntrl(data, dxstate);
|
||||
err = wait_event_timeout(data->gp0_wait_q, data->gp0_received,
|
||||
msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
|
||||
if (err == 0) {
|
||||
bt_dev_err(data->hdev,
|
||||
"Timeout (%u ms) on alive interrupt for D3 entry",
|
||||
BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
|
||||
return -EBUSY;
|
||||
}
|
||||
err = btintel_pcie_set_dxstate(data, dxstate);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bt_dev_dbg(data->hdev,
|
||||
"device entered into d3 state from d0 in %lld us",
|
||||
ktime_to_us(ktime_get() - start));
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int btintel_pcie_suspend(struct device *dev)
|
||||
|
|
@ -2581,21 +2681,50 @@ static int btintel_pcie_resume(struct device *dev)
|
|||
|
||||
start = ktime_get();
|
||||
|
||||
/* Refer: 6.4.11.7 -> Platform power management */
|
||||
btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0);
|
||||
err = wait_event_timeout(data->gp0_wait_q, data->gp0_received,
|
||||
msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
|
||||
if (err == 0) {
|
||||
bt_dev_err(data->hdev,
|
||||
"Timeout (%u ms) on alive interrupt for D0 entry",
|
||||
BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
|
||||
return -EBUSY;
|
||||
/* When the system enters S4 (hibernate) mode, bluetooth device loses
|
||||
* power, which results in the erasure of its loaded firmware.
|
||||
* Consequently, function level reset (flr) is required on system
|
||||
* resume to bring the controller back into an operational state by
|
||||
* initiating a new firmware download.
|
||||
*/
|
||||
|
||||
if (data->pm_sx_event == PM_EVENT_FREEZE ||
|
||||
data->pm_sx_event == PM_EVENT_HIBERNATE) {
|
||||
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
|
||||
btintel_pcie_reset(data->hdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Refer: 6.4.11.7 -> Platform power management */
|
||||
err = btintel_pcie_set_dxstate(data, BTINTEL_PCIE_STATE_D0);
|
||||
|
||||
if (err == 0) {
|
||||
bt_dev_dbg(data->hdev,
|
||||
"device entered into d0 state from d3 in %lld us",
|
||||
ktime_to_us(ktime_get() - start));
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Trigger function level reset if the controller is in error
|
||||
* state during resume() to bring back the controller to
|
||||
* operational mode
|
||||
*/
|
||||
|
||||
data->boot_stage_cache = btintel_pcie_rd_reg32(data,
|
||||
BTINTEL_PCIE_CSR_BOOT_STAGE_REG);
|
||||
if (btintel_pcie_in_error(data) ||
|
||||
btintel_pcie_in_device_halt(data)) {
|
||||
bt_dev_err(data->hdev, "Controller in error state for D0 entry");
|
||||
if (!test_and_set_bit(BTINTEL_PCIE_COREDUMP_INPROGRESS,
|
||||
&data->flags)) {
|
||||
data->dmp_hdr.trigger_reason =
|
||||
BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT;
|
||||
queue_work(data->workqueue, &data->rx_work);
|
||||
}
|
||||
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
|
||||
btintel_pcie_reset(data->hdev);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops btintel_pcie_pm_ops = {
|
||||
|
|
|
|||
|
|
@ -158,6 +158,8 @@ enum msix_mbox_int_causes {
|
|||
/* Default interrupt timeout in msec */
|
||||
#define BTINTEL_DEFAULT_INTR_TIMEOUT_MS 3000
|
||||
|
||||
#define BTINTEL_PCIE_DX_TRANSITION_MAX_RETRIES 3
|
||||
|
||||
/* The number of descriptors in TX queues */
|
||||
#define BTINTEL_PCIE_TX_DESCS_COUNT 32
|
||||
|
||||
|
|
@ -464,6 +466,7 @@ struct btintel_pcie_dump_header {
|
|||
* @txq: TX Queue struct
|
||||
* @rxq: RX Queue struct
|
||||
* @alive_intr_ctxt: Alive interrupt context
|
||||
* @pm_sx_event: PM event on which system got suspended
|
||||
*/
|
||||
struct btintel_pcie_data {
|
||||
struct pci_dev *pdev;
|
||||
|
|
@ -513,6 +516,7 @@ struct btintel_pcie_data {
|
|||
u32 alive_intr_ctxt;
|
||||
struct btintel_pcie_dbgc dbgc;
|
||||
struct btintel_pcie_dump_header dmp_hdr;
|
||||
u8 pm_sx_event;
|
||||
};
|
||||
|
||||
static inline u32 btintel_pcie_rd_reg32(struct btintel_pcie_data *data,
|
||||
|
|
|
|||
|
|
@ -615,7 +615,6 @@ static void btmtksdio_txrx_work(struct work_struct *work)
|
|||
|
||||
sdio_release_host(bdev->func);
|
||||
|
||||
pm_runtime_mark_last_busy(bdev->dev);
|
||||
pm_runtime_put_autosuspend(bdev->dev);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ enum btrtl_chip_id {
|
|||
CHIP_ID_8851B = 36,
|
||||
CHIP_ID_8922A = 44,
|
||||
CHIP_ID_8852BT = 47,
|
||||
CHIP_ID_8761C = 51,
|
||||
};
|
||||
|
||||
struct id_table {
|
||||
|
|
@ -230,6 +231,14 @@ static const struct id_table ic_id_table[] = {
|
|||
.cfg_name = "rtl_bt/rtl8761bu_config",
|
||||
.hw_info = "rtl8761bu" },
|
||||
|
||||
/* 8761CU */
|
||||
{ IC_INFO(RTL_ROM_LMP_8761A, 0x0e, 0, HCI_USB),
|
||||
.config_needed = false,
|
||||
.has_rom_version = true,
|
||||
.fw_name = "rtl_bt/rtl8761cu_fw",
|
||||
.cfg_name = "rtl_bt/rtl8761cu_config",
|
||||
.hw_info = "rtl8761cu" },
|
||||
|
||||
/* 8822C with UART interface */
|
||||
{ IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART),
|
||||
.config_needed = true,
|
||||
|
|
@ -344,7 +353,8 @@ static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev,
|
|||
(ic_id_table[i].hci_rev != hci_rev))
|
||||
continue;
|
||||
if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIVER) &&
|
||||
(ic_id_table[i].hci_ver != hci_ver))
|
||||
(ic_id_table[i].hci_ver != hci_ver) &&
|
||||
(ic_id_table[i].hci_ver != 0))
|
||||
continue;
|
||||
if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIBUS) &&
|
||||
(ic_id_table[i].hci_bus != hci_bus))
|
||||
|
|
@ -662,6 +672,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
|||
{ RTL_ROM_LMP_8851B, 36 }, /* 8851B */
|
||||
{ RTL_ROM_LMP_8922A, 44 }, /* 8922A */
|
||||
{ RTL_ROM_LMP_8852A, 47 }, /* 8852BT */
|
||||
{ RTL_ROM_LMP_8761A, 51 }, /* 8761C */
|
||||
};
|
||||
|
||||
if (btrtl_dev->fw_len <= 8)
|
||||
|
|
@ -1305,6 +1316,7 @@ void btrtl_set_quirks(struct hci_dev *hdev, struct btrtl_device_info *btrtl_dev)
|
|||
case CHIP_ID_8851B:
|
||||
case CHIP_ID_8922A:
|
||||
case CHIP_ID_8852BT:
|
||||
case CHIP_ID_8761C:
|
||||
hci_set_quirk(hdev, HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED);
|
||||
|
||||
/* RTL8852C needs to transmit mSBC data continuously without
|
||||
|
|
@ -1524,6 +1536,8 @@ MODULE_FIRMWARE("rtl_bt/rtl8761b_fw.bin");
|
|||
MODULE_FIRMWARE("rtl_bt/rtl8761b_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8761bu_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8761bu_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8761cu_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8761cu_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8821a_fw.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8821a_config.bin");
|
||||
MODULE_FIRMWARE("rtl_bt/rtl8821c_fw.bin");
|
||||
|
|
|
|||
|
|
@ -504,6 +504,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
/* Realtek 8821CE Bluetooth devices */
|
||||
{ USB_DEVICE(0x13d3, 0x3529), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3533), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Realtek 8822CE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0xb00c), .driver_info = BTUSB_REALTEK |
|
||||
|
|
@ -585,6 +587,12 @@ static const struct usb_device_id quirks_table[] = {
|
|||
/* Realtek 8852BT/8852BE-VT Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0x8520), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe12f), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3618), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3619), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Realtek 8922AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0x8922), .driver_info = BTUSB_REALTEK |
|
||||
|
|
@ -621,6 +629,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
/* Additional MediaTek MT7920 Bluetooth devices */
|
||||
{ USB_DEVICE(0x0489, 0xe134), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe135), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3620), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3621), .driver_info = BTUSB_MEDIATEK |
|
||||
|
|
@ -685,6 +695,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe153), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe170), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04ca, 0x3804), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04ca, 0x38e4), .driver_info = BTUSB_MEDIATEK |
|
||||
|
|
@ -781,6 +793,8 @@ static const struct usb_device_id quirks_table[] = {
|
|||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x2b89, 0x8761), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x2b89, 0x6275), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Additional Realtek 8821AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0b05, 0x17dc), .driver_info = BTUSB_REALTEK },
|
||||
|
|
@ -1131,6 +1145,24 @@ static void btusb_qca_reset(struct hci_dev *hdev)
|
|||
btusb_reset(hdev);
|
||||
}
|
||||
|
||||
static u8 btusb_classify_qca_pkt_type(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
/* Some Qualcomm controllers, e.g., QCNFA765 with WCN6855 chip, send debug
|
||||
* packets as ACL frames with connection handle 0x2EDC. These are not real
|
||||
* ACL packets and should be reclassified as HCI_DIAG_PKT to prevent
|
||||
* "ACL packet for unknown connection handle 3804" errors.
|
||||
*/
|
||||
if (skb->len >= 2) {
|
||||
u16 handle = get_unaligned_le16(skb->data);
|
||||
|
||||
if (handle == 0x2EDC)
|
||||
return HCI_DIAG_PKT;
|
||||
}
|
||||
|
||||
/* Use default packet type for other packets */
|
||||
return hci_skb_pkt_type(skb);
|
||||
}
|
||||
|
||||
static inline void btusb_free_frags(struct btusb_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
@ -2808,6 +2840,19 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
|
|||
btusb_stop_traffic(data);
|
||||
usb_kill_anchored_urbs(&data->tx_anchor);
|
||||
|
||||
/* Toggle the hard reset line. The MediaTek device is going to
|
||||
* yank itself off the USB and then replug. The cleanup is handled
|
||||
* correctly on the way out (standard USB disconnect), and the new
|
||||
* device is detected cleanly and bound to the driver again like
|
||||
* it should be.
|
||||
*/
|
||||
if (data->reset_gpio) {
|
||||
gpiod_set_value_cansleep(data->reset_gpio, 1);
|
||||
msleep(200);
|
||||
gpiod_set_value_cansleep(data->reset_gpio, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = btmtk_usb_subsys_reset(hdev, btmtk_data->dev_id);
|
||||
|
||||
usb_queue_reset_device(data->intf);
|
||||
|
|
@ -3261,6 +3306,7 @@ static const struct qca_device_info qca_devices_table[] = {
|
|||
|
||||
static const struct qca_custom_firmware qca_custom_btfws[] = {
|
||||
{ 0x00130201, 0x030A, "QCA2066" },
|
||||
{ 0x00130201, 0x030B, "QCA2066" },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
@ -4226,6 +4272,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
data->recv_acl = btusb_recv_acl_qca;
|
||||
hci_devcd_register(hdev, btusb_coredump_qca, btusb_dump_hdr_qca, NULL);
|
||||
data->setup_on_usb = btusb_setup_qca;
|
||||
hdev->classify_pkt_type = btusb_classify_qca_pkt_type;
|
||||
hdev->shutdown = btusb_shutdown_qca;
|
||||
hdev->set_bdaddr = btusb_set_bdaddr_wcn6855;
|
||||
hdev->reset = btusb_qca_reset;
|
||||
|
|
|
|||
|
|
@ -326,7 +326,6 @@ static irqreturn_t bcm_host_wake(int irq, void *data)
|
|||
bt_dev_dbg(bdev, "Host wake IRQ");
|
||||
|
||||
pm_runtime_get(bdev->dev);
|
||||
pm_runtime_mark_last_busy(bdev->dev);
|
||||
pm_runtime_put_autosuspend(bdev->dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -710,7 +709,6 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
|
|||
mutex_lock(&bcm_device_lock);
|
||||
if (bcm->dev && bcm_device_exists(bcm->dev)) {
|
||||
pm_runtime_get(bcm->dev->dev);
|
||||
pm_runtime_mark_last_busy(bcm->dev->dev);
|
||||
pm_runtime_put_autosuspend(bcm->dev->dev);
|
||||
}
|
||||
mutex_unlock(&bcm_device_lock);
|
||||
|
|
@ -748,10 +746,8 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
|
|||
|
||||
skb = skb_dequeue(&bcm->txq);
|
||||
|
||||
if (bdev) {
|
||||
pm_runtime_mark_last_busy(bdev->dev);
|
||||
if (bdev)
|
||||
pm_runtime_put_autosuspend(bdev->dev);
|
||||
}
|
||||
|
||||
mutex_unlock(&bcm_device_lock);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -58,6 +60,7 @@ enum {
|
|||
H5_TX_ACK_REQ, /* Pending ack to send */
|
||||
H5_WAKEUP_DISABLE, /* Device cannot wake host */
|
||||
H5_HW_FLOW_CONTROL, /* Use HW flow control */
|
||||
H5_CRC, /* Use CRC */
|
||||
};
|
||||
|
||||
struct h5 {
|
||||
|
|
@ -141,8 +144,8 @@ static void h5_link_control(struct hci_uart *hu, const void *data, size_t len)
|
|||
|
||||
static u8 h5_cfg_field(struct h5 *h5)
|
||||
{
|
||||
/* Sliding window size (first 3 bits) */
|
||||
return h5->tx_win & 0x07;
|
||||
/* Sliding window size (first 3 bits) and CRC request (fifth bit). */
|
||||
return (h5->tx_win & 0x07) | 0x10;
|
||||
}
|
||||
|
||||
static void h5_timed_event(struct timer_list *t)
|
||||
|
|
@ -213,7 +216,6 @@ static void h5_peer_reset(struct hci_uart *hu)
|
|||
static int h5_open(struct hci_uart *hu)
|
||||
{
|
||||
struct h5 *h5;
|
||||
const unsigned char sync[] = { 0x01, 0x7e };
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
|
|
@ -243,9 +245,11 @@ static int h5_open(struct hci_uart *hu)
|
|||
|
||||
set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags);
|
||||
|
||||
/* Send initial sync request */
|
||||
h5_link_control(hu, sync, sizeof(sync));
|
||||
mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT);
|
||||
/*
|
||||
* Wait one jiffy because the UART layer won't set HCI_UART_PROTO_READY,
|
||||
* which allows us to send link packets, until this function returns.
|
||||
*/
|
||||
mod_timer(&h5->timer, jiffies + 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -360,8 +364,10 @@ static void h5_handle_internal_rx(struct hci_uart *hu)
|
|||
h5_link_control(hu, conf_rsp, 2);
|
||||
h5_link_control(hu, conf_req, 3);
|
||||
} else if (memcmp(data, conf_rsp, 2) == 0) {
|
||||
if (H5_HDR_LEN(hdr) > 2)
|
||||
if (H5_HDR_LEN(hdr) > 2) {
|
||||
h5->tx_win = (data[2] & 0x07);
|
||||
assign_bit(H5_CRC, &h5->flags, data[2] & 0x10);
|
||||
}
|
||||
BT_DBG("Three-wire init complete. tx_win %u", h5->tx_win);
|
||||
h5->state = H5_ACTIVE;
|
||||
hci_uart_init_ready(hu);
|
||||
|
|
@ -425,7 +431,24 @@ static void h5_complete_rx_pkt(struct hci_uart *hu)
|
|||
|
||||
static int h5_rx_crc(struct hci_uart *hu, unsigned char c)
|
||||
{
|
||||
struct h5 *h5 = hu->priv;
|
||||
const unsigned char *hdr = h5->rx_skb->data;
|
||||
u16 crc;
|
||||
__be16 crc_be;
|
||||
|
||||
crc = crc_ccitt(0xffff, hdr, 4 + H5_HDR_LEN(hdr));
|
||||
crc = bitrev16(crc);
|
||||
|
||||
crc_be = cpu_to_be16(crc);
|
||||
|
||||
if (memcmp(&crc_be, hdr + 4 + H5_HDR_LEN(hdr), 2) != 0) {
|
||||
bt_dev_err(hu->hdev, "Received packet with invalid CRC");
|
||||
h5_reset_rx(h5);
|
||||
} else {
|
||||
/* Remove CRC bytes */
|
||||
skb_trim(h5->rx_skb, 4 + H5_HDR_LEN(hdr));
|
||||
h5_complete_rx_pkt(hu);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -556,6 +579,7 @@ static void h5_reset_rx(struct h5 *h5)
|
|||
h5->rx_func = h5_rx_delimiter;
|
||||
h5->rx_pending = 0;
|
||||
clear_bit(H5_RX_ESC, &h5->flags);
|
||||
clear_bit(H5_CRC, &h5->flags);
|
||||
}
|
||||
|
||||
static int h5_recv(struct hci_uart *hu, const void *data, int count)
|
||||
|
|
@ -592,7 +616,6 @@ static int h5_recv(struct hci_uart *hu, const void *data, int count)
|
|||
|
||||
if (hu->serdev) {
|
||||
pm_runtime_get(&hu->serdev->dev);
|
||||
pm_runtime_mark_last_busy(&hu->serdev->dev);
|
||||
pm_runtime_put_autosuspend(&hu->serdev->dev);
|
||||
}
|
||||
|
||||
|
|
@ -634,7 +657,6 @@ static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
|
||||
if (hu->serdev) {
|
||||
pm_runtime_get_sync(&hu->serdev->dev);
|
||||
pm_runtime_mark_last_busy(&hu->serdev->dev);
|
||||
pm_runtime_put_autosuspend(&hu->serdev->dev);
|
||||
}
|
||||
|
||||
|
|
@ -686,6 +708,7 @@ static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type,
|
|||
struct h5 *h5 = hu->priv;
|
||||
struct sk_buff *nskb;
|
||||
u8 hdr[4];
|
||||
u16 crc;
|
||||
int i;
|
||||
|
||||
if (!valid_packet_type(pkt_type)) {
|
||||
|
|
@ -713,6 +736,7 @@ static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type,
|
|||
/* Reliable packet? */
|
||||
if (pkt_type == HCI_ACLDATA_PKT || pkt_type == HCI_COMMAND_PKT) {
|
||||
hdr[0] |= 1 << 7;
|
||||
hdr[0] |= (test_bit(H5_CRC, &h5->flags) && 1) << 6;
|
||||
hdr[0] |= h5->tx_seq;
|
||||
h5->tx_seq = (h5->tx_seq + 1) % 8;
|
||||
}
|
||||
|
|
@ -732,6 +756,15 @@ static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type,
|
|||
for (i = 0; i < len; i++)
|
||||
h5_slip_one_byte(nskb, data[i]);
|
||||
|
||||
if (H5_HDR_CRC(hdr)) {
|
||||
crc = crc_ccitt(0xffff, hdr, 4);
|
||||
crc = crc_ccitt(crc, data, len);
|
||||
crc = bitrev16(crc);
|
||||
|
||||
h5_slip_one_byte(nskb, (crc >> 8) & 0xff);
|
||||
h5_slip_one_byte(nskb, crc & 0xff);
|
||||
}
|
||||
|
||||
h5_slip_delim(nskb);
|
||||
|
||||
return nskb;
|
||||
|
|
|
|||
|
|
@ -280,7 +280,6 @@ static irqreturn_t intel_irq(int irq, void *dev_id)
|
|||
|
||||
/* Host/Controller are now LPM resumed, trigger a new delayed suspend */
|
||||
pm_runtime_get(&idev->pdev->dev);
|
||||
pm_runtime_mark_last_busy(&idev->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&idev->pdev->dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -371,7 +370,6 @@ static void intel_busy_work(struct work_struct *work)
|
|||
list_for_each_entry(idev, &intel_device_list, list) {
|
||||
if (intel->hu->tty->dev->parent == idev->pdev->dev.parent) {
|
||||
pm_runtime_get(&idev->pdev->dev);
|
||||
pm_runtime_mark_last_busy(&idev->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&idev->pdev->dev);
|
||||
break;
|
||||
}
|
||||
|
|
@ -1003,7 +1001,6 @@ static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
list_for_each_entry(idev, &intel_device_list, list) {
|
||||
if (hu->tty->dev->parent == idev->pdev->dev.parent) {
|
||||
pm_runtime_get_sync(&idev->pdev->dev);
|
||||
pm_runtime_mark_last_busy(&idev->pdev->dev);
|
||||
pm_runtime_put_autosuspend(&idev->pdev->dev);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -647,10 +647,13 @@ enum {
|
|||
#define HCI_LE_EXT_ADV 0x10
|
||||
#define HCI_LE_PERIODIC_ADV 0x20
|
||||
#define HCI_LE_CHAN_SEL_ALG2 0x40
|
||||
#define HCI_LE_PAST_SENDER 0x01
|
||||
#define HCI_LE_PAST_RECEIVER 0x02
|
||||
#define HCI_LE_CIS_CENTRAL 0x10
|
||||
#define HCI_LE_CIS_PERIPHERAL 0x20
|
||||
#define HCI_LE_ISO_BROADCASTER 0x40
|
||||
#define HCI_LE_ISO_SYNC_RECEIVER 0x80
|
||||
#define HCI_LE_LL_EXT_FEATURE 0x80
|
||||
|
||||
/* Connection modes */
|
||||
#define HCI_CM_ACTIVE 0x0000
|
||||
|
|
@ -2068,6 +2071,44 @@ struct hci_cp_le_set_privacy_mode {
|
|||
__u8 mode;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_PAST 0x205a
|
||||
struct hci_cp_le_past {
|
||||
__le16 handle;
|
||||
__le16 service_data;
|
||||
__le16 sync_handle;
|
||||
} __packed;
|
||||
|
||||
struct hci_rp_le_past {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_PAST_SET_INFO 0x205b
|
||||
struct hci_cp_le_past_set_info {
|
||||
__le16 handle;
|
||||
__le16 service_data;
|
||||
__u8 adv_handle;
|
||||
} __packed;
|
||||
|
||||
struct hci_rp_le_past_set_info {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_PAST_PARAMS 0x205c
|
||||
struct hci_cp_le_past_params {
|
||||
__le16 handle;
|
||||
__u8 mode;
|
||||
__le16 skip;
|
||||
__le16 sync_timeout;
|
||||
__u8 cte_type;
|
||||
} __packed;
|
||||
|
||||
struct hci_rp_le_past_params {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_READ_BUFFER_SIZE_V2 0x2060
|
||||
struct hci_rp_le_read_buffer_size_v2 {
|
||||
__u8 status;
|
||||
|
|
@ -2215,6 +2256,19 @@ struct hci_cp_le_set_host_feature {
|
|||
__u8 bit_value;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_READ_ALL_LOCAL_FEATURES 0x2087
|
||||
struct hci_rp_le_read_all_local_features {
|
||||
__u8 status;
|
||||
__u8 page;
|
||||
__u8 features[248];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_READ_ALL_REMOTE_FEATURES 0x2088
|
||||
struct hci_cp_le_read_all_remote_features {
|
||||
__le16 handle;
|
||||
__u8 pages;
|
||||
} __packed;
|
||||
|
||||
/* ---- HCI Events ---- */
|
||||
struct hci_ev_status {
|
||||
__u8 status;
|
||||
|
|
@ -2800,6 +2854,20 @@ struct hci_evt_le_ext_adv_set_term {
|
|||
__u8 num_evts;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LE_PAST_RECEIVED 0x18
|
||||
struct hci_ev_le_past_received {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
__le16 service_data;
|
||||
__le16 sync_handle;
|
||||
__u8 sid;
|
||||
__u8 bdaddr_type;
|
||||
bdaddr_t bdaddr;
|
||||
__u8 phy;
|
||||
__le16 interval;
|
||||
__u8 clock_accuracy;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EVT_LE_CIS_ESTABLISHED 0x19
|
||||
struct hci_evt_le_cis_established {
|
||||
__u8 status;
|
||||
|
|
@ -2883,6 +2951,15 @@ struct hci_evt_le_big_info_adv_report {
|
|||
__u8 encryption;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE 0x2b
|
||||
struct hci_evt_le_read_all_remote_features_complete {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
__u8 max_pages;
|
||||
__u8 valid_pages;
|
||||
__u8 features[248];
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_VENDOR 0xff
|
||||
|
||||
/* Internal events generated by Bluetooth stack */
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ enum hci_conn_flags {
|
|||
HCI_CONN_FLAG_REMOTE_WAKEUP = BIT(0),
|
||||
HCI_CONN_FLAG_DEVICE_PRIVACY = BIT(1),
|
||||
HCI_CONN_FLAG_ADDRESS_RESOLUTION = BIT(2),
|
||||
HCI_CONN_FLAG_PAST = BIT(3),
|
||||
};
|
||||
typedef u8 hci_conn_flags_t;
|
||||
|
||||
|
|
@ -377,7 +378,7 @@ struct hci_dev {
|
|||
__u8 minor_class;
|
||||
__u8 max_page;
|
||||
__u8 features[HCI_MAX_PAGES][8];
|
||||
__u8 le_features[8];
|
||||
__u8 le_features[248];
|
||||
__u8 le_accept_list_size;
|
||||
__u8 le_resolv_list_size;
|
||||
__u8 le_num_of_adv_sets;
|
||||
|
|
@ -701,6 +702,7 @@ struct hci_conn {
|
|||
__u8 attempt;
|
||||
__u8 dev_class[3];
|
||||
__u8 features[HCI_MAX_PAGES][8];
|
||||
__u8 le_features[248];
|
||||
__u16 pkt_type;
|
||||
__u16 link_policy;
|
||||
__u8 key_type;
|
||||
|
|
@ -1570,9 +1572,9 @@ int hci_le_create_cis_pending(struct hci_dev *hdev);
|
|||
int hci_conn_check_create_cis(struct hci_conn *conn);
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
u8 role, u16 handle);
|
||||
u8 dst_type, u8 role, u16 handle);
|
||||
struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
|
||||
bdaddr_t *dst, u8 role);
|
||||
bdaddr_t *dst, u8 dst_type, u8 role);
|
||||
void hci_conn_del(struct hci_conn *conn);
|
||||
void hci_conn_hash_flush(struct hci_dev *hdev);
|
||||
|
||||
|
|
@ -1601,6 +1603,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
||||
struct bt_iso_qos *qos,
|
||||
__u8 base_len, __u8 *base, u16 timeout);
|
||||
int hci_past_bis(struct hci_conn *conn, bdaddr_t *dst, __u8 dst_type);
|
||||
struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
__u8 dst_type, struct bt_iso_qos *qos,
|
||||
u16 timeout);
|
||||
|
|
@ -2053,6 +2056,20 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
|
|||
#define sync_recv_capable(dev) \
|
||||
((dev)->le_features[3] & HCI_LE_ISO_SYNC_RECEIVER)
|
||||
#define sync_recv_enabled(dev) (le_enabled(dev) && sync_recv_capable(dev))
|
||||
#define past_sender_capable(dev) \
|
||||
((dev)->le_features[3] & HCI_LE_PAST_SENDER)
|
||||
#define past_receiver_capable(dev) \
|
||||
((dev)->le_features[3] & HCI_LE_PAST_RECEIVER)
|
||||
#define past_capable(dev) \
|
||||
(past_sender_capable(dev) || past_receiver_capable(dev))
|
||||
#define past_sender_enabled(dev) \
|
||||
(le_enabled(dev) && past_sender_capable(dev))
|
||||
#define past_receiver_enabled(dev) \
|
||||
(le_enabled(dev) && past_receiver_capable(dev))
|
||||
#define past_enabled(dev) \
|
||||
(past_sender_enabled(dev) || past_receiver_enabled(dev))
|
||||
#define ll_ext_feature_capable(dev) \
|
||||
((dev)->le_features[7] & HCI_LE_LL_EXT_FEATURE)
|
||||
|
||||
#define mws_transport_config_capable(dev) (((dev)->commands[30] & 0x08) && \
|
||||
(!hci_test_quirk((dev), HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG)))
|
||||
|
|
|
|||
|
|
@ -188,3 +188,6 @@ int hci_le_conn_update_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
|||
|
||||
int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn);
|
||||
int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn);
|
||||
int hci_past_sync(struct hci_conn *conn, struct hci_conn *le);
|
||||
|
||||
int hci_le_read_remote_features(struct hci_conn *conn);
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ struct mgmt_rp_read_index_list {
|
|||
#define MGMT_SETTING_ISO_BROADCASTER BIT(20)
|
||||
#define MGMT_SETTING_ISO_SYNC_RECEIVER BIT(21)
|
||||
#define MGMT_SETTING_LL_PRIVACY BIT(22)
|
||||
#define MGMT_SETTING_PAST_SENDER BIT(23)
|
||||
#define MGMT_SETTING_PAST_RECEIVER BIT(24)
|
||||
|
||||
#define MGMT_OP_READ_INFO 0x0004
|
||||
#define MGMT_READ_INFO_SIZE 0
|
||||
|
|
|
|||
|
|
@ -922,10 +922,12 @@ static int hci_conn_hash_alloc_unset(struct hci_dev *hdev)
|
|||
U16_MAX, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
|
||||
bdaddr_t *dst, u8 dst_type,
|
||||
u8 role, u16 handle)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct smp_irk *irk = NULL;
|
||||
|
||||
switch (type) {
|
||||
case ACL_LINK:
|
||||
|
|
@ -937,12 +939,14 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
|||
case PA_LINK:
|
||||
if (!hdev->iso_mtu)
|
||||
return ERR_PTR(-ECONNREFUSED);
|
||||
irk = hci_get_irk(hdev, dst, dst_type);
|
||||
break;
|
||||
case LE_LINK:
|
||||
if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU)
|
||||
return ERR_PTR(-ECONNREFUSED);
|
||||
if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU)
|
||||
return ERR_PTR(-ECONNREFUSED);
|
||||
irk = hci_get_irk(hdev, dst, dst_type);
|
||||
break;
|
||||
case SCO_LINK:
|
||||
case ESCO_LINK:
|
||||
|
|
@ -960,7 +964,15 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
|||
if (!conn)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* If and IRK exists use its identity address */
|
||||
if (!irk) {
|
||||
bacpy(&conn->dst, dst);
|
||||
conn->dst_type = dst_type;
|
||||
} else {
|
||||
bacpy(&conn->dst, &irk->bdaddr);
|
||||
conn->dst_type = irk->addr_type;
|
||||
}
|
||||
|
||||
bacpy(&conn->src, &hdev->bdaddr);
|
||||
conn->handle = handle;
|
||||
conn->hdev = hdev;
|
||||
|
|
@ -1059,7 +1071,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
|||
}
|
||||
|
||||
struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
|
||||
bdaddr_t *dst, u8 role)
|
||||
bdaddr_t *dst, u8 dst_type, u8 role)
|
||||
{
|
||||
int handle;
|
||||
|
||||
|
|
@ -1069,16 +1081,16 @@ struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
|
|||
if (unlikely(handle < 0))
|
||||
return ERR_PTR(-ECONNREFUSED);
|
||||
|
||||
return __hci_conn_add(hdev, type, dst, role, handle);
|
||||
return __hci_conn_add(hdev, type, dst, dst_type, role, handle);
|
||||
}
|
||||
|
||||
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
||||
u8 role, u16 handle)
|
||||
u8 dst_type, u8 role, u16 handle)
|
||||
{
|
||||
if (handle > HCI_CONN_HANDLE_MAX)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return __hci_conn_add(hdev, type, dst, role, handle);
|
||||
return __hci_conn_add(hdev, type, dst, dst_type, role, handle);
|
||||
}
|
||||
|
||||
static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
|
||||
|
|
@ -1410,14 +1422,13 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
if (conn) {
|
||||
bacpy(&conn->dst, dst);
|
||||
} else {
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, dst, role);
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, dst, dst_type, role);
|
||||
if (IS_ERR(conn))
|
||||
return conn;
|
||||
hci_conn_hold(conn);
|
||||
conn->pending_sec_level = sec_level;
|
||||
}
|
||||
|
||||
conn->dst_type = dst_type;
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->conn_timeout = conn_timeout;
|
||||
conn->le_adv_phy = phy;
|
||||
|
|
@ -1587,7 +1598,7 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
memcmp(conn->le_per_adv_data, base, base_len)))
|
||||
return ERR_PTR(-EADDRINUSE);
|
||||
|
||||
conn = hci_conn_add_unset(hdev, BIS_LINK, dst, HCI_ROLE_MASTER);
|
||||
conn = hci_conn_add_unset(hdev, BIS_LINK, dst, 0, HCI_ROLE_MASTER);
|
||||
if (IS_ERR(conn))
|
||||
return conn;
|
||||
|
||||
|
|
@ -1633,7 +1644,8 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
|
||||
BT_DBG("requesting refresh of dst_addr");
|
||||
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, dst, HCI_ROLE_MASTER);
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, dst, dst_type,
|
||||
HCI_ROLE_MASTER);
|
||||
if (IS_ERR(conn))
|
||||
return conn;
|
||||
|
||||
|
|
@ -1644,7 +1656,6 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
|
||||
conn->state = BT_CONNECT;
|
||||
set_bit(HCI_CONN_SCANNING, &conn->flags);
|
||||
conn->dst_type = dst_type;
|
||||
conn->sec_level = BT_SECURITY_LOW;
|
||||
conn->pending_sec_level = sec_level;
|
||||
conn->conn_timeout = conn_timeout;
|
||||
|
|
@ -1681,7 +1692,8 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
|
||||
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
|
||||
if (!acl) {
|
||||
acl = hci_conn_add_unset(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
|
||||
acl = hci_conn_add_unset(hdev, ACL_LINK, dst, 0,
|
||||
HCI_ROLE_MASTER);
|
||||
if (IS_ERR(acl))
|
||||
return acl;
|
||||
}
|
||||
|
|
@ -1750,7 +1762,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
|||
|
||||
sco = hci_conn_hash_lookup_ba(hdev, type, dst);
|
||||
if (!sco) {
|
||||
sco = hci_conn_add_unset(hdev, type, dst, HCI_ROLE_MASTER);
|
||||
sco = hci_conn_add_unset(hdev, type, dst, 0, HCI_ROLE_MASTER);
|
||||
if (IS_ERR(sco)) {
|
||||
hci_conn_drop(acl);
|
||||
return sco;
|
||||
|
|
@ -1942,7 +1954,7 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
cis = hci_conn_hash_lookup_cis(hdev, dst, dst_type, qos->ucast.cig,
|
||||
qos->ucast.cis);
|
||||
if (!cis) {
|
||||
cis = hci_conn_add_unset(hdev, CIS_LINK, dst,
|
||||
cis = hci_conn_add_unset(hdev, CIS_LINK, dst, dst_type,
|
||||
HCI_ROLE_MASTER);
|
||||
if (IS_ERR(cis))
|
||||
return cis;
|
||||
|
|
@ -2133,12 +2145,11 @@ struct hci_conn *hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst,
|
|||
|
||||
bt_dev_dbg(hdev, "dst %pMR type %d sid %d", dst, dst_type, sid);
|
||||
|
||||
conn = hci_conn_add_unset(hdev, PA_LINK, dst, HCI_ROLE_SLAVE);
|
||||
conn = hci_conn_add_unset(hdev, PA_LINK, dst, dst_type, HCI_ROLE_SLAVE);
|
||||
if (IS_ERR(conn))
|
||||
return conn;
|
||||
|
||||
conn->iso_qos = *qos;
|
||||
conn->dst_type = dst_type;
|
||||
conn->sid = sid;
|
||||
conn->state = BT_LISTEN;
|
||||
conn->conn_timeout = msecs_to_jiffies(qos->bcast.sync_timeout * 10);
|
||||
|
|
@ -2245,6 +2256,18 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
|||
return conn;
|
||||
}
|
||||
|
||||
int hci_past_bis(struct hci_conn *conn, bdaddr_t *dst, __u8 dst_type)
|
||||
{
|
||||
struct hci_conn *le;
|
||||
|
||||
/* Lookup existing LE connection to rebind to */
|
||||
le = hci_conn_hash_lookup_le(conn->hdev, dst, dst_type);
|
||||
if (!le)
|
||||
return -EINVAL;
|
||||
|
||||
return hci_past_sync(conn, le);
|
||||
}
|
||||
|
||||
static void bis_mark_per_adv(struct hci_conn *conn, void *data)
|
||||
{
|
||||
struct iso_list_data *d = data;
|
||||
|
|
|
|||
|
|
@ -2267,7 +2267,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
|
|||
} else {
|
||||
if (!conn) {
|
||||
conn = hci_conn_add_unset(hdev, ACL_LINK, &cp->bdaddr,
|
||||
HCI_ROLE_MASTER);
|
||||
0, HCI_ROLE_MASTER);
|
||||
if (IS_ERR(conn))
|
||||
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
|
||||
}
|
||||
|
|
@ -2886,12 +2886,8 @@ static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status)
|
|||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
|
||||
if (conn) {
|
||||
if (conn->state == BT_CONFIG) {
|
||||
if (conn && conn->state == BT_CONFIG)
|
||||
hci_connect_cfm(conn, status);
|
||||
hci_conn_drop(conn);
|
||||
}
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
|
@ -3123,7 +3119,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
|
|||
&ev->bdaddr,
|
||||
BDADDR_BREDR)) {
|
||||
conn = hci_conn_add_unset(hdev, ev->link_type,
|
||||
&ev->bdaddr, HCI_ROLE_SLAVE);
|
||||
&ev->bdaddr, 0,
|
||||
HCI_ROLE_SLAVE);
|
||||
if (IS_ERR(conn)) {
|
||||
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
|
||||
goto unlock;
|
||||
|
|
@ -3299,7 +3296,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
|
|||
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
|
||||
&ev->bdaddr);
|
||||
if (!conn) {
|
||||
conn = hci_conn_add_unset(hdev, ev->link_type, &ev->bdaddr,
|
||||
conn = hci_conn_add_unset(hdev, ev->link_type, &ev->bdaddr, 0,
|
||||
HCI_ROLE_SLAVE);
|
||||
if (IS_ERR(conn)) {
|
||||
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
|
||||
|
|
@ -3914,11 +3911,49 @@ static u8 hci_cc_le_setup_iso_path(struct hci_dev *hdev, void *data,
|
|||
return rp->status;
|
||||
}
|
||||
|
||||
static u8 hci_cc_le_read_all_local_features(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_le_read_all_local_features *rp = data;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
|
||||
|
||||
if (rp->status)
|
||||
return rp->status;
|
||||
|
||||
memcpy(hdev->le_features, rp->features, 248);
|
||||
|
||||
return rp->status;
|
||||
}
|
||||
|
||||
static void hci_cs_le_create_big(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", status);
|
||||
}
|
||||
|
||||
static void hci_cs_le_read_all_remote_features(struct hci_dev *hdev, u8 status)
|
||||
{
|
||||
struct hci_cp_le_read_remote_features *cp;
|
||||
struct hci_conn *conn;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", status);
|
||||
|
||||
if (!status)
|
||||
return;
|
||||
|
||||
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_READ_ALL_REMOTE_FEATURES);
|
||||
if (!cp)
|
||||
return;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
|
||||
if (conn && conn->state == BT_CONFIG)
|
||||
hci_connect_cfm(conn, status);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static u8 hci_cc_set_per_adv_param(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -4170,6 +4205,9 @@ static const struct hci_cc {
|
|||
sizeof(struct hci_rp_le_set_cig_params), HCI_MAX_EVENT_SIZE),
|
||||
HCI_CC(HCI_OP_LE_SETUP_ISO_PATH, hci_cc_le_setup_iso_path,
|
||||
sizeof(struct hci_rp_le_setup_iso_path)),
|
||||
HCI_CC(HCI_OP_LE_READ_ALL_LOCAL_FEATURES,
|
||||
hci_cc_le_read_all_local_features,
|
||||
sizeof(struct hci_rp_le_read_all_local_features)),
|
||||
};
|
||||
|
||||
static u8 hci_cc_func(struct hci_dev *hdev, const struct hci_cc *cc,
|
||||
|
|
@ -4324,6 +4362,8 @@ static const struct hci_cs {
|
|||
HCI_CS(HCI_OP_LE_EXT_CREATE_CONN, hci_cs_le_ext_create_conn),
|
||||
HCI_CS(HCI_OP_LE_CREATE_CIS, hci_cs_le_create_cis),
|
||||
HCI_CS(HCI_OP_LE_CREATE_BIG, hci_cs_le_create_big),
|
||||
HCI_CS(HCI_OP_LE_READ_ALL_REMOTE_FEATURES,
|
||||
hci_cs_le_read_all_remote_features),
|
||||
};
|
||||
|
||||
static void hci_cmd_status_evt(struct hci_dev *hdev, void *data,
|
||||
|
|
@ -5644,6 +5684,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
|||
struct hci_conn *conn;
|
||||
struct smp_irk *irk;
|
||||
u8 addr_type;
|
||||
int err;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
|
|
@ -5670,14 +5711,13 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
|||
if (status)
|
||||
goto unlock;
|
||||
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, bdaddr, role);
|
||||
conn = hci_conn_add_unset(hdev, LE_LINK, bdaddr, bdaddr_type,
|
||||
role);
|
||||
if (IS_ERR(conn)) {
|
||||
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
conn->dst_type = bdaddr_type;
|
||||
|
||||
/* If we didn't have a hci_conn object previously
|
||||
* but we're in central role this must be something
|
||||
* initiated using an accept list. Since accept list based
|
||||
|
|
@ -5775,26 +5815,8 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
|||
hci_debugfs_create_conn(conn);
|
||||
hci_conn_add_sysfs(conn);
|
||||
|
||||
/* The remote features procedure is defined for central
|
||||
* role only. So only in case of an initiated connection
|
||||
* request the remote features.
|
||||
*
|
||||
* If the local controller supports peripheral-initiated features
|
||||
* exchange, then requesting the remote features in peripheral
|
||||
* role is possible. Otherwise just transition into the
|
||||
* connected state without requesting the remote features.
|
||||
*/
|
||||
if (conn->out ||
|
||||
(hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES)) {
|
||||
struct hci_cp_le_read_remote_features cp;
|
||||
|
||||
cp.handle = __cpu_to_le16(conn->handle);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES,
|
||||
sizeof(cp), &cp);
|
||||
|
||||
hci_conn_hold(conn);
|
||||
} else {
|
||||
err = hci_le_read_remote_features(conn);
|
||||
if (err) {
|
||||
conn->state = BT_CONNECTED;
|
||||
hci_connect_cfm(conn, status);
|
||||
}
|
||||
|
|
@ -5936,6 +5958,71 @@ static void hci_le_ext_adv_term_evt(struct hci_dev *hdev, void *data,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle)
|
||||
{
|
||||
struct hci_cp_le_pa_term_sync cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = handle;
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_le_past_received_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_past_received *ev = data;
|
||||
int mask = hdev->link_mode;
|
||||
__u8 flags = 0;
|
||||
struct hci_conn *pa_sync, *conn;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
hci_dev_clear_flag(hdev, HCI_PA_SYNC);
|
||||
|
||||
conn = hci_conn_hash_lookup_create_pa_sync(hdev);
|
||||
if (!conn) {
|
||||
bt_dev_err(hdev,
|
||||
"Unable to find connection for dst %pMR sid 0x%2.2x",
|
||||
&ev->bdaddr, ev->sid);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
conn->sync_handle = le16_to_cpu(ev->sync_handle);
|
||||
conn->sid = HCI_SID_INVALID;
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, PA_LINK,
|
||||
&flags);
|
||||
if (!(mask & HCI_LM_ACCEPT)) {
|
||||
hci_le_pa_term_sync(hdev, ev->sync_handle);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!(flags & HCI_PROTO_DEFER))
|
||||
goto unlock;
|
||||
|
||||
/* Add connection to indicate PA sync event */
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY, 0,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (IS_ERR(pa_sync))
|
||||
goto unlock;
|
||||
|
||||
pa_sync->sync_handle = le16_to_cpu(ev->sync_handle);
|
||||
|
||||
if (ev->status) {
|
||||
set_bit(HCI_CONN_PA_SYNC_FAILED, &pa_sync->flags);
|
||||
|
||||
/* Notify iso layer */
|
||||
hci_connect_cfm(pa_sync, ev->status);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -6412,16 +6499,6 @@ static void hci_le_ext_adv_report_evt(struct hci_dev *hdev, void *data,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle)
|
||||
{
|
||||
struct hci_cp_le_pa_term_sync cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = handle;
|
||||
|
||||
return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
|
|
@ -6460,7 +6537,7 @@ static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
|
|||
goto unlock;
|
||||
|
||||
/* Add connection to indicate PA sync event */
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY,
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY, 0,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (IS_ERR(pa_sync))
|
||||
|
|
@ -6553,7 +6630,6 @@ static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, void *data,
|
|||
|
||||
conn->state = BT_CONNECTED;
|
||||
hci_connect_cfm(conn, status);
|
||||
hci_conn_drop(conn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6901,7 +6977,7 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data,
|
|||
|
||||
cis = hci_conn_hash_lookup_handle(hdev, cis_handle);
|
||||
if (!cis) {
|
||||
cis = hci_conn_add(hdev, CIS_LINK, &acl->dst,
|
||||
cis = hci_conn_add(hdev, CIS_LINK, &acl->dst, acl->dst_type,
|
||||
HCI_ROLE_SLAVE, cis_handle);
|
||||
if (IS_ERR(cis)) {
|
||||
hci_le_reject_cis(hdev, ev->cis_handle);
|
||||
|
|
@ -7018,7 +7094,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
|||
bt_dev_dbg(hdev, "ignore too large handle %u", handle);
|
||||
continue;
|
||||
}
|
||||
bis = hci_conn_add(hdev, BIS_LINK, BDADDR_ANY,
|
||||
bis = hci_conn_add(hdev, BIS_LINK, BDADDR_ANY, 0,
|
||||
HCI_ROLE_SLAVE, handle);
|
||||
if (IS_ERR(bis))
|
||||
continue;
|
||||
|
|
@ -7131,6 +7207,50 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_read_all_remote_features_evt(struct hci_dev *hdev,
|
||||
void *data, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_evt_le_read_all_remote_features_complete *ev = data;
|
||||
struct hci_conn *conn;
|
||||
|
||||
bt_dev_dbg(hdev, "status 0x%2.2x", ev->status);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
if (!ev->status)
|
||||
memcpy(conn->le_features, ev->features, 248);
|
||||
|
||||
if (conn->state == BT_CONFIG) {
|
||||
__u8 status;
|
||||
|
||||
/* If the local controller supports peripheral-initiated
|
||||
* features exchange, but the remote controller does
|
||||
* not, then it is possible that the error code 0x1a
|
||||
* for unsupported remote feature gets returned.
|
||||
*
|
||||
* In this specific case, allow the connection to
|
||||
* transition into connected state and mark it as
|
||||
* successful.
|
||||
*/
|
||||
if (!conn->out &&
|
||||
ev->status == HCI_ERROR_UNSUPPORTED_REMOTE_FEATURE &&
|
||||
(hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))
|
||||
status = 0x00;
|
||||
else
|
||||
status = ev->status;
|
||||
|
||||
conn->state = BT_CONNECTED;
|
||||
hci_connect_cfm(conn, status);
|
||||
}
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
#define HCI_LE_EV_VL(_op, _func, _min_len, _max_len) \
|
||||
[_op] = { \
|
||||
.func = _func, \
|
||||
|
|
@ -7206,6 +7326,10 @@ static const struct hci_le_ev {
|
|||
/* [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)),
|
||||
/* [0x18 = HCI_EVT_LE_PAST_RECEIVED] */
|
||||
HCI_LE_EV(HCI_EV_LE_PAST_RECEIVED,
|
||||
hci_le_past_received_evt,
|
||||
sizeof(struct hci_ev_le_past_received)),
|
||||
/* [0x19 = HCI_EVT_LE_CIS_ESTABLISHED] */
|
||||
HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_established_evt,
|
||||
sizeof(struct hci_evt_le_cis_established)),
|
||||
|
|
@ -7232,6 +7356,12 @@ static const struct hci_le_ev {
|
|||
hci_le_big_info_adv_report_evt,
|
||||
sizeof(struct hci_evt_le_big_info_adv_report),
|
||||
HCI_MAX_EVENT_SIZE),
|
||||
/* [0x2b = HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE] */
|
||||
HCI_LE_EV_VL(HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE,
|
||||
hci_le_read_all_remote_features_evt,
|
||||
sizeof(struct
|
||||
hci_evt_le_read_all_remote_features_complete),
|
||||
HCI_MAX_EVENT_SIZE),
|
||||
};
|
||||
|
||||
static void hci_le_meta_evt(struct hci_dev *hdev, void *data,
|
||||
|
|
|
|||
|
|
@ -4011,8 +4011,19 @@ static int hci_le_read_buffer_size_sync(struct hci_dev *hdev)
|
|||
/* Read LE Local Supported Features */
|
||||
static int hci_le_read_local_features_sync(struct hci_dev *hdev)
|
||||
{
|
||||
return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_LOCAL_FEATURES,
|
||||
int err;
|
||||
|
||||
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_LOCAL_FEATURES,
|
||||
0, NULL, HCI_CMD_TIMEOUT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ll_ext_feature_capable(hdev) && hdev->commands[47] & BIT(2))
|
||||
return __hci_cmd_sync_status(hdev,
|
||||
HCI_OP_LE_READ_ALL_LOCAL_FEATURES,
|
||||
0, NULL, HCI_CMD_TIMEOUT);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Read LE Supported States */
|
||||
|
|
@ -4324,6 +4335,10 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
|
|||
if (ll_privacy_capable(hdev))
|
||||
hdev->conn_flags |= HCI_CONN_FLAG_ADDRESS_RESOLUTION;
|
||||
|
||||
/* Mark PAST if supported */
|
||||
if (past_capable(hdev))
|
||||
hdev->conn_flags |= HCI_CONN_FLAG_PAST;
|
||||
|
||||
/* If the controller supports Extended Scanner Filter
|
||||
* Policies, enable the corresponding event.
|
||||
*/
|
||||
|
|
@ -4393,6 +4408,9 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
|
|||
if (ext_adv_capable(hdev))
|
||||
events[2] |= 0x02; /* LE Advertising Set Terminated */
|
||||
|
||||
if (past_receiver_capable(hdev))
|
||||
events[2] |= 0x80; /* LE PAST Received */
|
||||
|
||||
if (cis_capable(hdev)) {
|
||||
events[3] |= 0x01; /* LE CIS Established */
|
||||
if (cis_peripheral_capable(hdev))
|
||||
|
|
@ -7006,7 +7024,7 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
|
|||
goto unlock;
|
||||
|
||||
/* Add connection to indicate PA sync error */
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY,
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY, 0,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (IS_ERR(pa_sync))
|
||||
|
|
@ -7021,10 +7039,41 @@ static void create_pa_complete(struct hci_dev *hdev, void *data, int err)
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static int hci_le_past_params_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
struct hci_conn *acl, struct bt_iso_qos *qos)
|
||||
{
|
||||
struct hci_cp_le_past_params cp;
|
||||
int err;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = cpu_to_le16(acl->handle);
|
||||
/* An HCI_LE_Periodic_Advertising_Sync_Transfer_Received event is sent
|
||||
* to the Host. HCI_LE_Periodic_Advertising_Report events will be
|
||||
* enabled with duplicate filtering enabled.
|
||||
*/
|
||||
cp.mode = 0x03;
|
||||
cp.skip = cpu_to_le16(qos->bcast.skip);
|
||||
cp.sync_timeout = cpu_to_le16(qos->bcast.sync_timeout);
|
||||
cp.cte_type = qos->bcast.sync_cte_type;
|
||||
|
||||
/* HCI_LE_PAST_PARAMS command returns a command complete event so it
|
||||
* cannot wait for HCI_EV_LE_PAST_RECEIVED.
|
||||
*/
|
||||
err = __hci_cmd_sync_status(hdev, HCI_OP_LE_PAST_PARAMS,
|
||||
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Wait for HCI_EV_LE_PAST_RECEIVED event */
|
||||
return __hci_cmd_sync_status_sk(hdev, HCI_OP_NOP, 0, NULL,
|
||||
HCI_EV_LE_PAST_RECEIVED,
|
||||
conn->conn_timeout, NULL);
|
||||
}
|
||||
|
||||
static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
struct hci_cp_le_pa_create_sync cp;
|
||||
struct hci_conn *conn = data;
|
||||
struct hci_conn *conn = data, *le;
|
||||
struct bt_iso_qos *qos = &conn->iso_qos;
|
||||
int err;
|
||||
|
||||
|
|
@ -7056,6 +7105,24 @@ static int hci_le_pa_create_sync(struct hci_dev *hdev, void *data)
|
|||
|
||||
hci_update_passive_scan_sync(hdev);
|
||||
|
||||
/* Check if PAST is possible:
|
||||
*
|
||||
* 1. Check if an ACL connection with the destination address exists
|
||||
* 2. Check if that HCI_CONN_FLAG_PAST has been set which indicates that
|
||||
* user really intended to use PAST.
|
||||
*/
|
||||
le = hci_conn_hash_lookup_le(hdev, &conn->dst, conn->dst_type);
|
||||
if (le) {
|
||||
struct hci_conn_params *params;
|
||||
|
||||
params = hci_conn_params_lookup(hdev, &le->dst, le->dst_type);
|
||||
if (params && params->flags & HCI_CONN_FLAG_PAST) {
|
||||
err = hci_le_past_params_sync(hdev, conn, le, qos);
|
||||
if (!err)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* SID has not been set listen for HCI_EV_LE_EXT_ADV_REPORT to update
|
||||
* it.
|
||||
*/
|
||||
|
|
@ -7172,3 +7239,182 @@ int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn)
|
|||
return hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn,
|
||||
create_big_complete);
|
||||
}
|
||||
|
||||
struct past_data {
|
||||
struct hci_conn *conn;
|
||||
struct hci_conn *le;
|
||||
};
|
||||
|
||||
static void past_complete(struct hci_dev *hdev, void *data, int err)
|
||||
{
|
||||
struct past_data *past = data;
|
||||
|
||||
bt_dev_dbg(hdev, "err %d", err);
|
||||
|
||||
kfree(past);
|
||||
}
|
||||
|
||||
static int hci_le_past_set_info_sync(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
struct past_data *past = data;
|
||||
struct hci_cp_le_past_set_info cp;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!hci_conn_valid(hdev, past->conn) ||
|
||||
!hci_conn_valid(hdev, past->le)) {
|
||||
hci_dev_unlock(hdev);
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = cpu_to_le16(past->le->handle);
|
||||
cp.adv_handle = past->conn->iso_qos.bcast.bis;
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return __hci_cmd_sync_status(hdev, HCI_OP_LE_PAST_SET_INFO,
|
||||
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
||||
}
|
||||
|
||||
static int hci_le_past_sync(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
struct past_data *past = data;
|
||||
struct hci_cp_le_past cp;
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (!hci_conn_valid(hdev, past->conn) ||
|
||||
!hci_conn_valid(hdev, past->le)) {
|
||||
hci_dev_unlock(hdev);
|
||||
return -ECANCELED;
|
||||
}
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = cpu_to_le16(past->le->handle);
|
||||
cp.sync_handle = cpu_to_le16(past->conn->sync_handle);
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
|
||||
return __hci_cmd_sync_status(hdev, HCI_OP_LE_PAST,
|
||||
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
||||
}
|
||||
|
||||
int hci_past_sync(struct hci_conn *conn, struct hci_conn *le)
|
||||
{
|
||||
struct past_data *data;
|
||||
int err;
|
||||
|
||||
if (conn->type != BIS_LINK && conn->type != PA_LINK)
|
||||
return -EINVAL;
|
||||
|
||||
if (!past_sender_capable(conn->hdev))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->conn = conn;
|
||||
data->le = le;
|
||||
|
||||
if (conn->role == HCI_ROLE_MASTER)
|
||||
err = hci_cmd_sync_queue_once(conn->hdev,
|
||||
hci_le_past_set_info_sync, data,
|
||||
past_complete);
|
||||
else
|
||||
err = hci_cmd_sync_queue_once(conn->hdev, hci_le_past_sync,
|
||||
data, past_complete);
|
||||
|
||||
if (err)
|
||||
kfree(data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void le_read_features_complete(struct hci_dev *hdev, void *data, int err)
|
||||
{
|
||||
struct hci_conn *conn = data;
|
||||
|
||||
bt_dev_dbg(hdev, "err %d", err);
|
||||
|
||||
if (err == -ECANCELED)
|
||||
return;
|
||||
|
||||
hci_conn_drop(conn);
|
||||
}
|
||||
|
||||
static int hci_le_read_all_remote_features_sync(struct hci_dev *hdev,
|
||||
void *data)
|
||||
{
|
||||
struct hci_conn *conn = data;
|
||||
struct hci_cp_le_read_all_remote_features cp;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.pages = 10; /* Attempt to read all pages */
|
||||
|
||||
/* Wait for HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE event otherwise
|
||||
* hci_conn_drop may run prematurely causing a disconnection.
|
||||
*/
|
||||
return __hci_cmd_sync_status_sk(hdev,
|
||||
HCI_OP_LE_READ_ALL_REMOTE_FEATURES,
|
||||
sizeof(cp), &cp,
|
||||
HCI_EVT_LE_ALL_REMOTE_FEATURES_COMPLETE,
|
||||
HCI_CMD_TIMEOUT, NULL);
|
||||
|
||||
return __hci_cmd_sync_status(hdev, HCI_OP_LE_READ_ALL_REMOTE_FEATURES,
|
||||
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
|
||||
}
|
||||
|
||||
static int hci_le_read_remote_features_sync(struct hci_dev *hdev, void *data)
|
||||
{
|
||||
struct hci_conn *conn = data;
|
||||
struct hci_cp_le_read_remote_features cp;
|
||||
|
||||
if (!hci_conn_valid(hdev, conn))
|
||||
return -ECANCELED;
|
||||
|
||||
/* Check if LL Extended Feature Set is supported and
|
||||
* HCI_OP_LE_READ_ALL_REMOTE_FEATURES is supported then use that to read
|
||||
* all features.
|
||||
*/
|
||||
if (ll_ext_feature_capable(hdev) && hdev->commands[47] & BIT(3))
|
||||
return hci_le_read_all_remote_features_sync(hdev, data);
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
|
||||
/* Wait for HCI_EV_LE_REMOTE_FEAT_COMPLETE event otherwise
|
||||
* hci_conn_drop may run prematurely causing a disconnection.
|
||||
*/
|
||||
return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_READ_REMOTE_FEATURES,
|
||||
sizeof(cp), &cp,
|
||||
HCI_EV_LE_REMOTE_FEAT_COMPLETE,
|
||||
HCI_CMD_TIMEOUT, NULL);
|
||||
}
|
||||
|
||||
int hci_le_read_remote_features(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
int err;
|
||||
|
||||
/* The remote features procedure is defined for central
|
||||
* role only. So only in case of an initiated connection
|
||||
* request the remote features.
|
||||
*
|
||||
* If the local controller supports peripheral-initiated features
|
||||
* exchange, then requesting the remote features in peripheral
|
||||
* role is possible. Otherwise just transition into the
|
||||
* connected state without requesting the remote features.
|
||||
*/
|
||||
if (conn->out || (hdev->le_features[0] & HCI_LE_PERIPHERAL_FEATURES))
|
||||
err = hci_cmd_sync_queue_once(hdev,
|
||||
hci_le_read_remote_features_sync,
|
||||
hci_conn_hold(conn),
|
||||
le_read_features_complete);
|
||||
else
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,14 +80,15 @@ 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 bool iso_match_sid_past(struct sock *sk, void *data);
|
||||
static bool iso_match_sync_handle(struct sock *sk, void *data);
|
||||
static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data);
|
||||
static void iso_sock_disconn(struct sock *sk);
|
||||
|
||||
typedef bool (*iso_sock_match_t)(struct sock *sk, void *data);
|
||||
|
||||
static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst,
|
||||
enum bt_sock_state state,
|
||||
static struct sock *iso_get_sock(struct hci_dev *hdev, bdaddr_t *src,
|
||||
bdaddr_t *dst, enum bt_sock_state state,
|
||||
iso_sock_match_t match, void *data);
|
||||
|
||||
/* ---- ISO timers ---- */
|
||||
|
|
@ -637,8 +638,8 @@ static struct sock *__iso_get_sock_listen_by_sid(bdaddr_t *ba, bdaddr_t *bc,
|
|||
* match func data - pass -1 to ignore
|
||||
* Returns closest match.
|
||||
*/
|
||||
static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst,
|
||||
enum bt_sock_state state,
|
||||
static struct sock *iso_get_sock(struct hci_dev *hdev, bdaddr_t *src,
|
||||
bdaddr_t *dst, enum bt_sock_state state,
|
||||
iso_sock_match_t match, void *data)
|
||||
{
|
||||
struct sock *sk = NULL, *sk1 = NULL;
|
||||
|
|
@ -650,9 +651,26 @@ static struct sock *iso_get_sock(bdaddr_t *src, bdaddr_t *dst,
|
|||
continue;
|
||||
|
||||
/* Match Broadcast destination */
|
||||
if (bacmp(dst, BDADDR_ANY) && bacmp(&iso_pi(sk)->dst, dst))
|
||||
if (bacmp(dst, BDADDR_ANY) && bacmp(&iso_pi(sk)->dst, dst)) {
|
||||
struct smp_irk *irk1, *irk2;
|
||||
|
||||
/* Check if destination is an RPA that we can resolve */
|
||||
irk1 = hci_find_irk_by_rpa(hdev, dst);
|
||||
if (!irk1)
|
||||
continue;
|
||||
|
||||
/* Match with identity address */
|
||||
if (bacmp(&iso_pi(sk)->dst, &irk1->bdaddr)) {
|
||||
/* Check if socket destination address is also
|
||||
* an RPA and if the IRK matches.
|
||||
*/
|
||||
irk2 = hci_find_irk_by_rpa(hdev,
|
||||
&iso_pi(sk)->dst);
|
||||
if (!irk2 || irk1 != irk2)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use Match function if provided */
|
||||
if (match && !match(sk, data))
|
||||
continue;
|
||||
|
|
@ -986,20 +1004,14 @@ static int iso_sock_bind_bc(struct socket *sock, struct sockaddr_unsized *addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int iso_sock_bind_pa_sk(struct sock *sk, struct sockaddr_iso *sa,
|
||||
/* Must be called on the locked socket. */
|
||||
static int iso_sock_rebind_bis(struct sock *sk, struct sockaddr_iso *sa,
|
||||
int addr_len)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (sk->sk_type != SOCK_SEQPACKET) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
if (!test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags))
|
||||
return -EBADFD;
|
||||
|
||||
if (sa->iso_bc->bc_num_bis > ISO_MAX_NUM_BIS) {
|
||||
err = -EINVAL;
|
||||
|
|
@ -1022,6 +1034,77 @@ static int iso_sock_bind_pa_sk(struct sock *sk, struct sockaddr_iso *sa,
|
|||
return err;
|
||||
}
|
||||
|
||||
static struct hci_dev *iso_conn_get_hdev(struct iso_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = NULL;
|
||||
|
||||
iso_conn_lock(conn);
|
||||
if (conn->hcon)
|
||||
hdev = hci_dev_hold(conn->hcon->hdev);
|
||||
iso_conn_unlock(conn);
|
||||
|
||||
return hdev;
|
||||
}
|
||||
|
||||
/* Must be called on the locked socket. */
|
||||
static int iso_sock_rebind_bc(struct sock *sk, struct sockaddr_iso *sa,
|
||||
int addr_len)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct hci_conn *bis;
|
||||
int err;
|
||||
|
||||
if (sk->sk_type != SOCK_SEQPACKET || !iso_pi(sk)->conn)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if it is really a Broadcast address being requested */
|
||||
if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc))
|
||||
return -EINVAL;
|
||||
|
||||
/* Check if the address hasn't changed then perhaps only the number of
|
||||
* bis has changed.
|
||||
*/
|
||||
if (!bacmp(&iso_pi(sk)->dst, &sa->iso_bc->bc_bdaddr) ||
|
||||
!bacmp(&sa->iso_bc->bc_bdaddr, BDADDR_ANY))
|
||||
return iso_sock_rebind_bis(sk, sa, addr_len);
|
||||
|
||||
/* Check if the address type is of LE type */
|
||||
if (!bdaddr_type_is_le(sa->iso_bc->bc_bdaddr_type))
|
||||
return -EINVAL;
|
||||
|
||||
hdev = iso_conn_get_hdev(iso_pi(sk)->conn);
|
||||
if (!hdev)
|
||||
return -EINVAL;
|
||||
|
||||
bis = iso_pi(sk)->conn->hcon;
|
||||
|
||||
/* Release the socket before lookups since that requires hci_dev_lock
|
||||
* which shall not be acquired while holding sock_lock for proper
|
||||
* ordering.
|
||||
*/
|
||||
release_sock(sk);
|
||||
hci_dev_lock(bis->hdev);
|
||||
lock_sock(sk);
|
||||
|
||||
if (!iso_pi(sk)->conn || iso_pi(sk)->conn->hcon != bis) {
|
||||
/* raced with iso_conn_del() or iso_disconn_sock() */
|
||||
err = -ENOTCONN;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
BT_DBG("sk %p %pMR type %u", sk, &sa->iso_bc->bc_bdaddr,
|
||||
sa->iso_bc->bc_bdaddr_type);
|
||||
|
||||
err = hci_past_bis(bis, &sa->iso_bc->bc_bdaddr,
|
||||
le_addr_type(sa->iso_bc->bc_bdaddr_type));
|
||||
|
||||
unlock:
|
||||
hci_dev_unlock(hdev);
|
||||
hci_dev_put(hdev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int iso_sock_bind(struct socket *sock, struct sockaddr_unsized *addr,
|
||||
int addr_len)
|
||||
{
|
||||
|
|
@ -1037,13 +1120,12 @@ static int iso_sock_bind(struct socket *sock, struct sockaddr_unsized *addr,
|
|||
|
||||
lock_sock(sk);
|
||||
|
||||
/* Allow the user to bind a PA sync socket to a number
|
||||
* of BISes to sync to.
|
||||
if ((sk->sk_state == BT_CONNECT2 || sk->sk_state == BT_CONNECTED) &&
|
||||
addr_len > sizeof(*sa)) {
|
||||
/* Allow the user to rebind to a different address using
|
||||
* PAST procedures.
|
||||
*/
|
||||
if ((sk->sk_state == BT_CONNECT2 ||
|
||||
sk->sk_state == BT_CONNECTED) &&
|
||||
test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) {
|
||||
err = iso_sock_bind_pa_sk(sk, sa, addr_len);
|
||||
err = iso_sock_rebind_bc(sk, sa, addr_len);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
@ -1939,6 +2021,11 @@ static bool iso_match_pa_sync_flag(struct sock *sk, void *data)
|
|||
return test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags);
|
||||
}
|
||||
|
||||
static bool iso_match_dst(struct sock *sk, void *data)
|
||||
{
|
||||
return !bacmp(&iso_pi(sk)->dst, (bdaddr_t *)data);
|
||||
}
|
||||
|
||||
static void iso_conn_ready(struct iso_conn *conn)
|
||||
{
|
||||
struct sock *parent = NULL;
|
||||
|
|
@ -1947,23 +2034,45 @@ static void iso_conn_ready(struct iso_conn *conn)
|
|||
struct hci_ev_le_pa_sync_established *ev2 = NULL;
|
||||
struct hci_ev_le_per_adv_report *ev3 = NULL;
|
||||
struct hci_conn *hcon;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
BT_DBG("conn %p", conn);
|
||||
|
||||
if (sk) {
|
||||
/* Attempt to update source address in case of BIS Sender if
|
||||
* the advertisement is using a random address.
|
||||
*/
|
||||
if (conn->hcon->type == BIS_LINK &&
|
||||
conn->hcon->role == HCI_ROLE_MASTER &&
|
||||
!bacmp(&conn->hcon->dst, BDADDR_ANY)) {
|
||||
struct hci_conn *bis = conn->hcon;
|
||||
struct adv_info *adv;
|
||||
|
||||
adv = hci_find_adv_instance(bis->hdev,
|
||||
bis->iso_qos.bcast.bis);
|
||||
if (adv && bacmp(&adv->random_addr, BDADDR_ANY)) {
|
||||
lock_sock(sk);
|
||||
iso_pi(sk)->src_type = BDADDR_LE_RANDOM;
|
||||
bacpy(&iso_pi(sk)->src, &adv->random_addr);
|
||||
release_sock(sk);
|
||||
}
|
||||
}
|
||||
|
||||
iso_sock_ready(conn->sk);
|
||||
} else {
|
||||
hcon = conn->hcon;
|
||||
if (!hcon)
|
||||
return;
|
||||
|
||||
hdev = hcon->hdev;
|
||||
|
||||
if (test_bit(HCI_CONN_BIG_SYNC, &hcon->flags)) {
|
||||
/* A BIS slave hcon is notified to the ISO layer
|
||||
* after the Command Complete for the LE Setup
|
||||
* ISO Data Path command is received. Get the
|
||||
* parent socket that matches the hcon BIG handle.
|
||||
*/
|
||||
parent = iso_get_sock(&hcon->src, &hcon->dst,
|
||||
parent = iso_get_sock(hdev, &hcon->src, &hcon->dst,
|
||||
BT_LISTEN, iso_match_big_hcon,
|
||||
hcon);
|
||||
} else if (test_bit(HCI_CONN_BIG_SYNC_FAILED, &hcon->flags)) {
|
||||
|
|
@ -1971,12 +2080,12 @@ static void iso_conn_ready(struct iso_conn *conn)
|
|||
HCI_EVT_LE_BIG_SYNC_ESTABLISHED);
|
||||
|
||||
/* Get reference to PA sync parent socket, if it exists */
|
||||
parent = iso_get_sock(&hcon->src, &hcon->dst,
|
||||
parent = iso_get_sock(hdev, &hcon->src, &hcon->dst,
|
||||
BT_LISTEN,
|
||||
iso_match_pa_sync_flag,
|
||||
NULL);
|
||||
if (!parent && ev)
|
||||
parent = iso_get_sock(&hcon->src,
|
||||
parent = iso_get_sock(hdev, &hcon->src,
|
||||
&hcon->dst,
|
||||
BT_LISTEN,
|
||||
iso_match_big, ev);
|
||||
|
|
@ -1984,7 +2093,7 @@ static void iso_conn_ready(struct iso_conn *conn)
|
|||
ev2 = hci_recv_event_data(hcon->hdev,
|
||||
HCI_EV_LE_PA_SYNC_ESTABLISHED);
|
||||
if (ev2)
|
||||
parent = iso_get_sock(&hcon->src,
|
||||
parent = iso_get_sock(hdev, &hcon->src,
|
||||
&hcon->dst,
|
||||
BT_LISTEN,
|
||||
iso_match_sid, ev2);
|
||||
|
|
@ -1992,7 +2101,7 @@ static void iso_conn_ready(struct iso_conn *conn)
|
|||
ev3 = hci_recv_event_data(hcon->hdev,
|
||||
HCI_EV_LE_PER_ADV_REPORT);
|
||||
if (ev3)
|
||||
parent = iso_get_sock(&hcon->src,
|
||||
parent = iso_get_sock(hdev, &hcon->src,
|
||||
&hcon->dst,
|
||||
BT_LISTEN,
|
||||
iso_match_sync_handle_pa_report,
|
||||
|
|
@ -2000,8 +2109,8 @@ static void iso_conn_ready(struct iso_conn *conn)
|
|||
}
|
||||
|
||||
if (!parent)
|
||||
parent = iso_get_sock(&hcon->src, BDADDR_ANY,
|
||||
BT_LISTEN, NULL, NULL);
|
||||
parent = iso_get_sock(hdev, &hcon->src, BDADDR_ANY,
|
||||
BT_LISTEN, iso_match_dst, BDADDR_ANY);
|
||||
|
||||
if (!parent)
|
||||
return;
|
||||
|
|
@ -2090,6 +2199,16 @@ static bool iso_match_sid(struct sock *sk, void *data)
|
|||
return ev->sid == iso_pi(sk)->bc_sid;
|
||||
}
|
||||
|
||||
static bool iso_match_sid_past(struct sock *sk, void *data)
|
||||
{
|
||||
struct hci_ev_le_past_received *ev = data;
|
||||
|
||||
if (iso_pi(sk)->bc_sid == HCI_SID_INVALID)
|
||||
return true;
|
||||
|
||||
return ev->sid == iso_pi(sk)->bc_sid;
|
||||
}
|
||||
|
||||
static bool iso_match_sync_handle(struct sock *sk, void *data)
|
||||
{
|
||||
struct hci_evt_le_big_info_adv_report *ev = data;
|
||||
|
|
@ -2109,6 +2228,7 @@ static bool iso_match_sync_handle_pa_report(struct sock *sk, void *data)
|
|||
int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
{
|
||||
struct hci_ev_le_pa_sync_established *ev1;
|
||||
struct hci_ev_le_past_received *ev1a;
|
||||
struct hci_evt_le_big_info_adv_report *ev2;
|
||||
struct hci_ev_le_per_adv_report *ev3;
|
||||
struct sock *sk;
|
||||
|
|
@ -2122,6 +2242,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
* SID to listen to and once sync is established its handle needs to
|
||||
* be stored in iso_pi(sk)->sync_handle so it can be matched once
|
||||
* receiving the BIG Info.
|
||||
* 1a. HCI_EV_LE_PAST_RECEIVED: alternative to 1.
|
||||
* 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.
|
||||
|
|
@ -2131,7 +2252,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
*/
|
||||
ev1 = hci_recv_event_data(hdev, HCI_EV_LE_PA_SYNC_ESTABLISHED);
|
||||
if (ev1) {
|
||||
sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_LISTEN,
|
||||
sk = iso_get_sock(hdev, &hdev->bdaddr, bdaddr, BT_LISTEN,
|
||||
iso_match_sid, ev1);
|
||||
if (sk && !ev1->status) {
|
||||
iso_pi(sk)->sync_handle = le16_to_cpu(ev1->handle);
|
||||
|
|
@ -2141,10 +2262,22 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
goto done;
|
||||
}
|
||||
|
||||
ev1a = hci_recv_event_data(hdev, HCI_EV_LE_PAST_RECEIVED);
|
||||
if (ev1a) {
|
||||
sk = iso_get_sock(hdev, &hdev->bdaddr, bdaddr, BT_LISTEN,
|
||||
iso_match_sid_past, ev1a);
|
||||
if (sk && !ev1a->status) {
|
||||
iso_pi(sk)->sync_handle = le16_to_cpu(ev1a->sync_handle);
|
||||
iso_pi(sk)->bc_sid = ev1a->sid;
|
||||
}
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
ev2 = hci_recv_event_data(hdev, HCI_EVT_LE_BIG_INFO_ADV_REPORT);
|
||||
if (ev2) {
|
||||
/* Check if BIGInfo report has already been handled */
|
||||
sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_CONNECTED,
|
||||
sk = iso_get_sock(hdev, &hdev->bdaddr, bdaddr, BT_CONNECTED,
|
||||
iso_match_sync_handle, ev2);
|
||||
if (sk) {
|
||||
sock_put(sk);
|
||||
|
|
@ -2153,10 +2286,10 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
}
|
||||
|
||||
/* Try to get PA sync socket, if it exists */
|
||||
sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_CONNECT2,
|
||||
sk = iso_get_sock(hdev, &hdev->bdaddr, bdaddr, BT_CONNECT2,
|
||||
iso_match_sync_handle, ev2);
|
||||
if (!sk)
|
||||
sk = iso_get_sock(&hdev->bdaddr, bdaddr,
|
||||
sk = iso_get_sock(hdev, &hdev->bdaddr, bdaddr,
|
||||
BT_LISTEN,
|
||||
iso_match_sync_handle,
|
||||
ev2);
|
||||
|
|
@ -2195,7 +2328,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
u8 *base;
|
||||
struct hci_conn *hcon;
|
||||
|
||||
sk = iso_get_sock(&hdev->bdaddr, bdaddr, BT_LISTEN,
|
||||
sk = iso_get_sock(hdev, &hdev->bdaddr, bdaddr, BT_LISTEN,
|
||||
iso_match_sync_handle_pa_report, ev3);
|
||||
if (!sk)
|
||||
goto done;
|
||||
|
|
@ -2245,8 +2378,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
|||
hcon->le_per_adv_data_len = 0;
|
||||
}
|
||||
} else {
|
||||
sk = iso_get_sock(&hdev->bdaddr, BDADDR_ANY,
|
||||
BT_LISTEN, NULL, NULL);
|
||||
sk = iso_get_sock(hdev, &hdev->bdaddr, BDADDR_ANY,
|
||||
BT_LISTEN, iso_match_dst, BDADDR_ANY);
|
||||
}
|
||||
|
||||
done:
|
||||
|
|
|
|||
|
|
@ -852,6 +852,12 @@ static u32 get_supported_settings(struct hci_dev *hdev)
|
|||
if (ll_privacy_capable(hdev))
|
||||
settings |= MGMT_SETTING_LL_PRIVACY;
|
||||
|
||||
if (past_sender_capable(hdev))
|
||||
settings |= MGMT_SETTING_PAST_SENDER;
|
||||
|
||||
if (past_receiver_capable(hdev))
|
||||
settings |= MGMT_SETTING_PAST_RECEIVER;
|
||||
|
||||
settings |= MGMT_SETTING_PHY_CONFIGURATION;
|
||||
|
||||
return settings;
|
||||
|
|
@ -937,6 +943,12 @@ static u32 get_current_settings(struct hci_dev *hdev)
|
|||
if (ll_privacy_enabled(hdev))
|
||||
settings |= MGMT_SETTING_LL_PRIVACY;
|
||||
|
||||
if (past_sender_enabled(hdev))
|
||||
settings |= MGMT_SETTING_PAST_SENDER;
|
||||
|
||||
if (past_receiver_enabled(hdev))
|
||||
settings |= MGMT_SETTING_PAST_RECEIVER;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
|
@ -5110,6 +5122,69 @@ static void device_flags_changed(struct sock *sk, struct hci_dev *hdev,
|
|||
mgmt_event(MGMT_EV_DEVICE_FLAGS_CHANGED, hdev, &ev, sizeof(ev), sk);
|
||||
}
|
||||
|
||||
static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
|
||||
if (!conn)
|
||||
return false;
|
||||
|
||||
if (conn->dst_type != type)
|
||||
return false;
|
||||
|
||||
if (conn->state != BT_CONNECTED)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static struct hci_conn_params *hci_conn_params_set(struct hci_dev *hdev,
|
||||
bdaddr_t *addr, u8 addr_type,
|
||||
u8 auto_connect)
|
||||
{
|
||||
struct hci_conn_params *params;
|
||||
|
||||
params = hci_conn_params_add(hdev, addr, addr_type);
|
||||
if (!params)
|
||||
return NULL;
|
||||
|
||||
if (params->auto_connect == auto_connect)
|
||||
return params;
|
||||
|
||||
hci_pend_le_list_del_init(params);
|
||||
|
||||
switch (auto_connect) {
|
||||
case HCI_AUTO_CONN_DISABLED:
|
||||
case HCI_AUTO_CONN_LINK_LOSS:
|
||||
/* If auto connect is being disabled when we're trying to
|
||||
* connect to device, keep connecting.
|
||||
*/
|
||||
if (params->explicit_connect)
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_conns);
|
||||
break;
|
||||
case HCI_AUTO_CONN_REPORT:
|
||||
if (params->explicit_connect)
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_conns);
|
||||
else
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_reports);
|
||||
break;
|
||||
case HCI_AUTO_CONN_DIRECT:
|
||||
case HCI_AUTO_CONN_ALWAYS:
|
||||
if (!is_connected(hdev, addr, addr_type))
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_conns);
|
||||
break;
|
||||
}
|
||||
|
||||
params->auto_connect = auto_connect;
|
||||
|
||||
bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
|
||||
addr, addr_type, auto_connect);
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
|
||||
u16 len)
|
||||
{
|
||||
|
|
@ -5152,11 +5227,18 @@ static int set_device_flags(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
|
||||
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
|
||||
le_addr_type(cp->addr.type));
|
||||
if (!params) {
|
||||
/* Create a new hci_conn_params if it doesn't exist */
|
||||
params = hci_conn_params_set(hdev, &cp->addr.bdaddr,
|
||||
le_addr_type(cp->addr.type),
|
||||
HCI_AUTO_CONN_DISABLED);
|
||||
if (!params) {
|
||||
bt_dev_warn(hdev, "No such LE device %pMR (0x%x)",
|
||||
&cp->addr.bdaddr, le_addr_type(cp->addr.type));
|
||||
&cp->addr.bdaddr,
|
||||
le_addr_type(cp->addr.type));
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
supported_flags = hdev->conn_flags;
|
||||
|
||||
|
|
@ -7542,68 +7624,6 @@ static int get_clock_info(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool is_connected(struct hci_dev *hdev, bdaddr_t *addr, u8 type)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, addr);
|
||||
if (!conn)
|
||||
return false;
|
||||
|
||||
if (conn->dst_type != type)
|
||||
return false;
|
||||
|
||||
if (conn->state != BT_CONNECTED)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function requires the caller holds hdev->lock */
|
||||
static int hci_conn_params_set(struct hci_dev *hdev, bdaddr_t *addr,
|
||||
u8 addr_type, u8 auto_connect)
|
||||
{
|
||||
struct hci_conn_params *params;
|
||||
|
||||
params = hci_conn_params_add(hdev, addr, addr_type);
|
||||
if (!params)
|
||||
return -EIO;
|
||||
|
||||
if (params->auto_connect == auto_connect)
|
||||
return 0;
|
||||
|
||||
hci_pend_le_list_del_init(params);
|
||||
|
||||
switch (auto_connect) {
|
||||
case HCI_AUTO_CONN_DISABLED:
|
||||
case HCI_AUTO_CONN_LINK_LOSS:
|
||||
/* If auto connect is being disabled when we're trying to
|
||||
* connect to device, keep connecting.
|
||||
*/
|
||||
if (params->explicit_connect)
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_conns);
|
||||
break;
|
||||
case HCI_AUTO_CONN_REPORT:
|
||||
if (params->explicit_connect)
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_conns);
|
||||
else
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_reports);
|
||||
break;
|
||||
case HCI_AUTO_CONN_DIRECT:
|
||||
case HCI_AUTO_CONN_ALWAYS:
|
||||
if (!is_connected(hdev, addr, addr_type))
|
||||
hci_pend_le_list_add(params, &hdev->pend_le_conns);
|
||||
break;
|
||||
}
|
||||
|
||||
params->auto_connect = auto_connect;
|
||||
|
||||
bt_dev_dbg(hdev, "addr %pMR (type %u) auto_connect %u",
|
||||
addr, addr_type, auto_connect);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void device_added(struct sock *sk, struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr, u8 type, u8 action)
|
||||
{
|
||||
|
|
@ -7715,17 +7735,13 @@ static int add_device(struct sock *sk, struct hci_dev *hdev,
|
|||
/* If the connection parameters don't exist for this device,
|
||||
* they will be created and configured with defaults.
|
||||
*/
|
||||
if (hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
|
||||
auto_conn) < 0) {
|
||||
params = hci_conn_params_set(hdev, &cp->addr.bdaddr, addr_type,
|
||||
auto_conn);
|
||||
if (!params) {
|
||||
err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_DEVICE,
|
||||
MGMT_STATUS_FAILED, &cp->addr,
|
||||
sizeof(cp->addr));
|
||||
goto unlock;
|
||||
} else {
|
||||
params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr,
|
||||
addr_type);
|
||||
if (params)
|
||||
current_flags = params->flags;
|
||||
}
|
||||
|
||||
cmd = mgmt_pending_new(sk, MGMT_OP_ADD_DEVICE, hdev, data, len);
|
||||
|
|
|
|||
Loading…
Reference in New Issue