1 /* $NetBSD: btattach.c,v 1.5 2009/12/06 12:55:46 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.5 2009/12/06 12:55:46 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 49 static void sighandler(int); 50 static void usage(void); 51 52 static int sigcount = 0; /* signals received */ 53 static int opt_debug = 0; /* global? */ 54 55 const struct devtype types[] = { 56 { 57 .name = "bcsp", 58 .line = "bcsp", 59 .descr = "Generic BlueCore Serial Protocol", 60 .cflag = CRTSCTS, 61 .speed = B57600, 62 }, 63 { 64 .name = "bcm2035", 65 .line = "btuart", 66 .descr = "Broadcom BCM2035", 67 .init = &init_bcm2035, 68 .speed = B115200, 69 }, 70 { 71 .name = "bgb2xx", 72 .line = "btuart", 73 .descr = "Philips BGB2xx module", 74 .init = &init_bgb2xx, 75 .cflag = CRTSCTS, 76 .speed = B115200, 77 }, 78 { 79 .name = "btuart", 80 .line = "btuart", 81 .descr = "Generic UART (the default)", 82 }, 83 { 84 .name = "csr", 85 .line = "btuart", 86 .descr = "CSR Casira serial adaptor", 87 .init = &init_csr, 88 .cflag = CRTSCTS, 89 .speed = B57600, 90 }, 91 { 92 .name = "digi", 93 .line = "btuart", 94 .descr = "Digianswer based cards", 95 .init = &init_digi, 96 .cflag = CRTSCTS, 97 .speed = B9600, 98 }, 99 { 100 .name = "ericsson", 101 .line = "btuart", 102 .descr = "Ericsson based modules", 103 .init = &init_ericsson, 104 .cflag = CRTSCTS, 105 .speed = B57600, 106 }, 107 { 108 .name = "st", 109 .line = "btuart", 110 .descr = "ST Microelectronics minikits based on STLC2410/STLC2415", 111 .init = &init_st, 112 .cflag = CRTSCTS, 113 .speed = B57600, 114 }, 115 { 116 .name = "stlc2500", 117 .descr = "ST Microelectronics minikits based on STLC2500", 118 .init = &init_stlc2500, 119 .cflag = CRTSCTS, 120 .speed = B115200, 121 }, 122 { 123 .name = "swave", 124 .line = "btuart", 125 .descr = "Silicon Wave kits", 126 .init = &init_swave, 127 .cflag = CRTSCTS, 128 .speed = B57600, 129 }, 130 { 131 .name = "texas", 132 .line = "btuart", 133 .descr = "Texas Instruments", 134 .cflag = CRTSCTS, 135 .speed = B115200, 136 }, 137 { 138 .name = "unistone", 139 .line = "btuart", 140 .descr = "Infineon UniStone", 141 .init = &init_unistone, 142 .cflag = CRTSCTS, 143 .speed = B115200, 144 }, 145 }; 146 147 int 148 main(int argc, char *argv[]) 149 { 150 const struct devtype *type; 151 struct termios tio; 152 unsigned int init_speed, speed; 153 tcflag_t cflag; 154 int fd, ch, i; 155 const char *name; 156 char *ptr; 157 158 init_speed = 0; 159 cflag = CLOCAL; 160 name = "btuart"; 161 162 while ((ch = getopt(argc, argv, "dfi:op")) != -1) { 163 switch (ch) { 164 case 'd': 165 opt_debug++; 166 break; 167 168 case 'f': 169 cflag |= CRTSCTS; 170 break; 171 172 case 'i': 173 init_speed = strtoul(optarg, &ptr, 10); 174 if (ptr[0] != '\0') 175 errx(EXIT_FAILURE, "invalid speed: %s", optarg); 176 177 break; 178 179 case 'o': 180 cflag |= (PARENB | PARODD); 181 break; 182 183 case 'p': 184 cflag |= PARENB; 185 break; 186 187 case '?': 188 default: 189 usage(); 190 } 191 } 192 argc -= optind; 193 argv += optind; 194 195 if (argc == 3) { 196 name = argv[0]; 197 argv++; 198 argc--; 199 } 200 201 for (i = 0; ; i++) { 202 if (i == __arraycount(types)) 203 errx(EXIT_FAILURE, "unknown type: %s", name); 204 205 type = &types[i]; 206 if (strcasecmp(type->name, name) == 0) 207 break; 208 } 209 210 if (argc != 2) 211 usage(); 212 213 /* parse tty speed */ 214 speed = strtoul(argv[1], &ptr, 10); 215 if (ptr[0] != '\0') 216 errx(EXIT_FAILURE, "invalid speed: %s", argv[1]); 217 218 if (init_speed == 0) 219 init_speed = (type->speed ? type->speed : speed); 220 221 /* open tty */ 222 if ((fd = open(argv[0], O_RDWR | O_EXLOCK, 0)) < 0) 223 err(EXIT_FAILURE, "%s", argv[0]); 224 225 /* setup tty */ 226 if (tcgetattr(fd, &tio) < 0) 227 err(EXIT_FAILURE, "tcgetattr"); 228 229 cfmakeraw(&tio); 230 tio.c_cflag |= (cflag | type->cflag); 231 232 if (cfsetspeed(&tio, init_speed) < 0 233 || tcsetattr(fd, TCSANOW, &tio) < 0 234 || tcflush(fd, TCIOFLUSH) < 0) 235 err(EXIT_FAILURE, "tty setup failed"); 236 237 /* initialize device */ 238 if (type->init != NULL) 239 (*type->init)(fd, speed); 240 241 if (cfsetspeed(&tio, speed) < 0 242 || tcsetattr(fd, TCSADRAIN, &tio) < 0) 243 err(EXIT_FAILURE, "tty setup failed"); 244 245 /* start line discipline */ 246 if (ioctl(fd, TIOCSLINED, type->line) < 0) 247 err(EXIT_FAILURE, "%s", type->line); 248 249 if (opt_debug == 0 && daemon(0, 0) < 0) 250 warn("detach failed!"); 251 252 /* store PID in "/var/run/btattach-{tty}.pid" */ 253 ptr = strrchr(argv[0], '/'); 254 asprintf(&ptr, "%s-%s", getprogname(), (ptr ? ptr + 1 : argv[0])); 255 if (ptr == NULL || pidfile(ptr) < 0) 256 warn("no pidfile"); 257 258 free(ptr); 259 260 (void)signal(SIGHUP, sighandler); 261 (void)signal(SIGINT, sighandler); 262 (void)signal(SIGTERM, sighandler); 263 (void)signal(SIGTSTP, sighandler); 264 (void)signal(SIGUSR1, sighandler); 265 (void)signal(SIGUSR2, sighandler); 266 267 while (sigcount == 0) 268 select(0, NULL, NULL, NULL, NULL); 269 270 return EXIT_SUCCESS; 271 } 272 273 static void 274 usage(void) 275 { 276 size_t i; 277 278 fprintf(stderr, 279 "Usage: %s [-dfop] [-i speed] [type] tty speed\n" 280 "\n" 281 "Where:\n" 282 "\t-d debug mode (no detach, dump io)\n" 283 "\t-f enable flow control\n" 284 "\t-i speed init speed\n" 285 "\t-o odd parity\n" 286 "\t-p even parity\n" 287 "\n" 288 "Known types:\n" 289 "", getprogname()); 290 291 for (i = 0; i < __arraycount(types); i++) 292 fprintf(stderr, "\t%-12s%s\n", types[i].name, types[i].descr); 293 294 exit(EXIT_FAILURE); 295 } 296 297 static void 298 sighandler(int s) 299 { 300 301 sigcount++; 302 } 303 304 static void 305 hexdump(uint8_t *ptr, size_t len) 306 { 307 308 while (len--) 309 printf(" %2.2x", *ptr++); 310 } 311 312 /* 313 * send HCI comamnd 314 */ 315 void 316 uart_send_cmd(int fd, uint16_t opcode, void *buf, size_t len) 317 { 318 struct iovec iov[2]; 319 hci_cmd_hdr_t hdr; 320 321 hdr.type = HCI_CMD_PKT; 322 hdr.opcode = htole16(opcode); 323 hdr.length = len; 324 325 iov[0].iov_base = &hdr; 326 iov[0].iov_len = sizeof(hdr); 327 iov[1].iov_base = buf; 328 iov[1].iov_len = len; 329 330 if (opt_debug) { 331 printf("<<"); 332 hexdump(iov[0].iov_base, iov[0].iov_len); 333 hexdump(iov[1].iov_base, iov[1].iov_len); 334 printf("\n"); 335 fflush(stdout); 336 } 337 338 if (writev(fd, iov, __arraycount(iov)) < 0) 339 err(EXIT_FAILURE, "writev"); 340 341 tcdrain(fd); 342 } 343 344 /* 345 * get next character 346 * store in iovec and inc counter if it fits 347 */ 348 static uint8_t 349 uart_getc(int fd, struct iovec *iov, int ioc, size_t *count) 350 { 351 uint8_t ch, *b; 352 ssize_t n; 353 size_t off; 354 355 n = read(fd, &ch, sizeof(ch)); 356 if (n < 0) 357 err(EXIT_FAILURE, "read"); 358 359 if (n == 0) 360 errx(EXIT_FAILURE, "eof"); 361 362 if (opt_debug) 363 printf(" %2.2x", ch); 364 365 off = *count; 366 while (ioc > 0) { 367 if (iov->iov_len > off) { 368 b = iov->iov_base; 369 b[off] = ch; 370 *count += 1; 371 break; 372 } 373 374 off -= iov->iov_len; 375 iov++; 376 ioc--; 377 } 378 379 return ch; 380 } 381 382 /* 383 * read next packet, storing into iovec 384 */ 385 static size_t 386 uart_recv_pkt(int fd, struct iovec *iov, int ioc) 387 { 388 size_t count, want; 389 uint8_t type; 390 391 if (opt_debug) 392 printf(">>"); 393 394 count = 0; 395 type = uart_getc(fd, iov, ioc, &count); 396 switch(type) { 397 case HCI_EVENT_PKT: 398 (void)uart_getc(fd, iov, ioc, &count); /* event */ 399 want = uart_getc(fd, iov, ioc, &count); 400 break; 401 402 case HCI_ACL_DATA_PKT: 403 (void)uart_getc(fd, iov, ioc, &count); /* handle LSB */ 404 (void)uart_getc(fd, iov, ioc, &count); /* handle MSB */ 405 want = uart_getc(fd, iov, ioc, &count) | /* LSB */ 406 uart_getc(fd, iov, ioc, &count) << 8; /* MSB */ 407 break; 408 409 case HCI_SCO_DATA_PKT: 410 (void)uart_getc(fd, iov, ioc, &count); /* handle LSB */ 411 (void)uart_getc(fd, iov, ioc, &count); /* handle MSB */ 412 want = uart_getc(fd, iov, ioc, &count); 413 break; 414 415 default: /* out of sync? */ 416 errx(EXIT_FAILURE, "unknown packet type 0x%2.2x\n", type); 417 } 418 419 while (want-- > 0) 420 (void)uart_getc(fd, iov, ioc, &count); 421 422 if (opt_debug) 423 printf("\n"); 424 425 return count; 426 } 427 428 /* 429 * read next matching event packet to buffer 430 */ 431 size_t 432 uart_recv_ev(int fd, uint8_t event, void *buf, size_t len) 433 { 434 struct iovec iov[2]; 435 hci_event_hdr_t hdr; 436 size_t n; 437 438 iov[0].iov_base = &hdr; 439 iov[0].iov_len = sizeof(hdr); 440 iov[1].iov_base = buf; 441 iov[1].iov_len = len; 442 443 for (;;) { 444 n = uart_recv_pkt(fd, iov, __arraycount(iov)); 445 if (n < sizeof(hdr) 446 || hdr.type != HCI_EVENT_PKT 447 || hdr.event != event) 448 continue; 449 450 n -= sizeof(hdr); 451 break; 452 } 453 454 return n; 455 } 456 457 /* 458 * read next matching command_complete event to buffer 459 */ 460 size_t 461 uart_recv_cc(int fd, uint16_t opcode, void *buf, size_t len) 462 { 463 struct iovec iov[3]; 464 hci_event_hdr_t hdr; 465 hci_command_compl_ep cc; 466 size_t n; 467 468 iov[0].iov_base = &hdr; 469 iov[0].iov_len = sizeof(hdr); 470 iov[1].iov_base = &cc; 471 iov[1].iov_len = sizeof(cc); 472 iov[2].iov_base = buf; 473 iov[2].iov_len = len; 474 475 for (;;) { 476 n = uart_recv_pkt(fd, iov, __arraycount(iov)); 477 if (n < sizeof(hdr) 478 || hdr.type != HCI_EVENT_PKT 479 || hdr.event != HCI_EVENT_COMMAND_COMPL) 480 continue; 481 482 n -= sizeof(hdr); 483 if (n < sizeof(cc) 484 || cc.opcode != htole16(opcode)) 485 continue; 486 487 n -= sizeof(cc); 488 break; 489 } 490 491 return n; 492 } 493