1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <assert.h>
21 #include "securec.h"
22 #include "sysinit/sysinit.h"
23 #include "nimble/hci_common.h"
24 #include "host/ble_hs.h"
25 #include "nimble/nimble_port.h"
26 #include "nimble/ble_hci_trans.h"
27 #include "wm_bt.h"
28 #include "wm_mem.h"
29
30 #define BLE_HCI_UART_H4_NONE 0x00
31 #define BLE_HCI_UART_H4_CMD 0x01
32 #define BLE_HCI_UART_H4_ACL 0x02
33 #define BLE_HCI_UART_H4_SCO 0x03
34 #define BLE_HCI_UART_H4_EVT 0x04
35 #define BLE_HCI_UART_H4_SYNC_LOSS 0x80
36 #define BLE_HCI_UART_H4_SKIP_CMD 0x81
37 #define BLE_HCI_UART_H4_SKIP_ACL 0x82
38 #define BLE_HCI_UART_H4_LE_EVT 0x83
39 #define BLE_HCI_UART_H4_SKIP_EVT 0x84
40
41 #define BLE_HCI_EVENT_HDR_LEN (2)
42 #define BLE_HCI_CMD_HDR_LEN (3)
43
44 static volatile int ble_hci_cmd_pkts = 0;
45 static ble_hci_trans_rx_cmd_fn *ble_hci_rx_cmd_hs_cb;
46 static void *ble_hci_rx_cmd_hs_arg;
47 static ble_hci_trans_rx_acl_fn *ble_hci_rx_acl_hs_cb;
48 static void *ble_hci_rx_acl_hs_arg;
49 static struct os_mempool ble_hci_vuart_evt_hi_pool;
50
51 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
52 static os_membuf_t *ble_hci_vuart_evt_hi_buf = NULL;
53
54 #else
55 static os_membuf_t ble_hci_vuart_evt_hi_buf[
56 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
57 ];
58 #endif
59
60 static struct os_mempool ble_hci_vuart_evt_lo_pool;
61
62 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
63 static os_membuf_t *ble_hci_vuart_evt_lo_buf = NULL;
64 #else
65 static os_membuf_t ble_hci_vuart_evt_lo_buf[
66 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
67 ];
68 #endif
69
70 static struct os_mempool ble_hci_vuart_cmd_pool;
71
72 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
73 static os_membuf_t *ble_hci_vuart_cmd_buf = NULL;
74 #else
75 static os_membuf_t ble_hci_vuart_cmd_buf[OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)];
76 #endif
77
78 static struct os_mbuf_pool ble_hci_vuart_acl_mbuf_pool;
79 static struct os_mempool_ext ble_hci_vuart_acl_pool;
80
81 /*
82 * The MBUF payload size must accommodate the HCI data header size plus the
83 * maximum ACL data packet length. The ACL block size is the size of the
84 * mbufs we will allocate.
85 */
86 #define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \
87 + BLE_MBUF_MEMBLOCK_OVERHEAD \
88 + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
89
90 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
91 static os_membuf_t *ble_hci_vuart_acl_buf = NULL;
92 #else
93 static os_membuf_t ble_hci_vuart_acl_buf[OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), ACL_BLOCK_SIZE)
94 ];
95 #endif
96
97 #define HCI_VUART_RX_QUEUE 0
98
99 #if HCI_VUART_RX_QUEUE
100
101 #define HCI_RESP_QUEUE_FULL (20)
102 #define HCI_RESP_QUEUE_HALF_FULL (10)
103
104 struct QUEUE_ITEM {
105 int size;
106 uint8_t *payload;
107 TAILQ_ENTRY(QUEUE_ITEM) entries;
108 };
109
110 static TAILQ_HEAD(, QUEUE_ITEM) hci_resp_queue;
111 static volatile uint8_t hci_resp_queue_counter = 0;
112
113 static struct ble_npl_mutex hci_resp_queue_mutex;
114 static struct ble_npl_event ble_hs_ev_hci_rx;
115 static struct ble_npl_eventq hci_evt_rx_tx_queue;
116
117 #endif
118
119 #define HCI_DBG FALSE
120
121 #ifndef HCI_DBG
122 #define HCI_DBG TRUE
123 #endif
124
125 #if (HCI_DBG == TRUE)
126 #define HCIDBG(fmt, ...) \
127 do { \
128 if (1) \
129 printf("%s(L%d): " fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
130 } while (0)
131 #else
132 #define HCIDBG(param, ...)
133 #endif
134
135 #if (HCI_DBG == TRUE)
hci_dbg_hexstring(const char * msg,const uint8_t * ptr,int a_length)136 static void hci_dbg_hexstring(const char *msg, const uint8_t *ptr, int a_length)
137 {
138 #define DBG_TRACE_WARNING_MAX_SIZE_W 252
139 // 123
140 #define DBG_TRACE_WARNING_MAX_SIZE 256
141 // 128
142 char sbuffer[DBG_TRACE_WARNING_MAX_SIZE];
143 uint8_t offset = 0;
144 int i = 0;
145 int length = 0;
146
147 if (msg) {
148 printf("[%d]%s", tls_os_get_time(), msg);
149 }
150
151 if (a_length <= 0 || ptr == NULL) {
152 return;
153 }
154 length = a_length;
155
156 do {
157 for (; i < length; i++) {
158 offset += sprintf_s(sbuffer + offset, sizeof(sbuffer + offset), "%02X ", (uint8_t)ptr[i]);
159 if (offset > DBG_TRACE_WARNING_MAX_SIZE_W) {
160 break;
161 }
162 }
163
164 sbuffer[offset - 1] = '\r';
165 sbuffer[offset] = '\n';
166 sbuffer[offset + 1] = 0;
167
168 if (offset > DBG_TRACE_WARNING_MAX_SIZE_W) {
169 sbuffer[offset - 2] = '.'; // 2:byte alignment
170 sbuffer[offset - 3] = '.'; // 3:byte alignment
171 }
172
173 printf("%s", sbuffer);
174 offset = 0;
175 } while (i < length);
176 }
177 #endif
178
ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn * cmd_cb,void * cmd_arg,ble_hci_trans_rx_acl_fn * acl_cb,void * acl_arg)179 void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
180 void *cmd_arg,
181 ble_hci_trans_rx_acl_fn *acl_cb,
182 void *acl_arg)
183 {
184 ble_hci_rx_cmd_hs_cb = cmd_cb;
185 ble_hci_rx_cmd_hs_arg = cmd_arg;
186 ble_hci_rx_acl_hs_cb = acl_cb;
187 ble_hci_rx_acl_hs_arg = acl_arg;
188 }
ble_hci_trans_hs_cmd_tx(uint8_t * cmd)189 int ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
190 {
191 uint16_t len;
192 assert(cmd != NULL);
193 *cmd = BLE_HCI_UART_H4_CMD;
194 len = BLE_HCI_CMD_HDR_LEN + cmd[3] + 1; // 3:array element
195
196 while (ble_hci_cmd_pkts <= 0) {
197 tls_os_time_delay(1000 / HZ); // 1000:byte alignment
198 }
199 tls_bt_vuart_host_send_packet(cmd, len);
200 ble_hci_trans_buf_free(cmd);
201 return 0;
202 }
203
ble_hci_trans_ll_evt_tx(uint8_t * hci_ev)204 int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev)
205 {
206 int rc = -1;
207
208 if (ble_hci_rx_cmd_hs_cb) {
209 rc = ble_hci_rx_cmd_hs_cb(hci_ev, ble_hci_rx_cmd_hs_arg);
210 }
211
212 return rc;
213 }
214
ble_hci_trans_hs_acl_tx(struct os_mbuf * om)215 int ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
216 {
217 uint16_t len = 0;
218 uint8_t data[MYNEWT_VAL(BLE_ACL_BUF_SIZE) + 1];
219
220 /* If this packet is zero length, just free it */
221 if (OS_MBUF_PKTLEN(om) == 0) {
222 os_mbuf_free_chain(om);
223 return 0;
224 }
225
226 data[0] = BLE_HCI_UART_H4_ACL;
227 len++;
228
229 while (ble_hci_cmd_pkts <= 0) {
230 tls_os_time_delay(1000 / HZ); // 1000:byte alignment
231 }
232
233 os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), &data[1]);
234 len += OS_MBUF_PKTLEN(om);
235 tls_bt_vuart_host_send_packet(data, len);
236 os_mbuf_free_chain(om);
237 return 0;
238 }
239
ble_hci_trans_buf_alloc(int type)240 uint8_t *ble_hci_trans_buf_alloc(int type)
241 {
242 uint8_t *buf;
243
244 switch (type) {
245 case BLE_HCI_TRANS_BUF_CMD:
246 buf = os_memblock_get(&ble_hci_vuart_cmd_pool);
247 break;
248
249 case BLE_HCI_TRANS_BUF_EVT_HI:
250 buf = os_memblock_get(&ble_hci_vuart_evt_hi_pool);
251 if (buf == NULL) {
252 /* If no high-priority event buffers remain, try to grab a
253 * low-priority one.
254 */
255 buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
256 }
257
258 break;
259
260 case BLE_HCI_TRANS_BUF_EVT_LO:
261 buf = os_memblock_get(&ble_hci_vuart_evt_lo_pool);
262 break;
263
264 default:
265 assert(0);
266 buf = NULL;
267 }
268
269 return buf;
270 }
271
ble_hci_trans_buf_free(uint8_t * buf)272 void ble_hci_trans_buf_free(uint8_t *buf)
273 {
274 int rc;
275
276 /*
277 * XXX: this may look a bit odd, but the controller uses the command
278 * buffer to send back the command complete/status as an immediate
279 * response to the command. This was done to insure that the controller
280 * could always send back one of these events when a command was received.
281 * Thus, we check to see which pool the buffer came from so we can free
282 * it to the appropriate pool
283 */
284 if (os_memblock_from(&ble_hci_vuart_evt_hi_pool, buf)) {
285 rc = os_memblock_put(&ble_hci_vuart_evt_hi_pool, buf);
286 assert(rc == 0);
287 } else if (os_memblock_from(&ble_hci_vuart_evt_lo_pool, buf)) {
288 rc = os_memblock_put(&ble_hci_vuart_evt_lo_pool, buf);
289 assert(rc == 0);
290 } else {
291 assert(os_memblock_from(&ble_hci_vuart_cmd_pool, buf));
292 rc = os_memblock_put(&ble_hci_vuart_cmd_pool, buf);
293 assert(rc == 0);
294 }
295 }
296
297 /**
298 * Unsupported; the RAM transport does not have a dedicated ACL data packet
299 * pool.
300 */
ble_hci_trans_set_acl_free_cb(os_mempool_put_fn * cb,void * arg)301 int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
302 {
303 return BLE_ERR_UNSUPPORTED;
304 }
305
ble_hci_trans_reset(void)306 int ble_hci_trans_reset(void)
307 {
308 /* No work to do. All allocated buffers are owned by the host or
309 * controller, and they will get freed by their owners.
310 */
311 return 0;
312 }
313
314 /**
315 * Allocates a buffer (mbuf) for ACL operation.
316 *
317 * @return The allocated buffer on success;
318 * NULL on buffer exhaustion.
319 */
ble_hci_trans_acl_buf_alloc(void)320 static struct os_mbuf *ble_hci_trans_acl_buf_alloc(void)
321 {
322 struct os_mbuf *m;
323 uint8_t usrhdr_len;
324 #if MYNEWT_VAL(BLE_DEVICE)
325 usrhdr_len = sizeof(struct ble_mbuf_hdr);
326 #elif MYNEWT_VAL(BLE_HS_FLOW_CTRL)
327 usrhdr_len = BLE_MBUF_HS_HDR_LEN;
328 #else
329 usrhdr_len = 0;
330 #endif
331 m = os_mbuf_get_pkthdr(&ble_hci_vuart_acl_mbuf_pool, usrhdr_len);
332 return m;
333 }
334
ble_hci_rx_acl(uint8_t * data,uint16_t len)335 static void ble_hci_rx_acl(uint8_t *data, uint16_t len)
336 {
337 struct os_mbuf *m;
338 int sr;
339
340 if (len < BLE_HCI_DATA_HDR_SZ || len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) {
341 assert(0);
342 return;
343 }
344
345 m = ble_hci_trans_acl_buf_alloc();
346 if (!m) {
347 assert(0);
348 return;
349 }
350
351 if (os_mbuf_append(m, data, len)) {
352 assert(0);
353 os_mbuf_free_chain(m);
354 return;
355 }
356
357 OS_ENTER_CRITICAL(sr);
358
359 if (ble_hci_rx_acl_hs_cb) {
360 ble_hci_rx_acl_hs_cb(m, NULL);
361 }
362
363 OS_EXIT_CRITICAL(sr);
364 }
365
notify_host_send_available(int cnt)366 void notify_host_send_available(int cnt)
367 {
368 ble_hci_cmd_pkts = cnt;
369 }
370
ble_hci_trans_hs_rx(uint8_t * data,uint16_t len)371 static int ble_hci_trans_hs_rx(uint8_t *data, uint16_t len)
372 {
373 if (data[0] == BLE_HCI_UART_H4_EVT) {
374 uint8_t *evbuf;
375 int totlen;
376 int rc;
377 totlen = BLE_HCI_EVENT_HDR_LEN + data[2]; // 2:byte alignment
378 assert(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN);
379
380 if (data[1] == BLE_HCI_EVCODE_HW_ERROR) {
381 assert(0);
382 }
383
384 /* Allocate LE Advertising Report Event from lo pool only */
385 if ((data[1] == BLE_HCI_EVCODE_LE_META) && (data[3] == BLE_HCI_LE_SUBEV_ADV_RPT)) { // 3:byte alignment
386 evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
387 /* Skip advertising report if we're out of memory */
388 if (!evbuf) {
389 return 0;
390 }
391 } else {
392 evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
393 assert(evbuf != NULL);
394 }
395
396 memcpy_s(evbuf, sizeof(*evbuf), &data[1], totlen);
397 rc = ble_hci_trans_ll_evt_tx(evbuf);
398 assert(rc == 0);
399 } else if (data[0] == BLE_HCI_UART_H4_ACL) {
400 ble_hci_rx_acl(data + 1, len - 1);
401 }
402
403 return 0;
404 }
405
406 #if HCI_VUART_RX_QUEUE
ble_hs_event_hci_rx_func(void * arg)407 static void ble_hs_event_hci_rx_func(void *arg)
408 {
409 uint32_t i = 0;
410 struct QUEUE_ITEM *item = NULL;
411 struct QUEUE_ITEM *item_next = NULL;
412 ble_npl_mutex_pend(&hci_resp_queue_mutex, 0);
413 item = TAILQ_FIRST(&hci_resp_queue);
414 if (item) {
415 TAILQ_REMOVE(&hci_resp_queue, item, entries);
416 item_next = TAILQ_FIRST(&hci_resp_queue);
417 hci_resp_queue_counter--;
418 }
419
420 ble_npl_mutex_release(&hci_resp_queue_mutex);
421
422 if (item) {
423 ble_hci_trans_hs_rx(item->payload, item->size);
424 #if (HCI_DBG == TRUE)
425 hci_dbg_hexstring("***", item->payload, item->size);
426 #endif
427 tls_mem_free(item->payload);
428 tls_mem_free(item);
429 }
430
431 /* More hci response available, notify the host statck for reading again */
432
433 if (item_next) {
434 ble_npl_eventq_put(&hci_evt_rx_tx_queue, &ble_hs_ev_hci_rx);
435 }
436 }
437
438 #endif
439
440 #define HCI_COMMAND_PKT 0x01
441 #define HCI_ACLDATA_PKT 0x02
442 #define HCI_SCODATA_PKT 0x03
443 #define HCI_EVENT_PKT 0x04
444 #define BT_HCI_EVT_LE_META_EVENT 0x3e
445 #define BT_HCI_EVT_LE_ADVERTISING_REPORT 0x02
446
notify_host_recv(uint8_t * data,uint16_t len)447 static void notify_host_recv(uint8_t *data, uint16_t len)
448 {
449 #if HCI_VUART_RX_QUEUE
450
451 if (data == NULL || len == 0) { return; }
452
453 #if (HCI_DBG == TRUE)
454 hci_dbg_hexstring("<<<", data, len);
455 #endif
456
457 if (data[0] == HCI_EVENT_PKT && data[1] == BT_HCI_EVT_LE_META_EVENT
458 && data[3] == BT_HCI_EVT_LE_ADVERTISING_REPORT) { // 3:byte alignment
459 if (hci_resp_queue_counter > HCI_RESP_QUEUE_HALF_FULL) {
460 HCIDBG("Too much hci_adv_report_evt, discard it");
461 ble_npl_eventq_put(&hci_evt_rx_tx_queue, &ble_hs_ev_hci_rx);
462 return;
463 }
464 }
465
466 if (hci_resp_queue_counter > HCI_RESP_QUEUE_FULL) {
467 HCIDBG("Too much(%d) hci_response_evt, discard it", hci_resp_queue_counter);
468 ble_npl_eventq_put(&hci_evt_rx_tx_queue, &ble_hs_ev_hci_rx);
469 return;
470 }
471
472 struct QUEUE_ITEM *item = tls_mem_alloc(sizeof(struct QUEUE_ITEM));
473
474 if (item == NULL) {
475 MODLOG_DFLT(INFO, "Alloc queue item failed, no memory available");
476 return;
477 }
478
479 item->payload = tls_mem_alloc(len);
480 if (item->payload == NULL) {
481 MODLOG_DFLT(INFO, "Alloc queue item payload failed, no memory available");
482 tls_mem_free(item);
483 return;
484 }
485
486 memcpy_s(item->payload, sizeof(*item->payload), data, len);
487 item->size = len;
488 ble_npl_mutex_pend(&hci_resp_queue_mutex, 0);
489 TAILQ_INSERT_TAIL(&hci_resp_queue, item, entries);
490 hci_resp_queue_counter++;
491 ble_npl_mutex_release(&hci_resp_queue_mutex);
492 ble_npl_eventq_put(&hci_evt_rx_tx_queue, &ble_hs_ev_hci_rx);
493 #else
494 ble_hci_trans_hs_rx(data, len);
495 #endif
496 return;
497 }
498
499 static tls_bt_host_if_t vuart_hci_cb = {
500 .notify_controller_avaiable_hci_buffer = notify_host_send_available,
501 .notify_host_recv_h4 = notify_host_recv,
502 };
503
wm_ble_controller_init(uint8_t uart_idx)504 static int wm_ble_controller_init(uint8_t uart_idx)
505 {
506 tls_bt_hci_if_t hci_if;
507 tls_bt_status_t status;
508 hci_if.uart_index = uart_idx;
509 status = tls_bt_ctrl_enable(&hci_if, 0);
510 if ((status != TLS_BT_STATUS_SUCCESS) && (status != TLS_BT_STATUS_DONE)) {
511 return TLS_BT_STATUS_CTRL_ENABLE_FAILED;
512 }
513
514 status = tls_bt_ctrl_if_register(&vuart_hci_cb);
515 if (status != TLS_BT_STATUS_SUCCESS) {
516 return TLS_BT_STATUS_CTRL_ENABLE_FAILED;
517 }
518
519 return 0;
520 }
wm_ble_controller_deinit(void)521 static int wm_ble_controller_deinit(void)
522 {
523 return tls_bt_ctrl_disable();
524 }
525
526 /**
527 * Initializes the VUART HCI transport module.
528 *
529 * @return 0 on success;
530 * A BLE_ERR_[...] error code on failure.
531 */
532 #if HCI_VUART_RX_QUEUE
533
534 static void *tls_host_vuart_task_stack_ptr = NULL;
nimble_vhci_task(void)535 static void nimble_vhci_task(void)
536 {
537 struct ble_npl_event *ev;
538 int arg;
539
540 while (1) {
541 ev = ble_npl_eventq_get(&hci_evt_rx_tx_queue, BLE_NPL_TIME_FOREVER);
542 ble_npl_event_run(ev);
543 arg = (int)ble_npl_event_get_arg(ev);
544 }
545 }
546 #endif
ble_hci_vuart_init(uint8_t uart_idx)547 int ble_hci_vuart_init(uint8_t uart_idx)
548 {
549 int rc;
550 /* Ensure this function only gets called by sysinit. */
551 SYSINIT_ASSERT_ACTIVE();
552 #if HCI_VUART_RX_QUEUE
553 /* Initialize default event queue */
554 ble_npl_eventq_init(&hci_evt_rx_tx_queue);
555 ble_npl_event_init(&ble_hs_ev_hci_rx, ble_hs_event_hci_rx_func, NULL);
556 rc = ble_npl_mutex_init(&hci_resp_queue_mutex);
557 assert(rc == BLE_NPL_OK);
558 TAILQ_INIT(&hci_resp_queue);
559 hci_resp_queue_counter = 0;
560 tls_host_vuart_task_stack_ptr = (void *)tls_mem_alloc(MYNEWT_VAL(OS_HS_VUART_STACK_SIZE) * sizeof(
561 uint32_t));
562 assert(tls_host_vuart_task_stack_ptr != NULL);
563 tls_os_task_create(NULL, "btv",
564 nimble_vhci_task,
565 (void *)0,
566 (void *)tls_host_vuart_task_stack_ptr,
567 MYNEWT_VAL(OS_HS_VUART_STACK_SIZE)*sizeof(uint32_t),
568 MYNEWT_VAL(OS_HS_VUART_TASK_PRIO),
569 0);
570 #endif
571 rc = wm_ble_controller_init(uart_idx);
572 assert(rc == 0);
573 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
574 ble_hci_vuart_acl_buf = (os_membuf_t *)tls_mem_alloc(
575 sizeof(os_membuf_t) *
576 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), ACL_BLOCK_SIZE));
577 assert(ble_hci_vuart_acl_buf != NULL);
578 #endif
579 rc = os_mempool_ext_init(&ble_hci_vuart_acl_pool,
580 MYNEWT_VAL(BLE_ACL_BUF_COUNT),
581 ACL_BLOCK_SIZE,
582 ble_hci_vuart_acl_buf,
583 "ble_hci_vuart_acl_pool");
584 SYSINIT_PANIC_ASSERT(rc == 0);
585 rc = os_mbuf_pool_init(&ble_hci_vuart_acl_mbuf_pool,
586 &ble_hci_vuart_acl_pool.mpe_mp,
587 ACL_BLOCK_SIZE,
588 MYNEWT_VAL(BLE_ACL_BUF_COUNT));
589 SYSINIT_PANIC_ASSERT(rc == 0);
590 /*
591 * Create memory pool of HCI command buffers. NOTE: we currently dont
592 * allow this to be configured. The controller will only allow one
593 * outstanding command. We decided to keep this a pool in case we allow
594 * allow the controller to handle more than one outstanding command.
595 */
596 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
597 ble_hci_vuart_cmd_buf = (os_membuf_t *)tls_mem_alloc(
598 sizeof(os_membuf_t) *
599 OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ));
600 assert(ble_hci_vuart_cmd_buf != NULL);
601 #endif
602 rc = os_mempool_init(&ble_hci_vuart_cmd_pool,
603 1,
604 BLE_HCI_TRANS_CMD_SZ,
605 ble_hci_vuart_cmd_buf,
606 "ble_hci_vuart_cmd_pool");
607 SYSINIT_PANIC_ASSERT(rc == 0);
608 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
609 ble_hci_vuart_evt_hi_buf = (os_membuf_t *)tls_mem_alloc(
610 sizeof(os_membuf_t) *
611 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
612 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)));
613 assert(ble_hci_vuart_evt_hi_buf != NULL);
614 #endif
615 rc = os_mempool_init(&ble_hci_vuart_evt_hi_pool,
616 MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
617 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
618 ble_hci_vuart_evt_hi_buf,
619 "ble_hci_vuart_evt_hi_pool");
620 SYSINIT_PANIC_ASSERT(rc == 0);
621 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
622 ble_hci_vuart_evt_lo_buf = (os_membuf_t *)tls_mem_alloc(
623 sizeof(os_membuf_t) *
624 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
625 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)));
626 assert(ble_hci_vuart_evt_lo_buf != NULL);
627 #endif
628 rc = os_mempool_init(&ble_hci_vuart_evt_lo_pool,
629 MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
630 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
631 ble_hci_vuart_evt_lo_buf,
632 "ble_hci_vuart_evt_lo_pool");
633 SYSINIT_PANIC_ASSERT(rc == 0);
634
635 return rc;
636 }
637
ble_hci_vuart_deinit(void)638 int ble_hci_vuart_deinit(void)
639 {
640 int rc;
641 rc = wm_ble_controller_deinit();
642 assert(rc == 0);
643 #if MYNEWT_VAL(SYS_MEM_DYNAMIC)
644
645 if (ble_hci_vuart_acl_buf) {
646 tls_mem_free(ble_hci_vuart_acl_buf);
647 ble_hci_vuart_acl_buf = NULL;
648 }
649
650 if (ble_hci_vuart_cmd_buf) {
651 tls_mem_free(ble_hci_vuart_cmd_buf);
652 ble_hci_vuart_cmd_buf = NULL;
653 }
654
655 if (ble_hci_vuart_evt_hi_buf) {
656 tls_mem_free(ble_hci_vuart_evt_hi_buf);
657 ble_hci_vuart_evt_hi_buf = NULL;
658 }
659
660 if (ble_hci_vuart_evt_lo_buf) {
661 tls_mem_free(ble_hci_vuart_evt_lo_buf);
662 ble_hci_vuart_evt_lo_buf = NULL;
663 }
664
665 #endif
666 return rc;
667 }