Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
orangepi-xunlong
GitHub Repository: orangepi-xunlong/orangepi-build
Path: blob/next/external/cache/sources/rtk_hciattach/hciattach.c
18115 views
1
/*
2
*
3
* BlueZ - Bluetooth protocol stack for Linux
4
*
5
* Copyright (C) 2000-2001 Qualcomm Incorporated
6
* Copyright (C) 2002-2003 Maxim Krasnyansky <[email protected]>
7
* Copyright (C) 2002-2010 Marcel Holtmann <[email protected]>
8
*
9
*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
14
*
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
19
*
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
*
24
*/
25
26
#ifdef HAVE_CONFIG_H
27
#include <config.h>
28
#endif
29
30
#define _GNU_SOURCE
31
#include <stdio.h>
32
#include <errno.h>
33
#include <fcntl.h>
34
#include <unistd.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <signal.h>
38
#include <syslog.h>
39
#include <termios.h>
40
#include <time.h>
41
#include <sys/time.h>
42
#include <sys/poll.h>
43
#include <sys/param.h>
44
#include <sys/ioctl.h>
45
#include <sys/socket.h>
46
#include <sys/uio.h>
47
#include <sys/timerfd.h>
48
49
#include "hciattach.h"
50
51
#define RFKILL_NODE "/sys/class/rfkill/rfkill0/state"
52
53
#ifdef NEED_PPOLL
54
#include "ppoll.h"
55
#endif
56
57
/* #define SCHED_ENABLE */
58
59
#ifdef SCHED_ENABLE
60
#include <sched.h>
61
#endif
62
63
struct uart_t {
64
char *type;
65
int m_id;
66
int p_id;
67
int proto;
68
int init_speed;
69
int speed;
70
int flags;
71
int pm;
72
char *bdaddr;
73
int (*init) (int fd, struct uart_t *u, struct termios *ti);
74
int (*post) (int fd, struct uart_t *u, struct termios *ti);
75
};
76
77
#define FLOW_CTL 0x0001
78
#define ENABLE_PM 1
79
#define DISABLE_PM 0
80
81
static volatile sig_atomic_t __io_canceled = 0;
82
83
static void sig_hup(int sig)
84
{
85
RS_INFO("signal hup.");
86
}
87
88
static void sig_term(int sig)
89
{
90
switch (sig) {
91
case SIGINT:
92
RS_INFO("signal int.");
93
break;
94
case SIGTERM:
95
RS_INFO("signal term.");
96
break;
97
}
98
__io_canceled = 1;
99
}
100
101
static void sig_alarm(int sig)
102
{
103
RS_ERR("Initialization timed out.");
104
exit(1);
105
}
106
107
static int uart_speed(int s)
108
{
109
switch (s) {
110
case 9600:
111
return B9600;
112
case 19200:
113
return B19200;
114
case 38400:
115
return B38400;
116
case 57600:
117
return B57600;
118
case 115200:
119
return B115200;
120
case 230400:
121
return B230400;
122
case 460800:
123
return B460800;
124
case 500000:
125
return B500000;
126
case 576000:
127
return B576000;
128
case 921600:
129
return B921600;
130
case 1000000:
131
return B1000000;
132
case 1152000:
133
return B1152000;
134
case 1500000:
135
return B1500000;
136
case 2000000:
137
return B2000000;
138
#ifdef B2500000
139
case 2500000:
140
return B2500000;
141
#endif
142
#ifdef B3000000
143
case 3000000:
144
return B3000000;
145
#endif
146
#ifdef B3500000
147
case 3500000:
148
return B3500000;
149
#endif
150
#ifdef B4000000
151
case 4000000:
152
return B4000000;
153
#endif
154
default:
155
return B57600;
156
}
157
}
158
159
int set_speed(int fd, struct termios *ti, int speed)
160
{
161
if (cfsetospeed(ti, uart_speed(speed)) < 0)
162
return -errno;
163
164
if (cfsetispeed(ti, uart_speed(speed)) < 0)
165
return -errno;
166
167
if (tcsetattr(fd, TCSANOW, ti) < 0)
168
return -errno;
169
170
return 0;
171
}
172
173
static int realtek_init(int fd, struct uart_t *u, struct termios *ti)
174
{
175
176
RS_INFO("Realtek Bluetooth init uart with init speed:%d, type:HCI UART %s",
177
u->init_speed,
178
(u->proto == HCI_UART_H4) ? "H4" : "H5");
179
return rtb_init(fd, u->proto, u->speed, ti);
180
}
181
182
static int realtek_post(int fd, struct uart_t *u, struct termios *ti)
183
{
184
RS_INFO("Realtek Bluetooth post process");
185
return rtb_post(fd, u->proto, ti);
186
}
187
188
struct uart_t uart[] = {
189
{ "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, DISABLE_PM, NULL, NULL},
190
191
/* Realtek Bluetooth H4 */
192
{ "rtk_h4", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post },
193
194
/* Realtek Bluetooth H5 */
195
{ "rtk_h5", 0x0000, 0x0000, HCI_UART_3WIRE, 115200,115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post },
196
197
{ NULL, 0 }
198
};
199
200
static struct uart_t * get_by_id(int m_id, int p_id)
201
{
202
int i;
203
for (i = 0; uart[i].type; i++) {
204
if (uart[i].m_id == m_id && uart[i].p_id == p_id)
205
return &uart[i];
206
}
207
return NULL;
208
}
209
210
static struct uart_t * get_by_type(char *type)
211
{
212
int i;
213
for (i = 0; uart[i].type; i++) {
214
if (!strcmp(uart[i].type, type))
215
return &uart[i];
216
}
217
return NULL;
218
}
219
220
/* Initialize UART driver */
221
static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
222
{
223
struct termios ti;
224
int fd, i;
225
unsigned long flags = 0;
226
227
if (raw)
228
flags |= 1 << HCI_UART_RAW_DEVICE;
229
230
fd = open(dev, O_RDWR | O_NOCTTY);
231
if (fd < 0) {
232
RS_ERR("Can't open serial port, %d, %s", errno,
233
strerror(errno));
234
return -1;
235
}
236
237
tcflush(fd, TCIOFLUSH);
238
239
if (tcgetattr(fd, &ti) < 0) {
240
RS_ERR("Can't get port settings, %d, %s", errno,
241
strerror(errno));
242
return -1;
243
}
244
245
cfmakeraw(&ti);
246
247
ti.c_cflag |= CLOCAL;
248
if (u->flags & FLOW_CTL)
249
ti.c_cflag |= CRTSCTS;
250
else
251
ti.c_cflag &= ~CRTSCTS;
252
253
if (tcsetattr(fd, TCSANOW, &ti) < 0) {
254
RS_ERR("Can't set port settings, %d, %s", errno,
255
strerror(errno));
256
return -1;
257
}
258
259
/* Set initial baudrate */
260
if (set_speed(fd, &ti, u->init_speed) < 0) {
261
RS_ERR("Can't set initial baud rate, %d, %s", errno,
262
strerror(errno));
263
return -1;
264
}
265
266
tcflush(fd, TCIOFLUSH);
267
268
if (send_break) {
269
tcsendbreak(fd, 0);
270
usleep(500000);
271
}
272
273
if (u->init && u->init(fd, u, &ti) < 0)
274
return -1;
275
276
tcflush(fd, TCIOFLUSH);
277
278
/* Set actual baudrate
279
* There is no need to change baudrate after uart init
280
* */
281
/* if (set_speed(fd, &ti, u->speed) < 0) {
282
* perror("Can't set baud rate");
283
* return -1;
284
* }
285
*/
286
287
/* Set TTY to N_HCI line discipline */
288
i = N_HCI;
289
if (ioctl(fd, TIOCSETD, &i) < 0) {
290
RS_ERR("Can't set line discipline %d, %s", errno,
291
strerror(errno));
292
return -1;
293
}
294
295
if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
296
RS_ERR("Can't set UART flags %d, %s", errno, strerror(errno));
297
return -1;
298
}
299
300
if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
301
RS_ERR("Can't set device %d, %s", errno, strerror(errno));
302
return -1;
303
}
304
305
if (u->post && u->post(fd, u, &ti) < 0)
306
return -1;
307
308
return fd;
309
}
310
311
static int reset_bluetooth(void)
312
{
313
314
int fd;
315
char state[2];
316
int result;
317
318
/* power off and power on BT */
319
fd = open(RFKILL_NODE, O_RDWR);
320
if (fd < 0) {
321
RS_ERR("Cannot open %s, %d %s", RFKILL_NODE, errno,
322
strerror(errno));
323
return -1;
324
}
325
state[0] = '0';
326
state[1] = '\0';
327
result = write(fd, state, strlen(state) + 1);
328
if (result != (strlen(state) + 1)) {
329
RS_ERR("Cannot write 0 to rfkill state %d %s", errno,
330
strerror(errno));
331
close(fd);
332
return -1;
333
}
334
335
usleep(500000);
336
337
state[0] = '1';
338
state[1] = '\0';
339
result = write(fd, state, strlen(state) + 1);
340
if (result != (strlen(state) + 1)) {
341
RS_ERR("Cannot write 1 to rfkill state %d %s", errno,
342
strerror(errno));
343
close(fd);
344
return -1;
345
}
346
347
usleep(500000);
348
close(fd);
349
350
return 0;
351
}
352
353
static void usage(void)
354
{
355
RS_INFO("hciattach - HCI UART driver initialization utility");
356
RS_INFO("Usage:");
357
RS_INFO("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]");
358
RS_INFO("\thciattach -l");
359
}
360
361
int main(int argc, char *argv[])
362
{
363
struct uart_t *u = NULL;
364
int detach, printpid, raw, opt, i, n, ld, err;
365
int to = 10;
366
int init_speed = 0;
367
int send_break = 0;
368
pid_t pid;
369
struct sigaction sa;
370
struct pollfd p;
371
sigset_t sigs;
372
char dev[PATH_MAX];
373
#ifdef SCHED_ENABLE
374
struct sched_param sched_par;
375
#endif
376
377
detach = 1;
378
printpid = 0;
379
raw = 0;
380
381
while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) {
382
switch(opt) {
383
case 'b':
384
send_break = 1;
385
break;
386
387
case 'n':
388
detach = 0;
389
break;
390
391
case 'p':
392
printpid = 1;
393
break;
394
395
case 't':
396
to = atoi(optarg);
397
break;
398
399
case 's':
400
init_speed = atoi(optarg);
401
break;
402
403
case 'l':
404
for (i = 0; uart[i].type; i++) {
405
RS_INFO("%-10s0x%04x,0x%04x", uart[i].type,
406
uart[i].m_id, uart[i].p_id);
407
}
408
exit(0);
409
410
case 'r':
411
raw = 1;
412
break;
413
414
default:
415
usage();
416
exit(1);
417
}
418
}
419
420
n = argc - optind;
421
if (n < 2) {
422
usage();
423
exit(1);
424
}
425
426
for (n = 0; optind < argc; n++, optind++) {
427
char *opt;
428
429
opt = argv[optind];
430
431
switch(n) {
432
case 0:
433
dev[0] = 0;
434
if (!strchr(opt, '/'))
435
strcpy(dev, "/dev/");
436
strcat(dev, opt);
437
break;
438
439
case 1:
440
if (strchr(argv[optind], ',')) {
441
int m_id, p_id;
442
sscanf(argv[optind], "%x,%x", &m_id, &p_id);
443
u = get_by_id(m_id, p_id);
444
} else {
445
u = get_by_type(opt);
446
}
447
448
if (!u) {
449
RS_ERR("Unknown device type or id");
450
exit(1);
451
}
452
453
break;
454
455
case 2:
456
u->speed = atoi(argv[optind]);
457
break;
458
459
case 3:
460
if (!strcmp("flow", argv[optind]))
461
u->flags |= FLOW_CTL;
462
else
463
u->flags &= ~FLOW_CTL;
464
break;
465
466
case 4:
467
if (!strcmp("sleep", argv[optind]))
468
u->pm = ENABLE_PM;
469
else
470
u->pm = DISABLE_PM;
471
break;
472
473
case 5:
474
u->bdaddr = argv[optind];
475
break;
476
}
477
}
478
479
if (!u) {
480
RS_ERR("Unknown device type or id");
481
exit(1);
482
}
483
484
start:
485
486
#ifdef SCHED_ENABLE
487
RS_INFO("Increase the priority of the process with set sched");
488
memset(&sched_par, 0, sizeof(sched_par));
489
sched_par.sched_priority = 99;
490
err = sched_setscheduler(0, SCHED_FIFO, &sched_par);
491
if (err == -1) {
492
RS_ERR("Call sched_setscheduler error, %s",
493
strerror(errno));
494
}
495
/* #else
496
* RS_INFO("Increase the priority of the process with nice");
497
* err = nice(-20);
498
* if (err == -1) {
499
* RS_ERR("Call nice error, %s", strerror(errno));
500
* }
501
*/
502
#endif
503
504
/* If user specified a initial speed, use that instead of
505
the hardware's default */
506
if (init_speed)
507
u->init_speed = init_speed;
508
509
memset(&sa, 0, sizeof(sa));
510
sa.sa_flags = SA_NOCLDSTOP;
511
sa.sa_handler = sig_alarm;
512
sigaction(SIGALRM, &sa, NULL);
513
514
/* 10 seconds should be enough for initialization */
515
alarm(to);
516
517
n = init_uart(dev, u, send_break, raw);
518
if (n < 0) {
519
RS_ERR("Can't initialize device %d, %s", errno,
520
strerror(errno));
521
exit(1);
522
}
523
524
RS_INFO("Device setup complete");
525
526
alarm(0);
527
528
memset(&sa, 0, sizeof(sa));
529
sa.sa_flags = SA_NOCLDSTOP;
530
sa.sa_handler = SIG_IGN;
531
sigaction(SIGCHLD, &sa, NULL);
532
sigaction(SIGPIPE, &sa, NULL);
533
534
sa.sa_handler = sig_term;
535
sigaction(SIGTERM, &sa, NULL);
536
sigaction(SIGINT, &sa, NULL);
537
538
sa.sa_handler = sig_hup;
539
sigaction(SIGHUP, &sa, NULL);
540
541
if (detach) {
542
if ((pid = fork())) {
543
if (printpid)
544
RS_INFO("%d", pid);
545
return 0;
546
}
547
548
for (i = 0; i < 20; i++)
549
if (i != n)
550
close(i);
551
}
552
553
p.fd = n;
554
p.events = POLLERR | POLLHUP;
555
556
sigfillset(&sigs);
557
sigdelset(&sigs, SIGCHLD);
558
sigdelset(&sigs, SIGPIPE);
559
sigdelset(&sigs, SIGTERM);
560
sigdelset(&sigs, SIGINT);
561
sigdelset(&sigs, SIGHUP);
562
563
while (!__io_canceled) {
564
p.revents = 0;
565
err = ppoll(&p, 1, NULL, &sigs);
566
if (err < 0 && errno == EINTR) {
567
RS_INFO("Got EINTR.");
568
continue;
569
} if (err)
570
break;
571
}
572
573
RS_INFO("err %d, p->revents %04x", err, p.revents);
574
575
/* Restore TTY line discipline */
576
RS_INFO("Restore TTY line discipline");
577
ld = N_TTY;
578
if (ioctl(n, TIOCSETD, &ld) < 0) {
579
RS_ERR("Can't restore line discipline %d, %s", errno,
580
strerror(errno));
581
exit(1);
582
}
583
584
if (p.revents & (POLLERR | POLLHUP)) {
585
RS_INFO("Recover...");
586
reset_bluetooth();
587
goto start;
588
}
589
590
return 0;
591
}
592
593
void util_hexdump(const uint8_t *buf, size_t len)
594
{
595
static const char hexdigits[] = "0123456789abcdef";
596
char str[16 * 3];
597
size_t i;
598
599
if (!buf || !len)
600
return;
601
602
for (i = 0; i < len; i++) {
603
str[((i % 16) * 3)] = hexdigits[buf[i] >> 4];
604
str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
605
str[((i % 16) * 3) + 2] = ' ';
606
if ((i + 1) % 16 == 0) {
607
str[16 * 3 - 1] = '\0';
608
RS_INFO("%s", str);
609
}
610
}
611
612
if (i % 16 > 0) {
613
str[(i % 16) * 3 - 1] = '\0';
614
RS_INFO("%s", str);
615
}
616
}
617
618
int timeout_set(int fd, unsigned int msec)
619
{
620
struct itimerspec itimer;
621
unsigned int sec = msec / 1000;
622
623
memset(&itimer, 0, sizeof(itimer));
624
itimer.it_interval.tv_sec = 0;
625
itimer.it_interval.tv_nsec = 0;
626
itimer.it_value.tv_sec = sec;
627
itimer.it_value.tv_nsec = (msec - (sec * 1000)) * 1000 * 1000;
628
629
return timerfd_settime(fd, 0, &itimer, NULL);
630
}
631
632
633