Skip to content

Commit 8961987

Browse files
kirankrishnappa-intelVudentz
authored andcommitted
Bluetooth: Enumerate local supported codec and cache details
Move reading of supported local codecs into a separate init function, query codecs capabilities and cache the data Signed-off-by: Kiran K <[email protected]> Signed-off-by: Chethan T N <[email protected]> Signed-off-by: Srivatsa Ravishankar <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 49d8a56 commit 8961987

File tree

6 files changed

+244
-5
lines changed

6 files changed

+244
-5
lines changed

include/net/bluetooth/hci.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,28 @@ struct hci_rp_read_data_block_size {
13081308
} __packed;
13091309

13101310
#define HCI_OP_READ_LOCAL_CODECS 0x100b
1311+
struct hci_std_codecs {
1312+
__u8 num;
1313+
__u8 codec[];
1314+
} __packed;
1315+
1316+
struct hci_vnd_codec {
1317+
/* company id */
1318+
__le16 cid;
1319+
/* vendor codec id */
1320+
__le16 vid;
1321+
} __packed;
1322+
1323+
struct hci_vnd_codecs {
1324+
__u8 num;
1325+
struct hci_vnd_codec codec[];
1326+
} __packed;
1327+
1328+
struct hci_rp_read_local_supported_codecs {
1329+
__u8 status;
1330+
struct hci_std_codecs std_codecs;
1331+
struct hci_vnd_codecs vnd_codecs;
1332+
} __packed;
13111333

