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