/*
check whether we're reopening an existing tty */
//查看是否已经存在此终端。
if
(driver->flags & TTY_DRIVER_DEVPTS_MEM) {
tty = devpts_get_tty(idx);//这个是从终端,所以要获的主终端。
if
(tty && driver->subtype == PTY_TYPE_MASTER)
tty
= tty->link;
}
else {
tty
= driver->ttys[idx];
}
if (tty) goto fast_track;
/*
* First time open is complex, especially for
PTY devices.
* This code guarantees that either everything
succeeds and the
* TTY is ready for operation, or else the
table slots are vacated
* and the allocated memory released. (Except that the termios
* and locked termios may be retained.)
*/
if
(!try_module_get(driver->owner)) {
retval
= -ENODEV;
goto
end_init;
}
tty = alloc_tty_struct();
//分配终端
if(!tty)
goto
fail_no_mem;
initialize_tty_struct(tty);
//初始化终端
if
(driver->type == TTY_DRIVER_TYPE_PTY) {
o_tty = alloc_tty_struct();
//如果是伪终端,则创建从伪终端。
if
(!o_tty)
goto
free_mem_out;
initialize_tty_struct(o_tty);
o_tty->driver
= driver->other;
o_tty->index
= idx;
tty_line_name(driver->other,
idx, o_tty->name);
/* Job control check -- must be done at start (POSIX.1
7.1.1.4). */
if (L_TOSTOP(tty) && file->f_op->write !=
redirected_tty_write) {
retval = tty_check_change(tty);
if (retval)
return retval;
}
add_wait_queue(&tty->write_wait, &wait);
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
if (tty_hung_up_p(file) || (tty->link &&
!tty->link->count)) {
retval = -EIO;
break;
}
if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT,
&tty->flags))) {
while (nr > 0) {
ssize_t num = opost_block(tty, b, nr);
if (num
if (num == -EAGAIN)
break;
retval = num;
goto break_out;
}
b += num;
nr -= num;
if (nr == 0)
break;
c = *b;
if (opost(c, tty)
break;
b++; nr--;
}
if (tty->driver->flush_chars)
tty->driver->flush_chars(tty);
} else {
while (nr > 0) {
c =
tty->driver->write(tty, b, nr);
if (c
retval = c;
goto break_out;
}
if (!c)
break;
b += c;
nr -= c;
}
}
if (!nr)
break;
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
}
schedule();
}
break_out:
__set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
return (b - buf) ? b - buf : retval;
}
然后就执行driver->write即
ptm的driver是ptm_driver,pts的driver是pts_driver,这两个都是在 unix98_pty_init初始化。
static void __init unix98_pty_init(void)
{
devfs_mk_dir("pts");
ptm_driver->init_termios.c_iflag = 0;
ptm_driver->init_termios.c_oflag = 0;
ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver,
&pty_ops);
ptm_driver->ioctl =
pty_unix98_ioctl;
pts_driver->type = TTY_DRIVER_TYPE_PTY;
pts_driver->subtype = PTY_TYPE_SLAVE;
pts_driver->init_termios = tty_std_termios;
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->flags = TTY_DRIVER_RESET_TERMIOS |
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
tty_set_operations(pts_driver,
&pty_ops);
if (tty_register_driver(ptm_driver))
panic("Couldn't register Unix98 ptm driver");
if (tty_register_driver(pts_driver))
panic("Couldn't register Unix98 pts driver");
}
static struct
tty_operations pty_ops = {
.open = pty_open,
.close = pty_close,
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
};
故执行driver->write就会执行pty_write
pty_write;
static int pty_write(struct tty_struct * tty, const unsigned
char *buf, int count)
{
struct tty_struct *to = tty->link;
int c;
if (!to ||
tty->stopped)
return 0;
c = to->ldisc.receive_room(to);
if (c > count)
c = count;
to->ldisc.receive_buf(to, buf, NULL, c);
//这个的效果是将数据放到终端队中另一个终端的read_Buf,就实现了虚拟设备的作用,即pts的输出会放到ptm的read_buf,ptm的输出会放到pts的read_buf。
return c;
}
当执行read时,调用tty_read
tty_read直接是调用N_TTY行规的read,是read_chan.
当对ptmx执行ioctl时:
会调用
int tty_ioctl(struct
inode * inode, struct file * file,
unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case TIOCSTI:
return tiocsti(tty, p);
case TIOCGWINSZ:
return tiocgwinsz(tty, p);
}
if (tty->driver->ioctl) {
retval =
(tty->driver->ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
ld = tty_ldisc_ref_wait(tty);
retval = -EINVAL;
if (ld->ioctl) {
retval = ld->ioctl(tty, file, cmd, arg);
if (retval == -ENOIOCTLCMD)
retval = -EINVAL;
}
}
然后就会执行drvier->ioctl,就是
pty_unix98_ioctl,
static int pty_unix98_ioctl(struct tty_struct *tty, struct file
*file,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case TIOCSPTLCK: /* Set
PT Lock (disallow slave open) */
return
pty_set_lock(tty, (int __user *)arg);
case
TIOCGPTN: /* Get PT Number */
return
put_user(tty->index, (unsigned int __user *)arg);
//获取对应的pts编号。
}
}
当最tty设备文件进行操作时:file->f_ops=tty_fops
static struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
因为tty_regiser_driver会将tty字符设备的fops赋值为tty_fops:
int
tty_register_driver(struct tty_driver *driver)
{