//Linux kernel release 2.6.xx
//linux uart 驱动中接收和发送函数的调用层次,记录如下:
module_init(s3c24xx_serial_modinit); //drivers/serial/samsung.c
uart_register_driver(&s3c24xx_uart_drv);
tty_register_driver(normal); //drivers/serial/serial_core.c
cdev_init(&driver->cdev, &tty_fops); //drivers/char/tty_io.c 注册字符设备,指定fops
//进入参数tty_fops中,在tty_fops中有
**//1. open ---> tty_open(tty_ops里面的) ---> uart_open(uart_ops里面的) ---> uart_start**
open //应用层。 tty_fops中有 .open = tty_open
tty_open //drivers/char/tty_io.c。tty_open函数中有 tty->ops->open(tty, filp); ops是:tty_operations结构指针
uart_open //serial/serial_core.c中有static const struct tty_operations uart_ops = {
//.open = uart_open,
uart_startup(state, 0); //uport是struct uart_port结构。 在struct uart_port (一个串口)中,ops类型是 struct
// uart_ops结构此函数中有 uport->ops->startup(uport);
// .startup = s3c24xx_serial_startup, (在drivers/serial/samsung.c结构
// static struct uart_ops s3c24xx_serial_ops = { 中)
//在probe函数中,.probe = s5p_serial_probe, --> s3c24xx_serial_probe(pdev, s5p_uart_inf[pdev->id]);
//在s3c24xx_serial_probe函数中,获取端口 ourport = &s3c24xx_serial_ports[dev->id];
//在数组s3c24xx_serial_ports中包含了函数集 .ops= &s3c24xx_serial_ops,
s3c24xx_serial_startup, //使能串口中断、串口时钟
request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,s3c24xx_serial_portname(port), ourport);
//指定串口中断函数
request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,s3c24xx_serial_portname(port), ourport);
s3c24xx_serial_rx_chars //直接读寄存器
**// 2. 写调用流程为 write---> tty_write ---> n_tty_write(线路规程里面) ---> uart_write ---> uart_start --> __uart_start --> 进入函数s3c24xx_serial_rx_chars**
write
tty_write
do_tty_write(ld->ops->write, tty, file, buf, count); //参数 ld->ops->write; struct tty_ldisc *ld;
//进入结构tty_ldisc,里面包含struct tty_ldisc { struct tty_ldisc_ops *ops; ... };
struct tty_ldisc_ops tty_ldisc_N_TTY = {
.write = n_tty_write, //调用n_tty_write
n_tty_write() //函数中有 tty->ops->write(tty, b, nr); ,tty是tty_struct类型。 进入tty_struct中的 struct tty_operations *ops中
//struct tty_operations uart_ops = { .write = uart_write,
uart_write()
uart_start()
__uart_start() //此函数中有 port->ops->start_tx(port);
//进入ops结构中 .start_tx = s3c24xx_serial_start_tx,
//使能发送
s3c24xx_serial_tx_chars() //使能后自动调用中断发送函数
**//3. 读调用流程为**
read
tty_read // if (ld->ops->read) ; struct tty_ldisc *ld;
//进入结构 tty_ldisc ,里面包含struct tty_ldisc { struct tty_ldisc_ops *ops; ... };
struct tty_ldisc_ops tty_ldisc_N_TTY = {
.read = n_tty_read,
n_tty_read
copy_from_read_buf(struct tty_struct *tty, unsigned char __user **b, size_t *nr)
copy_to_user(*b, &tty->read_buf[tty->read_tail], n); //从read_buf读数据,当驱动里面有数据的时候,驱动就将数据往 read_buf 里面送
//
s3c24xx_serial_rx_chars(中断函数)
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,ch, flag); /* 9. 将接收到的字符发送到串口驱动的buf(tty->tty_bufhead中) */
tty_insert_flip_char(tty, ch, flag);
tb->char_buf_ptr[tb->used++] = ch; //struct tty_buffer *tb = tty->buf.tail;
tty_flip_buffer_push(tty); /*serial/samsung.c 10. 把串口驱动收到的数据发送到线路规程的 read_buf */
flush_to_ldisc(&tty->buf.work.work); //tty_buffer.c 402行
disc->ops->receive_buf(); //struct tty_ldisc *disc;
进入结构tty_ldisc
struct tty_ldisc {
struct tty_ldisc_ops *ops;
};
进入结构 tty_ldisc_ops
struct tty_ldisc_ops tty_ldisc_N_TTY = { //char/n_tty.c
.receive_buf = n_tty_receive_buf,
n_tty_receive_buf()
n_tty_receive_break()
put_tty_queue()
put_tty_queue_nolock()
tty->read_buf[tty->read_head] = c;
综上,中断函数中获取数据的调用层次为:s3c24xx_serial_rx_chars()--->uart_insert_char()---->tty_insert_flip_char()
-->tty_flip_buffer_push()-->flush_to_ldisc()--->n_tty_receive_buf()--->n_tty_receive_char()
linux uart 驱动中 open、read、write调用层次
最新推荐文章于 2023-06-26 20:46:11 发布