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