1 /*
2 * Copyright (c) 2019 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/init.h>
8 #include <zephyr/sys/byteorder.h>
9
10 #include <zephyr/bluetooth/bluetooth.h>
11 #include <zephyr/bluetooth/hci.h>
12 #include <zephyr/drivers/bluetooth.h>
13
14 #include <zephyr/device.h>
15 #include <zephyr/ipc/ipc_service.h>
16
17 #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(bt_hci_driver);
20
21 #define DT_DRV_COMPAT zephyr_bt_hci_ipc
22
23 #define IPC_BOUND_TIMEOUT_IN_MS K_MSEC(1000)
24
25 struct ipc_data {
26 bt_hci_recv_t recv;
27 struct ipc_ept hci_ept;
28 struct ipc_ept_cfg hci_ept_cfg;
29 struct k_sem bound_sem;
30 const struct device *ipc;
31 };
32
is_hci_event_discardable(const uint8_t * evt_data)33 static bool is_hci_event_discardable(const uint8_t *evt_data)
34 {
35 uint8_t evt_type = evt_data[0];
36
37 switch (evt_type) {
38 #if defined(CONFIG_BT_CLASSIC)
39 case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI:
40 case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT:
41 return true;
42 #endif
43 case BT_HCI_EVT_LE_META_EVENT: {
44 uint8_t subevt_type = evt_data[sizeof(struct bt_hci_evt_hdr)];
45
46 switch (subevt_type) {
47 case BT_HCI_EVT_LE_ADVERTISING_REPORT:
48 return true;
49 #if defined(CONFIG_BT_EXT_ADV)
50 case BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT:
51 {
52 const struct bt_hci_evt_le_ext_advertising_report *ext_adv =
53 (void *)&evt_data[3];
54
55 return (ext_adv->num_reports == 1) &&
56 ((ext_adv->adv_info[0].evt_type &
57 BT_HCI_LE_ADV_EVT_TYPE_LEGACY) != 0);
58 }
59 #endif
60 default:
61 return false;
62 }
63 }
64 default:
65 return false;
66 }
67 }
68
bt_ipc_evt_recv(const uint8_t * data,size_t remaining)69 static struct net_buf *bt_ipc_evt_recv(const uint8_t *data, size_t remaining)
70 {
71 bool discardable;
72 struct bt_hci_evt_hdr hdr;
73 struct net_buf *buf;
74 size_t buf_tailroom;
75
76 if (remaining < sizeof(hdr)) {
77 LOG_ERR("Not enough data for event header");
78 return NULL;
79 }
80
81 discardable = is_hci_event_discardable(data);
82
83 memcpy((void *)&hdr, data, sizeof(hdr));
84 data += sizeof(hdr);
85 remaining -= sizeof(hdr);
86
87 if (remaining != hdr.len) {
88 LOG_ERR("Event payload length is not correct");
89 return NULL;
90 }
91 LOG_DBG("len %u", hdr.len);
92
93 do {
94 buf = bt_buf_get_evt(hdr.evt, discardable, discardable ? K_NO_WAIT : K_SECONDS(10));
95 if (!buf) {
96 if (discardable) {
97 LOG_DBG("Discardable buffer pool full, ignoring event");
98 return buf;
99 }
100 LOG_WRN("Couldn't allocate a buffer after waiting 10 seconds.");
101 }
102 } while (!buf);
103
104 net_buf_add_mem(buf, &hdr, sizeof(hdr));
105
106 buf_tailroom = net_buf_tailroom(buf);
107 if (buf_tailroom < remaining) {
108 LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom);
109 net_buf_unref(buf);
110 return NULL;
111 }
112
113 net_buf_add_mem(buf, data, remaining);
114
115 return buf;
116 }
117
bt_ipc_acl_recv(const uint8_t * data,size_t remaining)118 static struct net_buf *bt_ipc_acl_recv(const uint8_t *data, size_t remaining)
119 {
120 struct bt_hci_acl_hdr hdr;
121 struct net_buf *buf;
122 size_t buf_tailroom;
123
124 if (remaining < sizeof(hdr)) {
125 LOG_ERR("Not enough data for ACL header");
126 return NULL;
127 }
128
129 buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_NO_WAIT);
130 if (buf) {
131 memcpy((void *)&hdr, data, sizeof(hdr));
132 data += sizeof(hdr);
133 remaining -= sizeof(hdr);
134
135 net_buf_add_mem(buf, &hdr, sizeof(hdr));
136 } else {
137 LOG_ERR("No available ACL buffers!");
138 return NULL;
139 }
140
141 if (remaining != sys_le16_to_cpu(hdr.len)) {
142 LOG_ERR("ACL payload length is not correct");
143 net_buf_unref(buf);
144 return NULL;
145 }
146
147 buf_tailroom = net_buf_tailroom(buf);
148 if (buf_tailroom < remaining) {
149 LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom);
150 net_buf_unref(buf);
151 return NULL;
152 }
153
154 LOG_DBG("len %u", remaining);
155 net_buf_add_mem(buf, data, remaining);
156
157 return buf;
158 }
159
bt_ipc_iso_recv(const uint8_t * data,size_t remaining)160 static struct net_buf *bt_ipc_iso_recv(const uint8_t *data, size_t remaining)
161 {
162 struct bt_hci_iso_hdr hdr;
163 static size_t fail_cnt;
164 struct net_buf *buf;
165 size_t buf_tailroom;
166
167 if (remaining < sizeof(hdr)) {
168 LOG_ERR("Not enough data for ISO header");
169 return NULL;
170 }
171
172 buf = bt_buf_get_rx(BT_BUF_ISO_IN, K_NO_WAIT);
173 if (buf) {
174 memcpy((void *)&hdr, data, sizeof(hdr));
175 data += sizeof(hdr);
176 remaining -= sizeof(hdr);
177
178 net_buf_add_mem(buf, &hdr, sizeof(hdr));
179
180 fail_cnt = 0U;
181 } else {
182 if ((fail_cnt % 100U) == 0U) {
183 LOG_ERR("No available ISO buffers (%zu)!", fail_cnt);
184 }
185
186 fail_cnt++;
187
188 return NULL;
189 }
190
191 if (remaining != bt_iso_hdr_len(sys_le16_to_cpu(hdr.len))) {
192 LOG_ERR("ISO payload length is not correct");
193 net_buf_unref(buf);
194 return NULL;
195 }
196
197 buf_tailroom = net_buf_tailroom(buf);
198 if (buf_tailroom < remaining) {
199 LOG_ERR("Not enough space in buffer %zu/%zu", remaining, buf_tailroom);
200 net_buf_unref(buf);
201 return NULL;
202 }
203
204 LOG_DBG("len %zu", remaining);
205 net_buf_add_mem(buf, data, remaining);
206
207 return buf;
208 }
209
bt_ipc_rx(const struct device * dev,const uint8_t * data,size_t len)210 static void bt_ipc_rx(const struct device *dev, const uint8_t *data, size_t len)
211 {
212 struct ipc_data *ipc = dev->data;
213 uint8_t pkt_indicator;
214 struct net_buf *buf = NULL;
215 size_t remaining = len;
216
217 LOG_HEXDUMP_DBG(data, len, "ipc data:");
218
219 pkt_indicator = *data++;
220 remaining -= sizeof(pkt_indicator);
221
222 switch (pkt_indicator) {
223 case BT_HCI_H4_EVT:
224 buf = bt_ipc_evt_recv(data, remaining);
225 break;
226
227 case BT_HCI_H4_ACL:
228 buf = bt_ipc_acl_recv(data, remaining);
229 break;
230
231 case BT_HCI_H4_ISO:
232 buf = bt_ipc_iso_recv(data, remaining);
233 break;
234
235 default:
236 LOG_ERR("Unknown HCI type %u", pkt_indicator);
237 return;
238 }
239
240 if (buf) {
241 LOG_DBG("Calling bt_recv(%p)", buf);
242 ipc->recv(dev, buf);
243
244 LOG_HEXDUMP_DBG(buf->data, buf->len, "RX buf payload:");
245 }
246 }
247
bt_ipc_send(const struct device * dev,struct net_buf * buf)248 static int bt_ipc_send(const struct device *dev, struct net_buf *buf)
249 {
250 struct ipc_data *data = dev->data;
251 int err;
252 uint8_t pkt_indicator;
253
254 LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
255
256 switch (bt_buf_get_type(buf)) {
257 case BT_BUF_ACL_OUT:
258 pkt_indicator = BT_HCI_H4_ACL;
259 break;
260 case BT_BUF_CMD:
261 pkt_indicator = BT_HCI_H4_CMD;
262 break;
263 case BT_BUF_ISO_OUT:
264 pkt_indicator = BT_HCI_H4_ISO;
265 break;
266 default:
267 LOG_ERR("Unknown type %u", bt_buf_get_type(buf));
268 goto done;
269 }
270 net_buf_push_u8(buf, pkt_indicator);
271
272 LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:");
273 err = ipc_service_send(&data->hci_ept, buf->data, buf->len);
274 if (err < 0) {
275 LOG_ERR("Failed to send (err %d)", err);
276 }
277
278 done:
279 net_buf_unref(buf);
280 return 0;
281 }
282
hci_ept_bound(void * priv)283 static void hci_ept_bound(void *priv)
284 {
285 const struct device *dev = priv;
286 struct ipc_data *ipc = dev->data;
287
288 k_sem_give(&ipc->bound_sem);
289 }
290
hci_ept_recv(const void * data,size_t len,void * priv)291 static void hci_ept_recv(const void *data, size_t len, void *priv)
292 {
293 const struct device *dev = priv;
294
295 bt_ipc_rx(dev, data, len);
296 }
297
bt_hci_transport_setup(const struct device * dev)298 int __weak bt_hci_transport_setup(const struct device *dev)
299 {
300 ARG_UNUSED(dev);
301 return 0;
302 }
303
bt_hci_transport_teardown(const struct device * dev)304 int __weak bt_hci_transport_teardown(const struct device *dev)
305 {
306 ARG_UNUSED(dev);
307 return 0;
308 }
309
bt_ipc_open(const struct device * dev,bt_hci_recv_t recv)310 static int bt_ipc_open(const struct device *dev, bt_hci_recv_t recv)
311 {
312 struct ipc_data *ipc = dev->data;
313 int err;
314
315 err = bt_hci_transport_setup(NULL);
316 if (err) {
317 LOG_ERR("HCI transport setup failed with: %d\n", err);
318 return err;
319 }
320
321 LOG_DBG("");
322
323 err = ipc_service_open_instance(ipc->ipc);
324 if (err && (err != -EALREADY)) {
325 LOG_ERR("IPC service instance initialization failed: %d\n", err);
326 return err;
327 }
328
329 err = ipc_service_register_endpoint(ipc->ipc, &ipc->hci_ept, &ipc->hci_ept_cfg);
330 if (err) {
331 LOG_ERR("Registering endpoint failed with %d", err);
332 return err;
333 }
334
335 err = k_sem_take(&ipc->bound_sem, IPC_BOUND_TIMEOUT_IN_MS);
336 if (err) {
337 LOG_ERR("Endpoint binding failed with %d", err);
338 return err;
339 }
340
341 ipc->recv = recv;
342
343 return 0;
344 }
345
bt_ipc_close(const struct device * dev)346 static int bt_ipc_close(const struct device *dev)
347 {
348 struct ipc_data *ipc = dev->data;
349 int err;
350
351 if (IS_ENABLED(CONFIG_BT_HCI_HOST)) {
352 err = bt_hci_cmd_send_sync(BT_HCI_OP_RESET, NULL, NULL);
353 if (err) {
354 LOG_ERR("Sending reset command failed with: %d", err);
355 return err;
356 }
357 }
358
359 err = ipc_service_deregister_endpoint(&ipc->hci_ept);
360 if (err) {
361 LOG_ERR("Deregistering HCI endpoint failed with: %d", err);
362 return err;
363 }
364
365 err = ipc_service_close_instance(ipc->ipc);
366 if (err) {
367 LOG_ERR("Closing IPC service failed with: %d", err);
368 return err;
369 }
370
371 err = bt_hci_transport_teardown(NULL);
372 if (err) {
373 LOG_ERR("HCI transport teardown failed with: %d", err);
374 return err;
375 }
376
377 ipc->recv = NULL;
378
379 return 0;
380 }
381
382 static DEVICE_API(bt_hci, drv) = {
383 .open = bt_ipc_open,
384 .close = bt_ipc_close,
385 .send = bt_ipc_send,
386 };
387
388 #define IPC_DEVICE_INIT(inst) \
389 static struct ipc_data ipc_data_##inst = { \
390 .bound_sem = Z_SEM_INITIALIZER(ipc_data_##inst.bound_sem, 0, 1), \
391 .hci_ept_cfg = { \
392 .name = DT_INST_PROP(inst, bt_hci_ipc_name), \
393 .cb = { \
394 .bound = hci_ept_bound, \
395 .received = hci_ept_recv, \
396 }, \
397 .priv = (void *)DEVICE_DT_INST_GET(inst), \
398 }, \
399 .ipc = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
400 }; \
401 DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &ipc_data_##inst, NULL, \
402 POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv)
403
404 DT_INST_FOREACH_STATUS_OKAY(IPC_DEVICE_INIT)
405