//如果没有指定TTY_DRIVER_DYNAMIC_DEV.即动态设备管理 if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { for (i = 0; i num; i++) tty_register_device(driver, i, NULL); } proc_tty_register_driver(driver); return 0; } 这个函数操作比较简单。就是为tty_driver创建字符设备。然后将字符设备的操作集指定为tty_fops.并且将tty_driver挂载到tty_drivers链表中.其实这个链表的作用跟我们之前分析的input子系统中的input_dev[ ]数组类似。都是以设备号为关键字找到对应的driver. 特别的。如果没有定义TTY_DRIVER_DYNAMIC_DEV.还会在sysfs中创建一个类设备.这样主要是为了udev管理设备. 以流程图的方式将上述操作表示如下:
if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) retval = -EBUSY;
if (retval) { #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "error %d in opening %s...", retval, tty->name); #endif release_dev(filp); if (retval != -ERESTARTSYS) return retval; if (signal_pending(current)) return retval; schedule(); /* * Need to reset f_op in case a hangup happened. */ if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; goto retry_open; }
ld = &tty_ldiscs[disc]; /* Check the entry is defined */ if (ld->flags & LDISC_FLAG_DEFINED) { /* If the module is being unloaded we can't use it */ if (!try_module_get(ld->owner)) ld = NULL; else /* lock it */ ld->refcount++; } else ld = NULL; spin_unlock_irqrestore(&tty_ldisc_lock, flags); return ld; } 这个函数的操作为到tty_ldiscs[ ]找到对应项.这个数组中的成员是调用tty_register_ldisc()将其设置进去的.
ret = tty_write_lock(tty, file->f_flags & O_NDELAY); if (ret return ret;
/* * We chunk up writes into a temporary buffer. This * simplifies low-level drivers immensely, since they * don't have locking issues and user mode accesses. * * But if TTY_NO_WRITE_SPLIT is set, we should use a * big chunk-size.. * * The default chunk-size is 2kB, because the NTTY * layer has problems with bigger chunks. It will * claim to be able to handle more characters than * it actually does. * * FIXME: This can probably go away now except that 64K chunks * are too likely to fail unless switched to vmalloc... */ chunk = 2048; if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) chunk = 65536; if (count chunk = count;
/* write_buf/write_cnt is protected by the atomic_write_lock mutex */ if (tty->write_cnt unsigned char *buf;
/* We want to wait for the line discipline to sort out in this situation */ ld = tty_ldisc_ref_wait(tty); lock_kernel(); if (ld->read) i = (ld->read)(tty, file, buf, count); else i = -EIO; tty_ldisc_deref(ld); unlock_kernel(); if (i > 0) inode->i_atime = current_fs_time(inode->i_sb); return i; } 这个read操作就更简单。直接调用ldsic->read()完成工作 流程图如下: