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 <errno.h>
22 #include <stddef.h>
23 #include "syscfg/syscfg.h"
24 #include "sysinit/sysinit.h"
25 #include "os/os.h"
26 #include "mem/mem.h"
27 #include "nimble/ble.h"
28 #include "nimble/ble_hci_trans.h"
29 #include "transport/ram/ble_hci_ram.h"
30
31 static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_hs_cb;
32 static void *ble_hci_ram_rx_cmd_hs_arg;
33
34 static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_ll_cb;
35 static void *ble_hci_ram_rx_cmd_ll_arg;
36
37 static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_hs_cb;
38 static void *ble_hci_ram_rx_acl_hs_arg;
39
40 static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_ll_cb;
41 static void *ble_hci_ram_rx_acl_ll_arg;
42
43 static struct os_mempool ble_hci_ram_cmd_pool;
44 static os_membuf_t ble_hci_ram_cmd_buf[
45 OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ)
46 ];
47
48 static struct os_mempool ble_hci_ram_evt_hi_pool;
49 static os_membuf_t ble_hci_ram_evt_hi_buf[
50 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
51 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
52 ];
53
54 static struct os_mempool ble_hci_ram_evt_lo_pool;
55 static os_membuf_t ble_hci_ram_evt_lo_buf[
56 OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
57 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))
58 ];
59
60 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)61 ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb,
62 void *cmd_arg,
63 ble_hci_trans_rx_acl_fn *acl_cb,
64 void *acl_arg)
65 {
66 ble_hci_ram_rx_cmd_hs_cb = cmd_cb;
67 ble_hci_ram_rx_cmd_hs_arg = cmd_arg;
68 ble_hci_ram_rx_acl_hs_cb = acl_cb;
69 ble_hci_ram_rx_acl_hs_arg = acl_arg;
70 }
71
72 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)73 ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb,
74 void *cmd_arg,
75 ble_hci_trans_rx_acl_fn *acl_cb,
76 void *acl_arg)
77 {
78 ble_hci_ram_rx_cmd_ll_cb = cmd_cb;
79 ble_hci_ram_rx_cmd_ll_arg = cmd_arg;
80 ble_hci_ram_rx_acl_ll_cb = acl_cb;
81 ble_hci_ram_rx_acl_ll_arg = acl_arg;
82 }
83
84 int
ble_hci_trans_hs_cmd_tx(uint8_t * cmd)85 ble_hci_trans_hs_cmd_tx(uint8_t *cmd)
86 {
87 int rc;
88
89 assert(ble_hci_ram_rx_cmd_ll_cb != NULL);
90
91 rc = ble_hci_ram_rx_cmd_ll_cb(cmd, ble_hci_ram_rx_cmd_ll_arg);
92 return rc;
93 }
94
95 int
ble_hci_trans_ll_evt_tx(uint8_t * hci_ev)96 ble_hci_trans_ll_evt_tx(uint8_t *hci_ev)
97 {
98 int rc;
99
100 assert(ble_hci_ram_rx_cmd_hs_cb != NULL);
101
102 rc = ble_hci_ram_rx_cmd_hs_cb(hci_ev, ble_hci_ram_rx_cmd_hs_arg);
103 return rc;
104 }
105
106 int
ble_hci_trans_hs_acl_tx(struct os_mbuf * om)107 ble_hci_trans_hs_acl_tx(struct os_mbuf *om)
108 {
109 int rc;
110
111 assert(ble_hci_ram_rx_acl_ll_cb != NULL);
112
113 rc = ble_hci_ram_rx_acl_ll_cb(om, ble_hci_ram_rx_acl_ll_arg);
114 return rc;
115 }
116
117 int
ble_hci_trans_ll_acl_tx(struct os_mbuf * om)118 ble_hci_trans_ll_acl_tx(struct os_mbuf *om)
119 {
120 int rc;
121
122 assert(ble_hci_ram_rx_acl_hs_cb != NULL);
123
124 rc = ble_hci_ram_rx_acl_hs_cb(om, ble_hci_ram_rx_acl_hs_arg);
125 return rc;
126 }
127
128 uint8_t *
ble_hci_trans_buf_alloc(int type)129 ble_hci_trans_buf_alloc(int type)
130 {
131 uint8_t *buf;
132
133 switch (type) {
134 case BLE_HCI_TRANS_BUF_CMD:
135 buf = os_memblock_get(&ble_hci_ram_cmd_pool);
136 break;
137
138 case BLE_HCI_TRANS_BUF_EVT_HI:
139 buf = os_memblock_get(&ble_hci_ram_evt_hi_pool);
140 if (buf == NULL) {
141 /* If no high-priority event buffers remain, try to grab a
142 * low-priority one.
143 */
144 buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO);
145 }
146 break;
147
148 case BLE_HCI_TRANS_BUF_EVT_LO:
149 buf = os_memblock_get(&ble_hci_ram_evt_lo_pool);
150 break;
151
152 default:
153 assert(0);
154 buf = NULL;
155 }
156
157 return buf;
158 }
159
160 void
ble_hci_trans_buf_free(uint8_t * buf)161 ble_hci_trans_buf_free(uint8_t *buf)
162 {
163 int rc;
164
165 /* XXX: this may look a bit odd, but the controller uses the command
166 * buffer to send back the command complete/status as an immediate
167 * response to the command. This was done to insure that the controller
168 * could always send back one of these events when a command was received.
169 * Thus, we check to see which pool the buffer came from so we can free
170 * it to the appropriate pool
171 */
172 if (os_memblock_from(&ble_hci_ram_evt_hi_pool, buf)) {
173 rc = os_memblock_put(&ble_hci_ram_evt_hi_pool, buf);
174 assert(rc == 0);
175 } else if (os_memblock_from(&ble_hci_ram_evt_lo_pool, buf)) {
176 rc = os_memblock_put(&ble_hci_ram_evt_lo_pool, buf);
177 assert(rc == 0);
178 } else {
179 assert(os_memblock_from(&ble_hci_ram_cmd_pool, buf));
180 rc = os_memblock_put(&ble_hci_ram_cmd_pool, buf);
181 assert(rc == 0);
182 }
183 }
184
185 /**
186 * Unsupported; the RAM transport does not have a dedicated ACL data packet
187 * pool.
188 */
189 int
ble_hci_trans_set_acl_free_cb(os_mempool_put_fn * cb,void * arg)190 ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
191 {
192 return BLE_ERR_UNSUPPORTED;
193 }
194
195 int
ble_hci_trans_reset(void)196 ble_hci_trans_reset(void)
197 {
198 /* No work to do. All allocated buffers are owned by the host or
199 * controller, and they will get freed by their owners.
200 */
201 return 0;
202 }
203
204 void
ble_hci_ram_init(void)205 ble_hci_ram_init(void)
206 {
207 int rc;
208
209 /* Ensure this function only gets called by sysinit. */
210 SYSINIT_ASSERT_ACTIVE();
211
212 /*
213 * Create memory pool of HCI command buffers. NOTE: we currently dont
214 * allow this to be configured. The controller will only allow one
215 * outstanding command. We decided to keep this a pool in case we allow
216 * allow the controller to handle more than one outstanding command.
217 */
218 rc = os_mempool_init(&ble_hci_ram_cmd_pool,
219 1,
220 BLE_HCI_TRANS_CMD_SZ,
221 ble_hci_ram_cmd_buf,
222 "ble_hci_ram_cmd_pool");
223 SYSINIT_PANIC_ASSERT(rc == 0);
224
225 rc = os_mempool_init(&ble_hci_ram_evt_hi_pool,
226 MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT),
227 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
228 ble_hci_ram_evt_hi_buf,
229 "ble_hci_ram_evt_hi_pool");
230 SYSINIT_PANIC_ASSERT(rc == 0);
231
232 rc = os_mempool_init(&ble_hci_ram_evt_lo_pool,
233 MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT),
234 MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE),
235 ble_hci_ram_evt_lo_buf,
236 "ble_hci_ram_evt_lo_pool");
237 SYSINIT_PANIC_ASSERT(rc == 0);
238 }
239