mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-02-15 08:32:44 -05:00
Merge tag 'for-net-next-2025-07-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Luiz Augusto von Dentz says: ==================== bluetooth-next pull request for net-next: core: - hci_sync: fix double free in 'hci_discovery_filter_clear()' - hci_event: Mask data status from LE ext adv reports - hci_devcd_dump: fix out-of-bounds via dev_coredumpv - ISO: add socket option to report packet seqnum via CMSG - hci_event: Add support for handling LE BIG Sync Lost event - ISO: Support SCM_TIMESTAMPING for ISO TS - hci_core: Add PA_LINK to distinguish BIG sync and PA sync connections - hci_sock: Reset cookie to zero in hci_sock_free_cookie() drivers: - btusb: Add new VID/PID 0489/e14e for MT7925 - btusb: Add a new VID/PID 2c7c/7009 for MT7925 - btusb: Add RTL8852BE device 0x13d3:0x3618 - btusb: Add support for variant of RTL8851BE (USB ID 13d3:3601) - btusb: Add USB ID 3625:010b for TP-LINK Archer TX10UB Nano - btusb: QCA: Support downloading custom-made firmwares - btusb: Add one more ID 0x28de:0x1401 for Qualcomm WCN6855 - nxp: add support for supply and reset - btnxpuart: Add support for 4M baudrate - btnxpuart: Correct the Independent Reset handling after FW dump - btnxpuart: Add uevents for FW dump and FW download complete - btintel: Define a macro for Intel Reset vendor command - btintel_pcie: Support Function level reset - btintel_pcie: Add support for device 0x4d76 - btintel_pcie: Make driver wait for alive interrupt - btintel_pcie: Fix Alive Context State Handling - hci_qca: Enable ISO data packet RX * tag 'for-net-next-2025-07-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next: (42 commits) Bluetooth: Add PA_LINK to distinguish BIG sync and PA sync connections Bluetooth: hci_event: Mask data status from LE ext adv reports Bluetooth: btintel_pcie: Fix Alive Context State Handling Bluetooth: btintel_pcie: Make driver wait for alive interrupt Bluetooth: hci_devcd_dump: fix out-of-bounds via dev_coredumpv Bluetooth: hci_sync: fix double free in 'hci_discovery_filter_clear()' Bluetooth: btusb: Add one more ID 0x28de:0x1401 for Qualcomm WCN6855 Bluetooth: btusb: Sort WCN6855 device IDs by VID and PID Bluetooth: btusb: QCA: Support downloading custom-made firmwares Bluetooth: btnxpuart: Add uevents for FW dump and FW download complete Bluetooth: btnxpuart: Correct the Independent Reset handling after FW dump Bluetooth: ISO: Support SCM_TIMESTAMPING for ISO TS Bluetooth: ISO: add socket option to report packet seqnum via CMSG Bluetooth: btintel: Define a macro for Intel Reset vendor command Bluetooth: Fix typos in comments Bluetooth: RFCOMM: Fix typos in comments Bluetooth: aosp: Fix typo in comment Bluetooth: hci_bcm4377: Fix typo in comment Bluetooth: btrtl: Fix typo in comment Bluetooth: btmtk: Fix typo in log string ... ==================== Link: https://patch.msgid.link/20250723190233.166823-1-luiz.dentz@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -34,6 +34,13 @@ properties:
|
||||
This property depends on the module vendor's
|
||||
configuration.
|
||||
|
||||
max-speed:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum:
|
||||
- 3000000
|
||||
- 4000000
|
||||
default: 3000000
|
||||
|
||||
firmware-name:
|
||||
maxItems: 1
|
||||
|
||||
@@ -65,6 +72,14 @@ properties:
|
||||
description:
|
||||
The GPIO number of the NXP chipset used for BT_WAKE_OUT.
|
||||
|
||||
vcc-supply:
|
||||
description:
|
||||
phandle of the regulator that provides the supply voltage.
|
||||
|
||||
reset-gpios:
|
||||
description:
|
||||
Chip powerdown/reset signal (PDn).
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
@@ -78,10 +93,13 @@ examples:
|
||||
bluetooth {
|
||||
compatible = "nxp,88w8987-bt";
|
||||
fw-init-baudrate = <3000000>;
|
||||
max-speed = <4000000>;
|
||||
firmware-name = "uartuart8987_bt_v0.bin";
|
||||
device-wakeup-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
|
||||
nxp,wakein-pin = /bits/ 8 <18>;
|
||||
nxp,wakeout-pin = /bits/ 8 <19>;
|
||||
vcc-supply = <&nxp_iw612_supply>;
|
||||
reset-gpios = <&gpioctrl 2 GPIO_ACTIVE_LOW>;
|
||||
local-bd-address = [66 55 44 33 22 11];
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
@@ -555,7 +555,7 @@ int btintel_parse_version_tlv(struct hci_dev *hdev,
|
||||
/* Consume Command Complete Status field */
|
||||
skb_pull(skb, 1);
|
||||
|
||||
/* Event parameters contatin multiple TLVs. Read each of them
|
||||
/* Event parameters contain multiple TLVs. Read each of them
|
||||
* and only keep the required data. Also, it use existing legacy
|
||||
* version field like hw_platform, hw_variant, and fw_variant
|
||||
* to keep the existing setup flow
|
||||
@@ -889,7 +889,7 @@ int btintel_send_intel_reset(struct hci_dev *hdev, u32 boot_param)
|
||||
|
||||
params.boot_param = cpu_to_le32(boot_param);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params), ¶ms,
|
||||
skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params), ¶ms,
|
||||
HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "Failed to send Intel Reset command");
|
||||
@@ -1287,7 +1287,7 @@ static void btintel_reset_to_bootloader(struct hci_dev *hdev)
|
||||
params.boot_option = 0x00;
|
||||
params.boot_param = cpu_to_le32(0x00000000);
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(params),
|
||||
skb = __hci_cmd_sync(hdev, BTINTEL_HCI_OP_RESET, sizeof(params),
|
||||
¶ms, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "FW download error recovery failed (%ld)",
|
||||
|
||||
@@ -52,6 +52,8 @@ struct intel_tlv {
|
||||
u8 val[];
|
||||
} __packed;
|
||||
|
||||
#define BTINTEL_HCI_OP_RESET 0xfc01
|
||||
|
||||
#define BTINTEL_CNVI_BLAZARI 0x900
|
||||
#define BTINTEL_CNVI_BLAZARIW 0x901
|
||||
#define BTINTEL_CNVI_GAP 0x910
|
||||
|
||||
@@ -35,12 +35,20 @@
|
||||
|
||||
/* Intel Bluetooth PCIe device id table */
|
||||
static const struct pci_device_id btintel_pcie_table[] = {
|
||||
{ BTINTEL_PCI_DEVICE(0x4D76, PCI_ANY_ID) },
|
||||
{ BTINTEL_PCI_DEVICE(0xA876, PCI_ANY_ID) },
|
||||
{ BTINTEL_PCI_DEVICE(0xE476, PCI_ANY_ID) },
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
|
||||
|
||||
struct btintel_pcie_dev_recovery {
|
||||
struct list_head list;
|
||||
u8 count;
|
||||
time64_t last_error;
|
||||
char name[];
|
||||
};
|
||||
|
||||
/* Intel PCIe uses 4 bytes of HCI type instead of 1 byte BT SIG HCI type */
|
||||
#define BTINTEL_PCIE_HCI_TYPE_LEN 4
|
||||
#define BTINTEL_PCIE_HCI_CMD_PKT 0x00000001
|
||||
@@ -62,6 +70,9 @@ MODULE_DEVICE_TABLE(pci, btintel_pcie_table);
|
||||
#define BTINTEL_PCIE_TRIGGER_REASON_USER_TRIGGER 0x17A2
|
||||
#define BTINTEL_PCIE_TRIGGER_REASON_FW_ASSERT 0x1E61
|
||||
|
||||
#define BTINTEL_PCIE_RESET_WINDOW_SECS 5
|
||||
#define BTINTEL_PCIE_FLR_MAX_RETRY 1
|
||||
|
||||
/* Alive interrupt context */
|
||||
enum {
|
||||
BTINTEL_PCIE_ROM,
|
||||
@@ -99,6 +110,36 @@ struct btintel_pcie_dbgc_ctxt {
|
||||
struct btintel_pcie_dbgc_ctxt_buf bufs[BTINTEL_PCIE_DBGC_BUFFER_COUNT];
|
||||
};
|
||||
|
||||
struct btintel_pcie_removal {
|
||||
struct pci_dev *pdev;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
static LIST_HEAD(btintel_pcie_recovery_list);
|
||||
static DEFINE_SPINLOCK(btintel_pcie_recovery_lock);
|
||||
|
||||
static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt)
|
||||
{
|
||||
switch (alive_intr_ctxt) {
|
||||
case BTINTEL_PCIE_ROM:
|
||||
return "rom";
|
||||
case BTINTEL_PCIE_FW_DL:
|
||||
return "fw_dl";
|
||||
case BTINTEL_PCIE_D0:
|
||||
return "d0";
|
||||
case BTINTEL_PCIE_D3:
|
||||
return "d3";
|
||||
case BTINTEL_PCIE_HCI_RESET:
|
||||
return "hci_reset";
|
||||
case BTINTEL_PCIE_INTEL_HCI_RESET1:
|
||||
return "intel_reset1";
|
||||
case BTINTEL_PCIE_INTEL_HCI_RESET2:
|
||||
return "intel_reset2";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* This function initializes the memory for DBGC buffers and formats the
|
||||
* DBGC fragment which consists header info and DBGC buffer's LSB, MSB and
|
||||
* size as the payload
|
||||
@@ -299,10 +340,14 @@ static inline void btintel_pcie_dump_debug_registers(struct hci_dev *hdev)
|
||||
}
|
||||
|
||||
static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
|
||||
struct sk_buff *skb)
|
||||
struct sk_buff *skb, u32 pkt_type, u16 opcode)
|
||||
{
|
||||
int ret;
|
||||
u16 tfd_index;
|
||||
u32 old_ctxt;
|
||||
bool wait_on_alive = false;
|
||||
struct hci_dev *hdev = data->hdev;
|
||||
|
||||
struct txq *txq = &data->txq;
|
||||
|
||||
tfd_index = data->ia.tr_hia[BTINTEL_PCIE_TXQ_NUM];
|
||||
@@ -310,6 +355,26 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
|
||||
if (tfd_index > txq->count)
|
||||
return -ERANGE;
|
||||
|
||||
/* Firmware raises alive interrupt on HCI_OP_RESET or
|
||||
* BTINTEL_HCI_OP_RESET
|
||||
*/
|
||||
wait_on_alive = (pkt_type == BTINTEL_PCIE_HCI_CMD_PKT &&
|
||||
(opcode == BTINTEL_HCI_OP_RESET || opcode == HCI_OP_RESET));
|
||||
|
||||
if (wait_on_alive) {
|
||||
data->gp0_received = false;
|
||||
old_ctxt = data->alive_intr_ctxt;
|
||||
data->alive_intr_ctxt =
|
||||
(opcode == BTINTEL_HCI_OP_RESET ? BTINTEL_PCIE_INTEL_HCI_RESET1 :
|
||||
BTINTEL_PCIE_HCI_RESET);
|
||||
bt_dev_dbg(data->hdev, "sending cmd: 0x%4.4x alive context changed: %s -> %s",
|
||||
opcode, btintel_pcie_alivectxt_state2str(old_ctxt),
|
||||
btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
|
||||
}
|
||||
|
||||
memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &pkt_type,
|
||||
BTINTEL_PCIE_HCI_TYPE_LEN);
|
||||
|
||||
/* Prepare for TX. It updates the TFD with the length of data and
|
||||
* address of the DMA buffer, and copy the data to the DMA buffer
|
||||
*/
|
||||
@@ -328,11 +393,24 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data,
|
||||
ret = wait_event_timeout(data->tx_wait_q, data->tx_wait_done,
|
||||
msecs_to_jiffies(BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS));
|
||||
if (!ret) {
|
||||
bt_dev_err(data->hdev, "tx completion timeout");
|
||||
bt_dev_err(data->hdev, "Timeout (%u ms) on tx completion",
|
||||
BTINTEL_PCIE_TX_WAIT_TIMEOUT_MS);
|
||||
btintel_pcie_dump_debug_registers(data->hdev);
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
if (wait_on_alive) {
|
||||
ret = wait_event_timeout(data->gp0_wait_q,
|
||||
data->gp0_received,
|
||||
msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
|
||||
if (!ret) {
|
||||
hdev->stat.err_tx++;
|
||||
bt_dev_err(hdev, "Timeout (%u ms) on alive interrupt, alive context: %s",
|
||||
BTINTEL_DEFAULT_INTR_TIMEOUT_MS,
|
||||
btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
|
||||
return -ETIME;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -811,28 +889,6 @@ static void btintel_pcie_wr_sleep_cntrl(struct btintel_pcie_data *data,
|
||||
btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_SLEEP_CTL_REG, dxstate);
|
||||
}
|
||||
|
||||
static inline char *btintel_pcie_alivectxt_state2str(u32 alive_intr_ctxt)
|
||||
{
|
||||
switch (alive_intr_ctxt) {
|
||||
case BTINTEL_PCIE_ROM:
|
||||
return "rom";
|
||||
case BTINTEL_PCIE_FW_DL:
|
||||
return "fw_dl";
|
||||
case BTINTEL_PCIE_D0:
|
||||
return "d0";
|
||||
case BTINTEL_PCIE_D3:
|
||||
return "d3";
|
||||
case BTINTEL_PCIE_HCI_RESET:
|
||||
return "hci_reset";
|
||||
case BTINTEL_PCIE_INTEL_HCI_RESET1:
|
||||
return "intel_reset1";
|
||||
case BTINTEL_PCIE_INTEL_HCI_RESET2:
|
||||
return "intel_reset2";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static int btintel_pcie_read_device_mem(struct btintel_pcie_data *data,
|
||||
void *buf, u32 dev_addr, int len)
|
||||
{
|
||||
@@ -928,11 +984,13 @@ static void btintel_pcie_msix_gp0_handler(struct btintel_pcie_data *data)
|
||||
case BTINTEL_PCIE_INTEL_HCI_RESET1:
|
||||
if (btintel_pcie_in_op(data)) {
|
||||
submit_rx = true;
|
||||
signal_waitq = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (btintel_pcie_in_iml(data)) {
|
||||
submit_rx = true;
|
||||
signal_waitq = true;
|
||||
data->alive_intr_ctxt = BTINTEL_PCIE_FW_DL;
|
||||
break;
|
||||
}
|
||||
@@ -1930,7 +1988,9 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
|
||||
__u16 opcode = ~0;
|
||||
int ret;
|
||||
u32 type;
|
||||
u32 old_ctxt;
|
||||
|
||||
if (test_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags))
|
||||
return -ENODEV;
|
||||
|
||||
/* Due to the fw limitation, the type header of the packet should be
|
||||
* 4 bytes unlike 1 byte for UART. In UART, the firmware can read
|
||||
@@ -1955,17 +2015,14 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
|
||||
struct hci_command_hdr *cmd = (void *)skb->data;
|
||||
__u16 opcode = le16_to_cpu(cmd->opcode);
|
||||
|
||||
/* When the 0xfc01 command is issued to boot into
|
||||
* the operational firmware, it will actually not
|
||||
* send a command complete event. To keep the flow
|
||||
/* When the BTINTEL_HCI_OP_RESET command is issued to
|
||||
* boot into the operational firmware, it will actually
|
||||
* not send a command complete event. To keep the flow
|
||||
* control working inject that event here.
|
||||
*/
|
||||
if (opcode == 0xfc01)
|
||||
if (opcode == BTINTEL_HCI_OP_RESET)
|
||||
btintel_pcie_inject_cmd_complete(hdev, opcode);
|
||||
}
|
||||
/* Firmware raises alive interrupt on HCI_OP_RESET */
|
||||
if (opcode == HCI_OP_RESET)
|
||||
data->gp0_received = false;
|
||||
|
||||
hdev->stat.cmd_tx++;
|
||||
break;
|
||||
@@ -1984,38 +2041,14 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev,
|
||||
bt_dev_err(hdev, "Unknown HCI packet type");
|
||||
return -EILSEQ;
|
||||
}
|
||||
memcpy(skb_push(skb, BTINTEL_PCIE_HCI_TYPE_LEN), &type,
|
||||
BTINTEL_PCIE_HCI_TYPE_LEN);
|
||||
|
||||
ret = btintel_pcie_send_sync(data, skb);
|
||||
ret = btintel_pcie_send_sync(data, skb, type, opcode);
|
||||
if (ret) {
|
||||
hdev->stat.err_tx++;
|
||||
bt_dev_err(hdev, "Failed to send frame (%d)", ret);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if (type == BTINTEL_PCIE_HCI_CMD_PKT &&
|
||||
(opcode == HCI_OP_RESET || opcode == 0xfc01)) {
|
||||
old_ctxt = data->alive_intr_ctxt;
|
||||
data->alive_intr_ctxt =
|
||||
(opcode == 0xfc01 ? BTINTEL_PCIE_INTEL_HCI_RESET1 :
|
||||
BTINTEL_PCIE_HCI_RESET);
|
||||
bt_dev_dbg(data->hdev, "sent cmd: 0x%4.4x alive context changed: %s -> %s",
|
||||
opcode, btintel_pcie_alivectxt_state2str(old_ctxt),
|
||||
btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
|
||||
if (opcode == HCI_OP_RESET) {
|
||||
ret = wait_event_timeout(data->gp0_wait_q,
|
||||
data->gp0_received,
|
||||
msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
|
||||
if (!ret) {
|
||||
hdev->stat.err_tx++;
|
||||
bt_dev_err(hdev, "No alive interrupt received for %s",
|
||||
btintel_pcie_alivectxt_state2str(data->alive_intr_ctxt));
|
||||
ret = -ETIME;
|
||||
goto exit_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
hdev->stat.byte_tx += skb->len;
|
||||
kfree_skb(skb);
|
||||
|
||||
@@ -2192,9 +2225,191 @@ static int btintel_pcie_setup(struct hci_dev *hdev)
|
||||
}
|
||||
btintel_pcie_start_rx(data);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
set_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct btintel_pcie_dev_recovery *
|
||||
btintel_pcie_get_recovery(struct pci_dev *pdev, struct device *dev)
|
||||
{
|
||||
struct btintel_pcie_dev_recovery *tmp, *data = NULL;
|
||||
const char *name = pci_name(pdev);
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
|
||||
spin_lock(&btintel_pcie_recovery_lock);
|
||||
list_for_each_entry(tmp, &btintel_pcie_recovery_list, list) {
|
||||
if (strcmp(tmp->name, name))
|
||||
continue;
|
||||
data = tmp;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&btintel_pcie_recovery_lock);
|
||||
|
||||
if (data) {
|
||||
bt_dev_dbg(hdev, "Found restart data for BDF: %s", data->name);
|
||||
return data;
|
||||
}
|
||||
|
||||
data = kzalloc(struct_size(data, name, strlen(name) + 1), GFP_ATOMIC);
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
strscpy_pad(data->name, name, strlen(name) + 1);
|
||||
spin_lock(&btintel_pcie_recovery_lock);
|
||||
list_add_tail(&data->list, &btintel_pcie_recovery_list);
|
||||
spin_unlock(&btintel_pcie_recovery_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void btintel_pcie_free_restart_list(void)
|
||||
{
|
||||
struct btintel_pcie_dev_recovery *tmp;
|
||||
|
||||
while ((tmp = list_first_entry_or_null(&btintel_pcie_recovery_list,
|
||||
typeof(*tmp), list))) {
|
||||
list_del(&tmp->list);
|
||||
kfree(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static void btintel_pcie_inc_recovery_count(struct pci_dev *pdev,
|
||||
struct device *dev)
|
||||
{
|
||||
struct btintel_pcie_dev_recovery *data;
|
||||
time64_t retry_window;
|
||||
|
||||
data = btintel_pcie_get_recovery(pdev, dev);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
retry_window = ktime_get_boottime_seconds() - data->last_error;
|
||||
if (data->count == 0) {
|
||||
data->last_error = ktime_get_boottime_seconds();
|
||||
data->count++;
|
||||
} else if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
|
||||
data->count <= BTINTEL_PCIE_FLR_MAX_RETRY) {
|
||||
data->count++;
|
||||
} else if (retry_window > BTINTEL_PCIE_RESET_WINDOW_SECS) {
|
||||
data->last_error = 0;
|
||||
data->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data);
|
||||
|
||||
static void btintel_pcie_removal_work(struct work_struct *wk)
|
||||
{
|
||||
struct btintel_pcie_removal *removal =
|
||||
container_of(wk, struct btintel_pcie_removal, work);
|
||||
struct pci_dev *pdev = removal->pdev;
|
||||
struct btintel_pcie_data *data;
|
||||
int err;
|
||||
|
||||
pci_lock_rescan_remove();
|
||||
|
||||
if (!pdev->bus)
|
||||
goto error;
|
||||
|
||||
data = pci_get_drvdata(pdev);
|
||||
|
||||
btintel_pcie_disable_interrupts(data);
|
||||
btintel_pcie_synchronize_irqs(data);
|
||||
|
||||
flush_work(&data->rx_work);
|
||||
flush_work(&data->hdev->dump.dump_rx);
|
||||
|
||||
bt_dev_dbg(data->hdev, "Release bluetooth interface");
|
||||
btintel_pcie_release_hdev(data);
|
||||
|
||||
err = pci_reset_function(pdev);
|
||||
if (err) {
|
||||
BT_ERR("Failed resetting the pcie device (%d)", err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
btintel_pcie_enable_interrupts(data);
|
||||
btintel_pcie_config_msix(data);
|
||||
|
||||
err = btintel_pcie_enable_bt(data);
|
||||
if (err) {
|
||||
BT_ERR("Failed to enable bluetooth hardware after reset (%d)",
|
||||
err);
|
||||
goto error;
|
||||
}
|
||||
|
||||
btintel_pcie_reset_ia(data);
|
||||
btintel_pcie_start_rx(data);
|
||||
data->flags = 0;
|
||||
|
||||
err = btintel_pcie_setup_hdev(data);
|
||||
if (err) {
|
||||
BT_ERR("Failed registering hdev (%d)", err);
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
pci_dev_put(pdev);
|
||||
pci_unlock_rescan_remove();
|
||||
kfree(removal);
|
||||
}
|
||||
|
||||
static void btintel_pcie_reset(struct hci_dev *hdev)
|
||||
{
|
||||
struct btintel_pcie_removal *removal;
|
||||
struct btintel_pcie_data *data;
|
||||
|
||||
data = hci_get_drvdata(hdev);
|
||||
|
||||
if (!test_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags))
|
||||
return;
|
||||
|
||||
if (test_and_set_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags))
|
||||
return;
|
||||
|
||||
removal = kzalloc(sizeof(*removal), GFP_ATOMIC);
|
||||
if (!removal)
|
||||
return;
|
||||
|
||||
removal->pdev = data->pdev;
|
||||
INIT_WORK(&removal->work, btintel_pcie_removal_work);
|
||||
pci_dev_get(removal->pdev);
|
||||
schedule_work(&removal->work);
|
||||
}
|
||||
|
||||
static void btintel_pcie_hw_error(struct hci_dev *hdev, u8 code)
|
||||
{
|
||||
struct btintel_pcie_dev_recovery *data;
|
||||
struct btintel_pcie_data *dev_data = hci_get_drvdata(hdev);
|
||||
struct pci_dev *pdev = dev_data->pdev;
|
||||
time64_t retry_window;
|
||||
|
||||
if (code == 0x13) {
|
||||
bt_dev_err(hdev, "Encountered top exception");
|
||||
return;
|
||||
}
|
||||
|
||||
data = btintel_pcie_get_recovery(pdev, &hdev->dev);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
retry_window = ktime_get_boottime_seconds() - data->last_error;
|
||||
|
||||
if (retry_window < BTINTEL_PCIE_RESET_WINDOW_SECS &&
|
||||
data->count >= BTINTEL_PCIE_FLR_MAX_RETRY) {
|
||||
bt_dev_err(hdev, "Exhausted maximum: %d recovery attempts: %d",
|
||||
BTINTEL_PCIE_FLR_MAX_RETRY, data->count);
|
||||
bt_dev_dbg(hdev, "Boot time: %lld seconds",
|
||||
ktime_get_boottime_seconds());
|
||||
bt_dev_dbg(hdev, "last error at: %lld seconds",
|
||||
data->last_error);
|
||||
return;
|
||||
}
|
||||
btintel_pcie_inc_recovery_count(pdev, &hdev->dev);
|
||||
btintel_pcie_reset(hdev);
|
||||
}
|
||||
|
||||
static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
|
||||
{
|
||||
int err;
|
||||
@@ -2216,9 +2431,10 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
|
||||
hdev->send = btintel_pcie_send_frame;
|
||||
hdev->setup = btintel_pcie_setup;
|
||||
hdev->shutdown = btintel_shutdown_combined;
|
||||
hdev->hw_error = btintel_hw_error;
|
||||
hdev->hw_error = btintel_pcie_hw_error;
|
||||
hdev->set_diag = btintel_set_diag;
|
||||
hdev->set_bdaddr = btintel_set_bdaddr;
|
||||
hdev->reset = btintel_pcie_reset;
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
@@ -2366,7 +2582,20 @@ static struct pci_driver btintel_pcie_driver = {
|
||||
.driver.coredump = btintel_pcie_coredump
|
||||
#endif
|
||||
};
|
||||
module_pci_driver(btintel_pcie_driver);
|
||||
|
||||
static int __init btintel_pcie_init(void)
|
||||
{
|
||||
return pci_register_driver(&btintel_pcie_driver);
|
||||
}
|
||||
|
||||
static void __exit btintel_pcie_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&btintel_pcie_driver);
|
||||
btintel_pcie_free_restart_list();
|
||||
}
|
||||
|
||||
module_init(btintel_pcie_init);
|
||||
module_exit(btintel_pcie_exit);
|
||||
|
||||
MODULE_AUTHOR("Tedd Ho-Jeong An <tedd.an@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Bluetooth PCIe transport driver ver " VERSION);
|
||||
|
||||
@@ -117,7 +117,9 @@ enum {
|
||||
enum {
|
||||
BTINTEL_PCIE_CORE_HALTED,
|
||||
BTINTEL_PCIE_HWEXP_INPROGRESS,
|
||||
BTINTEL_PCIE_COREDUMP_INPROGRESS
|
||||
BTINTEL_PCIE_COREDUMP_INPROGRESS,
|
||||
BTINTEL_PCIE_RECOVERY_IN_PROGRESS,
|
||||
BTINTEL_PCIE_SETUP_DONE
|
||||
};
|
||||
|
||||
enum btintel_pcie_tlv_type {
|
||||
|
||||
@@ -316,7 +316,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count,
|
||||
|
||||
/* Resync STP when unexpected data is being read */
|
||||
if (shdr->prefix != 0x80 || bdev->stp_dlen > 2048) {
|
||||
bt_dev_err(bdev->hdev, "stp format unexpect (%d, %d)",
|
||||
bt_dev_err(bdev->hdev, "stp format unexpected (%d, %d)",
|
||||
shdr->prefix, bdev->stp_dlen);
|
||||
bdev->stp_cursor = 2;
|
||||
bdev->stp_dlen = 0;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
@@ -73,7 +75,8 @@
|
||||
#define FW_AUTH_ENC 0xc0
|
||||
|
||||
#define HCI_NXP_PRI_BAUDRATE 115200
|
||||
#define HCI_NXP_SEC_BAUDRATE 3000000
|
||||
#define HCI_NXP_SEC_BAUDRATE_3M 3000000
|
||||
#define HCI_NXP_SEC_BAUDRATE_4M 4000000
|
||||
|
||||
#define MAX_FW_FILE_NAME_LEN 50
|
||||
|
||||
@@ -201,12 +204,14 @@ struct btnxpuart_dev {
|
||||
u32 new_baudrate;
|
||||
u32 current_baudrate;
|
||||
u32 fw_init_baudrate;
|
||||
u32 secondary_baudrate;
|
||||
enum bootloader_param_change timeout_changed;
|
||||
enum bootloader_param_change baudrate_changed;
|
||||
bool helper_downloaded;
|
||||
|
||||
struct ps_data psdata;
|
||||
struct btnxpuart_data *nxp_data;
|
||||
struct reset_control *pdn;
|
||||
};
|
||||
|
||||
#define NXP_V1_FW_REQ_PKT 0xa5
|
||||
@@ -365,17 +370,26 @@ static u8 crc8_table[CRC8_TABLE_SIZE];
|
||||
|
||||
static struct sk_buff *nxp_drv_send_cmd(struct hci_dev *hdev, u16 opcode,
|
||||
u32 plen,
|
||||
void *param)
|
||||
void *param,
|
||||
bool resp)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
/* set flag to prevent nxp_enqueue from parsing values from this command and
|
||||
* calling hci_cmd_sync_queue() again.
|
||||
*/
|
||||
psdata->driver_sent_cmd = true;
|
||||
skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_CMD_TIMEOUT);
|
||||
if (resp) {
|
||||
skb = __hci_cmd_sync(hdev, opcode, plen, param, HCI_CMD_TIMEOUT);
|
||||
} else {
|
||||
__hci_cmd_send(hdev, opcode, plen, param);
|
||||
/* Allow command to be sent before tx_work is cancelled
|
||||
* by btnxpuart_flush()
|
||||
*/
|
||||
msleep(20);
|
||||
}
|
||||
psdata->driver_sent_cmd = false;
|
||||
|
||||
return skb;
|
||||
@@ -595,7 +609,8 @@ static int send_ps_cmd(struct hci_dev *hdev, void *data)
|
||||
pcmd.ps_cmd = BT_PS_DISABLE;
|
||||
pcmd.c2h_ps_interval = __cpu_to_le16(psdata->c2h_ps_interval);
|
||||
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_AUTO_SLEEP_MODE, sizeof(pcmd), &pcmd);
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_AUTO_SLEEP_MODE, sizeof(pcmd),
|
||||
&pcmd, true);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "Setting Power Save mode failed (%ld)", PTR_ERR(skb));
|
||||
return PTR_ERR(skb);
|
||||
@@ -644,7 +659,8 @@ static int send_wakeup_method_cmd(struct hci_dev *hdev, void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd), &pcmd);
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_WAKEUP_METHOD, sizeof(pcmd),
|
||||
&pcmd, true);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "Setting wake-up method failed (%ld)", PTR_ERR(skb));
|
||||
return PTR_ERR(skb);
|
||||
@@ -802,7 +818,10 @@ static bool nxp_fw_change_baudrate(struct hci_dev *hdev, u16 req_len)
|
||||
nxpdev->fw_v3_offset_correction += req_len;
|
||||
} else if (req_len == sizeof(uart_config)) {
|
||||
uart_config.clkdiv.address = __cpu_to_le32(clkdivaddr);
|
||||
uart_config.clkdiv.value = __cpu_to_le32(0x00c00000);
|
||||
if (nxpdev->new_baudrate == HCI_NXP_SEC_BAUDRATE_4M)
|
||||
uart_config.clkdiv.value = __cpu_to_le32(0x01000000);
|
||||
else
|
||||
uart_config.clkdiv.value = __cpu_to_le32(0x00c00000);
|
||||
uart_config.uartdiv.address = __cpu_to_le32(uartdivaddr);
|
||||
uart_config.uartdiv.value = __cpu_to_le32(1);
|
||||
uart_config.mcr.address = __cpu_to_le32(uartmcraddr);
|
||||
@@ -966,12 +985,13 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
goto free_skb;
|
||||
}
|
||||
if (nxpdev->baudrate_changed != changed) {
|
||||
nxpdev->new_baudrate = nxpdev->secondary_baudrate;
|
||||
if (nxp_fw_change_baudrate(hdev, len)) {
|
||||
nxpdev->baudrate_changed = changed;
|
||||
serdev_device_set_baudrate(nxpdev->serdev,
|
||||
HCI_NXP_SEC_BAUDRATE);
|
||||
nxpdev->secondary_baudrate);
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE;
|
||||
nxpdev->current_baudrate = nxpdev->secondary_baudrate;
|
||||
}
|
||||
goto free_skb;
|
||||
}
|
||||
@@ -992,7 +1012,7 @@ static int nxp_recv_fw_req_v1(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
nxpdev->helper_downloaded = true;
|
||||
serdev_device_wait_until_sent(nxpdev->serdev, 0);
|
||||
serdev_device_set_baudrate(nxpdev->serdev,
|
||||
HCI_NXP_SEC_BAUDRATE);
|
||||
HCI_NXP_SEC_BAUDRATE_3M);
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
} else {
|
||||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
@@ -1216,12 +1236,13 @@ static int nxp_recv_fw_req_v3(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
if (nxpdev->baudrate_changed != changed) {
|
||||
nxpdev->new_baudrate = nxpdev->secondary_baudrate;
|
||||
if (nxp_fw_change_baudrate(hdev, len)) {
|
||||
nxpdev->baudrate_changed = cmd_sent;
|
||||
serdev_device_set_baudrate(nxpdev->serdev,
|
||||
HCI_NXP_SEC_BAUDRATE);
|
||||
nxpdev->secondary_baudrate);
|
||||
serdev_device_set_flow_control(nxpdev->serdev, true);
|
||||
nxpdev->current_baudrate = HCI_NXP_SEC_BAUDRATE;
|
||||
nxpdev->current_baudrate = nxpdev->secondary_baudrate;
|
||||
}
|
||||
goto free_skb;
|
||||
}
|
||||
@@ -1265,7 +1286,8 @@ static int nxp_set_baudrate_cmd(struct hci_dev *hdev, void *data)
|
||||
if (!psdata)
|
||||
return 0;
|
||||
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_SET_OPER_SPEED, 4, (u8 *)&new_baudrate);
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_SET_OPER_SPEED, 4,
|
||||
(u8 *)&new_baudrate, true);
|
||||
if (IS_ERR(skb)) {
|
||||
bt_dev_err(hdev, "Setting baudrate failed (%ld)", PTR_ERR(skb));
|
||||
return PTR_ERR(skb);
|
||||
@@ -1323,7 +1345,7 @@ static void nxp_coredump(struct hci_dev *hdev)
|
||||
struct sk_buff *skb;
|
||||
u8 pcmd = 2;
|
||||
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_TRIGGER_DUMP, 1, &pcmd);
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_TRIGGER_DUMP, 1, &pcmd, true);
|
||||
if (IS_ERR(skb))
|
||||
bt_dev_err(hdev, "Failed to trigger FW Dump. (%ld)", PTR_ERR(skb));
|
||||
else
|
||||
@@ -1365,7 +1387,6 @@ static int nxp_process_fw_dump(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
||||
if (buf_len == 0) {
|
||||
bt_dev_warn(hdev, "==== FW dump complete ===");
|
||||
clear_bit(BTNXPUART_FW_DUMP_IN_PROGRESS, &nxpdev->tx_state);
|
||||
hci_devcd_complete(hdev);
|
||||
nxp_set_ind_reset(hdev, NULL);
|
||||
}
|
||||
@@ -1419,6 +1440,10 @@ static int nxp_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
|
||||
static int nxp_setup(struct hci_dev *hdev)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct serdev_device *serdev = nxpdev->serdev;
|
||||
char device_string[30];
|
||||
char event_string[50];
|
||||
char *envp[] = {device_string, event_string, NULL};
|
||||
int err = 0;
|
||||
|
||||
if (nxp_check_boot_sign(nxpdev)) {
|
||||
@@ -1431,6 +1456,12 @@ static int nxp_setup(struct hci_dev *hdev)
|
||||
clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
}
|
||||
|
||||
snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev));
|
||||
snprintf(event_string, 50, "BTNXPUART_STATE=FW_READY");
|
||||
bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string,
|
||||
event_string);
|
||||
kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp);
|
||||
|
||||
serdev_device_set_baudrate(nxpdev->serdev, nxpdev->fw_init_baudrate);
|
||||
nxpdev->current_baudrate = nxpdev->fw_init_baudrate;
|
||||
|
||||
@@ -1447,8 +1478,8 @@ static int nxp_post_init(struct hci_dev *hdev)
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct ps_data *psdata = &nxpdev->psdata;
|
||||
|
||||
if (nxpdev->current_baudrate != HCI_NXP_SEC_BAUDRATE) {
|
||||
nxpdev->new_baudrate = HCI_NXP_SEC_BAUDRATE;
|
||||
if (nxpdev->current_baudrate != nxpdev->secondary_baudrate) {
|
||||
nxpdev->new_baudrate = nxpdev->secondary_baudrate;
|
||||
nxp_set_baudrate_cmd(hdev, NULL);
|
||||
}
|
||||
if (psdata->cur_h2c_wakeupmode != psdata->h2c_wakeupmode)
|
||||
@@ -1479,7 +1510,13 @@ static int nxp_shutdown(struct hci_dev *hdev)
|
||||
u8 pcmd = 0;
|
||||
|
||||
if (ind_reset_in_progress(nxpdev)) {
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1, &pcmd);
|
||||
if (test_and_clear_bit(BTNXPUART_FW_DUMP_IN_PROGRESS,
|
||||
&nxpdev->tx_state))
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1,
|
||||
&pcmd, false);
|
||||
else
|
||||
skb = nxp_drv_send_cmd(hdev, HCI_NXP_IND_RESET, 1,
|
||||
&pcmd, true);
|
||||
serdev_device_set_flow_control(nxpdev->serdev, false);
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
/* HCI_NXP_IND_RESET command may not returns any response */
|
||||
@@ -1745,11 +1782,41 @@ static const struct serdev_device_ops btnxpuart_client_ops = {
|
||||
.write_wakeup = btnxpuart_write_wakeup,
|
||||
};
|
||||
|
||||
static void nxp_coredump_notify(struct hci_dev *hdev, int state)
|
||||
{
|
||||
struct btnxpuart_dev *nxpdev = hci_get_drvdata(hdev);
|
||||
struct serdev_device *serdev = nxpdev->serdev;
|
||||
char device_string[30];
|
||||
char event_string[50];
|
||||
char *envp[] = {device_string, event_string, NULL};
|
||||
|
||||
snprintf(device_string, 30, "BTNXPUART_DEV=%s", dev_name(&serdev->dev));
|
||||
switch (state) {
|
||||
case HCI_DEVCOREDUMP_ACTIVE:
|
||||
snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_ACTIVE");
|
||||
break;
|
||||
case HCI_DEVCOREDUMP_DONE:
|
||||
snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_DONE");
|
||||
break;
|
||||
case HCI_DEVCOREDUMP_TIMEOUT:
|
||||
snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_TIMEOUT");
|
||||
break;
|
||||
default:
|
||||
snprintf(event_string, 50, "BTNXPUART_STATE=FW_DUMP_STATE_%d",
|
||||
state);
|
||||
break;
|
||||
}
|
||||
bt_dev_dbg(hdev, "==== Send uevent: %s:%s ===", device_string,
|
||||
event_string);
|
||||
kobject_uevent_env(&serdev->dev.kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
static int nxp_serdev_probe(struct serdev_device *serdev)
|
||||
{
|
||||
struct hci_dev *hdev;
|
||||
struct btnxpuart_dev *nxpdev;
|
||||
bdaddr_t ba = {0};
|
||||
int err;
|
||||
|
||||
nxpdev = devm_kzalloc(&serdev->dev, sizeof(*nxpdev), GFP_KERNEL);
|
||||
if (!nxpdev)
|
||||
@@ -1773,10 +1840,31 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
||||
if (!nxpdev->fw_init_baudrate)
|
||||
nxpdev->fw_init_baudrate = FW_INIT_BAUDRATE;
|
||||
|
||||
device_property_read_u32(&nxpdev->serdev->dev, "max-speed",
|
||||
&nxpdev->secondary_baudrate);
|
||||
if (!nxpdev->secondary_baudrate ||
|
||||
(nxpdev->secondary_baudrate != HCI_NXP_SEC_BAUDRATE_3M &&
|
||||
nxpdev->secondary_baudrate != HCI_NXP_SEC_BAUDRATE_4M)) {
|
||||
if (nxpdev->secondary_baudrate)
|
||||
dev_err(&serdev->dev,
|
||||
"Invalid max-speed. Using default 3000000.");
|
||||
nxpdev->secondary_baudrate = HCI_NXP_SEC_BAUDRATE_3M;
|
||||
}
|
||||
|
||||
set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
|
||||
|
||||
crc8_populate_msb(crc8_table, POLYNOMIAL8);
|
||||
|
||||
nxpdev->pdn = devm_reset_control_get_optional_shared(&serdev->dev, NULL);
|
||||
if (IS_ERR(nxpdev->pdn))
|
||||
return PTR_ERR(nxpdev->pdn);
|
||||
|
||||
err = devm_regulator_get_enable(&serdev->dev, "vcc");
|
||||
if (err) {
|
||||
dev_err(&serdev->dev, "Failed to enable vcc regulator\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Initialize and register HCI device */
|
||||
hdev = hci_alloc_dev();
|
||||
if (!hdev) {
|
||||
@@ -1784,6 +1872,8 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
reset_control_deassert(nxpdev->pdn);
|
||||
|
||||
nxpdev->hdev = hdev;
|
||||
|
||||
hdev->bus = HCI_UART;
|
||||
@@ -1817,11 +1907,13 @@ static int nxp_serdev_probe(struct serdev_device *serdev)
|
||||
if (ps_setup(hdev))
|
||||
goto probe_fail;
|
||||
|
||||
hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr, NULL);
|
||||
hci_devcd_register(hdev, nxp_coredump, nxp_coredump_hdr,
|
||||
nxp_coredump_notify);
|
||||
|
||||
return 0;
|
||||
|
||||
probe_fail:
|
||||
reset_control_assert(nxpdev->pdn);
|
||||
hci_free_dev(hdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1849,6 +1941,7 @@ static void nxp_serdev_remove(struct serdev_device *serdev)
|
||||
|
||||
ps_cleanup(nxpdev);
|
||||
hci_unregister_dev(hdev);
|
||||
reset_control_assert(nxpdev->pdn);
|
||||
hci_free_dev(hdev);
|
||||
}
|
||||
|
||||
|
||||
@@ -693,7 +693,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev,
|
||||
|
||||
/* Loop from the end of the firmware parsing instructions, until
|
||||
* we find an instruction that identifies the "project ID" for the
|
||||
* hardware supported by this firwmare file.
|
||||
* hardware supported by this firmware file.
|
||||
* Once we have that, we double-check that project_id is suitable
|
||||
* for the hardware we are working with.
|
||||
*/
|
||||
|
||||
@@ -298,44 +298,6 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* QCA WCN6855 chipset */
|
||||
{ USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0c9), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
@@ -344,18 +306,28 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0cb), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0cc), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0ce), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0d0), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0d6), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0de), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0df), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0e1), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0e3), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0ea), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe0ec), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04ca, 0x3022), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04ca, 0x3023), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04ca, 0x3024), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
@@ -368,6 +340,36 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x04ca, 0x3a27), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0cf3, 0xe600), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9108), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9109), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9208), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9209), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9308), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9309), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9408), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9409), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9508), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9509), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9608), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9609), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x10ab, 0x9f09), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x28de, 0x1401), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* QCA WCN785x chipset */
|
||||
{ USB_DEVICE(0x0cf3, 0xe700), .driver_info = BTUSB_QCA_WCN6855 |
|
||||
@@ -515,6 +517,11 @@ static const struct usb_device_id quirks_table[] = {
|
||||
/* Realtek 8851BE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0xb850), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3600), .driver_info = BTUSB_REALTEK },
|
||||
{ USB_DEVICE(0x13d3, 0x3601), .driver_info = BTUSB_REALTEK },
|
||||
|
||||
/* Realtek 8851BU Bluetooth devices */
|
||||
{ USB_DEVICE(0x3625, 0x010b), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Realtek 8852AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK |
|
||||
@@ -565,6 +572,8 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3591), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3618), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe123), .driver_info = BTUSB_REALTEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe125), .driver_info = BTUSB_REALTEK |
|
||||
@@ -705,6 +714,8 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe139), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe14e), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe14f), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x0489, 0xe150), .driver_info = BTUSB_MEDIATEK |
|
||||
@@ -725,6 +736,8 @@ static const struct usb_device_id quirks_table[] = {
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x13d3, 0x3630), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
{ USB_DEVICE(0x2c7c, 0x7009), .driver_info = BTUSB_MEDIATEK |
|
||||
BTUSB_WIDEBAND_SPEECH },
|
||||
|
||||
/* Additional Realtek 8723AE Bluetooth devices */
|
||||
{ USB_DEVICE(0x0930, 0x021d), .driver_info = BTUSB_REALTEK },
|
||||
@@ -2594,12 +2607,12 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
else
|
||||
urb = alloc_ctrl_urb(hdev, skb);
|
||||
|
||||
/* When the 0xfc01 command is issued to boot into
|
||||
* the operational firmware, it will actually not
|
||||
* send a command complete event. To keep the flow
|
||||
/* When the BTINTEL_HCI_OP_RESET command is issued to
|
||||
* boot into the operational firmware, it will actually
|
||||
* not send a command complete event. To keep the flow
|
||||
* control working inject that event here.
|
||||
*/
|
||||
if (opcode == 0xfc01)
|
||||
if (opcode == BTINTEL_HCI_OP_RESET)
|
||||
inject_cmd_complete(hdev, opcode);
|
||||
} else {
|
||||
urb = alloc_ctrl_urb(hdev, skb);
|
||||
@@ -3179,6 +3192,12 @@ struct qca_device_info {
|
||||
u8 ver_offset; /* offset of version structure in rampatch */
|
||||
};
|
||||
|
||||
struct qca_custom_firmware {
|
||||
u32 rom_version;
|
||||
u16 board_id;
|
||||
const char *subdirectory;
|
||||
};
|
||||
|
||||
static const struct qca_device_info qca_devices_table[] = {
|
||||
{ 0x00000100, 20, 4, 8 }, /* Rome 1.0 */
|
||||
{ 0x00000101, 20, 4, 8 }, /* Rome 1.1 */
|
||||
@@ -3192,6 +3211,11 @@ static const struct qca_device_info qca_devices_table[] = {
|
||||
{ 0x00190200, 40, 4, 16 }, /* WCN785x 2.0 */
|
||||
};
|
||||
|
||||
static const struct qca_custom_firmware qca_custom_btfws[] = {
|
||||
{ 0x00130201, 0x030A, "QCA2066" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static u16 qca_extract_board_id(const struct qca_version *ver)
|
||||
{
|
||||
u16 flag = le16_to_cpu(ver->flag);
|
||||
@@ -3218,6 +3242,26 @@ static u16 qca_extract_board_id(const struct qca_version *ver)
|
||||
return board_id;
|
||||
}
|
||||
|
||||
static const char *qca_get_fw_subdirectory(const struct qca_version *ver)
|
||||
{
|
||||
const struct qca_custom_firmware *ptr;
|
||||
u32 rom_ver;
|
||||
u16 board_id;
|
||||
|
||||
rom_ver = le32_to_cpu(ver->rom_version);
|
||||
board_id = qca_extract_board_id(ver);
|
||||
if (!board_id)
|
||||
return NULL;
|
||||
|
||||
for (ptr = qca_custom_btfws; ptr->rom_version; ptr++) {
|
||||
if (ptr->rom_version == rom_ver &&
|
||||
ptr->board_id == board_id)
|
||||
return ptr->subdirectory;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int btusb_qca_send_vendor_req(struct usb_device *udev, u8 request,
|
||||
void *data, u16 size)
|
||||
{
|
||||
@@ -3322,15 +3366,22 @@ static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev,
|
||||
{
|
||||
struct qca_rampatch_version *rver;
|
||||
const struct firmware *fw;
|
||||
const char *fw_subdir;
|
||||
u32 ver_rom, ver_patch, rver_rom;
|
||||
u16 rver_rom_low, rver_rom_high, rver_patch;
|
||||
char fwname[64];
|
||||
char fwname[80];
|
||||
int err;
|
||||
|
||||
ver_rom = le32_to_cpu(ver->rom_version);
|
||||
ver_patch = le32_to_cpu(ver->patch_version);
|
||||
|
||||
snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", ver_rom);
|
||||
fw_subdir = qca_get_fw_subdirectory(ver);
|
||||
if (fw_subdir)
|
||||
snprintf(fwname, sizeof(fwname), "qca/%s/rampatch_usb_%08x.bin",
|
||||
fw_subdir, ver_rom);
|
||||
else
|
||||
snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin",
|
||||
ver_rom);
|
||||
|
||||
err = request_firmware(&fw, fwname, &hdev->dev);
|
||||
if (err) {
|
||||
@@ -3374,10 +3425,11 @@ static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size,
|
||||
const struct qca_version *ver)
|
||||
{
|
||||
u32 rom_version = le32_to_cpu(ver->rom_version);
|
||||
const char *variant;
|
||||
const char *variant, *fw_subdir;
|
||||
int len;
|
||||
u16 board_id;
|
||||
|
||||
fw_subdir = qca_get_fw_subdirectory(ver);
|
||||
board_id = qca_extract_board_id(ver);
|
||||
|
||||
switch (le32_to_cpu(ver->ram_version)) {
|
||||
@@ -3390,7 +3442,12 @@ static void btusb_generate_qca_nvm_name(char *fwname, size_t max_size,
|
||||
break;
|
||||
}
|
||||
|
||||
len = snprintf(fwname, max_size, "qca/nvm_usb_%08x", rom_version);
|
||||
if (fw_subdir)
|
||||
len = snprintf(fwname, max_size, "qca/%s/nvm_usb_%08x",
|
||||
fw_subdir, rom_version);
|
||||
else
|
||||
len = snprintf(fwname, max_size, "qca/nvm_usb_%08x",
|
||||
rom_version);
|
||||
if (variant)
|
||||
len += snprintf(fwname + len, max_size - len, "%s", variant);
|
||||
if (board_id)
|
||||
@@ -3403,7 +3460,7 @@ static int btusb_setup_qca_load_nvm(struct hci_dev *hdev,
|
||||
const struct qca_device_info *info)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
char fwname[64];
|
||||
char fwname[80];
|
||||
int err;
|
||||
|
||||
btusb_generate_qca_nvm_name(fwname, sizeof(fwname), ver);
|
||||
@@ -3802,6 +3859,8 @@ static int btusb_hci_drv_supported_altsettings(struct hci_dev *hdev, void *data,
|
||||
|
||||
/* There are at most 7 alt (0 - 6) */
|
||||
rp = kmalloc(sizeof(*rp) + 7, GFP_KERNEL);
|
||||
if (!rp)
|
||||
return -ENOMEM;
|
||||
|
||||
rp->num = 0;
|
||||
if (!drvdata->isoc)
|
||||
|
||||
@@ -420,7 +420,7 @@ struct bcm4377_ring_state {
|
||||
* payloads_dma:DMA address for payload buffer
|
||||
* events: pointer to array of completions if waiting is allowed
|
||||
* msgids: bitmap to keep track of used message ids
|
||||
* lock: Spinlock to protect access to ring structurs used in the irq handler
|
||||
* lock: Spinlock to protect access to ring structures used in the irq handler
|
||||
*/
|
||||
struct bcm4377_transfer_ring {
|
||||
enum bcm4377_transfer_ring_id ring_id;
|
||||
|
||||
@@ -1029,12 +1029,12 @@ static struct sk_buff *intel_dequeue(struct hci_uart *hu)
|
||||
struct hci_command_hdr *cmd = (void *)skb->data;
|
||||
__u16 opcode = le16_to_cpu(cmd->opcode);
|
||||
|
||||
/* When the 0xfc01 command is issued to boot into
|
||||
* the operational firmware, it will actually not
|
||||
* send a command complete event. To keep the flow
|
||||
* control working inject that event here.
|
||||
/* When the BTINTEL_HCI_OP_RESET command is issued to boot into
|
||||
* the operational firmware, it will actually not send a command
|
||||
* complete event. To keep the flow control working inject that
|
||||
* event here.
|
||||
*/
|
||||
if (opcode == 0xfc01)
|
||||
if (opcode == BTINTEL_HCI_OP_RESET)
|
||||
inject_cmd_complete(hu->hdev, opcode);
|
||||
}
|
||||
|
||||
|
||||
@@ -1264,6 +1264,7 @@ static const struct h4_recv_pkt qca_recv_pkts[] = {
|
||||
{ H4_RECV_ACL, .recv = qca_recv_acl_data },
|
||||
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
||||
{ H4_RECV_EVENT, .recv = qca_recv_event },
|
||||
{ H4_RECV_ISO, .recv = hci_recv_frame },
|
||||
{ QCA_IBS_WAKE_IND_EVENT, .recv = qca_ibs_wake_ind },
|
||||
{ QCA_IBS_WAKE_ACK_EVENT, .recv = qca_ibs_wake_ack },
|
||||
{ QCA_IBS_SLEEP_IND_EVENT, .recv = qca_ibs_sleep_ind },
|
||||
|
||||
@@ -244,6 +244,12 @@ struct bt_codecs {
|
||||
|
||||
#define BT_ISO_BASE 20
|
||||
|
||||
/* Socket option value 21 reserved */
|
||||
|
||||
#define BT_PKT_SEQNUM 22
|
||||
|
||||
#define BT_SCM_PKT_SEQNUM 0x05
|
||||
|
||||
__printf(1, 2)
|
||||
void bt_info(const char *fmt, ...);
|
||||
__printf(1, 2)
|
||||
@@ -391,7 +397,8 @@ struct bt_sock {
|
||||
enum {
|
||||
BT_SK_DEFER_SETUP,
|
||||
BT_SK_SUSPEND,
|
||||
BT_SK_PKT_STATUS
|
||||
BT_SK_PKT_STATUS,
|
||||
BT_SK_PKT_SEQNUM,
|
||||
};
|
||||
|
||||
struct bt_sock_list {
|
||||
@@ -475,6 +482,7 @@ struct bt_skb_cb {
|
||||
u8 pkt_type;
|
||||
u8 force_active;
|
||||
u16 expect;
|
||||
u16 pkt_seqnum;
|
||||
u8 incoming:1;
|
||||
u8 pkt_status:2;
|
||||
union {
|
||||
@@ -488,6 +496,7 @@ struct bt_skb_cb {
|
||||
|
||||
#define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
|
||||
#define hci_skb_pkt_status(skb) bt_cb((skb))->pkt_status
|
||||
#define hci_skb_pkt_seqnum(skb) bt_cb((skb))->pkt_seqnum
|
||||
#define hci_skb_expect(skb) bt_cb((skb))->expect
|
||||
#define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
|
||||
#define hci_skb_event(skb) bt_cb((skb))->hci.req_event
|
||||
|
||||
@@ -562,6 +562,7 @@ enum {
|
||||
#define LE_LINK 0x80
|
||||
#define CIS_LINK 0x82
|
||||
#define BIS_LINK 0x83
|
||||
#define PA_LINK 0x84
|
||||
#define INVALID_LINK 0xff
|
||||
|
||||
/* LMP features */
|
||||
@@ -2634,6 +2635,7 @@ struct hci_ev_le_conn_complete {
|
||||
#define LE_EXT_ADV_DIRECT_IND 0x0004
|
||||
#define LE_EXT_ADV_SCAN_RSP 0x0008
|
||||
#define LE_EXT_ADV_LEGACY_PDU 0x0010
|
||||
#define LE_EXT_ADV_DATA_STATUS_MASK 0x0060
|
||||
#define LE_EXT_ADV_EVT_TYPE_MASK 0x007f
|
||||
|
||||
#define ADDR_LE_DEV_PUBLIC 0x00
|
||||
@@ -2837,7 +2839,7 @@ struct hci_evt_le_create_big_complete {
|
||||
} __packed;
|
||||
|
||||
#define HCI_EVT_LE_BIG_SYNC_ESTABLISHED 0x1d
|
||||
struct hci_evt_le_big_sync_estabilished {
|
||||
struct hci_evt_le_big_sync_established {
|
||||
__u8 status;
|
||||
__u8 handle;
|
||||
__u8 latency[3];
|
||||
@@ -2851,6 +2853,12 @@ struct hci_evt_le_big_sync_estabilished {
|
||||
__le16 bis[];
|
||||
} __packed;
|
||||
|
||||
#define HCI_EVT_LE_BIG_SYNC_LOST 0x1e
|
||||
struct hci_evt_le_big_sync_lost {
|
||||
__u8 handle;
|
||||
__u8 reason;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EVT_LE_BIG_INFO_ADV_REPORT 0x22
|
||||
struct hci_evt_le_big_info_adv_report {
|
||||
__le16 sync_handle;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/idr.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/srcu.h>
|
||||
|
||||
#include <net/bluetooth/hci.h>
|
||||
@@ -94,6 +95,7 @@ struct discovery_state {
|
||||
u16 uuid_count;
|
||||
u8 (*uuids)[16];
|
||||
unsigned long name_resolve_timeout;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
#define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */
|
||||
@@ -889,6 +891,7 @@ static inline void iso_recv(struct hci_conn *hcon, struct sk_buff *skb,
|
||||
|
||||
static inline void discovery_init(struct hci_dev *hdev)
|
||||
{
|
||||
spin_lock_init(&hdev->discovery.lock);
|
||||
hdev->discovery.state = DISCOVERY_STOPPED;
|
||||
INIT_LIST_HEAD(&hdev->discovery.all);
|
||||
INIT_LIST_HEAD(&hdev->discovery.unknown);
|
||||
@@ -903,8 +906,11 @@ static inline void hci_discovery_filter_clear(struct hci_dev *hdev)
|
||||
hdev->discovery.report_invalid_rssi = true;
|
||||
hdev->discovery.rssi = HCI_RSSI_INVALID;
|
||||
hdev->discovery.uuid_count = 0;
|
||||
|
||||
spin_lock(&hdev->discovery.lock);
|
||||
kfree(hdev->discovery.uuids);
|
||||
hdev->discovery.uuids = NULL;
|
||||
spin_unlock(&hdev->discovery.lock);
|
||||
}
|
||||
|
||||
bool hci_discovery_active(struct hci_dev *hdev);
|
||||
@@ -1009,6 +1015,7 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
h->iso_num++;
|
||||
break;
|
||||
}
|
||||
@@ -1036,6 +1043,7 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
h->iso_num--;
|
||||
break;
|
||||
}
|
||||
@@ -1054,6 +1062,7 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
|
||||
return h->sco_num;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
return h->iso_num;
|
||||
default:
|
||||
return 0;
|
||||
@@ -1136,7 +1145,7 @@ hci_conn_hash_lookup_create_pa_sync(struct hci_dev *hdev)
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type != BIS_LINK)
|
||||
if (c->type != PA_LINK)
|
||||
continue;
|
||||
|
||||
if (!test_bit(HCI_CONN_CREATE_PA_SYNC, &c->flags))
|
||||
@@ -1331,7 +1340,7 @@ hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev,
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type != BIS_LINK)
|
||||
if (c->type != PA_LINK)
|
||||
continue;
|
||||
|
||||
if (handle == c->iso_qos.bcast.big && num_bis == c->num_bis) {
|
||||
@@ -1346,7 +1355,8 @@ hci_conn_hash_lookup_big_sync_pend(struct hci_dev *hdev,
|
||||
}
|
||||
|
||||
static inline struct hci_conn *
|
||||
hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state)
|
||||
hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state,
|
||||
__u8 role)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
@@ -1354,7 +1364,7 @@ hci_conn_hash_lookup_big_state(struct hci_dev *hdev, __u8 handle, __u16 state)
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type != BIS_LINK || c->state != state)
|
||||
if (c->type != BIS_LINK || c->state != state || c->role != role)
|
||||
continue;
|
||||
|
||||
if (handle == c->iso_qos.bcast.big) {
|
||||
@@ -1400,7 +1410,7 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle)
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type != BIS_LINK)
|
||||
if (c->type != PA_LINK)
|
||||
continue;
|
||||
|
||||
/* Ignore the listen hcon, we are looking
|
||||
@@ -1420,26 +1430,6 @@ hci_conn_hash_lookup_pa_sync_handle(struct hci_dev *hdev, __u16 sync_handle)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
|
||||
__u8 type, __u16 state)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if (c->type == type && c->state == state) {
|
||||
rcu_read_unlock();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef void (*hci_conn_func_t)(struct hci_conn *conn, void *data);
|
||||
static inline void hci_conn_hash_list_state(struct hci_dev *hdev,
|
||||
hci_conn_func_t func, __u8 type,
|
||||
@@ -2019,6 +2009,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
return iso_connect_ind(hdev, bdaddr, flags);
|
||||
|
||||
default:
|
||||
|
||||
@@ -364,6 +364,13 @@ int bt_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
|
||||
put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_STATUS,
|
||||
sizeof(pkt_status), &pkt_status);
|
||||
}
|
||||
|
||||
if (test_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags)) {
|
||||
u16 pkt_seqnum = hci_skb_pkt_seqnum(skb);
|
||||
|
||||
put_cmsg(msg, SOL_BLUETOOTH, BT_SCM_PKT_SEQNUM,
|
||||
sizeof(pkt_seqnum), &pkt_seqnum);
|
||||
}
|
||||
}
|
||||
|
||||
skb_free_datagram(sk, skb);
|
||||
|
||||
@@ -70,7 +70,7 @@ void aosp_do_open(struct hci_dev *hdev)
|
||||
rp = (struct aosp_rp_le_get_vendor_capa *)skb->data;
|
||||
|
||||
version_supported = le16_to_cpu(rp->version_supported);
|
||||
/* AOSP displays the verion number like v0.98, v1.00, etc. */
|
||||
/* AOSP displays the version number like v0.98, v1.00, etc. */
|
||||
bt_dev_info(hdev, "AOSP extensions version v%u.%02u",
|
||||
version_supported >> 8, version_supported & 0xff);
|
||||
|
||||
|
||||
@@ -249,15 +249,15 @@ static void hci_devcd_dump(struct hci_dev *hdev)
|
||||
|
||||
size = hdev->dump.tail - hdev->dump.head;
|
||||
|
||||
/* Emit a devcoredump with the available data */
|
||||
dev_coredumpv(&hdev->dev, hdev->dump.head, size, GFP_KERNEL);
|
||||
|
||||
/* Send a copy to monitor as a diagnostic packet */
|
||||
skb = bt_skb_alloc(size, GFP_ATOMIC);
|
||||
if (skb) {
|
||||
skb_put_data(skb, hdev->dump.head, size);
|
||||
hci_recv_diag(hdev, skb);
|
||||
}
|
||||
|
||||
/* Emit a devcoredump with the available data */
|
||||
dev_coredumpv(&hdev->dev, hdev->dump.head, size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static void hci_devcd_handle_pkt_complete(struct hci_dev *hdev,
|
||||
|
||||
@@ -785,7 +785,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
|
||||
d->sync_handle = conn->sync_handle;
|
||||
|
||||
if (test_and_clear_bit(HCI_CONN_PA_SYNC, &conn->flags)) {
|
||||
hci_conn_hash_list_flag(hdev, find_bis, BIS_LINK,
|
||||
hci_conn_hash_list_flag(hdev, find_bis, PA_LINK,
|
||||
HCI_CONN_PA_SYNC, d);
|
||||
|
||||
if (!d->count)
|
||||
@@ -814,7 +814,7 @@ static int hci_le_big_terminate(struct hci_dev *hdev, u8 big, struct hci_conn *c
|
||||
*
|
||||
* Detects if there any BIS left connected in a BIG
|
||||
* broadcaster: Remove advertising instance and terminate BIG.
|
||||
* broadcaster receiver: Teminate BIG sync and terminate PA sync.
|
||||
* broadcaster receiver: Terminate BIG sync and terminate PA sync.
|
||||
*/
|
||||
static void bis_cleanup(struct hci_conn *conn)
|
||||
{
|
||||
@@ -914,6 +914,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
if (hdev->iso_mtu)
|
||||
/* Dedicated ISO Buffer exists */
|
||||
break;
|
||||
@@ -979,6 +980,7 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
/* conn->src should reflect the local identity address */
|
||||
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
|
||||
|
||||
@@ -1033,7 +1035,6 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t
|
||||
}
|
||||
|
||||
hci_conn_init_sysfs(conn);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
@@ -1077,6 +1078,7 @@ static void hci_conn_cleanup_child(struct hci_conn *conn, u8 reason)
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
if ((conn->state != BT_CONNECTED &&
|
||||
!test_bit(HCI_CONN_CREATE_CIS, &conn->flags)) ||
|
||||
test_bit(HCI_CONN_BIG_CREATED, &conn->flags))
|
||||
@@ -1152,7 +1154,8 @@ void hci_conn_del(struct hci_conn *conn)
|
||||
} else {
|
||||
/* Unacked ISO frames */
|
||||
if (conn->type == CIS_LINK ||
|
||||
conn->type == BIS_LINK) {
|
||||
conn->type == BIS_LINK ||
|
||||
conn->type == PA_LINK) {
|
||||
if (hdev->iso_pkts)
|
||||
hdev->iso_cnt += conn->sent;
|
||||
else if (hdev->le_pkts)
|
||||
@@ -2081,7 +2084,7 @@ 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, BIS_LINK, dst, HCI_ROLE_SLAVE);
|
||||
conn = hci_conn_add_unset(hdev, PA_LINK, dst, HCI_ROLE_SLAVE);
|
||||
if (IS_ERR(conn))
|
||||
return conn;
|
||||
|
||||
@@ -2146,7 +2149,8 @@ struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid,
|
||||
struct hci_link *link;
|
||||
|
||||
/* Look for any BIS that is open for rebinding */
|
||||
conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN);
|
||||
conn = hci_conn_hash_lookup_big_state(hdev, qos->bcast.big, BT_OPEN,
|
||||
HCI_ROLE_MASTER);
|
||||
if (conn) {
|
||||
memcpy(qos, &conn->iso_qos, sizeof(*qos));
|
||||
conn->state = BT_CONNECTED;
|
||||
@@ -2245,7 +2249,7 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
|
||||
* the start periodic advertising and create BIG commands have
|
||||
* been queued
|
||||
*/
|
||||
hci_conn_hash_list_state(hdev, bis_mark_per_adv, BIS_LINK,
|
||||
hci_conn_hash_list_state(hdev, bis_mark_per_adv, PA_LINK,
|
||||
BT_BOUND, &data);
|
||||
|
||||
/* Queue start periodic advertising and create BIG */
|
||||
@@ -2979,6 +2983,7 @@ void hci_conn_tx_queue(struct hci_conn *conn, struct sk_buff *skb)
|
||||
switch (conn->type) {
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
case ACL_LINK:
|
||||
case LE_LINK:
|
||||
break;
|
||||
|
||||
@@ -1256,12 +1256,10 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
if (addr_type == irk->addr_type &&
|
||||
bacmp(bdaddr, &irk->bdaddr) == 0) {
|
||||
irk_to_return = irk;
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (irk_to_return && hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_IRK,
|
||||
irk_to_return->val)) {
|
||||
bt_dev_warn_ratelimited(hdev, "Identity key blocked for %pMR",
|
||||
@@ -2938,12 +2936,14 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
case HCI_ACLDATA_PKT:
|
||||
/* Detect if ISO packet has been sent as ACL */
|
||||
if (hci_conn_num(hdev, CIS_LINK) ||
|
||||
hci_conn_num(hdev, BIS_LINK)) {
|
||||
hci_conn_num(hdev, BIS_LINK) ||
|
||||
hci_conn_num(hdev, PA_LINK)) {
|
||||
__u16 handle = __le16_to_cpu(hci_acl_hdr(skb)->handle);
|
||||
__u8 type;
|
||||
|
||||
type = hci_conn_lookup_type(hdev, hci_handle(handle));
|
||||
if (type == CIS_LINK || type == BIS_LINK)
|
||||
if (type == CIS_LINK || type == BIS_LINK ||
|
||||
type == PA_LINK)
|
||||
hci_skb_pkt_type(skb) = HCI_ISODATA_PKT;
|
||||
}
|
||||
break;
|
||||
@@ -3398,6 +3398,7 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote)
|
||||
break;
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
cnt = hdev->iso_mtu ? hdev->iso_cnt :
|
||||
hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
|
||||
break;
|
||||
@@ -3411,7 +3412,7 @@ static inline void hci_quote_sent(struct hci_conn *conn, int num, int *quote)
|
||||
}
|
||||
|
||||
static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
|
||||
__u8 type2, int *quote)
|
||||
int *quote)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *conn = NULL, *c;
|
||||
@@ -3423,7 +3424,7 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(c, &h->list, list) {
|
||||
if ((c->type != type && c->type != type2) ||
|
||||
if (c->type != type ||
|
||||
skb_queue_empty(&c->data_q))
|
||||
continue;
|
||||
|
||||
@@ -3627,7 +3628,7 @@ static void hci_sched_sco(struct hci_dev *hdev, __u8 type)
|
||||
else
|
||||
cnt = &hdev->sco_cnt;
|
||||
|
||||
while (*cnt && (conn = hci_low_sent(hdev, type, type, "e))) {
|
||||
while (*cnt && (conn = hci_low_sent(hdev, type, "e))) {
|
||||
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
|
||||
BT_DBG("skb %p len %d", skb, skb->len);
|
||||
hci_send_conn_frame(hdev, conn, skb);
|
||||
@@ -3746,8 +3747,8 @@ static void hci_sched_le(struct hci_dev *hdev)
|
||||
hci_prio_recalculate(hdev, LE_LINK);
|
||||
}
|
||||
|
||||
/* Schedule CIS */
|
||||
static void hci_sched_iso(struct hci_dev *hdev)
|
||||
/* Schedule iso */
|
||||
static void hci_sched_iso(struct hci_dev *hdev, __u8 type)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct sk_buff *skb;
|
||||
@@ -3755,14 +3756,12 @@ static void hci_sched_iso(struct hci_dev *hdev)
|
||||
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
if (!hci_conn_num(hdev, CIS_LINK) &&
|
||||
!hci_conn_num(hdev, BIS_LINK))
|
||||
if (!hci_conn_num(hdev, type))
|
||||
return;
|
||||
|
||||
cnt = hdev->iso_pkts ? &hdev->iso_cnt :
|
||||
hdev->le_pkts ? &hdev->le_cnt : &hdev->acl_cnt;
|
||||
while (*cnt && (conn = hci_low_sent(hdev, CIS_LINK, BIS_LINK,
|
||||
"e))) {
|
||||
while (*cnt && (conn = hci_low_sent(hdev, type, "e))) {
|
||||
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
|
||||
BT_DBG("skb %p len %d", skb, skb->len);
|
||||
hci_send_conn_frame(hdev, conn, skb);
|
||||
@@ -3787,7 +3786,9 @@ static void hci_tx_work(struct work_struct *work)
|
||||
/* Schedule queues and send stuff to HCI driver */
|
||||
hci_sched_sco(hdev, SCO_LINK);
|
||||
hci_sched_sco(hdev, ESCO_LINK);
|
||||
hci_sched_iso(hdev);
|
||||
hci_sched_iso(hdev, CIS_LINK);
|
||||
hci_sched_iso(hdev, BIS_LINK);
|
||||
hci_sched_iso(hdev, PA_LINK);
|
||||
hci_sched_acl(hdev);
|
||||
hci_sched_le(hdev);
|
||||
}
|
||||
|
||||
@@ -4432,6 +4432,7 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
if (hdev->iso_pkts) {
|
||||
hdev->iso_cnt += count;
|
||||
if (hdev->iso_cnt > hdev->iso_pkts)
|
||||
@@ -5717,7 +5718,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
|
||||
conn->state = BT_CONFIG;
|
||||
|
||||
/* Store current advertising instance as connection advertising instance
|
||||
* when sotfware rotation is in use so it can be re-enabled when
|
||||
* when software rotation is in use so it can be re-enabled when
|
||||
* disconnected.
|
||||
*/
|
||||
if (!ext_adv_capable(hdev))
|
||||
@@ -6239,6 +6240,11 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
static u8 ext_evt_type_to_legacy(struct hci_dev *hdev, u16 evt_type)
|
||||
{
|
||||
u16 pdu_type = evt_type & ~LE_EXT_ADV_DATA_STATUS_MASK;
|
||||
|
||||
if (!pdu_type)
|
||||
return LE_ADV_NONCONN_IND;
|
||||
|
||||
if (evt_type & LE_EXT_ADV_LEGACY_PDU) {
|
||||
switch (evt_type) {
|
||||
case LE_LEGACY_ADV_IND:
|
||||
@@ -6270,8 +6276,7 @@ static u8 ext_evt_type_to_legacy(struct hci_dev *hdev, u16 evt_type)
|
||||
if (evt_type & LE_EXT_ADV_SCAN_IND)
|
||||
return LE_ADV_SCAN_IND;
|
||||
|
||||
if (evt_type == LE_EXT_ADV_NON_CONN_IND ||
|
||||
evt_type & LE_EXT_ADV_DIRECT_IND)
|
||||
if (evt_type & LE_EXT_ADV_DIRECT_IND)
|
||||
return LE_ADV_NONCONN_IND;
|
||||
|
||||
invalid:
|
||||
@@ -6350,8 +6355,8 @@ static int hci_le_pa_term_sync(struct hci_dev *hdev, __le16 handle)
|
||||
return hci_send_cmd(hdev, HCI_OP_LE_PA_TERM_SYNC, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
static void hci_le_pa_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_pa_sync_established *ev = data;
|
||||
int mask = hdev->link_mode;
|
||||
@@ -6377,7 +6382,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
|
||||
conn->sync_handle = le16_to_cpu(ev->handle);
|
||||
conn->sid = HCI_SID_INVALID;
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, BIS_LINK,
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, PA_LINK,
|
||||
&flags);
|
||||
if (!(mask & HCI_LM_ACCEPT)) {
|
||||
hci_le_pa_term_sync(hdev, ev->handle);
|
||||
@@ -6388,7 +6393,7 @@ static void hci_le_pa_sync_estabilished_evt(struct hci_dev *hdev, void *data,
|
||||
goto unlock;
|
||||
|
||||
/* Add connection to indicate PA sync event */
|
||||
pa_sync = hci_conn_add_unset(hdev, BIS_LINK, BDADDR_ANY,
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (IS_ERR(pa_sync))
|
||||
@@ -6419,7 +6424,7 @@ static void hci_le_per_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, BIS_LINK, &flags);
|
||||
mask |= hci_proto_connect_ind(hdev, BDADDR_ANY, PA_LINK, &flags);
|
||||
if (!(mask & HCI_LM_ACCEPT))
|
||||
goto unlock;
|
||||
|
||||
@@ -6681,8 +6686,8 @@ static void hci_le_phy_update_evt(struct hci_dev *hdev, void *data,
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_cis_estabilished_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
static void hci_le_cis_established_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_evt_le_cis_established *ev = data;
|
||||
struct hci_conn *conn;
|
||||
@@ -6876,7 +6881,8 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
|
||||
|
||||
/* Connect all BISes that are bound to the BIG */
|
||||
while ((conn = hci_conn_hash_lookup_big_state(hdev, ev->handle,
|
||||
BT_BOUND))) {
|
||||
BT_BOUND,
|
||||
HCI_ROLE_MASTER))) {
|
||||
if (ev->status) {
|
||||
hci_connect_cfm(conn, ev->status);
|
||||
hci_conn_del(conn);
|
||||
@@ -6909,7 +6915,7 @@ static void hci_le_create_big_complete_evt(struct hci_dev *hdev, void *data,
|
||||
static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_evt_le_big_sync_estabilished *ev = data;
|
||||
struct hci_evt_le_big_sync_established *ev = data;
|
||||
struct hci_conn *bis, *conn;
|
||||
int i;
|
||||
|
||||
@@ -6992,6 +6998,37 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_big_sync_lost_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_evt_le_big_sync_lost *ev = data;
|
||||
struct hci_conn *bis, *conn;
|
||||
|
||||
bt_dev_dbg(hdev, "big handle 0x%2.2x", ev->handle);
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
/* Delete the pa sync connection */
|
||||
bis = hci_conn_hash_lookup_pa_sync_big_handle(hdev, ev->handle);
|
||||
if (bis) {
|
||||
conn = hci_conn_hash_lookup_pa_sync_handle(hdev,
|
||||
bis->sync_handle);
|
||||
if (conn)
|
||||
hci_conn_del(conn);
|
||||
}
|
||||
|
||||
/* Delete each bis connection */
|
||||
while ((bis = hci_conn_hash_lookup_big_state(hdev, ev->handle,
|
||||
BT_CONNECTED,
|
||||
HCI_ROLE_SLAVE))) {
|
||||
clear_bit(HCI_CONN_BIG_SYNC, &bis->flags);
|
||||
hci_disconn_cfm(bis, ev->reason);
|
||||
hci_conn_del(bis);
|
||||
}
|
||||
|
||||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
@@ -7043,7 +7080,7 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
|
||||
/* Entries in this table shall have their position according to the subevent
|
||||
* opcode they handle so the use of the macros above is recommend since it does
|
||||
* attempt to initialize at its proper index using Designated Initializers that
|
||||
* way events without a callback function can be ommited.
|
||||
* way events without a callback function can be omitted.
|
||||
*/
|
||||
static const struct hci_le_ev {
|
||||
void (*func)(struct hci_dev *hdev, void *data, struct sk_buff *skb);
|
||||
@@ -7089,7 +7126,7 @@ static const struct hci_le_ev {
|
||||
HCI_MAX_EVENT_SIZE),
|
||||
/* [0x0e = HCI_EV_LE_PA_SYNC_ESTABLISHED] */
|
||||
HCI_LE_EV(HCI_EV_LE_PA_SYNC_ESTABLISHED,
|
||||
hci_le_pa_sync_estabilished_evt,
|
||||
hci_le_pa_sync_established_evt,
|
||||
sizeof(struct hci_ev_le_pa_sync_established)),
|
||||
/* [0x0f = HCI_EV_LE_PER_ADV_REPORT] */
|
||||
HCI_LE_EV_VL(HCI_EV_LE_PER_ADV_REPORT,
|
||||
@@ -7100,7 +7137,7 @@ static const struct hci_le_ev {
|
||||
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)),
|
||||
/* [0x19 = HCI_EVT_LE_CIS_ESTABLISHED] */
|
||||
HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_estabilished_evt,
|
||||
HCI_LE_EV(HCI_EVT_LE_CIS_ESTABLISHED, hci_le_cis_established_evt,
|
||||
sizeof(struct hci_evt_le_cis_established)),
|
||||
/* [0x1a = HCI_EVT_LE_CIS_REQ] */
|
||||
HCI_LE_EV(HCI_EVT_LE_CIS_REQ, hci_le_cis_req_evt,
|
||||
@@ -7113,7 +7150,12 @@ static const struct hci_le_ev {
|
||||
/* [0x1d = HCI_EV_LE_BIG_SYNC_ESTABLISHED] */
|
||||
HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_ESTABLISHED,
|
||||
hci_le_big_sync_established_evt,
|
||||
sizeof(struct hci_evt_le_big_sync_estabilished),
|
||||
sizeof(struct hci_evt_le_big_sync_established),
|
||||
HCI_MAX_EVENT_SIZE),
|
||||
/* [0x1e = HCI_EVT_LE_BIG_SYNC_LOST] */
|
||||
HCI_LE_EV_VL(HCI_EVT_LE_BIG_SYNC_LOST,
|
||||
hci_le_big_sync_lost_evt,
|
||||
sizeof(struct hci_evt_le_big_sync_lost),
|
||||
HCI_MAX_EVENT_SIZE),
|
||||
/* [0x22 = HCI_EVT_LE_BIG_INFO_ADV_REPORT] */
|
||||
HCI_LE_EV_VL(HCI_EVT_LE_BIG_INFO_ADV_REPORT,
|
||||
@@ -7399,7 +7441,7 @@ static const struct hci_ev {
|
||||
/* [0x2c = HCI_EV_SYNC_CONN_COMPLETE] */
|
||||
HCI_EV(HCI_EV_SYNC_CONN_COMPLETE, hci_sync_conn_complete_evt,
|
||||
sizeof(struct hci_ev_sync_conn_complete)),
|
||||
/* [0x2d = HCI_EV_EXTENDED_INQUIRY_RESULT] */
|
||||
/* [0x2f = HCI_EV_EXTENDED_INQUIRY_RESULT] */
|
||||
HCI_EV_VL(HCI_EV_EXTENDED_INQUIRY_RESULT,
|
||||
hci_extended_inquiry_result_evt,
|
||||
sizeof(struct hci_ev_ext_inquiry_result), HCI_MAX_EVENT_SIZE),
|
||||
|
||||
@@ -118,7 +118,7 @@ static void hci_sock_free_cookie(struct sock *sk)
|
||||
int id = hci_pi(sk)->cookie;
|
||||
|
||||
if (id) {
|
||||
hci_pi(sk)->cookie = 0xffffffff;
|
||||
hci_pi(sk)->cookie = 0;
|
||||
ida_free(&sock_cookie_ida, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2929,7 +2929,7 @@ static int hci_le_set_ext_scan_param_sync(struct hci_dev *hdev, u8 type,
|
||||
if (sent) {
|
||||
struct hci_conn *conn;
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, BIS_LINK,
|
||||
conn = hci_conn_hash_lookup_ba(hdev, PA_LINK,
|
||||
&sent->bdaddr);
|
||||
if (conn) {
|
||||
struct bt_iso_qos *qos = &conn->iso_qos;
|
||||
@@ -5493,7 +5493,7 @@ static int hci_disconnect_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
{
|
||||
struct hci_cp_disconnect cp;
|
||||
|
||||
if (conn->type == BIS_LINK) {
|
||||
if (conn->type == BIS_LINK || conn->type == PA_LINK) {
|
||||
/* This is a BIS connection, hci_conn_del will
|
||||
* do the necessary cleanup.
|
||||
*/
|
||||
@@ -5562,7 +5562,7 @@ static int hci_connect_cancel_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
return HCI_ERROR_LOCAL_HOST_TERM;
|
||||
}
|
||||
|
||||
if (conn->type == BIS_LINK) {
|
||||
if (conn->type == BIS_LINK || conn->type == PA_LINK) {
|
||||
/* There is no way to cancel a BIS without terminating the BIG
|
||||
* which is done later on connection cleanup.
|
||||
*/
|
||||
@@ -5627,7 +5627,7 @@ static int hci_reject_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
|
||||
if (conn->type == CIS_LINK)
|
||||
return hci_le_reject_cis_sync(hdev, conn, reason);
|
||||
|
||||
if (conn->type == BIS_LINK)
|
||||
if (conn->type == BIS_LINK || conn->type == PA_LINK)
|
||||
return -EINVAL;
|
||||
|
||||
if (conn->type == SCO_LINK || conn->type == ESCO_LINK)
|
||||
@@ -5677,7 +5677,7 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason)
|
||||
}
|
||||
|
||||
/* Cleanup hci_conn object if it cannot be cancelled as it
|
||||
* likelly means the controller and host stack are out of sync
|
||||
* likely means the controller and host stack are out of sync
|
||||
* or in case of LE it was still scanning so it can be cleanup
|
||||
* safely.
|
||||
*/
|
||||
@@ -6116,7 +6116,7 @@ static int hci_update_event_filter_sync(struct hci_dev *hdev)
|
||||
&b->bdaddr,
|
||||
HCI_CONN_SETUP_AUTO_ON);
|
||||
if (err)
|
||||
bt_dev_dbg(hdev, "Failed to set event filter for %pMR",
|
||||
bt_dev_err(hdev, "Failed to set event filter for %pMR",
|
||||
&b->bdaddr);
|
||||
else
|
||||
scan = SCAN_PAGE;
|
||||
@@ -6994,7 +6994,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, BIS_LINK, BDADDR_ANY,
|
||||
pa_sync = hci_conn_add_unset(hdev, PA_LINK, BDADDR_ANY,
|
||||
HCI_ROLE_SLAVE);
|
||||
|
||||
if (IS_ERR(pa_sync))
|
||||
|
||||
@@ -1687,6 +1687,17 @@ static int iso_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
|
||||
break;
|
||||
|
||||
case BT_PKT_SEQNUM:
|
||||
err = copy_safe_from_sockptr(&opt, sizeof(opt), optval, optlen);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
if (opt)
|
||||
set_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags);
|
||||
else
|
||||
clear_bit(BT_SK_PKT_SEQNUM, &bt_sk(sk)->flags);
|
||||
break;
|
||||
|
||||
case BT_ISO_QOS:
|
||||
if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
|
||||
sk->sk_state != BT_CONNECT2 &&
|
||||
@@ -1891,7 +1902,7 @@ static void iso_sock_ready(struct sock *sk)
|
||||
|
||||
static bool iso_match_big(struct sock *sk, void *data)
|
||||
{
|
||||
struct hci_evt_le_big_sync_estabilished *ev = data;
|
||||
struct hci_evt_le_big_sync_established *ev = data;
|
||||
|
||||
return ev->handle == iso_pi(sk)->qos.bcast.big;
|
||||
}
|
||||
@@ -1912,7 +1923,7 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
{
|
||||
struct sock *parent = NULL;
|
||||
struct sock *sk = conn->sk;
|
||||
struct hci_ev_le_big_sync_estabilished *ev = NULL;
|
||||
struct hci_ev_le_big_sync_established *ev = NULL;
|
||||
struct hci_ev_le_pa_sync_established *ev2 = NULL;
|
||||
struct hci_ev_le_per_adv_report *ev3 = NULL;
|
||||
struct hci_conn *hcon;
|
||||
@@ -2023,7 +2034,7 @@ static void iso_conn_ready(struct iso_conn *conn)
|
||||
hci_conn_hold(hcon);
|
||||
iso_chan_add(conn, sk, parent);
|
||||
|
||||
if ((ev && ((struct hci_evt_le_big_sync_estabilished *)ev)->status) ||
|
||||
if ((ev && ((struct hci_evt_le_big_sync_established *)ev)->status) ||
|
||||
(ev2 && ev2->status)) {
|
||||
/* Trigger error signal on child socket */
|
||||
sk->sk_err = ECONNREFUSED;
|
||||
@@ -2082,7 +2093,7 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
* proceed to establishing a BIG sync:
|
||||
*
|
||||
* 1. HCI_EV_LE_PA_SYNC_ESTABLISHED: The socket may specify a specific
|
||||
* SID to listen to and once sync is estabilished its handle needs to
|
||||
* 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.
|
||||
* 2. HCI_EVT_LE_BIG_INFO_ADV_REPORT: When connect_ind is triggered by a
|
||||
@@ -2226,7 +2237,8 @@ int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
|
||||
|
||||
static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
{
|
||||
if (hcon->type != CIS_LINK && hcon->type != BIS_LINK) {
|
||||
if (hcon->type != CIS_LINK && hcon->type != BIS_LINK &&
|
||||
hcon->type != PA_LINK) {
|
||||
if (hcon->type != LE_LINK)
|
||||
return;
|
||||
|
||||
@@ -2267,7 +2279,8 @@ static void iso_connect_cfm(struct hci_conn *hcon, __u8 status)
|
||||
|
||||
static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
{
|
||||
if (hcon->type != CIS_LINK && hcon->type != BIS_LINK)
|
||||
if (hcon->type != CIS_LINK && hcon->type != BIS_LINK &&
|
||||
hcon->type != PA_LINK)
|
||||
return;
|
||||
|
||||
BT_DBG("hcon %p reason %d", hcon, reason);
|
||||
@@ -2278,7 +2291,8 @@ static void iso_disconn_cfm(struct hci_conn *hcon, __u8 reason)
|
||||
void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
{
|
||||
struct iso_conn *conn = hcon->iso_data;
|
||||
__u16 pb, ts, len;
|
||||
struct skb_shared_hwtstamps *hwts;
|
||||
__u16 pb, ts, len, sn;
|
||||
|
||||
if (!conn)
|
||||
goto drop;
|
||||
@@ -2301,13 +2315,17 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
if (ts) {
|
||||
struct hci_iso_ts_data_hdr *hdr;
|
||||
|
||||
/* TODO: add timestamp to the packet? */
|
||||
hdr = skb_pull_data(skb, HCI_ISO_TS_DATA_HDR_SIZE);
|
||||
if (!hdr) {
|
||||
BT_ERR("Frame is too short (len %d)", skb->len);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
/* Record the timestamp to skb */
|
||||
hwts = skb_hwtstamps(skb);
|
||||
hwts->hwtstamp = us_to_ktime(le32_to_cpu(hdr->ts));
|
||||
|
||||
sn = __le16_to_cpu(hdr->sn);
|
||||
len = __le16_to_cpu(hdr->slen);
|
||||
} else {
|
||||
struct hci_iso_data_hdr *hdr;
|
||||
@@ -2318,18 +2336,20 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
goto drop;
|
||||
}
|
||||
|
||||
sn = __le16_to_cpu(hdr->sn);
|
||||
len = __le16_to_cpu(hdr->slen);
|
||||
}
|
||||
|
||||
flags = hci_iso_data_flags(len);
|
||||
len = hci_iso_data_len(len);
|
||||
|
||||
BT_DBG("Start: total len %d, frag len %d flags 0x%4.4x", len,
|
||||
skb->len, flags);
|
||||
BT_DBG("Start: total len %d, frag len %d flags 0x%4.4x sn %d",
|
||||
len, skb->len, flags, sn);
|
||||
|
||||
if (len == skb->len) {
|
||||
/* Complete frame received */
|
||||
hci_skb_pkt_status(skb) = flags & 0x03;
|
||||
hci_skb_pkt_seqnum(skb) = sn;
|
||||
iso_recv_frame(conn, skb);
|
||||
return;
|
||||
}
|
||||
@@ -2352,9 +2372,17 @@ void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
|
||||
goto drop;
|
||||
|
||||
hci_skb_pkt_status(conn->rx_skb) = flags & 0x03;
|
||||
hci_skb_pkt_seqnum(conn->rx_skb) = sn;
|
||||
skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
|
||||
skb->len);
|
||||
conn->rx_len = len - skb->len;
|
||||
|
||||
/* Copy hw timestamp from skb to rx_skb if present */
|
||||
if (ts) {
|
||||
hwts = skb_hwtstamps(conn->rx_skb);
|
||||
hwts->hwtstamp = skb_hwtstamps(skb)->hwtstamp;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ISO_CONT:
|
||||
|
||||
@@ -54,7 +54,7 @@ EXPORT_SYMBOL(baswap);
|
||||
* bt_to_errno() - Bluetooth error codes to standard errno
|
||||
* @code: Bluetooth error code to be converted
|
||||
*
|
||||
* This function takes a Bluetooth error code as input and convets
|
||||
* This function takes a Bluetooth error code as input and converts
|
||||
* it to an equivalent Unix/standard errno value.
|
||||
*
|
||||
* Return:
|
||||
|
||||
@@ -3237,6 +3237,7 @@ static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
|
||||
switch (link_type) {
|
||||
case CIS_LINK:
|
||||
case BIS_LINK:
|
||||
case PA_LINK:
|
||||
case LE_LINK:
|
||||
switch (addr_type) {
|
||||
case ADDR_LE_DEV_PUBLIC:
|
||||
|
||||
@@ -1962,7 +1962,8 @@ static void rfcomm_accept_connection(struct rfcomm_session *s)
|
||||
int err;
|
||||
|
||||
/* Fast check for a new connection.
|
||||
* Avoids unnesesary socket allocations. */
|
||||
* Avoids unnecessary socket allocations.
|
||||
*/
|
||||
if (list_empty(&bt_sk(sock->sk)->accept_q))
|
||||
return;
|
||||
|
||||
|
||||
@@ -980,7 +980,7 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty,
|
||||
baud = RFCOMM_RPN_BR_230400;
|
||||
break;
|
||||
default:
|
||||
/* 9600 is standard accordinag to the RFCOMM specification */
|
||||
/* 9600 is standard according to the RFCOMM specification */
|
||||
baud = RFCOMM_RPN_BR_9600;
|
||||
break;
|
||||
|
||||
|
||||
@@ -3189,7 +3189,7 @@ static void smp_ready_cb(struct l2cap_chan *chan)
|
||||
/* No need to call l2cap_chan_hold() here since we already own
|
||||
* the reference taken in smp_new_conn_cb(). This is just the
|
||||
* first time that we tie it to a specific pointer. The code in
|
||||
* l2cap_core.c ensures that there's no risk this function wont
|
||||
* l2cap_core.c ensures that there's no risk this function won't
|
||||
* get called if smp_new_conn_cb was previously called.
|
||||
*/
|
||||
conn->smp = chan;
|
||||
|
||||
Reference in New Issue
Block a user