一、应用程序中write函数到底层驱动历程
和前文提到的一样,首先先注册串口,使用uart_register_driver函数,依次分别为tty_register_driver,cdev_init函数,找到使用的file_operations,即应用程序与tty架构的统一接口。步骤不再赘述。
static const struct file_operations tty_fops ={
.llseek=no_llseek,
.read=tty_read,
.write=tty_write,
.poll=tty_poll,
.unlocked_ioctl=tty_ioctl,
.compat_ioctl=tty_compat_ioctl,
.open=tty_open,
.release=tty_release,
.fasync=tty_fasync,
};
tty_write函数
static ssize_t tty_write(struct file *file, const char __user *buf,
size_t count, loff_t*ppos)
{struct inode *inode = file->f_path.dentry->d_inode;struct tty_struct *tty =file_tty(file);struct tty_ldisc *ld;
ssize_t ret;
...
ret= do_tty_write(ld->ops->write, tty, file, buf, count);
...
}
这里通过do_tty_write函数调用到了线路规程(ldisc)中的函数,结构名为tty_ldisc_N_TTY。
struct tty_ldisc_ops tty_ldisc_N_TTY ={
.magic=TTY_LDISC_MAGIC,
.name= "n_tty",
.open=n_tty_open,
.close=n_tty_close,
.flush_buffer=n_tty_flush_buffer,
.chars_in_buffer=n_tty_chars_in_buffer,
.read=n_tty_read,
.write=n_tty_write,
.ioctl=n_tty_ioctl,
.set_termios=n_tty_set_termios,
.poll=n_tty_poll,
.receive_buf=n_tty_receive_buf,
.write_wakeup=n_tty_write_wakeup
};
n_tty_write函数
static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,const unsigned char *buf, size_t nr)
{const unsigned char *b =buf;
DECLARE_WAITQUEUE(wait, current);intc;
ssize_t retval= 0;
...
c = tty->ops->write(tty, b, nr);
...
}
ops为struct tty_operations类型,由上文可知该结构名为
static const struct tty_operations uart_ops ={
....write=uart_write,
...};
uart_write函数
static int uart_write(struct tty_struct *tty,const unsigned char *buf, intcount)
{struct uart_state *state = tty->driver_data;struct uart_port *port;struct circ_buf *circ;
unsignedlongflags;int c, ret = 0;
...
uart_start(tty);
...
}
uart_start函数中又调用了__uart_start函数
static void __uart_start(struct tty_struct *tty)
{struct uart_state *state = tty->driver_data;struct uart_port *port = state->uart_port;if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&
!tty->stopped && !tty->hw_stopped)
port->ops->start_tx(port);
}
这里的port就是uart_port类型的了,终于到达底层驱动了,好累。。又是这个数组,同样的函数操作集
static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] ={
[0] ={
.port={
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype=UPIO_MEM,
.irq=IRQ_S3CUART_RX0,
.uartclk= 0,
.fifosize= 16,
.ops= &s3c24xx_serial_ops,
.flags=UPF_BOOT_AUTOCONF,
.line= 0,
}
},
...
}
所以在底层驱动与之对应的就是s3c24xx_serial_start_tx这个函数。层层追溯下来,最终与应用程序中的write函数千里相会。。。
static void s3c24xx_serial_start_tx(struct uart_port *port)
{struct s3c24xx_uart_port *ourport =to_ourport(port);if (!tx_enabled(port)) {if (port->flags &UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
enable_irq(ourport->tx_irq);
tx_enabled(port)= 1;
}
}
但是要让各位看官失望了。这个函数很简单,功能上来说就是如果没有打开发送使能就去打开。那么串口驱动又是在什么地方去完成发送数据相关的操作呢?
预知后事如何,且听下回分析。
如果有疑问或建议,欢迎指出。
原文:http://www.cnblogs.com/51qianrushi/p/4324845.html