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