Commit 2efb07b5 authored by David S. Miller's avatar David S. Miller

Merge tag 'for-net-next-2023-04-23' of...

Merge tag 'for-net-next-2023-04-23' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next

bluetooth-next pull request for net-next:

 - Introduce devcoredump support
 - Add support for Realtek RTL8821CS, RTL8851B, RTL8852BS
 - Add support for Mediatek MT7663, MT7922
 - Add support for NXP w8997
 - Add support for Actions Semi ATS2851
 - Add support for QTI WCN6855
 - Add support for Marvell 88W8997
parents fd84c569 d883a466
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/bluetooth/nxp,88w8987-bt.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP Bluetooth chips
description:
This binding describes UART-attached NXP bluetooth chips. These chips
are dual-radio chips supporting WiFi and Bluetooth. The bluetooth
works on standard H4 protocol over 4-wire UART. The RTS and CTS lines
are used during FW download. To enable power save mode, the host
asserts break signal over UART-TX line to put the chip into power save
state. De-asserting break wakes up the BT chip.
maintainers:
- Neeraj Sanjay Kale <neeraj.sanjaykale@nxp.com>
properties:
compatible:
enum:
- nxp,88w8987-bt
- nxp,88w8997-bt
fw-init-baudrate:
description:
Chip baudrate after FW is downloaded and initialized.
This property depends on the module vendor's
configuration. If this property is not specified,
115200 is set as default.
required:
- compatible
additionalProperties: false
examples:
- |
serial {
bluetooth {
compatible = "nxp,88w8987-bt";
fw-init-baudrate = <3000000>;
};
};
......@@ -23,6 +23,7 @@ properties:
- qcom,wcn3998-bt
- qcom,qca6390-bt
- qcom,wcn6750-bt
- qcom,wcn6855-bt
enable-gpios:
maxItems: 1
......@@ -133,6 +134,22 @@ allOf:
- vddrfa1p7-supply
- vddrfa1p2-supply
- vddasd-supply
- if:
properties:
compatible:
contains:
enum:
- qcom,wcn6855-bt
then:
required:
- enable-gpios
- swctrl-gpios
- vddio-supply
- vddbtcxmx-supply
- vddrfacmn-supply
- vddrfa0p8-supply
- vddrfa1p2-supply
- vddrfa1p7-supply
examples:
- |
......
......@@ -15,11 +15,29 @@ maintainers:
properties:
compatible:
const: mrvl,88w8897
enum:
- mrvl,88w8897
- mrvl,88w8997
max-speed:
description: see Documentation/devicetree/bindings/serial/serial.yaml
required:
- compatible
allOf:
- if:
properties:
compatible:
contains:
const: mrvl,88w8997
then:
properties:
max-speed: true
else:
properties:
max-speed: false
additionalProperties: false
examples:
......
......@@ -4,24 +4,30 @@
$id: http://devicetree.org/schemas/net/realtek-bluetooth.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: RTL8723BS/RTL8723CS/RTL8822CS Bluetooth
title: RTL8723BS/RTL8723CS/RTL8821CS/RTL8822CS Bluetooth
maintainers:
- Vasily Khoruzhick <anarsoul@gmail.com>
- Alistair Francis <alistair@alistair23.me>
description:
RTL8723CS/RTL8723CS/RTL8822CS is WiFi + BT chip. WiFi part is connected over
SDIO, while BT is connected over serial. It speaks H5 protocol with few
extra commands to upload firmware and change module speed.
RTL8723CS/RTL8723CS/RTL8821CS/RTL8822CS is a WiFi + BT chip. WiFi part
is connected over SDIO, while BT is connected over serial. It speaks
H5 protocol with few extra commands to upload firmware and change
module speed.
properties:
compatible:
enum:
- realtek,rtl8723bs-bt
- realtek,rtl8723cs-bt
- realtek,rtl8723ds-bt
- realtek,rtl8822cs-bt
oneOf:
- enum:
- realtek,rtl8723bs-bt
- realtek,rtl8723cs-bt
- realtek,rtl8723ds-bt
- realtek,rtl8822cs-bt
- items:
- enum:
- realtek,rtl8821cs-bt
- const: realtek,rtl8822cs-bt
device-wake-gpios:
maxItems: 1
......
......@@ -23237,6 +23237,13 @@ L: linux-mm@kvack.org
S: Maintained
F: mm/zswap.c
NXP BLUETOOTH WIRELESS DRIVERS
M: Amitkumar Karwar <amitkumar.karwar@nxp.com>
M: Neeraj Kale <neeraj.sanjaykale@nxp.com>
S: Maintained
F: Documentation/devicetree/bindings/net/bluetooth/nxp,88w8987-bt.yaml
F: drivers/bluetooth/btnxpuart.c
THE REST
M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
......
......@@ -716,7 +716,7 @@ &uart1 {
status = "okay";
bluetooth {
compatible = "realtek,rtl8821cs-bt";
compatible = "realtek,rtl8821cs-bt", "realtek,rtl8822cs-bt";
device-wake-gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>;
enable-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
host-wake-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>;
......
......@@ -363,6 +363,7 @@ config BT_HCIBLUECARD
config BT_HCIVHCI
tristate "HCI VHCI (Virtual HCI device) driver"
select WANT_DEV_COREDUMP
help
Bluetooth Virtual HCI device driver.
This driver is required if you want to use HCI Emulation software.
......@@ -465,4 +466,17 @@ config BT_VIRTIO
Say Y here to compile support for HCI over Virtio into the
kernel or say M to compile as a module.
config BT_NXPUART
tristate "NXP protocol support"
depends on SERIAL_DEV_BUS
select CRC32
select CRC8
help
NXP is serial driver required for NXP Bluetooth
devices with UART interface.
Say Y here to compile support for NXP Bluetooth UART device into
the kernel, or say M here to compile as a module (btnxpuart).
endmenu
......@@ -29,6 +29,7 @@ obj-$(CONFIG_BT_QCA) += btqca.o
obj-$(CONFIG_BT_MTK) += btmtk.o
obj-$(CONFIG_BT_VIRTIO) += virtio_bt.o
obj-$(CONFIG_BT_NXPUART) += btnxpuart.o
obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
......
......@@ -6,6 +6,7 @@
* Copyright (C) 2015 Intel Corporation
*/
#include <linux/efi.h>
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/dmi.h>
......@@ -34,6 +35,43 @@
/* For kmalloc-ing the fw-name array instead of putting it on the stack */
typedef char bcm_fw_name[BCM_FW_NAME_LEN];
#ifdef CONFIG_EFI
static int btbcm_set_bdaddr_from_efi(struct hci_dev *hdev)
{
efi_guid_t guid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61, 0xb5, 0x1f,
0x43, 0x26, 0x81, 0x23, 0xd1, 0x13);
bdaddr_t efi_bdaddr, bdaddr;
efi_status_t status;
unsigned long len;
int ret;
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
return -EOPNOTSUPP;
len = sizeof(efi_bdaddr);
status = efi.get_variable(L"BDADDR", &guid, NULL, &len, &efi_bdaddr);
if (status != EFI_SUCCESS)
return -ENXIO;
if (len != sizeof(efi_bdaddr))
return -EIO;
baswap(&bdaddr, &efi_bdaddr);
ret = btbcm_set_bdaddr(hdev, &bdaddr);
if (ret)
return ret;
bt_dev_info(hdev, "BCM: Using EFI device address (%pMR)", &bdaddr);
return 0;
}
#else
static int btbcm_set_bdaddr_from_efi(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
#endif
int btbcm_check_bdaddr(struct hci_dev *hdev)
{
struct hci_rp_read_bd_addr *bda;
......@@ -87,9 +125,12 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
!bacmp(&bda->bdaddr, BDADDR_BCM4345C5) ||
!bacmp(&bda->bdaddr, BDADDR_BCM43430A0) ||
!bacmp(&bda->bdaddr, BDADDR_BCM43341B)) {
bt_dev_info(hdev, "BCM: Using default device address (%pMR)",
&bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
/* Try falling back to BDADDR EFI variable */
if (btbcm_set_bdaddr_from_efi(hdev) != 0) {
bt_dev_info(hdev, "BCM: Using default device address (%pMR)",
&bda->bdaddr);
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
}
}
kfree_skb(skb);
......
......@@ -43,6 +43,12 @@ struct cmd_write_boot_params {
u8 fw_build_yy;
} __packed;
static struct {
const char *driver_name;
u8 hw_variant;
u32 fw_build_num;
} coredump_info;
int btintel_check_bdaddr(struct hci_dev *hdev)
{
struct hci_rp_read_bd_addr *bda;
......@@ -315,6 +321,9 @@ int btintel_version_info(struct hci_dev *hdev, struct intel_version *ver)
return -EINVAL;
}
coredump_info.hw_variant = ver->hw_variant;
coredump_info.fw_build_num = ver->fw_build_num;
bt_dev_info(hdev, "%s revision %u.%u build %u week %u %u",
variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
ver->fw_build_num, ver->fw_build_ww,
......@@ -509,6 +518,9 @@ static int btintel_version_info_tlv(struct hci_dev *hdev,
return -EINVAL;
}
coredump_info.hw_variant = INTEL_HW_VARIANT(version->cnvi_bt);
coredump_info.fw_build_num = version->build_num;
bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant,
2000 + (version->timestamp >> 8), version->timestamp & 0xff,
version->build_type, version->build_num);
......@@ -1462,6 +1474,59 @@ int btintel_set_quality_report(struct hci_dev *hdev, bool enable)
}
EXPORT_SYMBOL_GPL(btintel_set_quality_report);
static void btintel_coredump(struct hci_dev *hdev)
{
struct sk_buff *skb;
skb = __hci_cmd_sync(hdev, 0xfc4e, 0, NULL, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Coredump failed (%ld)", PTR_ERR(skb));
return;
}
kfree_skb(skb);
}
static void btintel_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)
{
char buf[80];
snprintf(buf, sizeof(buf), "Controller Name: 0x%X\n",
coredump_info.hw_variant);
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Firmware Version: 0x%X\n",
coredump_info.fw_build_num);
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Driver: %s\n", coredump_info.driver_name);
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Vendor: Intel\n");
skb_put_data(skb, buf, strlen(buf));
}
static int btintel_register_devcoredump_support(struct hci_dev *hdev)
{
struct intel_debug_features features;
int err;
err = btintel_read_debug_features(hdev, &features);
if (err) {
bt_dev_info(hdev, "Error reading debug features");
return err;
}
if (!(features.page1[0] & 0x3f)) {
bt_dev_dbg(hdev, "Telemetry exception format not supported");
return -EOPNOTSUPP;
}
hci_devcd_register(hdev, btintel_coredump, btintel_dmp_hdr, NULL);
return err;
}
static const struct firmware *btintel_legacy_rom_get_fw(struct hci_dev *hdev,
struct intel_version *ver)
{
......@@ -2597,6 +2662,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
btintel_set_msft_opcode(hdev, ver.hw_variant);
err = btintel_bootloader_setup(hdev, &ver);
btintel_register_devcoredump_support(hdev);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
......@@ -2670,6 +2736,7 @@ static int btintel_setup_combined(struct hci_dev *hdev)
btintel_set_msft_opcode(hdev, ver.hw_variant);
err = btintel_bootloader_setup(hdev, &ver);
btintel_register_devcoredump_support(hdev);
break;
case 0x17:
case 0x18:
......@@ -2684,15 +2751,15 @@ static int btintel_setup_combined(struct hci_dev *hdev)
*/
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
/* Valid LE States quirk for GfP */
if (INTEL_HW_VARIANT(ver_tlv.cnvi_bt) == 0x18)
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
/* Apply LE States quirk from solar onwards */
set_bit(HCI_QUIRK_VALID_LE_STATES, &hdev->quirks);
/* Setup MSFT Extension support */
btintel_set_msft_opcode(hdev,
INTEL_HW_VARIANT(ver_tlv.cnvi_bt));
err = btintel_bootloader_setup_tlv(hdev, &ver_tlv);
btintel_register_devcoredump_support(hdev);
break;
default:
bt_dev_err(hdev, "Unsupported Intel hw variant (%u)",
......@@ -2742,7 +2809,7 @@ static int btintel_shutdown_combined(struct hci_dev *hdev)
return 0;
}
int btintel_configure_setup(struct hci_dev *hdev)
int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name)
{
hdev->manufacturer = 2;
hdev->setup = btintel_setup_combined;
......@@ -2751,6 +2818,8 @@ int btintel_configure_setup(struct hci_dev *hdev)
hdev->set_diag = btintel_set_diag_combined;
hdev->set_bdaddr = btintel_set_bdaddr;
coredump_info.driver_name = driver_name;
return 0;
}
EXPORT_SYMBOL_GPL(btintel_configure_setup);
......
......@@ -143,6 +143,13 @@ struct btintel_loc_aware_reg {
__le32 delta;
} __packed;
#define INTEL_TLV_TYPE_ID 0x01
#define INTEL_TLV_SYSTEM_EXCEPTION 0x00
#define INTEL_TLV_FATAL_EXCEPTION 0x01
#define INTEL_TLV_DEBUG_EXCEPTION 0x02
#define INTEL_TLV_TEST_EXCEPTION 0xDE
#define INTEL_HW_PLATFORM(cnvx_bt) ((u8)(((cnvx_bt) & 0x0000ff00) >> 8))
#define INTEL_HW_VARIANT(cnvx_bt) ((u8)(((cnvx_bt) & 0x003f0000) >> 16))
#define INTEL_CNVX_TOP_TYPE(cnvx_top) ((cnvx_top) & 0x00000fff)
......@@ -212,7 +219,7 @@ int btintel_read_boot_params(struct hci_dev *hdev,
struct intel_boot_params *params);
int btintel_download_firmware(struct hci_dev *dev, struct intel_version *ver,
const struct firmware *fw, u32 *boot_param);
int btintel_configure_setup(struct hci_dev *hdev);
int btintel_configure_setup(struct hci_dev *hdev, const char *driver_name);
void btintel_bootup(struct hci_dev *hdev, const void *ptr, unsigned int len);
void btintel_secure_send_result(struct hci_dev *hdev,
const void *ptr, unsigned int len);
......@@ -293,7 +300,8 @@ static inline int btintel_download_firmware(struct hci_dev *dev,
return -EOPNOTSUPP;
}
static inline int btintel_configure_setup(struct hci_dev *hdev)
static inline int btintel_configure_setup(struct hci_dev *hdev,
const char *driver_name)
{
return -ENODEV;
}
......
......@@ -40,7 +40,7 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = {
{"EXTLAST", NULL, 0, 0xFE},
};
static const struct of_device_id btmrvl_sdio_of_match_table[] = {
static const struct of_device_id btmrvl_sdio_of_match_table[] __maybe_unused = {
{ .compatible = "marvell,sd8897-bt" },
{ .compatible = "marvell,sd8997-bt" },
{ }
......
......@@ -959,16 +959,16 @@ static void btmtkuart_remove(struct serdev_device *serdev)
hci_free_dev(hdev);
}
static const struct btmtkuart_data mt7622_data = {
static const struct btmtkuart_data mt7622_data __maybe_unused = {
.fwname = FIRMWARE_MT7622,
};
static const struct btmtkuart_data mt7663_data = {
static const struct btmtkuart_data mt7663_data __maybe_unused = {
.flags = BTMTKUART_FLAG_STANDALONE_HW,
.fwname = FIRMWARE_MT7663,
};
static const struct btmtkuart_data mt7668_data = {
static const struct btmtkuart_data mt7668_data __maybe_unused = {
.flags = BTMTKUART_FLAG_STANDALONE_HW,
.fwname = FIRMWARE_MT7668,
};
......
This diff is collapsed.
......@@ -614,6 +614,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
config.type = ELF_TYPE_PATCH;
snprintf(config.fwname, sizeof(config.fwname),
"qca/msbtfw%02x.mbn", rom_ver);
} else if (soc_type == QCA_WCN6855) {
snprintf(config.fwname, sizeof(config.fwname),
"qca/hpbtfw%02x.tlv", rom_ver);
} else {
snprintf(config.fwname, sizeof(config.fwname),
"qca/rampatch_%08x.bin", soc_ver);
......@@ -648,6 +651,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
else if (soc_type == QCA_WCN6750)
snprintf(config.fwname, sizeof(config.fwname),
"qca/msnv%02x.bin", rom_ver);
else if (soc_type == QCA_WCN6855)
snprintf(config.fwname, sizeof(config.fwname),
"qca/hpnv%02x.bin", rom_ver);
else
snprintf(config.fwname, sizeof(config.fwname),
"qca/nvm_%08x.bin", soc_ver);
......@@ -685,11 +691,17 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
return err;
}
if (soc_type == QCA_WCN3991 || soc_type == QCA_WCN6750) {
switch (soc_type) {
case QCA_WCN3991:
case QCA_WCN6750:
case QCA_WCN6855:
/* get fw build info */
err = qca_read_fw_build_info(hdev);
if (err < 0)
return err;
break;
default:
break;
}
bt_dev_info(hdev, "QCA setup on UART is completed");
......
......@@ -147,6 +147,7 @@ enum qca_btsoc_type {
QCA_WCN3991,
QCA_QCA6390,
QCA_WCN6750,
QCA_WCN6855,
};
#if IS_ENABLED(CONFIG_BT_QCA)
......@@ -168,6 +169,10 @@ static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
{
return soc_type == QCA_WCN6750;
}
static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
{
return soc_type == QCA_WCN6855;
}
#else
......@@ -206,6 +211,11 @@ static inline bool qca_is_wcn6750(enum qca_btsoc_type soc_type)
return false;
}
static inline bool qca_is_wcn6855(enum qca_btsoc_type soc_type)
{
return false;
}
static inline int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
......
This diff is collapsed.
......@@ -14,6 +14,11 @@
struct btrtl_device_info;
struct rtl_chip_type_evt {
__u8 status;
__u8 type;
} __packed;
struct rtl_download_cmd {
__u8 index;
__u8 data[RTL_FRAG_LEN];
......@@ -44,7 +49,58 @@ struct rtl_vendor_config_entry {
struct rtl_vendor_config {
__le32 signature;
__le16 total_len;
struct rtl_vendor_config_entry entry[];
__u8 entry[];
} __packed;
struct rtl_epatch_header_v2 {
__u8 signature[8];
__u8 fw_version[8];
__le32 num_sections;
} __packed;
struct rtl_section {
__le32 opcode;
__le32 len;
u8 data[];
} __packed;
struct rtl_section_hdr {
__le16 num;
__le16 reserved;
} __packed;
struct rtl_common_subsec {
__u8 eco;
__u8 prio;
__u8 cb[2];
__le32 len;
__u8 data[];
};
struct rtl_sec_hdr {
__u8 eco;
__u8 prio;
__u8 key_id;
__u8 reserved;
__le32 len;
__u8 data[];
} __packed;
struct rtl_subsection {
struct list_head list;
u32 opcode;
u32 len;
u8 prio;
u8 *data;
};
struct rtl_iovec {
u8 *data;
u32 len;
};
struct rtl_vendor_cmd {
__u8 param[5];
} __packed;
enum {
......
......@@ -354,7 +354,6 @@ static void btsdio_remove(struct sdio_func *func)
BT_DBG("func %p", func);
cancel_work_sync(&data->work);
if (!data)
return;
......
This diff is collapsed.
......@@ -55,12 +55,14 @@
* @drive_rts_on_open: drive RTS signal on ->open() when platform requires it
* @no_uart_clock_set: UART clock set command for >3Mbps mode is unavailable
* @max_autobaud_speed: max baudrate supported by device in autobaud mode
* @max_speed: max baudrate supported
*/
struct bcm_device_data {
bool no_early_set_baudrate;
bool drive_rts_on_open;
bool no_uart_clock_set;
u32 max_autobaud_speed;
u32 max_speed;
};
/**
......@@ -888,7 +890,7 @@ static int bcm_resume(struct device *dev)
#endif
/* Some firmware reports an IRQ which does not work (wrong pin in fw table?) */
static struct gpiod_lookup_table asus_tf103c_irq_gpios = {
static struct gpiod_lookup_table irq_on_int33fc02_pin17_gpios = {
.dev_id = "serial0-0",
.table = {
GPIO_LOOKUP("INT33FC:02", 17, "host-wakeup-alt", GPIO_ACTIVE_HIGH),
......@@ -897,13 +899,32 @@ static struct gpiod_lookup_table asus_tf103c_irq_gpios = {
};
static const struct dmi_system_id bcm_broken_irq_dmi_table[] = {
{
.ident = "Acer Iconia One 7 B1-750",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
DMI_MATCH(DMI_PRODUCT_NAME, "VESPA2"),
},
.driver_data = &irq_on_int33fc02_pin17_gpios,
},
{
.ident = "Asus TF103C",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "TF103C"),
},
.driver_data = &asus_tf103c_irq_gpios,
.driver_data = &irq_on_int33fc02_pin17_gpios,
},
{
.ident = "Lenovo Yoga Tablet 2 830F/L / 1050F/L",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
/* Partial match on beginning of BIOS version */
DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
},
.driver_data = &irq_on_int33fc02_pin17_gpios,
},
{
.ident = "Meegopad T08",
......@@ -1300,6 +1321,12 @@ static const struct hci_uart_proto bcm_proto = {
};
#ifdef CONFIG_ACPI
/* bcm43430a0/a1 BT does not support 48MHz UART clock, limit to 2000000 baud */
static struct bcm_device_data bcm43430_device_data = {
.max_speed = 2000000,
};
static const struct acpi_device_id bcm_acpi_match[] = {
{ "BCM2E00" },
{ "BCM2E01" },
......@@ -1414,19 +1441,19 @@ static const struct acpi_device_id bcm_acpi_match[] = {
{ "BCM2E71" },
{ "BCM2E72" },
{ "BCM2E73" },
{ "BCM2E74" },
{ "BCM2E75" },
{ "BCM2E74", (long)&bcm43430_device_data },
{ "BCM2E75", (long)&bcm43430_device_data },
{ "BCM2E76" },
{ "BCM2E77" },
{ "BCM2E78" },
{ "BCM2E79" },
{ "BCM2E7A" },
{ "BCM2E7B" },
{ "BCM2E7B", (long)&bcm43430_device_data },
{ "BCM2E7C" },
{ "BCM2E7D" },
{ "BCM2E7E" },
{ "BCM2E7F" },
{ "BCM2E80" },
{ "BCM2E80", (long)&bcm43430_device_data },
{ "BCM2E81" },
{ "BCM2E82" },
{ "BCM2E83" },
......@@ -1435,7 +1462,7 @@ static const struct acpi_device_id bcm_acpi_match[] = {
{ "BCM2E86" },
{ "BCM2E87" },
{ "BCM2E88" },
{ "BCM2E89" },
{ "BCM2E89", (long)&bcm43430_device_data },
{ "BCM2E8A" },
{ "BCM2E8B" },
{ "BCM2E8C" },
......@@ -1444,29 +1471,30 @@ static const struct acpi_device_id bcm_acpi_match[] = {
{ "BCM2E90" },
{ "BCM2E92" },
{ "BCM2E93" },
{ "BCM2E94" },
{ "BCM2E94", (long)&bcm43430_device_data },
{ "BCM2E95" },
{ "BCM2E96" },
{ "BCM2E97" },
{ "BCM2E98" },
{ "BCM2E99" },
{ "BCM2E99", (long)&bcm43430_device_data },
{ "BCM2E9A" },
{ "BCM2E9B" },
{ "BCM2E9B", (long)&bcm43430_device_data },
{ "BCM2E9C" },
{ "BCM2E9D" },
{ "BCM2E9F", (long)&bcm43430_device_data },
{ "BCM2EA0" },
{ "BCM2EA1" },
{ "BCM2EA2" },
{ "BCM2EA3" },
{ "BCM2EA2", (long)&bcm43430_device_data },
{ "BCM2EA3", (long)&bcm43430_device_data },
{ "BCM2EA4" },
{ "BCM2EA5" },
{ "BCM2EA6" },
{ "BCM2EA7" },
{ "BCM2EA8" },
{ "BCM2EA9" },
{ "BCM2EAA" },
{ "BCM2EAB" },
{ "BCM2EAC" },
{ "BCM2EAA", (long)&bcm43430_device_data },
{ "BCM2EAB", (long)&bcm43430_device_data },
{ "BCM2EAC", (long)&bcm43430_device_data },
{ },
};
MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
......@@ -1535,6 +1563,8 @@ static int bcm_serdev_probe(struct serdev_device *serdev)
bcmdev->no_early_set_baudrate = data->no_early_set_baudrate;
bcmdev->drive_rts_on_open = data->drive_rts_on_open;
bcmdev->no_uart_clock_set = data->no_uart_clock_set;
if (data->max_speed && bcmdev->oper_speed > data->max_speed)
bcmdev->oper_speed = data->max_speed;
}
return hci_uart_register_device(&bcmdev->serdev_hu, &bcm_proto);
......
......@@ -463,6 +463,8 @@ static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c)
if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_ack) {
bt_dev_err(hu->hdev, "Out-of-order packet arrived (%u != %u)",
H5_HDR_SEQ(hdr), h5->tx_ack);
set_bit(H5_TX_ACK_REQ, &h5->flags);
hci_uart_tx_wakeup(hu);
h5_reset_rx(h5);
return 0;
}
......@@ -936,6 +938,8 @@ static int h5_btrtl_setup(struct h5 *h5)
err = btrtl_download_firmware(h5->hu->hdev, btrtl_dev);
/* Give the device some time before the hci-core sends it a reset */
usleep_range(10000, 20000);
if (err)
goto out_free;
btrtl_set_quirks(h5->hu->hdev, btrtl_dev);
......@@ -1100,6 +1104,8 @@ static const struct of_device_id rtl_bluetooth_of_match[] = {
.data = (const void *)&h5_data_rtl8822cs },
{ .compatible = "realtek,rtl8723bs-bt",
.data = (const void *)&h5_data_rtl8723bs },
{ .compatible = "realtek,rtl8723cs-bt",
.data = (const void *)&h5_data_rtl8723bs },
{ .compatible = "realtek,rtl8723ds-bt",
.data = (const void *)&h5_data_rtl8723bs },
#endif
......
......@@ -323,9 +323,9 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
/* Disable hardware flow control */
ktermios = tty->termios;
ktermios.c_cflag &= ~CRTSCTS;
status = tty_set_termios(tty, &ktermios);
tty_set_termios(tty, &ktermios);
BT_DBG("Disabling hardware flow control: %s",
status ? "failed" : "success");
(tty->termios.c_cflag & CRTSCTS) ? "failed" : "success");
/* Clear RTS to prevent the device from sending */
/* Most UARTs need OUT2 to enable interrupts */
......@@ -357,9 +357,9 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable)
/* Re-enable hardware flow control */
ktermios = tty->termios;
ktermios.c_cflag |= CRTSCTS;
status = tty_set_termios(tty, &ktermios);
tty_set_termios(tty, &ktermios);
BT_DBG("Enabling hardware flow control: %s",
status ? "failed" : "success");
!(tty->termios.c_cflag & CRTSCTS) ? "failed" : "success");
}
}
......
......@@ -786,7 +786,7 @@ MODULE_DEVICE_TABLE(of, hci_ti_of_match);
static struct serdev_device_driver hci_ti_drv = {
.driver = {
.name = "hci-ti",
.of_match_table = of_match_ptr(hci_ti_of_match),
.of_match_table = hci_ti_of_match,
},
.probe = hci_ti_probe,
.remove = hci_ti_remove,
......
......@@ -27,10 +27,12 @@
#define MRVL_ACK 0x5A
#define MRVL_NAK 0xBF
#define MRVL_RAW_DATA 0x1F
#define MRVL_SET_BAUDRATE 0xFC09
enum {
STATE_CHIP_VER_PENDING,
STATE_FW_REQ_PENDING,
STATE_FW_LOADED,
};
struct mrvl_data {
......@@ -254,6 +256,14 @@ static int mrvl_recv(struct hci_uart *hu, const void *data, int count)
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
return -EUNATCH;
/* We might receive some noise when there is no firmware loaded. Therefore,
* we drop data if the firmware is not loaded yet and if there is no fw load
* request pending.
*/
if (!test_bit(STATE_FW_REQ_PENDING, &mrvl->flags) &&
!test_bit(STATE_FW_LOADED, &mrvl->flags))
return count;
mrvl->rx_skb = h4_recv_buf(hu->hdev, mrvl->rx_skb, data, count,
mrvl_recv_pkts,
ARRAY_SIZE(mrvl_recv_pkts));
......@@ -354,6 +364,7 @@ static int mrvl_load_firmware(struct hci_dev *hdev, const char *name)
static int mrvl_setup(struct hci_uart *hu)
{
int err;
struct mrvl_data *mrvl = hu->priv;
hci_uart_set_flow_control(hu, true);
......@@ -367,9 +378,9 @@ static int mrvl_setup(struct hci_uart *hu)
hci_uart_wait_until_sent(hu);
if (hu->serdev)
serdev_device_set_baudrate(hu->serdev, 3000000);
serdev_device_set_baudrate(hu->serdev, hu->oper_speed);
else
hci_uart_set_baudrate(hu, 3000000);
hci_uart_set_baudrate(hu, hu->oper_speed);
hci_uart_set_flow_control(hu, false);
......@@ -377,13 +388,54 @@ static int mrvl_setup(struct hci_uart *hu)
if (err)
return err;
set_bit(STATE_FW_LOADED, &mrvl->flags);
return 0;
}
static int mrvl_set_baudrate(struct hci_uart *hu, unsigned int speed)
{
int err;
struct mrvl_data *mrvl = hu->priv;
__le32 speed_le = cpu_to_le32(speed);
/* The firmware might be loaded by the Wifi driver over SDIO. We wait
* up to 10s for the CTS to go up. Afterward, we know that the firmware
* is ready.
*/
err = serdev_device_wait_for_cts(hu->serdev, true, 10000);
if (err) {
bt_dev_err(hu->hdev, "Wait for CTS failed with %d\n", err);
return err;
}
set_bit(STATE_FW_LOADED, &mrvl->flags);
err = __hci_cmd_sync_status(hu->hdev, MRVL_SET_BAUDRATE,
sizeof(speed_le), &speed_le,
HCI_INIT_TIMEOUT);
if (err) {
bt_dev_err(hu->hdev, "send command failed: %d", err);
return err;
}
serdev_device_set_baudrate(hu->serdev, speed);
/* We forcefully have to send a command to the bluetooth module so that
* the driver detects it after a baudrate change. This is foreseen by
* hci_serdev by setting HCI_UART_VND_DETECT which then causes a dummy
* local version read.
*/
set_bit(HCI_UART_VND_DETECT, &hu->hdev_flags);
return 0;
}
static const struct hci_uart_proto mrvl_proto = {
static const struct hci_uart_proto mrvl_proto_8897 = {
.id = HCI_UART_MRVL,
.name = "Marvell",
.init_speed = 115200,
.oper_speed = 3000000,
.open = mrvl_open,
.close = mrvl_close,
.flush = mrvl_flush,
......@@ -393,18 +445,37 @@ static const struct hci_uart_proto mrvl_proto = {
.dequeue = mrvl_dequeue,
};
static const struct hci_uart_proto mrvl_proto_8997 = {
.id = HCI_UART_MRVL,
.name = "Marvell 8997",
.init_speed = 115200,
.oper_speed = 3000000,
.open = mrvl_open,
.close = mrvl_close,
.flush = mrvl_flush,
.set_baudrate = mrvl_set_baudrate,
.recv = mrvl_recv,
.enqueue = mrvl_enqueue,
.dequeue = mrvl_dequeue,
};
static int mrvl_serdev_probe(struct serdev_device *serdev)
{
struct mrvl_serdev *mrvldev;
const struct hci_uart_proto *mrvl_proto = device_get_match_data(&serdev->dev);
mrvldev = devm_kzalloc(&serdev->dev, sizeof(*mrvldev), GFP_KERNEL);
if (!mrvldev)
return -ENOMEM;
mrvldev->hu.oper_speed = mrvl_proto->oper_speed;
if (mrvl_proto->set_baudrate)
of_property_read_u32(serdev->dev.of_node, "max-speed", &mrvldev->hu.oper_speed);
mrvldev->hu.serdev = serdev;
serdev_device_set_drvdata(serdev, mrvldev);
return hci_uart_register_device(&mrvldev->hu, &mrvl_proto);
return hci_uart_register_device(&mrvldev->hu, mrvl_proto);
}
static void mrvl_serdev_remove(struct serdev_device *serdev)
......@@ -414,13 +485,12 @@ static void mrvl_serdev_remove(struct serdev_device *serdev)
hci_uart_unregister_device(&mrvldev->hu);
}
#ifdef CONFIG_OF
static const struct of_device_id mrvl_bluetooth_of_match[] = {
{ .compatible = "mrvl,88w8897" },
static const struct of_device_id __maybe_unused mrvl_bluetooth_of_match[] = {
{ .compatible = "mrvl,88w8897", .data = &mrvl_proto_8897},
{ .compatible = "mrvl,88w8997", .data = &mrvl_proto_8997},
{ },
};
MODULE_DEVICE_TABLE(of, mrvl_bluetooth_of_match);
#endif
static struct serdev_device_driver mrvl_serdev_driver = {
.probe = mrvl_serdev_probe,
......@@ -435,12 +505,12 @@ int __init mrvl_init(void)
{
serdev_device_driver_register(&mrvl_serdev_driver);
return hci_uart_register_proto(&mrvl_proto);
return hci_uart_register_proto(&mrvl_proto_8897);
}
int __exit mrvl_deinit(void)
{
serdev_device_driver_unregister(&mrvl_serdev_driver);
return hci_uart_unregister_proto(&mrvl_proto);
return hci_uart_unregister_proto(&mrvl_proto_8897);
}
......@@ -1317,7 +1317,8 @@ static int qca_set_baudrate(struct hci_dev *hdev, uint8_t baudrate)
/* Give the controller time to process the request */
if (qca_is_wcn399x(qca_soc_type(hu)) ||
qca_is_wcn6750(qca_soc_type(hu)))
qca_is_wcn6750(qca_soc_type(hu)) ||
qca_is_wcn6855(qca_soc_type(hu)))
usleep_range(1000, 10000);
else
msleep(300);
......@@ -1394,7 +1395,8 @@ static unsigned int qca_get_speed(struct hci_uart *hu,
static int qca_check_speeds(struct hci_uart *hu)
{
if (qca_is_wcn399x(qca_soc_type(hu)) ||
qca_is_wcn6750(qca_soc_type(hu))) {
qca_is_wcn6750(qca_soc_type(hu)) ||
qca_is_wcn6855(qca_soc_type(hu))) {
if (!qca_get_speed(hu, QCA_INIT_SPEED) &&
!qca_get_speed(hu, QCA_OPER_SPEED))
return -EINVAL;
......@@ -1428,7 +1430,8 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
* changing the baudrate of chip and host.
*/
if (qca_is_wcn399x(soc_type) ||
qca_is_wcn6750(soc_type))
qca_is_wcn6750(soc_type) ||
qca_is_wcn6855(soc_type))
hci_uart_set_flow_control(hu, true);
if (soc_type == QCA_WCN3990) {
......@@ -1446,7 +1449,8 @@ static int qca_set_speed(struct hci_uart *hu, enum qca_speed_type speed_type)
error:
if (qca_is_wcn399x(soc_type) ||
qca_is_wcn6750(soc_type))
qca_is_wcn6750(soc_type) ||
qca_is_wcn6855(soc_type))
hci_uart_set_flow_control(hu, false);
if (soc_type == QCA_WCN3990) {
......@@ -1682,7 +1686,8 @@ static int qca_power_on(struct hci_dev *hdev)
return 0;
if (qca_is_wcn399x(soc_type) ||
qca_is_wcn6750(soc_type)) {
qca_is_wcn6750(soc_type) ||
qca_is_wcn6855(soc_type)) {
ret = qca_regulator_init(hu);
} else {
qcadev = serdev_device_get_drvdata(hu->serdev);
......@@ -1723,7 +1728,8 @@ static int qca_setup(struct hci_uart *hu)
bt_dev_info(hdev, "setting up %s",
qca_is_wcn399x(soc_type) ? "wcn399x" :
(soc_type == QCA_WCN6750) ? "wcn6750" : "ROME/QCA6390");
(soc_type == QCA_WCN6750) ? "wcn6750" :
(soc_type == QCA_WCN6855) ? "wcn6855" : "ROME/QCA6390");
qca->memdump_state = QCA_MEMDUMP_IDLE;
......@@ -1735,7 +1741,8 @@ static int qca_setup(struct hci_uart *hu)
clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
if (qca_is_wcn399x(soc_type) ||
qca_is_wcn6750(soc_type)) {
qca_is_wcn6750(soc_type) ||
qca_is_wcn6855(soc_type)) {
set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);
hci_set_aosp_capable(hdev);
......@@ -1757,7 +1764,8 @@ static int qca_setup(struct hci_uart *hu)
}
if (!(qca_is_wcn399x(soc_type) ||
qca_is_wcn6750(soc_type))) {
qca_is_wcn6750(soc_type) ||
qca_is_wcn6855(soc_type))) {
/* Get QCA version information */
ret = qca_read_soc_version(hdev, &ver, soc_type);
if (ret)
......@@ -1827,7 +1835,7 @@ static const struct hci_uart_proto qca_proto = {
.dequeue = qca_dequeue,
};
static const struct qca_device_data qca_soc_data_wcn3990 = {
static const struct qca_device_data qca_soc_data_wcn3990 __maybe_unused = {
.soc_type = QCA_WCN3990,
.vregs = (struct qca_vreg []) {
{ "vddio", 15000 },
......@@ -1838,7 +1846,7 @@ static const struct qca_device_data qca_soc_data_wcn3990 = {
.num_vregs = 4,
};
static const struct qca_device_data qca_soc_data_wcn3991 = {
static const struct qca_device_data qca_soc_data_wcn3991 __maybe_unused = {
.soc_type = QCA_WCN3991,
.vregs = (struct qca_vreg []) {
{ "vddio", 15000 },
......@@ -1850,7 +1858,7 @@ static const struct qca_device_data qca_soc_data_wcn3991 = {
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
};
static const struct qca_device_data qca_soc_data_wcn3998 = {
static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = {
.soc_type = QCA_WCN3998,
.vregs = (struct qca_vreg []) {
{ "vddio", 10000 },
......@@ -1861,12 +1869,12 @@ static const struct qca_device_data qca_soc_data_wcn3998 = {
.num_vregs = 4,
};
static const struct qca_device_data qca_soc_data_qca6390 = {
static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = {
.soc_type = QCA_QCA6390,
.num_vregs = 0,
};
static const struct qca_device_data qca_soc_data_wcn6750 = {
static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = {
.soc_type = QCA_WCN6750,
.vregs = (struct qca_vreg []) {
{ "vddio", 5000 },
......@@ -1883,6 +1891,20 @@ static const struct qca_device_data qca_soc_data_wcn6750 = {
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
};
static const struct qca_device_data qca_soc_data_wcn6855 __maybe_unused = {
.soc_type = QCA_WCN6855,
.vregs = (struct qca_vreg []) {
{ "vddio", 5000 },
{ "vddbtcxmx", 126000 },
{ "vddrfacmn", 12500 },
{ "vddrfa0p8", 102000 },
{ "vddrfa1p7", 302000 },
{ "vddrfa1p2", 257000 },
},
.num_vregs = 6,
.capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES,
};
static void qca_power_shutdown(struct hci_uart *hu)
{
struct qca_serdev *qcadev;
......@@ -1912,7 +1934,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
host_set_baudrate(hu, 2400);
qca_send_power_pulse(hu, false);
qca_regulator_disable(qcadev);
} else if (soc_type == QCA_WCN6750) {
} else if (soc_type == QCA_WCN6750 || soc_type == QCA_WCN6855) {
gpiod_set_value_cansleep(qcadev->bt_en, 0);
msleep(100);
qca_regulator_disable(qcadev);
......@@ -2047,7 +2069,8 @@ static int qca_serdev_probe(struct serdev_device *serdev)
if (data &&
(qca_is_wcn399x(data->soc_type) ||
qca_is_wcn6750(data->soc_type))) {
qca_is_wcn6750(data->soc_type) ||
qca_is_wcn6855(data->soc_type))) {
qcadev->btsoc_type = data->soc_type;
qcadev->bt_power = devm_kzalloc(&serdev->dev,
sizeof(struct qca_power),
......@@ -2067,14 +2090,18 @@ static int qca_serdev_probe(struct serdev_device *serdev)
qcadev->bt_en = devm_gpiod_get_optional(&serdev->dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR_OR_NULL(qcadev->bt_en) && data->soc_type == QCA_WCN6750) {
if (IS_ERR_OR_NULL(qcadev->bt_en) &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855)) {
dev_err(&serdev->dev, "failed to acquire BT_EN gpio\n");
power_ctrl_enabled = false;
}
qcadev->sw_ctrl = devm_gpiod_get_optional(&serdev->dev, "swctrl",
GPIOD_IN);
if (IS_ERR_OR_NULL(qcadev->sw_ctrl) && data->soc_type == QCA_WCN6750)
if (IS_ERR_OR_NULL(qcadev->sw_ctrl) &&
(data->soc_type == QCA_WCN6750 ||
data->soc_type == QCA_WCN6855))
dev_warn(&serdev->dev, "failed to acquire SW_CTRL gpio\n");
qcadev->susclk = devm_clk_get_optional(&serdev->dev, NULL);
......@@ -2150,8 +2177,9 @@ static void qca_serdev_remove(struct serdev_device *serdev)
struct qca_power *power = qcadev->bt_power;
if ((qca_is_wcn399x(qcadev->btsoc_type) ||
qca_is_wcn6750(qcadev->btsoc_type)) &&
power->vregs_on)
qca_is_wcn6750(qcadev->btsoc_type) ||
qca_is_wcn6855(qcadev->btsoc_type)) &&
power->vregs_on)
qca_power_shutdown(&qcadev->serdev_hu);
else if (qcadev->susclk)
clk_disable_unprepare(qcadev->susclk);
......@@ -2335,6 +2363,7 @@ static const struct of_device_id qca_bluetooth_of_match[] = {
{ .compatible = "qcom,wcn3991-bt", .data = &qca_soc_data_wcn3991},
{ .compatible = "qcom,wcn3998-bt", .data = &qca_soc_data_wcn3998},
{ .compatible = "qcom,wcn6750-bt", .data = &qca_soc_data_wcn6750},
{ .compatible = "qcom,wcn6855-bt", .data = &qca_soc_data_wcn6855},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, qca_bluetooth_of_match);
......
......@@ -278,6 +278,104 @@ static int vhci_setup(struct hci_dev *hdev)
return 0;
}
static void vhci_coredump(struct hci_dev *hdev)
{
/* No need to do anything */
}
static void vhci_coredump_hdr(struct hci_dev *hdev, struct sk_buff *skb)
{
char buf[80];
snprintf(buf, sizeof(buf), "Controller Name: vhci_ctrl\n");
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Firmware Version: vhci_fw\n");
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Driver: vhci_drv\n");
skb_put_data(skb, buf, strlen(buf));
snprintf(buf, sizeof(buf), "Vendor: vhci\n");
skb_put_data(skb, buf, strlen(buf));
}
#define MAX_COREDUMP_LINE_LEN 40
struct devcoredump_test_data {
enum devcoredump_state state;
unsigned int timeout;
char data[MAX_COREDUMP_LINE_LEN];
};
static inline void force_devcd_timeout(struct hci_dev *hdev,
unsigned int timeout)
{
#ifdef CONFIG_DEV_COREDUMP
hdev->dump.timeout = msecs_to_jiffies(timeout * 1000);
#endif
}
static ssize_t force_devcd_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct vhci_data *data = file->private_data;
struct hci_dev *hdev = data->hdev;
struct sk_buff *skb = NULL;
struct devcoredump_test_data dump_data;
size_t data_size;
int ret;
if (count < offsetof(struct devcoredump_test_data, data) ||
count > sizeof(dump_data))
return -EINVAL;
if (copy_from_user(&dump_data, user_buf, count))
return -EFAULT;
data_size = count - offsetof(struct devcoredump_test_data, data);
skb = alloc_skb(data_size, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
skb_put_data(skb, &dump_data.data, data_size);
hci_devcd_register(hdev, vhci_coredump, vhci_coredump_hdr, NULL);
/* Force the devcoredump timeout */
if (dump_data.timeout)
force_devcd_timeout(hdev, dump_data.timeout);
ret = hci_devcd_init(hdev, skb->len);
if (ret) {
BT_ERR("Failed to generate devcoredump");
kfree_skb(skb);
return ret;
}
hci_devcd_append(hdev, skb);
switch (dump_data.state) {
case HCI_DEVCOREDUMP_DONE:
hci_devcd_complete(hdev);
break;
case HCI_DEVCOREDUMP_ABORT:
hci_devcd_abort(hdev);
break;
case HCI_DEVCOREDUMP_TIMEOUT:
/* Do nothing */
break;
default:
return -EINVAL;
}
return count;
}
static const struct file_operations force_devcoredump_fops = {
.open = simple_open,
.write = force_devcd_write,
};
static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
{
struct hci_dev *hdev;
......@@ -355,6 +453,9 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data,
&aosp_capable_fops);
debugfs_create_file("force_devcoredump", 0644, hdev->debugfs, data,
&force_devcoredump_fops);
hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
skb_put_u8(skb, 0xff);
......
......@@ -366,7 +366,7 @@ int serdev_device_set_parity(struct serdev_device *serdev,
struct serdev_controller *ctrl = serdev->ctrl;
if (!ctrl || !ctrl->ops->set_parity)
return -ENOTSUPP;
return -EOPNOTSUPP;
return ctrl->ops->set_parity(ctrl, parity);
}
......@@ -388,7 +388,7 @@ int serdev_device_get_tiocm(struct serdev_device *serdev)
struct serdev_controller *ctrl = serdev->ctrl;
if (!ctrl || !ctrl->ops->get_tiocm)
return -ENOTSUPP;
return -EOPNOTSUPP;
return ctrl->ops->get_tiocm(ctrl);
}
......@@ -399,12 +399,23 @@ int serdev_device_set_tiocm(struct serdev_device *serdev, int set, int clear)
struct serdev_controller *ctrl = serdev->ctrl;
if (!ctrl || !ctrl->ops->set_tiocm)
return -ENOTSUPP;
return -EOPNOTSUPP;
return ctrl->ops->set_tiocm(ctrl, set, clear);
}
EXPORT_SYMBOL_GPL(serdev_device_set_tiocm);
int serdev_device_break_ctl(struct serdev_device *serdev, int break_state)
{
struct serdev_controller *ctrl = serdev->ctrl;
if (!ctrl || !ctrl->ops->break_ctl)
return -EOPNOTSUPP;
return ctrl->ops->break_ctl(ctrl, break_state);
}
EXPORT_SYMBOL_GPL(serdev_device_break_ctl);
static int serdev_drv_probe(struct device *dev)
{
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
......
......@@ -231,7 +231,7 @@ static int ttyport_get_tiocm(struct serdev_controller *ctrl)
struct tty_struct *tty = serport->tty;
if (!tty->ops->tiocmget)
return -ENOTSUPP;
return -EOPNOTSUPP;
return tty->ops->tiocmget(tty);
}
......@@ -242,11 +242,22 @@ static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, u
struct tty_struct *tty = serport->tty;
if (!tty->ops->tiocmset)
return -ENOTSUPP;
return -EOPNOTSUPP;
return tty->ops->tiocmset(tty, set, clear);
}
static int ttyport_break_ctl(struct serdev_controller *ctrl, unsigned int break_state)
{
struct serport *serport = serdev_controller_get_drvdata(ctrl);
struct tty_struct *tty = serport->tty;
if (!tty->ops->break_ctl)
return -EOPNOTSUPP;
return tty->ops->break_ctl(tty, break_state);
}
static const struct serdev_controller_ops ctrl_ops = {
.write_buf = ttyport_write_buf,
.write_flush = ttyport_write_flush,
......@@ -259,6 +270,7 @@ static const struct serdev_controller_ops ctrl_ops = {
.wait_until_sent = ttyport_wait_until_sent,
.get_tiocm = ttyport_get_tiocm,
.set_tiocm = ttyport_set_tiocm,
.break_ctl = ttyport_break_ctl,
};
struct device *serdev_tty_port_register(struct tty_port *port,
......
......@@ -93,6 +93,7 @@ struct serdev_controller_ops {
void (*wait_until_sent)(struct serdev_controller *, long);
int (*get_tiocm)(struct serdev_controller *);
int (*set_tiocm)(struct serdev_controller *, unsigned int, unsigned int);
int (*break_ctl)(struct serdev_controller *ctrl, unsigned int break_state);
};
/**
......@@ -203,6 +204,7 @@ int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_
void serdev_device_wait_until_sent(struct serdev_device *, long);
int serdev_device_get_tiocm(struct serdev_device *);
int serdev_device_set_tiocm(struct serdev_device *, int, int);
int serdev_device_break_ctl(struct serdev_device *serdev, int break_state);
void serdev_device_write_wakeup(struct serdev_device *);
int serdev_device_write(struct serdev_device *, const unsigned char *, size_t, long);
void serdev_device_write_flush(struct serdev_device *);
......@@ -250,11 +252,15 @@ static inline int serdev_device_write_buf(struct serdev_device *serdev,
static inline void serdev_device_wait_until_sent(struct serdev_device *sdev, long timeout) {}
static inline int serdev_device_get_tiocm(struct serdev_device *serdev)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
static inline int serdev_device_set_tiocm(struct serdev_device *serdev, int set, int clear)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
static inline int serdev_device_break_ctl(struct serdev_device *serdev, int break_state)
{
return -EOPNOTSUPP;
}
static inline int serdev_device_write(struct serdev_device *sdev, const unsigned char *buf,
size_t count, unsigned long timeout)
......
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright 2023 NXP
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
......@@ -171,23 +172,39 @@ struct bt_iso_io_qos {
__u8 rtn;
};
struct bt_iso_qos {
union {
__u8 cig;
__u8 big;
};
union {
__u8 cis;
__u8 bis;
};
union {
__u8 sca;
__u8 sync_interval;
};
struct bt_iso_ucast_qos {
__u8 cig;
__u8 cis;
__u8 sca;
__u8 packing;
__u8 framing;
struct bt_iso_io_qos in;
struct bt_iso_io_qos out;
};
struct bt_iso_bcast_qos {
__u8 big;
__u8 bis;
__u8 sync_interval;
__u8 packing;
__u8 framing;
struct bt_iso_io_qos in;
struct bt_iso_io_qos out;
__u8 encryption;
__u8 bcode[16];
__u8 options;
__u16 skip;
__u16 sync_timeout;
__u8 sync_cte_type;
__u8 mse;
__u16 timeout;
};
struct bt_iso_qos {
union {
struct bt_iso_ucast_qos ucast;
struct bt_iso_bcast_qos bcast;
};
};
#define BT_ISO_PHY_1M 0x01
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2022 Google Corporation
*/
#ifndef __COREDUMP_H
#define __COREDUMP_H
#define DEVCOREDUMP_TIMEOUT msecs_to_jiffies(10000) /* 10 sec */
typedef void (*coredump_t)(struct hci_dev *hdev);
typedef void (*dmp_hdr_t)(struct hci_dev *hdev, struct sk_buff *skb);
typedef void (*notify_change_t)(struct hci_dev *hdev, int state);
/* struct hci_devcoredump - Devcoredump state
*
* @supported: Indicates if FW dump collection is supported by driver
* @state: Current state of dump collection
* @timeout: Indicates a timeout for collecting the devcoredump
*
* @alloc_size: Total size of the dump
* @head: Start of the dump
* @tail: Pointer to current end of dump
* @end: head + alloc_size for easy comparisons
*
* @dump_q: Dump queue for state machine to process
* @dump_rx: Devcoredump state machine work
* @dump_timeout: Devcoredump timeout work
*
* @coredump: Called from the driver's .coredump() function.
* @dmp_hdr: Create a dump header to identify controller/fw/driver info
* @notify_change: Notify driver when devcoredump state has changed
*/
struct hci_devcoredump {
bool supported;
enum devcoredump_state {
HCI_DEVCOREDUMP_IDLE,
HCI_DEVCOREDUMP_ACTIVE,
HCI_DEVCOREDUMP_DONE,
HCI_DEVCOREDUMP_ABORT,
HCI_DEVCOREDUMP_TIMEOUT,
} state;
unsigned long timeout;
size_t alloc_size;
char *head;
char *tail;
char *end;
struct sk_buff_head dump_q;
struct work_struct dump_rx;
struct delayed_work dump_timeout;
coredump_t coredump;
dmp_hdr_t dmp_hdr;
notify_change_t notify_change;
};
#ifdef CONFIG_DEV_COREDUMP
void hci_devcd_reset(struct hci_dev *hdev);
void hci_devcd_rx(struct work_struct *work);
void hci_devcd_timeout(struct work_struct *work);
int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump,
dmp_hdr_t dmp_hdr, notify_change_t notify_change);
int hci_devcd_init(struct hci_dev *hdev, u32 dump_size);
int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb);
int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len);
int hci_devcd_complete(struct hci_dev *hdev);
int hci_devcd_abort(struct hci_dev *hdev);
#else
static inline void hci_devcd_reset(struct hci_dev *hdev) {}
static inline void hci_devcd_rx(struct work_struct *work) {}
static inline void hci_devcd_timeout(struct work_struct *work) {}
static inline int hci_devcd_register(struct hci_dev *hdev, coredump_t coredump,
dmp_hdr_t dmp_hdr,
notify_change_t notify_change)
{
return -EOPNOTSUPP;
}
static inline int hci_devcd_init(struct hci_dev *hdev, u32 dump_size)
{
return -EOPNOTSUPP;
}
static inline int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb)
{
return -EOPNOTSUPP;
}
static inline int hci_devcd_append_pattern(struct hci_dev *hdev,
u8 pattern, u32 len)
{
return -EOPNOTSUPP;
}
static inline int hci_devcd_complete(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline int hci_devcd_abort(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
#endif /* CONFIG_DEV_COREDUMP */
#endif /* __COREDUMP_H */
......@@ -294,6 +294,21 @@ enum {
* during the hdev->setup vendor callback.
*/
HCI_QUIRK_BROKEN_MWS_TRANSPORT_CONFIG,
/* When this quirk is set, max_page for local extended features
* is set to 1, even if controller reports higher number. Some
* controllers (e.g. RTL8723CS) report more pages, but they
* don't actually support features declared there.
*/
HCI_QUIRK_BROKEN_LOCAL_EXT_FEATURES_PAGE_2,
/*
* When this quirk is set, the HCI_OP_LE_SET_RPA_TIMEOUT command is
* skipped during initialization. This is required for the Actions
* Semiconductor ATS2851 based controllers, which erroneously claims
* to support it.
*/
HCI_QUIRK_BROKEN_SET_RPA_TIMEOUT,
};
/* HCI device flags */
......
/*
BlueZ - Bluetooth protocol stack for Linux
Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
Copyright 2023 NXP
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
......@@ -32,6 +33,7 @@
#include <net/bluetooth/hci.h>
#include <net/bluetooth/hci_sync.h>
#include <net/bluetooth/hci_sock.h>
#include <net/bluetooth/coredump.h>
/* HCI priority */
#define HCI_PRIO_MAX 7
......@@ -590,6 +592,10 @@ struct hci_dev {
const char *fw_info;
struct dentry *debugfs;
#ifdef CONFIG_DEV_COREDUMP
struct hci_devcoredump dump;
#endif
struct device dev;
struct rfkill *rfkill;
......@@ -764,7 +770,10 @@ struct hci_conn {
void *iso_data;
struct amp_mgr *amp_mgr;
struct hci_conn *link;
struct list_head link_list;
struct hci_conn *parent;
struct hci_link *link;
struct bt_codec codec;
void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
......@@ -774,6 +783,11 @@ struct hci_conn {
void (*cleanup)(struct hci_conn *conn);
};
struct hci_link {
struct list_head list;
struct hci_conn *conn;
};
struct hci_chan {
struct list_head list;
__u16 handle;
......@@ -979,7 +993,7 @@ static inline bool hci_conn_sc_enabled(struct hci_conn *conn)
static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
list_add_rcu(&c->list, &h->list);
list_add_tail_rcu(&c->list, &h->list);
switch (c->type) {
case ACL_LINK:
h->acl_num++;
......@@ -1091,7 +1105,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_bis(struct hci_dev *hdev,
if (bacmp(&c->dst, ba) || c->type != ISO_LINK)
continue;
if (c->iso_qos.big == big && c->iso_qos.bis == bis) {
if (c->iso_qos.bcast.big == big && c->iso_qos.bcast.bis == bis) {
rcu_read_unlock();
return c;
}
......@@ -1166,7 +1180,9 @@ static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev,
static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
bdaddr_t *ba,
__u8 ba_type)
__u8 ba_type,
__u8 cig,
__u8 id)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *c;
......@@ -1177,6 +1193,14 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
if (c->type != ISO_LINK)
continue;
/* Match CIG ID if set */
if (cig != BT_ISO_QOS_CIG_UNSET && cig != c->iso_qos.ucast.cig)
continue;
/* Match CIS ID if set */
if (id != BT_ISO_QOS_CIS_UNSET && id != c->iso_qos.ucast.cis)
continue;
if (ba_type == c->dst_type && !bacmp(&c->dst, ba)) {
rcu_read_unlock();
return c;
......@@ -1200,7 +1224,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_cig(struct hci_dev *hdev,
if (c->type != ISO_LINK)
continue;
if (handle == c->iso_qos.cig) {
if (handle == c->iso_qos.ucast.cig) {
rcu_read_unlock();
return c;
}
......@@ -1223,7 +1247,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_big(struct hci_dev *hdev,
if (bacmp(&c->dst, BDADDR_ANY) || c->type != ISO_LINK)
continue;
if (handle == c->iso_qos.big) {
if (handle == c->iso_qos.bcast.big) {
rcu_read_unlock();
return c;
}
......@@ -1332,7 +1356,7 @@ struct hci_conn *hci_connect_bis(struct hci_dev *hdev, bdaddr_t *dst,
__u8 dst_type, struct bt_iso_qos *qos,
__u8 data_len, __u8 *data);
int hci_pa_create_sync(struct hci_dev *hdev, bdaddr_t *dst, __u8 dst_type,
__u8 sid);
__u8 sid, struct bt_iso_qos *qos);
int hci_le_big_create_sync(struct hci_dev *hdev, struct bt_iso_qos *qos,
__u16 sync_handle, __u8 num_bis, __u8 bis[]);
int hci_conn_check_link_mode(struct hci_conn *conn);
......@@ -1377,12 +1401,14 @@ static inline void hci_conn_put(struct hci_conn *conn)
put_device(&conn->dev);
}
static inline void hci_conn_hold(struct hci_conn *conn)
static inline struct hci_conn *hci_conn_hold(struct hci_conn *conn)
{
BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
atomic_inc(&conn->refcnt);
cancel_delayed_work(&conn->disc_work);
return conn;
}
static inline void hci_conn_drop(struct hci_conn *conn)
......@@ -1497,6 +1523,15 @@ static inline void hci_set_aosp_capable(struct hci_dev *hdev)
#endif
}
static inline void hci_devcd_setup(struct hci_dev *hdev)
{
#ifdef CONFIG_DEV_COREDUMP
INIT_WORK(&hdev->dump.dump_rx, hci_devcd_rx);
INIT_DELAYED_WORK(&hdev->dump.dump_timeout, hci_devcd_timeout);
skb_queue_head_init(&hdev->dump.dump_q);
#endif
}
int hci_dev_open(__u16 dev);
int hci_dev_close(__u16 dev);
int hci_dev_do_close(struct hci_dev *hdev);
......@@ -1668,9 +1703,13 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define scan_1m(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_1M) || \
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_1M))
#define le_2m_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_2M))
#define scan_2m(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_2M) || \
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_2M))
#define le_coded_capable(dev) (((dev)->le_features[1] & HCI_LE_PHY_CODED))
#define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED))
......
......@@ -41,6 +41,8 @@ void hci_cmd_sync_clear(struct hci_dev *hdev);
void hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
void __hci_cmd_sync_cancel(struct hci_dev *hdev, int err);
int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
void *data, hci_cmd_sync_work_destroy_t destroy);
......@@ -122,6 +124,8 @@ int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);
int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_le_create_cis_sync(struct hci_dev *hdev, struct hci_conn *conn);
int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle);
int hci_le_terminate_big_sync(struct hci_dev *hdev, u8 handle, u8 reason);
......
......@@ -694,7 +694,7 @@ struct l2cap_conn {
struct sk_buff_head pending_rx;
struct work_struct pending_rx_work;
struct work_struct id_addr_update_work;
struct delayed_work id_addr_timer;
__u8 disc_reason;
......
......@@ -91,26 +91,26 @@ struct mgmt_rp_read_index_list {
#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1)
#define MGMT_MAX_SHORT_NAME_LENGTH (HCI_MAX_SHORT_NAME_LENGTH + 1)
#define MGMT_SETTING_POWERED 0x00000001
#define MGMT_SETTING_CONNECTABLE 0x00000002
#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
#define MGMT_SETTING_DISCOVERABLE 0x00000008
#define MGMT_SETTING_BONDABLE 0x00000010
#define MGMT_SETTING_LINK_SECURITY 0x00000020
#define MGMT_SETTING_SSP 0x00000040
#define MGMT_SETTING_BREDR 0x00000080
#define MGMT_SETTING_HS 0x00000100
#define MGMT_SETTING_LE 0x00000200
#define MGMT_SETTING_ADVERTISING 0x00000400
#define MGMT_SETTING_SECURE_CONN 0x00000800
#define MGMT_SETTING_DEBUG_KEYS 0x00001000
#define MGMT_SETTING_PRIVACY 0x00002000
#define MGMT_SETTING_CONFIGURATION 0x00004000
#define MGMT_SETTING_STATIC_ADDRESS 0x00008000
#define MGMT_SETTING_PHY_CONFIGURATION 0x00010000
#define MGMT_SETTING_WIDEBAND_SPEECH 0x00020000
#define MGMT_SETTING_CIS_CENTRAL 0x00040000
#define MGMT_SETTING_CIS_PERIPHERAL 0x00080000
#define MGMT_SETTING_POWERED BIT(0)
#define MGMT_SETTING_CONNECTABLE BIT(1)
#define MGMT_SETTING_FAST_CONNECTABLE BIT(2)
#define MGMT_SETTING_DISCOVERABLE BIT(3)
#define MGMT_SETTING_BONDABLE BIT(4)
#define MGMT_SETTING_LINK_SECURITY BIT(5)
#define MGMT_SETTING_SSP BIT(6)
#define MGMT_SETTING_BREDR BIT(7)
#define MGMT_SETTING_HS BIT(8)
#define MGMT_SETTING_LE BIT(9)
#define MGMT_SETTING_ADVERTISING BIT(10)
#define MGMT_SETTING_SECURE_CONN BIT(11)
#define MGMT_SETTING_DEBUG_KEYS BIT(12)
#define MGMT_SETTING_PRIVACY BIT(13)
#define MGMT_SETTING_CONFIGURATION BIT(14)
#define MGMT_SETTING_STATIC_ADDRESS BIT(15)
#define MGMT_SETTING_PHY_CONFIGURATION BIT(16)
#define MGMT_SETTING_WIDEBAND_SPEECH BIT(17)
#define MGMT_SETTING_CIS_CENTRAL BIT(18)
#define MGMT_SETTING_CIS_PERIPHERAL BIT(19)
#define MGMT_OP_READ_INFO 0x0004
#define MGMT_READ_INFO_SIZE 0
......@@ -635,21 +635,21 @@ struct mgmt_rp_get_phy_configuration {
} __packed;
#define MGMT_GET_PHY_CONFIGURATION_SIZE 0
#define MGMT_PHY_BR_1M_1SLOT 0x00000001
#define MGMT_PHY_BR_1M_3SLOT 0x00000002
#define MGMT_PHY_BR_1M_5SLOT 0x00000004
#define MGMT_PHY_EDR_2M_1SLOT 0x00000008
#define MGMT_PHY_EDR_2M_3SLOT 0x00000010
#define MGMT_PHY_EDR_2M_5SLOT 0x00000020
#define MGMT_PHY_EDR_3M_1SLOT 0x00000040
#define MGMT_PHY_EDR_3M_3SLOT 0x00000080
#define MGMT_PHY_EDR_3M_5SLOT 0x00000100
#define MGMT_PHY_LE_1M_TX 0x00000200
#define MGMT_PHY_LE_1M_RX 0x00000400
#define MGMT_PHY_LE_2M_TX 0x00000800
#define MGMT_PHY_LE_2M_RX 0x00001000
#define MGMT_PHY_LE_CODED_TX 0x00002000
#define MGMT_PHY_LE_CODED_RX 0x00004000
#define MGMT_PHY_BR_1M_1SLOT BIT(0)
#define MGMT_PHY_BR_1M_3SLOT BIT(1)
#define MGMT_PHY_BR_1M_5SLOT BIT(2)
#define MGMT_PHY_EDR_2M_1SLOT BIT(3)
#define MGMT_PHY_EDR_2M_3SLOT BIT(4)
#define MGMT_PHY_EDR_2M_5SLOT BIT(5)
#define MGMT_PHY_EDR_3M_1SLOT BIT(6)
#define MGMT_PHY_EDR_3M_3SLOT BIT(7)
#define MGMT_PHY_EDR_3M_5SLOT BIT(8)
#define MGMT_PHY_LE_1M_TX BIT(9)
#define MGMT_PHY_LE_1M_RX BIT(10)
#define MGMT_PHY_LE_2M_TX BIT(11)
#define MGMT_PHY_LE_2M_RX BIT(12)
#define MGMT_PHY_LE_CODED_TX BIT(13)
#define MGMT_PHY_LE_CODED_RX BIT(14)
#define MGMT_PHY_BREDR_MASK (MGMT_PHY_BR_1M_1SLOT | MGMT_PHY_BR_1M_3SLOT | \
MGMT_PHY_BR_1M_5SLOT | MGMT_PHY_EDR_2M_1SLOT | \
......@@ -974,11 +974,11 @@ struct mgmt_ev_auth_failed {
__u8 status;
} __packed;
#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01
#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
#define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04
#define MGMT_DEV_FOUND_INITIATED_CONN 0x08
#define MGMT_DEV_FOUND_NAME_REQUEST_FAILED 0x10
#define MGMT_DEV_FOUND_CONFIRM_NAME BIT(0)
#define MGMT_DEV_FOUND_LEGACY_PAIRING BIT(1)
#define MGMT_DEV_FOUND_NOT_CONNECTABLE BIT(2)
#define MGMT_DEV_FOUND_INITIATED_CONN BIT(3)
#define MGMT_DEV_FOUND_NAME_REQUEST_FAILED BIT(4)
#define MGMT_EV_DEVICE_FOUND 0x0012
struct mgmt_ev_device_found {
......
......@@ -17,6 +17,8 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \
eir.o hci_sync.o
bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o
bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_LE) += iso.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
......
This diff is collapsed.
This diff is collapsed.
......@@ -2544,6 +2544,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout);
INIT_DELAYED_WORK(&hdev->ncmd_timer, hci_ncmd_timeout);
hci_devcd_setup(hdev);
hci_request_setup(hdev);
hci_init_sysfs(hdev);
......@@ -2802,6 +2803,9 @@ int hci_suspend_dev(struct hci_dev *hdev)
if (mgmt_powering_down(hdev))
return 0;
/* Cancel potentially blocking sync operation before suspend */
__hci_cmd_sync_cancel(hdev, -EHOSTDOWN);
hci_req_sync_lock(hdev);
ret = hci_suspend_sync(hdev);
hci_req_sync_unlock(hdev);
......
......@@ -189,7 +189,7 @@ static int uuids_show(struct seq_file *f, void *p)
}
hci_dev_unlock(hdev);
return 0;
return 0;
}
DEFINE_SHOW_ATTRIBUTE(uuids);
......
This diff is collapsed.
......@@ -987,6 +987,34 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
BT_DBG("cmd %x arg %lx", cmd, arg);
/* Make sure the cmd is valid before doing anything */
switch (cmd) {
case HCIGETDEVLIST:
case HCIGETDEVINFO:
case HCIGETCONNLIST:
case HCIDEVUP:
case HCIDEVDOWN:
case HCIDEVRESET:
case HCIDEVRESTAT:
case HCISETSCAN:
case HCISETAUTH:
case HCISETENCRYPT:
case HCISETPTYPE:
case HCISETLINKPOL:
case HCISETLINKMODE:
case HCISETACLMTU:
case HCISETSCOMTU:
case HCIINQUIRY:
case HCISETRAW:
case HCIGETCONNINFO:
case HCIGETAUTHINFO:
case HCIBLOCKADDR:
case HCIUNBLOCKADDR:
break;
default:
return -ENOIOCTLCMD;
}
lock_sock(sk);
if (hci_pi(sk)->channel != HCI_CHANNEL_RAW) {
......@@ -1003,7 +1031,14 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
if (hci_sock_gen_cookie(sk)) {
struct sk_buff *skb;
if (capable(CAP_NET_ADMIN))
/* Perform careful checks before setting the HCI_SOCK_TRUSTED
* flag. Make sure that not only the current task but also
* the socket opener has the required capability, since
* privileged programs can be tricked into making ioctl calls
* on HCI sockets, and the socket should not be marked as
* trusted simply because the ioctl caller is privileged.
*/
if (sk_capable(sk, CAP_NET_ADMIN))
hci_sock_set_flag(sk, HCI_SOCK_TRUSTED);
/* Send event to monitor */
......
This diff is collapsed.
This diff is collapsed.
......@@ -745,7 +745,7 @@ EXPORT_SYMBOL_GPL(l2cap_chan_list);
static void l2cap_conn_update_id_addr(struct work_struct *work)
{
struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
id_addr_update_work);
id_addr_timer.work);
struct hci_conn *hcon = conn->hcon;
struct l2cap_chan *chan;
......@@ -1907,8 +1907,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
if (work_pending(&conn->pending_rx_work))
cancel_work_sync(&conn->pending_rx_work);
if (work_pending(&conn->id_addr_update_work))
cancel_work_sync(&conn->id_addr_update_work);
cancel_delayed_work_sync(&conn->id_addr_timer);
l2cap_unregister_all_users(conn);
......@@ -4694,7 +4693,6 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
chan = l2cap_get_chan_by_scid(conn, scid);
if (!chan) {
mutex_unlock(&conn->chan_lock);
return 0;
}
......@@ -7874,7 +7872,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
skb_queue_head_init(&conn->pending_rx);
INIT_WORK(&conn->pending_rx_work, process_pending_rx);
INIT_WORK(&conn->id_addr_update_work, l2cap_conn_update_id_addr);
INIT_DELAYED_WORK(&conn->id_addr_timer, l2cap_conn_update_id_addr);
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
......
This diff is collapsed.
This diff is collapsed.
......@@ -58,6 +58,8 @@
#define SMP_TIMEOUT msecs_to_jiffies(30000)
#define ID_ADDR_TIMEOUT msecs_to_jiffies(200)
#define AUTH_REQ_MASK(dev) (hci_dev_test_flag(dev, HCI_SC_ENABLED) ? \
0x3f : 0x07)
#define KEY_DIST_MASK 0x07
......@@ -1067,7 +1069,12 @@ static void smp_notify_keys(struct l2cap_conn *conn)
if (hcon->type == LE_LINK) {
bacpy(&hcon->dst, &smp->remote_irk->bdaddr);
hcon->dst_type = smp->remote_irk->addr_type;
queue_work(hdev->workqueue, &conn->id_addr_update_work);
/* Use a short delay to make sure the new address is
* propagated _before_ the channels.
*/
queue_delayed_work(hdev->workqueue,
&conn->id_addr_timer,
ID_ADDR_TIMEOUT);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment