Tty用于表示各种终端,这些终端包括串行端口终端(/dev/ttySn)、伪终端(/dev/pty/)、控制台终端(/dev/ttyn, /dev/console)等,tty驱动架构中,包括tty核心、tty线路规程、tty驱动层概念,用户空间通过文件操作与tty_core交互,tty_core根据文件操作的类型选择line discipline(如read和write操作)或直接跟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_driver和tty_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->magic为TTY_DRIVER_MAGIC,这个魔数是在定义ioctl 命令时使用,根据 Linux 内核惯例来为驱动选择 ioctl 号。
第2844行driver->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~2917、2936~2942行,如果driver->flags 定义了TTY_DRIVER_DEVPTS_MEM,则使用devpts进行动态内存映射,分配num * 2个字空间,初始化driver->ttys和driver->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(¤t->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(¤t->sighand->siglock);
1838 mutex_unlock(&tty_mutex);
1839 return 0;
1840 }
第1712行获得对应节点的设备号。
第1724~1737行判断设备号是不是 (5,0) ,即当前进程的控制终端/dev/tty,如果当前进程的控制终端存在,则获得它并获得其tty_driver、index,跳到got_driver;如果当前进程的控制终端不存在则退出。
第1738~1746行判断设备号是不是 (4,0) ,即当前控制台console终端/dev/tty0,如果是则获得它并获得其tty_driver、index,跳到got_driver。
第1747~1760行判断设备号是不是 (5,1) ,即外接的控制台终端/dev/console,如果是外接的控制台则调用console_device获得其tty_driver跳到got_driver,console_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~1776行tty检查是否存在,不存在则需要重新打开它,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 }
第2732行tty_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->flag的TTY_LDISC标志位,清tty->flag的TTY_LDISC_CHANGING标志位,然后唤醒tty_ldisc_wait等待队列中的进程。
做完这些后tty_init_dev函数第1342行返回该新创建的tty。
回到__tty_open函数中,第1790行把该tty赋给filp文件指针的private_data字段。
第1801行如果一切顺利的话,则调用tty->ops->open函数,在前面的代码中已经知道tty->ops为相应tty_driver的ops。
__tty_open剩下的代码都比较简单,不再分析。
至此,tty_open函数分析完了,该函数涉及到线路规程的部分内容,相对比较复杂,如果你觉得台混乱,可以先看完后面的分析,整理思路,然后再回来看一遍。
接着将分析tty_read和tty_write函数。