Line Disciplines

来源:互联网 发布:数控编程 过程 编辑:程序博客网 时间:2024/06/01 20:44
在Linux tty子系统中,Line Disciplines处在底层驱动与上层应用的之间,先来看一个例子:
#include <linux/init.h>#include <linux/module.h>#include <linux/tty.h>#include <linux/tty_ldisc.h>static int my_ldisc_tty_open(struct tty_struct *tty){printk("%s\n", __func__);if (tty->ops->write == NULL)return -EOPNOTSUPP;tty->disc_data = NULL;tty->receive_room = 65536;tty_driver_flush_buffer(tty);return 0;}static void my_ldisc_tty_close(struct tty_struct *tty){printk("%s\n", __func__);}static ssize_t my_ldisc_tty_read(struct tty_struct *tty, struct file *file,unsigned char __user *buf, size_t nr){printk("%s\n", __func__);return 0;}static ssize_t my_ldisc_tty_write(struct tty_struct *tty, struct file *flie,const unsigned char *buf, size_t nr){printk("%s %s\n", __func__, buf);int space = tty_write_room(tty);if (space >= nr)return tty->ops->write(tty, buf, nr);set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);return -ENOBUFS;}static void my_ldisc_tty_receive(struct tty_struct *tty, const u8 *data,char *flags, int count){int i;printk("%s\n", __func__);for (i = 0; i < count; i++)printk("%02x ", *data++);printk("\n");}static struct tty_ldisc_ops my_ldisc_ops = {.magic= TTY_LDISC_MAGIC,.owner= THIS_MODULE,.name= "my_ldisc",.open= my_ldisc_tty_open,.close= my_ldisc_tty_close,.read= my_ldisc_tty_read,.write= my_ldisc_tty_write,.receive_buf= my_ldisc_tty_receive,};static int __init my_ldisc_init(void){printk("%s\n", __func__);return tty_register_ldisc(N_MYLDISC, &my_ldisc_ops);}static void __exit my_ldisc_exit(void){printk("%s\n", __func__);tty_unregister_ldisc(N_MYLDISC);}module_init(my_ldisc_init);module_exit(my_ldisc_exit);MODULE_LICENSE("GPL");
注册一个ldisc驱动使用tty_register_ldisc()函数,注销使用tty_unregister_ldisc()函数,tty_register_ldisc()函数需要两个参数,第一个参数是一个数字编号,在tty.h中定义,如果你新增了一个ldisc驱动的话,需要定义一个数字编号。在串口应用用,如果你没有指定一个ldisc的话,默认使用的是N_TTY这个ldisc。另一个参数是操作接口,那么我们只需要实现这个接口中的一些函数就行了。

常用的接口函数有,open、close、read、write、receive_buf等。

在串口应用中,调用write系统调用时将触发这里的write接口,在write接口函数中,调用tty驱动的write函数将数据发送的串口中,这样串口数据就通过tx线缆发送出去了。可以看出ldisc相当于一个中转站,起到一个承上启下的作用。

如果串口电路收到数据,将触发这里的receive_buf接口,这里呢并没有做任何处理,只是简单将收到的数据给打印出来了。

ldisc驱动用在什么地方呢?通常用在在驱动层需要操作串口的地方,例如蓝牙的hci_ldisc.c、GSM的n_gsm.c都是这一类应用。


还有一个问题,在驱动层我们实际上是不知道我们到底操作的那个串口,这需要在串口应用层指定。代码如下:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/ioctl.h>#include <unistd.h>#include <termios.h>#define DEV_NAME"/dev/s3c2410_serial0"void tty_config(int fd){struct termios options;tcgetattr(fd, &options);cfsetispeed(&options, B115200);cfsetospeed(&options, B115200);options.c_cflag |= (CLOCAL | CREAD);options.c_cflag &= ~PARENB;options.c_cflag &= ~CSTOPB;options.c_cflag &= ~CSIZE;options.c_cflag |= CS8;options.c_cflag &= ~CRTSCTS;options.c_iflag &= ~(IXON | IXOFF | IXANY);tcsetattr(fd, TCSANOW, &options);}int main(void){int i, fd;char *tmp = "ldisc test\n";fd = open(DEV_NAME, O_RDWR | O_NOCTTY);if (fd < 0) {printf("open tty device error\n");exit(EXIT_FAILURE);}tty_config(fd);i = 20;if (ioctl(fd, TIOCSETD, &i)) {printf("set line discipline error\n");exit(EXIT_FAILURE);}for (i = 0; i < 10; i++)write(fd, tmp, strlen(tmp));while (1);close(fd);exit(EXIT_SUCCESS);}
在串口应用中,打开一个tty设备之后,使用ioctl来指定到底用哪一个ldisc,注意编号需要和底层驱动相对应。
0 0