btattach.c revision 1.8 1 /* $NetBSD: btattach.c,v 1.8 2010/03/08 17:59:52 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.8 2010/03/08 17:59:52 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, i, j, k, n;
526 unsigned char buf[32];
527 const int bauds[] = {
528 57600, /* BCSP specific default */
529 921600, /* latest major baud rate */
530 115200, /* old major baud rate */
531
532 460800,
533 230400,
534 // 76800,
535 28800,
536 38400,
537 19200,
538 14400,
539 9600,
540 7200,
541 4800,
542 2400,
543 1800,
544 1200,
545 600,
546 300,
547 200,
548 150,
549 134,
550 110,
551 75,
552 50,
553 };
554 const unsigned char bcsp_lepkt[] =
555 /* ESC ------- header ------- --- link establish --- ESC */
556 { 0xc0, 0x00, 0x41, 0x00, 0xbe, 0xda, 0xdc, 0xed, 0xed, 0xc0 };
557
558 printf("test mode\n");
559
560 /* open tty */
561 if ((fd = open(tty, O_RDWR | O_NONBLOCK | O_EXLOCK, 0)) < 0)
562 err(EXIT_FAILURE, "%s", tty);
563
564 /* setup tty */
565 if (tcgetattr(fd, &tio) < 0)
566 err(EXIT_FAILURE, "tcgetattr");
567 cfmakeraw(&tio);
568 tio.c_cflag |= (CLOCAL | CRTSCTS | PARENB);
569 tio.c_cflag |= cflag;
570 tio.c_cflag &= ~Cflag;
571
572 guessed = 0;
573 for (i = 0; i < __arraycount(bauds); i++) {
574 if (cfsetspeed(&tio, bauds[i]) < 0
575 || tcsetattr(fd, TCSANOW, &tio) < 0
576 || tcflush(fd, TCIOFLUSH) < 0)
577 if (bauds[i] > 115200)
578 continue;
579 else
580 err(EXIT_FAILURE, "tty setup failed");
581
582 if (opt_debug)
583 printf(" try with B%d\n", bauds[i]);
584
585 sleep(bauds[i] < 9600 ? 3 : 1);
586
587 n = read(fd, buf, sizeof(buf));
588 if (opt_debug > 1)
589 printf(" %dbyte read\n", n);
590 if (n < 0) {
591 if (i == 0 && errno == EAGAIN) {
592 printf("This module is *maybe* supported by btuart(4).\n"
593 "you specify aproporiate <speed>.\n"
594 " Also can specify <type> for initialize.\n");
595 guessed = 1;
596 break;
597 }
598 if (errno == EAGAIN)
599 continue;
600
601 err(EXIT_FAILURE, "read");
602 } else {
603 if (n < sizeof(bcsp_lepkt))
604 continue;
605 for (j = 0; j < n - sizeof(bcsp_lepkt); j++) {
606 for (k = 0; k < sizeof(bcsp_lepkt); k++)
607 if (buf[j + k] != bcsp_lepkt[k]) {
608 j += k;
609 break;
610 }
611 if (k < sizeof(bcsp_lepkt))
612 continue;
613
614 printf(
615 "This module is supported by bcsp(4).\n"
616 " baud rate %d\n",
617 bauds[i]);
618 if (tio.c_cflag & PARENB)
619 printf(" with %sparity\n",
620 tio.c_cflag & PARODD ? "odd " : "");
621 guessed = 1;
622 break;
623 }
624 if (guessed)
625 break;
626 }
627
628 }
629
630 close(fd);
631
632 if (!guessed)
633 printf("don't understand...\n");
634 }
635