xref: /netbsd/usr.sbin/btattach/btattach.c (revision 6550d01e)
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 
49 static void sighandler(int);
50 static void usage(void);
51 static void test(const char *, tcflag_t, tcflag_t);
52 
53 static int sigcount = 0;	/* signals received */
54 static int opt_debug = 0;	/* global? */
55 
56 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 
148 int
149 main(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 
296 static void
297 usage(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 
324 static void
325 sighandler(int s)
326 {
327 
328 	sigcount++;
329 }
330 
331 static void
332 hexdump(uint8_t *ptr, size_t len)
333 {
334 
335 	while (len--)
336 		printf(" %2.2x", *ptr++);
337 }
338 
339 /*
340  * send HCI comamnd
341  */
342 void
343 uart_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  */
375 static uint8_t
376 uart_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  */
412 static size_t
413 uart_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  */
458 size_t
459 uart_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  */
487 size_t
488 uart_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 
521 static void
522 test(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