新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 打通linux的tty驅動的數據鏈路

        打通linux的tty驅動的數據鏈路

        作者: 時間:2016-10-08 來源:網絡 收藏

        一、首先把tty驅動在linux中的分層結構理清楚:

        本文引用地址:http://www.104case.com/article/201610/305940.htm
        .

        自上而下分為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 drivern);

        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_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的調用,實則上就是應用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… …… :


        上一頁 1 2 3 下一頁

        關鍵詞:

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 元阳县| 佛冈县| 烟台市| 大同县| 华坪县| 慈利县| 云梦县| 夏津县| 松阳县| 蒙山县| 叶城县| 浦东新区| 神农架林区| 梓潼县| 昌平区| 阜康市| 定结县| 城市| 怀来县| 南投市| 丰镇市| 哈密市| 旬邑县| 澄城县| 内乡县| 邳州市| 镇康县| 漳平市| 武强县| 鄂州市| 孟连| 舞阳县| 金门县| 汉中市| 文水县| 汤阴县| 冕宁县| 呼图壁县| 利辛县| 海丰县| 西藏|