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