Commit b32563b6 authored by David S. Miller's avatar David S. Miller

Merge tag 'for-net-next-2021-11-16' of...

Merge tag 'for-net-next-2021-11-16' 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:

 - Add support for AOSP Bluetooth Quality Report
 - Enables AOSP extension for Mediatek Chip (MT7921 & MT7922)
 - Rework of HCI command execution serialization
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 65483559 28491d7e
......@@ -19,6 +19,10 @@ config BT_QCA
tristate
select FW_LOADER
config BT_MTK
tristate
select FW_LOADER
config BT_HCIBTUSB
tristate "HCI USB driver"
depends on USB
......@@ -55,6 +59,7 @@ config BT_HCIBTUSB_BCM
config BT_HCIBTUSB_MTK
bool "MediaTek protocol support"
depends on BT_HCIBTUSB
select BT_MTK
default n
help
The MediaTek protocol support enables firmware download
......@@ -383,6 +388,7 @@ config BT_ATH3K
config BT_MTKSDIO
tristate "MediaTek HCI SDIO driver"
depends on MMC
select BT_MTK
help
MediaTek Bluetooth HCI SDIO driver.
This driver is required if you want to use MediaTek Bluetooth
......
......@@ -25,6 +25,7 @@ obj-$(CONFIG_BT_QCOMSMD) += btqcomsmd.o
obj-$(CONFIG_BT_BCM) += btbcm.o
obj-$(CONFIG_BT_RTL) += btrtl.o
obj-$(CONFIG_BT_QCA) += btqca.o
obj-$(CONFIG_BT_MTK) += btmtk.o
obj-$(CONFIG_BT_VIRTIO) += virtio_bt.o
......
......@@ -628,6 +628,9 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
if (!data->bulk_pkt_size)
goto done;
rwlock_init(&data->lock);
data->reassembly = NULL;
......
......@@ -2081,14 +2081,16 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
if (ver->img_type == 0x03) {
btintel_clear_flag(hdev, INTEL_BOOTLOADER);
btintel_check_bdaddr(hdev);
}
/* If the OTP has no valid Bluetooth device address, then there will
* also be no valid address for the operational firmware.
*/
if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) {
bt_dev_info(hdev, "No device address configured");
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
} else {
/*
* Check for valid bd address in boot loader mode. Device
* will be marked as unconfigured if empty bd address is
* found.
*/
if (!bacmp(&ver->otp_bd_addr, BDADDR_ANY)) {
bt_dev_info(hdev, "No device address configured");
set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
}
}
btintel_get_fw_name_tlv(ver, fwname, sizeof(fwname), "sfi");
......@@ -2466,6 +2468,10 @@ static int btintel_setup_combined(struct hci_dev *hdev)
goto exit_error;
}
/* memset ver_tlv to start with clean state as few fields are exclusive
* to bootloader mode and are not populated in operational mode
*/
memset(&ver_tlv, 0, sizeof(ver_tlv));
/* For TLV type device, parse the tlv data */
err = btintel_parse_version_tlv(hdev, &ver_tlv, skb);
if (err) {
......
/**
/*
* Marvell Bluetooth driver
*
* Copyright (C) 2009, Marvell International Ltd.
......
// SPDX-License-Identifier: ISC
/* Copyright (C) 2021 MediaTek Inc.
*
*/
#include <linux/module.h>
#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "btmtk.h"
#define VERSION "0.1"
/* It is for mt79xx download rom patch*/
#define MTK_FW_ROM_PATCH_HEADER_SIZE 32
#define MTK_FW_ROM_PATCH_GD_SIZE 64
#define MTK_FW_ROM_PATCH_SEC_MAP_SIZE 64
#define MTK_SEC_MAP_COMMON_SIZE 12
#define MTK_SEC_MAP_NEED_SEND_SIZE 52
struct btmtk_patch_header {
u8 datetime[16];
u8 platform[4];
__le16 hwver;
__le16 swver;
__le32 magicnum;
} __packed;
struct btmtk_global_desc {
__le32 patch_ver;
__le32 sub_sys;
__le32 feature_opt;
__le32 section_num;
} __packed;
struct btmtk_section_map {
__le32 sectype;
__le32 secoffset;
__le32 secsize;
union {
__le32 u4SecSpec[13];
struct {
__le32 dlAddr;
__le32 dlsize;
__le32 seckeyidx;
__le32 alignlen;
__le32 sectype;
__le32 dlmodecrctype;
__le32 crc;
__le32 reserved[6];
} bin_info_spec;
};
} __packed;
int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
{
struct btmtk_hci_wmt_params wmt_params;
struct btmtk_global_desc *globaldesc = NULL;
struct btmtk_section_map *sectionmap;
const struct firmware *fw;
const u8 *fw_ptr;
const u8 *fw_bin_ptr;
int err, dlen, i, status;
u8 flag, first_block, retry;
u32 section_num, dl_size, section_offset;
u8 cmd[64];
err = request_firmware(&fw, fwname, &hdev->dev);
if (err < 0) {
bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
return err;
}
fw_ptr = fw->data;
fw_bin_ptr = fw_ptr;
globaldesc = (struct btmtk_global_desc *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE);
section_num = le32_to_cpu(globaldesc->section_num);
for (i = 0; i < section_num; i++) {
first_block = 1;
fw_ptr = fw_bin_ptr;
sectionmap = (struct btmtk_section_map *)(fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
MTK_FW_ROM_PATCH_GD_SIZE + MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i);
section_offset = le32_to_cpu(sectionmap->secoffset);
dl_size = le32_to_cpu(sectionmap->bin_info_spec.dlsize);
if (dl_size > 0) {
retry = 20;
while (retry > 0) {
cmd[0] = 0; /* 0 means legacy dl mode. */
memcpy(cmd + 1,
fw_ptr + MTK_FW_ROM_PATCH_HEADER_SIZE +
MTK_FW_ROM_PATCH_GD_SIZE +
MTK_FW_ROM_PATCH_SEC_MAP_SIZE * i +
MTK_SEC_MAP_COMMON_SIZE,
MTK_SEC_MAP_NEED_SEND_SIZE + 1);
wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
wmt_params.status = &status;
wmt_params.flag = 0;
wmt_params.dlen = MTK_SEC_MAP_NEED_SEND_SIZE + 1;
wmt_params.data = &cmd;
err = wmt_cmd_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
err);
goto err_release_fw;
}
if (status == BTMTK_WMT_PATCH_UNDONE) {
break;
} else if (status == BTMTK_WMT_PATCH_PROGRESS) {
msleep(100);
retry--;
} else if (status == BTMTK_WMT_PATCH_DONE) {
goto next_section;
} else {
bt_dev_err(hdev, "Failed wmt patch dwnld status (%d)",
status);
goto err_release_fw;
}
}
fw_ptr += section_offset;
wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
wmt_params.status = NULL;
while (dl_size > 0) {
dlen = min_t(int, 250, dl_size);
if (first_block == 1) {
flag = 1;
first_block = 0;
} else if (dl_size - dlen <= 0) {
flag = 3;
} else {
flag = 2;
}
wmt_params.flag = flag;
wmt_params.dlen = dlen;
wmt_params.data = fw_ptr;
err = wmt_cmd_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
err);
goto err_release_fw;
}
dl_size -= dlen;
fw_ptr += dlen;
}
}
next_section:
continue;
}
/* Wait a few moments for firmware activation done */
usleep_range(100000, 120000);
err_release_fw:
release_firmware(fw);
return err;
}
EXPORT_SYMBOL_GPL(btmtk_setup_firmware_79xx);
int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
{
struct btmtk_hci_wmt_params wmt_params;
const struct firmware *fw;
const u8 *fw_ptr;
size_t fw_size;
int err, dlen;
u8 flag, param;
err = request_firmware(&fw, fwname, &hdev->dev);
if (err < 0) {
bt_dev_err(hdev, "Failed to load firmware file (%d)", err);
return err;
}
/* Power on data RAM the firmware relies on. */
param = 1;
wmt_params.op = BTMTK_WMT_FUNC_CTRL;
wmt_params.flag = 3;
wmt_params.dlen = sizeof(param);
wmt_params.data = &param;
wmt_params.status = NULL;
err = wmt_cmd_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to power on data RAM (%d)", err);
goto err_release_fw;
}
fw_ptr = fw->data;
fw_size = fw->size;
/* The size of patch header is 30 bytes, should be skip */
if (fw_size < 30) {
err = -EINVAL;
goto err_release_fw;
}
fw_size -= 30;
fw_ptr += 30;
flag = 1;
wmt_params.op = BTMTK_WMT_PATCH_DWNLD;
wmt_params.status = NULL;
while (fw_size > 0) {
dlen = min_t(int, 250, fw_size);
/* Tell device the position in sequence */
if (fw_size - dlen <= 0)
flag = 3;
else if (fw_size < fw->size - 30)
flag = 2;
wmt_params.flag = flag;
wmt_params.dlen = dlen;
wmt_params.data = fw_ptr;
err = wmt_cmd_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt patch dwnld (%d)",
err);
goto err_release_fw;
}
fw_size -= dlen;
fw_ptr += dlen;
}
wmt_params.op = BTMTK_WMT_RST;
wmt_params.flag = 4;
wmt_params.dlen = 0;
wmt_params.data = NULL;
wmt_params.status = NULL;
/* Activate funciton the firmware providing to */
err = wmt_cmd_sync(hdev, &wmt_params);
if (err < 0) {
bt_dev_err(hdev, "Failed to send wmt rst (%d)", err);
goto err_release_fw;
}
/* Wait a few moments for firmware activation done */
usleep_range(10000, 12000);
err_release_fw:
release_firmware(fw);
return err;
}
EXPORT_SYMBOL_GPL(btmtk_setup_firmware);
int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
long ret;
skb = __hci_cmd_sync(hdev, 0xfc1a, 6, bdaddr, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
bt_dev_err(hdev, "changing Mediatek device address failed (%ld)",
ret);
return ret;
}
kfree_skb(skb);
return 0;
}
EXPORT_SYMBOL_GPL(btmtk_set_bdaddr);
MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
MODULE_AUTHOR("Mark Chen <mark-yw.chen@mediatek.com>");
MODULE_DESCRIPTION("Bluetooth support for MediaTek devices ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FIRMWARE_MT7663);
MODULE_FIRMWARE(FIRMWARE_MT7668);
MODULE_FIRMWARE(FIRMWARE_MT7961);
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2021 MediaTek Inc. */
#define FIRMWARE_MT7663 "mediatek/mt7663pr2h.bin"
#define FIRMWARE_MT7668 "mediatek/mt7668pr2h.bin"
#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin"
#define HCI_WMT_MAX_EVENT_SIZE 64
#define BTMTK_WMT_REG_READ 0x2
enum {
BTMTK_WMT_PATCH_DWNLD = 0x1,
BTMTK_WMT_TEST = 0x2,
BTMTK_WMT_WAKEUP = 0x3,
BTMTK_WMT_HIF = 0x4,
BTMTK_WMT_FUNC_CTRL = 0x6,
BTMTK_WMT_RST = 0x7,
BTMTK_WMT_REGISTER = 0x8,
BTMTK_WMT_SEMAPHORE = 0x17,
};
enum {
BTMTK_WMT_INVALID,
BTMTK_WMT_PATCH_UNDONE,
BTMTK_WMT_PATCH_PROGRESS,
BTMTK_WMT_PATCH_DONE,
BTMTK_WMT_ON_UNDONE,
BTMTK_WMT_ON_DONE,
BTMTK_WMT_ON_PROGRESS,
};
struct btmtk_wmt_hdr {
u8 dir;
u8 op;
__le16 dlen;
u8 flag;
} __packed;
struct btmtk_hci_wmt_cmd {
struct btmtk_wmt_hdr hdr;
u8 data[];
} __packed;
struct btmtk_hci_wmt_evt {
struct hci_event_hdr hhdr;
struct btmtk_wmt_hdr whdr;
} __packed;
struct btmtk_hci_wmt_evt_funcc {
struct btmtk_hci_wmt_evt hwhdr;
__be16 status;
} __packed;
struct btmtk_hci_wmt_evt_reg {
struct btmtk_hci_wmt_evt hwhdr;
u8 rsv[2];
u8 num;
__le32 addr;
__le32 val;
} __packed;
struct btmtk_tci_sleep {
u8 mode;
__le16 duration;
__le16 host_duration;
u8 host_wakeup_pin;
u8 time_compensation;
} __packed;
struct btmtk_hci_wmt_params {
u8 op;
u8 flag;
u16 dlen;
const void *data;
u32 *status;
};
typedef int (*wmt_cmd_sync_func_t)(struct hci_dev *,
struct btmtk_hci_wmt_params *);
#if IS_ENABLED(CONFIG_BT_MTK)
int btmtk_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync);
int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync);
#else
static inline int btmtk_set_bdaddr(struct hci_dev *hdev,
const bdaddr_t *bdaddr)
{
return -EOPNOTSUPP;
}
static int btmtk_setup_firmware_79xx(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
{
return -EOPNOTSUPP;
}
static int btmtk_setup_firmware(struct hci_dev *hdev, const char *fwname,
wmt_cmd_sync_func_t wmt_cmd_sync)
{
return -EOPNOTSUPP;
}
#endif
This diff is collapsed.
......@@ -295,6 +295,8 @@ static int btsdio_probe(struct sdio_func *func,
switch (func->device) {
case SDIO_DEVICE_ID_BROADCOM_43341:
case SDIO_DEVICE_ID_BROADCOM_43430:
case SDIO_DEVICE_ID_BROADCOM_4345:
case SDIO_DEVICE_ID_BROADCOM_43455:
case SDIO_DEVICE_ID_BROADCOM_4356:
return -ENODEV;
}
......
This diff is collapsed.
......@@ -1508,7 +1508,6 @@ static const struct of_device_id bcm_bluetooth_of_match[] = {
{ .compatible = "brcm,bcm4330-bt" },
{ .compatible = "brcm,bcm4334-bt" },
{ .compatible = "brcm,bcm4345c5" },
{ .compatible = "brcm,bcm4330-bt" },
{ .compatible = "brcm,bcm43438-bt", .data = &bcm43438_device_data },
{ .compatible = "brcm,bcm43540-bt", .data = &bcm4354_device_data },
{ .compatible = "brcm,bcm4335a0" },
......
......@@ -252,7 +252,7 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
}
if (!dlen) {
hu->padding = (skb->len - 1) % alignment;
hu->padding = (skb->len + 1) % alignment;
hu->padding = (alignment - hu->padding) % alignment;
/* No more data, complete frame */
......@@ -260,7 +260,7 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
skb = NULL;
}
} else {
hu->padding = (skb->len - 1) % alignment;
hu->padding = (skb->len + 1) % alignment;
hu->padding = (alignment - hu->padding) % alignment;
/* Complete frame */
......
......@@ -38,9 +38,12 @@ struct vhci_data {
struct mutex open_mutex;
struct delayed_work open_timeout;
struct work_struct suspend_work;
bool suspended;
bool wakeup;
__u16 msft_opcode;
bool aosp_capable;
};
static int vhci_open_dev(struct hci_dev *hdev)
......@@ -114,6 +117,17 @@ static ssize_t force_suspend_read(struct file *file, char __user *user_buf,
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static void vhci_suspend_work(struct work_struct *work)
{
struct vhci_data *data = container_of(work, struct vhci_data,
suspend_work);
if (data->suspended)
hci_suspend_dev(data->hdev);
else
hci_resume_dev(data->hdev);
}
static ssize_t force_suspend_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
......@@ -129,16 +143,10 @@ static ssize_t force_suspend_write(struct file *file,
if (data->suspended == enable)
return -EALREADY;
if (enable)
err = hci_suspend_dev(data->hdev);
else
err = hci_resume_dev(data->hdev);
if (err)
return err;
data->suspended = enable;
schedule_work(&data->suspend_work);
return count;
}
......@@ -176,6 +184,8 @@ static ssize_t force_wakeup_write(struct file *file,
if (data->wakeup == enable)
return -EALREADY;
data->wakeup = enable;
return count;
}
......@@ -186,6 +196,88 @@ static const struct file_operations force_wakeup_fops = {
.llseek = default_llseek,
};
static int msft_opcode_set(void *data, u64 val)
{
struct vhci_data *vhci = data;
if (val > 0xffff || hci_opcode_ogf(val) != 0x3f)
return -EINVAL;
if (vhci->msft_opcode)
return -EALREADY;
vhci->msft_opcode = val;
return 0;
}
static int msft_opcode_get(void *data, u64 *val)
{
struct vhci_data *vhci = data;
*val = vhci->msft_opcode;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(msft_opcode_fops, msft_opcode_get, msft_opcode_set,
"%llu\n");
static ssize_t aosp_capable_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct vhci_data *vhci = file->private_data;
char buf[3];
buf[0] = vhci->aosp_capable ? 'Y' : 'N';
buf[1] = '\n';
buf[2] = '\0';
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
}
static ssize_t aosp_capable_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
{
struct vhci_data *vhci = file->private_data;
bool enable;
int err;
err = kstrtobool_from_user(user_buf, count, &enable);
if (err)
return err;
if (!enable)
return -EINVAL;
if (vhci->aosp_capable)
return -EALREADY;
vhci->aosp_capable = enable;
return count;
}
static const struct file_operations aosp_capable_fops = {
.open = simple_open,
.read = aosp_capable_read,
.write = aosp_capable_write,
.llseek = default_llseek,
};
static int vhci_setup(struct hci_dev *hdev)
{
struct vhci_data *vhci = hci_get_drvdata(hdev);
if (vhci->msft_opcode)
hci_set_msft_opcode(hdev, vhci->msft_opcode);
if (vhci->aosp_capable)
hci_set_aosp_capable(hdev);
return 0;
}
static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
{
struct hci_dev *hdev;
......@@ -228,6 +320,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
hdev->get_data_path_id = vhci_get_data_path_id;
hdev->get_codec_config_data = vhci_get_codec_config_data;
hdev->wakeup = vhci_wakeup;
hdev->setup = vhci_setup;
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
/* bit 6 is for external configuration */
if (opcode & 0x40)
......@@ -251,6 +345,14 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
&force_wakeup_fops);
if (IS_ENABLED(CONFIG_BT_MSFTEXT))
debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data,
&msft_opcode_fops);
if (IS_ENABLED(CONFIG_BT_AOSPEXT))
debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data,
&aosp_capable_fops);
hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
skb_put_u8(skb, 0xff);
......@@ -440,6 +542,7 @@ static int vhci_open(struct inode *inode, struct file *file)
mutex_init(&data->open_mutex);
INIT_DELAYED_WORK(&data->open_timeout, vhci_open_timeout);
INIT_WORK(&data->suspend_work, vhci_suspend_work);
file->private_data = data;
nonseekable_open(inode, file);
......@@ -455,6 +558,7 @@ static int vhci_release(struct inode *inode, struct file *file)
struct hci_dev *hdev;
cancel_delayed_work_sync(&data->open_timeout);
flush_work(&data->suspend_work);
hdev = data->hdev;
......
......@@ -202,6 +202,9 @@ static void virtbt_rx_handle(struct virtio_bluetooth *vbt, struct sk_buff *skb)
hci_skb_pkt_type(skb) = pkt_type;
hci_recv_frame(vbt->hdev, skb);
break;
default:
kfree_skb(skb);
break;
}
}
......
......@@ -105,6 +105,7 @@
#define SDIO_VENDOR_ID_MEDIATEK 0x037a
#define SDIO_DEVICE_ID_MEDIATEK_MT7663 0x7663
#define SDIO_DEVICE_ID_MEDIATEK_MT7668 0x7668
#define SDIO_DEVICE_ID_MEDIATEK_MT7961 0x7961
#define SDIO_VENDOR_ID_MICROCHIP_WILC 0x0296
#define SDIO_DEVICE_ID_MICROCHIP_WILC1000 0x5347
......
......@@ -380,6 +380,7 @@ typedef void (*hci_req_complete_skb_t)(struct hci_dev *hdev, u8 status,
#define HCI_REQ_SKB BIT(1)
struct hci_ctrl {
struct sock *sk;
u16 opcode;
u8 req_flags;
u8 req_event;
......@@ -405,6 +406,7 @@ struct bt_skb_cb {
#define hci_skb_pkt_type(skb) bt_cb((skb))->pkt_type
#define hci_skb_expect(skb) bt_cb((skb))->expect
#define hci_skb_opcode(skb) bt_cb((skb))->hci.opcode
#define hci_skb_sk(skb) bt_cb((skb))->hci.sk
static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
{
......
......@@ -566,6 +566,7 @@ enum {
#define HCI_ERROR_INVALID_LL_PARAMS 0x1e
#define HCI_ERROR_UNSPECIFIED 0x1f
#define HCI_ERROR_ADVERTISING_TIMEOUT 0x3c
#define HCI_ERROR_CANCELLED_BY_HOST 0x44
/* Flow control modes */
#define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
......
......@@ -30,6 +30,7 @@
#include <linux/rculist.h>
#include <net/bluetooth/hci.h>
#include <net/bluetooth/hci_sync.h>
#include <net/bluetooth/hci_sock.h>
/* HCI priority */
......@@ -475,6 +476,9 @@ struct hci_dev {
struct work_struct power_on;
struct delayed_work power_off;
struct work_struct error_reset;
struct work_struct cmd_sync_work;
struct list_head cmd_sync_work_list;
struct mutex cmd_sync_work_lock;
__u16 discov_timeout;
struct delayed_work discov_off;
......@@ -489,10 +493,7 @@ struct hci_dev {
struct work_struct tx_work;
struct work_struct discov_update;
struct work_struct bg_scan_update;
struct work_struct scan_update;
struct work_struct connectable_update;
struct work_struct discoverable_update;
struct delayed_work le_scan_disable;
struct delayed_work le_scan_restart;
......@@ -519,7 +520,6 @@ struct hci_dev {
bool advertising_paused;
struct notifier_block suspend_notifier;
struct work_struct suspend_prepare;
enum suspended_state suspend_state_next;
enum suspended_state suspend_state;
bool scanning_paused;
......@@ -528,9 +528,6 @@ struct hci_dev {
bdaddr_t wake_addr;
u8 wake_addr_type;
wait_queue_head_t suspend_wait_q;
DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS);
struct hci_conn_hash conn_hash;
struct list_head mgmt_pending;
......@@ -603,6 +600,7 @@ struct hci_dev {
#if IS_ENABLED(CONFIG_BT_AOSPEXT)
bool aosp_capable;
bool aosp_quality_report;
#endif
int (*open)(struct hci_dev *hdev);
......@@ -1461,8 +1459,11 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define scan_coded(dev) (((dev)->le_tx_def_phys & HCI_LE_SET_PHY_CODED) || \
((dev)->le_rx_def_phys & HCI_LE_SET_PHY_CODED))
#define ll_privacy_capable(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
/* Use LL Privacy based address resolution if supported */
#define use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
#define use_ll_privacy(dev) (ll_privacy_capable(dev) && \
hci_dev_test_flag(dev, HCI_ENABLE_LL_PRIVACY))
/* Use enhanced synchronous connection if command is supported */
#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
......@@ -1690,10 +1691,6 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
int hci_register_cb(struct hci_cb *hcb);
int hci_unregister_cb(struct hci_cb *hcb);
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout);
int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param);
......@@ -1704,9 +1701,6 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
u32 hci_conn_get_phy(struct hci_conn *conn);
/* ----- HCI Sockets ----- */
......@@ -1806,7 +1800,6 @@ int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 entered);
void mgmt_auth_failed(struct hci_conn *conn, u8 status);
void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
u8 status);
void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
......@@ -1831,8 +1824,6 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t *bdaddr,
u16 max_interval, u16 latency, u16 timeout);
void mgmt_smp_complete(struct hci_conn *conn, bool complete);
bool mgmt_get_connectable(struct hci_dev *hdev);
void mgmt_set_connectable_complete(struct hci_dev *hdev, u8 status);
void mgmt_set_discoverable_complete(struct hci_dev *hdev, u8 status);
u8 mgmt_get_adv_discov_flags(struct hci_dev *hdev);
void mgmt_advertising_added(struct sock *sk, struct hci_dev *hdev,
u8 instance);
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2021 Intel Corporation
*/
typedef int (*hci_cmd_sync_work_func_t)(struct hci_dev *hdev, void *data);
typedef void (*hci_cmd_sync_work_destroy_t)(struct hci_dev *hdev, void *data,
int err);
struct hci_cmd_sync_work_entry {
struct list_head list;
hci_cmd_sync_work_func_t func;
void *data;
hci_cmd_sync_work_destroy_t destroy;
};
/* Function with sync suffix shall not be called with hdev->lock held as they
* wait the command to complete and in the meantime an event could be received
* which could attempt to acquire hdev->lock causing a deadlock.
*/
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout);
struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout,
struct sock *sk);
int __hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u32 timeout);
int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
const void *param, u8 event, u32 timeout,
struct sock *sk);
void hci_cmd_sync_init(struct hci_dev *hdev);
void hci_cmd_sync_clear(struct hci_dev *hdev);
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);
int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_eir_sync(struct hci_dev *hdev);
int hci_update_class_sync(struct hci_dev *hdev);
int hci_update_name_sync(struct hci_dev *hdev);
int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode);
int hci_update_random_address_sync(struct hci_dev *hdev, bool require_privacy,
bool rpa, u8 *own_addr_type);
int hci_update_scan_rsp_data_sync(struct hci_dev *hdev, u8 instance);
int hci_update_adv_data_sync(struct hci_dev *hdev, u8 instance);
int hci_schedule_adv_instance_sync(struct hci_dev *hdev, u8 instance,
bool force);
int hci_setup_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance);
int hci_start_ext_adv_sync(struct hci_dev *hdev, u8 instance);
int hci_enable_ext_advertising_sync(struct hci_dev *hdev, u8 instance);
int hci_enable_advertising_sync(struct hci_dev *hdev);
int hci_enable_advertising(struct hci_dev *hdev);
int hci_remove_advertising_sync(struct hci_dev *hdev, struct sock *sk,
u8 instance, bool force);
int hci_disable_advertising_sync(struct hci_dev *hdev);
int hci_update_passive_scan_sync(struct hci_dev *hdev);
int hci_update_passive_scan(struct hci_dev *hdev);
int hci_read_rssi_sync(struct hci_dev *hdev, __le16 handle);
int hci_read_tx_power_sync(struct hci_dev *hdev, __le16 handle, u8 type);
int hci_write_sc_support_sync(struct hci_dev *hdev, u8 val);
int hci_read_clock_sync(struct hci_dev *hdev, struct hci_cp_read_clock *cp);
int hci_write_fast_connectable_sync(struct hci_dev *hdev, bool enable);
int hci_update_scan_sync(struct hci_dev *hdev);
int hci_write_le_host_supported_sync(struct hci_dev *hdev, u8 le, u8 simul);
int hci_remove_ext_adv_instance_sync(struct hci_dev *hdev, u8 instance,
struct sock *sk);
struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev, bool ext,
struct sock *sk);
int hci_reset_sync(struct hci_dev *hdev);
int hci_dev_open_sync(struct hci_dev *hdev);
int hci_dev_close_sync(struct hci_dev *hdev);
int hci_powered_update_sync(struct hci_dev *hdev);
int hci_set_powered_sync(struct hci_dev *hdev, u8 val);
int hci_update_discoverable_sync(struct hci_dev *hdev);
int hci_update_discoverable(struct hci_dev *hdev);
int hci_update_connectable_sync(struct hci_dev *hdev);
int hci_start_discovery_sync(struct hci_dev *hdev);
int hci_stop_discovery_sync(struct hci_dev *hdev);
int hci_suspend_sync(struct hci_dev *hdev);
int hci_resume_sync(struct hci_dev *hdev);
......@@ -15,7 +15,7 @@ bluetooth_6lowpan-y := 6lowpan.o
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \
eir.o
eir.o hci_sync.o
bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
......
......@@ -8,9 +8,43 @@
#include "aosp.h"
/* Command complete parameters of LE_Get_Vendor_Capabilities_Command
* The parameters grow over time. The base version that declares the
* version_supported field is v0.95. Refer to
* https://cs.android.com/android/platform/superproject/+/master:system/
* bt/gd/hci/controller.cc;l=452?q=le_get_vendor_capabilities_handler
*/
struct aosp_rp_le_get_vendor_capa {
/* v0.95: 15 octets */
__u8 status;
__u8 max_advt_instances;
__u8 offloaded_resolution_of_private_address;
__le16 total_scan_results_storage;
__u8 max_irk_list_sz;
__u8 filtering_support;
__u8 max_filter;
__u8 activity_energy_info_support;
__le16 version_supported;
__le16 total_num_of_advt_tracked;
__u8 extended_scan_support;
__u8 debug_logging_supported;
/* v0.96: 16 octets */
__u8 le_address_generation_offloading_support;
/* v0.98: 21 octets */
__le32 a2dp_source_offload_capability_mask;
__u8 bluetooth_quality_report_support;
/* v1.00: 25 octets */
__le32 dynamic_audio_buffer_support;
} __packed;
#define VENDOR_CAPA_BASE_SIZE 15
#define VENDOR_CAPA_0_98_SIZE 21
void aosp_do_open(struct hci_dev *hdev)
{
struct sk_buff *skb;
struct aosp_rp_le_get_vendor_capa *rp;
u16 version_supported;
if (!hdev->aosp_capable)
return;
......@@ -20,9 +54,54 @@ void aosp_do_open(struct hci_dev *hdev)
/* LE Get Vendor Capabilities Command */
skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb))
if (IS_ERR(skb)) {
bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)",
PTR_ERR(skb));
return;
}
/* A basic length check */
if (skb->len < VENDOR_CAPA_BASE_SIZE)
goto length_error;
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. */
bt_dev_info(hdev, "AOSP extensions version v%u.%02u",
version_supported >> 8, version_supported & 0xff);
/* Do not support very old versions. */
if (version_supported < 95) {
bt_dev_warn(hdev, "AOSP capabilities version %u too old",
version_supported);
goto done;
}
if (version_supported < 98) {
bt_dev_warn(hdev, "AOSP quality report is not supported");
goto done;
}
if (skb->len < VENDOR_CAPA_0_98_SIZE)
goto length_error;
/* The bluetooth_quality_report_support is defined at version
* v0.98. Refer to
* https://cs.android.com/android/platform/superproject/+/
* master:system/bt/gd/hci/controller.cc;l=477
*/
if (rp->bluetooth_quality_report_support) {
hdev->aosp_quality_report = true;
bt_dev_info(hdev, "AOSP quality report is supported");
}
goto done;
length_error:
bt_dev_err(hdev, "AOSP capabilities length %d too short", skb->len);
done:
kfree_skb(skb);
}
......@@ -33,3 +112,90 @@ void aosp_do_close(struct hci_dev *hdev)
bt_dev_dbg(hdev, "Cleanup of AOSP extension");
}
/* BQR command */
#define BQR_OPCODE hci_opcode_pack(0x3f, 0x015e)
/* BQR report action */
#define REPORT_ACTION_ADD 0x00
#define REPORT_ACTION_DELETE 0x01
#define REPORT_ACTION_CLEAR 0x02
/* BQR event masks */
#define QUALITY_MONITORING BIT(0)
#define APPRAOCHING_LSTO BIT(1)
#define A2DP_AUDIO_CHOPPY BIT(2)
#define SCO_VOICE_CHOPPY BIT(3)
#define DEFAULT_BQR_EVENT_MASK (QUALITY_MONITORING | APPRAOCHING_LSTO | \
A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY)
/* Reporting at milliseconds so as not to stress the controller too much.
* Range: 0 ~ 65535 ms
*/
#define DEFALUT_REPORT_INTERVAL_MS 5000
struct aosp_bqr_cp {
__u8 report_action;
__u32 event_mask;
__u16 min_report_interval;
} __packed;
static int enable_quality_report(struct hci_dev *hdev)
{
struct sk_buff *skb;
struct aosp_bqr_cp cp;
cp.report_action = REPORT_ACTION_ADD;
cp.event_mask = DEFAULT_BQR_EVENT_MASK;
cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS;
skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Enabling Android BQR failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
return 0;
}
static int disable_quality_report(struct hci_dev *hdev)
{
struct sk_buff *skb;
struct aosp_bqr_cp cp = { 0 };
cp.report_action = REPORT_ACTION_CLEAR;
skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Disabling Android BQR failed (%ld)",
PTR_ERR(skb));
return PTR_ERR(skb);
}
kfree_skb(skb);
return 0;
}
bool aosp_has_quality_report(struct hci_dev *hdev)
{
return hdev->aosp_quality_report;
}
int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
{
if (!aosp_has_quality_report(hdev))
return -EOPNOTSUPP;
bt_dev_dbg(hdev, "quality report enable %d", enable);
/* Enable or disable the quality report feature. */
if (enable)
return enable_quality_report(hdev);
else
return disable_quality_report(hdev);
}
......@@ -8,9 +8,22 @@
void aosp_do_open(struct hci_dev *hdev);
void aosp_do_close(struct hci_dev *hdev);
bool aosp_has_quality_report(struct hci_dev *hdev);
int aosp_set_quality_report(struct hci_dev *hdev, bool enable);
#else
static inline void aosp_do_open(struct hci_dev *hdev) {}
static inline void aosp_do_close(struct hci_dev *hdev) {}
static inline bool aosp_has_quality_report(struct hci_dev *hdev)
{
return false;
}
static inline int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
{
return -EOPNOTSUPP;
}
#endif
......@@ -501,9 +501,7 @@ static int __init cmtp_init(void)
{
BT_INFO("CMTP (CAPI Emulation) ver %s", VERSION);
cmtp_init_sockets();
return 0;
return cmtp_init_sockets();
}
static void __exit cmtp_exit(void)
......
......@@ -25,9 +25,11 @@ static int hci_codec_list_add(struct list_head *list,
}
entry->transport = sent->transport;
entry->len = len;
entry->num_caps = rp->num_caps;
if (rp->num_caps)
entry->num_caps = 0;
if (rp) {
entry->num_caps = rp->num_caps;
memcpy(entry->caps, caps, len);
}
list_add(&entry->list, list);
return 0;
......@@ -58,6 +60,18 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
__u32 len;
cmd->transport = i;
/* If Read_Codec_Capabilities command is not supported
* then just add codec to the list without caps
*/
if (!(hdev->commands[45] & 0x08)) {
hci_dev_lock(hdev);
hci_codec_list_add(&hdev->local_codecs, cmd,
NULL, NULL, 0);
hci_dev_unlock(hdev);
continue;
}
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
sizeof(*cmd), cmd,
HCI_CMD_TIMEOUT);
......
......@@ -108,7 +108,7 @@ static void hci_connect_le_scan_cleanup(struct hci_conn *conn)
break;
}
hci_update_background_scan(hdev);
hci_update_passive_scan(hdev);
}
static void hci_conn_cleanup(struct hci_conn *conn)
......@@ -900,25 +900,15 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
hci_conn_del(conn);
/* The suspend notifier is waiting for all devices to disconnect and an
* LE connect cancel will result in an hci_le_conn_failed. Once the last
* connection is deleted, we should also wake the suspend queue to
* complete suspend operations.
*/
if (list_empty(&hdev->conn_hash.list) &&
test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
wake_up(&hdev->suspend_wait_q);
}
/* Since we may have temporarily stopped the background scanning in
* favor of connection establishment, we should restart it.
*/
hci_update_background_scan(hdev);
hci_update_passive_scan(hdev);
/* Re-enable advertising in case this was a failed connection
/* Enable advertising in case this was a failed connection
* attempt as a peripheral.
*/
hci_req_reenable_advertising(hdev);
hci_enable_advertising(hdev);
}
static void create_le_conn_complete(struct hci_dev *hdev, u8 status, u16 opcode)
......@@ -1411,7 +1401,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
conn->conn_timeout = conn_timeout;
conn->conn_reason = conn_reason;
hci_update_background_scan(hdev);
hci_update_passive_scan(hdev);
done:
hci_conn_hold(conn);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -22,9 +22,17 @@
#include <asm/unaligned.h>
#define HCI_REQ_DONE 0
#define HCI_REQ_PEND 1
#define HCI_REQ_CANCELED 2
#define hci_req_sync_lock(hdev) mutex_lock(&hdev->req_lock)
#define hci_req_sync_unlock(hdev) mutex_unlock(&hdev->req_lock)
#define HCI_REQ_DONE 0
#define HCI_REQ_PEND 1
#define HCI_REQ_CANCELED 2
struct hci_request {
struct hci_dev *hdev;
struct sk_buff_head cmd_q;
......@@ -40,6 +48,8 @@ void hci_req_purge(struct hci_request *req);
bool hci_req_status_pend(struct hci_dev *hdev);
int hci_req_run(struct hci_request *req, hci_req_complete_t complete);
int hci_req_run_skb(struct hci_request *req, hci_req_complete_skb_t complete);
void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
struct sk_buff *skb);
void hci_req_add(struct hci_request *req, u16 opcode, u32 plen,
const void *param);
void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
......@@ -117,10 +127,5 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason);
void __hci_abort_conn(struct hci_request *req, struct hci_conn *conn,
u8 reason);
static inline void hci_update_background_scan(struct hci_dev *hdev)
{
queue_work(hdev->req_workqueue, &hdev->bg_scan_update);
}
void hci_request_setup(struct hci_dev *hdev);
void hci_request_cancel_all(struct hci_dev *hdev);
......@@ -889,10 +889,6 @@ static int hci_sock_release(struct socket *sock)
}
sock_orphan(sk);
skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue);
release_sock(sk);
sock_put(sk);
return 0;
......@@ -2058,6 +2054,12 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
return err;
}
static void hci_sock_destruct(struct sock *sk)
{
skb_queue_purge(&sk->sk_receive_queue);
skb_queue_purge(&sk->sk_write_queue);
}
static const struct proto_ops hci_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
......@@ -2111,6 +2113,7 @@ static int hci_sock_create(struct net *net, struct socket *sock, int protocol,
sock->state = SS_UNCONNECTED;
sk->sk_state = BT_OPEN;
sk->sk_destruct = hci_sock_destruct;
bt_sock_link(&hci_sk_list, sk);
return 0;
......
This diff is collapsed.
......@@ -86,6 +86,8 @@ static void bt_host_release(struct device *dev)
if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
hci_release_dev(hdev);
else
kfree(hdev);
module_put(THIS_MODULE);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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