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