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 <string.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <stdint.h>
25 #include "sysinit/sysinit.h"
26 #include "syscfg/syscfg.h"
27 #include "os/os_cputime.h"
28 #include "bsp/bsp.h"
29 #include "os/os.h"
30 #include "mem/mem.h"
31 #include "hal/hal_gpio.h"
32 #include "hal/hal_spi.h"
33
34 /* BLE */
35 #include "nimble/ble.h"
36 #include "nimble/nimble_opt.h"
37 #include "nimble/hci_common.h"
38 #include "nimble/ble_hci_trans.h"
39
40 #include "transport/emspi/ble_hci_emspi.h"
41
42 #include "am_mcu_apollo.h"
43
44 /***
45 * NOTES:
46 * The emspi HCI transport doesn't use event buffer priorities. All incoming
47 * and outgoing events use buffers from the same pool.
48 *
49 */
50
51 #define BLE_HCI_EMSPI_PKT_EVT_COUNT \
52 (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + \
53 MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT))
54
55 #define BLE_HCI_EMSPI_PKT_NONE 0x00
56 #define BLE_HCI_EMSPI_PKT_CMD 0x01
57 #define BLE_HCI_EMSPI_PKT_ACL 0x02
58 #define BLE_HCI_EMSPI_PKT_EVT 0x04
59
60 #define BLE_HCI_EMSPI_CTLR_STATUS_OK 0xc0
61 #define BLE_HCI_EMSPI_OP_TX 0x42
62 #define BLE_HCI_EMSPI_OP_RX 0x81
63
64 static os_event_fn ble_hci_emspi_event_txrx;
65
66 static struct os_event ble_hci_emspi_ev_txrx = {
67 .ev_cb = ble_hci_emspi_event_txrx,
68 };
69
70 static struct os_eventq ble_hci_emspi_evq;
71 static struct os_task ble_hci_emspi_task;
72 static os_stack_t ble_hci_emspi_stack[MYNEWT_VAL(BLE_HCI_EMSPI_STACK_SIZE)];
73
74 static ble_hci_trans_rx_cmd_fn *ble_hci_emspi_rx_cmd_cb;
75 static void *ble_hci_emspi_rx_cmd_arg;
76
77 static ble_hci_trans_rx_acl_fn *ble_hci_emspi_rx_acl_cb;
78 static void *ble_hci_emspi_rx_acl_arg;
79
80 static struct os_mempool ble_hci_emspi_evt_hi_pool;
81 static os_membuf_t ble_hci_emspi_evt_hi_buf[
82 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
83 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
84 ];
85
86 static struct os_mempool ble_hci_emspi_evt_lo_pool;
87 static os_membuf_t ble_hci_emspi_evt_lo_buf[
88 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
89 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
90 ];
91
92 static struct os_mempool ble_hci_emspi_cmd_pool;
93 static os_membuf_t ble_hci_emspi_cmd_buf[
94 OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)
95 ];
96
97 static struct os_mbuf_pool ble_hci_emspi_acl_mbuf_pool;
98 static struct os_mempool_ext ble_hci_emspi_acl_pool;
99
100 /*
101 * The MBUF payload size must accommodate the HCI data header size plus the
102 * maximum ACL data packet length. The ACL block size is the size of the
103 * mbufs we will allocate.
104 */
105 #define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \
106 + BLE_MBUF_MEMBLOCK_OVERHEAD \
107 + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)
108
109 static os_membuf_t ble_hci_emspi_acl_buf[
110 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT),
111 ACL_BLOCK_SIZE)
112 ];
113
114 /**
115 * A packet to be sent over the EMSPI. This can be a command, an event, or ACL
116 * data.
117 */
118 struct ble_hci_emspi_pkt {
119 STAILQ_ENTRY(ble_hci_emspi_pkt) next;
120 void *data;
121 uint8_t type;
122 };
123 STAILQ_HEAD(, ble_hci_emspi_pkt) ble_hci_emspi_tx_q;
124
125 static struct os_mempool ble_hci_emspi_pkt_pool;
126 static os_membuf_t ble_hci_emspi_pkt_buf[
127 OS_MEMPOOL_SIZE(BLE_HCI_EMSPI_PKT_EVT_COUNT + 1 +
128 MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT),
129 sizeof (struct ble_hci_emspi_pkt))
130 ];
131
132 static void
ble_hci_emspi_rdy_isr(void * arg)133 ble_hci_emspi_rdy_isr(void *arg)
134 {
135 os_eventq_put(&ble_hci_emspi_evq, &ble_hci_emspi_ev_txrx);
136 }
137
138 static void
ble_hci_emspi_initiate_write(void)139 ble_hci_emspi_initiate_write(void)
140 {
141 hal_gpio_irq_disable(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN));
142
143 /* Assert slave select. */
144 hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_SS_PIN), 0);
145
146 /* Wait for controller to indicate ready-to-receive. */
147 while (!hal_gpio_read(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN))) { }
148 }
149
150 static void
ble_hci_emspi_terminate_write(void)151 ble_hci_emspi_terminate_write(void)
152 {
153 const uint64_t rdy_mask =
154 AM_HAL_GPIO_BIT(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN));
155 os_sr_t sr;
156
157 am_hal_gpio_int_clear(rdy_mask);
158
159 /* Deassert slave select. */
160 hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_SS_PIN), 1);
161
162 OS_ENTER_CRITICAL(sr);
163 hal_gpio_irq_enable(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN));
164
165 if (hal_gpio_read(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN))) {
166 am_hal_gpio_int_set(rdy_mask);
167 }
168
169 OS_EXIT_CRITICAL(sr);
170 }
171
172 static int
ble_hci_emspi_write_hdr(uint8_t first_byte,uint8_t * out_buf_size)173 ble_hci_emspi_write_hdr(uint8_t first_byte, uint8_t *out_buf_size)
174 {
175 const uint8_t hdr[2] = { first_byte, 0x00 };
176 uint8_t rx[2];
177 int rc;
178
179 /* Send command header. */
180 rc = hal_spi_txrx(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), (void *)hdr, rx, 2);
181 if (rc != 0) {
182 return rc;
183 }
184
185 /* Check for "OK" status. */
186 if (rx[0] != BLE_HCI_EMSPI_CTLR_STATUS_OK) {
187 return BLE_ERR_HW_FAIL;
188 }
189
190 *out_buf_size = rx[1];
191 return 0;
192 }
193
194 /**
195 * Transmits a chunk of bytes to the controller.
196 */
197 static int
ble_hci_emspi_tx_chunk(const uint8_t * data,int len,int * out_bytes_txed)198 ble_hci_emspi_tx_chunk(const uint8_t *data, int len, int *out_bytes_txed)
199 {
200 uint8_t buf_size;
201 int rc;
202
203 /* Silence spurious "may be used uninitialized" warning. */
204 *out_bytes_txed = 0;
205
206 ble_hci_emspi_initiate_write();
207
208 rc = ble_hci_emspi_write_hdr(BLE_HCI_EMSPI_OP_TX, &buf_size);
209 if (rc != 0) {
210 goto done;
211 }
212
213 if (buf_size == 0) {
214 rc = 0;
215 goto done;
216 }
217
218 if (buf_size < len) {
219 len = buf_size;
220 }
221 rc = hal_spi_txrx(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), (void *)data, NULL,
222 len);
223 if (rc != 0) {
224 goto done;
225 }
226 *out_bytes_txed = len;
227
228 done:
229 ble_hci_emspi_terminate_write();
230 return rc;
231 }
232
233 /**
234 * Transmits a full command or ACL data packet to the controller.
235 */
236 static int
ble_hci_emspi_tx(const uint8_t * data,int len)237 ble_hci_emspi_tx(const uint8_t *data, int len)
238 {
239 int bytes_txed;
240 int rc;
241
242 while (len > 0) {
243 rc = ble_hci_emspi_tx_chunk(data, len, &bytes_txed);
244 if (rc != 0) {
245 goto done;
246 }
247
248 data += bytes_txed;
249 len -= bytes_txed;
250 }
251
252 rc = 0;
253
254 done:
255 return rc;
256 }
257
258 /**
259 * Reads the specified number of bytes from the controller.
260 */
261 static int
ble_hci_emspi_rx(uint8_t * data,int max_len)262 ble_hci_emspi_rx(uint8_t *data, int max_len)
263 {
264 uint8_t buf_size;
265 int rc;
266
267 ble_hci_emspi_initiate_write();
268
269 rc = ble_hci_emspi_write_hdr(BLE_HCI_EMSPI_OP_RX, &buf_size);
270 if (rc != 0) {
271 goto done;
272 }
273
274 if (buf_size > max_len) {
275 buf_size = max_len;
276 }
277
278 rc = hal_spi_txrx(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), NULL, data, buf_size);
279 if (rc != 0) {
280 rc = BLE_ERR_HW_FAIL;
281 goto done;
282 }
283
284 done:
285 ble_hci_emspi_terminate_write();
286 return rc;
287 }
288
289 /**
290 * Allocates a buffer (mbuf) for ACL operation.
291 *
292 * @return The allocated buffer on success;
293 * NULL on buffer exhaustion.
294 */
295 static struct os_mbuf *
ble_hci_trans_acl_buf_alloc(void)296 ble_hci_trans_acl_buf_alloc(void)
297 {
298 uint8_t usrhdr_len;
299
300 #if MYNEWT_VAL(BLE_HS_FLOW_CTRL)
301 usrhdr_len = BLE_MBUF_HS_HDR_LEN;
302 #else
303 usrhdr_len = 0;
304 #endif
305
306 return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, usrhdr_len);
307 }
308
309 /**
310 * Transmits an ACL data packet to the controller. The caller relinquishes the
311 * specified mbuf, regardless of return status.
312 */
313 static int
ble_hci_emspi_acl_tx(struct os_mbuf * om)314 ble_hci_emspi_acl_tx(struct os_mbuf *om)
315 {
316 struct ble_hci_emspi_pkt *pkt;
317 os_sr_t sr;
318
319 /* If this packet is zero length, just free it */
320 if (OS_MBUF_PKTLEN(om) == 0) {
321 os_mbuf_free_chain(om);
322 return 0;
323 }
324
325 pkt = os_memblock_get(&ble_hci_emspi_pkt_pool);
326 if (pkt == NULL) {
327 os_mbuf_free_chain(om);
328 return BLE_ERR_MEM_CAPACITY;
329 }
330
331 pkt->type = BLE_HCI_EMSPI_PKT_ACL;
332 pkt->data = om;
333
334 OS_ENTER_CRITICAL(sr);
335 STAILQ_INSERT_TAIL(&ble_hci_emspi_tx_q, pkt, next);
336 OS_EXIT_CRITICAL(sr);
337
338 os_eventq_put(&ble_hci_emspi_evq, &ble_hci_emspi_ev_txrx);
339
340 return 0;
341 }
342
343 /**
344 * Transmits a command packet to the controller. The caller relinquishes the
345 * specified buffer, regardless of return status.
346 */
347 static int
ble_hci_emspi_cmdevt_tx(uint8_t * cmd_buf,uint8_t pkt_type)348 ble_hci_emspi_cmdevt_tx(uint8_t *cmd_buf, uint8_t pkt_type)
349 {
350 struct ble_hci_emspi_pkt *pkt;
351 os_sr_t sr;
352
353 pkt = os_memblock_get(&ble_hci_emspi_pkt_pool);
354 if (pkt == NULL) {
355 ble_hci_trans_buf_free(cmd_buf);
356 return BLE_ERR_MEM_CAPACITY;
357 }
358
359 pkt->type = pkt_type;
360 pkt->data = cmd_buf;
361
362 OS_ENTER_CRITICAL(sr);
363 STAILQ_INSERT_TAIL(&ble_hci_emspi_tx_q, pkt, next);
364 OS_EXIT_CRITICAL(sr);
365
366 os_eventq_put(&ble_hci_emspi_evq, &ble_hci_emspi_ev_txrx);
367
368 return 0;
369 }
370
371 static int
ble_hci_emspi_tx_flat(const uint8_t * data,int len)372 ble_hci_emspi_tx_flat(const uint8_t *data, int len)
373 {
374 int rc;
375
376 rc = ble_hci_emspi_tx(data, len);
377 return rc;
378 }
379
380 static int
ble_hci_emspi_tx_pkt_type(uint8_t pkt_type)381 ble_hci_emspi_tx_pkt_type(uint8_t pkt_type)
382 {
383 return ble_hci_emspi_tx_flat(&pkt_type, 1);
384 }
385
386 static int
ble_hci_emspi_tx_cmd(const uint8_t * data)387 ble_hci_emspi_tx_cmd(const uint8_t *data)
388 {
389 int len;
390 int rc;
391
392 rc = ble_hci_emspi_tx_pkt_type(BLE_HCI_EMSPI_PKT_CMD);
393 if (rc != 0) {
394 return rc;
395 }
396
397 len = data[2] + BLE_HCI_CMD_HDR_LEN;
398 rc = ble_hci_emspi_tx_flat(data, len);
399 if (rc != 0) {
400 return rc;
401 }
402
403 return 0;
404 }
405
406 static int
ble_hci_emspi_tx_acl(struct os_mbuf * om)407 ble_hci_emspi_tx_acl(struct os_mbuf *om)
408 {
409 struct os_mbuf *cur;
410 int rc;
411
412 rc = ble_hci_emspi_tx_pkt_type(BLE_HCI_EMSPI_PKT_ACL);
413 if (rc != 0) {
414 return rc;
415 }
416
417 cur = om;
418 while (cur != NULL) {
419 rc = ble_hci_emspi_tx(cur->om_data, cur->om_len);
420 if (rc != 0) {
421 break;
422 }
423
424 cur = SLIST_NEXT(cur, om_next);
425 }
426
427 return rc;
428 }
429
430 static struct ble_hci_emspi_pkt *
ble_hci_emspi_pull_next_tx(void)431 ble_hci_emspi_pull_next_tx(void)
432 {
433 struct ble_hci_emspi_pkt *pkt;
434 os_sr_t sr;
435
436 OS_ENTER_CRITICAL(sr);
437 pkt = STAILQ_FIRST(&ble_hci_emspi_tx_q);
438 if (pkt != NULL) {
439 STAILQ_REMOVE(&ble_hci_emspi_tx_q, pkt, ble_hci_emspi_pkt, next);
440 }
441 OS_EXIT_CRITICAL(sr);
442
443 return pkt;
444 }
445
446 static int
ble_hci_emspi_tx_pkt(void)447 ble_hci_emspi_tx_pkt(void)
448 {
449 struct ble_hci_emspi_pkt *pkt;
450 int rc;
451
452 pkt = ble_hci_emspi_pull_next_tx();
453 if (pkt == NULL) {
454 return -1;
455 }
456
457 switch (pkt->type) {
458 case BLE_HCI_EMSPI_PKT_CMD:
459 rc = ble_hci_emspi_tx_cmd(pkt->data);
460 ble_hci_trans_buf_free(pkt->data);
461 break;
462
463 case BLE_HCI_EMSPI_PKT_ACL:
464 rc = ble_hci_emspi_tx_acl(pkt->data);
465 os_mbuf_free_chain(pkt->data);
466 break;
467
468 default:
469 rc = -1;
470 break;
471 }
472
473 os_memblock_put(&ble_hci_emspi_pkt_pool, pkt);
474
475 return rc;
476 }
477
478 static int
ble_hci_emspi_rx_evt(void)479 ble_hci_emspi_rx_evt(void)
480 {
481 uint8_t *data;
482 uint8_t len;
483 int rc;
484
485 /* XXX: we should not assert if host cannot allocate an event. Need
486 * to determine what to do here.
487 */
488 data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
489 assert(data != NULL);
490
491 rc = ble_hci_emspi_rx(data, BLE_HCI_EVENT_HDR_LEN);
492 if (rc != 0) {
493 goto err;
494 }
495
496 len = data[1];
497 if (len > 0) {
498 rc = ble_hci_emspi_rx(data + BLE_HCI_EVENT_HDR_LEN, len);
499 if (rc != 0) {
500 goto err;
501 }
502 }
503
504 assert(ble_hci_emspi_rx_cmd_cb != NULL);
505 ble_hci_emspi_rx_cmd_cb(data, ble_hci_emspi_rx_cmd_arg);
506 if (rc != 0) {
507 goto err;
508 }
509
510 return 0;
511
512 err:
513 ble_hci_trans_buf_free(data);
514 return rc;
515 }
516
517 static int
ble_hci_emspi_rx_acl(void)518 ble_hci_emspi_rx_acl(void)
519 {
520 struct os_mbuf *om;
521 uint16_t len;
522 int rc;
523
524 /* XXX: we should not assert if host cannot allocate an mbuf. Need to
525 * determine what to do here.
526 */
527 om = ble_hci_trans_acl_buf_alloc();
528 assert(om != NULL);
529
530 rc = ble_hci_emspi_rx(om->om_data, BLE_HCI_DATA_HDR_SZ);
531 if (rc != 0) {
532 goto err;
533 }
534
535 len = get_le16(om->om_data + 2);
536 if (len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) {
537 /*
538 * Data portion cannot exceed data length of acl buffer. If it does
539 * this is considered to be a loss of sync.
540 */
541 rc = BLE_ERR_UNSPECIFIED;
542 goto err;
543 }
544
545 if (len > 0) {
546 rc = ble_hci_emspi_rx(om->om_data + BLE_HCI_DATA_HDR_SZ, len);
547 if (rc != 0) {
548 goto err;
549 }
550 }
551
552 OS_MBUF_PKTLEN(om) = BLE_HCI_DATA_HDR_SZ + len;
553 om->om_len = BLE_HCI_DATA_HDR_SZ + len;
554
555 assert(ble_hci_emspi_rx_cmd_cb != NULL);
556 rc = ble_hci_emspi_rx_acl_cb(om, ble_hci_emspi_rx_acl_arg);
557 if (rc != 0) {
558 goto err;
559 }
560
561 return 0;
562
563 err:
564 os_mbuf_free_chain(om);
565 return rc;
566 }
567
568 /**
569 * @return The type of packet to follow success;
570 * -1 if there is no valid packet to receive.
571 */
572 static int
ble_hci_emspi_rx_pkt(void)573 ble_hci_emspi_rx_pkt(void)
574 {
575 uint8_t pkt_type;
576 int rc;
577
578 /* XXX: This is awkward; should read the full packet in "one go". */
579 rc = ble_hci_emspi_rx(&pkt_type, 1);
580 if (rc != 0) {
581 return rc;
582 }
583
584 switch (pkt_type) {
585 case BLE_HCI_EMSPI_PKT_EVT:
586 return ble_hci_emspi_rx_evt();
587
588 case BLE_HCI_EMSPI_PKT_ACL:
589 return ble_hci_emspi_rx_acl();
590
591 default:
592 /* XXX */
593 return -1;
594 }
595 }
596
597 static void
ble_hci_emspi_set_rx_cbs(ble_hci_trans_rx_cmd_fn * cmd_cb,void * cmd_arg,ble_hci_trans_rx_acl_fn * acl_cb,void * acl_arg)598 ble_hci_emspi_set_rx_cbs(ble_hci_trans_rx_cmd_fn *cmd_cb,
599 void *cmd_arg,
600 ble_hci_trans_rx_acl_fn *acl_cb,
601 void *acl_arg)
602 {
603 ble_hci_emspi_rx_cmd_cb = cmd_cb;
604 ble_hci_emspi_rx_cmd_arg = cmd_arg;
605 ble_hci_emspi_rx_acl_cb = acl_cb;
606 ble_hci_emspi_rx_acl_arg = acl_arg;
607 }
608
609 static void
ble_hci_emspi_free_pkt(uint8_t type,uint8_t * cmdevt,struct os_mbuf * acl)610 ble_hci_emspi_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl)
611 {
612 switch (type) {
613 case BLE_HCI_EMSPI_PKT_NONE:
614 break;
615
616 case BLE_HCI_EMSPI_PKT_CMD:
617 case BLE_HCI_EMSPI_PKT_EVT:
618 ble_hci_trans_buf_free(cmdevt);
619 break;
620
621 case BLE_HCI_EMSPI_PKT_ACL:
622 os_mbuf_free_chain(acl);
623 break;
624
625 default:
626 assert(0);
627 break;
628 }
629 }
630
631 /**
632 * Unsupported. This is a host-only transport.
633 */
634 int
ble_hci_trans_ll_evt_tx(uint8_t * cmd)635 ble_hci_trans_ll_evt_tx(uint8_t *cmd)
636 {
637 return BLE_ERR_UNSUPPORTED;
638 }
639
640 /**
641 * Unsupported. This is a host-only transport.
642 */
643 int
ble_hci_trans_ll_acl_tx(struct os_mbuf * om)644 ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
645 {
646 return BLE_ERR_UNSUPPORTED;
647 }
648
649 /**
650 * Sends an HCI command from the host to the controller.
651 *
652 * @param cmd The HCI command to send. This buffer must be
653 * allocated via ble_hci_trans_buf_alloc().
654 *
655 * @return 0 on success;
656 * A BLE_ERR_[...] error code on failure.
657 */
658 int
ble_hci_trans_hs_cmd_tx(uint8_t * cmd)659 ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
660 {
661 int rc;
662
663 rc = ble_hci_emspi_cmdevt_tx(cmd, BLE_HCI_EMSPI_PKT_CMD);
664 return rc;
665 }
666
667 /**
668 * Sends ACL data from host to controller.
669 *
670 * @param om The ACL data packet to send.
671 *
672 * @return 0 on success;
673 * A BLE_ERR_[...] error code on failure.
674 */
675 int
ble_hci_trans_hs_acl_tx(struct os_mbuf * om)676 ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
677 {
678 int rc;
679
680 rc = ble_hci_emspi_acl_tx(om);
681 return rc;
682 }
683
684 /**
685 * Configures the HCI transport to call the specified callback upon receiving
686 * HCI packets from the controller. This function should only be called by by
687 * host.
688 *
689 * @param cmd_cb The callback to execute upon receiving an HCI
690 * event.
691 * @param cmd_arg Optional argument to pass to the command
692 * callback.
693 * @param acl_cb The callback to execute upon receiving ACL
694 * data.
695 * @param acl_arg Optional argument to pass to the ACL
696 * callback.
697 */
698 void
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)699 ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
700 void *cmd_arg,
701 ble_hci_trans_rx_acl_fn *acl_cb,
702 void *acl_arg)
703 {
704 ble_hci_emspi_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg);
705 }
706
707 /**
708 * Configures the HCI transport to operate with a host. The transport will
709 * execute specified callbacks upon receiving HCI packets from the controller.
710 *
711 * @param cmd_cb The callback to execute upon receiving an HCI
712 * event.
713 * @param cmd_arg Optional argument to pass to the command
714 * callback.
715 * @param acl_cb The callback to execute upon receiving ACL
716 * data.
717 * @param acl_arg Optional argument to pass to the ACL
718 * callback.
719 */
720 void
ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn * cmd_cb,void * cmd_arg,ble_hci_trans_rx_acl_fn * acl_cb,void * acl_arg)721 ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb,
722 void *cmd_arg,
723 ble_hci_trans_rx_acl_fn *acl_cb,
724 void *acl_arg)
725 {
726 /* Unsupported. */
727 assert(0);
728 }
729
730 /**
731 * Allocates a flat buffer of the specified type.
732 *
733 * @param type The type of buffer to allocate; one of the
734 * BLE_HCI_TRANS_BUF_[...] constants.
735 *
736 * @return The allocated buffer on success;
737 * NULL on buffer exhaustion.
738 */
739 uint8_t *
ble_hci_trans_buf_alloc(int type)740 ble_hci_trans_buf_alloc(int type)
741 {
742 uint8_t *buf;
743
744 switch (type) {
745 case BLE_HCI_TRANS_BUF_CMD:
746 buf = os_memblock_get(&ble_hci_emspi_cmd_pool);
747 break;
748 case BLE_HCI_TRANS_BUF_EVT_HI:
749 buf = os_memblock_get(&ble_hci_emspi_evt_hi_pool);
750 if (buf == NULL) {
751 /* If no high-priority event buffers remain, try to grab a
752 * low-priority one.
753 */
754 buf = os_memblock_get(&ble_hci_emspi_evt_lo_pool);
755 }
756 break;
757
758 case BLE_HCI_TRANS_BUF_EVT_LO:
759 buf = os_memblock_get(&ble_hci_emspi_evt_lo_pool);
760 break;
761
762 default:
763 assert(0);
764 buf = NULL;
765 }
766
767 return buf;
768 }
769
770 /**
771 * Frees the specified flat buffer. The buffer must have been allocated via
772 * ble_hci_trans_buf_alloc().
773 *
774 * @param buf The buffer to free.
775 */
776 void
ble_hci_trans_buf_free(uint8_t * buf)777 ble_hci_trans_buf_free(uint8_t *buf)
778 {
779 int rc;
780
781 if (buf != NULL) {
782 if (os_memblock_from(&ble_hci_emspi_evt_hi_pool, buf)) {
783 rc = os_memblock_put(&ble_hci_emspi_evt_hi_pool, buf);
784 assert(rc == 0);
785 } else if (os_memblock_from(&ble_hci_emspi_evt_lo_pool, buf)) {
786 rc = os_memblock_put(&ble_hci_emspi_evt_lo_pool, buf);
787 assert(rc == 0);
788 } else {
789 assert(os_memblock_from(&ble_hci_emspi_cmd_pool, buf));
790 rc = os_memblock_put(&ble_hci_emspi_cmd_pool, buf);
791 assert(rc == 0);
792 }
793 }
794 }
795
796 /**
797 * Configures a callback to get executed whenever an ACL data packet is freed.
798 * The function is called in lieu of actually freeing the packet.
799 *
800 * @param cb The callback to configure.
801 *
802 * @return 0 on success.
803 */
804 int
ble_hci_trans_set_acl_free_cb(os_mempool_put_fn * cb,void * arg)805 ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
806 {
807 ble_hci_emspi_acl_pool.mpe_put_cb = cb;
808 ble_hci_emspi_acl_pool.mpe_put_arg = arg;
809 return 0;
810 }
811
812 /**
813 * Resets the HCI UART transport to a clean state. Frees all buffers and
814 * reconfigures the UART.
815 *
816 * @return 0 on success;
817 * A BLE_ERR_[...] error code on failure.
818 */
819 int
ble_hci_trans_reset(void)820 ble_hci_trans_reset(void)
821 {
822 struct ble_hci_emspi_pkt *pkt;
823
824 hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_RESET_PIN), 1);
825
826 while ((pkt = STAILQ_FIRST(&ble_hci_emspi_tx_q)) != NULL) {
827 STAILQ_REMOVE(&ble_hci_emspi_tx_q, pkt, ble_hci_emspi_pkt, next);
828 ble_hci_emspi_free_pkt(pkt->type, pkt->data, pkt->data);
829 os_memblock_put(&ble_hci_emspi_pkt_pool, pkt);
830 }
831
832 return 0;
833 }
834
835 static void
ble_hci_emspi_event_txrx(struct os_event * ev)836 ble_hci_emspi_event_txrx(struct os_event *ev)
837 {
838 int rc;
839
840 rc = ble_hci_emspi_rx_pkt();
841
842 do {
843 rc = ble_hci_emspi_tx_pkt();
844 } while (rc == 0);
845 }
846
847 static void
ble_hci_emspi_loop(void * unused)848 ble_hci_emspi_loop(void *unused)
849 {
850 while (1) {
851 os_eventq_run(&ble_hci_emspi_evq);
852 }
853 }
854
855 static void
ble_hci_emspi_init_hw(void)856 ble_hci_emspi_init_hw(void)
857 {
858 struct hal_spi_settings spi_cfg;
859 int rc;
860
861 rc = hal_gpio_init_out(MYNEWT_VAL(BLE_HCI_EMSPI_RESET_PIN), 0);
862 SYSINIT_PANIC_ASSERT(rc == 0);
863
864 rc = hal_gpio_init_out(MYNEWT_VAL(BLE_HCI_EMSPI_SS_PIN), 1);
865 SYSINIT_PANIC_ASSERT(rc == 0);
866
867 spi_cfg.data_order = HAL_SPI_MSB_FIRST;
868 spi_cfg.data_mode = HAL_SPI_MODE0;
869 spi_cfg.baudrate = MYNEWT_VAL(BLE_HCI_EMSPI_BAUD);
870 spi_cfg.word_size = HAL_SPI_WORD_SIZE_8BIT;
871
872 rc = hal_spi_config(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM), &spi_cfg);
873 SYSINIT_PANIC_ASSERT(rc == 0);
874
875 rc = hal_gpio_irq_init(MYNEWT_VAL(BLE_HCI_EMSPI_RDY_PIN),
876 ble_hci_emspi_rdy_isr, NULL,
877 HAL_GPIO_TRIG_RISING, HAL_GPIO_PULL_DOWN);
878 SYSINIT_PANIC_ASSERT(rc == 0);
879
880 rc = hal_spi_enable(MYNEWT_VAL(BLE_HCI_EMSPI_SPI_NUM));
881 assert(rc == 0);
882
883 hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_RESET_PIN), 1);
884 }
885
886 /**
887 * Initializes the UART HCI transport module.
888 *
889 * @return 0 on success;
890 * A BLE_ERR_[...] error code on failure.
891 */
892 void
ble_hci_emspi_init(void)893 ble_hci_emspi_init(void)
894 {
895 int rc;
896
897 /* Ensure this function only gets called by sysinit. */
898 SYSINIT_ASSERT_ACTIVE();
899
900 rc = os_mempool_ext_init(&ble_hci_emspi_acl_pool,
901 MYNEWT_VAL(BLE_ACL_BUF_COUNT),
902 ACL_BLOCK_SIZE,
903 ble_hci_emspi_acl_buf,
904 "ble_hci_emspi_acl_pool");
905 SYSINIT_PANIC_ASSERT(rc == 0);
906
907 rc = os_mbuf_pool_init(&ble_hci_emspi_acl_mbuf_pool,
908 &ble_hci_emspi_acl_pool.mpe_mp,
909 ACL_BLOCK_SIZE,
910 MYNEWT_VAL(BLE_ACL_BUF_COUNT));
911 SYSINIT_PANIC_ASSERT(rc == 0);
912
913 /*
914 * Create memory pool of HCI command buffers. NOTE: we currently dont
915 * allow this to be configured. The controller will only allow one
916 * outstanding command. We decided to keep this a pool in case we allow
917 * allow the controller to handle more than one outstanding command.
918 */
919 rc = os_mempool_init(&ble_hci_emspi_cmd_pool,
920 1,
921 BLE_HCI_TRANS_CMD_SZ,
922 ble_hci_emspi_cmd_buf,
923 "ble_hci_emspi_cmd_pool");
924 SYSINIT_PANIC_ASSERT(rc == 0);
925
926 rc = os_mempool_init(&ble_hci_emspi_evt_hi_pool,
927 MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
928 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
929 ble_hci_emspi_evt_hi_buf,
930 "ble_hci_emspi_evt_hi_pool");
931 SYSINIT_PANIC_ASSERT(rc == 0);
932
933 rc = os_mempool_init(&ble_hci_emspi_evt_lo_pool,
934 MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
935 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
936 ble_hci_emspi_evt_lo_buf,
937 "ble_hci_emspi_evt_lo_pool");
938 SYSINIT_PANIC_ASSERT(rc == 0);
939
940 /*
941 * Create memory pool of packet list nodes. NOTE: the number of these
942 * buffers should be, at least, the total number of event buffers (hi
943 * and lo), the number of command buffers (currently 1) and the total
944 * number of buffers that the controller could possibly hand to the host.
945 */
946 rc = os_mempool_init(&ble_hci_emspi_pkt_pool,
947 BLE_HCI_EMSPI_PKT_EVT_COUNT + 1 +
948 MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT),
949 sizeof (struct ble_hci_emspi_pkt),
950 ble_hci_emspi_pkt_buf,
951 "ble_hci_emspi_pkt_pool");
952 SYSINIT_PANIC_ASSERT(rc == 0);
953
954 STAILQ_INIT(&ble_hci_emspi_tx_q);
955
956 ble_hci_emspi_init_hw();
957
958 /* Initialize the LL task */
959 os_eventq_init(&ble_hci_emspi_evq);
960 rc = os_task_init(&ble_hci_emspi_task, "ble_hci_emspi", ble_hci_emspi_loop,
961 NULL, MYNEWT_VAL(BLE_HCI_EMSPI_PRIO), OS_WAIT_FOREVER,
962 ble_hci_emspi_stack,
963 MYNEWT_VAL(BLE_HCI_EMSPI_STACK_SIZE));
964 SYSINIT_PANIC_ASSERT(rc == 0);
965 }
966