一.串口结构体
1.串口驱动结构体
struct uart_driver { struct module *owner; //模块所有者 const char *driver_name; //驱动名 const char *dev_name; //设备名 int major; //主设备号 int minor; //次设备号 int nr; //支持串口个数 struct console *cons; //控制台设备 struct uart_state *state; //串口状态 struct tty_driver *tty_driver; //tty设备 };
2.串口端口结构体
struct uart_port { spinlock_t lock; unsigned long iobase; //io端口基地址 unsigned char __iomem *membase; //内存端口基地址 unsigned int (*serial_in)(struct uart_port *, int); void (*serial_out)(struct uart_port *, int, int); void (*set_termios)(struct uart_port *,struct ktermios *new,struct ktermios *old); void (*pm)(struct uart_port *, unsigned int state,unsigned int old); unsigned int irq; //中断号 unsigned long irqflags; //中断标志 unsigned int uartclk; unsigned int fifosize; //fifo大小 unsigned char x_char; unsigned char regshift; //寄存器偏移值 unsigned char iotype; //io访问类型 unsigned char unused1; unsigned int read_status_mask; unsigned int ignore_status_mask; struct uart_state *state; //uart_state结构体 struct uart_icount icount; //串口使用计数 struct console *cons; //console控制台 #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ) unsigned long sysrq; #endif upf_t flags; unsigned int mctrl; unsigned int timeout; unsigned int type; const struct uart_ops *ops; //串口操作函数集 unsigned int custom_divisor; unsigned int line; //端口号 resource_size_t mapbase; struct device *dev; //设备文件 unsigned char hub6; unsigned char suspended; unsigned char irq_wake; unsigned char unused[2]; void *private_data; };
3.操作函数集
struct uart_ops { unsigned int (*tx_empty)(struct uart_port *); //发送缓冲区为空 void (*set_mctrl)(struct uart_port *, unsigned int mctrl); //设置串口modem控制模式 unsigned int (*get_mctrl)(struct uart_port *); //获取串口modem控制模式 void (*stop_tx)(struct uart_port *); //停止发送 void (*start_tx)(struct uart_port *); //开始发送 void (*send_xchar)(struct uart_port *, char ch); void (*stop_rx)(struct uart_port *); //停止接收 void (*enable_ms)(struct uart_port *); //使能modem状态信息 void (*break_ctl)(struct uart_port *, int ctl); int (*startup)(struct uart_port *); //打开串口 void (*shutdown)(struct uart_port *); //关闭串口 void (*flush_buffer)(struct uart_port *); void (*set_termios)(struct uart_port *, struct ktermios *new,struct ktermios *old); //设置串口参数 void (*set_ldisc)(struct uart_port *, int new); void (*pm)(struct uart_port *, unsigned int state,unsigned int oldstate); int (*set_wake)(struct uart_port *, unsigned int state); const char *(*type)(struct uart_port *); void (*release_port)(struct uart_port *); //释放端口 int (*request_port)(struct uart_port *); //请求端口 void (*config_port)(struct uart_port *, int); //配置端口 int (*verify_port)(struct uart_port *, struct serial_struct *); //校验端口 int (*ioctl)(struct uart_port *, unsigned int, unsigned long); //控制 #ifdef CONFIG_CONSOLE_POLL void (*poll_put_char)(struct uart_port *, unsigned char); int (*poll_get_char)(struct uart_port *); #endif };
4.uart_state
struct uart_state { struct tty_port port; int pm_state; struct circ_buf xmit; struct tasklet_struct tlet; struct uart_port *uart_port; };
二.串口驱动的注册与注销
注册
int uart_register_driver(struct uart_driver *drv) { struct tty_driver *normal; int i, retval; BUG_ON(drv->state); drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL); //分配uart_state内存 if (!drv->state) goto out; normal = alloc_tty_driver(drv->nr); //分配tty_driver if (!normal) goto out_kfree; drv->tty_driver = normal; //tty_driver和uart_driver捆绑 normal->owner = drv->owner; //模块所有者 normal->driver_name = drv->driver_name; //驱动名 normal->name = drv->dev_name; //设备名 normal->major = drv->major; //主设备号 normal->minor_start = drv->minor; //次设备号 normal->type = TTY_DRIVER_TYPE_SERIAL; //tty类型 normal->subtype = SERIAL_TYPE_NORMAL; //tty子类型 normal->init_termios = tty_std_termios; //termios结构体 normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //设置默认串口信息 normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; //波特率 normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; normal->driver_state = drv; tty_set_operations(normal, &uart_ops); //设置tty操作函数集 for (i = 0; i < drv->nr; i++) { //初始化uart_state struct uart_state *state = drv->state + i; struct tty_port *port = &state->port; tty_port_init(port); //初始化tty端口 port->ops = &uart_port_ops; //tty端口操作函数集 port->close_delay = 500; /* .5 seconds */ port->closing_wait = 30000; /* 30 seconds */ tasklet_init(&state->tlet, uart_tasklet_action,(unsigned long)state); } retval = tty_register_driver(normal); //注册tty驱动 if (retval >= 0) return retval; put_tty_driver(normal); //引用计数 out_kfree: kfree(drv->state); out: return -ENOMEM; }
注销
void uart_unregister_driver(struct uart_driver *drv) { struct tty_driver *p = drv->tty_driver; tty_unregister_driver(p); //注销tty驱动 put_tty_driver(p); //减少引用计数 kfree(drv->state); drv->tty_driver = NULL; }
三.端口注册与注销
注册
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) { struct uart_state *state; struct tty_port *port; int ret = 0; struct device *tty_dev; BUG_ON(in_interrupt()); if (uport->line >= drv->nr) return -EINVAL; state = drv->state + uport->line; //获取uart_state port = &state->port; //获取tty_port mutex_lock(&port_mutex); mutex_lock(&port->mutex); if (state->uart_port) { ret = -EINVAL; goto out; } state->uart_port = uport; //设置uart_state->uart_port state->pm_state = -1; uport->cons = drv->cons; //设置uart_port->cons控制台 uport->state = state; //设置uart_port->state if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { spin_lock_init(&uport->lock); lockdep_set_class(&uport->lock, &port_lock_key); } uart_configure_port(drv, state, uport); //配置端口 tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev); //生成tty设备文件/dev/ttyXXX if (likely(!IS_ERR(tty_dev))) { device_init_wakeup(tty_dev, 1); device_set_wakeup_enable(tty_dev, 0); } else printk(KERN_ERR "Cannot register tty device on line %d\n",uport->line); uport->flags &= ~UPF_DEAD; out: mutex_unlock(&port->mutex); mutex_unlock(&port_mutex); return ret; }
uart_configure_port
static void uart_configure_port(struct uart_driver *drv, struct uart_state *state,struct uart_port *port) { unsigned int flags; if (!port->iobase && !port->mapbase && !port->membase) return; flags = 0; if (port->flags & UPF_AUTO_IRQ) //设置可中断标志 flags |= UART_CONFIG_IRQ; if (port->flags & UPF_BOOT_AUTOCONF) { //设置自动配置标志 if (!(port->flags & UPF_FIXED_TYPE)) { port->type = PORT_UNKNOWN; flags |= UART_CONFIG_TYPE; } port->ops->config_port(port, flags); //调用uart_port的config_port方法 } if (port->type != PORT_UNKNOWN) { unsigned long flags; uart_report_port(drv, port); uart_change_pm(state, 0); spin_lock_irqsave(&port->lock, flags); port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); //调用uart_port的set_mctrl方法 spin_unlock_irqrestore(&port->lock, flags); if (port->cons && !(port->cons->flags & CON_ENABLED)) //若console存在且设置了CON_ENABLED标志 register_console(port->cons); //注册控制台设备 if (!uart_console(port)) uart_change_pm(state, 3); } }
注销
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport) { struct uart_state *state = drv->state + uport->line; struct tty_port *port = &state->port; BUG_ON(in_interrupt()); if (state->uart_port != uport) printk(KERN_ALERT "Removing wrong port: %p != %p\n",state->uart_port, uport); mutex_lock(&port_mutex); mutex_lock(&port->mutex); uport->flags |= UPF_DEAD; mutex_unlock(&port->mutex); tty_unregister_device(drv->tty_driver, uport->line); if (port->tty) tty_vhangup(port->tty); if (uport->type != PORT_UNKNOWN) uport->ops->release_port(uport); uport->type = PORT_UNKNOWN; tasklet_kill(&state->tlet); state->uart_port = NULL; mutex_unlock(&port_mutex); return 0; }
四.串口对应的tty_driver的操作函数集
1.tty的操作函数集uart_ops
static const struct tty_operations uart_ops = { .open = uart_open, .close = uart_close, .write = uart_write, .put_char = uart_put_char, .flush_chars = uart_flush_chars, .write_room = uart_write_room, .chars_in_buffer= uart_chars_in_buffer, .flush_buffer = uart_flush_buffer, .ioctl = uart_ioctl, .throttle = uart_throttle, .unthrottle = uart_unthrottle, .send_xchar = uart_send_xchar, .set_termios = uart_set_termios, .set_ldisc = uart_set_ldisc, .stop = uart_stop, .start = uart_start, .hangup = uart_hangup, .break_ctl = uart_break_ctl, .wait_until_sent= uart_wait_until_sent, #ifdef CONFIG_PROC_FS .proc_fops = &uart_proc_fops, #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, .get_icount = uart_get_icount, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, .poll_get_char = uart_poll_get_char, .poll_put_char = uart_poll_put_char, #endif };
2.open方法
static int uart_open(struct tty_struct *tty, struct file *filp) { struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; struct uart_state *state; struct tty_port *port; int retval, line = tty->index; BUG_ON(!tty_locked()); pr_debug("uart_open(%d) called\n", line); retval = -ENODEV; if (line >= tty->driver->num) goto fail; state = uart_get(drv, line); //获取uart_state if (IS_ERR(state)) { retval = PTR_ERR(state); goto fail; } port = &state->port; //获取tty_port tty->driver_data = state; state->uart_port->state = state; tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; tty->alt_speed = 0; tty_port_tty_set(port, tty); if (tty_hung_up_p(filp)) { retval = -EAGAIN; port->count--; mutex_unlock(&port->mutex); goto fail; } if (port->count == 1) uart_change_pm(state, 0); retval = uart_startup(tty, state, 0); //启动串口 mutex_unlock(&port->mutex); if (retval == 0) retval = tty_port_block_til_ready(port, tty, filp); fail: return retval; }
uart_startup
static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) { struct uart_port *uport = state->uart_port; //获取uart_port struct tty_port *port = &state->port; //获取tty_port unsigned long page; int retval = 0; if (port->flags & ASYNC_INITIALIZED) return 0; set_bit(TTY_IO_ERROR, &tty->flags); if (uport->type == PORT_UNKNOWN) return 0; if (!state->xmit.buf) { /* This is protected by the per port mutex */ page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM; state->xmit.buf = (unsigned char *) page; uart_circ_clear(&state->xmit); } retval = uport->ops->startup(uport); //调用uart_port的startup方法 if (retval == 0) { if (init_hw) { uart_change_speed(tty, state, NULL); if (tty->termios->c_cflag & CBAUD) uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); } if (port->flags & ASYNC_CTS_FLOW) { spin_lock_irq(&uport->lock); if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) tty->hw_stopped = 1; spin_unlock_irq(&uport->lock); } set_bit(ASYNCB_INITIALIZED, &port->flags); clear_bit(TTY_IO_ERROR, &tty->flags); } if (retval && capable(CAP_SYS_ADMIN)) retval = 0; return retval; }
3.写方法
static int uart_write(struct tty_struct *tty,const unsigned char *buf, int count) { struct uart_state *state = tty->driver_data; //获取uart_state struct uart_port *port; struct circ_buf *circ; unsigned long flags; int c, ret = 0; if (!state) { WARN_ON(1); return -EL3HLT; } port = state->uart_port; //获取uart_port circ = &state->xmit; if (!circ->buf) return 0; spin_lock_irqsave(&port->lock, flags); while (1) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); if (count < c) c = count; if (c <= 0) break; memcpy(circ->buf + circ->head, buf, c); circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); buf += c; count -= c; ret += c; } spin_unlock_irqrestore(&port->lock, flags); uart_start(tty); //调用uart_start方法 return ret; }
uart_start
static void uart_start(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; //获取tty_state struct uart_port *port = state->uart_port; //获取uart_port unsigned long flags; spin_lock_irqsave(&port->lock, flags); __uart_start(tty); //调用__uart_start函数 spin_unlock_irqrestore(&port->lock, flags); }
uart_start>>>__uart_start
static void __uart_start(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; //获取uart_state struct uart_port *port = state->uart_port; //获取uart_port if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&!tty->stopped && !tty->hw_stopped) port->ops->start_tx(port); //调用uart_port的start_tx方法 }