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

 /* line disciplines */
#define N_TTY 0
#define N_SLIP 1
... ...
#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */
#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中初始化结构体

 /* drivers/tty/tty_io.c */
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,
};

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)

 /* drivers/tty/serial/serial_core.c */
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.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的例子,用户可以编写自己的线路规程模块,进行数据封装,有自己的方法集。

 /* drivers/tty/N_tty.c */
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,
  .fasync = n_tty_fasync,
  .receive_buf2 = n_tty_receive_buf2,
};

2.4.关于uart_ops函数集赋值

-->platform_driver_register(platform_driver*)

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

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

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

 /* drivers/tty/serial/imx.c */
static struct uart_ops imx_pops = {
  .tx_empty = imx_tx_empty,
  .set_mctrl = imx_set_mctrl,
  .get_mctrl = imx_get_mctrl,
  .stop_tx = imx_stop_tx,
  .start_tx = imx_start_tx,
  .stop_rx = imx_stop_rx,
  .enable_ms = imx_enable_ms,
  .break_ctl = imx_break_ctl,
  .startup = imx_startup,
  .shutdown = imx_shutdown,
  .flush_buffer = imx_flush_buffer,
  .set_termios = imx_set_termios,
  .type = imx_type,
  .release_port = imx_release_port,
  .request_port = imx_request_port,
  .config_port = imx_config_port,
  .verify_port = imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
  .poll_get_char = imx_poll_get_char,
  .poll_put_char = imx_poll_put_char,
#endif
#ifdef CONFIG_IB2_SUPPORT
  .ioctl = imx_ioctl,
#endif
};

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

[uart]2.tty和uart的函数调用流程的更多相关文章

  1. [tty与uart]2.tty和uart的函数调用流程

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

  2. [tty与uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  3. [uart]3.tty驱动分析

    转自:http://www.wowotech.net/linux_kenrel/183.html 目录: 1 首先分析设备驱动的注册 1.1 uart_register_driver分析 1.2 tt ...

  4. [tty与uart]1.Linux中tty框架与uart框架之间的调用关系剖析

    转自:http://developer.51cto.com/art/201209/357501_all.htm 目录 1.tty框架 2.uart框架 3.自底向上 4.自顶向下 5.关系图 在这期间 ...

  5. tty初探 — uart驱动框架分析

    写在前面: 我们没有讲UART驱动,不过我们认为,只要系统学习了第2期,应该具备分析UART驱动的能力,小编做答疑几年以来,陆陆续续有不少人问到UART驱动怎么写,所以今天就分享一篇深度长文(1700 ...

  6. [tty与uart]UART中的硬件流控RTS与CTS

    转自:http://blog.csdn.net/zeroboundary/article/details/8966586 在RS232中本来CTS 与RTS 有明确的意义,但自从贺氏(HAYES ) ...

  7. [tty与uart]理解线路规程的作用

    转自:http://biancheng.dnbcw.info/linux/336240.html Linux OS的设备驱动有相当经典的抽象思想以及分层思想.与通信世界里面的思想相一致. 一.在Lin ...

  8. [tty与uart]stty命令使用

    中文解释链接:http://linux.51yip.com/search/stty 英文解释链接:http://pubs.opengroup.org/onlinepubs/9699919799/uti ...

  9. s3c2440裸机-UART编程(二、UART编程实现)

    UART编程 1.初始化 我们的2440支持3个UART串口,以uart0为例讲解. 那么我们需要实现以下这几个函数完成串口的最基本功能: (1)uart0_init()用于初始化串口 (2)putc ...

随机推荐

  1. 更改npm全局模块和cache默认安装位置

    来源于:http://blog.csdn.net/friendan/article/details/51736231 1.因为我安装的Node.js自带了npm,所以在nodejs文件夹里面新建以下两 ...

  2. 深入了解PHP闭包的使用以及实现

    一.介绍 匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数.最经常用作回调函数(callback)参数的值.当然,也有其它应用 ...

  3. python中如何对list之间求交集,并集和差集

    最近遇到一个从list a里面去除list b的元素的问题,由于a很大,b也不小.所以遇到点困难,现在mark一下. 先说最简单的方法: a = [1, 2, 3, 4, 5, 6, 7, 8, 9, ...

  4. iOS - App 应用

    1.Xcode 项目属性 Product Name 软件名称.产品名称.项目名称 Organization Name 公司名称.组织名称 Organization Identifier 公司的唯一标识 ...

  5. oracle中的一些基本概念

    Oracle数据库的物理文件是存储在磁盘上的数据文件.控制文件和日志文件的总称.数据文件和日志文件是数据库中最重要的文件.数据库由若干个表空间组成,表空间由表组成,表由段组成,段由区间组成,区间由数据 ...

  6. 图解最小生成树 - 克鲁斯卡尔(Kruskal)算法

    我们在前面讲过的<克里姆算法>是以某个顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树的.同样的思路,我们也可以直接就以边为目标去构建,因为权值为边上,直接找最小权值的边来构建生成树 ...

  7. Linux内存初始化(四) 创建系统内存地址映射

    一.前言 经过内存初始化代码分析(一)和内存初始化代码分析(二)的过渡,我们终于来到了内存初始化的核心部分:paging_init.当然本文不能全部解析完该函数(那需要的篇幅太长了),我们只关注创建系 ...

  8. org.hibernate.MappingException: entity class not found hbm可以解析,但是实体类不能解析

    在hbm.xml中给实体类加上包  com.we.lkl.studentVO

  9. mysql查询-不存在记录时赋对应的数据

    使用mysql数据库,执行查询的时候,有时候就不存在记录,但是正好在不存在记录的时候又需要给赋予相应的查询结果字段,代码实现如下: select IFNULL(('), '1970-01-01 00: ...

  10. Scala first trial

    scala是一种将面向对象和函数式编程相结合的语言,在spark中大显身手,在大数据时代下,不会scala都不敢说自己是搞大数据的.前段时间参加BDTC2014大数据会议时,spark的贡献者,陈超老 ...