以下是在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