• I.MX6 Linux Serial Baud Rate hacking


    /********************************************************************************
     *                 I.MX6 Linux Serial Baud Rate hacking
     *   声明:
     *      1. 本文的源代码来自:myzr_android4_2_2_1_1_0.tar.bz2;
     *      2. 本文的目的是为了知道I.MX6串口支持的波特率有哪些,最大是多大,
     *          并加以验证,因为IMX6DQRM_revC.pdf数据手册上说能达到5Mbit/s:
     *          High-speed TIA/EIA-232-F compatible, up to 5.0 Mbit/s
     *      3. 本文的内容主要用了vim+ctags进行代码跟踪,所以使用了跟踪线路图
     *          进行标记,我是这么认为的;
     *
     *                               2015-6-26 晴 深圳 南山平山村 曾剑锋
     *******************************************************************************/
    
                            \\\\\-*- 目录 -*-//////////
                            |  一、内核驱动代码跟踪:      
                            |  二、Linux C测试代码:       
                            |  三、jni Android.mk写法:    
                            \\\\\\\\///////////////
    
    一、内核驱动代码跟踪:
        //cat drivers/tty/serial/imx.c
        static int __init imx_serial_init(void)        <----------+
        {                                                         |
            int ret;                                              |
                                                                  |
            printk(KERN_INFO "Serial: IMX driver
    ");             |
                                                                  |
            ret = uart_register_driver(&imx_reg);                 |
            if (ret)                                              |
                return ret;                                       |
                                                                  |
            ret = platform_driver_register(&serial_imx_driver);   |
            if (ret != 0)                            |            |
                uart_unregister_driver(&imx_reg);    |            |
                                                     |            |
            return 0;                                +--------+   |
        }                                                     |   |
                                                              |   |
        static void __exit imx_serial_exit(void)              |   |
        {                                                     |   |
            platform_driver_unregister(&serial_imx_driver);   |   |
            uart_unregister_driver(&imx_reg);                 |   |
        }                                                     |   |
                                                              |   |
        module_init(imx_serial_init);      --->---------------*---+
        module_exit(imx_serial_exit);                         |
                                                +-------------+
                                                V
        static struct platform_driver serial_imx_driver = {
            .probe      = serial_imx_probe,      --->---+
            .remove     = serial_imx_remove,            |
                                                        |
            .suspend    = serial_imx_suspend,           |
            .resume     = serial_imx_resume,            |
            .driver     = {                             |
                .name   = "imx-uart",                   |
                .owner  = THIS_MODULE,                  |
            },              ----------------------------+
        };                  |                           
                            V
        static int serial_imx_probe(struct platform_device *pdev)
        {
            ......
            sport->port.dev = &pdev->dev;
            sport->port.mapbase = res->start;
            sport->port.membase = base;
            sport->port.type = PORT_IMX,
            sport->port.iotype = UPIO_MEM;
            sport->port.irq = platform_get_irq(pdev, 0);
            sport->rxirq = platform_get_irq(pdev, 0);
            sport->txirq = platform_get_irq(pdev, 1);
            sport->rtsirq = platform_get_irq(pdev, 2);
            sport->port.fifosize = 32;
            sport->port.ops = &imx_pops;      ------------+
            sport->port.flags = UPF_BOOT_AUTOCONF;        |
            sport->port.line = pdev->id;                  |
            init_timer(&sport->timer);                    |
            sport->timer.function = imx_timeout;          |
            sport->timer.data     = (unsigned long)sport; |
            ......                 +----------------------+
        }                          |
                                   V
        static struct uart_ops imx_pops = {
            .tx_empty   = imx_tx_empty,
            .set_mctrl  = imx_set_mctrl,
            .get_mctrl  = imx_get_mctrl,
            .stop_tx    = imx_stop_tx,
            .start_tx   = imx_start_tx,
            .stop_rx    = imx_stop_rx,
            .enable_ms  = imx_enable_ms,
            .break_ctl  = imx_break_ctl,
            .startup    = imx_startup,
            .shutdown   = imx_shutdown,
            .set_termios    = imx_set_termios,       ------------+
            .type       = imx_type,                              |
            .release_port   = imx_release_port,                  |
            .request_port   = imx_request_port,                  |
            .config_port    = imx_config_port,                   |
            .verify_port    = imx_verify_port,                   |
        #if defined(CONFIG_CONSOLE_POLL)                         |
            .poll_get_char  = imx_poll_get_char,                 |
            .poll_put_char  = imx_poll_put_char,                 |
        #endif             +-------------------------------------+
        };                 |                                     
                           V
        static void imx_set_termios(struct uart_port *port, struct ktermios *termios,
                   struct ktermios *old)
        {
            ......
            /*
             * Ask the core to calculate the divisor for us.
             * 获取到的调试信息:
             *    zengjf port->uartclk : 5000000   --> 最高波特率5Mbit/s
             *    zengjf baud : 115200             --> 当前设置的波特率
             *    zengjf quot : 43                 --> 不知道啥意思 :)
             */
            baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);  ---+
            printk("zengjf port->uartclk : %d
    ", port->uartclk / 16);                 |
            printk("zengjf baud : %d
    ", baud);                                        |
            quot = uart_get_divisor(port, baud);                                       |
            printk("zengjf quot : %d
    ", quot);                                        |
            ......             +-------------------------------------------------------+
        }                      |
                               |
                               V  //cat drivers/tty/serial/serial_core.c
        unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
                   struct ktermios *old, unsigned int min, unsigned int max)
        {
            ......
            for (try = 0; try < 2; try++) {
                baud = tty_termios_baud_rate(termios);  -----+
                ......                                       |
            }                                                |
            ......         +---------------------------------+
        }                  |
                           |
                           V  //cat drivers/tty/tty_ioctl.c
        speed_t tty_termios_baud_rate(struct ktermios *termios)
        {
            unsigned int cbaud;
        
            cbaud = termios->c_cflag & CBAUD;
        
        #ifdef BOTHER
            /* Magic token for arbitrary speed via c_ispeed/c_ospeed */
            if (cbaud == BOTHER)
                return termios->c_ospeed;
        #endif
            if (cbaud & CBAUDEX) {
                cbaud &= ~CBAUDEX;
                    
                if (cbaud < 1 || cbaud + 15 > n_baud_table)
                    termios->c_cflag &= ~CBAUDEX;
                else
                    cbaud += 15;
            }
        
            /**
             * 输出可用的波特率,以下是输出结果(不需要可以删除):
             *   warning: `zygote' uses 32-bit capabilities (legacy support in use)
             *   request_suspend_state: wakeup (3->0) at 17554141337 (1970-01-02 00:00:07.145049000 UTC)
             *   eth0: Freescale FEC PHY driver [Generic PHY] (mii_bus:phy_addr=1:01, irq=-1)
             *   ADDRCONF(NETDEV_UP): eth0: link is not ready
             *   acc_open
             *   acc_release
             *   ehci_fsl_bus_resume begins, Host 1
             *   ehci_fsl_bus_resume ends, Host 1
             *   ehci_fsl_bus_resume begins, DR
             *   ehci_fsl_bus_suspend begins, Host 1
             *   ehci_fsl_bus_suspend ends, Host 1
             *   init: sys_prop: permission denied uid:1003  name:service.bootanim.exit
             *   zengjf baud_table size : 31
             *   zengjf baud_table[0] = 0
             *   zengjf baud_table[1] = 50
             *   zengjf baud_table[2] = 75
             *   zengjf baud_table[3] = 110
             *   zengjf baud_table[4] = 134
             *   zengjf baud_table[5] = 150
             *   zengjf baud_table[6] = 200
             *   zengjf baud_table[7] = 300
             *   zengjf baud_table[8] = 600
             *   zengjf baud_table[9] = 1200
             *   zengjf baud_table[10] = 1800
             *   zengjf baud_table[11] = 2400
             *   zengjf baud_table[12] = 4800
             *   zengjf baud_table[13] = 9600
             *   zengjf baud_table[14] = 19200
             *   zengjf baud_table[15] = 38400
             *   zengjf baud_table[16] = 57600
             *   zengjf baud_table[17] = 115200
             *   zengjf baud_table[18] = 230400
             *   zengjf baud_table[19] = 460800
             *   zengjf baud_table[20] = 500000
             *   zengjf baud_table[21] = 576000
             *   zengjf baud_table[22] = 921600
             *   zengjf baud_table[23] = 1000000
             *   zengjf baud_table[24] = 1152000
             *   zengjf baud_table[25] = 1500000
             *   zengjf baud_table[26] = 2000000
             *   zengjf baud_table[27] = 2500000
             *   zengjf baud_table[28] = 3000000
             *   zengjf baud_table[29] = 3500000
             *   zengjf baud_table[30] = 4000000
             */
            printk("zengjf baud_table size : %d
    ", sizeof(baud_table)/sizeof(baud_table[0]));
            int i = 0;
            for(i = 0; i < sizeof(baud_table)/sizeof(baud_table[0]); i++) {
                printk("zengjf baud_table[%d] = %u
    ", i, baud_table[i]);
            }
        
            return baud_table[cbaud];  -->------------+
        }                                             |
                                                      |
        static const speed_t baud_table[] = {   <---- +
            0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, -----+
            9600, 19200, 38400, 57600, 115200, 230400, 460800,                    |
        #ifdef __sparc__                                                          |
            76800, 153600, 307200, 614400, 921600                                 |
        #else                                                                     |
            500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,           |
            2500000, 3000000, 3500000, 4000000                                    |
        #endif                                                                    |
        };                                    // 波特率对应的宏,主要是应用层用       |        
                                                    +-----------------------------+
        #ifndef __sparc__                           |                             
        static const tcflag_t baud_bits[] = {       V
            B0, B50, B75, B110, B134, B150, B200, B300, B600,      ->-----+
            B1200, B1800, B2400, B4800, B9600, B19200, B38400,             |
            B57600, B115200, B230400, B460800, B500000, B576000,           |
            B921600, B1000000, B1152000, B1500000, B2000000, B2500000,     |
            B3000000, B3500000, B4000000                                   |
        };                                                                 |
        #else                                                              |
        static const tcflag_t baud_bits[] = {                              |
            B0, B50, B75, B110, B134, B150, B200, B300, B600,              |
            B1200, B1800, B2400, B4800, B9600, B19200, B38400,             |
            B57600, B115200, B230400, B460800, B76800, B153600,            |
            B307200, B614400, B921600                                      |
        };                                                                 |
        #endif                                                             |
                                                                           |
         /* c_cflag bit meaning */                                         |
        #define CBAUD   0010017                                            |
        #define  B0 0000000     /* hang up */                              |
        #define  B50    0000001                   <------------------------+
        #define  B75    0000002
        #define  B110   0000003
        #define  B134   0000004
        #define  B150   0000005
        #define  B200   0000006
        #define  B300   0000007
        #define  B600   0000010
        #define  B1200  0000011
        #define  B1800  0000012
        #define  B2400  0000013
        #define  B4800  0000014
        #define  B9600  0000015
        #define  B19200 0000016
        #define  B38400 0000017
        #define EXTA B19200
        #define EXTB B38400
        #define CSIZE   0000060
        #define   CS5   0000000
        #define   CS6   0000020
        #define   CS7   0000040
        #define   CS8   0000060
        #define CSTOPB  0000100
        #define CREAD   0000200
        #define PARENB  0000400
        #define PARODD  0001000
        #define HUPCL   0002000
        #define CLOCAL  0004000
        #define CBAUDEX 0010000
        #define    BOTHER 0010000
        #define    B57600 0010001
        #define   B115200 0010002
        #define   B230400 0010003
        #define   B460800 0010004
        #define   B500000 0010005
        #define   B576000 0010006
        #define   B921600 0010007
        #define  B1000000 0010010
        #define  B1152000 0010011
        #define  B1500000 0010012
        #define  B2000000 0010013
        #define  B2500000 0010014
        #define  B3000000 0010015
        #define  B3500000 0010016
        #define  B4000000 0010017
        #define CIBAUD    002003600000      /* input baud rate */
        #define CMSPAR    010000000000      /* mark or space (stick) parity */
        #define CRTSCTS   020000000000      /* flow control */
        
    二、Linux C测试代码:
        // 测试代码参考:http://blog.csdn.net/shui1025701856/article/details/7571686
        #include <stdio.h>  
        #include <stdlib.h>  
        #include <unistd.h>  
        #include <sys/types.h>  
        #include <sys/stat.h>  
        #include <fcntl.h>      //文件控制定义  
        #include <termios.h>    //终端控制定义  
        #include <errno.h>  
         
        #define DEVICE "/dev/ttymxc2"  
          
        int serial_fd = 0;  
          
        //打开串口并初始化设置  
        init_serial(void)  
        {  
            serial_fd = open(DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);  
            if (serial_fd < 0) {  
                perror("open");  
                return -1;  
            }  
              
            //串口主要设置结构体termios <termios.h>  
            struct termios options;  
              
            /**1. tcgetattr函数用于获取与终端相关的参数。 
            *参数fd为终端的文件描述符,返回的结果保存在termios结构体中 
            */  
            tcgetattr(serial_fd, &options);  
            /**2. 修改所获得的参数*/  
            options.c_cflag |= (CLOCAL | CREAD);    //设置控制模式状态,本地连接,接收使能  
            options.c_cflag &= ~CSIZE;              //字符长度,设置数据位之前一定要屏掉这个位  
            options.c_cflag &= ~CRTSCTS;            //无硬件流控  
            options.c_cflag |= CS8;                 //8位数据长度  
            options.c_cflag &= ~CSTOPB;             //1位停止位  
            options.c_iflag |= IGNPAR;              //无奇偶检验位  
            options.c_oflag = 0;                    //输出模式  
            options.c_lflag = 0;                    //不激活终端模式  
            //cfsetospeed(&options, B115200);       //设置波特率  
            cfsetospeed(&options, B1500000);        //设置波特率  
              
            /**3. 设置新属性,TCSANOW:所有改变立即生效*/  
            tcflush(serial_fd, TCIFLUSH);           //溢出数据可以接收,但不读  
            tcsetattr(serial_fd, TCSANOW, &options);  
              
            return 0;  
        }  
          
        /** 
        *串口发送数据 
        *@fd:串口描述符 
        *@data:待发送数据 
        *@datalen:数据长度 
        */  
        int uart_send(int fd, char *data, int datalen)  
        {  
            int len = 0;  
            len = write(fd, data, datalen);         //实际写入的长度  
            if(len == datalen) {  
                return len;  
            } else {  
                tcflush(fd, TCOFLUSH);              //TCOFLUSH刷新写入的数据但不传送  
                return -1;  
            }  
              
            return 0;  
        }  
          
        /** 
        *串口接收数据 
        *要求启动后,在pc端发送ascii文件 
        */  
        int uart_recv(int fd, char *data, int datalen)  
        {  
            int len=0, ret = 0;  
            fd_set fs_read;  
            struct timeval tv_timeout;  
              
            FD_ZERO(&fs_read);  
            FD_SET(fd, &fs_read);  
            tv_timeout.tv_sec  = (10*20/115200+2);  
            tv_timeout.tv_usec = 0;  
              
            ret = select(fd+1, &fs_read, NULL, NULL, &tv_timeout);  
            printf("ret = %d
    ", ret);  
            //如果返回0,代表在描述符状态改变前已超过timeout时间,错误返回-1  
                  
            if (FD_ISSET(fd, &fs_read)) {  
                len = read(fd, data, datalen);  
                printf("len = %d
    ", len);  
                return len;  
            } else {  
                perror("select");  
                return -1;  
            }  
              
            return 0;  
        }  
          
        int main(int argc, char **argv)  
        {  
            init_serial();  
          
            char buf[]="hello world";  
            char buf1[10];  
            int i = 100;
            while (i--) {
                uart_send(serial_fd, buf, 1);  
                printf("
    ");
                uart_recv(serial_fd, buf1, 1);  
                printf("uart receive %s
    ", buf1);  
            }  
              
            close(serial_fd);  
            return 0;  
        }
        
    三、jni Android.mk写法: 
        LOCAL_PATH := $(call my-dir)
        
        include $(CLEAR_VARS)
        LOCAL_MODULE    := UART_test
        LOCAL_SRC_FILES := UART_test.c
        
        include $(BUILD_EXECUTABLE)
            
  • 相关阅读:
    tomcat配置虚拟主机
    android widget 开发实例 : 桌面便签程序的实现具体解释和源代码 (上)
    Delphi 2007体验!
    ACE定时器
    Unity--关于优化方面的那些事儿(一)
    LTP介绍
    Java正則表達式入门
    Spring整合Hibernate的步骤
    ThreadPool.QueueUserWorkItem的性能问题
    用Bootstrap 写了个站点
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4602058.html
Copyright © 2020-2023  润新知