hci_unit.c revision 1.16 1 1.16 thorpej /* $NetBSD: hci_unit.c,v 1.16 2021/08/07 16:19:18 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.16 thorpej __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.16 2021/08/07 16:19:18 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.16 thorpej CFARGS(.iattr = "btbus"));
198 1.3 plunky
199 1.1 gdamore return 0;
200 1.1 gdamore
201 1.1 gdamore bad2:
202 1.8 plunky (*unit->hci_if->disable)(unit->hci_dev);
203 1.8 plunky unit->hci_flags &= ~BTF_RUNNING;
204 1.1 gdamore bad1:
205 1.5 ad softint_disestablish(unit->hci_rxint);
206 1.1 gdamore unit->hci_rxint = NULL;
207 1.1 gdamore
208 1.1 gdamore return err;
209 1.1 gdamore }
210 1.1 gdamore
211 1.1 gdamore void
212 1.1 gdamore hci_disable(struct hci_unit *unit)
213 1.1 gdamore {
214 1.1 gdamore struct hci_link *link, *next;
215 1.1 gdamore struct hci_memo *memo;
216 1.8 plunky int acl;
217 1.1 gdamore
218 1.3 plunky if (unit->hci_bthub) {
219 1.12 plunky device_t hub;
220 1.12 plunky
221 1.12 plunky hub = unit->hci_bthub;
222 1.3 plunky unit->hci_bthub = NULL;
223 1.12 plunky
224 1.12 plunky mutex_exit(bt_lock);
225 1.12 plunky config_detach(hub, DETACH_FORCE);
226 1.12 plunky mutex_enter(bt_lock);
227 1.3 plunky }
228 1.3 plunky
229 1.1 gdamore if (unit->hci_rxint) {
230 1.5 ad softint_disestablish(unit->hci_rxint);
231 1.1 gdamore unit->hci_rxint = NULL;
232 1.1 gdamore }
233 1.1 gdamore
234 1.8 plunky (*unit->hci_if->disable)(unit->hci_dev);
235 1.8 plunky unit->hci_flags &= ~BTF_RUNNING;
236 1.1 gdamore
237 1.1 gdamore /*
238 1.1 gdamore * close down any links, take care to close SCO first since
239 1.1 gdamore * they may depend on ACL links.
240 1.1 gdamore */
241 1.1 gdamore for (acl = 0 ; acl < 2 ; acl++) {
242 1.1 gdamore next = TAILQ_FIRST(&unit->hci_links);
243 1.1 gdamore while ((link = next) != NULL) {
244 1.1 gdamore next = TAILQ_NEXT(link, hl_next);
245 1.1 gdamore if (acl || link->hl_type != HCI_LINK_ACL)
246 1.1 gdamore hci_link_free(link, ECONNABORTED);
247 1.1 gdamore }
248 1.1 gdamore }
249 1.1 gdamore
250 1.1 gdamore while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
251 1.1 gdamore hci_memo_free(memo);
252 1.1 gdamore
253 1.8 plunky /* (no need to hold hci_devlock, the driver is disabled) */
254 1.8 plunky
255 1.1 gdamore MBUFQ_DRAIN(&unit->hci_eventq);
256 1.1 gdamore unit->hci_eventqlen = 0;
257 1.1 gdamore
258 1.1 gdamore MBUFQ_DRAIN(&unit->hci_aclrxq);
259 1.1 gdamore unit->hci_aclrxqlen = 0;
260 1.1 gdamore
261 1.1 gdamore MBUFQ_DRAIN(&unit->hci_scorxq);
262 1.1 gdamore unit->hci_scorxqlen = 0;
263 1.1 gdamore
264 1.1 gdamore MBUFQ_DRAIN(&unit->hci_cmdwait);
265 1.1 gdamore MBUFQ_DRAIN(&unit->hci_scodone);
266 1.1 gdamore }
267 1.1 gdamore
268 1.1 gdamore struct hci_unit *
269 1.13 plunky hci_unit_lookup(const bdaddr_t *addr)
270 1.1 gdamore {
271 1.1 gdamore struct hci_unit *unit;
272 1.1 gdamore
273 1.1 gdamore SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
274 1.1 gdamore if ((unit->hci_flags & BTF_UP) == 0)
275 1.1 gdamore continue;
276 1.1 gdamore
277 1.1 gdamore if (bdaddr_same(&unit->hci_bdaddr, addr))
278 1.1 gdamore break;
279 1.1 gdamore }
280 1.1 gdamore
281 1.1 gdamore return unit;
282 1.1 gdamore }
283 1.1 gdamore
284 1.1 gdamore /*
285 1.10 plunky * update num_cmd_pkts and push on pending commands queue
286 1.10 plunky */
287 1.10 plunky void
288 1.10 plunky hci_num_cmds(struct hci_unit *unit, uint8_t num)
289 1.10 plunky {
290 1.10 plunky struct mbuf *m;
291 1.10 plunky
292 1.10 plunky unit->hci_num_cmd_pkts = num;
293 1.10 plunky
294 1.10 plunky while (unit->hci_num_cmd_pkts > 0 && MBUFQ_FIRST(&unit->hci_cmdwait)) {
295 1.10 plunky MBUFQ_DEQUEUE(&unit->hci_cmdwait, m);
296 1.10 plunky hci_output_cmd(unit, m);
297 1.10 plunky }
298 1.10 plunky }
299 1.10 plunky
300 1.10 plunky /*
301 1.1 gdamore * construct and queue a HCI command packet
302 1.1 gdamore */
303 1.1 gdamore int
304 1.1 gdamore hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
305 1.1 gdamore {
306 1.1 gdamore struct mbuf *m;
307 1.1 gdamore hci_cmd_hdr_t *p;
308 1.1 gdamore
309 1.4 plunky KASSERT(unit != NULL);
310 1.1 gdamore
311 1.1 gdamore m = m_gethdr(M_DONTWAIT, MT_DATA);
312 1.1 gdamore if (m == NULL)
313 1.1 gdamore return ENOMEM;
314 1.1 gdamore
315 1.1 gdamore p = mtod(m, hci_cmd_hdr_t *);
316 1.1 gdamore p->type = HCI_CMD_PKT;
317 1.1 gdamore p->opcode = htole16(opcode);
318 1.1 gdamore p->length = len;
319 1.1 gdamore m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
320 1.1 gdamore
321 1.1 gdamore if (len) {
322 1.4 plunky KASSERT(buf != NULL);
323 1.1 gdamore
324 1.1 gdamore m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
325 1.1 gdamore if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
326 1.1 gdamore m_freem(m);
327 1.1 gdamore return ENOMEM;
328 1.1 gdamore }
329 1.1 gdamore }
330 1.1 gdamore
331 1.7 plunky DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
332 1.1 gdamore HCI_OGF(opcode), HCI_OCF(opcode));
333 1.1 gdamore
334 1.1 gdamore /* and send it on */
335 1.1 gdamore if (unit->hci_num_cmd_pkts == 0)
336 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
337 1.1 gdamore else
338 1.1 gdamore hci_output_cmd(unit, m);
339 1.1 gdamore
340 1.1 gdamore return 0;
341 1.1 gdamore }
342 1.1 gdamore
343 1.1 gdamore /*
344 1.1 gdamore * Incoming packet processing. Since the code is single threaded
345 1.1 gdamore * in any case (IPL_SOFTNET), we handle it all in one interrupt function
346 1.1 gdamore * picking our way through more important packets first so that hopefully
347 1.1 gdamore * we will never get clogged up with bulk data.
348 1.1 gdamore */
349 1.1 gdamore static void
350 1.1 gdamore hci_intr(void *arg)
351 1.1 gdamore {
352 1.1 gdamore struct hci_unit *unit = arg;
353 1.1 gdamore struct mbuf *m;
354 1.1 gdamore
355 1.11 ad mutex_enter(bt_lock);
356 1.1 gdamore another:
357 1.8 plunky mutex_enter(&unit->hci_devlock);
358 1.1 gdamore
359 1.1 gdamore if (unit->hci_eventqlen > 0) {
360 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_eventq, m);
361 1.1 gdamore unit->hci_eventqlen--;
362 1.8 plunky mutex_exit(&unit->hci_devlock);
363 1.8 plunky
364 1.1 gdamore KASSERT(m != NULL);
365 1.1 gdamore
366 1.1 gdamore DPRINTFN(10, "(%s) recv event, len = %d\n",
367 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
368 1.1 gdamore
369 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
370 1.1 gdamore hci_mtap(m, unit);
371 1.1 gdamore hci_event(m, unit);
372 1.1 gdamore
373 1.1 gdamore goto another;
374 1.1 gdamore }
375 1.1 gdamore
376 1.1 gdamore if (unit->hci_scorxqlen > 0) {
377 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
378 1.1 gdamore unit->hci_scorxqlen--;
379 1.8 plunky mutex_exit(&unit->hci_devlock);
380 1.8 plunky
381 1.1 gdamore KASSERT(m != NULL);
382 1.1 gdamore
383 1.1 gdamore DPRINTFN(10, "(%s) recv SCO, len = %d\n",
384 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
385 1.1 gdamore
386 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
387 1.1 gdamore hci_mtap(m, unit);
388 1.1 gdamore hci_sco_recv(m, unit);
389 1.1 gdamore
390 1.1 gdamore goto another;
391 1.1 gdamore }
392 1.1 gdamore
393 1.1 gdamore if (unit->hci_aclrxqlen > 0) {
394 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
395 1.1 gdamore unit->hci_aclrxqlen--;
396 1.8 plunky mutex_exit(&unit->hci_devlock);
397 1.8 plunky
398 1.1 gdamore KASSERT(m != NULL);
399 1.1 gdamore
400 1.1 gdamore DPRINTFN(10, "(%s) recv ACL, len = %d\n",
401 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
402 1.1 gdamore
403 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
404 1.1 gdamore hci_mtap(m, unit);
405 1.1 gdamore hci_acl_recv(m, unit);
406 1.1 gdamore
407 1.1 gdamore goto another;
408 1.1 gdamore }
409 1.1 gdamore
410 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_scodone, m);
411 1.1 gdamore if (m != NULL) {
412 1.1 gdamore struct hci_link *link;
413 1.8 plunky
414 1.8 plunky mutex_exit(&unit->hci_devlock);
415 1.1 gdamore
416 1.1 gdamore DPRINTFN(11, "(%s) complete SCO\n",
417 1.7 plunky device_xname(unit->hci_dev));
418 1.1 gdamore
419 1.1 gdamore TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
420 1.1 gdamore if (link == M_GETCTX(m, struct hci_link *)) {
421 1.1 gdamore hci_sco_complete(link, 1);
422 1.1 gdamore break;
423 1.1 gdamore }
424 1.1 gdamore }
425 1.1 gdamore
426 1.1 gdamore unit->hci_num_sco_pkts++;
427 1.1 gdamore m_freem(m);
428 1.1 gdamore
429 1.1 gdamore goto another;
430 1.1 gdamore }
431 1.1 gdamore
432 1.8 plunky mutex_exit(&unit->hci_devlock);
433 1.11 ad mutex_exit(bt_lock);
434 1.1 gdamore
435 1.1 gdamore DPRINTFN(10, "done\n");
436 1.1 gdamore }
437 1.1 gdamore
438 1.1 gdamore /**********************************************************************
439 1.1 gdamore *
440 1.1 gdamore * IO routines
441 1.1 gdamore *
442 1.8 plunky * input & complete routines will be called from device drivers,
443 1.8 plunky * possibly in interrupt context. We return success or failure to
444 1.8 plunky * enable proper accounting but we own the mbuf.
445 1.1 gdamore */
446 1.1 gdamore
447 1.8 plunky bool
448 1.1 gdamore hci_input_event(struct hci_unit *unit, struct mbuf *m)
449 1.1 gdamore {
450 1.8 plunky bool rv;
451 1.8 plunky
452 1.8 plunky mutex_enter(&unit->hci_devlock);
453 1.1 gdamore
454 1.1 gdamore if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
455 1.7 plunky DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
456 1.1 gdamore m_freem(m);
457 1.8 plunky rv = false;
458 1.1 gdamore } else {
459 1.1 gdamore unit->hci_eventqlen++;
460 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_eventq, m);
461 1.5 ad softint_schedule(unit->hci_rxint);
462 1.8 plunky rv = true;
463 1.1 gdamore }
464 1.8 plunky
465 1.8 plunky mutex_exit(&unit->hci_devlock);
466 1.8 plunky return rv;
467 1.1 gdamore }
468 1.1 gdamore
469 1.8 plunky bool
470 1.1 gdamore hci_input_acl(struct hci_unit *unit, struct mbuf *m)
471 1.1 gdamore {
472 1.8 plunky bool rv;
473 1.8 plunky
474 1.8 plunky mutex_enter(&unit->hci_devlock);
475 1.1 gdamore
476 1.1 gdamore if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
477 1.7 plunky DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
478 1.1 gdamore m_freem(m);
479 1.8 plunky rv = false;
480 1.1 gdamore } else {
481 1.1 gdamore unit->hci_aclrxqlen++;
482 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
483 1.5 ad softint_schedule(unit->hci_rxint);
484 1.8 plunky rv = true;
485 1.1 gdamore }
486 1.8 plunky
487 1.8 plunky mutex_exit(&unit->hci_devlock);
488 1.8 plunky return rv;
489 1.1 gdamore }
490 1.1 gdamore
491 1.8 plunky bool
492 1.1 gdamore hci_input_sco(struct hci_unit *unit, struct mbuf *m)
493 1.1 gdamore {
494 1.8 plunky bool rv;
495 1.8 plunky
496 1.8 plunky mutex_enter(&unit->hci_devlock);
497 1.1 gdamore
498 1.1 gdamore if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
499 1.7 plunky DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
500 1.1 gdamore m_freem(m);
501 1.8 plunky rv = false;
502 1.1 gdamore } else {
503 1.1 gdamore unit->hci_scorxqlen++;
504 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
505 1.5 ad softint_schedule(unit->hci_rxint);
506 1.8 plunky rv = true;
507 1.1 gdamore }
508 1.8 plunky
509 1.8 plunky mutex_exit(&unit->hci_devlock);
510 1.8 plunky return rv;
511 1.1 gdamore }
512 1.1 gdamore
513 1.1 gdamore void
514 1.1 gdamore hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
515 1.1 gdamore {
516 1.1 gdamore void *arg;
517 1.1 gdamore
518 1.1 gdamore hci_mtap(m, unit);
519 1.1 gdamore
520 1.7 plunky DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", device_xname(unit->hci_dev),
521 1.1 gdamore unit->hci_num_cmd_pkts);
522 1.1 gdamore
523 1.1 gdamore unit->hci_num_cmd_pkts--;
524 1.1 gdamore
525 1.1 gdamore /*
526 1.1 gdamore * If context is set, this was from a HCI raw socket
527 1.1 gdamore * and a record needs to be dropped from the sockbuf.
528 1.1 gdamore */
529 1.1 gdamore arg = M_GETCTX(m, void *);
530 1.1 gdamore if (arg != NULL)
531 1.1 gdamore hci_drop(arg);
532 1.1 gdamore
533 1.8 plunky (*unit->hci_if->output_cmd)(unit->hci_dev, m);
534 1.1 gdamore }
535 1.1 gdamore
536 1.1 gdamore void
537 1.1 gdamore hci_output_acl(struct hci_unit *unit, struct mbuf *m)
538 1.1 gdamore {
539 1.1 gdamore
540 1.1 gdamore hci_mtap(m, unit);
541 1.1 gdamore
542 1.7 plunky DPRINTFN(10, "(%s) num_acl_pkts=%d\n", device_xname(unit->hci_dev),
543 1.1 gdamore unit->hci_num_acl_pkts);
544 1.1 gdamore
545 1.1 gdamore unit->hci_num_acl_pkts--;
546 1.8 plunky (*unit->hci_if->output_acl)(unit->hci_dev, m);
547 1.1 gdamore }
548 1.1 gdamore
549 1.1 gdamore void
550 1.1 gdamore hci_output_sco(struct hci_unit *unit, struct mbuf *m)
551 1.1 gdamore {
552 1.1 gdamore
553 1.1 gdamore hci_mtap(m, unit);
554 1.1 gdamore
555 1.7 plunky DPRINTFN(10, "(%s) num_sco_pkts=%d\n", device_xname(unit->hci_dev),
556 1.1 gdamore unit->hci_num_sco_pkts);
557 1.1 gdamore
558 1.1 gdamore unit->hci_num_sco_pkts--;
559 1.8 plunky (*unit->hci_if->output_sco)(unit->hci_dev, m);
560 1.1 gdamore }
561 1.1 gdamore
562 1.8 plunky bool
563 1.1 gdamore hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
564 1.1 gdamore {
565 1.1 gdamore
566 1.1 gdamore if (unit->hci_rxint == NULL) {
567 1.7 plunky DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
568 1.1 gdamore m_freem(m);
569 1.8 plunky return false;
570 1.1 gdamore }
571 1.8 plunky
572 1.8 plunky mutex_enter(&unit->hci_devlock);
573 1.8 plunky
574 1.8 plunky MBUFQ_ENQUEUE(&unit->hci_scodone, m);
575 1.8 plunky softint_schedule(unit->hci_rxint);
576 1.8 plunky
577 1.8 plunky mutex_exit(&unit->hci_devlock);
578 1.8 plunky return true;
579 1.1 gdamore }
580