LINUX设备驱动之tty及console驱动(一)

    技术2025-09-18  25

    Eric Fang  2010-02-22

    --------------------------------------------------------------

    本站分析linux内核源码,版本号为2.6.32.3

    转载请注明出处:http://ericfang.cublog.cn/

    --------------------------------------------------------------

     

    在前面输入子系统的分析所举的键盘驱动例子里,其上报给输入子系统的事件的处理中,会对相应的控制台操作,本文将分析tty驱动和console驱动。

     

    Tty用于表示各种终端,这些终端包括串行端口终端(/dev/ttySn)、伪终端(/dev/pty/)、控制台终端(/dev/ttyn, /dev/console)等,tty驱动架构中,包括tty核心、tty线路规程、tty驱动层概念,用户空间通过文件操作与tty_core交互,tty_core根据文件操作的类型选择line discipline(如readwrite操作)或直接跟tty_driver(如ioctl操作)交互,而line discipline对相应的终端进行一系列的输入与输出规范设置,然后再交给tty_driver处理,从层次上看,这个line discipline就是tty特有的对一些操作的统一设置。

     

    一.Tty驱动的注册

    上面提到的tty_driver,在内核中必然存在它对应的结构:

    0333       struct tty_driver {

    0334              int    magic;            /* magic number for this structure */

    0335              struct kref kref;     /* Reference management */

    0336              struct cdev cdev;

    0337              struct module  *owner;

    0338              const char      *driver_name;

    0339              const char      *name;

    0340              int    name_base;     /* offset of printed name */

    0341              int    major;            /* major device number */

    0342              int    minor_start;    /* start of minor device number */

    0343              int    minor_num;    /* number of *possible* devices */

    0344              int    num;              /* number of devices allocated */

    0345              short       type;              /* type of tty driver */

    0346              short       subtype;  /* subtype of tty driver */

    0347              struct ktermios init_termios; /* Initial termios */

    0348              int    flags;             /* tty driver flags */

    0349              struct proc_dir_entry *proc_entry; /* /proc fs entry */

    0350              struct tty_driver *other; /* only used for the PTY driver */

    0351      

    0352              /*

    0353              * Pointer to the tty data structures

    0354              */

    0355              struct tty_struct **ttys;

    0356              struct ktermios **termios;

    0357              struct ktermios **termios_locked;

    0358              void *driver_state;

    0359      

    0360              /*

    0361              * Driver methods

    0362              */

    0363      

    0364              const struct tty_operations *ops;

    0365              struct list_head tty_drivers;

    0366       };

    暂先不理会这个数据结构各字段的含义,像其他驱动程序一样,内核提供了创建和注册tty_driver的函数,分别是alloc_tty_drivertty_register_driver

    2838       struct tty_driver *alloc_tty_driver(int lines)

    2839       {

    2840              struct tty_driver *driver;

    2841      

    2842              driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);

    2843              if (driver) {

    2844                     kref_init(&driver->kref);

    2845                     driver->magic = TTY_DRIVER_MAGIC;

    2846                     driver->num = lines;

    2847                     /* later we'll move allocation of tables here */

    2848              }

    2849              return driver;

    2850       }

    2842行为tty_driver分配内存空间。

    2844行以原子性操作初始化driver的引用计数为1

    2844行定义driver->magicTTY_DRIVER_MAGIC,这个魔数是在定义ioctl 命令时使用,根据 Linux 内核惯例来为驱动选择 ioctl 号。

    2844driver->num用来表示次设备号的个数。

    接着看tty_register_driver函数:

    2907       int tty_register_driver(struct tty_driver *driver)

    2908       {

    2909              int error;

    2910              int i;

    2911                     dev_t dev;

    2912              void **p = NULL;

    2913      

    2914              if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {

    2915                     p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);

    2916                     if (!p)

    2917                            return -ENOMEM;

    2918              }

    2919      

    2920              if (!driver->major) {

    2921                     error = alloc_chrdev_region(&dev, driver->minor_start,

    2922                                                 driver->num, driver->name);

    2923                     if (!error) {

    2924                            driver->major = MAJOR(dev);

    2925                            driver->minor_start = MINOR(dev);

    2926                     }

    2927              } else {

    2928                     dev = MKDEV(driver->major, driver->minor_start);

    2929                     error = register_chrdev_region(dev, driver->num, driver->name);

    2930              }

    2931              if (error < 0) {

    2932                     kfree(p);

    2933                     return error;

    2934              }

    2935      

    2936              if (p) {

    2937                     driver->ttys = (struct tty_struct **)p;

    2938                     driver->termios = (struct ktermios **)(p + driver->num);

    2939              } else {

    2940                     driver->ttys = NULL;

    2941                     driver->termios = NULL;

    2942              }

    2943      

    2944              cdev_init(&driver->cdev, &tty_fops);

    2945              driver->cdev.owner = driver->owner;

    2946              error = cdev_add(&driver->cdev, dev, driver->num);

    2947              if (error) {

    2948                     unregister_chrdev_region(dev, driver->num);

    2949                     driver->ttys = NULL;

    2950                     driver->termios = NULL;

    2951                     kfree(p);

    2952                     return error;

    2953              }

    2954      

    2955              mutex_lock(&tty_mutex);

    2956              list_add(&driver->tty_drivers, &tty_drivers);

    2957              mutex_unlock(&tty_mutex);

    2958      

    2959              if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {

    2960                     for (i = 0; i < driver->num; i++)

    2961                         tty_register_device(driver, i, NULL);

    2962              }

    2963              proc_tty_register_driver(driver);

    2964              driver->flags |= TTY_DRIVER_INSTALLED;

    2965              return 0;

    2966       }

    2914~29172936~2942行,如果driver->flags 定义了TTY_DRIVER_DEVPTS_MEM,则使用devpts进行动态内存映射,分配num * 2个字空间,初始化driver->ttysdriver->termios

    函数的其他大部分代码为为tty_driver创建和注册字符设备,指定字符设备的操作集为tty_fops

    2956行将tty_driver插入到tty_drivers链表中,这样就可以通过比较设备号来获得相应设备号的tty_driver

    2963行调用proc_tty_register_driver注册tty_driver/proc下的交互文件。

     

    二.Tty设备文件的操作

    tty_driver对应的字符设备的文件操作为tty_fops

    0410       static const struct file_operations tty_fops = {

    0411                     .llseek            = no_llseek,

    0412              .read              = tty_read,

    0413              .write             = tty_write,

    0414              .poll        = tty_poll,

    0415              .unlocked_ioctl       = tty_ioctl,

    0416              .compat_ioctl  = tty_compat_ioctl,

    0417              .open             = tty_open,

    0418              .release    = tty_release,

    0419              .fasync           = tty_fasync,

    0420       };

    我们将分析这些具体的函数,其中将涉及到线路规程的内容。

    首先看tty_open函数:

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

    1844       {

    1845              int ret;

    1846      

    1847              lock_kernel();

    1848              ret = __tty_open(inode, filp);

    1849              unlock_kernel();

    1850              return ret;

    1851       }

    1847行用于获得大内核锁。

    大内核锁本质上是自旋锁,但又不同于自旋锁,自旋锁不可以递归获得锁的,因为那样会导致死锁,但大内核锁可以递归获得锁,大内核锁用于保护整个内核,而自旋锁用于保护非常特定的某一共享资源。

    另外如果没有定义CONFIG_LOCK_KERNEL的话,lock_kernel什么也不做。

    1849行,释放大内核锁。

    1848行,转入__tty_open(inode, filp)函数:

    1706       static int __tty_open(struct inode *inode, struct file *filp)

    1707       {

    1708              struct tty_struct *tty = NULL;

    1709              int noctty, retval;

    1710              struct tty_driver *driver;

    1711              int index;

    1712              dev_t device = inode->i_rdev;

    1713              unsigned saved_flags = filp->f_flags;

    1714      

    1715              nonseekable_open(inode, filp);

    1716      

    1717       retry_open:

    1718              noctty = filp->f_flags & O_NOCTTY;

    1719              index  = -1;

    1720              retval = 0;

    1721      

    1722              mutex_lock(&tty_mutex);

    1723      

    1724              if (device == MKDEV(TTYAUX_MAJOR, 0)) {

    1725                     tty = get_current_tty();

    1726                     if (!tty) {

    1727                            mutex_unlock(&tty_mutex);

    1728                            return -ENXIO;

    1729                     }

    1730                     driver = tty_driver_kref_get(tty->driver);

    1731                     index = tty->index;

    1732                     filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */

    1733                     /* noctty = 1; */

    1734                     /* FIXME: Should we take a driver reference ? */

    1735                     tty_kref_put(tty);

    1736                     goto got_driver;

    1737              }

    1738       #ifdef CONFIG_VT

    1739              if (device == MKDEV(TTY_MAJOR, 0)) {

    1740                     extern struct tty_driver *console_driver;

    1741                     driver = tty_driver_kref_get(console_driver);

    1742                     index = fg_console;

    1743                     noctty = 1;

    1744                     goto got_driver;

    1745              }

    1746       #endif

    1747              if (device == MKDEV(TTYAUX_MAJOR, 1)) {

    1748                     struct tty_driver *console_driver = console_device(&index);

    1749                     if (console_driver) {

    1750                            driver = tty_driver_kref_get(console_driver);

    1751                            if (driver) {

    1752                                   /* Don't let /dev/console block */

    1753                                   filp->f_flags |= O_NONBLOCK;

    1754                                   noctty = 1;

    1755                                   goto got_driver;

    1756                            }

    1757                     }

    1758                     mutex_unlock(&tty_mutex);

    1759                     return -ENODEV;

    1760              }

    1761      

    1762              driver = get_tty_driver(device, &index);

    1763              if (!driver) {

    1764                     mutex_unlock(&tty_mutex);

    1765                     return -ENODEV;

    1766              }

    1767       got_driver:

    1768              if (!tty) {

    1769                     /* check whether we're reopening an existing tty */

    1770                     tty = tty_driver_lookup_tty(driver, inode, index);

    1771      

    1772                     if (IS_ERR(tty)) {

    1773                            mutex_unlock(&tty_mutex);

    1774                            return PTR_ERR(tty);

    1775                     }

    1776              }

    1777      

    1778              if (tty) {

    1779                     retval = tty_reopen(tty);

    1780                     if (retval)

    1781                            tty = ERR_PTR(retval);

    1782              } else

    1783                     tty = tty_init_dev(driver, index, 0);

    1784      

    1785              mutex_unlock(&tty_mutex);

    1786              tty_driver_kref_put(driver);

    1787              if (IS_ERR(tty))

    1788                     return PTR_ERR(tty);

    1789      

    1790              filp->private_data = tty;

    1791              file_move(filp, &tty->tty_files);

    1792              check_tty_count(tty, "tty_open");

    1793              if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&

    1794                  tty->driver->subtype == PTY_TYPE_MASTER)

    1795                     noctty = 1;

    1796       #ifdef TTY_DEBUG_HANGUP

    1797              printk(KERN_DEBUG "opening %s...", tty->name);

    1798       #endif

    1799              if (!retval) {

    1800                     if (tty->ops->open)

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

    1802                     else

    1803                            retval = -ENODEV;

    1804              }

    1805              filp->f_flags = saved_flags;

    1806      

    1807              if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&

    1808                                                 !capable(CAP_SYS_ADMIN))

    1809                     retval = -EBUSY;

    1810      

    1811              if (retval) {

    1812       #ifdef TTY_DEBUG_HANGUP

    1813                     printk(KERN_DEBUG "error %d in opening %s...", retval,

    1814                            tty->name);

    1815       #endif

    1816                     tty_release_dev(filp);

    1817                     if (retval != -ERESTARTSYS)

    1818                            return retval;

    1819                     if (signal_pending(current))

    1820                            return retval;

    1821                     schedule();

    1822                     /*

    1823                     * Need to reset f_op in case a hangup happened.

    1824                     */

    1825                     if (filp->f_op == &hung_up_tty_fops)

    1826                            filp->f_op = &tty_fops;

    1827                     goto retry_open;

    1828              }

    1829      

    1830              mutex_lock(&tty_mutex);

    1831              spin_lock_irq(&current->sighand->siglock);

    1832              if (!noctty &&

    1833                  current->signal->leader &&

    1834                  !current->signal->tty &&

    1835                  tty->session == NULL)

    1836                     __proc_set_tty(current, tty);

    1837              spin_unlock_irq(&current->sighand->siglock);

    1838              mutex_unlock(&tty_mutex);

    1839              return 0;

    1840       }

    1712行获得对应节点的设备号。

    1724~1737行判断设备号是不是 (5,0) ,即当前进程的控制终端/dev/tty,如果当前进程的控制终端存在,则获得它并获得其tty_driverindex,跳到got_driver;如果当前进程的控制终端不存在则退出。

    1738~1746行判断设备号是不是 (4,0) ,即当前控制台console终端/dev/tty0,如果是则获得它并获得其tty_driverindex,跳到got_driver

    1747~1760行判断设备号是不是 (5,1) ,即外接的控制台终端/dev/console,如果是外接的控制台则调用console_device获得其tty_driver跳到got_driverconsole_device函数是在/kernel/printk.c中定义:

    1116 struct tty_driver *console_device(int *index)

    1117 {

    1118        struct console *c;

    1119        struct tty_driver *driver = NULL;

    1120      

    1121              acquire_console_sem();

    1122              for_each_console(c) {

    1123                     if (!c->device)

    1124                            continue;

    1125                     driver = c->device(c, index);

    1126                     if (driver)

    1127                            break;

    1128              }

    1129              release_console_sem();

    1130              return driver;

    1131       }

    0042       #define for_each_console(con) /

    0043              for (con = console_drivers; con != NULL; con = con->next)

    0085       struct console *console_drivers;

    也即在console_drivers找到该console,并调用其device函数获得其tty_driver

    如果不是上面三种情况,1762行调用get_tty_driver 函数:

    0268       static struct tty_driver *get_tty_driver(dev_t device, int *index)

    0269       {

    0270              struct tty_driver *p;

    0271      

    0272              list_for_each_entry(p, &tty_drivers, tty_drivers) {

    0273                     dev_t base = MKDEV(p->major, p->minor_start);

    0274                     if (device < base || device >= base + p->num)

    0275                            continue;

    0276                     *index = device - base;

    0277                     return tty_driver_kref_get(p);

    0278              }

    0279              return NULL;

    0280       }

    以文件设备号为关键字到tty_drivers链表中搜索所注册的driver,还记不记得在前面分析tty_register_driver函数时把相应的tty_driver插入到tty_drivers链表。

    1768~1776tty检查是否存在,不存在则需要重新打开它,tty_driver_lookup_tty函数如下:

    1145       static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,

    1146                     struct inode *inode, int idx)

    1147       {

    1148              struct tty_struct *tty;

    1149      

    1150              if (driver->ops->lookup)

    1151                     return driver->ops->lookup(driver, inode, idx);

    1152      

    1153              tty = driver->ttys[idx];

    1154              return tty;

    1155       }

    如果定义了driver->ops->lookup,就会调用它重新赋值tty,否则为driver->ttys[idx],我们在前面分析中已经这段ttys数组存放了相应的tty_struct的地址或者为空。

    1778~ 1783行,如果tty不为空则调用tty_reopen函数快速打开它,否则调用tty_init_dev函数重新创建一个tty_struct结构并进行相应的设置,来看看这里两个函数。

    1246       static int tty_reopen(struct tty_struct *tty)

    1247       {

    1248              struct tty_driver *driver = tty->driver;

    1249      

    1250              if (test_bit(TTY_CLOSING, &tty->flags))

    1251                     return -EIO;

    1252      

    1253              if (driver->type == TTY_DRIVER_TYPE_PTY &&

    1254                  driver->subtype == PTY_TYPE_MASTER) {

    1255                     /*

    1256                     * special case for PTY masters: only one open permitted,

    1257                     * and the slave side open count is incremented as well.

    1258                     */

    1259                     if (tty->count)

    1260                            return -EIO;

    1261      

    1262                     tty->link->count++;

    1263              }

    1264              tty->count++;

    1265              tty->driver = driver; /* N.B. why do this every time?? */

    1266      

    1267              mutex_lock(&tty->ldisc_mutex);

    1268              WARN_ON(!test_bit(TTY_LDISC, &tty->flags));

    1269              mutex_unlock(&tty->ldisc_mutex);

    1270      

    1271              return 0;

    1272       }

    这个函数比较简单,递增一些计数器后返回。第1265行,就如其注释,貌似可以去掉。

    接着看tty_init_dev函数:

    1299       struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,

    1300                                                               int first_ok)

    1301       {

    1302              struct tty_struct *tty;

    1303              int retval;

    1304      

    1305              /* Check if pty master is being opened multiple times */

    1306              if (driver->subtype == PTY_TYPE_MASTER &&

    1307                     (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)

    1308                     return ERR_PTR(-EIO);

    1309      

    1310              /*

    1311              * First time open is complex, especially for PTY devices.

    1312              * This code guarantees that either everything succeeds and the

    1313              * TTY is ready for operation, or else the table slots are vacated

    1314              * and the allocated memory released.  (Except that the termios

    1315              * and locked termios may be retained.)

    1316              */

    1317      

    1318              if (!try_module_get(driver->owner))

    1319                     return ERR_PTR(-ENODEV);

    1320      

    1321              tty = alloc_tty_struct();

    1322              if (!tty)

    1323                     goto fail_no_mem;

    1324              initialize_tty_struct(tty, driver, idx);

    1325      

    1326              retval = tty_driver_install_tty(driver, tty);

    1327              if (retval < 0) {

    1328                     free_tty_struct(tty);

    1329                     module_put(driver->owner);

    1330                     return ERR_PTR(retval);

    1331              }

    1332      

    1333              /*

    1334              * Structures all installed ... call the ldisc open routines.

    1335              * If we fail here just call release_tty to clean up.  No need

    1336              * to decrement the use counts, as release_tty doesn't care.

    1337              */

    1338      

    1339              retval = tty_ldisc_setup(tty, tty->link);

    1340              if (retval)

    1341                     goto release_mem_out;

    1342              return tty;

    1343      

    1344       fail_no_mem:

    1345              module_put(driver->owner);

    1346              return ERR_PTR(-ENOMEM);

    1347      

    1348              /* call the tty release_tty routine to clean out this slot */

    1349       release_mem_out:

    1350              if (printk_ratelimit())

    1351                     printk(KERN_INFO "tty_init_dev: ldisc open failed, "

    1352                                   "clearing slot %d/n", idx);

    1353              release_tty(tty, idx);

    1354              return ERR_PTR(retval);

    1355       }

    1305~1331行重新创建和初始化一个tty_struct,这里调用的函数都比较简单,我们重点分析线路规程部分代码。

    0167       struct tty_struct *alloc_tty_struct(void)

    0168       {

    0169              return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);

    0170       }

    2726       void initialize_tty_struct(struct tty_struct *tty,

    2727                     struct tty_driver *driver, int idx)

    2728       {

    2729              memset(tty, 0, sizeof(struct tty_struct));

    2730              kref_init(&tty->kref);

    2731              tty->magic = TTY_MAGIC;

    2732              tty_ldisc_init(tty);

    2733              tty->session = NULL;

    2734              tty->pgrp = NULL;

    2735              tty->overrun_time = jiffies;

    2736              tty->buf.head = tty->buf.tail = NULL;

    2737              tty_buffer_init(tty);

    2738              mutex_init(&tty->termios_mutex);

    2739              mutex_init(&tty->ldisc_mutex);

    2740              init_waitqueue_head(&tty->write_wait);

    2741              init_waitqueue_head(&tty->read_wait);

    2742              INIT_WORK(&tty->hangup_work, do_tty_hangup);

    2743              mutex_init(&tty->atomic_read_lock);

    2744              mutex_init(&tty->atomic_write_lock);

    2745              mutex_init(&tty->output_lock);

    2746              mutex_init(&tty->echo_lock);

    2747              spin_lock_init(&tty->read_lock);

    2748              spin_lock_init(&tty->ctrl_lock);

    2749              INIT_LIST_HEAD(&tty->tty_files);

    2750              INIT_WORK(&tty->SAK_work, do_SAK_work);

    2751      

    2752              tty->driver = driver;

    2753              tty->ops = driver->ops;

    2754              tty->index = idx;

    2755              tty_line_name(driver, idx, tty->name);

    2756       }

    2732tty_ldisc_init函数如下:

    0857       void tty_ldisc_init(struct tty_struct *tty)

    0858       {

    0859              struct tty_ldisc *ld = tty_ldisc_get(N_TTY);

    0860              if (IS_ERR(ld))

    0861                     panic("n_tty: init_tty");

    0862              tty_ldisc_assign(tty, ld);

    0863       }

    0190       static struct tty_ldisc *tty_ldisc_get(int disc)

    0191       {

    0192              struct tty_ldisc *ld;

    0193              struct tty_ldisc_ops *ldops;

    0194      

    0195              if (disc < N_TTY || disc >= NR_LDISCS)

    0196                     return ERR_PTR(-EINVAL);

    0197      

    0198              /*

    0199              * Get the ldisc ops - we may need to request them to be loaded

    0200              * dynamically and try again.

    0201              */

    0202              ldops = get_ldops(disc);

    0203              if (IS_ERR(ldops)) {

    0204                     request_module("tty-ldisc-%d", disc);

    0205                     ldops = get_ldops(disc);

    0206                     if (IS_ERR(ldops))

    0207                            return ERR_CAST(ldops);

    0208              }

    0209      

    0210              ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);

    0211              if (ld == NULL) {

    0212                     put_ldops(ldops);

    0213                     return ERR_PTR(-ENOMEM);

    0214              }

    0215      

    0216              ld->ops = ldops;

    0217              atomic_set(&ld->users, 1);

    0218              return ld;

    0219       }

    0202~0208行获得相应的规程操作,这里处于保险,如果不成功则再重复一次获取规程操作,还是不成功就返回错误。

    然后分配一个tty_ldisc结构,并把刚才获得的规程操作赋给它的ops字段,然后返回该tty_ldisc

    get_ldops函数如下:

    0148       static struct tty_ldisc_ops *get_ldops(int disc)

    0149       {

    0150              unsigned long flags;

    0151              struct tty_ldisc_ops *ldops, *ret;

    0152      

    0153              spin_lock_irqsave(&tty_ldisc_lock, flags);

    0154              ret = ERR_PTR(-EINVAL);

    0155              ldops = tty_ldiscs[disc];

    0156              if (ldops) {

    0157                     ret = ERR_PTR(-EAGAIN);

    0158                     if (try_module_get(ldops->owner)) {

    0159                            ldops->refcount++;

    0160                            ret = ldops;

    0161                     }

    0162              }

    0163              spin_unlock_irqrestore(&tty_ldisc_lock, flags);

    0164              return ret;

    0165       }

    0155行看出规程操作的结构变量存放在tty_ldiscs数组中,其声明如下:

    0049       static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];

    该数组什么时候初始化后面再做分析。

    接着继续看tty_init_dev中调用的其他函数:

    1201       static int tty_driver_install_tty(struct tty_driver *driver,

    1202                                                 struct tty_struct *tty)

    1203       {

    1204              int idx = tty->index;

    1205      

    1206              if (driver->ops->install)

    1207                     return driver->ops->install(driver, tty);

    1208      

    1209              if (tty_init_termios(tty) == 0) {

    1210                     tty_driver_kref_get(driver);

    1211                     tty->count++;

    1212                     driver->ttys[idx] = tty;

    1213                     return 0;

    1214              }

    1215              return -ENOMEM;

    1216       }

    1165       int tty_init_termios(struct tty_struct *tty)

    1166       {

    1167              struct ktermios *tp;

    1168              int idx = tty->index;

    1169      

    1170              tp = tty->driver->termios[idx];

    1171              if (tp == NULL) {

    1172                     tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);

    1173                     if (tp == NULL)

    1174                            return -ENOMEM;

    1175                     memcpy(tp, &tty->driver->init_termios,

    1176                                                 sizeof(struct ktermios));

    1177                     tty->driver->termios[idx] = tp;

    1178              }

    1179              tty->termios = tp;

    1180              tty->termios_locked = tp + 1;

    1181      

    1182              /* Compatibility until drivers always set this */

    1183              tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);

    1184              tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);

    1185              return 0;

    1186       }

    这些都是设置初始化一些结构字段,不做详细分析。

    接着重点分析第1339 tty_ldisc_setup函数,它用于打开线路规程,代码如下:

    0787       int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)

    0788       {

    0789              struct tty_ldisc *ld = tty->ldisc;

    0790              int retval;

    0791      

    0792              retval = tty_ldisc_open(tty, ld);

    0793              if (retval)

    0794                     return retval;

    0795      

    0796              if (o_tty) {

    0797                     retval = tty_ldisc_open(o_tty, o_tty->ldisc);

    0798                     if (retval) {

    0799                            tty_ldisc_close(tty, ld);

    0800                            return retval;

    0801                     }

    0802                     tty_ldisc_enable(o_tty);

    0803              }

    0804              tty_ldisc_enable(tty);

    0805              return 0;

    0806       }

    tty_ldisc_open调用相应规程操作的open函数。代码如下:

    0443       static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)

    0444       {

    0445              WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));

    0446              if (ld->ops->open)

    0447                     return ld->ops->open(tty);

    0448              return 0;

    0449       }

    这个open函数以后再分析。

    tty_ldisc_enable函数如下:

    0388       void tty_ldisc_enable(struct tty_struct *tty)

    0389       {

    0390              set_bit(TTY_LDISC, &tty->flags);

    0391              clear_bit(TTY_LDISC_CHANGING, &tty->flags);

    0392              wake_up(&tty_ldisc_wait);

    0393       }

    设置tty->flagTTY_LDISC标志位,清tty->flagTTY_LDISC_CHANGING标志位,然后唤醒tty_ldisc_wait等待队列中的进程。

    做完这些后tty_init_dev函数第1342行返回该新创建的tty

    回到__tty_open函数中,第1790行把该tty赋给filp文件指针的private_data字段。

    1801行如果一切顺利的话,则调用tty->ops->open函数,在前面的代码中已经知道tty->ops为相应tty_driverops

    __tty_open剩下的代码都比较简单,不再分析。

    至此,tty_open函数分析完了,该函数涉及到线路规程的部分内容,相对比较复杂,如果你觉得台混乱,可以先看完后面的分析,整理思路,然后再回来看一遍。

    接着将分析tty_readtty_write函数。

     

    接下一篇文章。

    最新回复(0)