日本a√视频在线,久久青青亚洲国产,亚洲一区欧美二区,免费g片在线观看网站

        <style id="k3y6c"><u id="k3y6c"></u></style>
        <s id="k3y6c"></s>
        <mark id="k3y6c"></mark>
          
          

          <mark id="k3y6c"></mark>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > 打通linux的tty驅(qū)動(dòng)的數(shù)據(jù)鏈路

          打通linux的tty驅(qū)動(dòng)的數(shù)據(jù)鏈路

          作者: 時(shí)間:2016-10-08 來源:網(wǎng)絡(luò) 收藏

          一、首先把tty驅(qū)動(dòng)在linux中的分層結(jié)構(gòu)理清楚:

          本文引用地址:http://yuyingmama.com.cn/article/201610/305940.htm
          .

          自上而下分為TTY核心層、TTY線路規(guī)程、TTY驅(qū)動(dòng)。

          二、TTY核心層與線路規(guī)程層分析

          用戶空間的程序直接對(duì)tty核心層進(jìn)行讀寫等相關(guān)操作,在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 drivern);

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

          ………

          以上的一段初始化代碼可以獲取以下信息:

          注冊(cè)了一個(gè)字符驅(qū)動(dòng),用戶空間操作對(duì)應(yīng)到tty_fops結(jié)構(gòu)體里的函數(shù):

          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,

          };

          對(duì)于字符設(shè)備驅(qū)動(dòng),我們知道,讀寫操作一一對(duì)應(yīng)于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是根據(jù)設(shè)備號(hào)device,通過查找tty_drivers全局鏈表來查找tty_driver.

          tty_init_dev是初始化一個(gè)tty結(jié)構(gòu)體:

          tty->driver= driver;

          tty->ops= driver->ops;

          并建立線路規(guī)程:

          ldops= tty_ldiscs[N_TTY];

          ld->ops= ldops;

          tty->ldisc= ld;

          其實(shí)tty_ldiscs[N_TTY]在console_init中確定,該函數(shù)在內(nèi)核啟動(dòng)的時(shí)候調(diào)用。

          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_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

          };

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

          tty->ops->open的調(diào)用,實(shí)則上就是應(yīng)用driver->ops->open.這樣,我們就從tty核心層到tty驅(qū)動(dòng)層了。

          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);

          ………

          }

          從以上這個(gè)函數(shù)里,可以看到tty_write調(diào)用路線規(guī)程的write函數(shù),所以,我們來看ldisc中的write函數(shù)是怎樣的。經(jīng)過一些操作后,最終調(diào)用:

          tty->ops->flush_chars(tty);

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

          顯然,這兩個(gè)函數(shù),都調(diào)用了tty_driver操作函數(shù),因?yàn)樵谥暗膖ty_open函數(shù)中有了tty->ops=driver-> ops這樣的操作。那么這個(gè)tty_driver是怎樣的呢,在TTY系統(tǒng)中,tty_driver是需要在驅(qū)動(dòng)層注冊(cè)的。注冊(cè)的時(shí)候就初始化了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里,也調(diào)用了線路規(guī)程的對(duì)應(yīng)read函數(shù)。不同的是,這個(gè)read沒有調(diào)用tty_driver里ops的read,而是這樣:

          uncopied= copy_from_read_buf(tty, b, nr);

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

          從函數(shù)名來看copy_from_read_buf,就是從read_buf這個(gè)緩沖區(qū)拷貝數(shù)據(jù)。實(shí)際上是在tty->read_buf的末尾 tty->read_tail中讀取數(shù)據(jù)。那么read_buf中的數(shù)據(jù)是怎么來的呢?猜想,那肯定是tty_driver干的事了。

          tty_ioctl:

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

          {

          ……

          switch(cmd) {

          case… …… :


          上一頁 1 2 3 下一頁

          關(guān)鍵詞:

          評(píng)論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