xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/transport/emspi/src/ble_hci_emspi.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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