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