其实driver/tty/serial目录下有很多厂家自己的uart驱动,还有些是spi转串口的驱动。
不过这些都设计到外围硬件,我这里没有外围设备,只是自己模拟来玩的,以后用到硬件时候往里面加就行了,驱动如下:
/* * drivers/tty/serial/sw_uart.c * (C) Copyright 2007-2011 * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com> * Aaron.Maoye <[email protected]> * * description for this code * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/clk.h> #include <linux/gpio.h> #include <linux/delay.h> #include <linux/ctype.h> #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/platform_device.h> #include <linux/console.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial_core.h> #include <linux/workqueue.h> #include <linux/serial.h> #include <linux/module.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/console.h> #include <linux/sysrq.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/tty.h> #include <linux/ratelimit.h> #include <linux/tty_flip.h> #include <linux/serial_reg.h> #include <linux/serial_core.h> #include <linux/serial.h> #include <linux/nmi.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/clk.h> #include <linux/timer.h> #include <linux/workqueue.h> #include <linux/dma-mapping.h> #include <asm/io.h> #include <asm/irq.h> #define SW_UART_NR 8 static struct timer_list *timer; struct platform_device *pdev; struct work_struct q_work; struct workqueue_struct *workqueue; volatile static int force_enable_work; //当有硬件数据到来时,要手动调用该函数接收数据并上报 static void sw_uart_handle_rx(unsigned long data) { #if 1 struct uart_port * port; struct tty_struct *tty; unsigned char ch = 0; int i; int flag; char *send_buff = "i am sclu, this is from serial rx"; flag = TTY_NORMAL; printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); port = (struct uart_port *)data; if (!port) return; if (!port->state) return; tty = port->state->port.tty; //tty->flags |= TTY_HW_COOK_IN; //tty = port->info->tty; if (!tty) return; // for (i = 0; i < strlen(send_buff) + 1; i++) { //用tty_insert_flip_char函数也可以 // ch = send_buff[i]; // uart_insert_char(port, 0, 0, ch, flag); // } tty_insert_flip_string(tty, send_buff, strlen(send_buff) + 1); // uart_insert_char(port, 0, 0, '\n', flag); // uart_insert_char(port, 0, 0, '\t', 0); tty_flip_buffer_push(tty); #endif timer->expires = jiffies + 3 * HZ; add_timer(timer); } static void sw_uart_stop_tx(struct uart_port *port) { //del_timer(timer); printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } //上层用户空间写的数据最终调用该函数完成发送 static void sw_uart_start_tx(struct uart_port *port) { struct circ_buf *xmit = &port->state->xmit; // printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); //开始发送数据 if(!force_enable_work || uart_circ_empty(xmit) || uart_tx_stopped(port)) queue_work(workqueue, &q_work); } static unsigned int sw_uart_tx_empty(struct uart_port *port) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); //当硬件fifo中的数据发送完成后,要返回TIOCSER_TEMI,否则上层一直写等待,如echo数据一直没有返回 return TIOCSER_TEMT; } static void sw_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static unsigned int sw_uart_get_mctrl(struct uart_port *port) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); return 0; } static void sw_uart_stop_rx(struct uart_port *port) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static void sw_uart_enable_ms(struct uart_port *port) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static void sw_uart_break_ctl(struct uart_port *port, int break_state) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static int sw_uart_startup(struct uart_port *port) { /* this is the first time this port is opened */ /* do any hardware initialization needed here */ /* create our timer and submit it */ force_enable_work = 0; if (!timer) { timer = kmalloc(sizeof(*timer), GFP_KERNEL); if (!timer) return -ENOMEM; } setup_timer(timer, sw_uart_handle_rx, (unsigned long)port); timer->expires = jiffies + HZ * 3; #if 0 timer->data = (unsigned long)port; timer->expires = jiffies + DELAY_TIME; timer->function = tiny_timer; #endif add_timer(timer); printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); return 0; } static void sw_uart_shutdown(struct uart_port *port) { /* The port is being closed by the last user. */ /* Do any hardware specific stuff here */ /* shut down our timer */ printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); force_enable_work = 1; cancel_work_sync(&q_work); } static void sw_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static const char *sw_uart_type(struct uart_port *port) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); return "SW"; } static void sw_uart_release_port(struct uart_port *port) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static int sw_uart_request_port(struct uart_port *port) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); return 0; } static void sw_uart_config_port(struct uart_port *port, int flags) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static int sw_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); return 0; } static void sw_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); } static struct uart_driver sw_uart_driver; static struct uart_ops sw_uart_ops = { #if 1 .tx_empty = sw_uart_tx_empty, .set_mctrl = sw_uart_set_mctrl, .get_mctrl = sw_uart_get_mctrl, .stop_tx = sw_uart_stop_tx, .enable_ms = sw_uart_enable_ms, .break_ctl = sw_uart_break_ctl, .set_termios = sw_uart_set_termios, .type = sw_uart_type, .release_port = sw_uart_release_port, .request_port = sw_uart_request_port, .config_port = sw_uart_config_port, .verify_port = sw_uart_verify_port, .pm = sw_uart_pm, #endif .startup = sw_uart_startup, .start_tx = sw_uart_start_tx, .stop_rx = sw_uart_stop_rx, .shutdown = sw_uart_shutdown, }; static struct uart_port tiny_port = { .ops = &sw_uart_ops, .type = PORT_8250, .fifosize = 64, .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, }; #ifdef CONFIG_CONSOLE_POLL static void sw_console_write(struct console *co, const char *s, unsigned int count) { } static int __init sw_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 115200; int bits = 8; int parity = 'n'; int flow = 'n'; port = &tiny_port; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); return uart_set_options(port, co, baud, parity, bits, flow); } #endif static void tx_work(struct work_struct *work) { #if 1 struct uart_port *port = &tiny_port; struct circ_buf *xmit = &port->state->xmit; int count; // printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); if (port->x_char) { printk("x_char %2x", port->x_char); port->icount.tx++; port->x_char = 0; return; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { return; } count = port->fifosize / 2; // printk("sclu %s, count = %d\n", __func__, count); //发送数据 // serial_out(&sw_uport->port, xmit->buf[xmit->tail], SW_UART_THR); printk("get data:\n"); do { printk("%c", xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) { break; } } while (--count > 0); printk("\n"); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) { // spin_unlock(&port->lock); uart_write_wakeup(port); // spin_lock(&port->lock); } if (uart_circ_empty(xmit)) sw_uart_stop_tx(port); #endif } #ifdef CONFIG_CONSOLE_POLL static struct console sw_console = { .name = "ttyVirtual", .write = sw_console_write, .device = uart_console_device, .setup = sw_console_setup, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, .data = &sw_uart_driver, }; #define SERIAL_CONSOLE &sw_console #else #define SERIAL_CONSOLE NULL #endif static struct uart_driver sw_uart_driver = { .owner = THIS_MODULE, .driver_name = "Virtual_serial", .dev_name = "ttyVirtual", .nr = SW_UART_NR, .cons = SERIAL_CONSOLE, }; static int __devinit sw_uart_probe(struct platform_device *pdev) { printk("%s, %d, %s\n", __FILE__, __LINE__, __func__); workqueue = create_singlethread_workqueue("ttyVirtual_work"); INIT_WORK(&q_work, tx_work); return uart_add_one_port(&sw_uart_driver, &tiny_port); } static int __devexit sw_uart_remove(struct platform_device *pdev) { return 0; } #define SERIAL_SW_PM_OPS NULL static struct platform_driver sw_uport_platform_driver = { .probe = sw_uart_probe, .remove = __devexit_p(sw_uart_remove), .driver.name = "ttyVirtual", .driver.pm = SERIAL_SW_PM_OPS, .driver.owner = THIS_MODULE, }; static int __init sw_uart_init(void) { int ret; printk("serial driver initializied\n"); ret = uart_register_driver(&sw_uart_driver); if (unlikely(ret)) { printk("serial driver initializied err\n"); return ret; } pdev = platform_device_register_simple("ttyVirtual", 0, NULL, 0); return platform_driver_register(&sw_uport_platform_driver); } static void __exit sw_uart_exit(void) { if (timer) { del_timer(timer); timer = NULL; } if (workqueue) { flush_workqueue(workqueue); destroy_workqueue(workqueue); workqueue = NULL; } printk("driver exit\n"); uart_remove_one_port(&sw_uart_driver, &tiny_port); platform_driver_unregister(&sw_uport_platform_driver); if (pdev) platform_device_unregister(pdev); uart_unregister_driver(&sw_uart_driver); } module_init(sw_uart_init); module_exit(sw_uart_exit); MODULE_AUTHOR("Aaron<[email protected]>"); MODULE_DESCRIPTION("Driver for SW serial device"); MODULE_LICENSE("GPL");
#include <termios.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <jni.h> #include <assert.h> #include <errno.h> #include <sys/epoll.h> #include <pthread.h> #include <sys/socket.h> #include <utils/Log.h> #include <stdlib.h> static int epoll_register(int epoll_fd, int fd) { struct epoll_event ev; int ret, flags; /* important: make the fd non-blocking */ flags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, flags | O_NONBLOCK); //fcntl(fd, F_SETOWN, getpid()); //sclu add ev.events = EPOLLIN; ev.data.fd = fd; do { ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev); } while (ret < 0 && errno == EINTR); return ret; } int main(int argc, char **argv) { struct termios uart_termios; int baudrate = atoi(argv[2]); int epoll_fd = epoll_create(1); int ret, err; char read_buf[1024]; int fd = open(argv[1], O_RDWR|O_NOCTTY|O_NDELAY); if(fd < 0) { LOGE("open %s failure, err = %s\n", argv[1], strerror(errno)); return fd; } fcntl(fd, F_SETFL, 0); tcflush(fd, TCIOFLUSH); if ((err = tcgetattr(fd, &uart_termios)) != 0) { LOGE("tcgetattr %s, err = %s\n", argv[1], strerror(errno)); close(fd); return err; } uart_termios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); uart_termios.c_oflag &= ~OPOST; uart_termios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); uart_termios.c_cflag &= ~(CSIZE|PARENB); uart_termios.c_cflag |= CS8; uart_termios.c_cflag &= ~CRTSCTS;//no flow control tcsetattr(fd, TCSANOW, &uart_termios); tcflush(fd, TCIOFLUSH); tcsetattr(fd, TCSANOW, &uart_termios); tcflush(fd, TCIOFLUSH); if (cfsetispeed(&uart_termios, baudrate)) { LOGE("cfsetispeed, err = %s\n", strerror(errno)); close(fd); return fd; } if (cfsetospeed(&uart_termios, baudrate)) { LOGE("cfsetospeed err = %s\n", strerror(errno)); close(fd); return fd; } tcsetattr (fd, TCSANOW, &uart_termios); epoll_register(epoll_fd, fd); ret = write(fd, "$$$$", 4); LOGE("ret = %d", ret); if ((ret = read(fd, read_buf, sizeof(read_buf))) > 0) { int i; for (i = 0; i < ret; i++) { LOGE("read:%c", read_buf[i]); } LOGE("\n"); } for (;;) { struct epoll_event events[1]; int ne, nevents, ret, size; LOGE("poll start"); nevents = epoll_wait(epoll_fd, events, 1, -1); LOGE("poll get data"); if (nevents < 0) { if (errno != EINTR) LOGE("epoll_wait() unexpected error: %s", strerror(errno)); continue; } for (ne = 0; ne < nevents; ne++) { if ((events[ne].events & (EPOLLERR | EPOLLHUP)) != 0) { LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?\n"); return -1; } if ((events[ne].events & EPOLLIN) != 0) { int event_fd = events[ne].data.fd; int i; if (event_fd == fd) { ret = read(fd, read_buf, sizeof(read_buf)); if (ret) { LOGE("data:%s", read_buf); char *p = "this is from userspace!"; write(fd, p, strlen(p) + 1); } } } } } return 0; }
还有就是打开节点时候要设置串口信息,入上面测试代码所示,刚开始自己用 cat /dev/ttyVirtual来看信息,发现底层发送上来的数据到了tty核心层后,原样的发送回去了,虽然上层一样可以接收到,但不是想要的结果。
还有,linux系用已经为我们写好了serial_core.c架构,我们的串口设备只学要按照其格式实现相应的函数即可,不过我们也可以自己实现一个,只要实现相应的tty_operations结构体函数即可,然后把它注册到tty核心层中,以后自己的串口驱动如果不需要linux默认的serial_core,注册时候指定自己的tty driver即可。
代码如下,功能是往tty driver写入数据,然后原样发送回来:
#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/tty.h> #include <linux/fs.h> #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/ioport.h> #include <linux/serial_reg.h> #include <linux/slab.h> #include <linux/serial_core.h> #include <linux/serial.h> #include <linux/tty.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("sclu"); #define TTY_LAN_MINORS_NUM 1 #define TTY_LAN_MAJOR 240 static int open_count = 0; static struct tty_driver *tty_lan_driver; static struct tty_struct *tty_lan_struct; static int tty_lan_open(struct tty_struct *tty, struct file *filp); static void tty_lan_close(struct tty_struct *tty, struct file *filp); static int tty_lan_write(struct tty_struct *tty, const unsigned char *buffer, int count); static int tty_lan_write_room(struct tty_struct *tty); static void tty_lan_set_termios(struct tty_struct *tty, struct ktermios * old); static int tty_lan_put_char(struct tty_struct *tty, unsigned char ch); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static struct tty_operations tty_lan_ops = { .open = tty_lan_open, .close = tty_lan_close, .write = tty_lan_write, .put_char = tty_lan_put_char, .write_room = tty_lan_write_room, .set_termios = tty_lan_set_termios, .wait_until_sent = uart_wait_until_sent, }; static int __init tty_lan_init(void) { int i; int retval; tty_lan_driver = alloc_tty_driver(TTY_LAN_MINORS_NUM); if(!tty_lan_driver) return -ENOMEM; tty_lan_driver->owner = THIS_MODULE; tty_lan_driver->driver_name = "tty_sclu"; tty_lan_driver->name = "ttty_sclu"; tty_lan_driver->major = TTY_LAN_MAJOR, tty_lan_driver->minor_start = 0; tty_lan_driver->type = TTY_DRIVER_TYPE_SERIAL; tty_lan_driver->subtype = SERIAL_TYPE_NORMAL; //TTY_DRIVER_DYNAMIC_DEV标志表示手动注册device设备,在tty_io.c中会判断,如果没有该标志,会调用tty_register_device, //后续就不用再次注册device设备了 tty_lan_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_lan_driver->init_termios = tty_std_termios; tty_lan_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; tty_set_operations(tty_lan_driver, &tty_lan_ops); retval = tty_register_driver(tty_lan_driver); if(retval){ printk(KERN_ERR"Failed to register tty_lan_driver!\n"); put_tty_driver(tty_lan_driver); return retval; } tty_register_device(tty_lan_driver, 0, NULL); return 0; } static int tty_lan_open(struct tty_struct *tty, struct file *filp) { if(open_count == 0){ printk("Open OK!\n"); } tty_lan_struct = kmalloc(sizeof(struct tty_struct), GFP_KERNEL); tty->low_latency = 1; tty_lan_struct = tty; return 0; } static void tty_lan_close(struct tty_struct *tty, struct file *filp) { printk("ClOSE OK!\n"); kfree(tty_lan_struct); return; } static int tty_lan_write(struct tty_struct *tty, const unsigned char *buffer, int count) { int retval = count; tty = tty_lan_struct; printk(KERN_DEBUG "%s - \n", __FUNCTION__); printk("count :%d\n", count); printk("user write: %s ", buffer); printk("\n"); tty_insert_flip_string(tty, buffer, count); tty_flip_buffer_push(tty); return retval; } static int tty_lan_put_char(struct tty_struct *tty, unsigned char ch) { printk("%c", ch); return 0; } static int tty_lan_write_room(struct tty_struct *tty) { int room; room = 255; return room; } static void tty_lan_set_termios(struct tty_struct *tty, struct ktermios *old) { tty = tty_lan_struct; if(tty->termios->c_cflag == old->c_cflag){ printk("Nothing to change!\n"); return ; } printk("There is something to Change............\n"); return ; } static void uart_wait_until_sent(struct tty_struct *tty, int timeout) { struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; printk("%s, %d\n", __func__, __LINE__); } static void __exit tty_lan_exit(void) { int i; tty_unregister_device(tty_lan_driver, 0); tty_unregister_driver(tty_lan_driver); } module_init(tty_lan_init);