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\n"); | | 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\n", port->uartclk / 16); | printk("zengjf baud : %d\n", baud); | quot = uart_get_divisor(port, baud); | printk("zengjf quot : %d\n", 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\n", 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\n", 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\n", ret); //如果返回0,代表在描述符状态改变前已超过timeout时间,错误返回-1 if (FD_ISSET(fd, &fs_read)) { len = read(fd, data, datalen); printf("len = %d\n", 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("\n"); uart_recv(serial_fd, buf1, 1); printf("uart receive %s\n", 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)