13121334
#define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c
13131335
struct hci_rp_read_local_pairing_opts {
@@ -1316,6 +1338,25 @@ struct hci_rp_read_local_pairing_opts {
13161338
__u8 max_key_size;
13171339
} __packed;
13181340

1341+
#define HCI_OP_READ_LOCAL_CODEC_CAPS 0x100e
1342+
struct hci_op_read_local_codec_caps {
1343+
__u8 id;
1344+
__le16 cid;
1345+
__le16 vid;
1346+
__u8 transport;
1347+
__u8 direction;
1348+
} __packed;
1349+
1350+
struct hci_codec_caps {
1351+
__u8 len;
1352+
__u8 data[];
1353+
} __packed;
1354+
1355+
struct hci_rp_read_local_codec_caps {
1356+
__u8 status;
1357+
__u8 num_caps;
1358+
} __packed;
1359+
13191360
#define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
13201361
struct hci_rp_read_page_scan_activity {
13211362
__u8 status;

include/net/bluetooth/hci_core.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,17 @@ struct bdaddr_list {
131131
u8 bdaddr_type;
132132
};
133133

134+
struct codec_list {
135+
struct list_head list;
136+
u8 id;
137+
__u16 cid;
138+
__u16 vid;
139+
u8 transport;
140+
u8 num_caps;
141+
u32 len;
142+
struct hci_codec_caps caps[];
143+
};
144+
134145
struct bdaddr_list_with_irk {
135146
struct list_head list;
136147
bdaddr_t bdaddr;
@@ -536,6 +547,7 @@ struct hci_dev {
536547
struct list_head pend_le_conns;
537548
struct list_head pend_le_reports;
538549
struct list_head blocked_keys;
550+
struct list_head local_codecs;
539551

540552
struct hci_dev_stats stat;
541553

@@ -1870,4 +1882,9 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
18701882
#define SCO_AIRMODE_CVSD 0x0000
18711883
#define SCO_AIRMODE_TRANSP 0x0003
18721884

1885+
#define LOCAL_CODEC_ACL_MASK BIT(0)
1886+
#define LOCAL_CODEC_SCO_MASK BIT(1)
1887+
1888+
#define TRANSPORT_TYPE_MAX 0x04
1889+
18731890
#endif /* __HCI_CORE_H */

net/bluetooth/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ 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 hci_request.o mgmt_util.o mgmt_config.o
17+
ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o
1818

1919
bluetooth-$(CONFIG_BT_BREDR) += sco.o
2020
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o

net/bluetooth/hci_codec.c

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
/* Copyright (C) 2021 Intel Corporation */
4+
5+
#include <net/bluetooth/bluetooth.h>
6+
#include <net/bluetooth/hci_core.h>
7+
#include "hci_codec.h"
8+
9+
static int hci_codec_list_add(struct list_head *list,
10+
struct hci_op_read_local_codec_caps *sent,
11+
struct hci_rp_read_local_codec_caps *rp,
12+
void *caps,
13+
__u32 len)
14+
{
15+
struct codec_list *entry;
16+
17+
entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
18+
if (!entry)
19+
return -ENOMEM;
20+
21+
entry->id = sent->id;
22+
if (sent->id == 0xFF) {
23+
entry->cid = __le16_to_cpu(sent->cid);
24+
entry->vid = __le16_to_cpu(sent->vid);
25+
}
26+
entry->transport = sent->transport;
27+
entry->len = len;
28+
entry->num_caps = rp->num_caps;
29+
if (rp->num_caps)
30+
memcpy(entry->caps, caps, len);
31+
list_add(&entry->list, list);
32+
33+
return 0;
34+
}
35+
36+
void hci_codec_list_clear(struct list_head *codec_list)
37+
{
38+
struct codec_list *c, *n;
39+
40+
list_for_each_entry_safe(c, n, codec_list, list) {
41+
list_del(&c->list);
42+
kfree(c);
43+
}
44+
}
45+
46+
static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport,
47+
struct hci_op_read_local_codec_caps
48+
*cmd)
49+
{
50+
__u8 i;
51+
52+
for (i = 0; i < TRANSPORT_TYPE_MAX; i++) {
53+
if (transport & BIT(i)) {
54+
struct hci_rp_read_local_codec_caps *rp;
55+
struct hci_codec_caps *caps;
56+
struct sk_buff *skb;
57+
__u8 j;
58+
__u32 len;
59+
60+
cmd->transport = i;
61+
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
62+
sizeof(*cmd), cmd,
63+
HCI_CMD_TIMEOUT);
64+
if (IS_ERR(skb)) {
65+
bt_dev_err(hdev, "Failed to read codec capabilities (%ld)",
66+
PTR_ERR(skb));
67+
continue;
68+
}
69+
70+
if (skb->len < sizeof(*rp))
71+
goto error;
72+
73+
rp = (void *)skb->data;
74+
75+
if (rp->status)
76+
goto error;
77+
78+
if (!rp->num_caps) {
79+
len = 0;
80+
/* this codec doesn't have capabilities */
81+
goto skip_caps_parse;
82+
}
83+
84+
skb_pull(skb, sizeof(*rp));
85+
86+
for (j = 0, len = 0; j < rp->num_caps; j++) {
87+
caps = (void *)skb->data;
88+
if (skb->len < sizeof(*caps))
89+
goto error;
90+
if (skb->len < caps->len)
91+
goto error;
92+
len += sizeof(caps->len) + caps->len;
93+
skb_pull(skb, sizeof(caps->len) + caps->len);
94+
}
95+
96+
skip_caps_parse:
97+
hci_dev_lock(hdev);
98+
hci_codec_list_add(&hdev->local_codecs, cmd, rp,
99+
(__u8 *)rp + sizeof(*rp), len);
100+
hci_dev_unlock(hdev);
101+
error:
102+
kfree_skb(skb);
103+
}
104+
}
105+
}
106+
107+
void hci_read_supported_codecs(struct hci_dev *hdev)
108+
{
109+
struct sk_buff *skb;
110+
struct hci_rp_read_local_supported_codecs *rp;
111+
struct hci_std_codecs *std_codecs;
112+
struct hci_vnd_codecs *vnd_codecs;
113+
struct hci_op_read_local_codec_caps caps;
114+
__u8 i;
115+
116+
skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
117+
HCI_CMD_TIMEOUT);
118+
119+
if (IS_ERR(skb)) {
120+
bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
121+
PTR_ERR(skb));
122+
return;
123+
}
124+
125+
if (skb->len < sizeof(*rp))
126+
goto error;
127+
128+
rp = (void *)skb->data;
129+
130+
if (rp->status)
131+
goto error;
132+
133+
skb_pull(skb, sizeof(rp->status));
134+
135+
std_codecs = (void *)skb->data;
136+
137+
/* validate codecs length before accessing */
138+
if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
139+
+ sizeof(std_codecs->num))
140+
goto error;
141+
142+
/* enumerate codec capabilities of standard codecs */
143+
memset(&caps, 0, sizeof(caps));
144+
for (i = 0; i < std_codecs->num; i++) {
145+
caps.id = std_codecs->codec[i];
146+
caps.direction = 0x00;
147+
hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
148+
}
149+
150+
skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
151+
+ sizeof(std_codecs->num));
152+
153+
vnd_codecs = (void *)skb->data;
154+
155+
/* validate vendor codecs length before accessing */
156+
if (skb->len <
157+
flex_array_size(vnd_codecs, codec, vnd_codecs->num)
158+
+ sizeof(vnd_codecs->num))
159+
goto error;
160+
161+
/* enumerate vendor codec capabilities */
162+
for (i = 0; i < vnd_codecs->num; i++) {
163+
caps.id = 0xFF;
164+
caps.cid = vnd_codecs->codec[i].cid;
165+
caps.vid = vnd_codecs->codec[i].vid;
166+
caps.direction = 0x00;
167+
hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
168+
}
169+
170+
error:
171+
kfree_skb(skb);
172+
}

