1 /* $NetBSD: btuart.c,v 1.28 2015/08/20 14:40:17 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2006, 2007 KIYOHARA Takashi 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: btuart.c,v 1.28 2015/08/20 14:40:17 christos Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/conf.h> 34 #include <sys/device.h> 35 #include <sys/errno.h> 36 #include <sys/fcntl.h> 37 #include <sys/kauth.h> 38 #include <sys/kernel.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/proc.h> 42 #include <sys/syslimits.h> 43 #include <sys/systm.h> 44 #include <sys/tty.h> 45 46 #include <sys/bus.h> 47 #include <sys/intr.h> 48 49 #include <netbt/bluetooth.h> 50 #include <netbt/hci.h> 51 52 #include "ioconf.h" 53 54 struct btuart_softc { 55 device_t sc_dev; 56 struct tty * sc_tp; /* tty pointer */ 57 58 bool sc_enabled; /* device is enabled */ 59 struct hci_unit *sc_unit; /* Bluetooth HCI handle */ 60 struct bt_stats sc_stats; 61 62 int sc_state; /* receive state */ 63 int sc_want; /* how much we want */ 64 struct mbuf * sc_rxp; /* incoming packet */ 65 66 bool sc_xmit; /* transmit is active */ 67 struct mbuf * sc_txp; /* outgoing packet */ 68 69 /* transmit queues */ 70 MBUFQ_HEAD() sc_cmdq; 71 MBUFQ_HEAD() sc_aclq; 72 MBUFQ_HEAD() sc_scoq; 73 }; 74 75 /* sc_state */ 76 #define BTUART_RECV_PKT_TYPE 0 /* packet type */ 77 #define BTUART_RECV_ACL_HDR 1 /* acl header */ 78 #define BTUART_RECV_SCO_HDR 2 /* sco header */ 79 #define BTUART_RECV_EVENT_HDR 3 /* event header */ 80 #define BTUART_RECV_ACL_DATA 4 /* acl packet data */ 81 #define BTUART_RECV_SCO_DATA 5 /* sco packet data */ 82 #define BTUART_RECV_EVENT_DATA 6 /* event packet data */ 83 84 static int btuart_match(device_t, cfdata_t, void *); 85 static void btuart_attach(device_t, device_t, void *); 86 static int btuart_detach(device_t, int); 87 88 static int btuartopen(dev_t, struct tty *); 89 static int btuartclose(struct tty *, int); 90 static int btuartioctl(struct tty *, u_long, void *, int, struct lwp *); 91 static int btuartinput(int, struct tty *); 92 static int btuartstart(struct tty *); 93 94 static int btuart_enable(device_t); 95 static void btuart_disable(device_t); 96 static void btuart_output_cmd(device_t, struct mbuf *); 97 static void btuart_output_acl(device_t, struct mbuf *); 98 static void btuart_output_sco(device_t, struct mbuf *); 99 static void btuart_stats(device_t, struct bt_stats *, int); 100 101 /* 102 * It doesn't need to be exported, as only btuartattach() uses it, 103 * but there's no "official" way to make it static. 104 */ 105 CFATTACH_DECL_NEW(btuart, sizeof(struct btuart_softc), 106 btuart_match, btuart_attach, btuart_detach, NULL); 107 108 static struct linesw btuart_disc = { 109 .l_name = "btuart", 110 .l_open = btuartopen, 111 .l_close = btuartclose, 112 .l_read = ttyerrio, 113 .l_write = ttyerrio, 114 .l_ioctl = btuartioctl, 115 .l_rint = btuartinput, 116 .l_start = btuartstart, 117 .l_modem = ttymodem, 118 .l_poll = ttyerrpoll, 119 }; 120 121 static const struct hci_if btuart_hci = { 122 .enable = btuart_enable, 123 .disable = btuart_disable, 124 .output_cmd = btuart_output_cmd, 125 .output_acl = btuart_output_acl, 126 .output_sco = btuart_output_sco, 127 .get_stats = btuart_stats, 128 .ipl = IPL_TTY, 129 }; 130 131 /***************************************************************************** 132 * 133 * autoconf(9) functions 134 */ 135 136 /* 137 * pseudo-device attach routine. 138 */ 139 void 140 btuartattach(int num __unused) 141 { 142 int error; 143 144 error = ttyldisc_attach(&btuart_disc); 145 if (error) { 146 aprint_error("%s: unable to register line discipline, " 147 "error = %d\n", btuart_cd.cd_name, error); 148 149 return; 150 } 151 152 error = config_cfattach_attach(btuart_cd.cd_name, &btuart_ca); 153 if (error) { 154 aprint_error("%s: unable to register cfattach, error = %d\n", 155 btuart_cd.cd_name, error); 156 157 config_cfdriver_detach(&btuart_cd); 158 (void) ttyldisc_detach(&btuart_disc); 159 } 160 } 161 162 /* 163 * Autoconf match routine. 164 */ 165 static int 166 btuart_match(device_t self __unused, cfdata_t cfdata __unused, 167 void *arg __unused) 168 { 169 170 /* pseudo-device; always present */ 171 return 1; 172 } 173 174 /* 175 * Autoconf attach routine. 176 * Called by config_attach_pseudo(9) when we open the line discipline. 177 */ 178 static void 179 btuart_attach(device_t parent __unused, device_t self, void *aux __unused) 180 { 181 struct btuart_softc *sc = device_private(self); 182 183 sc->sc_dev = self; 184 185 MBUFQ_INIT(&sc->sc_cmdq); 186 MBUFQ_INIT(&sc->sc_aclq); 187 MBUFQ_INIT(&sc->sc_scoq); 188 189 /* Attach Bluetooth unit */ 190 sc->sc_unit = hci_attach_pcb(&btuart_hci, self, 0); 191 if (sc->sc_unit == NULL) 192 aprint_error_dev(self, "HCI attach failed\n"); 193 } 194 195 /* 196 * Autoconf detach routine. 197 * Called when we close the line discipline. 198 */ 199 static int 200 btuart_detach(device_t self, int flags __unused) 201 { 202 struct btuart_softc *sc = device_private(self); 203 204 btuart_disable(self); 205 206 if (sc->sc_unit) { 207 hci_detach_pcb(sc->sc_unit); 208 sc->sc_unit = NULL; 209 } 210 211 return 0; 212 } 213 214 /***************************************************************************** 215 * 216 * Line discipline functions. 217 */ 218 219 static int 220 btuartopen(dev_t devno __unused, struct tty *tp) 221 { 222 struct btuart_softc *sc; 223 device_t dev; 224 cfdata_t cfdata; 225 struct lwp *l = curlwp; /* XXX */ 226 int error, unit, s; 227 228 error = kauth_authorize_device(l->l_cred, KAUTH_DEVICE_BLUETOOTH_BTUART, 229 KAUTH_ARG(KAUTH_REQ_DEVICE_BLUETOOTH_BTUART_ADD), NULL, NULL, NULL); 230 if (error) 231 return (error); 232 233 s = spltty(); 234 235 if (tp->t_linesw == &btuart_disc) { 236 sc = tp->t_sc; 237 if (sc != NULL) { 238 splx(s); 239 return EBUSY; 240 } 241 } 242 243 KASSERT(tp->t_oproc != NULL); 244 245 cfdata = malloc(sizeof(struct cfdata), M_DEVBUF, M_WAITOK); 246 for (unit = 0; unit < btuart_cd.cd_ndevs; unit++) 247 if (device_lookup(&btuart_cd, unit) == NULL) 248 break; 249 250 cfdata->cf_name = btuart_cd.cd_name; 251 cfdata->cf_atname = btuart_cd.cd_name; 252 cfdata->cf_unit = unit; 253 cfdata->cf_fstate = FSTATE_STAR; 254 255 dev = config_attach_pseudo(cfdata); 256 if (dev == NULL) { 257 free(cfdata, M_DEVBUF); 258 splx(s); 259 return EIO; 260 } 261 sc = device_private(dev); 262 263 aprint_normal_dev(dev, "major %llu minor %llu\n", 264 (unsigned long long)major(tp->t_dev), 265 (unsigned long long)minor(tp->t_dev)); 266 267 sc->sc_tp = tp; 268 tp->t_sc = sc; 269 270 mutex_spin_enter(&tty_lock); 271 ttyflush(tp, FREAD | FWRITE); 272 mutex_spin_exit(&tty_lock); 273 274 splx(s); 275 276 return 0; 277 } 278 279 static int 280 btuartclose(struct tty *tp, int flag __unused) 281 { 282 struct btuart_softc *sc = tp->t_sc; 283 cfdata_t cfdata; 284 int s; 285 286 s = spltty(); 287 288 mutex_spin_enter(&tty_lock); 289 ttyflush(tp, FREAD | FWRITE); 290 mutex_spin_exit(&tty_lock); /* XXX */ 291 292 ttyldisc_release(tp->t_linesw); 293 tp->t_linesw = ttyldisc_default(); 294 295 if (sc != NULL) { 296 tp->t_sc = NULL; 297 if (sc->sc_tp == tp) { 298 cfdata = device_cfdata(sc->sc_dev); 299 config_detach(sc->sc_dev, 0); 300 free(cfdata, M_DEVBUF); 301 } 302 } 303 304 splx(s); 305 306 return 0; 307 } 308 309 static int 310 btuartioctl(struct tty *tp, u_long cmd, void *data __unused, 311 int flag __unused, struct lwp *l __unused) 312 { 313 struct btuart_softc *sc = tp->t_sc; 314 int error; 315 316 if (sc == NULL || tp != sc->sc_tp) 317 return EPASSTHROUGH; 318 319 switch(cmd) { 320 default: 321 error = EPASSTHROUGH; 322 break; 323 } 324 325 return error; 326 } 327 328 static int 329 btuartinput(int c, struct tty *tp) 330 { 331 struct btuart_softc *sc = tp->t_sc; 332 struct mbuf *m = sc->sc_rxp; 333 int space = 0; 334 335 if (!sc->sc_enabled) 336 return 0; 337 338 c &= TTY_CHARMASK; 339 340 /* If we already started a packet, find the trailing end of it. */ 341 if (m) { 342 while (m->m_next) 343 m = m->m_next; 344 345 space = M_TRAILINGSPACE(m); 346 } 347 348 if (space == 0) { 349 if (m == NULL) { 350 /* new packet */ 351 MGETHDR(m, M_DONTWAIT, MT_DATA); 352 if (m == NULL) { 353 aprint_error_dev(sc->sc_dev, "out of memory\n"); 354 sc->sc_stats.err_rx++; 355 return 0; /* (lost sync) */ 356 } 357 358 sc->sc_rxp = m; 359 m->m_pkthdr.len = m->m_len = 0; 360 space = MHLEN; 361 362 sc->sc_state = BTUART_RECV_PKT_TYPE; 363 sc->sc_want = 1; 364 } else { 365 /* extend mbuf */ 366 MGET(m->m_next, M_DONTWAIT, MT_DATA); 367 if (m->m_next == NULL) { 368 aprint_error_dev(sc->sc_dev, "out of memory\n"); 369 sc->sc_stats.err_rx++; 370 return 0; /* (lost sync) */ 371 } 372 373 m = m->m_next; 374 m->m_len = 0; 375 space = MLEN; 376 377 if (sc->sc_want > MINCLSIZE) { 378 MCLGET(m, M_DONTWAIT); 379 if (m->m_flags & M_EXT) 380 space = MCLBYTES; 381 } 382 } 383 } 384 385 mtod(m, uint8_t *)[m->m_len++] = c; 386 sc->sc_rxp->m_pkthdr.len++; 387 sc->sc_stats.byte_rx++; 388 389 sc->sc_want--; 390 if (sc->sc_want > 0) 391 return 0; /* want more */ 392 393 switch (sc->sc_state) { 394 case BTUART_RECV_PKT_TYPE: /* Got packet type */ 395 396 switch (c) { 397 case HCI_ACL_DATA_PKT: 398 sc->sc_state = BTUART_RECV_ACL_HDR; 399 sc->sc_want = sizeof(hci_acldata_hdr_t) - 1; 400 break; 401 402 case HCI_SCO_DATA_PKT: 403 sc->sc_state = BTUART_RECV_SCO_HDR; 404 sc->sc_want = sizeof(hci_scodata_hdr_t) - 1; 405 break; 406 407 case HCI_EVENT_PKT: 408 sc->sc_state = BTUART_RECV_EVENT_HDR; 409 sc->sc_want = sizeof(hci_event_hdr_t) - 1; 410 break; 411 412 default: 413 aprint_error_dev(sc->sc_dev, 414 "Unknown packet type=%#x!\n", c); 415 sc->sc_stats.err_rx++; 416 m_freem(sc->sc_rxp); 417 sc->sc_rxp = NULL; 418 return 0; /* (lost sync) */ 419 } 420 421 break; 422 423 /* 424 * we assume (correctly of course :) that the packet headers all fit 425 * into a single pkthdr mbuf 426 */ 427 case BTUART_RECV_ACL_HDR: /* Got ACL Header */ 428 sc->sc_state = BTUART_RECV_ACL_DATA; 429 sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length; 430 sc->sc_want = le16toh(sc->sc_want); 431 break; 432 433 case BTUART_RECV_SCO_HDR: /* Got SCO Header */ 434 sc->sc_state = BTUART_RECV_SCO_DATA; 435 sc->sc_want = mtod(m, hci_scodata_hdr_t *)->length; 436 break; 437 438 case BTUART_RECV_EVENT_HDR: /* Got Event Header */ 439 sc->sc_state = BTUART_RECV_EVENT_DATA; 440 sc->sc_want = mtod(m, hci_event_hdr_t *)->length; 441 break; 442 443 case BTUART_RECV_ACL_DATA: /* ACL Packet Complete */ 444 if (!hci_input_acl(sc->sc_unit, sc->sc_rxp)) 445 sc->sc_stats.err_rx++; 446 447 sc->sc_stats.acl_rx++; 448 sc->sc_rxp = m = NULL; 449 break; 450 451 case BTUART_RECV_SCO_DATA: /* SCO Packet Complete */ 452 if (!hci_input_sco(sc->sc_unit, sc->sc_rxp)) 453 sc->sc_stats.err_rx++; 454 455 sc->sc_stats.sco_rx++; 456 sc->sc_rxp = m = NULL; 457 break; 458 459 case BTUART_RECV_EVENT_DATA: /* Event Packet Complete */ 460 if (!hci_input_event(sc->sc_unit, sc->sc_rxp)) 461 sc->sc_stats.err_rx++; 462 463 sc->sc_stats.evt_rx++; 464 sc->sc_rxp = m = NULL; 465 break; 466 467 default: 468 panic("%s: invalid state %d!\n", 469 device_xname(sc->sc_dev), sc->sc_state); 470 } 471 472 return 0; 473 } 474 475 static int 476 btuartstart(struct tty *tp) 477 { 478 struct btuart_softc *sc = tp->t_sc; 479 struct mbuf *m; 480 int count, rlen; 481 uint8_t *rptr; 482 483 if (!sc->sc_enabled) 484 return 0; 485 486 m = sc->sc_txp; 487 if (m == NULL) { 488 if (MBUFQ_FIRST(&sc->sc_cmdq)) { 489 MBUFQ_DEQUEUE(&sc->sc_cmdq, m); 490 sc->sc_stats.cmd_tx++; 491 } else if (MBUFQ_FIRST(&sc->sc_scoq)) { 492 MBUFQ_DEQUEUE(&sc->sc_scoq, m); 493 sc->sc_stats.sco_tx++; 494 } else if (MBUFQ_FIRST(&sc->sc_aclq)) { 495 MBUFQ_DEQUEUE(&sc->sc_aclq, m); 496 sc->sc_stats.acl_tx++; 497 } else { 498 sc->sc_xmit = false; 499 return 0; /* no more to send */ 500 } 501 502 sc->sc_txp = m; 503 sc->sc_xmit = true; 504 } 505 506 count = 0; 507 rlen = 0; 508 rptr = mtod(m, uint8_t *); 509 510 for(;;) { 511 if (rlen >= m->m_len) { 512 m = m->m_next; 513 if (m == NULL) { 514 m = sc->sc_txp; 515 sc->sc_txp = NULL; 516 517 if (M_GETCTX(m, void *) == NULL) 518 m_freem(m); 519 else if (!hci_complete_sco(sc->sc_unit, m)) 520 sc->sc_stats.err_tx++; 521 522 break; 523 } 524 525 rlen = 0; 526 rptr = mtod(m, uint8_t *); 527 continue; 528 } 529 530 if (putc(*rptr++, &tp->t_outq) < 0) { 531 m_adj(m, rlen); 532 break; 533 } 534 rlen++; 535 count++; 536 } 537 538 sc->sc_stats.byte_tx += count; 539 540 if (tp->t_outq.c_cc != 0) 541 (*tp->t_oproc)(tp); 542 543 return 0; 544 } 545 546 /***************************************************************************** 547 * 548 * bluetooth(9) functions 549 */ 550 551 static int 552 btuart_enable(device_t self) 553 { 554 struct btuart_softc *sc = device_private(self); 555 int s; 556 557 if (sc->sc_enabled) 558 return 0; 559 560 s = spltty(); 561 562 sc->sc_enabled = true; 563 sc->sc_xmit = false; 564 565 splx(s); 566 567 return 0; 568 } 569 570 static void 571 btuart_disable(device_t self) 572 { 573 struct btuart_softc *sc = device_private(self); 574 int s; 575 576 if (!sc->sc_enabled) 577 return; 578 579 s = spltty(); 580 581 if (sc->sc_rxp) { 582 m_freem(sc->sc_rxp); 583 sc->sc_rxp = NULL; 584 } 585 586 if (sc->sc_txp) { 587 m_freem(sc->sc_txp); 588 sc->sc_txp = NULL; 589 } 590 591 MBUFQ_DRAIN(&sc->sc_cmdq); 592 MBUFQ_DRAIN(&sc->sc_aclq); 593 MBUFQ_DRAIN(&sc->sc_scoq); 594 595 sc->sc_enabled = false; 596 597 splx(s); 598 } 599 600 static void 601 btuart_output_cmd(device_t self, struct mbuf *m) 602 { 603 struct btuart_softc *sc = device_private(self); 604 int s; 605 606 KASSERT(sc->sc_enabled); 607 608 M_SETCTX(m, NULL); 609 610 s = spltty(); 611 MBUFQ_ENQUEUE(&sc->sc_cmdq, m); 612 if (!sc->sc_xmit) 613 btuartstart(sc->sc_tp); 614 615 splx(s); 616 } 617 618 static void 619 btuart_output_acl(device_t self, struct mbuf *m) 620 { 621 struct btuart_softc *sc = device_private(self); 622 int s; 623 624 KASSERT(sc->sc_enabled); 625 626 M_SETCTX(m, NULL); 627 628 s = spltty(); 629 MBUFQ_ENQUEUE(&sc->sc_aclq, m); 630 if (!sc->sc_xmit) 631 btuartstart(sc->sc_tp); 632 633 splx(s); 634 } 635 636 static void 637 btuart_output_sco(device_t self, struct mbuf *m) 638 { 639 struct btuart_softc *sc = device_private(self); 640 int s; 641 642 KASSERT(sc->sc_enabled); 643 644 s = spltty(); 645 MBUFQ_ENQUEUE(&sc->sc_scoq, m); 646 if (!sc->sc_xmit) 647 btuartstart(sc->sc_tp); 648 649 splx(s); 650 } 651 652 static void 653 btuart_stats(device_t self, struct bt_stats *dest, int flush) 654 { 655 struct btuart_softc *sc = device_private(self); 656 int s; 657 658 s = spltty(); 659 660 memcpy(dest, &sc->sc_stats, sizeof(struct bt_stats)); 661 662 if (flush) 663 memset(&sc->sc_stats, 0, sizeof(struct bt_stats)); 664 665 splx(s); 666 } 667