zoukankan      html  css  js  c++  java
  • [uart]2.tty和uart的函数调用流程

    以下是在include/uapi/linux/tty.h中定义了现有的线规号,如果需要定义新的,则需要在后面添加新的

    1 /* line disciplines */
    2 #define N_TTY        0
    3 #define N_SLIP        1
    4 ... ...
    5 #define N_TRACESINK    23    /* Trace data routing for MIPI P1149.7 */
    6 #define N_TRACEROUTER    24    /* Trace data routing for MIPI P1149.7 */

    1.应用层发送数据

    -->write()

      -->file_operation.tty_write                  /* file_operation函数集在何时被赋值? */

        -->do_tty_write(ld->ops->write, tty, file, buf, count)   /* tty_ldisc->tty_ldisc_ops->write */

          -->tty_ldisc_ops.ldisc_write /* tty_ldisc_ops函数集在何时被赋值? */ ///该write函数是在线路规程模块中定义

            -->tty->driver->ops->write (tty, tbuf->buf, tbuf->count) /* tty_struct->tty_driver->tty_operations->write */

              -->tty_operations.uart_write     /* tty_operation函数集在何时被赋值? */

                -->uart_start(tty);

                  -->__uart_start(tty);

                    -->port->ops->start_tx(port);  /* uart_port->uart_ops->start_tx */

                      -->uart_ops.imx_start_tx  /* uart_ops函数集在何时被赋值? */

    至此消息也发送出去了,从消息流程可以看出来消息是经过ldisc线路规程层,然后tty层,然后到硬件驱动层。

    上面的调用关系有个问题,为什么顺序是调到ldisc层,又调回tty层,再直接到hardware层?

    • file_operation.do_tty_write(ld->ops->write, tty, file, buf, count)::: tty_ldisc->ops->(*write)(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr);
    • tty_ldisc_ops.n_tty_write(struct tty_struct *tty, struct file *file,const unsigned char *buf, size_t nr):::tty->ops->write(tty, b, nr);  tty_operations->ops->(*write)(struct tty_struct * tty,const unsigned char *buf, int count)
    • tty_operations.uart_write(struct tty_struct * tty, const unsigned char *buf, int count )::: memcpy(circ->buf + circ->head, buf, c);
    • uart_ops.imx_start_tx(struct uart_port *port)::: writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);

    2.uart和tty逐层调用关系

    2.1.关于file_operation函数集的赋值

    • uart_register_driver函数中完成了file_operations和tty_operations函数集的初始化

    -->uart_register_driver(uart_driver*)  //uart driver驱动文件中

      -->tty_set_operations(normal, &uart_ops);//完成tty_operation赋值,serail_core.c中初始化结构体

      -->tty_register_driver(normal)

        -->tty_cdev_add(driver, dev, 0, driver->num);

          -->cdev_init(&driver->cdevs[index], &tty_fops);//而tty_fops为file_operations 类型,tty_io.c中初始化结构体

     1 /* drivers/tty/tty_io.c */
     2 static const struct file_operations tty_fops = {
     3   .llseek    = no_llseek,
     4   .read    = tty_read,
     5   .write    = tty_write,
     6   .poll    = tty_poll,
     7   .unlocked_ioctl    = tty_ioctl,
     8   .compat_ioctl    = tty_compat_ioctl,
     9   .open    = tty_open,
    10   .release    = tty_release,
    11   .fasync    = tty_fasync,
    12 };

    2.2.关于tty_operation函数集的赋值(同上)

    -->uart_register_driver(uart_driver*)  //uart driver驱动文件中

      -->tty_set_operations(normal, &uart_ops);  //完成tty_operation赋值,serial_core.c

      -->tty_register_driver(normal)

     1 /* drivers/tty/serial/serial_core.c */
     2 static const struct tty_operations uart_ops = {
     3   .open    = uart_open,
     4   .close    = uart_close,
     5   .write    = uart_write,
     6   .put_char    = uart_put_char,
     7   .flush_chars    = uart_flush_chars,
     8   .write_room    = uart_write_room,
     9   .chars_in_buffer= uart_chars_in_buffer,
    10   .flush_buffer    = uart_flush_buffer,
    11   .ioctl    = uart_ioctl,
    12   .throttle    = uart_throttle,
    13   .unthrottle    = uart_unthrottle,
    14   .send_xchar    = uart_send_xchar,
    15   .set_termios    = uart_set_termios,
    16   .set_ldisc    = uart_set_ldisc,
    17   .stop    = uart_stop,
    18   .start    = uart_start,
    19   .hangup    = uart_hangup,
    20   .break_ctl    = uart_break_ctl,
    21   .wait_until_sent= uart_wait_until_sent,
    22 #ifdef CONFIG_PROC_FS
    23   .proc_fops    = &uart_proc_fops,
    24 #endif
    25   .tiocmget    = uart_tiocmget,
    26   .tiocmset    = uart_tiocmset,
    27   .get_icount    = uart_get_icount,
    28 #ifdef CONFIG_CONSOLE_POLL
    29   .poll_init    = uart_poll_init,
    30   .poll_get_char    = uart_poll_get_char,
    31   .poll_put_char    = uart_poll_put_char,
    32 #endif
    33 };

    2.3.关于tty_ldisc_ops函数集的赋值

    -->tty_register_ldisc(ldisc, tty_ldisc_ops);  /* 此函数可以是在线路规程模块初始化时调用 */

      -->tty_ldiscs[disc] = tty_ldisc_ops;    /* 可见是tty_ldiscs中包含每个线路规程号对应的ops函数集, 假如是默认tty, 则在n_tty.c中,全局变量tty_ldisc_N_TTY */

    下面只是默认N_tty.c中默认线路规程号N_tty的例子,用户可以编写自己的线路规程模块,进行数据封装,有自己的方法集。

     1 /* drivers/tty/N_tty.c */
     2 struct tty_ldisc_ops tty_ldisc_N_TTY = {
     3   .magic = TTY_LDISC_MAGIC,
     4   .name = "n_tty",
     5   .open = n_tty_open,
     6   .close = n_tty_close,
     7   .flush_buffer = n_tty_flush_buffer,
     8   .chars_in_buffer = n_tty_chars_in_buffer,
     9   .read = n_tty_read,
    10   .write = n_tty_write,
    11   .ioctl = n_tty_ioctl,
    12   .set_termios = n_tty_set_termios,
    13   .poll = n_tty_poll,
    14   .receive_buf = n_tty_receive_buf,
    15   .write_wakeup = n_tty_write_wakeup,
    16   .fasync    = n_tty_fasync,
    17   .receive_buf2    = n_tty_receive_buf2,
    18 };

    2.4.关于uart_ops函数集赋值

    -->platform_driver_register(platform_driver*)

      -->serial_imx_probe()  //设备驱动匹配

        -->sport->port.ops = &imx_pops; //调用也是通过port口来调ops

    这里举的例子是freescale的串口方法集

     1 /* drivers/tty/serial/imx.c */
     2 static struct uart_ops imx_pops = {
     3   .tx_empty    = imx_tx_empty,
     4   .set_mctrl    = imx_set_mctrl,
     5   .get_mctrl    = imx_get_mctrl,
     6   .stop_tx    = imx_stop_tx,
     7   .start_tx    = imx_start_tx,
     8   .stop_rx    = imx_stop_rx,
     9   .enable_ms    = imx_enable_ms,
    10   .break_ctl    = imx_break_ctl,
    11   .startup    = imx_startup,
    12   .shutdown    = imx_shutdown,
    13   .flush_buffer    = imx_flush_buffer,
    14   .set_termios    = imx_set_termios,
    15   .type    = imx_type,
    16   .release_port = imx_release_port,
    17   .request_port = imx_request_port,
    18   .config_port    = imx_config_port,
    19   .verify_port    = imx_verify_port,
    20 #if defined(CONFIG_CONSOLE_POLL)
    21   .poll_get_char = imx_poll_get_char,
    22   .poll_put_char = imx_poll_put_char,
    23 #endif
    24 #ifdef CONFIG_IB2_SUPPORT
    25   .ioctl = imx_ioctl,
    26 #endif 
    27 };

     3.线路规程号配置

     3.1.Console的线路规程是怎么回事

    -->__init console_init(void)

       -->tty_ldisc_begin();  /* Setup the default TTY line discipline. */

          -->(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);  /* tty_ldisc_N_TTY中对应都是n_tty_**函数集 */

    3.2.那么其他串口的的线路规程默认是怎样的?也是N_TTY吗

     答案:是的,这要从应用层open设备文件开始说起

    亦可参考该链接:http://blog.csdn.net/rockrockwu/article/details/7897283

    -->open("/dev/ttys0",O_RDWR|O_NOCTTY);  /* app layer */

      -->tty_operations.tty_open

        -->tty_init_dev

          -->initialize_tty_struct

            -->tty_ldisc_init

              -->struct tty_ldisc *ld = tty_ldisc_get(N_TTY)

              -->struct tty_struct *tty->ldisc = ld;  /* 至此tty_struct和N_TTY绑定,该串口默认线路规程 */

    3.3.应用程序修改线路规程

    如果不适用默认的线路规程,需要在串口实现一些协议,那该如何做呢?--新建线路规程号,实现线路规程代码

    ioctl(fd, TIOCSETD, &ldisc);  //application:ldisc=25

    -->tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  /* tty_io.c*/

      -->tiocsetd(tty, p)

        -->tty_set_ldisc(tty, ldisc)

          -->tty->ldisc = new_ldisc;  /* Now set up the new line discipline. */

    至此完成了新的ldisc设置。

     4.推荐几个Linux uart的博客

    http://www.uml.org.cn/embeded/201209071.asp

    http://www.wowotech.net/linux_kenrel/183.html

    http://blog.csdn.net/goodluckwhh/article/details/13368279

  • 相关阅读:
    PostgreSQL新手入门
    nodejs获取当前url和url参数值
    nodejs怎么同步从一个数据库查询函数中返回一个值
    linux几种快速清空文件内容的方法
    Redis常用命令(二)
    解读vscode断点调试配置文件【待续】
    以下公司【勿扰】
    思维定律与法则
    运行项目报错183
    css counter的使用方法
  • 原文地址:https://www.cnblogs.com/aaronLinux/p/5602031.html
Copyright © 2011-2022 走看看