微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > Linux下的串口总线驱动(二)

Linux下的串口总线驱动(二)

时间:11-22 来源:互联网 点击:
四.TTY层内核代码

TTY驱动程序有三种:控制台、串口和pty。在此我们主要分析Mini2440串口驱动。

我们现在跟踪uart_register_driver和uart_add_one_port发现,他们的原函数定义在TTY层驱动serial_core.o中。

int uart_register_driver(struct uart_driver *drv)

{

struct tty_driver *normal = NULL;

int i, retval;

BUG_ON(drv->state);

drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);

retval = -ENOMEM;

if (!drv->state)

goto out;

normal = alloc_tty_driver(drv->nr); //分配TTY驱动

if (!normal)

goto out;

drv->tty_driver = normal;

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;

normal->subtype = SERIAL_TYPE_NORMAL;

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状态

struct uart_state *state = drv->state + i;

struct tty_port *port = &state->port;

tty_port_init(port);

port->close_delay = 500;

port->closing_wait = 30000;

tasklet_init(&state->tlet, uart_tasklet_action,

(unsigned long)state);

}

retval = tty_register_driver(normal); //注册TTY驱动

out:

if (retval < 0) {

put_tty_driver(normal);

kfree(drv->state);

}

return retval;

}

在上面uart_register_driver这个函数里我们首先分配了TTY驱动,然后对其进行填充,初始的termios,并设置TTY驱动操作,最后注册TTY驱动。其中设置TTY驱动操作时用到uart_ops,我们看看这个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,

#ifdef CONFIG_CONSOLE_POLL

.poll_init = uart_poll_init,

.poll_get_char = uart_poll_get_char,

.poll_put_char = uart_poll_put_char,

#endif

};

终端设备可以完成收发数据的功能,当用户在有数据发送给终端设备时候,通过”write()系统调用—tty核心—线路规程”的层层调用,最终调用tty_driver结构体中的write()函数完成发送。因为传输速度和tty硬件缓冲区容量的原因,不是所有的写程序要求的字符都可以在调用写函数时候被发送出去,因此,写函数应当返回能够发给硬件的字节数以便用户程序检查是否所有的数据被真正写入。如果在write()调用期间发生任何错误,一个负的错误码应当被返回。在上面的uart_ops结构体中,我们先看看写函数uart_write的实现吧。

static int uart_write(struct tty_struct *tty, const unsigned char *buf, int count)

{

struct uart_state *state = tty->driver_data; //获取设备私有信息结构体

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端口

circ = &state->xmit; //数据缓冲区

if (!circ->buf)

return 0;

spin_lock_irqsave(&port->lock, flags); //获取UART端口操作的锁

while (1) {

//返回可用缓存空间的大小

c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top