hciattach.c 分析

原文地址:external/bluetooth/bluez/Tools/hciattach.c作者:xxha000721


external/bluetooth/bluez/Tools/hciattach.c 会生成 hciattach, 会被install 到 /system/bin/hciattach 
1. 先介绍一个数据结构 uart_t :

  1. 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 参数配置:

  1. 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() 函数:
  1. 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():

  1. 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():

  1. /* 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 中:

  1. 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等等

你可能感兴趣的:(hciattach.c 分析)