}
}
mutex_unlock(&tty_mutex);
return -ENODEV;
}
driver = get_tty_driver(device, &index);
if (!driver) {
mutex_unlock(&tty_mutex);
return -ENODEV;
}
got_driver:
if (!tty) {
//检查我们是否重复打开一个已经存在的tty
tty = tty_driver_lookup_tty(driver, inode, index);
if (IS_ERR(tty)) {
mutex_unlock(&tty_mutex);
return PTR_ERR(tty);
}
}
if (tty) {
retval = tty_reopen(tty); //重新打开
if (retval)
tty = ERR_PTR(retval);
} else
tty = tty_init_dev(driver, index, 0); //初始化,为需要打开的终端建立tty_struct结构体
mutex_unlock(&tty_mutex);
tty_driver_kref_put(driver);
if (IS_ERR(tty))
return PTR_ERR(tty);
filp->private_data = tty; //设置私有数据
file_move(filp, &tty->tty_files);
check_tty_count(tty, "tty_open");
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
noctty = 1;
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "opening %s...", tty->name);
#endif
if (!retval) {
if (tty->ops->open)
retval = tty->ops->open(tty, filp); //调用tty_operations下的open函数
else
retval = -ENODEV;
}
filp->f_flags = saved_flags;
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
tty_release_dev(filp);
if (retval != -ERESTARTSYS)
return retval;
if (signal_pending(current))
return retval;
schedule();
//需要复位f_op,以防挂起
if (filp->f_op == &hung_up_tty_fops)
filp->f_op = &tty_fops;
goto retry_open;
}
mutex_lock(&tty_mutex);
spin_lock_irq(¤t->sighand->siglock);
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
tty->session == NULL)
__proc_set_tty(current, tty);
spin_unlock_irq(¤t->sighand->siglock);
mutex_unlock(&tty_mutex);
return 0;
}
在上面这个open函数中,我们主要涉及为需要打开的终端建立tty_struct结构体而执行的一条代码tty_init_dev(driver, index, 0),同时看到了怎么调用tty_operations下的open函数。在此我们好好看看tty_init_dev(driver, index, 0)的内幕吧。
struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
int first_ok)
{
struct tty_struct *tty;
int retval;
//检查是否pty被多次打开
if (driver->subtype == PTY_TYPE_MASTER &&
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok)
return ERR_PTR(-EIO);
if (!try_module_get(driver->owner))
return ERR_PTR(-ENODEV);
tty = alloc_tty_struct(); //分配tty_struct结构体
if (!tty)
goto fail_no_mem;
initialize_tty_struct(tty, driver, idx); //初始化tty_struct结构体
retval = tty_driver_install_tty(driver, tty);
if (retval < 0) {
free_tty_struct(tty);
module_put(driver->owner);
return ERR_PTR(retval);
}
retval = tty_ldisc_setup(tty, tty->link); //调用ldisc下open
if (retval)
goto release_mem_out;
return tty;
fail_no_mem:
module_put(driver->owner);
return ERR_PTR(-ENOMEM);
release_mem_out:
if (printk_ratelimit())
printk(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx);
release_tty(tty, idx);
return ERR_PTR(retval);
}
我们继续跟踪tty_init_dev中的initialize_tty_struct(tty, driver, idx)函数实现吧
void initialize_tty_struct(struct tty_struct *tty,
struct tty_driver *driver, int idx)
{
memset(tty, 0, sizeof(struct tty_struct));
kref_init(&tty->kref);
tty->magic = TTY_MAGIC;
tty_ldisc_init(tty); // tty_ldisc的初始化,
tty->session = NULL;
tty->pgrp = NULL;
tty->overrun_time = jiffies;
tty->buf.head = tty->buf.tail = NULL;
tty_buffer_init(tty);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
mutex_init(&tty->atomic_read_lock);
mutex_init(&tty->atomic_write_lock);
mutex_init(&tty->output_lock);