hci_unit.c revision 1.15 1 1.15 thorpej /* $NetBSD: hci_unit.c,v 1.15 2021/04/24 23:37:01 thorpej Exp $ */
2 1.1 gdamore
3 1.1 gdamore /*-
4 1.1 gdamore * Copyright (c) 2005 Iain Hibbert.
5 1.1 gdamore * Copyright (c) 2006 Itronix Inc.
6 1.1 gdamore * All rights reserved.
7 1.1 gdamore *
8 1.1 gdamore * Redistribution and use in source and binary forms, with or without
9 1.1 gdamore * modification, are permitted provided that the following conditions
10 1.1 gdamore * are met:
11 1.1 gdamore * 1. Redistributions of source code must retain the above copyright
12 1.1 gdamore * notice, this list of conditions and the following disclaimer.
13 1.1 gdamore * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 gdamore * notice, this list of conditions and the following disclaimer in the
15 1.1 gdamore * documentation and/or other materials provided with the distribution.
16 1.1 gdamore * 3. The name of Itronix Inc. may not be used to endorse
17 1.1 gdamore * or promote products derived from this software without specific
18 1.1 gdamore * prior written permission.
19 1.1 gdamore *
20 1.1 gdamore * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
21 1.1 gdamore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 1.1 gdamore * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 1.1 gdamore * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
24 1.1 gdamore * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 1.1 gdamore * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 1.1 gdamore * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 1.1 gdamore * ON ANY THEORY OF LIABILITY, WHETHER IN
28 1.1 gdamore * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 1.1 gdamore * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 1.1 gdamore * POSSIBILITY OF SUCH DAMAGE.
31 1.1 gdamore */
32 1.1 gdamore
33 1.1 gdamore #include <sys/cdefs.h>
34 1.15 thorpej __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.15 2021/04/24 23:37:01 thorpej Exp $");
35 1.1 gdamore
36 1.1 gdamore #include <sys/param.h>
37 1.1 gdamore #include <sys/conf.h>
38 1.1 gdamore #include <sys/device.h>
39 1.1 gdamore #include <sys/kernel.h>
40 1.1 gdamore #include <sys/malloc.h>
41 1.1 gdamore #include <sys/mbuf.h>
42 1.1 gdamore #include <sys/proc.h>
43 1.1 gdamore #include <sys/queue.h>
44 1.1 gdamore #include <sys/systm.h>
45 1.5 ad #include <sys/intr.h>
46 1.11 ad #include <sys/socketvar.h>
47 1.1 gdamore
48 1.1 gdamore #include <netbt/bluetooth.h>
49 1.1 gdamore #include <netbt/hci.h>
50 1.1 gdamore
51 1.1 gdamore struct hci_unit_list hci_unit_list = SIMPLEQ_HEAD_INITIALIZER(hci_unit_list);
52 1.1 gdamore
53 1.1 gdamore MALLOC_DEFINE(M_BLUETOOTH, "Bluetooth", "Bluetooth System Memory");
54 1.1 gdamore
55 1.1 gdamore /*
56 1.1 gdamore * HCI Input Queue max lengths.
57 1.1 gdamore */
58 1.1 gdamore int hci_eventq_max = 20;
59 1.1 gdamore int hci_aclrxq_max = 50;
60 1.1 gdamore int hci_scorxq_max = 50;
61 1.1 gdamore
62 1.1 gdamore /*
63 1.9 plunky * This is the default minimum command set supported by older
64 1.9 plunky * devices. Anything conforming to 1.2 spec or later will get
65 1.9 plunky * updated during init.
66 1.9 plunky */
67 1.9 plunky static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
68 1.9 plunky 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
69 1.9 plunky 0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
70 1.9 plunky 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 1.9 plunky 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 1.9 plunky 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 1.9 plunky 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 1.9 plunky 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 1.9 plunky 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
76 1.9 plunky };
77 1.9 plunky
78 1.9 plunky /*
79 1.1 gdamore * bluetooth unit functions
80 1.1 gdamore */
81 1.1 gdamore static void hci_intr (void *);
82 1.1 gdamore
83 1.8 plunky struct hci_unit *
84 1.14 rmind hci_attach_pcb(const struct hci_if *hci_if, device_t dev, uint16_t flags)
85 1.1 gdamore {
86 1.8 plunky struct hci_unit *unit;
87 1.8 plunky
88 1.8 plunky KASSERT(dev != NULL);
89 1.8 plunky KASSERT(hci_if->enable != NULL);
90 1.8 plunky KASSERT(hci_if->disable != NULL);
91 1.8 plunky KASSERT(hci_if->output_cmd != NULL);
92 1.8 plunky KASSERT(hci_if->output_acl != NULL);
93 1.8 plunky KASSERT(hci_if->output_sco != NULL);
94 1.8 plunky KASSERT(hci_if->get_stats != NULL);
95 1.8 plunky
96 1.8 plunky unit = malloc(sizeof(struct hci_unit), M_BLUETOOTH, M_ZERO | M_WAITOK);
97 1.8 plunky KASSERT(unit != NULL);
98 1.1 gdamore
99 1.8 plunky unit->hci_dev = dev;
100 1.8 plunky unit->hci_if = hci_if;
101 1.8 plunky unit->hci_flags = flags;
102 1.8 plunky
103 1.8 plunky mutex_init(&unit->hci_devlock, MUTEX_DRIVER, hci_if->ipl);
104 1.11 ad cv_init(&unit->hci_init, "hci_init");
105 1.1 gdamore
106 1.1 gdamore MBUFQ_INIT(&unit->hci_eventq);
107 1.1 gdamore MBUFQ_INIT(&unit->hci_aclrxq);
108 1.1 gdamore MBUFQ_INIT(&unit->hci_scorxq);
109 1.1 gdamore MBUFQ_INIT(&unit->hci_cmdwait);
110 1.1 gdamore MBUFQ_INIT(&unit->hci_scodone);
111 1.1 gdamore
112 1.1 gdamore TAILQ_INIT(&unit->hci_links);
113 1.1 gdamore LIST_INIT(&unit->hci_memos);
114 1.1 gdamore
115 1.11 ad mutex_enter(bt_lock);
116 1.1 gdamore SIMPLEQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
117 1.11 ad mutex_exit(bt_lock);
118 1.8 plunky
119 1.8 plunky return unit;
120 1.1 gdamore }
121 1.1 gdamore
122 1.1 gdamore void
123 1.14 rmind hci_detach_pcb(struct hci_unit *unit)
124 1.1 gdamore {
125 1.1 gdamore
126 1.11 ad mutex_enter(bt_lock);
127 1.1 gdamore hci_disable(unit);
128 1.1 gdamore
129 1.1 gdamore SIMPLEQ_REMOVE(&hci_unit_list, unit, hci_unit, hci_next);
130 1.11 ad mutex_exit(bt_lock);
131 1.8 plunky
132 1.11 ad cv_destroy(&unit->hci_init);
133 1.8 plunky mutex_destroy(&unit->hci_devlock);
134 1.8 plunky free(unit, M_BLUETOOTH);
135 1.1 gdamore }
136 1.1 gdamore
137 1.1 gdamore int
138 1.1 gdamore hci_enable(struct hci_unit *unit)
139 1.1 gdamore {
140 1.8 plunky int err;
141 1.1 gdamore
142 1.1 gdamore /*
143 1.1 gdamore * Bluetooth spec says that a device can accept one
144 1.1 gdamore * command on power up until they send a Command Status
145 1.1 gdamore * or Command Complete event with more information, but
146 1.1 gdamore * it seems that some devices cant and prefer to send a
147 1.8 plunky * No-op Command Status packet when they are ready.
148 1.1 gdamore */
149 1.8 plunky unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
150 1.1 gdamore unit->hci_num_acl_pkts = 0;
151 1.1 gdamore unit->hci_num_sco_pkts = 0;
152 1.1 gdamore
153 1.1 gdamore /*
154 1.1 gdamore * only allow the basic packet types until
155 1.1 gdamore * the features report is in
156 1.1 gdamore */
157 1.1 gdamore unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
158 1.1 gdamore unit->hci_packet_type = unit->hci_acl_mask;
159 1.1 gdamore
160 1.9 plunky memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
161 1.9 plunky
162 1.5 ad unit->hci_rxint = softint_establish(SOFTINT_NET, &hci_intr, unit);
163 1.1 gdamore if (unit->hci_rxint == NULL)
164 1.1 gdamore return EIO;
165 1.1 gdamore
166 1.8 plunky err = (*unit->hci_if->enable)(unit->hci_dev);
167 1.1 gdamore if (err)
168 1.1 gdamore goto bad1;
169 1.1 gdamore
170 1.8 plunky unit->hci_flags |= BTF_RUNNING;
171 1.8 plunky
172 1.1 gdamore /*
173 1.1 gdamore * Reset the device, this will trigger initialisation
174 1.1 gdamore * and wake us up.
175 1.1 gdamore */
176 1.1 gdamore unit->hci_flags |= BTF_INIT;
177 1.1 gdamore
178 1.1 gdamore err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
179 1.1 gdamore if (err)
180 1.1 gdamore goto bad2;
181 1.1 gdamore
182 1.1 gdamore while (unit->hci_flags & BTF_INIT) {
183 1.11 ad err = cv_timedwait_sig(&unit->hci_init, bt_lock, 5 * hz);
184 1.1 gdamore if (err)
185 1.1 gdamore goto bad2;
186 1.1 gdamore
187 1.1 gdamore /* XXX
188 1.1 gdamore * "What If", while we were sleeping, the device
189 1.1 gdamore * was removed and detached? Ho Hum.
190 1.1 gdamore */
191 1.1 gdamore }
192 1.1 gdamore
193 1.3 plunky /*
194 1.3 plunky * Attach Bluetooth Device Hub
195 1.3 plunky */
196 1.15 thorpej unit->hci_bthub = config_found(unit->hci_dev, &unit->hci_bdaddr, NULL,
197 1.15 thorpej CFARG_IATTR, "btbus",
198 1.15 thorpej CFARG_EOL);
199 1.3 plunky
200 1.1 gdamore return 0;
201 1.1 gdamore
202 1.1 gdamore bad2:
203 1.8 plunky (*unit->hci_if->disable)(unit->hci_dev);
204 1.8 plunky unit->hci_flags &= ~BTF_RUNNING;
205 1.1 gdamore bad1:
206 1.5 ad softint_disestablish(unit->hci_rxint);
207 1.1 gdamore unit->hci_rxint = NULL;
208 1.1 gdamore
209 1.1 gdamore return err;
210 1.1 gdamore }
211 1.1 gdamore
212 1.1 gdamore void
213 1.1 gdamore hci_disable(struct hci_unit *unit)
214 1.1 gdamore {
215 1.1 gdamore struct hci_link *link, *next;
216 1.1 gdamore struct hci_memo *memo;
217 1.8 plunky int acl;
218 1.1 gdamore
219 1.3 plunky if (unit->hci_bthub) {
220 1.12 plunky device_t hub;
221 1.12 plunky
222 1.12 plunky hub = unit->hci_bthub;
223 1.3 plunky unit->hci_bthub = NULL;
224 1.12 plunky
225 1.12 plunky mutex_exit(bt_lock);
226 1.12 plunky config_detach(hub, DETACH_FORCE);
227 1.12 plunky mutex_enter(bt_lock);
228 1.3 plunky }
229 1.3 plunky
230 1.1 gdamore if (unit->hci_rxint) {
231 1.5 ad softint_disestablish(unit->hci_rxint);
232 1.1 gdamore unit->hci_rxint = NULL;
233 1.1 gdamore }
234 1.1 gdamore
235 1.8 plunky (*unit->hci_if->disable)(unit->hci_dev);
236 1.8 plunky unit->hci_flags &= ~BTF_RUNNING;
237 1.1 gdamore
238 1.1 gdamore /*
239 1.1 gdamore * close down any links, take care to close SCO first since
240 1.1 gdamore * they may depend on ACL links.
241 1.1 gdamore */
242 1.1 gdamore for (acl = 0 ; acl < 2 ; acl++) {
243 1.1 gdamore next = TAILQ_FIRST(&unit->hci_links);
244 1.1 gdamore while ((link = next) != NULL) {
245 1.1 gdamore next = TAILQ_NEXT(link, hl_next);
246 1.1 gdamore if (acl || link->hl_type != HCI_LINK_ACL)
247 1.1 gdamore hci_link_free(link, ECONNABORTED);
248 1.1 gdamore }
249 1.1 gdamore }
250 1.1 gdamore
251 1.1 gdamore while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
252 1.1 gdamore hci_memo_free(memo);
253 1.1 gdamore
254 1.8 plunky /* (no need to hold hci_devlock, the driver is disabled) */
255 1.8 plunky
256 1.1 gdamore MBUFQ_DRAIN(&unit->hci_eventq);
257 1.1 gdamore unit->hci_eventqlen = 0;
258 1.1 gdamore
259 1.1 gdamore MBUFQ_DRAIN(&unit->hci_aclrxq);
260 1.1 gdamore unit->hci_aclrxqlen = 0;
261 1.1 gdamore
262 1.1 gdamore MBUFQ_DRAIN(&unit->hci_scorxq);
263 1.1 gdamore unit->hci_scorxqlen = 0;
264 1.1 gdamore
265 1.1 gdamore MBUFQ_DRAIN(&unit->hci_cmdwait);
266 1.1 gdamore MBUFQ_DRAIN(&unit->hci_scodone);
267 1.1 gdamore }
268 1.1 gdamore
269 1.1 gdamore struct hci_unit *
270 1.13 plunky hci_unit_lookup(const bdaddr_t *addr)
271 1.1 gdamore {
272 1.1 gdamore struct hci_unit *unit;
273 1.1 gdamore
274 1.1 gdamore SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
275 1.1 gdamore if ((unit->hci_flags & BTF_UP) == 0)
276 1.1 gdamore continue;
277 1.1 gdamore
278 1.1 gdamore if (bdaddr_same(&unit->hci_bdaddr, addr))
279 1.1 gdamore break;
280 1.1 gdamore }
281 1.1 gdamore
282 1.1 gdamore return unit;
283 1.1 gdamore }
284 1.1 gdamore
285 1.1 gdamore /*
286 1.10 plunky * update num_cmd_pkts and push on pending commands queue
287 1.10 plunky */
288 1.10 plunky void
289 1.10 plunky hci_num_cmds(struct hci_unit *unit, uint8_t num)
290 1.10 plunky {
291 1.10 plunky struct mbuf *m;
292 1.10 plunky
293 1.10 plunky unit->hci_num_cmd_pkts = num;
294 1.10 plunky
295 1.10 plunky while (unit->hci_num_cmd_pkts > 0 && MBUFQ_FIRST(&unit->hci_cmdwait)) {
296 1.10 plunky MBUFQ_DEQUEUE(&unit->hci_cmdwait, m);
297 1.10 plunky hci_output_cmd(unit, m);
298 1.10 plunky }
299 1.10 plunky }
300 1.10 plunky
301 1.10 plunky /*
302 1.1 gdamore * construct and queue a HCI command packet
303 1.1 gdamore */
304 1.1 gdamore int
305 1.1 gdamore hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
306 1.1 gdamore {
307 1.1 gdamore struct mbuf *m;
308 1.1 gdamore hci_cmd_hdr_t *p;
309 1.1 gdamore
310 1.4 plunky KASSERT(unit != NULL);
311 1.1 gdamore
312 1.1 gdamore m = m_gethdr(M_DONTWAIT, MT_DATA);
313 1.1 gdamore if (m == NULL)
314 1.1 gdamore return ENOMEM;
315 1.1 gdamore
316 1.1 gdamore p = mtod(m, hci_cmd_hdr_t *);
317 1.1 gdamore p->type = HCI_CMD_PKT;
318 1.1 gdamore p->opcode = htole16(opcode);
319 1.1 gdamore p->length = len;
320 1.1 gdamore m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
321 1.1 gdamore
322 1.1 gdamore if (len) {
323 1.4 plunky KASSERT(buf != NULL);
324 1.1 gdamore
325 1.1 gdamore m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
326 1.1 gdamore if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
327 1.1 gdamore m_freem(m);
328 1.1 gdamore return ENOMEM;
329 1.1 gdamore }
330 1.1 gdamore }
331 1.1 gdamore
332 1.7 plunky DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
333 1.1 gdamore HCI_OGF(opcode), HCI_OCF(opcode));
334 1.1 gdamore
335 1.1 gdamore /* and send it on */
336 1.1 gdamore if (unit->hci_num_cmd_pkts == 0)
337 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
338 1.1 gdamore else
339 1.1 gdamore hci_output_cmd(unit, m);
340 1.1 gdamore
341 1.1 gdamore return 0;
342 1.1 gdamore }
343 1.1 gdamore
344 1.1 gdamore /*
345 1.1 gdamore * Incoming packet processing. Since the code is single threaded
346 1.1 gdamore * in any case (IPL_SOFTNET), we handle it all in one interrupt function
347 1.1 gdamore * picking our way through more important packets first so that hopefully
348 1.1 gdamore * we will never get clogged up with bulk data.
349 1.1 gdamore */
350 1.1 gdamore static void
351 1.1 gdamore hci_intr(void *arg)
352 1.1 gdamore {
353 1.1 gdamore struct hci_unit *unit = arg;
354 1.1 gdamore struct mbuf *m;
355 1.1 gdamore
356 1.11 ad mutex_enter(bt_lock);
357 1.1 gdamore another:
358 1.8 plunky mutex_enter(&unit->hci_devlock);
359 1.1 gdamore
360 1.1 gdamore if (unit->hci_eventqlen > 0) {
361 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_eventq, m);
362 1.1 gdamore unit->hci_eventqlen--;
363 1.8 plunky mutex_exit(&unit->hci_devlock);
364 1.8 plunky
365 1.1 gdamore KASSERT(m != NULL);
366 1.1 gdamore
367 1.1 gdamore DPRINTFN(10, "(%s) recv event, len = %d\n",
368 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
369 1.1 gdamore
370 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
371 1.1 gdamore hci_mtap(m, unit);
372 1.1 gdamore hci_event(m, unit);
373 1.1 gdamore
374 1.1 gdamore goto another;
375 1.1 gdamore }
376 1.1 gdamore
377 1.1 gdamore if (unit->hci_scorxqlen > 0) {
378 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
379 1.1 gdamore unit->hci_scorxqlen--;
380 1.8 plunky mutex_exit(&unit->hci_devlock);
381 1.8 plunky
382 1.1 gdamore KASSERT(m != NULL);
383 1.1 gdamore
384 1.1 gdamore DPRINTFN(10, "(%s) recv SCO, len = %d\n",
385 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
386 1.1 gdamore
387 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
388 1.1 gdamore hci_mtap(m, unit);
389 1.1 gdamore hci_sco_recv(m, unit);
390 1.1 gdamore
391 1.1 gdamore goto another;
392 1.1 gdamore }
393 1.1 gdamore
394 1.1 gdamore if (unit->hci_aclrxqlen > 0) {
395 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
396 1.1 gdamore unit->hci_aclrxqlen--;
397 1.8 plunky mutex_exit(&unit->hci_devlock);
398 1.8 plunky
399 1.1 gdamore KASSERT(m != NULL);
400 1.1 gdamore
401 1.1 gdamore DPRINTFN(10, "(%s) recv ACL, len = %d\n",
402 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
403 1.1 gdamore
404 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
405 1.1 gdamore hci_mtap(m, unit);
406 1.1 gdamore hci_acl_recv(m, unit);
407 1.1 gdamore
408 1.1 gdamore goto another;
409 1.1 gdamore }
410 1.1 gdamore
411 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_scodone, m);
412 1.1 gdamore if (m != NULL) {
413 1.1 gdamore struct hci_link *link;
414 1.8 plunky
415 1.8 plunky mutex_exit(&unit->hci_devlock);
416 1.1 gdamore
417 1.1 gdamore DPRINTFN(11, "(%s) complete SCO\n",
418 1.7 plunky device_xname(unit->hci_dev));
419 1.1 gdamore
420 1.1 gdamore TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
421 1.1 gdamore if (link == M_GETCTX(m, struct hci_link *)) {
422 1.1 gdamore hci_sco_complete(link, 1);
423 1.1 gdamore break;
424 1.1 gdamore }
425 1.1 gdamore }
426 1.1 gdamore
427 1.1 gdamore unit->hci_num_sco_pkts++;
428 1.1 gdamore m_freem(m);
429 1.1 gdamore
430 1.1 gdamore goto another;
431 1.1 gdamore }
432 1.1 gdamore
433 1.8 plunky mutex_exit(&unit->hci_devlock);
434 1.11 ad mutex_exit(bt_lock);
435 1.1 gdamore
436 1.1 gdamore DPRINTFN(10, "done\n");
437 1.1 gdamore }
438 1.1 gdamore
439 1.1 gdamore /**********************************************************************
440 1.1 gdamore *
441 1.1 gdamore * IO routines
442 1.1 gdamore *
443 1.8 plunky * input & complete routines will be called from device drivers,
444 1.8 plunky * possibly in interrupt context. We return success or failure to
445 1.8 plunky * enable proper accounting but we own the mbuf.
446 1.1 gdamore */
447 1.1 gdamore
448 1.8 plunky bool
449 1.1 gdamore hci_input_event(struct hci_unit *unit, struct mbuf *m)
450 1.1 gdamore {
451 1.8 plunky bool rv;
452 1.8 plunky
453 1.8 plunky mutex_enter(&unit->hci_devlock);
454 1.1 gdamore
455 1.1 gdamore if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
456 1.7 plunky DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
457 1.1 gdamore m_freem(m);
458 1.8 plunky rv = false;
459 1.1 gdamore } else {
460 1.1 gdamore unit->hci_eventqlen++;
461 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_eventq, m);
462 1.5 ad softint_schedule(unit->hci_rxint);
463 1.8 plunky rv = true;
464 1.1 gdamore }
465 1.8 plunky
466 1.8 plunky mutex_exit(&unit->hci_devlock);
467 1.8 plunky return rv;
468 1.1 gdamore }
469 1.1 gdamore
470 1.8 plunky bool
471 1.1 gdamore hci_input_acl(struct hci_unit *unit, struct mbuf *m)
472 1.1 gdamore {
473 1.8 plunky bool rv;
474 1.8 plunky
475 1.8 plunky mutex_enter(&unit->hci_devlock);
476 1.1 gdamore
477 1.1 gdamore if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
478 1.7 plunky DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
479 1.1 gdamore m_freem(m);
480 1.8 plunky rv = false;
481 1.1 gdamore } else {
482 1.1 gdamore unit->hci_aclrxqlen++;
483 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
484 1.5 ad softint_schedule(unit->hci_rxint);
485 1.8 plunky rv = true;
486 1.1 gdamore }
487 1.8 plunky
488 1.8 plunky mutex_exit(&unit->hci_devlock);
489 1.8 plunky return rv;
490 1.1 gdamore }
491 1.1 gdamore
492 1.8 plunky bool
493 1.1 gdamore hci_input_sco(struct hci_unit *unit, struct mbuf *m)
494 1.1 gdamore {
495 1.8 plunky bool rv;
496 1.8 plunky
497 1.8 plunky mutex_enter(&unit->hci_devlock);
498 1.1 gdamore
499 1.1 gdamore if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
500 1.7 plunky DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
501 1.1 gdamore m_freem(m);
502 1.8 plunky rv = false;
503 1.1 gdamore } else {
504 1.1 gdamore unit->hci_scorxqlen++;
505 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
506 1.5 ad softint_schedule(unit->hci_rxint);
507 1.8 plunky rv = true;
508 1.1 gdamore }
509 1.8 plunky
510 1.8 plunky mutex_exit(&unit->hci_devlock);
511 1.8 plunky return rv;
512 1.1 gdamore }
513 1.1 gdamore
514 1.1 gdamore void
515 1.1 gdamore hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
516 1.1 gdamore {
517 1.1 gdamore void *arg;
518 1.1 gdamore
519 1.1 gdamore hci_mtap(m, unit);
520 1.1 gdamore
521 1.7 plunky DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", device_xname(unit->hci_dev),
522 1.1 gdamore unit->hci_num_cmd_pkts);
523 1.1 gdamore
524 1.1 gdamore unit->hci_num_cmd_pkts--;
525 1.1 gdamore
526 1.1 gdamore /*
527 1.1 gdamore * If context is set, this was from a HCI raw socket
528 1.1 gdamore * and a record needs to be dropped from the sockbuf.
529 1.1 gdamore */
530 1.1 gdamore arg = M_GETCTX(m, void *);
531 1.1 gdamore if (arg != NULL)
532 1.1 gdamore hci_drop(arg);
533 1.1 gdamore
534 1.8 plunky (*unit->hci_if->output_cmd)(unit->hci_dev, m);
535 1.1 gdamore }
536 1.1 gdamore
537 1.1 gdamore void
538 1.1 gdamore hci_output_acl(struct hci_unit *unit, struct mbuf *m)
539 1.1 gdamore {
540 1.1 gdamore
541 1.1 gdamore hci_mtap(m, unit);
542 1.1 gdamore
543 1.7 plunky DPRINTFN(10, "(%s) num_acl_pkts=%d\n", device_xname(unit->hci_dev),
544 1.1 gdamore unit->hci_num_acl_pkts);
545 1.1 gdamore
546 1.1 gdamore unit->hci_num_acl_pkts--;
547 1.8 plunky (*unit->hci_if->output_acl)(unit->hci_dev, m);
548 1.1 gdamore }
549 1.1 gdamore
550 1.1 gdamore void
551 1.1 gdamore hci_output_sco(struct hci_unit *unit, struct mbuf *m)
552 1.1 gdamore {
553 1.1 gdamore
554 1.1 gdamore hci_mtap(m, unit);
555 1.1 gdamore
556 1.7 plunky DPRINTFN(10, "(%s) num_sco_pkts=%d\n", device_xname(unit->hci_dev),
557 1.1 gdamore unit->hci_num_sco_pkts);
558 1.1 gdamore
559 1.1 gdamore unit->hci_num_sco_pkts--;
560 1.8 plunky (*unit->hci_if->output_sco)(unit->hci_dev, m);
561 1.1 gdamore }
562 1.1 gdamore
563 1.8 plunky bool
564 1.1 gdamore hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
565 1.1 gdamore {
566 1.1 gdamore
567 1.1 gdamore if (unit->hci_rxint == NULL) {
568 1.7 plunky DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
569 1.1 gdamore m_freem(m);
570 1.8 plunky return false;
571 1.1 gdamore }
572 1.8 plunky
573 1.8 plunky mutex_enter(&unit->hci_devlock);
574 1.8 plunky
575 1.8 plunky MBUFQ_ENQUEUE(&unit->hci_scodone, m);
576 1.8 plunky softint_schedule(unit->hci_rxint);
577 1.8 plunky
578 1.8 plunky mutex_exit(&unit->hci_devlock);
579 1.8 plunky return true;
580 1.1 gdamore }
581