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