Home | History | Annotate | Line # | Download | only in btattach
      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