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