这篇博客主要是通过一个简单的例子来了解Android的串口驱动和应用,为方便后续对Android
串口服务和USB虚拟串口服务的了解。这个例子中,参考了《Linux Device Drivers》书中的例子,
并在该例子中增加了串口接收的处理。由于手上的机器是手机,硬件上只保留了一个串口用于debug。
而且这里只做一个回环测试,因此使用一个FIFO模拟硬件的读写:
void serial_in(char *data) //硬件:读取串口,FIFO:出队 void serial_out(char data) //硬件:写串口 ,FIFO:入队
通过这两个函数就可以模拟串口的读写。
关于linux串口驱动框架,可以参考Linux Device Drivers》书中的《TTY Drivers》章节,比较
简单,这里不再复述。
串口应用方面的了解,可以参考《Serial Programming Guide for POSIX Operating systems.html" target="_blank">Systems》
文件,Google可以搜得到。
(A) 添加串口驱动
(B) 添加应用测试
(C) 测试
(A) 添加串口驱动
主要是注册驱动,配置硬件,提供硬件读写接口,并生成ttyxxx节点,这里是生成ttytiny0,为
用户空间提供串口的读写,配置等接口。
kernel/drivers/tty/serial/tiny_serial.c
1 #include <linux/kernel.h> 2 #include <linux/errno.h> 3 #include <linux/init.h> 4 #include <linux/slab.h> 5 #include <linux/tty.h> 6 #include <linux/tty_flip.h> 7 #include <linux/serial.h> 8 #include <linux/serial_core.h> 9 #include <linux/module.h> 10 11 12 #define TINY_SERIAL_DEBUG 13 #define pr_fmt(fmt) "tiny_serial: " fmt 14 15 #if defined(TINY_SERIAL_DEBUG) 16 #define DBG(fmt, ...) printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) 17 #else 18 #define DBG(fmt, ...) no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) 19 #endif 20 21 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" 22 #define DRIVER_DESC "Tiny serial driver" 23 24 /* Module information */ 25 MODULE_AUTHOR( DRIVER_AUTHOR ); 26 MODULE_DESCRIPTION( DRIVER_DESC ); 27 MODULE_LICENSE("GPL"); 28 29 #define DELAY_TIME 100// HZ * 2 /* 2 seconds per character */ 30 #define TINY_DATA_CHARACTER 't' 31 32 #define TINY_SERIAL_MAJOR 4 //240 /* experimental range */ 33 #define TINY_SERIAL_MINORS 68 //1 /* only have one minor */ 34 #define UART_NR 1 /* only use one port */ 35 36 #define TINY_SERIAL_NAME "ttytiny" 37 38 #define MY_NAME TINY_SERIAL_NAME 39 40 #define BUF_SIZE 200 41 42 static char buf[BUF_SIZE]; 43 static char *read_ptr; 44 static char *write_ptr; 45 46 static struct timer_list *timer; 47 48 49 static void serial_out(char data) 50 { 51 *write_ptr = data; 52 write_ptr++; 53 if (write_ptr >= buf + BUF_SIZE) 54 write_ptr = buf; 55 } 56 57 static void serial_in(char *data) 58 { 59 if (read_ptr == NULL) { 60 DBG("pointer is null !\n"); 61 } 62 63 if (read_ptr && (read_ptr != write_ptr)) { 64 *data = *read_ptr; 65 read_ptr++; 66 if(read_ptr >= buf + BUF_SIZE) 67 read_ptr = buf; 68 } 69 } 70 71 72 static void tiny_stop_tx(struct uart_port *port) 73 { 74 DBG("tiny_stop_tx()\n"); 75 } 76 77 static void tiny_stop_rx(struct uart_port *port) 78 { 79 DBG("tiny_stop_rx()\n"); 80 } 81 82 static void tiny_enable_ms(struct uart_port *port) 83 { 84 DBG("tiny_enable_ms()\n"); 85 } 86 87 static void tiny_rx_chars(struct uart_port *port, int size) 88 { 89 int i = 0; 90 char byte; 91 char flag; 92 struct tty_port *tty = &port->state->port; 93 94 if (size <= 0) { 95 return; 96 } 97 98 while (size--) { 99 serial_in(&byte); 100 DBG("read: 0x%2x\n", byte); 101 flag = TTY_NORMAL; 102 port->icount.rx++; 103 104 if (uart_handle_sysrq_char(port, byte)) { 105 DBG("found ignore char !\n"); 106 goto ignore_char; 107 } 108 109 uart_insert_char(port, 0, 0, byte, flag); 110 ignore_char: 111 i ++; 112 } 113 tty_flip_buffer_push(tty); 114 DBG("push to user space !\n"); 115 } 116 117 static int tiny_tx_chars(struct uart_port *port) 118 { 119 struct circ_buf *xmit = &port->state->xmit; 120 int count; 121 122 DBG("tiny_tx_chars()\n"); 123 124 if (port->x_char) { 125 DBG("wrote 0x%2x\r\n", port->x_char); 126 port->icount.tx++; 127 port->x_char = 0; 128 return; 129 } 130 if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { 131 tiny_stop_tx(port); 132 return; 133 } 134 135 count = port->fifosize >> 1; 136 137 do { 138 DBG("wrote 0x%2x\r\n", xmit->buf[xmit->tail]); 139 serial_out(xmit->buf[xmit->tail]); 140 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 141 port->icount.tx++; 142 if (uart_circ_empty(xmit)) 143 break; 144 } while (--count > 0); 145 146 if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 147 uart_write_wakeup(port); 148 149 if (uart_circ_empty(xmit)) 150 tiny_stop_tx(port); 151 152 return ((port->fifosize >> 1) - count + 1); 153 } 154 155 static void tiny_start_tx(struct uart_port *port) 156 { 157 DBG("tiny_start_tx()\n"); 158 } 159 160 static void tiny_timer(unsigned long data) 161 { 162 struct uart_port *port; 163 struct tty_port *tport; 164 int ret = 0; 165 166 DBG("tiny_timer()\n"); 167 port = (struct uart_port *)data; 168 if (!port) 169 return; 170 if (!port->state) 171 return; 172 tport = &port->state->port; 173 174 #if 0 /* [cgw]: but it really push the data through */ 175 /* add one character to the tty port */ 176 /* this doesn't actually push the data through unless tty->low_latency is set */ 177 tty_insert_flip_char(tport, TINY_DATA_CHARACTER, 0); 178 179 tty_flip_buffer_push(tport); 180 #endif 181 182 /* resubmit the timer again */ 183 timer->expires = jiffies + DELAY_TIME; 184 add_timer(timer); 185 186 /* see if we have any data to transmit */ 187 ret = tiny_tx_chars(port); 188 tiny_rx_chars(port, ret); 189 } 190 191 static unsigned int tiny_tx_empty(struct uart_port *port) 192 { 193 DBG("tiny_tx_empty()\n"); 194 return 0; 195 } 196 197 static unsigned int tiny_get_mctrl(struct uart_port *port) 198 { 199 DBG("tiny_get_mctrl()\n"); 200 return 0; 201 } 202 203 static void tiny_set_mctrl(struct uart_port *port, unsigned int mctrl) 204 { 205 DBG("tiny_set_mctrl()\n"); 206 } 207 208 static void tiny_break_ctl(struct uart_port *port, int break_state) 209 { 210 DBG("tiny_set_mctrl()\n"); 211 } 212 213 static void tiny_set_termios(struct uart_port *port, 214 struct ktermios *new, struct ktermios *old) 215 { 216 int baud, quot, cflag = new->c_cflag; 217 218 DBG("tiny_set_termios()\n"); 219 220 /* get the byte size */ 221 switch (cflag & CSIZE) { 222 case CS5: 223 DBG(" - data bits = 5\n"); 224 break; 225 case CS6: 226 DBG(" - data bits = 6\n"); 227 break; 228 case CS7: 229 DBG(" - data bits = 7\n"); 230 break; 231 default: // CS8 232 DBG(" - data bits = 8\n"); 233 break; 234 } 235 236 /* determine the parity */ 237 if (cflag & PARENB) 238 if (cflag & PARODD) 239 DBG(" - parity = odd\n"); 240 else 241 DBG(" - parity = even\n"); 242 else 243 DBG(" - parity = none\n"); 244 245 /* figure out the stop bits requested */ 246 if (cflag & CSTOPB) 247 DBG(" - stop bits = 2\n"); 248 else 249 DBG(" - stop bits = 1\n"); 250 251 /* figure out the flow control settings */ 252 if (cflag & CRTSCTS) 253 DBG(" - RTS/CTS is enabled\n"); 254 else 255 DBG(" - RTS/CTS is disabled\n"); 256 257 /* Set baud rate */ 258 //baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16); 259 baud = uart_get_baud_rate(port, new, old, 9600, 115200); 260 quot = uart_get_divisor(port, baud); 261 262 //UART_PUT_DIV_LO(port, (quot & 0xff)); 263 //UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8)); 264 } 265 266 static int tiny_startup(struct uart_port *port) 267 { 268 /* this is the first time this port is opened */ 269 /* do any hardware initialization needed here */ 270 271 DBG("tiny_startup()\n"); 272 273 /* create our timer and submit it */ 274 if (!timer) { 275 timer = kmalloc(sizeof(*timer), GFP_KERNEL); 276 if (!timer) 277 return -ENOMEM; 278 init_timer(timer); 279 } 280 timer->data = (unsigned long)port; 281 timer->expires = jiffies + DELAY_TIME; 282 timer->function = tiny_timer; 283 add_timer(timer); 284 return 0; 285 } 286 287 static void tiny_shutdown(struct uart_port *port) 288 { 289 /* The port is being closed by the last user. */ 290 /* Do any hardware specific stuff here */ 291 292 DBG("tiny_shutdown()\n"); 293 294 /* shut down our timer */ 295 del_timer(timer); 296 } 297 298 static const char *tiny_type(struct uart_port *port) 299 { 300 DBG("tiny_type()\n"); 301 return "tinytty"; 302 } 303 304 static void tiny_release_port(struct uart_port *port) 305 { 306 DBG("tiny_release_port()\n"); 307 } 308 309 static int tiny_request_port(struct uart_port *port) 310 { 311 DBG("tiny_request_port()\n"); 312 return 0; 313 } 314 315 static void tiny_config_port(struct uart_port *port, int flags) 316 { 317 DBG("tiny_config_port()\n"); 318 } 319 320 static int tiny_verify_port(struct uart_port *port, struct serial_struct *ser) 321 { 322 DBG("tiny_verify_port()\n"); 323 return 0; 324 } 325 326 static struct uart_ops tiny_ops = { 327 .tx_empty = tiny_tx_empty, 328 .set_mctrl = tiny_set_mctrl, 329 .get_mctrl = tiny_get_mctrl, 330 .stop_tx = tiny_stop_tx, 331 .start_tx = tiny_start_tx, 332 .stop_rx = tiny_stop_rx, 333 .enable_ms = tiny_enable_ms, 334 .break_ctl = tiny_break_ctl, 335 .startup = tiny_startup, 336 .shutdown = tiny_shutdown, 337 .set_termios = tiny_set_termios, 338 .type = tiny_type, 339 .release_port = tiny_release_port, 340 .request_port = tiny_request_port, 341 .config_port = tiny_config_port, 342 .verify_port = tiny_verify_port, 343 }; 344 345 static struct uart_port tiny_port = { 346 .ops = &tiny_ops, 347 .line = 0, 348 .type = 104, 349 .iotype = SERIAL_IO_PORT, 350 .fifosize = 128, 351 .flags = ASYNC_BOOT_AUTOCONF, 352 .irq = 0, 353 }; 354 355 static struct uart_driver tiny_reg = { 356 .owner = THIS_MODULE, 357 .driver_name = TINY_SERIAL_NAME, 358 .dev_name = TINY_SERIAL_NAME, 359 .major = TINY_SERIAL_MAJOR, 360 .minor = TINY_SERIAL_MINORS, 361 .nr = UART_NR, 362 }; 363 364 static int __init tiny_init(void) 365 { 366 int result; 367 368 DBG(KERN_INFO "Tiny serial driver loaded\n"); 369 370 result = uart_register_driver(&tiny_reg); 371 if (result) { 372 DBG("tiny_init() error!\n"); 373 return result; 374 } 375 376 result = uart_add_one_port(&tiny_reg, &tiny_port); 377 if (result) { 378 DBG("uart_add_one_port() error!\n"); 379 uart_unregister_driver(&tiny_reg); 380 } 381 382 read_ptr = buf; 383 write_ptr = buf; 384 385 return result; 386 } 387 388 module_init(tiny_init);
kernel/drivers/tty/serial/Makefile
1 ...... 2 obj-$(CONFIG_SERIAL_TINY_SERIAL) += tiny_serial.o
kernel/drivers/tty/serial/Kconfig
1 ...... 2 config SERIAL_TINY_SERIAL 3 tristate "Tiny UART support" 4 select SERIAL_CORE 5 help 6 This driver supports the virtual UART port.
device/.../common/rootdir/root/ueventd.xxx.rc
1 ...... 2 /dev/ttytiny0 0660 system system
(B) 添加应用测试
这是一个简单的串口应用测试,主要是打开串口,设置,读写数据,关闭串口等操作。这里通过
发送“hello, tiny serial driver !”到串口,并从串口读回,模拟回环测试。
frameworks/base/tests/TinySerialTest/tiny_serial_test.c
1 #define LOG_TAG "TinySerialTest" 2 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <strings.h> 7 #include <sys/types.h> 8 #include <sys/stat.h> 9 #include <fcntl.h> 10 #include <unistd.h> 11 #include <utils/Log.h> 12 #include <termios.h> 13 14 #include <sys/select.h> 15 #include <sys/time.h> 16 17 #define PAR_NONE 0 18 #define PAR_EVEN 1 19 #define PAR_ODD 2 20 21 #define DATA_8BIT 1 22 #define DATA_7BIT 2 23 24 #define STOP_1BIT 1 25 #define STOP_2BIT 2 26 27 28 struct tiny_op { 29 int max_fd; 30 int fd; 31 fd_set rfds; 32 fd_set wfds; 33 fd_set efds; 34 struct timeval r_timeout; 35 struct timeval w_timeout; 36 }; 37 38 static struct tiny_op tops; 39 40 41 static void set_termios(struct termios *termios, int baudrate, int parity, int bits, int stop) 42 { 43 termios->c_cflag |= CLOCAL | CREAD; 44 45 termios->c_cflag &= ~CSIZE; 46 switch (bits) { 47 case DATA_7BIT: 48 termios->c_cflag |= CS7; 49 break; 50 51 case DATA_8BIT: 52 termios->c_cflag |= CS8; 53 break; 54 55 default: 56 termios->c_cflag |= CS8; 57 break; 58 } 59 60 switch (parity) { 61 case PAR_NONE: 62 termios->c_cflag &= ~PARENB; 63 termios->c_cflag &= ~PARODD; 64 break; 65 66 case PAR_EVEN: 67 termios->c_cflag |= PARENB; 68 termios->c_cflag &= ~PARODD; 69 break; 70 71 case PAR_ODD: 72 termios->c_cflag |= PARENB; 73 termios->c_cflag |= PARODD; 74 break; 75 76 default: 77 termios->c_cflag &= ~PARENB; 78 termios->c_cflag &= ~PARODD; 79 break; 80 } 81 82 switch (stop) { 83 case STOP_1BIT: 84 termios->c_cflag &= ~CSTOPB; 85 break; 86 87 case STOP_2BIT: 88 termios->c_cflag |= CSTOPB; 89 break; 90 91 default: 92 termios->c_cflag &= ~CSTOPB; 93 break; 94 } 95 96 termios->c_iflag |= INPCK | ISTRIP; 97 termios->c_lflag = 0; 98 termios->c_oflag = 0; 99 100 termios->c_cc[VTIME] = 5; 101 termios->c_cc[VMIN] = 0; 102 #if 1 103 cfsetspeed(termios, baudrate); 104 #else 105 cfsetispeed(termios, baudrate); 106 cfsetospeed(termios, baudrate); 107 #endif 108 } 109 110 111 static int tiny_write(struct tiny_op *op, char *buff, int size) 112 { 113 int ret = -1; 114 int len = 0; 115 116 op->w_timeout.tv_sec = 5; 117 op->w_timeout.tv_usec = 0; 118 119 ret = select(op->max_fd, NULL, &op->wfds, &op->efds, &op->w_timeout); 120 if (ret < 0) { 121 ALOGE("select failed !"); 122 return -1; 123 } if (0 == ret) { 124 ALOGW("select times out !"); 125 } else { 126 if (FD_ISSET(op->fd, &op->wfds)) { 127 ALOGI("we can write something to tiny serial !"); 128 len = write(op->fd, (const void *)buff, size); 129 if (len == size) { 130 ALOGW("succeed to write ttytiny0"); 131 } else { 132 ALOGI("len = %d", len); 133 } 134 } 135 136 if (FD_ISSET(op->fd, &op->efds)) { 137 ALOGW("oops, exception occur !"); 138 return -1; 139 } 140 } 141 142 return 0; 143 } 144 145 146 static int tiny_read(struct tiny_op *op, char *buff, int size) 147 { 148 int ret = -1; 149 int len = 0; 150 151 op->r_timeout.tv_sec = 5; 152 op->r_timeout.tv_usec = 0; 153 154 ret = select(op->max_fd, &op->rfds, NULL, &op->efds, &op->r_timeout); 155 if (ret < 0) { 156 ALOGE("select failed !"); 157 return -1; 158 } if (0 == ret) { 159 ALOGW("select times out !"); 160 } else { 161 if (FD_ISSET(op->fd, &op->rfds)) { 162 ALOGI("we have something to read !"); 163 len = read(op->fd, (void *)buff, size); 164 ALOGI("read form tiny serial: %s, len: %d", buff, len); 165 } 166 167 if (FD_ISSET(op->fd, &op->efds)) { 168 ALOGW("oops, exception occur !"); 169 return -1; 170 } 171 } 172 173 return 0; 174 } 175 176 177 int main(int argc, char **argv) 178 { 179 int fd = -1, ret = -1; 180 struct termios oldtio, newtio; 181 182 char *str = {"hello, tiny serial driver !\0"}; 183 char buff[strlen(str)]; 184 185 186 bzero((void *)&oldtio, sizeof(oldtio)); 187 bzero((void *)&newtio, sizeof(newtio)); 188 189 fd = open("/dev/ttytiny0", O_RDWR | O_NOCTTY | O_NONBLOCK); 190 if (fd == -1) { 191 ALOGW("failed to open /dev/ttytiny0 !"); 192 return -1; 193 } 194 195 ALOGW("succeed to open /dev/ttytiny0 !"); 196 197 ret = tcgetattr(fd, &oldtio); 198 if (ret != 0) { 199 ALOGW("failed to get attr !"); 200 close(fd); 201 return -1; 202 } 203 204 set_termios(&newtio, B38400, PAR_EVEN, DATA_8BIT, STOP_1BIT); 205 tcflush(fd, TCIOFLUSH); 206 207 ret = tcsetattr(fd, TCSANOW, &newtio); 208 if (ret != 0) { 209 ALOGW("failed to set termios !"); 210 close(fd); 211 return -1; 212 } 213 214 tops.fd = fd; 215 tops.max_fd = tops.fd + 1; 216 217 FD_ZERO(&tops.rfds); 218 FD_ZERO(&tops.wfds); 219 FD_ZERO(&tops.efds); 220 FD_SET(tops.fd, &tops.rfds); 221 FD_SET(tops.fd, &tops.wfds); 222 FD_SET(tops.fd, &tops.efds); 223 224 if (tiny_write(&tops, str, strlen(str)) != 0) { 225 close(fd); 226 return -1; 227 } 228 229 if (tiny_read(&tops, buff, sizeof(buff)) != 0) { 230 close(fd); 231 return -1; 232 } 233 234 ret = tcsetattr(fd, TCSANOW, &oldtio); 235 if (ret != 0) { 236 ALOGW("failed to restore attr !"); 237 } 238 239 tcflush(fd, TCIOFLUSH); 240 241 if (close(fd) != 0) { 242 ALOGW("failed to close ttytiny0 !"); 243 return -1; 244 } 245 246 return 0; 247 }
frameworks/base/tests/TinySerialTest/Android.mk
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES:= \ 5 tiny_serial_test.c 6 7 LOCAL_SHARED_LIBRARIES := \ 8 libutils \ 9 libcutils 10 11 #LOCAL_C_INCLUDES := \ 12 13 LOCAL_MODULE:= tiny_serial_test 14 15 include $(BUILD_EXECUTABLE)
(C) 测试
mmm编译生成tiny_serial_test.bin文件,push到目标板/system/bin目录,在执行:
用户空间打印:
...... 01-01 08:07:11.832 2462 2462 W TinySerialTest: succeed to open /dev/ttytiny0 ! 01-01 08:07:11.855 2462 2462 I TinySerialTest: we can write something to tiny serial ! 01-01 08:07:11.859 2462 2462 W TinySerialTest: succeed to write ttytiny0 01-01 08:07:13.023 2462 2462 I TinySerialTest: we have something to read ! 01-01 08:07:13.023 2462 2462 I TinySerialTest: read form tiny serial: hello, tiny serial driver !, len: 27
kernel打印:
...... 01-01 08:07:11.809 <1>[ 180.247772] c0 tiny_serial: tiny_startup() 01-01 08:07:11.809 <1>[ 180.251800] c0 tiny_serial: tiny_set_termios() 01-01 08:07:11.822 <1>[ 180.256622] c0 tiny_serial: - data bits = 8 01-01 08:07:11.822 <1>[ 180.260833] c0 tiny_serial: - parity = none 01-01 08:07:11.822 <1>[ 180.265075] c0 tiny_serial: - stop bits = 1 01-01 08:07:11.831 <1>[ 180.269531] c0 tiny_serial: - RTS/CTS is disabled 01-01 08:07:11.831 <1>[ 180.274261] c0 tiny_serial: tiny_set_mctrl() 01-01 08:07:11.840 <1>[ 180.279144] c0 tiny_serial: tiny_set_termios() 01-01 08:07:11.840 <1>[ 180.283538] c0 tiny_serial: - data bits = 8 01-01 08:07:11.850 <1>[ 180.288452] c0 tiny_serial: - parity = even 01-01 08:07:11.850 <1>[ 180.292663] c0 tiny_serial: - stop bits = 1 01-01 08:07:11.859 <1>[ 180.297332] c0 tiny_serial: - RTS/CTS is disabled 01-01 08:07:11.859 <1>[ 180.302215] c0 tiny_serial: tiny_start_tx() ...... 01-01 08:07:13.022 <1>[ 181.246063] c0 tiny_serial: tiny_timer() 01-01 08:07:13.022 <1>[ 181.249908] c0 tiny_serial: tiny_tx_chars() 01-01 08:07:13.022 <1>[ 181.254089] c0 tiny_serial: wrote 0x68 01-01 08:07:13.022 <1>[ 181.257934] c0 tiny_serial: wrote 0x65 01-01 08:07:13.022 <1>[ 181.261718] c0 tiny_serial: wrote 0x6c 01-01 08:07:13.022 <1>[ 181.265563] c0 tiny_serial: wrote 0x6c 01-01 08:07:13.022 <1>[ 181.269409] c0 tiny_serial: wrote 0x6f 01-01 08:07:13.022 <1>[ 181.273193] c0 tiny_serial: wrote 0x2c 01-01 08:07:13.022 <1>[ 181.277038] c0 tiny_serial: wrote 0x20 01-01 08:07:13.022 <1>[ 181.280853] c0 tiny_serial: wrote 0x74 01-01 08:07:13.022 <1>[ 181.284667] c0 tiny_serial: wrote 0x69 01-01 08:07:13.022 <1>[ 181.288513] c0 tiny_serial: wrote 0x6e 01-01 08:07:13.022 <1>[ 181.292327] c0 tiny_serial: wrote 0x79 01-01 08:07:13.022 <1>[ 181.296173] c0 tiny_serial: wrote 0x20 01-01 08:07:13.022 <1>[ 181.299987] c0 tiny_serial: wrote 0x73 01-01 08:07:13.022 <1>[ 181.303802] c0 tiny_serial: wrote 0x65 01-01 08:07:13.022 <1>[ 181.307647] c0 tiny_serial: wrote 0x72 01-01 08:07:13.022 <1>[ 181.311462] c0 tiny_serial: wrote 0x69 01-01 08:07:13.022 <1>[ 181.315277] c0 tiny_serial: wrote 0x61 01-01 08:07:13.022 <1>[ 181.319122] c0 tiny_serial: wrote 0x6c 01-01 08:07:13.022 <1>[ 181.322937] c0 tiny_serial: wrote 0x20 01-01 08:07:13.022 <1>[ 181.326782] c0 tiny_serial: wrote 0x64 01-01 08:07:13.022 <1>[ 181.330566] c0 tiny_serial: wrote 0x72 01-01 08:07:13.022 <1>[ 181.334411] c0 tiny_serial: wrote 0x69 01-01 08:07:13.022 <1>[ 181.338256] c0 tiny_serial: wrote 0x76 01-01 08:07:13.022 <1>[ 181.342041] c0 tiny_serial: wrote 0x65 01-01 08:07:13.022 <1>[ 181.345886] c0 tiny_serial: wrote 0x72 01-01 08:07:13.022 <1>[ 181.349731] c0 tiny_serial: wrote 0x20 01-01 08:07:13.022 <1>[ 181.353515] c0 tiny_serial: wrote 0x21 01-01 08:07:13.022 <1>[ 181.357360] c0 tiny_serial: tiny_stop_tx() 01-01 08:07:13.022 <1>[ 181.361419] c0 tiny_serial: read: 0x68 01-01 08:07:13.022 <1>[ 181.365173] c0 tiny_serial: read: 0x65 01-01 08:07:13.022 <1>[ 181.368927] c0 tiny_serial: read: 0x6c 01-01 08:07:13.022 <1>[ 181.372650] c0 tiny_serial: read: 0x6c 01-01 08:07:13.022 <1>[ 181.376403] c0 tiny_serial: read: 0x6f 01-01 08:07:13.022 <1>[ 181.380126] c0 tiny_serial: read: 0x2c 01-01 08:07:13.022 <1>[ 181.383850] c0 tiny_serial: read: 0x20 01-01 08:07:13.022 <1>[ 181.387634] c0 tiny_serial: read: 0x74 01-01 08:07:13.022 <1>[ 181.391326] c0 tiny_serial: read: 0x69 01-01 08:07:13.022 <1>[ 181.395080] c0 tiny_serial: read: 0x6e 01-01 08:07:13.022 <1>[ 181.398834] c0 tiny_serial: read: 0x79 01-01 08:07:13.022 <1>[ 181.402557] c0 tiny_serial: read: 0x20 01-01 08:07:13.022 <1>[ 181.406311] c0 tiny_serial: read: 0x73 01-01 08:07:13.022 <1>[ 181.410034] c0 tiny_serial: read: 0x65 01-01 08:07:13.022 <1>[ 181.413757] c0 tiny_serial: read: 0x72 01-01 08:07:13.022 <1>[ 181.417572] c0 tiny_serial: read: 0x69 01-01 08:07:13.022 <1>[ 181.421234] c0 tiny_serial: read: 0x61 01-01 08:07:13.022 <1>[ 181.424987] c0 tiny_serial: read: 0x6c 01-01 08:07:13.022 <1>[ 181.428741] c0 tiny_serial: read: 0x20 01-01 08:07:13.022 <1>[ 181.432464] c0 tiny_serial: read: 0x64 01-01 08:07:13.022 <1>[ 181.436218] c0 tiny_serial: read: 0x72 01-01 08:07:13.022 <1>[ 181.439941] c0 tiny_serial: read: 0x69 01-01 08:07:13.022 <1>[ 181.443664] c0 tiny_serial: read: 0x76 01-01 08:07:13.022 <1>[ 181.447448] c0 tiny_serial: read: 0x65 01-01 08:07:13.022 <1>[ 181.451141] c0 tiny_serial: read: 0x72 01-01 08:07:13.022 <1>[ 181.454864] c0 tiny_serial: read: 0x20 01-01 08:07:13.022 <1>[ 181.458648] c0 tiny_serial: read: 0x21 01-01 08:07:13.022 <1>[ 181.462371] c0 tiny_serial: push to user space ! ...... 01-01 08:07:13.031 <1>[ 181.470153] c0 tiny_serial: tiny_set_termios() 01-01 08:07:13.031 <1>[ 181.474517] c0 tiny_serial: - data bits = 8 01-01 08:07:13.043 <1>[ 181.479492] c0 tiny_serial: - parity = none 01-01 08:07:13.043 <1>[ 181.483673] c0 tiny_serial: - stop bits = 1 ...... 01-01 08:07:13.052 <1>[ 181.490936] c0 tiny_serial: - RTS/CTS is disabled 01-01 08:07:13.052 <1>[ 181.495758] c0 tiny_serial: tiny_tx_empty() ...... 01-01 08:07:23.081 <1>[ 191.520050] c0 tiny_serial: tiny_stop_rx() 01-01 08:07:23.081 <1>[ 191.524078] c0 tiny_serial: tiny_tx_empty() 01-01 08:07:23.090 <1>[ 191.528594] c0 tiny_serial: tiny_set_mctrl() 01-01 08:07:23.090 <1>[ 191.532806] c0 tiny_serial: tiny_shutdown() ......