Skip to content

Commit 0442529

Browse files
Hsin-chen ChuangVudentz
authored andcommitted
Bluetooth: Introduce HCI Driver protocol
Although commit 75ddcd5 ("Bluetooth: btusb: Configure altsetting for HCI_USER_CHANNEL") has enabled the HCI_USER_CHANNEL user to send out SCO data through USB Bluetooth chips, it's observed that with the patch HFP is flaky on most of the existing USB Bluetooth controllers: Intel chips sometimes send out no packet for Transparent codec; MTK chips may generate SCO data with a wrong handle for CVSD codec; RTK could split the data with a wrong packet size for Transparent codec; ... etc. To address the issue above one needs to reset the altsetting back to zero when there is no active SCO connection, which is the same as the BlueZ behavior, and another benefit is the bus doesn't need to reserve bandwidth when no SCO connection. This patch adds the infrastructure that allow the user space program to talk to Bluetooth drivers directly: - Define the new packet type HCI_DRV_PKT which is specifically used for communication between the user space program and the Bluetooth drviers - hci_send_frame intercepts the packets and invokes drivers' HCI Drv callbacks (so far only defined for btusb) - 2 kinds of events to user space: Command Status and Command Complete, the former simply returns the status while the later may contain additional response data. Cc: chromeos-bluetooth-upstreaming@chromium.org Fixes: b16b327 ("Bluetooth: btusb: add sysfs attribute to control USB alt setting") Signed-off-by: Hsin-chen Chuang <chharry@chromium.org> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
1 parent c50b566 commit 0442529

File tree

9 files changed

+273
-9
lines changed

9 files changed

+273
-9
lines changed

drivers/bluetooth/btusb.c

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <net/bluetooth/bluetooth.h>
2323
#include <net/bluetooth/hci_core.h>
24+
#include <net/bluetooth/hci_drv.h>
2425

