这个工具的源代码位于 external/bluetooth/bluez/Tools/hciattach.c
编译完会生成 hciattach 工具,
会被install 到 /system/bin/hciattach
1. 先介绍一个数据结构 uart_t :
struct uart_t {
char *type; //name,这里为texas
int m_id;
int p_id;
int proto;
int init_speed; //波特率
int speed;
int flags; //UART 标志位
char *bdaddr;
int (*init) (int fd, struct uart_t *u, struct termios *ti); //u -> init,这里为texas
int (*post) (int fd, struct uart_t *u, struct termios *ti); //u -> post,这里为texas2
};
2. 各种 BT 模块的 uart 参数配置:
struct uart_t uart[] = {
{ "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
{ "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, ericsson },
{ "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200, FLOW_CTL, NULL, digi },
{ "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
/* Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter */
{ "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
/* CSR Casira serial adapter or BrainBoxes serial dongle (BL642) */
{ "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
/* BrainBoxes PCMCIA card (BL620) */
{ "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, csr },
/* Silicon Wave kits */
{ "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, swave },
/* Texas Instruments Bluelink (BRF) modules */
{ "texas", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texas, texas2 }, //这里就用的这项数据。
{ "texasalt", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texasalt, NULL },
/* ST Microelectronics minikits based on STLC2410/STLC2415 */
{ "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, st },
/* ST Microelectronics minikits based on STLC2500 */
{ "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "00:80:E1:00:AB:BA", stlc2500 },
/* Philips generic Ericsson IP core based */
{ "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
/* Philips BGB2xx Module */
{ "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "BD:B2:10:00:AB:BA", bgb2xx },
/* Sphinx Electronics PICO Card */
{ "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
/* Inventel BlueBird Module */
{ "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
/* COM One Platinium Bluetooth PC Card */
{ "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
/* TDK Bluetooth PC Card and IBM Bluetooth PC Card II */
{ "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
/* Socket Bluetooth CF Card (Rev G) */
{ "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400, 0, NULL, bcsp },
/* 3Com Bluetooth Card (Version 3.0) */
{ "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
/* AmbiCom BT2000C Bluetooth PC/CF Card */
{ "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800, FLOW_CTL, NULL, csr },
/* Zoom Bluetooth PCMCIA Card */
{ "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
/* Sitecom CN-504 PCMCIA Card */
{ "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
/* Billionton PCBTC1 PCMCIA Card */
{ "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
/* Broadcom BCM2035 */
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
{ NULL, 0 }
};
3. main() 函数:int main(int argc, char *argv[])
{
struct uart_t *u = NULL;
int detach, printpid, raw, opt, i, n, ld, err;
int to = 10;
int init_speed = 0;
int send_break = 0;
pid_t pid;
struct sigaction sa;
struct pollfd p;
sigset_t sigs;
char dev[PATH_MAX];
detach = 1;
printpid = 0;
raw = 0;
while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) { //解析参数
switch(opt) {
case 'b':
send_break = 1;
break;
case 'n': // 比如 有 -n 参数就会进这里
detach = 0;
break;
case 'p':
printpid = 1;
break;
case 't':
to = atoi(optarg);
break;
case 's':
init_speed = atoi(optarg);
break;
case 'l':
for (i = 0; uart[i].type; i++) {
printf("%-10s0x%04x,0x%04x\n", uart[i].type,
uart[i].m_id, uart[i].p_id);
}
exit(0);
case 'r':
raw = 1;
break;
default:
usage();
exit(1);
}
}
n = argc - optind;
if (n < 2) {
usage();
exit(1);
}
for (n = 0; optind < argc; n++, optind++) {
char *opt;
opt = argv[optind];
switch(n) {
case 0:
dev[0] = 0;
if (!strchr(opt, '/')) //opt = /dev/ttyO1
strcpy(dev, "/dev/");
strcat(dev, opt); //strcat之后,dev =/dev/ttyO1
break;
case 1:
if (strchr(argv[optind], ',')) {
int m_id, p_id;
sscanf(argv[optind], "%x,%x", &m_id, &p_id);
u = get_by_id(m_id, p_id);
} else {
u = get_by_type(opt); //如果参数有/dev/ttyO1,就会这里得到uart_t u
}
if (!u) {
fprintf(stderr, "Unknown device type or id\n");
exit(1);
}
break;
case 2:
u->speed = atoi(argv[optind]); //这里获得波特率参数。
break;
case 3:
if (!strcmp("flow", argv[optind]))
u->flags |= FLOW_CTL; //uart flag 流控制标志
else
u->flags &= ~FLOW_CTL;
break;
case 4:
u->bdaddr = argv[optind];
break;
}
}
if (!u) {
fprintf(stderr, "Unknown device type or id\n");
exit(1);
}
/* If user specified a initial speed, use that instead of
the hardware's default */
if (init_speed)
u->init_speed = init_speed; //波特率
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_NOCLDSTOP;
sa.sa_handler = sig_alarm; //sig_alarm = Initialization time out
sigaction(SIGALRM, &sa, NULL); //sigaction 超时后就会 打印出该sa_handler.
/* 10 seconds should be enough for initialization */
alarm(to);
bcsp_max_retries = to;
n = init_uart(dev, u, send_break, raw); //这里会进入init_uart,初始化串口。
if (n < 0) {
perror("Can't initialize device");
exit(1);
}
printf("Device setup complete\n");
alarm(0);
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_NOCLDSTOP;
sa.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = sig_term;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = sig_hup;
sigaction(SIGHUP, &sa, NULL);
if (detach) {
if ((pid = fork())) {
if (printpid)
printf("%d\n", pid);
return 0;
}
for (i = 0; i < 20; i++)
if (i != n)
close(i);
}
p.fd = n;
p.events = POLLERR | POLLHUP;
sigfillset(&sigs);
sigdelset(&sigs, SIGCHLD);
sigdelset(&sigs, SIGPIPE);
sigdelset(&sigs, SIGTERM);
sigdelset(&sigs, SIGINT);
sigdelset(&sigs, SIGHUP);
while (!__io_canceled) {
p.revents = 0;
err = ppoll(&p, 1, NULL, &sigs);
if (err < 0 && errno == EINTR)
continue;
if (err)
break;
}
/* Restore TTY line discipline */
ld = N_TTY;
if (ioctl(n, TIOCSETD, &ld) < 0) {
perror("Can't restore line discipline");
exit(1);
}
return 0;
}
4.get_by_id() / get_by_type():
static struct uart_t * get_by_id(int m_id, int p_id)
{
int i;
for (i = 0; uart[i].type; i++) {
if (uart[i].m_id == m_id && uart[i].p_id == p_id)
return &uart[i];
}
return NULL;
}
static struct uart_t * get_by_type(char *type)
{
int i;
for (i = 0; uart[i].type; i++) {
if (!strcmp(uart[i].type, type)) //获取/dev/ttyO1
return &uart[i];
}
return NULL;
}
5.init_uart():
/* Initialize UART driver */
static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
{
struct termios ti;
int fd, i;
unsigned long flags = 0;
if (raw)
flags |= 1 << HCI_UART_RAW_DEVICE;
fd = open(dev, O_RDWR | O_NOCTTY); //打开 /dev/ttyO1
if (fd < 0) {
perror("Can't open serial port");
return -1;
}
tcflush(fd, TCIOFLUSH); //一系列 UART 口配置
if (tcgetattr(fd, &ti) < 0) {
perror("Can't get port settings");
return -1;
}
cfmakeraw(&ti);
ti.c_cflag |= CLOCAL;
if (u->flags & FLOW_CTL) //添加流控制标志
ti.c_cflag |= CRTSCTS;
else
ti.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &ti) < 0) {
perror("Can't set port settings");
return -1;
}
/* Set initial baudrate */
if (set_speed(fd, &ti, u->init_speed) < 0) { //初始波特率设置
perror("Can't set initial baud rate");
return -1;
}
tcflush(fd, TCIOFLUSH);
if (send_break) {
tcsendbreak(fd, 0);
usleep(500000);
}
if (u->init && u->init(fd, u, &ti) < 0) //这里调用texas()函数
return -1;
tcflush(fd, TCIOFLUSH);
/* Set actual baudrate */
if (set_speed(fd, &ti, u->speed) < 0) { //实际波特率设置
perror("Can't set baud rate");
return -1;
}
/* Set TTY to N_HCI line discipline */
i = N_HCI;
if (ioctl(fd, TIOCSETD, &i) < 0) {
perror("Can't set line discipline");
return -1;
}
if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
perror("Can't set UART flags");
return -1;
}
if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
perror("Can't set device");
return -1;
}
if (u->post && u->post(fd, u, &ti) < 0) //一切正常的话,就运行texas2()
return -1;
return fd;
}
6. texas 相关的一系列函数,这个被定义在 hciattach_ti.c 中:
static int texas(int fd, struct uart_t *u, struct termios *ti)
{
return texas_init(fd, ti);
}
static int texas2(int fd, struct uart_t *u, struct termios *ti)
{
return texas_post(fd, ti);
}
static int texasalt(int fd, struct uart_t *u, struct termios *ti)
{
return texasalt_init(fd, u->speed, ti);
}
7. 这个代码中,还有其他公司的一些接口,如爱立信,BCM,st等等