linux 串口调用函数,[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_FS23   .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_POLL29   .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_SUPPORT25   .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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值