net/bluetooth/hci_codec.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
/* Copyright (C) 2014 Intel Corporation */
4+
5+
void hci_read_supported_codecs(struct hci_dev *hdev);
6+
void hci_codec_list_clear(struct list_head *codec_list);

net/bluetooth/hci_core.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "leds.h"
4646
#include "msft.h"
4747
#include "aosp.h"
48+
#include "hci_codec.h"
4849

4950
static void hci_rx_work(struct work_struct *work);
5051
static void hci_cmd_work(struct work_struct *work);
@@ -838,10 +839,6 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
838839
if (hdev->commands[22] & 0x04)
839840
hci_set_event_mask_page_2(req);
840841

841-
/* Read local codec list if the HCI command is supported */
842-
if (hdev->commands[29] & 0x20)
843-
hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL);
844-
845842
/* Read local pairing options if the HCI command is supported */
846843
if (hdev->commands[41] & 0x08)
847844
hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0, NULL);
@@ -937,6 +934,10 @@ static int __hci_init(struct hci_dev *hdev)
937934
if (err < 0)
938935
return err;
939936

937+
/* Read local codec list if the HCI command is supported */
938+
if (hdev->commands[29] & 0x20)
939+
hci_read_supported_codecs(hdev);
940+
940941
/* This function is only called when the controller is actually in
941942
* configured state. When the controller is marked as unconfigured,
942943
* this initialization procedure is not run.
@@ -1848,6 +1849,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
18481849
memset(hdev->eir, 0, sizeof(hdev->eir));
18491850
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
18501851
bacpy(&hdev->random_addr, BDADDR_ANY);
1852+
hci_codec_list_clear(&hdev->local_codecs);
18511853

18521854
hci_req_sync_unlock(hdev);
18531855

@@ -3848,6 +3850,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
38483850
INIT_LIST_HEAD(&hdev->adv_instances);
38493851
INIT_LIST_HEAD(&hdev->blocked_keys);
38503852

3853+
INIT_LIST_HEAD(&hdev->local_codecs);
38513854
INIT_WORK(&hdev->rx_work, hci_rx_work);
38523855
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
38533856
INIT_WORK(&hdev->tx_work, hci_tx_work);

0 commit comments

Comments
 (0)