/* * linux/kernel/chr_drv/pty.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * pty.c * * This module exports the following pty function: * * int pty_open(struct tty_struct * tty, struct file * filp); */ #include #include #include #include #include #include #include #include #define MIN(a,b) ((a) < (b) ? (a) : (b)) static void pty_close(struct tty_struct * tty, struct file * filp) { if (!tty) return; if (IS_A_PTY_MASTER(tty->line)) { if (tty->count > 1) printk("master pty_close: count = %d!!\n", tty->count); } else { if (tty->count > 2) return; } wake_up_interruptible(&tty->secondary.proc_list); wake_up_interruptible(&tty->read_q.proc_list); wake_up_interruptible(&tty->write_q.proc_list); if (!tty->link) return; wake_up_interruptible(&tty->link->secondary.proc_list); wake_up_interruptible(&tty->link->read_q.proc_list); wake_up_interruptible(&tty->link->write_q.proc_list); if (IS_A_PTY_MASTER(tty->line)) tty_hangup(tty->link); else { start_tty(tty); set_bit(TTY_SLAVE_CLOSED, &tty->link->flags); } } static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) { unsigned long count, n; struct tty_queue *fq, *tq; int skip_readq; if (from->stopped || EMPTY(&from->write_q)) return; fq = &from->write_q; /* Bypass the read_q if this is a pty master. */ skip_readq = IS_A_PTY_MASTER(to->line) && to->disc == N_TTY; tq = skip_readq ? &to->secondary : &to->read_q; count = MIN(CHARS(fq), LEFT(tq)); while (count) { n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head), count); memcpy(&tq->buf[tq->head], &fq->buf[fq->tail], n); count -= n; fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1); tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1); } if (skip_readq) wake_up_interruptible(&to->secondary.proc_list); else TTY_READ_FLUSH(to); if (LEFT(fq) > WAKEUP_CHARS) wake_up_interruptible(&fq->proc_list); if (from->write_data_cnt) { set_bit(from->line, &tty_check_write); mark_bh(TTY_BH); } } /* * This routine gets called when tty_write has put something into * the write_queue. It copies the input to the output-queue of its * slave. */ static void pty_write(struct tty_struct * tty) { if (tty->link) pty_copy(tty,tty->link); } int pty_open(struct tty_struct *tty, struct file * filp) { if (!tty || !tty->link) return -ENODEV; if (IS_A_PTY_SLAVE(tty->line)) clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags); tty->write = tty->link->write = pty_write; tty->close = tty->link->close = pty_close; wake_up_interruptible(&tty->read_q.proc_list); if (filp->f_flags & O_NDELAY) return 0; while (!tty->link->count && !(current->signal & ~current->blocked)) interruptible_sleep_on(&tty->link->read_q.proc_list); if (!tty->link->count) return -ERESTARTSYS; return 0; }