2526
#include "btintel.h"
2627
#include "btbcm.h"
@@ -3800,6 +3801,61 @@ static ssize_t isoc_alt_store(struct device *dev,
38003801

38013802
static DEVICE_ATTR_RW(isoc_alt);
38023803

3804+
static const struct {
3805+
u16 opcode;
3806+
const char *desc;
3807+
} btusb_hci_drv_supported_commands[] = {
3808+
/* Common commands */
3809+
{ HCI_DRV_OP_READ_INFO, "Read Info" },
3810+
};
3811+
static int btusb_hci_drv_read_info(struct hci_dev *hdev, void *data,
3812+
u16 data_len)
3813+
{
3814+
struct hci_drv_rp_read_info *rp;
3815+
size_t rp_size;
3816+
int err, i;
3817+
u16 opcode, num_supported_commands =
3818+
ARRAY_SIZE(btusb_hci_drv_supported_commands);
3819+
3820+
rp_size = sizeof(*rp) + num_supported_commands * 2;
3821+
3822+
rp = kmalloc(rp_size, GFP_KERNEL);
3823+
if (!rp)
3824+
return -ENOMEM;
3825+
3826+
strscpy_pad(rp->driver_name, btusb_driver.name);
3827+
3828+
rp->num_supported_commands = cpu_to_le16(num_supported_commands);
3829+
for (i = 0; i < num_supported_commands; i++) {
3830+
opcode = btusb_hci_drv_supported_commands[i].opcode;
3831+
bt_dev_info(hdev,
3832+
"Supported HCI Drv command (0x%02x|0x%04x): %s",
3833+
hci_opcode_ogf(opcode),
3834+
hci_opcode_ocf(opcode),
3835+
btusb_hci_drv_supported_commands[i].desc);
3836+
rp->supported_commands[i] = cpu_to_le16(opcode);
3837+
}
3838+
3839+
err = hci_drv_cmd_complete(hdev, HCI_DRV_OP_READ_INFO,
3840+
HCI_DRV_STATUS_SUCCESS, rp, rp_size);
3841+
3842+
kfree(rp);
3843+
return err;
3844+
}
3845+
3846+
static const struct hci_drv_handler btusb_hci_drv_common_handlers[] = {
3847+
{ btusb_hci_drv_read_info, HCI_DRV_READ_INFO_SIZE },
3848+
};
3849+
3850+
static const struct hci_drv_handler btusb_hci_drv_specific_handlers[] = {};
3851+
3852+
static struct hci_drv btusb_hci_drv = {
3853+
.common_handler_count = ARRAY_SIZE(btusb_hci_drv_common_handlers),
3854+
.common_handlers = btusb_hci_drv_common_handlers,
3855+
.specific_handler_count = ARRAY_SIZE(btusb_hci_drv_specific_handlers),
3856+
.specific_handlers = btusb_hci_drv_specific_handlers,
3857+
};
3858+
38033859
static int btusb_probe(struct usb_interface *intf,
38043860
const struct usb_device_id *id)
38053861
{
@@ -3939,12 +3995,13 @@ static int btusb_probe(struct usb_interface *intf,
39393995
data->reset_gpio = reset_gpio;
39403996
}
39413997

3942-
hdev->open = btusb_open;
3943-
hdev->close = btusb_close;
3944-
hdev->flush = btusb_flush;
3945-
hdev->send = btusb_send_frame;
3946-
hdev->notify = btusb_notify;
3947-
hdev->wakeup = btusb_wakeup;
3998+
hdev->open = btusb_open;
3999+
hdev->close = btusb_close;
4000+
hdev->flush = btusb_flush;
4001+
hdev->send = btusb_send_frame;
4002+
hdev->notify = btusb_notify;
4003+
hdev->wakeup = btusb_wakeup;
4004+
hdev->hci_drv = &btusb_hci_drv;
39484005

39494006
#ifdef CONFIG_PM
39504007
err = btusb_config_oob_wake(hdev);

include/net/bluetooth/hci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ enum {
494494
#define HCI_EVENT_PKT 0x04
495495
#define HCI_ISODATA_PKT 0x05
496496
#define HCI_DIAG_PKT 0xf0
497+
#define HCI_DRV_PKT 0xf1
497498
#define HCI_VENDOR_PKT 0xff
498499

499500
/* HCI packet types */

include/net/bluetooth/hci_core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/rculist.h>
3232

3333
#include <net/bluetooth/hci.h>
34+
#include <net/bluetooth/hci_drv.h>
3435
#include <net/bluetooth/hci_sync.h>
3536
#include <net/bluetooth/hci_sock.h>
3637
#include <net/bluetooth/coredump.h>
@@ -613,6 +614,8 @@ struct hci_dev {
613614
struct list_head monitored_devices;
614615
bool advmon_pend_notify;
615616

617+
struct hci_drv *hci_drv;
618+
616619
#if IS_ENABLED(CONFIG_BT_LEDS)
617620
struct led_trigger *power_led;
618621
#endif

include/net/bluetooth/hci_drv.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2025 Google Corporation
4+
*/
5+
6+
#ifndef __HCI_DRV_H
7+
#define __HCI_DRV_H
8+
9+
#include <linux/types.h>
10+
11+
#include <net/bluetooth/bluetooth.h>
12+
#include <net/bluetooth/hci.h>
13+
14+
struct hci_drv_cmd_hdr {
15+
__le16 opcode;
16+
__le16 len;
17+
} __packed;
18+
19+
struct hci_drv_ev_hdr {
20+
__le16 opcode;
21+
__le16 len;
22+
} __packed;
23+
24+
#define HCI_DRV_EV_CMD_STATUS 0x0000
25+
struct hci_drv_ev_cmd_status {
26+
__le16 opcode;
27+
__u8 status;
28+
} __packed;
29+
30+
#define HCI_DRV_EV_CMD_COMPLETE 0x0001
31+
struct hci_drv_ev_cmd_complete {
32+
__le16 opcode;
33+
__u8 status;
34+
__u8 data[];
35+
} __packed;
36+
37+
#define HCI_DRV_STATUS_SUCCESS 0x00
38+
#define HCI_DRV_STATUS_UNSPECIFIED_ERROR 0x01
39+
#define HCI_DRV_STATUS_UNKNOWN_COMMAND 0x02
40+
#define HCI_DRV_STATUS_INVALID_PARAMETERS 0x03
41+
42+
#define HCI_DRV_MAX_DRIVER_NAME_LENGTH 32
43+
44+
/* Common commands that make sense on all drivers start from 0x0000 */
45+
#define HCI_DRV_OP_READ_INFO 0x0000
46+
#define HCI_DRV_READ_INFO_SIZE 0
47+
struct hci_drv_rp_read_info {
48+
__u8 driver_name[HCI_DRV_MAX_DRIVER_NAME_LENGTH];
49+
__le16 num_supported_commands;
50+
__le16 supported_commands[];
51+
} __packed;
52+
53+
/* Driver specific OGF (Opcode Group Field)
54+
* Commands in this group may have different meanings across different drivers.
55+
*/
56+
#define HCI_DRV_OGF_DRIVER_SPECIFIC 0x01
57+
58+
int hci_drv_cmd_status(struct hci_dev *hdev, u16 cmd, u8 status);
59+
int hci_drv_cmd_complete(struct hci_dev *hdev, u16 cmd, u8 status, void *rp,
60+
size_t rp_len);
61+
int hci_drv_process_cmd(struct hci_dev *hdev, struct sk_buff *cmd_skb);
62+
63+
struct hci_drv_handler {
64+
int (*func)(struct hci_dev *hdev, void *data, u16 data_len);
65+
size_t data_len;
66+
};
67+
68+
struct hci_drv {
69+
size_t common_handler_count;
70+
const struct hci_drv_handler *common_handlers;
71+
72+
size_t specific_handler_count;
73+
const struct hci_drv_handler *specific_handlers;
74+
};
75+
76+
#endif /* __HCI_DRV_H */

include/net/bluetooth/hci_mon.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ struct hci_mon_hdr {
5151
#define HCI_MON_CTRL_EVENT 17
5252
#define HCI_MON_ISO_TX_PKT 18
5353
#define HCI_MON_ISO_RX_PKT 19
54+
#define HCI_MON_DRV_TX_PKT 20
55+
#define HCI_MON_DRV_RX_PKT 21
5456

5557
struct hci_mon_new_index {
5658
__u8 type;

net/bluetooth/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ bluetooth_6lowpan-y := 6lowpan.o
1414

1515
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
1616
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
17-
ecdh_helper.o mgmt_util.o mgmt_config.o hci_codec.o eir.o hci_sync.o
17+
ecdh_helper.o mgmt_util.o mgmt_config.o hci_codec.o eir.o hci_sync.o \
18+
hci_drv.o
1819

1920
bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o
2021

net/bluetooth/hci_core.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,6 +2911,8 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
29112911
break;
29122912
case HCI_ISODATA_PKT:
29132913
break;
2914+
case HCI_DRV_PKT:
2915+
break;
29142916
default:
29152917
kfree_skb(skb);
29162918
return -EINVAL;
@@ -3019,6 +3021,15 @@ static int hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
30193021
return -EINVAL;
30203022
}
30213023

3024+
if (hci_skb_pkt_type(skb) == HCI_DRV_PKT) {
3025+
/* Intercept HCI Drv packet here and don't go with hdev->send
3026+
* callback.
3027+
*/
3028+
err = hci_drv_process_cmd(hdev, skb);
3029+
kfree_skb(skb);
3030+
return err;
3031+
}
3032+
30223033
err = hdev->send(hdev, skb);
30233034
if (err < 0) {
30243035
bt_dev_err(hdev, "sending frame failed (%d)", err);

net/bluetooth/hci_drv.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2025 Google Corporation
4+
*/
5+
6+
#include <linux/skbuff.h>
7+
#include <linux/types.h>
8+
9+
#include <net/bluetooth/bluetooth.h>
10+
#include <net/bluetooth/hci.h>
11+
#include <net/bluetooth/hci_core.h>
12+
#include <net/bluetooth/hci_drv.h>
13+
14+
int hci_drv_cmd_status(struct hci_dev *hdev, u16 cmd, u8 status)
15+
{
16+
struct hci_drv_ev_hdr *hdr;
17+
struct hci_drv_ev_cmd_status *ev;
18+
struct sk_buff *skb;
19+
20+
skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
21+
if (!skb)
22+
return -ENOMEM;
23+
24+
hdr = skb_put(skb, sizeof(*hdr));
25+
hdr->opcode = __cpu_to_le16(HCI_DRV_EV_CMD_STATUS);
26+
hdr->len = __cpu_to_le16(sizeof(*ev));
27+
28+
ev = skb_put(skb, sizeof(*ev));
29+
ev->opcode = __cpu_to_le16(cmd);
30+
ev->status = status;
31+
32+
hci_skb_pkt_type(skb) = HCI_DRV_PKT;
33+
34+
return hci_recv_frame(hdev, skb);
35+
}
36+
EXPORT_SYMBOL(hci_drv_cmd_status);
37+
38+
int hci_drv_cmd_complete(struct hci_dev *hdev, u16 cmd, u8 status, void *rp,
39+
size_t rp_len)
40+
{
41+
struct hci_drv_ev_hdr *hdr;
42+
struct hci_drv_ev_cmd_complete *ev;
43+
struct sk_buff *skb;
44+
45+
skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
46+
if (!skb)
47+
return -ENOMEM;
48+
49+
hdr = skb_put(skb, sizeof(*hdr));
50+
hdr->opcode = __cpu_to_le16(HCI_DRV_EV_CMD_COMPLETE);
51+
hdr->len = __cpu_to_le16(sizeof(*ev) + rp_len);
52+
53+
ev = skb_put(skb, sizeof(*ev));
54+
ev->opcode = __cpu_to_le16(cmd);
55+
ev->status = status;
56+
57+
skb_put_data(skb, rp, rp_len);
58+
59+
hci_skb_pkt_type(skb) = HCI_DRV_PKT;
60+
61+
return hci_recv_frame(hdev, skb);
62+
}
63+
EXPORT_SYMBOL(hci_drv_cmd_complete);
64+
65+
int hci_drv_process_cmd(struct hci_dev *hdev, struct sk_buff *skb)
66+
{
67+
struct hci_drv_cmd_hdr *hdr;
68+
const struct hci_drv_handler *handler = NULL;
69+
u16 opcode, len, ogf, ocf;
70+
71+
hdr = skb_pull_data(skb, sizeof(*hdr));
72+
if (!hdr)
73+
return -EILSEQ;
74+
75+
opcode = __le16_to_cpu(hdr->opcode);
76+
len = __le16_to_cpu(hdr->len);
77+
if (len != skb->len)
78+
return -EILSEQ;
79+
80+
ogf = hci_opcode_ogf(opcode);
81+
ocf = hci_opcode_ocf(opcode);
82+
83+
if (!hdev->hci_drv)
84+
return hci_drv_cmd_status(hdev, opcode,
85+
HCI_DRV_STATUS_UNKNOWN_COMMAND);
86+
87+
if (ogf != HCI_DRV_OGF_DRIVER_SPECIFIC) {
88+
if (opcode < hdev->hci_drv->common_handler_count)
89+
handler = &hdev->hci_drv->common_handlers[opcode];
90+
} else {
91+
if (ocf < hdev->hci_drv->specific_handler_count)
92+
handler = &hdev->hci_drv->specific_handlers[ocf];
93+
}
94+
95+
if (!handler || !handler->func)
96+
return hci_drv_cmd_status(hdev, opcode,
97+
HCI_DRV_STATUS_UNKNOWN_COMMAND);
98+
99+
if (len != handler->data_len)
100+
return hci_drv_cmd_status(hdev, opcode,
101+
HCI_DRV_STATUS_INVALID_PARAMETERS);
102+
103+
return handler->func(hdev, skb->data, len);
104+
}
105+
EXPORT_SYMBOL(hci_drv_process_cmd);

net/bluetooth/hci_sock.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,8 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
234234
if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
235235
hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
236236
hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
237-
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT)
237+
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT &&
238+
hci_skb_pkt_type(skb) != HCI_DRV_PKT)
238239
continue;
239240
} else {
240241
/* Don't send frame to other channel types */
@@ -391,6 +392,12 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
391392
else
392393
opcode = cpu_to_le16(HCI_MON_ISO_TX_PKT);
393394
break;
395+
case HCI_DRV_PKT:
396+
if (bt_cb(skb)->incoming)
397+
opcode = cpu_to_le16(HCI_MON_DRV_RX_PKT);
398+
else
399+
opcode = cpu_to_le16(HCI_MON_DRV_TX_PKT);
400+
break;
394401
case HCI_DIAG_PKT:
395402
opcode = cpu_to_le16(HCI_MON_VENDOR_DIAG);
396403
break;
@@ -1860,7 +1867,8 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
18601867
if (hci_skb_pkt_type(skb) != HCI_COMMAND_PKT &&
18611868
hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
18621869
hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
1863-
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) {
1870+
hci_skb_pkt_type(skb) != HCI_ISODATA_PKT &&
1871+
hci_skb_pkt_type(skb) != HCI_DRV_PKT) {
18641872
err = -EINVAL;
18651873
goto drop;
18661874
}

0 commit comments

Comments
 (0)