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