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