hci_unit.c revision 1.8.6.1 1 1.8.6.1 bouyer /* $NetBSD: hci_unit.c,v 1.8.6.1 2008/01/02 21:57:17 bouyer 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.8.6.1 bouyer __KERNEL_RCSID(0, "$NetBSD: hci_unit.c,v 1.8.6.1 2008/01/02 21:57:17 bouyer 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.1 gdamore
47 1.1 gdamore #include <netbt/bluetooth.h>
48 1.1 gdamore #include <netbt/hci.h>
49 1.1 gdamore
50 1.1 gdamore struct hci_unit_list hci_unit_list = SIMPLEQ_HEAD_INITIALIZER(hci_unit_list);
51 1.1 gdamore
52 1.1 gdamore MALLOC_DEFINE(M_BLUETOOTH, "Bluetooth", "Bluetooth System Memory");
53 1.1 gdamore
54 1.1 gdamore /*
55 1.1 gdamore * HCI Input Queue max lengths.
56 1.1 gdamore */
57 1.1 gdamore int hci_eventq_max = 20;
58 1.1 gdamore int hci_aclrxq_max = 50;
59 1.1 gdamore int hci_scorxq_max = 50;
60 1.1 gdamore
61 1.1 gdamore /*
62 1.8.6.1 bouyer * This is the default minimum command set supported by older
63 1.8.6.1 bouyer * devices. Anything conforming to 1.2 spec or later will get
64 1.8.6.1 bouyer * updated during init.
65 1.8.6.1 bouyer */
66 1.8.6.1 bouyer static const uint8_t hci_cmds_v10[HCI_COMMANDS_SIZE] = {
67 1.8.6.1 bouyer 0xff, 0xff, 0xff, 0x01, 0xfe, 0xff, 0xff, 0xff,
68 1.8.6.1 bouyer 0xff, 0xff, 0xff, 0x7f, 0x32, 0x03, 0xb8, 0xfe,
69 1.8.6.1 bouyer 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70 1.8.6.1 bouyer 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 1.8.6.1 bouyer 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 1.8.6.1 bouyer 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 1.8.6.1 bouyer 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 1.8.6.1 bouyer 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
75 1.8.6.1 bouyer };
76 1.8.6.1 bouyer
77 1.8.6.1 bouyer /*
78 1.1 gdamore * bluetooth unit functions
79 1.1 gdamore */
80 1.1 gdamore static void hci_intr (void *);
81 1.1 gdamore
82 1.8 plunky struct hci_unit *
83 1.8 plunky hci_attach(const struct hci_if *hci_if, device_t dev, uint16_t flags)
84 1.1 gdamore {
85 1.8 plunky struct hci_unit *unit;
86 1.8 plunky int s;
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.1 gdamore
105 1.1 gdamore MBUFQ_INIT(&unit->hci_eventq);
106 1.1 gdamore MBUFQ_INIT(&unit->hci_aclrxq);
107 1.1 gdamore MBUFQ_INIT(&unit->hci_scorxq);
108 1.1 gdamore MBUFQ_INIT(&unit->hci_cmdwait);
109 1.1 gdamore MBUFQ_INIT(&unit->hci_scodone);
110 1.1 gdamore
111 1.1 gdamore TAILQ_INIT(&unit->hci_links);
112 1.1 gdamore LIST_INIT(&unit->hci_memos);
113 1.1 gdamore
114 1.8 plunky s = splsoftnet();
115 1.1 gdamore SIMPLEQ_INSERT_TAIL(&hci_unit_list, unit, hci_next);
116 1.8 plunky splx(s);
117 1.8 plunky
118 1.8 plunky return unit;
119 1.1 gdamore }
120 1.1 gdamore
121 1.1 gdamore void
122 1.1 gdamore hci_detach(struct hci_unit *unit)
123 1.1 gdamore {
124 1.8 plunky int s;
125 1.1 gdamore
126 1.8 plunky s = splsoftnet();
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.8 plunky splx(s);
131 1.8 plunky
132 1.8 plunky mutex_destroy(&unit->hci_devlock);
133 1.8 plunky free(unit, M_BLUETOOTH);
134 1.1 gdamore }
135 1.1 gdamore
136 1.1 gdamore int
137 1.1 gdamore hci_enable(struct hci_unit *unit)
138 1.1 gdamore {
139 1.8 plunky int err;
140 1.1 gdamore
141 1.1 gdamore /*
142 1.1 gdamore * Bluetooth spec says that a device can accept one
143 1.1 gdamore * command on power up until they send a Command Status
144 1.1 gdamore * or Command Complete event with more information, but
145 1.1 gdamore * it seems that some devices cant and prefer to send a
146 1.8 plunky * No-op Command Status packet when they are ready.
147 1.1 gdamore */
148 1.8 plunky unit->hci_num_cmd_pkts = (unit->hci_flags & BTF_POWER_UP_NOOP) ? 0 : 1;
149 1.1 gdamore unit->hci_num_acl_pkts = 0;
150 1.1 gdamore unit->hci_num_sco_pkts = 0;
151 1.1 gdamore
152 1.1 gdamore /*
153 1.1 gdamore * only allow the basic packet types until
154 1.1 gdamore * the features report is in
155 1.1 gdamore */
156 1.1 gdamore unit->hci_acl_mask = HCI_PKT_DM1 | HCI_PKT_DH1;
157 1.1 gdamore unit->hci_packet_type = unit->hci_acl_mask;
158 1.1 gdamore
159 1.8.6.1 bouyer memcpy(unit->hci_cmds, hci_cmds_v10, HCI_COMMANDS_SIZE);
160 1.8.6.1 bouyer
161 1.5 ad unit->hci_rxint = softint_establish(SOFTINT_NET, &hci_intr, unit);
162 1.1 gdamore if (unit->hci_rxint == NULL)
163 1.1 gdamore return EIO;
164 1.1 gdamore
165 1.8 plunky err = (*unit->hci_if->enable)(unit->hci_dev);
166 1.1 gdamore if (err)
167 1.1 gdamore goto bad1;
168 1.1 gdamore
169 1.8 plunky unit->hci_flags |= BTF_RUNNING;
170 1.8 plunky
171 1.1 gdamore /*
172 1.1 gdamore * Reset the device, this will trigger initialisation
173 1.1 gdamore * and wake us up.
174 1.1 gdamore */
175 1.1 gdamore unit->hci_flags |= BTF_INIT;
176 1.1 gdamore
177 1.1 gdamore err = hci_send_cmd(unit, HCI_CMD_RESET, NULL, 0);
178 1.1 gdamore if (err)
179 1.1 gdamore goto bad2;
180 1.1 gdamore
181 1.1 gdamore while (unit->hci_flags & BTF_INIT) {
182 1.2 gdamore err = tsleep(unit, PWAIT | PCATCH, __func__, 5 * hz);
183 1.1 gdamore if (err)
184 1.1 gdamore goto bad2;
185 1.1 gdamore
186 1.1 gdamore /* XXX
187 1.1 gdamore * "What If", while we were sleeping, the device
188 1.1 gdamore * was removed and detached? Ho Hum.
189 1.1 gdamore */
190 1.1 gdamore }
191 1.1 gdamore
192 1.3 plunky /*
193 1.3 plunky * Attach Bluetooth Device Hub
194 1.3 plunky */
195 1.7 plunky unit->hci_bthub = config_found_ia(unit->hci_dev,
196 1.3 plunky "btbus", &unit->hci_bdaddr, NULL);
197 1.3 plunky
198 1.1 gdamore return 0;
199 1.1 gdamore
200 1.1 gdamore bad2:
201 1.8 plunky (*unit->hci_if->disable)(unit->hci_dev);
202 1.8 plunky unit->hci_flags &= ~BTF_RUNNING;
203 1.1 gdamore bad1:
204 1.5 ad softint_disestablish(unit->hci_rxint);
205 1.1 gdamore unit->hci_rxint = NULL;
206 1.1 gdamore
207 1.1 gdamore return err;
208 1.1 gdamore }
209 1.1 gdamore
210 1.1 gdamore void
211 1.1 gdamore hci_disable(struct hci_unit *unit)
212 1.1 gdamore {
213 1.1 gdamore struct hci_link *link, *next;
214 1.1 gdamore struct hci_memo *memo;
215 1.8 plunky int acl;
216 1.1 gdamore
217 1.3 plunky if (unit->hci_bthub) {
218 1.3 plunky config_detach(unit->hci_bthub, DETACH_FORCE);
219 1.3 plunky unit->hci_bthub = NULL;
220 1.3 plunky }
221 1.3 plunky
222 1.1 gdamore if (unit->hci_rxint) {
223 1.5 ad softint_disestablish(unit->hci_rxint);
224 1.1 gdamore unit->hci_rxint = NULL;
225 1.1 gdamore }
226 1.1 gdamore
227 1.8 plunky (*unit->hci_if->disable)(unit->hci_dev);
228 1.8 plunky unit->hci_flags &= ~BTF_RUNNING;
229 1.1 gdamore
230 1.1 gdamore /*
231 1.1 gdamore * close down any links, take care to close SCO first since
232 1.1 gdamore * they may depend on ACL links.
233 1.1 gdamore */
234 1.1 gdamore for (acl = 0 ; acl < 2 ; acl++) {
235 1.1 gdamore next = TAILQ_FIRST(&unit->hci_links);
236 1.1 gdamore while ((link = next) != NULL) {
237 1.1 gdamore next = TAILQ_NEXT(link, hl_next);
238 1.1 gdamore if (acl || link->hl_type != HCI_LINK_ACL)
239 1.1 gdamore hci_link_free(link, ECONNABORTED);
240 1.1 gdamore }
241 1.1 gdamore }
242 1.1 gdamore
243 1.1 gdamore while ((memo = LIST_FIRST(&unit->hci_memos)) != NULL)
244 1.1 gdamore hci_memo_free(memo);
245 1.1 gdamore
246 1.8 plunky /* (no need to hold hci_devlock, the driver is disabled) */
247 1.8 plunky
248 1.1 gdamore MBUFQ_DRAIN(&unit->hci_eventq);
249 1.1 gdamore unit->hci_eventqlen = 0;
250 1.1 gdamore
251 1.1 gdamore MBUFQ_DRAIN(&unit->hci_aclrxq);
252 1.1 gdamore unit->hci_aclrxqlen = 0;
253 1.1 gdamore
254 1.1 gdamore MBUFQ_DRAIN(&unit->hci_scorxq);
255 1.1 gdamore unit->hci_scorxqlen = 0;
256 1.1 gdamore
257 1.1 gdamore MBUFQ_DRAIN(&unit->hci_cmdwait);
258 1.1 gdamore MBUFQ_DRAIN(&unit->hci_scodone);
259 1.1 gdamore }
260 1.1 gdamore
261 1.1 gdamore struct hci_unit *
262 1.1 gdamore hci_unit_lookup(bdaddr_t *addr)
263 1.1 gdamore {
264 1.1 gdamore struct hci_unit *unit;
265 1.1 gdamore
266 1.1 gdamore SIMPLEQ_FOREACH(unit, &hci_unit_list, hci_next) {
267 1.1 gdamore if ((unit->hci_flags & BTF_UP) == 0)
268 1.1 gdamore continue;
269 1.1 gdamore
270 1.1 gdamore if (bdaddr_same(&unit->hci_bdaddr, addr))
271 1.1 gdamore break;
272 1.1 gdamore }
273 1.1 gdamore
274 1.1 gdamore return unit;
275 1.1 gdamore }
276 1.1 gdamore
277 1.1 gdamore /*
278 1.1 gdamore * construct and queue a HCI command packet
279 1.1 gdamore */
280 1.1 gdamore int
281 1.1 gdamore hci_send_cmd(struct hci_unit *unit, uint16_t opcode, void *buf, uint8_t len)
282 1.1 gdamore {
283 1.1 gdamore struct mbuf *m;
284 1.1 gdamore hci_cmd_hdr_t *p;
285 1.1 gdamore
286 1.4 plunky KASSERT(unit != NULL);
287 1.1 gdamore
288 1.1 gdamore m = m_gethdr(M_DONTWAIT, MT_DATA);
289 1.1 gdamore if (m == NULL)
290 1.1 gdamore return ENOMEM;
291 1.1 gdamore
292 1.1 gdamore p = mtod(m, hci_cmd_hdr_t *);
293 1.1 gdamore p->type = HCI_CMD_PKT;
294 1.1 gdamore p->opcode = htole16(opcode);
295 1.1 gdamore p->length = len;
296 1.1 gdamore m->m_pkthdr.len = m->m_len = sizeof(hci_cmd_hdr_t);
297 1.1 gdamore
298 1.1 gdamore if (len) {
299 1.4 plunky KASSERT(buf != NULL);
300 1.1 gdamore
301 1.1 gdamore m_copyback(m, sizeof(hci_cmd_hdr_t), len, buf);
302 1.1 gdamore if (m->m_pkthdr.len != (sizeof(hci_cmd_hdr_t) + len)) {
303 1.1 gdamore m_freem(m);
304 1.1 gdamore return ENOMEM;
305 1.1 gdamore }
306 1.1 gdamore }
307 1.1 gdamore
308 1.7 plunky DPRINTFN(2, "(%s) opcode (%3.3x|%4.4x)\n", device_xname(unit->hci_dev),
309 1.1 gdamore HCI_OGF(opcode), HCI_OCF(opcode));
310 1.1 gdamore
311 1.1 gdamore /* and send it on */
312 1.1 gdamore if (unit->hci_num_cmd_pkts == 0)
313 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_cmdwait, m);
314 1.1 gdamore else
315 1.1 gdamore hci_output_cmd(unit, m);
316 1.1 gdamore
317 1.1 gdamore return 0;
318 1.1 gdamore }
319 1.1 gdamore
320 1.1 gdamore /*
321 1.1 gdamore * Incoming packet processing. Since the code is single threaded
322 1.1 gdamore * in any case (IPL_SOFTNET), we handle it all in one interrupt function
323 1.1 gdamore * picking our way through more important packets first so that hopefully
324 1.1 gdamore * we will never get clogged up with bulk data.
325 1.1 gdamore */
326 1.1 gdamore static void
327 1.1 gdamore hci_intr(void *arg)
328 1.1 gdamore {
329 1.1 gdamore struct hci_unit *unit = arg;
330 1.1 gdamore struct mbuf *m;
331 1.1 gdamore
332 1.1 gdamore another:
333 1.8 plunky mutex_enter(&unit->hci_devlock);
334 1.1 gdamore
335 1.1 gdamore if (unit->hci_eventqlen > 0) {
336 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_eventq, m);
337 1.1 gdamore unit->hci_eventqlen--;
338 1.8 plunky mutex_exit(&unit->hci_devlock);
339 1.8 plunky
340 1.1 gdamore KASSERT(m != NULL);
341 1.1 gdamore
342 1.1 gdamore DPRINTFN(10, "(%s) recv event, len = %d\n",
343 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
344 1.1 gdamore
345 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
346 1.1 gdamore hci_mtap(m, unit);
347 1.1 gdamore hci_event(m, unit);
348 1.1 gdamore
349 1.1 gdamore goto another;
350 1.1 gdamore }
351 1.1 gdamore
352 1.1 gdamore if (unit->hci_scorxqlen > 0) {
353 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_scorxq, m);
354 1.1 gdamore unit->hci_scorxqlen--;
355 1.8 plunky mutex_exit(&unit->hci_devlock);
356 1.8 plunky
357 1.1 gdamore KASSERT(m != NULL);
358 1.1 gdamore
359 1.1 gdamore DPRINTFN(10, "(%s) recv SCO, len = %d\n",
360 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
361 1.1 gdamore
362 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
363 1.1 gdamore hci_mtap(m, unit);
364 1.1 gdamore hci_sco_recv(m, unit);
365 1.1 gdamore
366 1.1 gdamore goto another;
367 1.1 gdamore }
368 1.1 gdamore
369 1.1 gdamore if (unit->hci_aclrxqlen > 0) {
370 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_aclrxq, m);
371 1.1 gdamore unit->hci_aclrxqlen--;
372 1.8 plunky mutex_exit(&unit->hci_devlock);
373 1.8 plunky
374 1.1 gdamore KASSERT(m != NULL);
375 1.1 gdamore
376 1.1 gdamore DPRINTFN(10, "(%s) recv ACL, len = %d\n",
377 1.7 plunky device_xname(unit->hci_dev), m->m_pkthdr.len);
378 1.1 gdamore
379 1.1 gdamore m->m_flags |= M_LINK0; /* mark incoming packet */
380 1.1 gdamore hci_mtap(m, unit);
381 1.1 gdamore hci_acl_recv(m, unit);
382 1.1 gdamore
383 1.1 gdamore goto another;
384 1.1 gdamore }
385 1.1 gdamore
386 1.1 gdamore MBUFQ_DEQUEUE(&unit->hci_scodone, m);
387 1.1 gdamore if (m != NULL) {
388 1.1 gdamore struct hci_link *link;
389 1.8 plunky
390 1.8 plunky mutex_exit(&unit->hci_devlock);
391 1.1 gdamore
392 1.1 gdamore DPRINTFN(11, "(%s) complete SCO\n",
393 1.7 plunky device_xname(unit->hci_dev));
394 1.1 gdamore
395 1.1 gdamore TAILQ_FOREACH(link, &unit->hci_links, hl_next) {
396 1.1 gdamore if (link == M_GETCTX(m, struct hci_link *)) {
397 1.1 gdamore hci_sco_complete(link, 1);
398 1.1 gdamore break;
399 1.1 gdamore }
400 1.1 gdamore }
401 1.1 gdamore
402 1.1 gdamore unit->hci_num_sco_pkts++;
403 1.1 gdamore m_freem(m);
404 1.1 gdamore
405 1.1 gdamore goto another;
406 1.1 gdamore }
407 1.1 gdamore
408 1.8 plunky mutex_exit(&unit->hci_devlock);
409 1.1 gdamore
410 1.1 gdamore DPRINTFN(10, "done\n");
411 1.1 gdamore }
412 1.1 gdamore
413 1.1 gdamore /**********************************************************************
414 1.1 gdamore *
415 1.1 gdamore * IO routines
416 1.1 gdamore *
417 1.8 plunky * input & complete routines will be called from device drivers,
418 1.8 plunky * possibly in interrupt context. We return success or failure to
419 1.8 plunky * enable proper accounting but we own the mbuf.
420 1.1 gdamore */
421 1.1 gdamore
422 1.8 plunky bool
423 1.1 gdamore hci_input_event(struct hci_unit *unit, struct mbuf *m)
424 1.1 gdamore {
425 1.8 plunky bool rv;
426 1.8 plunky
427 1.8 plunky mutex_enter(&unit->hci_devlock);
428 1.1 gdamore
429 1.1 gdamore if (unit->hci_eventqlen > hci_eventq_max || unit->hci_rxint == NULL) {
430 1.7 plunky DPRINTF("(%s) dropped event packet.\n", device_xname(unit->hci_dev));
431 1.1 gdamore m_freem(m);
432 1.8 plunky rv = false;
433 1.1 gdamore } else {
434 1.1 gdamore unit->hci_eventqlen++;
435 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_eventq, m);
436 1.5 ad softint_schedule(unit->hci_rxint);
437 1.8 plunky rv = true;
438 1.1 gdamore }
439 1.8 plunky
440 1.8 plunky mutex_exit(&unit->hci_devlock);
441 1.8 plunky return rv;
442 1.1 gdamore }
443 1.1 gdamore
444 1.8 plunky bool
445 1.1 gdamore hci_input_acl(struct hci_unit *unit, struct mbuf *m)
446 1.1 gdamore {
447 1.8 plunky bool rv;
448 1.8 plunky
449 1.8 plunky mutex_enter(&unit->hci_devlock);
450 1.1 gdamore
451 1.1 gdamore if (unit->hci_aclrxqlen > hci_aclrxq_max || unit->hci_rxint == NULL) {
452 1.7 plunky DPRINTF("(%s) dropped ACL packet.\n", device_xname(unit->hci_dev));
453 1.1 gdamore m_freem(m);
454 1.8 plunky rv = false;
455 1.1 gdamore } else {
456 1.1 gdamore unit->hci_aclrxqlen++;
457 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_aclrxq, m);
458 1.5 ad softint_schedule(unit->hci_rxint);
459 1.8 plunky rv = true;
460 1.1 gdamore }
461 1.8 plunky
462 1.8 plunky mutex_exit(&unit->hci_devlock);
463 1.8 plunky return rv;
464 1.1 gdamore }
465 1.1 gdamore
466 1.8 plunky bool
467 1.1 gdamore hci_input_sco(struct hci_unit *unit, struct mbuf *m)
468 1.1 gdamore {
469 1.8 plunky bool rv;
470 1.8 plunky
471 1.8 plunky mutex_enter(&unit->hci_devlock);
472 1.1 gdamore
473 1.1 gdamore if (unit->hci_scorxqlen > hci_scorxq_max || unit->hci_rxint == NULL) {
474 1.7 plunky DPRINTF("(%s) dropped SCO packet.\n", device_xname(unit->hci_dev));
475 1.1 gdamore m_freem(m);
476 1.8 plunky rv = false;
477 1.1 gdamore } else {
478 1.1 gdamore unit->hci_scorxqlen++;
479 1.1 gdamore MBUFQ_ENQUEUE(&unit->hci_scorxq, m);
480 1.5 ad softint_schedule(unit->hci_rxint);
481 1.8 plunky rv = true;
482 1.1 gdamore }
483 1.8 plunky
484 1.8 plunky mutex_exit(&unit->hci_devlock);
485 1.8 plunky return rv;
486 1.1 gdamore }
487 1.1 gdamore
488 1.1 gdamore void
489 1.1 gdamore hci_output_cmd(struct hci_unit *unit, struct mbuf *m)
490 1.1 gdamore {
491 1.1 gdamore void *arg;
492 1.1 gdamore
493 1.1 gdamore hci_mtap(m, unit);
494 1.1 gdamore
495 1.7 plunky DPRINTFN(10, "(%s) num_cmd_pkts=%d\n", device_xname(unit->hci_dev),
496 1.1 gdamore unit->hci_num_cmd_pkts);
497 1.1 gdamore
498 1.1 gdamore unit->hci_num_cmd_pkts--;
499 1.1 gdamore
500 1.1 gdamore /*
501 1.1 gdamore * If context is set, this was from a HCI raw socket
502 1.1 gdamore * and a record needs to be dropped from the sockbuf.
503 1.1 gdamore */
504 1.1 gdamore arg = M_GETCTX(m, void *);
505 1.1 gdamore if (arg != NULL)
506 1.1 gdamore hci_drop(arg);
507 1.1 gdamore
508 1.8 plunky (*unit->hci_if->output_cmd)(unit->hci_dev, m);
509 1.1 gdamore }
510 1.1 gdamore
511 1.1 gdamore void
512 1.1 gdamore hci_output_acl(struct hci_unit *unit, struct mbuf *m)
513 1.1 gdamore {
514 1.1 gdamore
515 1.1 gdamore hci_mtap(m, unit);
516 1.1 gdamore
517 1.7 plunky DPRINTFN(10, "(%s) num_acl_pkts=%d\n", device_xname(unit->hci_dev),
518 1.1 gdamore unit->hci_num_acl_pkts);
519 1.1 gdamore
520 1.1 gdamore unit->hci_num_acl_pkts--;
521 1.8 plunky (*unit->hci_if->output_acl)(unit->hci_dev, m);
522 1.1 gdamore }
523 1.1 gdamore
524 1.1 gdamore void
525 1.1 gdamore hci_output_sco(struct hci_unit *unit, struct mbuf *m)
526 1.1 gdamore {
527 1.1 gdamore
528 1.1 gdamore hci_mtap(m, unit);
529 1.1 gdamore
530 1.7 plunky DPRINTFN(10, "(%s) num_sco_pkts=%d\n", device_xname(unit->hci_dev),
531 1.1 gdamore unit->hci_num_sco_pkts);
532 1.1 gdamore
533 1.1 gdamore unit->hci_num_sco_pkts--;
534 1.8 plunky (*unit->hci_if->output_sco)(unit->hci_dev, m);
535 1.1 gdamore }
536 1.1 gdamore
537 1.8 plunky bool
538 1.1 gdamore hci_complete_sco(struct hci_unit *unit, struct mbuf *m)
539 1.1 gdamore {
540 1.1 gdamore
541 1.1 gdamore if (unit->hci_rxint == NULL) {
542 1.7 plunky DPRINTFN(10, "(%s) complete SCO!\n", device_xname(unit->hci_dev));
543 1.1 gdamore m_freem(m);
544 1.8 plunky return false;
545 1.1 gdamore }
546 1.8 plunky
547 1.8 plunky mutex_enter(&unit->hci_devlock);
548 1.8 plunky
549 1.8 plunky MBUFQ_ENQUEUE(&unit->hci_scodone, m);
550 1.8 plunky softint_schedule(unit->hci_rxint);
551 1.8 plunky
552 1.8 plunky mutex_exit(&unit->hci_devlock);
553 1.8 plunky return true;
554 1.1 gdamore }
555