1 /* $NetBSD: btattach.c,v 1.15 2017/08/11 11:54:08 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 Iain Hibbert 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 WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __COPYRIGHT("@(#) Copyright (c) 2008 Iain Hibbert. All rights reserved."); 30 __RCSID("$NetBSD: btattach.c,v 1.15 2017/08/11 11:54:08 jmcneill Exp $"); 31 32 #include <sys/ioctl.h> 33 #include <sys/param.h> 34 #include <sys/uio.h> 35 36 #include <bluetooth.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <termios.h> 44 #include <unistd.h> 45 #include <util.h> 46 47 #include "btattach.h" 48 49 static void sighandler(int); 50 __dead static void usage(void); 51 static void test(const char *, tcflag_t, tcflag_t); 52 53 static int sigcount = 0; /* signals received */ 54 static int opt_debug = 0; /* global? */ 55 56 static const struct devtype types[] = { 57 { 58 .name = "bcm2035", 59 .line = "btuart", 60 .descr = "Broadcom BCM2035", 61 .init = &init_bcm2035, 62 .speed = B115200, 63 }, 64 { 65 .name = "bcm43xx", 66 .line = "btuart", 67 .descr = "Broadcom BCM43xx", 68 .init = &init_bcm43xx, 69 .speed = B115200, 70 }, 71 { 72 .name = "bcm43xx-3wire", 73 .line = "bth5", 74 .descr = "Broadcom BCM43xx (3-wire)", 75 .init = &init_bcm43xx, 76 .speed = B115200, 77 }, 78 { 79 .name = "bcsp", 80 .line = "bcsp", 81 .descr = "Generic BlueCore Serial Protocol", 82 .cflag = CRTSCTS | PARENB, 83 .speed = B57600, 84 }, 85 { 86 .name = "bgb2xx", 87 .line = "btuart", 88 .descr = "Philips BGB2xx module", 89 .init = &init_bgb2xx, 90 .cflag = CRTSCTS, 91 .speed = B115200, 92 }, 93 { 94 .name = "btuart", 95 .line = "btuart", 96 .descr = "Generic UART (the default)", 97 }, 98 { 99 .name = "csr", 100 .line = "btuart", 101 .descr = "Cambridge Silicon Radio based modules (not BCSP)", 102 .init = &init_csr, 103 .cflag = CRTSCTS, 104 .speed = B57600, 105 }, 106 { 107 .name = "digi", 108 .line = "btuart", 109 .descr = "Digianswer based cards", 110 .init = &init_digi, 111 .cflag = CRTSCTS, 112 .speed = B9600, 113 }, 114 { 115 .name = "ericsson", 116 .line = "btuart", 117 .descr = "Ericsson based modules", 118 .init = &init_ericsson, 119 .cflag = CRTSCTS, 120 .speed = B57600, 121 }, 122 { 123 .name = "st", 124 .line = "btuart", 125 .descr = "ST Microelectronics minikits based on STLC2410/STLC2415", 126 .init = &init_st, 127 .cflag = CRTSCTS, 128 .speed = B57600, 129 }, 130 { 131 .name = "stlc2500", 132 .descr = "ST Microelectronics minikits based on STLC2500", 133 .init = &init_stlc2500, 134 .cflag = CRTSCTS, 135 .speed = B115200, 136 }, 137 { 138 .name = "swave", 139 .line = "btuart", 140 .descr = "Silicon Wave kits", 141 .init = &init_swave, 142 .cflag = CRTSCTS, 143 .speed = B57600, 144 }, 145 { 146 .name = "texas", 147 .line = "btuart", 148 .descr = "Texas Instruments", 149 .cflag = CRTSCTS, 150 .speed = B115200, 151 }, 152 { 153 .name = "unistone", 154 .line = "btuart", 155 .descr = "Infineon UniStone", 156 .init = &init_unistone, 157 .cflag = CRTSCTS, 158 .speed = B115200, 159 }, 160 }; 161 162 int 163 main(int argc, char *argv[]) 164 { 165 const struct devtype *type; 166 struct termios tio; 167 unsigned int init_speed, speed; 168 tcflag_t cflag, Cflag; 169 int fd, ch, tflag, i; 170 const char *name; 171 char *ptr; 172 173 init_speed = 0; 174 cflag = CLOCAL; 175 Cflag = 0; 176 tflag = 0; 177 name = "btuart"; 178 179 while ((ch = getopt(argc, argv, "dFfi:oPpt")) != -1) { 180 switch (ch) { 181 case 'd': 182 opt_debug++; 183 break; 184 185 case 'F': 186 Cflag |= CRTSCTS; 187 break; 188 189 case 'f': 190 cflag |= CRTSCTS; 191 break; 192 193 case 'i': 194 init_speed = strtoul(optarg, &ptr, 10); 195 if (ptr[0] != '\0') 196 errx(EXIT_FAILURE, "invalid speed: %s", optarg); 197 198 break; 199 200 case 'o': 201 cflag |= (PARENB | PARODD); 202 break; 203 204 case 'P': 205 Cflag |= PARENB; 206 break; 207 208 case 'p': 209 cflag |= PARENB; 210 break; 211 212 case 't': 213 tflag = 1; 214 break; 215 216 case '?': 217 default: 218 usage(); 219 } 220 } 221 argc -= optind; 222 argv += optind; 223 224 if (tflag) { 225 if (argc != 1) 226 usage(); 227 test(argv[0], cflag, Cflag); 228 exit(EXIT_SUCCESS); 229 } 230 231 if (argc == 3) { 232 name = argv[0]; 233 argv++; 234 argc--; 235 } 236 237 for (i = 0; ; i++) { 238 if (i == __arraycount(types)) 239 errx(EXIT_FAILURE, "unknown type: %s", name); 240 241 type = &types[i]; 242 if (strcasecmp(type->name, name) == 0) 243 break; 244 } 245 246 if (argc != 2) 247 usage(); 248 249 /* parse tty speed */ 250 speed = strtoul(argv[1], &ptr, 10); 251 if (ptr[0] != '\0') 252 errx(EXIT_FAILURE, "invalid speed: %s", argv[1]); 253 254 if (init_speed == 0) 255 init_speed = (type->speed ? type->speed : speed); 256 257 /* open tty */ 258 if ((fd = open(argv[0], O_RDWR | O_EXLOCK, 0)) < 0) 259 err(EXIT_FAILURE, "%s", argv[0]); 260 261 /* setup tty */ 262 if (tcgetattr(fd, &tio) < 0) 263 err(EXIT_FAILURE, "tcgetattr"); 264 265 cfmakeraw(&tio); 266 tio.c_cflag |= (cflag | type->cflag); 267 tio.c_cflag &= ~Cflag; 268 269 if (cfsetspeed(&tio, init_speed) < 0 270 || tcsetattr(fd, TCSANOW, &tio) < 0 271 || tcflush(fd, TCIOFLUSH) < 0) 272 err(EXIT_FAILURE, "tty setup failed"); 273 274 /* initialize device */ 275 if (type->init != NULL) 276 (*type->init)(fd, speed); 277 278 if (cfsetspeed(&tio, speed) < 0 279 || tcsetattr(fd, TCSADRAIN, &tio) < 0) 280 err(EXIT_FAILURE, "tty setup failed"); 281 282 /* start line discipline */ 283 if (ioctl(fd, TIOCSLINED, type->line) < 0) 284 err(EXIT_FAILURE, "%s", type->line); 285 286 if (opt_debug == 0 && daemon(0, 0) < 0) 287 warn("detach failed!"); 288 289 /* store PID in "/var/run/btattach-{tty}.pid" */ 290 ptr = strrchr(argv[0], '/'); 291 asprintf(&ptr, "%s-%s", getprogname(), (ptr ? ptr + 1 : argv[0])); 292 if (ptr == NULL || pidfile(ptr) < 0) 293 warn("no pidfile"); 294 295 free(ptr); 296 297 (void)signal(SIGHUP, sighandler); 298 (void)signal(SIGINT, sighandler); 299 (void)signal(SIGTERM, sighandler); 300 (void)signal(SIGTSTP, sighandler); 301 (void)signal(SIGUSR1, sighandler); 302 (void)signal(SIGUSR2, sighandler); 303 304 while (sigcount == 0) 305 select(0, NULL, NULL, NULL, NULL); 306 307 return EXIT_SUCCESS; 308 } 309 310 static void 311 usage(void) 312 { 313 size_t i; 314 315 fprintf(stderr, 316 "Usage: %s [-dFfoPp] [-i speed] [type] tty speed\n" 317 " %s -t [-dFfoPp] tty\n" 318 "\n" 319 "Where:\n" 320 "\t-d debug mode (no detach, dump io)\n" 321 "\t-F disable flow control\n" 322 "\t-f enable flow control\n" 323 "\t-i speed init speed\n" 324 "\t-o odd parity\n" 325 "\t-P no parity\n" 326 "\t-p even parity\n" 327 "\t-t test mode\n" 328 "\n" 329 "Known types:\n" 330 "", getprogname(), getprogname()); 331 332 for (i = 0; i < __arraycount(types); i++) 333 fprintf(stderr, "\t%-12s%s\n", types[i].name, types[i].descr); 334 335 exit(EXIT_FAILURE); 336 } 337 338 static void 339 sighandler(int s) 340 { 341 342 sigcount++; 343 } 344 345 static void 346 hexdump(uint8_t *ptr, size_t len) 347 { 348 349 while (len--) 350 printf(" %2.2x", *ptr++); 351 } 352 353 /* 354 * send HCI comamnd 355 */ 356 void 357 uart_send_cmd(int fd, uint16_t opcode, void *buf, size_t len) 358 { 359 struct iovec iov[2]; 360 hci_cmd_hdr_t hdr; 361 362 hdr.type = HCI_CMD_PKT; 363 hdr.opcode = htole16(opcode); 364 hdr.length = len; 365 366 iov[0].iov_base = &hdr; 367 iov[0].iov_len = sizeof(hdr); 368 iov[1].iov_base = buf; 369 iov[1].iov_len = len; 370 371 if (opt_debug) { 372 printf("<<"); 373 hexdump(iov[0].iov_base, iov[0].iov_len); 374 hexdump(iov[1].iov_base, iov[1].iov_len); 375 printf("\n"); 376 fflush(stdout); 377 } 378 379 if (writev(fd, iov, __arraycount(iov)) < 0) 380 err(EXIT_FAILURE, "writev"); 381 382 tcdrain(fd); 383 } 384 385 /* 386 * get next character 387 * store in iovec and inc counter if it fits 388 */ 389 static uint8_t 390 uart_getc(int fd, struct iovec *iov, int ioc, size_t *count) 391 { 392 uint8_t ch, *b; 393 ssize_t n; 394 size_t off; 395 396 n = read(fd, &ch, sizeof(ch)); 397 if (n < 0) 398 err(EXIT_FAILURE, "read"); 399 400 if (n == 0) 401 errx(EXIT_FAILURE, "eof"); 402 403 if (opt_debug) 404 printf(" %2.2x", ch); 405 406 off = *count; 407 while (ioc > 0) { 408 if (iov->iov_len > off) { 409 b = iov->iov_base; 410 b[off] = ch; 411 *count += 1; 412 break; 413 } 414 415 off -= iov->iov_len; 416 iov++; 417 ioc--; 418 } 419 420 return ch; 421 } 422 423 /* 424 * read next packet, storing into iovec 425 */ 426 static size_t 427 uart_recv_pkt(int fd, struct iovec *iov, int ioc) 428 { 429 size_t count, want; 430 uint8_t type; 431 432 if (opt_debug) 433 printf(">>"); 434 435 count = 0; 436 type = uart_getc(fd, iov, ioc, &count); 437 switch(type) { 438 case HCI_EVENT_PKT: 439 (void)uart_getc(fd, iov, ioc, &count); /* event */ 440 want = uart_getc(fd, iov, ioc, &count); 441 break; 442 443 case HCI_ACL_DATA_PKT: 444 (void)uart_getc(fd, iov, ioc, &count); /* handle LSB */ 445 (void)uart_getc(fd, iov, ioc, &count); /* handle MSB */ 446 want = uart_getc(fd, iov, ioc, &count) | /* LSB */ 447 uart_getc(fd, iov, ioc, &count) << 8; /* MSB */ 448 break; 449 450 case HCI_SCO_DATA_PKT: 451 (void)uart_getc(fd, iov, ioc, &count); /* handle LSB */ 452 (void)uart_getc(fd, iov, ioc, &count); /* handle MSB */ 453 want = uart_getc(fd, iov, ioc, &count); 454 break; 455 456 default: /* out of sync? */ 457 errx(EXIT_FAILURE, "unknown packet type 0x%2.2x", type); 458 } 459 460 while (want-- > 0) 461 (void)uart_getc(fd, iov, ioc, &count); 462 463 if (opt_debug) 464 printf("\n"); 465 466 return count; 467 } 468 469 /* 470 * read next matching event packet to buffer 471 */ 472 size_t 473 uart_recv_ev(int fd, uint8_t event, void *buf, size_t len) 474 { 475 struct iovec iov[2]; 476 hci_event_hdr_t hdr; 477 size_t n; 478 479 iov[0].iov_base = &hdr; 480 iov[0].iov_len = sizeof(hdr); 481 iov[1].iov_base = buf; 482 iov[1].iov_len = len; 483 484 for (;;) { 485 n = uart_recv_pkt(fd, iov, __arraycount(iov)); 486 if (n < sizeof(hdr) 487 || hdr.type != HCI_EVENT_PKT 488 || hdr.event != event) 489 continue; 490 491 n -= sizeof(hdr); 492 break; 493 } 494 495 return n; 496 } 497 498 /* 499 * read next matching command_complete event to buffer 500 */ 501 size_t 502 uart_recv_cc(int fd, uint16_t opcode, void *buf, size_t len) 503 { 504 struct iovec iov[3]; 505 hci_event_hdr_t hdr; 506 hci_command_compl_ep cc; 507 size_t n; 508 509 iov[0].iov_base = &hdr; 510 iov[0].iov_len = sizeof(hdr); 511 iov[1].iov_base = &cc; 512 iov[1].iov_len = sizeof(cc); 513 iov[2].iov_base = buf; 514 iov[2].iov_len = len; 515 516 for (;;) { 517 n = uart_recv_pkt(fd, iov, __arraycount(iov)); 518 if (n < sizeof(hdr) 519 || hdr.type != HCI_EVENT_PKT 520 || hdr.event != HCI_EVENT_COMMAND_COMPL) 521 continue; 522 523 n -= sizeof(hdr); 524 if (n < sizeof(cc) 525 || cc.opcode != htole16(opcode)) 526 continue; 527 528 n -= sizeof(cc); 529 break; 530 } 531 532 return n; 533 } 534 535 static void 536 test(const char *tty, tcflag_t cflag, tcflag_t Cflag) 537 { 538 struct termios tio; 539 int fd, guessed; 540 size_t i, j, k; 541 ssize_t n; 542 unsigned char buf[32]; 543 const int bauds[] = { 544 57600, /* BCSP specific default */ 545 921600, /* latest major baud rate */ 546 115200, /* old major baud rate */ 547 548 460800, 549 230400, 550 // 76800, 551 28800, 552 38400, 553 19200, 554 14400, 555 9600, 556 7200, 557 4800, 558 2400, 559 1800, 560 1200, 561 600, 562 300, 563 200, 564 150, 565 134, 566 110, 567 75, 568 50, 569 }; 570 const unsigned char bcsp_lepkt[] = 571 /* ESC ------- header ------- --- link establish --- ESC */ 572 { 0xc0, 0x00, 0x41, 0x00, 0xbe, 0xda, 0xdc, 0xed, 0xed, 0xc0 }; 573 574 printf("test mode\n"); 575 576 /* open tty */ 577 if ((fd = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK, 0)) < 0) 578 err(EXIT_FAILURE, "%s", tty); 579 580 /* setup tty */ 581 if (tcgetattr(fd, &tio) < 0) 582 err(EXIT_FAILURE, "tcgetattr"); 583 cfmakeraw(&tio); 584 tio.c_cflag |= (CLOCAL | CRTSCTS | PARENB); 585 tio.c_cflag |= cflag; 586 tio.c_cflag &= ~Cflag; 587 588 guessed = 0; 589 for (i = 0; i < __arraycount(bauds); i++) { 590 if (cfsetspeed(&tio, bauds[i]) < 0 591 || tcsetattr(fd, TCSANOW, &tio) < 0 592 || tcflush(fd, TCIOFLUSH) < 0) { 593 if (bauds[i] > 115200) 594 continue; 595 else 596 err(EXIT_FAILURE, "tty setup failed"); 597 } 598 599 if (opt_debug) 600 printf(" try with B%d\n", bauds[i]); 601 602 sleep(bauds[i] < 9600 ? 3 : 1); 603 604 n = read(fd, buf, sizeof(buf)); 605 if (opt_debug > 1) 606 printf(" %zd bytes read\n", n); 607 if (n < 0) { 608 if (i == 0 && errno == EAGAIN) { 609 printf("This module is *maybe* supported by btuart(4).\n" 610 "you specify aproporiate <speed>.\n" 611 " Also can specify <type> for initialize.\n"); 612 guessed = 1; 613 break; 614 } 615 if (errno == EAGAIN) 616 continue; 617 618 err(EXIT_FAILURE, "read"); 619 } else { 620 if ((size_t)n < sizeof(bcsp_lepkt)) 621 continue; 622 for (j = 0; j < n - sizeof(bcsp_lepkt); j++) { 623 for (k = 0; k < sizeof(bcsp_lepkt); k++) 624 if (buf[j + k] != bcsp_lepkt[k]) { 625 j += k; 626 break; 627 } 628 if (k < sizeof(bcsp_lepkt)) 629 continue; 630 631 printf( 632 "This module is supported by bcsp(4).\n" 633 " baud rate %d\n", 634 bauds[i]); 635 if (tio.c_cflag & PARENB) 636 printf(" with %sparity\n", 637 tio.c_cflag & PARODD ? "odd " : ""); 638 guessed = 1; 639 break; 640 } 641 if (guessed) 642 break; 643 } 644 645 } 646 647 close(fd); 648 649 if (!guessed) 650 printf("don't understand...\n"); 651 } 652