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