您的位置 首页 模拟

打通linux的tty驱动的数据链路

一、首先把tty驱动在linux中的分层结构理清楚:自上而下分为TTY核心层、TTY线路规程、TTY驱动。二、TTY核心层与线路规程层分析用户空间的程序直接对tty

一、首先把tty驱动在linux中的分层结构理清楚:

.

自上而下分为TTY核心层、TTY线路规程、TTY驱动。

二、TTY核心层与线路规程层剖析

用户空间的程序直接对tty核心层进行读写等相关操作,在tty_io.c中:

int__init tty_init(void)

{

cdev_init(tty_cdev,tty_fops);

if(cdev_add(tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||

register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, /dev/tty) 0)

panic(Couldn’tregister /dev/tty driver\n);

device_create(tty_class,NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, tty);

………

以上的一段初始化代码能够获取以下信息:

注册了一个字符驱动,用户空间操作对应到tty_fops结构体里的函数:

staticconst 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,

};

关于字符设备驱动,咱们知道,读写操作一一对应于fops.

tty_open:

static int tty_open(struct inode *inode, struct file *filp)

{

int index;

dev_tdevice = inode->i_rdev;

structtty_driver *driver;

……

driver= get_tty_driver(device, index);

……

tty= tty_init_dev(driver, index, 0);

……

retval= tty_add_file(tty, filp);

……

if(tty->ops->open)

retval= tty->ops->open(tty, filp);

get_tty_driver是依据设备号device,通过查找tty_drivers大局链表来查找tty_driver.

tty_init_dev是初始化一个tty结构体:

tty->driver= driver;

tty->ops= driver->ops;

并树立线路规程:

ldops= tty_ldiscs[N_TTY];

ld->ops= ldops;

tty->ldisc= ld;

其实tty_ldiscs[N_TTY]在console_init中确认,该函数在内核发动的时分调用。

tty_register_ldisc(N_TTY,tty_ldisc_N_TTY);

则:tty_ldiscs[N_TTY]=tty_ldisc_N_TTY;

struct tty_ldisc_ops tty_ldisc_N_TTY = {

。magic = TTY_LDISC_MAG%&&&&&%,

。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

};

tty_add_file主要是将tty保存到file的私有变量private_data中。

tty->ops->open的调用,实则上便是使用driver->ops->open.这样,咱们就从tty核心层到tty驱动层了。

tty_write:

static ssize_t tty_write(struct file *file, const char __user *buf,

size_t count, loff_t *ppos)

{

………

ld= tty_ldisc_ref_wait(tty);

if(!ld->ops->write)

ret= -EIO;

else

ret= do_tty_write(ld->ops->write, tty, file, buf, count);

………

}

从以上这个函数里,能够看到tty_write调用道路规程的write函数,所以,咱们来看ldisc中的write函数是怎样的。通过一些操作后,终究调用:

tty->ops->flush_chars(tty);

tty->ops->write(tty,b, nr);

明显,这两个函数,都调用了tty_driver操作函数,由于在之前的tty_open函数中有了tty->ops=driver-> ops这样的操作。那么这个tty_driver是怎样的呢,在TTY体系中,tty_driver是需要在驱动层注册的。注册的时分就初始化了ops, 也便是说,接下来的工作要看tty_driver的了。

tty_read:

static ssize_t tty_read(struct file *file, char __user *buf, size_t count,

loff_t *ppos)

{

………

ld= tty_ldisc_ref_wait(tty);

if(ld->ops->read)

i= (ld->ops->read)(tty, file, buf, count);

else

i= -EIO;

……

}

像tty_write的相同,在tty_read里,也调用了线路规程的对应read函数。不同的是,这个read没有调用tty_driver里ops的read,而是这样:

uncopied= copy_from_read_buf(tty, b, nr);

uncopied+= copy_from_read_buf(tty, b, nr);

从函数名来看copy_from_read_buf,便是从read_buf这个缓冲区复制数据。实际上是在tty->read_buf的结尾 tty->read_tail中读取数据。那么read_buf中的数据是怎样来的呢?猜测,那肯定是tty_driver干的事了。

tty_ioctl:

long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

{

……

switch(cmd) {

case… …… :

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/moni/297531.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部