X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fchar%2Ftty_ioctl.c;h=b1a757a5ee271c9c4a4dc5a4b2fc18c35c7fb491;hb=2735977b12cb0f113aae24afff04747b6d0f5bf1;hp=d4b6d64e858b5e4ec18255a992ce0e57a0cbd92b;hpb=4fd3670eb1d3c33e8952cf1e79edbb2d517dcfb5;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index d4b6d64e858..b1a757a5ee2 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,50 @@ #define TERMIOS_OLD 8 +int tty_chars_in_buffer(struct tty_struct *tty) +{ + if (tty->ops->chars_in_buffer) + return tty->ops->chars_in_buffer(tty); + else + return 0; +} + +EXPORT_SYMBOL(tty_chars_in_buffer); + +int tty_write_room(struct tty_struct *tty) +{ + if (tty->ops->write_room) + return tty->ops->write_room(tty); + return 2048; +} + +EXPORT_SYMBOL(tty_write_room); + +void tty_driver_flush_buffer(struct tty_struct *tty) +{ + if (tty->ops->flush_buffer) + tty->ops->flush_buffer(tty); +} + +EXPORT_SYMBOL(tty_driver_flush_buffer); + +void tty_throttle(struct tty_struct *tty) +{ + /* check TTY_THROTTLED first so it indicates our state */ + if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && + tty->ops->throttle) + tty->ops->throttle(tty); +} +EXPORT_SYMBOL(tty_throttle); + +void tty_unthrottle(struct tty_struct *tty) +{ + if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && + tty->ops->unthrottle) + tty->ops->unthrottle(tty); +} +EXPORT_SYMBOL(tty_unthrottle); + /** * tty_wait_until_sent - wait for I/O to finish * @tty: tty we are waiting for @@ -50,24 +95,21 @@ * Locking: none */ -void tty_wait_until_sent(struct tty_struct * tty, long timeout) +void tty_wait_until_sent(struct tty_struct *tty, long timeout) { #ifdef TTY_DEBUG_WAIT_UNTIL_SENT char buf[64]; - + printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf)); #endif - if (!tty->driver->chars_in_buffer) - return; if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; if (wait_event_interruptible_timeout(tty->write_wait, - !tty->driver->chars_in_buffer(tty), timeout) < 0) - return; - if (tty->driver->wait_until_sent) - tty->driver->wait_until_sent(tty, timeout); + !tty_chars_in_buffer(tty), timeout) >= 0) { + if (tty->ops->wait_until_sent) + tty->ops->wait_until_sent(tty, timeout); + } } - EXPORT_SYMBOL(tty_wait_until_sent); static void unset_locked_termios(struct ktermios *termios, @@ -75,8 +117,8 @@ static void unset_locked_termios(struct ktermios *termios, struct ktermios *locked) { int i; - -#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z))) + +#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z))) if (!locked) { printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n"); @@ -88,7 +130,7 @@ static void unset_locked_termios(struct ktermios *termios, NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag); NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag); termios->c_line = locked->c_line ? old->c_line : termios->c_line; - for (i=0; i < NCCS; i++) + for (i = 0; i < NCCS; i++) termios->c_cc[i] = locked->c_cc[i] ? old->c_cc[i] : termios->c_cc[i]; /* FIXME: What should we do for i/ospeed */ @@ -163,7 +205,6 @@ speed_t tty_termios_baud_rate(struct ktermios *termios) } return baud_table[cbaud]; } - EXPORT_SYMBOL(tty_termios_baud_rate); /** @@ -203,7 +244,6 @@ speed_t tty_termios_input_baud_rate(struct ktermios *termios) return tty_termios_baud_rate(termios); #endif } - EXPORT_SYMBOL(tty_termios_input_baud_rate); /** @@ -338,7 +378,6 @@ speed_t tty_get_baud_rate(struct tty_struct *tty) return baud; } - EXPORT_SYMBOL(tty_get_baud_rate); /** @@ -361,7 +400,6 @@ void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old) new->c_ispeed = old->c_ispeed; new->c_ospeed = old->c_ospeed; } - EXPORT_SYMBOL(tty_termios_copy_hw); /** @@ -395,21 +433,22 @@ EXPORT_SYMBOL(tty_termios_hw_change); * Locking: termios_sem */ -static void change_termios(struct tty_struct * tty, struct ktermios * new_termios) +static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) { int canon_change; - struct ktermios old_termios = *tty->termios; + struct ktermios old_termios; struct tty_ldisc *ld; - + unsigned long flags; + /* * Perform the actual termios internal changes under lock. */ - + /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ mutex_lock(&tty->termios_mutex); - + old_termios = *tty->termios; *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -419,7 +458,7 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio tty->canon_data = 0; tty->erasing = 0; } - + /* This bit should be in the ldisc code */ if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ @@ -434,17 +473,19 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio STOP_CHAR(tty) == '\023' && START_CHAR(tty) == '\021'); if (old_flow != new_flow) { + spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); if (new_flow) tty->ctrl_status |= TIOCPKT_DOSTOP; else tty->ctrl_status |= TIOCPKT_NOSTOP; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); wake_up_interruptible(&tty->link->read_wait); } } - - if (tty->driver->set_termios) - (*tty->driver->set_termios)(tty, &old_termios); + + if (tty->ops->set_termios) + (*tty->ops->set_termios)(tty, &old_termios); else tty_termios_copy_hw(tty->termios, &old_termios); @@ -470,7 +511,7 @@ static void change_termios(struct tty_struct * tty, struct ktermios * new_termio * Called functions take ldisc and termios_sem locks */ -static int set_termios(struct tty_struct * tty, void __user *arg, int opt) +static int set_termios(struct tty_struct *tty, void __user *arg, int opt) { struct ktermios tmp_termios; struct tty_ldisc *ld; @@ -479,7 +520,9 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) if (retval) return retval; + mutex_lock(&tty->termios_mutex); memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); + mutex_unlock(&tty->termios_mutex); if (opt & TERMIOS_TERMIO) { if (user_termio_to_kernel_termios(&tmp_termios, @@ -501,19 +544,19 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) return -EFAULT; #endif - /* If old style Bfoo values are used then load c_ispeed/c_ospeed with the real speed - so its unconditionally usable */ + /* If old style Bfoo values are used then load c_ispeed/c_ospeed + * with the real speed so its unconditionally usable */ tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); ld = tty_ldisc_ref(tty); - + if (ld != NULL) { if ((opt & TERMIOS_FLUSH) && ld->flush_buffer) ld->flush_buffer(tty); tty_ldisc_deref(ld); } - + if (opt & TERMIOS_WAIT) { tty_wait_until_sent(tty, 0); if (signal_pending(current)) @@ -529,14 +572,14 @@ static int set_termios(struct tty_struct * tty, void __user *arg, int opt) return 0; } -static int get_termio(struct tty_struct * tty, struct termio __user * termio) +static int get_termio(struct tty_struct *tty, struct termio __user *termio) { if (kernel_termios_to_user_termio(termio, tty->termios)) return -EFAULT; return 0; } -static unsigned long inq_canon(struct tty_struct * tty) +static unsigned long inq_canon(struct tty_struct *tty) { int nr, head, tail; @@ -561,7 +604,7 @@ static unsigned long inq_canon(struct tty_struct * tty) * * The "sg_flags" translation is a joke.. */ -static int get_sgflags(struct tty_struct * tty) +static int get_sgflags(struct tty_struct *tty) { int flags = 0; @@ -579,7 +622,7 @@ static int get_sgflags(struct tty_struct * tty) return flags; } -static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) +static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) { struct sgttyb tmp; @@ -590,11 +633,11 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); mutex_unlock(&tty->termios_mutex); - + return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static void set_sgflags(struct ktermios * termios, int flags) +static void set_sgflags(struct ktermios *termios, int flags) { termios->c_iflag = ICRNL | IXON; termios->c_oflag = 0; @@ -631,7 +674,7 @@ static void set_sgflags(struct ktermios * termios, int flags) * Locking: termios_sem */ -static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) +static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) { int retval; struct sgttyb tmp; @@ -640,7 +683,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) retval = tty_check_change(tty); if (retval) return retval; - + if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) return -EFAULT; @@ -651,7 +694,8 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) set_sgflags(&termios, tmp.sg_flags); /* Try and encode into Bfoo format */ #ifdef BOTHER - tty_termios_encode_baud_rate(&termios, termios.c_ispeed, termios.c_ospeed); + tty_termios_encode_baud_rate(&termios, termios.c_ispeed, + termios.c_ospeed); #endif mutex_unlock(&tty->termios_mutex); change_termios(tty, &termios); @@ -660,62 +704,74 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) #endif #ifdef TIOCGETC -static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars) +static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) { struct tchars tmp; + mutex_lock(&tty->termios_mutex); tmp.t_intrc = tty->termios->c_cc[VINTR]; tmp.t_quitc = tty->termios->c_cc[VQUIT]; tmp.t_startc = tty->termios->c_cc[VSTART]; tmp.t_stopc = tty->termios->c_cc[VSTOP]; tmp.t_eofc = tty->termios->c_cc[VEOF]; tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */ + mutex_unlock(&tty->termios_mutex); return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars) +static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) { struct tchars tmp; if (copy_from_user(&tmp, tchars, sizeof(tmp))) return -EFAULT; + mutex_lock(&tty->termios_mutex); tty->termios->c_cc[VINTR] = tmp.t_intrc; tty->termios->c_cc[VQUIT] = tmp.t_quitc; tty->termios->c_cc[VSTART] = tmp.t_startc; tty->termios->c_cc[VSTOP] = tmp.t_stopc; tty->termios->c_cc[VEOF] = tmp.t_eofc; tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ + mutex_unlock(&tty->termios_mutex); return 0; } #endif #ifdef TIOCGLTC -static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) +static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) { struct ltchars tmp; + mutex_lock(&tty->termios_mutex); tmp.t_suspc = tty->termios->c_cc[VSUSP]; - tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */ + /* what is dsuspc anyway? */ + tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; tmp.t_rprntc = tty->termios->c_cc[VREPRINT]; - tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */ + /* what is flushc anyway? */ + tmp.t_flushc = tty->termios->c_cc[VEOL2]; tmp.t_werasc = tty->termios->c_cc[VWERASE]; tmp.t_lnextc = tty->termios->c_cc[VLNEXT]; + mutex_unlock(&tty->termios_mutex); return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) +static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) { struct ltchars tmp; if (copy_from_user(&tmp, ltchars, sizeof(tmp))) return -EFAULT; + mutex_lock(&tty->termios_mutex); tty->termios->c_cc[VSUSP] = tmp.t_suspc; - tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */ + /* what is dsuspc anyway? */ + tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; tty->termios->c_cc[VREPRINT] = tmp.t_rprntc; - tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */ + /* what is flushc anyway? */ + tty->termios->c_cc[VEOL2] = tmp.t_flushc; tty->termios->c_cc[VWERASE] = tmp.t_werasc; tty->termios->c_cc[VLNEXT] = tmp.t_lnextc; + mutex_unlock(&tty->termios_mutex); return 0; } #endif @@ -732,8 +788,8 @@ static int send_prio_char(struct tty_struct *tty, char ch) { int was_stopped = tty->stopped; - if (tty->driver->send_xchar) { - tty->driver->send_xchar(tty, ch); + if (tty->ops->send_xchar) { + tty->ops->send_xchar(tty, ch); return 0; } @@ -742,13 +798,40 @@ static int send_prio_char(struct tty_struct *tty, char ch) if (was_stopped) start_tty(tty); - tty->driver->write(tty, &ch, 1); + tty->ops->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); tty_write_unlock(tty); return 0; } +/** + * tty_change_softcar - carrier change ioctl helper + * @tty: tty to update + * @arg: enable/disable CLOCAL + * + * Perform a change to the CLOCAL state and call into the driver + * layer to make it visible. All done with the termios mutex + */ + +static int tty_change_softcar(struct tty_struct *tty, int arg) +{ + int ret = 0; + int bit = arg ? CLOCAL : 0; + struct ktermios old; + + mutex_lock(&tty->termios_mutex); + old = *tty->termios; + tty->termios->c_cflag &= ~CLOCAL; + tty->termios->c_cflag |= bit; + if (tty->ops->set_termios) + tty->ops->set_termios(tty, &old); + if ((tty->termios->c_cflag & CLOCAL) != bit) + ret = -EINVAL; + mutex_unlock(&tty->termios_mutex); + return ret; +} + /** * tty_mode_ioctl - mode related ioctls * @tty: tty for the ioctl @@ -761,10 +844,10 @@ static int send_prio_char(struct tty_struct *tty, char ch) * consistent mode setting. */ -int tty_mode_ioctl(struct tty_struct * tty, struct file *file, +int tty_mode_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct tty_struct * real_tty; + struct tty_struct *real_tty; void __user *p = (void __user *)arg; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -775,100 +858,95 @@ int tty_mode_ioctl(struct tty_struct * tty, struct file *file, switch (cmd) { #ifdef TIOCGETP - case TIOCGETP: - return get_sgttyb(real_tty, (struct sgttyb __user *) arg); - case TIOCSETP: - case TIOCSETN: - return set_sgttyb(real_tty, (struct sgttyb __user *) arg); + case TIOCGETP: + return get_sgttyb(real_tty, (struct sgttyb __user *) arg); + case TIOCSETP: + case TIOCSETN: + return set_sgttyb(real_tty, (struct sgttyb __user *) arg); #endif #ifdef TIOCGETC - case TIOCGETC: - return get_tchars(real_tty, p); - case TIOCSETC: - return set_tchars(real_tty, p); + case TIOCGETC: + return get_tchars(real_tty, p); + case TIOCSETC: + return set_tchars(real_tty, p); #endif #ifdef TIOCGLTC - case TIOCGLTC: - return get_ltchars(real_tty, p); - case TIOCSLTC: - return set_ltchars(real_tty, p); + case TIOCGLTC: + return get_ltchars(real_tty, p); + case TIOCSLTC: + return set_ltchars(real_tty, p); #endif - case TCSETSF: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); - case TCSETSW: - return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); - case TCSETS: - return set_termios(real_tty, p, TERMIOS_OLD); + case TCSETSF: + return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); + case TCSETSW: + return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); + case TCSETS: + return set_termios(real_tty, p, TERMIOS_OLD); #ifndef TCGETS2 - case TCGETS: - if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + case TCGETS: + if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; #else - case TCGETS: - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; - case TCGETS2: - if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; - case TCSETSF2: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); - case TCSETSW2: - return set_termios(real_tty, p, TERMIOS_WAIT); - case TCSETS2: - return set_termios(real_tty, p, 0); + case TCGETS: + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; + case TCGETS2: + if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) + return -EFAULT; + return 0; + case TCSETSF2: + return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); + case TCSETSW2: + return set_termios(real_tty, p, TERMIOS_WAIT); + case TCSETS2: + return set_termios(real_tty, p, 0); #endif - case TCGETA: - return get_termio(real_tty, p); - case TCSETAF: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO); - case TCSETAW: - return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); - case TCSETA: - return set_termios(real_tty, p, TERMIOS_TERMIO); + case TCGETA: + return get_termio(real_tty, p); + case TCSETAF: + return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO); + case TCSETAW: + return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); + case TCSETA: + return set_termios(real_tty, p, TERMIOS_TERMIO); #ifndef TCGETS2 - case TIOCGLCKTRMIOS: - if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; - - case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; - return 0; + case TIOCGLCKTRMIOS: + if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) + return -EFAULT; + return 0; + case TIOCSLCKTRMIOS: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (user_termios_to_kernel_termios(real_tty->termios_locked, + (struct termios __user *) arg)) + return -EFAULT; + return 0; #else - case TIOCGLCKTRMIOS: - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; - - case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; + case TIOCGLCKTRMIOS: + if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) + return -EFAULT; + return 0; + case TIOCSLCKTRMIOS: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (user_termios_to_kernel_termios_1(real_tty->termios_locked, + (struct termios __user *) arg)) + return -EFAULT; return 0; #endif - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg); - case TIOCSSOFTCAR: - if (get_user(arg, (unsigned int __user *) arg)) - return -EFAULT; - mutex_lock(&tty->termios_mutex); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - mutex_unlock(&tty->termios_mutex); - return 0; - default: - return -ENOIOCTLCMD; + case TIOCGSOFTCAR: + return put_user(C_CLOCAL(tty) ? 1 : 0, + (int __user *)arg); + case TIOCSSOFTCAR: + if (get_user(arg, (unsigned int __user *) arg)) + return -EFAULT; + return tty_change_softcar(tty, arg); + default: + return -ENOIOCTLCMD; } } - EXPORT_SYMBOL_GPL(tty_mode_ioctl); int tty_perform_flush(struct tty_struct *tty, unsigned long arg) @@ -889,8 +967,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) ld->flush_buffer(tty); /* fall through */ case TCOFLUSH: - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); break; default: tty_ldisc_deref(ld); @@ -899,13 +976,13 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) tty_ldisc_deref(ld); return 0; } - EXPORT_SYMBOL_GPL(tty_perform_flush); -int n_tty_ioctl(struct tty_struct * tty, struct file * file, +int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct tty_struct * real_tty; + struct tty_struct *real_tty; + unsigned long flags; int retval; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -915,68 +992,67 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, real_tty = tty; switch (cmd) { - case TCXONC: - retval = tty_check_change(tty); - if (retval) - return retval; - switch (arg) { - case TCOOFF: - if (!tty->flow_stopped) { - tty->flow_stopped = 1; - stop_tty(tty); - } - break; - case TCOON: - if (tty->flow_stopped) { - tty->flow_stopped = 0; - start_tty(tty); - } - break; - case TCIOFF: - if (STOP_CHAR(tty) != __DISABLED_CHAR) - return send_prio_char(tty, STOP_CHAR(tty)); - break; - case TCION: - if (START_CHAR(tty) != __DISABLED_CHAR) - return send_prio_char(tty, START_CHAR(tty)); - break; - default: - return -EINVAL; + case TCXONC: + retval = tty_check_change(tty); + if (retval) + return retval; + switch (arg) { + case TCOOFF: + if (!tty->flow_stopped) { + tty->flow_stopped = 1; + stop_tty(tty); } - return 0; - case TCFLSH: - return tty_perform_flush(tty, arg); - case TIOCOUTQ: - return put_user(tty->driver->chars_in_buffer ? - tty->driver->chars_in_buffer(tty) : 0, - (int __user *) arg); - case TIOCINQ: - retval = tty->read_cnt; - if (L_ICANON(tty)) - retval = inq_canon(tty); - return put_user(retval, (unsigned int __user *) arg); - case TIOCPKT: - { - int pktmode; - - if (tty->driver->type != TTY_DRIVER_TYPE_PTY || - tty->driver->subtype != PTY_TYPE_MASTER) - return -ENOTTY; - if (get_user(pktmode, (int __user *) arg)) - return -EFAULT; - if (pktmode) { - if (!tty->packet) { - tty->packet = 1; - tty->link->ctrl_status = 0; - } - } else - tty->packet = 0; - return 0; - } + break; + case TCOON: + if (tty->flow_stopped) { + tty->flow_stopped = 0; + start_tty(tty); + } + break; + case TCIOFF: + if (STOP_CHAR(tty) != __DISABLED_CHAR) + return send_prio_char(tty, STOP_CHAR(tty)); + break; + case TCION: + if (START_CHAR(tty) != __DISABLED_CHAR) + return send_prio_char(tty, START_CHAR(tty)); + break; default: - /* Try the mode commands */ - return tty_mode_ioctl(tty, file, cmd, arg); + return -EINVAL; } + return 0; + case TCFLSH: + return tty_perform_flush(tty, arg); + case TIOCOUTQ: + return put_user(tty_chars_in_buffer(tty), (int __user *) arg); + case TIOCINQ: + retval = tty->read_cnt; + if (L_ICANON(tty)) + retval = inq_canon(tty); + return put_user(retval, (unsigned int __user *) arg); + case TIOCPKT: + { + int pktmode; + + if (tty->driver->type != TTY_DRIVER_TYPE_PTY || + tty->driver->subtype != PTY_TYPE_MASTER) + return -ENOTTY; + if (get_user(pktmode, (int __user *) arg)) + return -EFAULT; + spin_lock_irqsave(&tty->ctrl_lock, flags); + if (pktmode) { + if (!tty->packet) { + tty->packet = 1; + tty->link->ctrl_status = 0; + } + } else + tty->packet = 0; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + return 0; + } + default: + /* Try the mode commands */ + return tty_mode_ioctl(tty, file, cmd, arg); + } } - EXPORT_SYMBOL(n_tty_ioctl);