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