X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fchar%2Ftty_ioctl.c;h=3b6fa7b0be8ba81c1f9d658cf63740394225172d;hb=97d41e90fe61399b99d74820cb7f2d6e0fbac91d;hp=f19cf9d7792d57816b53cf0e697bda80fe07a50e;hpb=2f058256cb64e346f4fb4499ff4e0f1c2791a4b4;p=powerpc.git diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index f19cf9d779..3b6fa7b0be 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,18 @@ #define TERMIOS_WAIT 2 #define TERMIOS_TERMIO 4 + +/** + * tty_wait_until_sent - wait for I/O to finish + * @tty: tty we are waiting for + * @timeout: how long we will wait + * + * Wait for characters pending in a tty driver to hit the wire, or + * for a timeout to occur (eg due to flow control) + * + * Locking: none + */ + void tty_wait_until_sent(struct tty_struct * tty, long timeout) { DECLARE_WAITQUEUE(wait, current); @@ -94,6 +107,18 @@ static void unset_locked_termios(struct termios *termios, old->c_cc[i] : termios->c_cc[i]; } +/** + * change_termios - update termios values + * @tty: tty to update + * @new_termios: desired new value + * + * Perform updates to the termios values set on this terminal. There + * is a bit of layering violation here with n_tty in terms of the + * internal knowledge of this function. + * + * Locking: termios_sem + */ + static void change_termios(struct tty_struct * tty, struct termios * new_termios) { int canon_change; @@ -107,7 +132,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); @@ -152,9 +177,22 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios (ld->set_termios)(tty, &old_termios); tty_ldisc_deref(ld); } - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); } +/** + * set_termios - set termios values for a tty + * @tty: terminal device + * @arg: user data + * @opt: option information + * + * Helper function to prepare termios data and run neccessary other + * functions before using change_termios to do the actual changes. + * + * Locking: + * Called functions take ldisc and termios_sem locks + */ + static int set_termios(struct tty_struct * tty, void __user *arg, int opt) { struct termios tmp_termios; @@ -247,13 +285,13 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { struct sgttyb tmp; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tmp.sg_ispeed = 0; tmp.sg_ospeed = 0; tmp.sg_erase = tty->termios->c_cc[VERASE]; tmp.sg_kill = tty->termios->c_cc[VKILL]; tmp.sg_flags = get_sgflags(tty); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -284,6 +322,17 @@ static void set_sgflags(struct termios * termios, int flags) } } +/** + * set_sgttyb - set legacy terminal values + * @tty: tty structure + * @sgttyb: pointer to old style terminal structure + * + * Updates a terminal from the legacy BSD style terminal information + * structure. + * + * Locking: termios_sem + */ + static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) { int retval; @@ -297,12 +346,12 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) return -EFAULT; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); termios = *tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); change_termios(tty, &termios); return 0; } @@ -369,22 +418,33 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars) } #endif -/* - * Send a high priority character to the tty. +/** + * send_prio_char - send priority character + * + * Send a high priority character to the tty even if stopped + * + * Locking: none for xchar method, write ordering for write method. */ -static void send_prio_char(struct tty_struct *tty, char ch) + +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); - return; + return 0; } + + if (mutex_lock_interruptible(&tty->atomic_write_lock)) + return -ERESTARTSYS; + if (was_stopped) start_tty(tty); tty->driver->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); + mutex_unlock(&tty->atomic_write_lock); + return 0; } int n_tty_ioctl(struct tty_struct * tty, struct file * file, @@ -458,11 +518,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, break; case TCIOFF: if (STOP_CHAR(tty) != __DISABLED_CHAR) - send_prio_char(tty, STOP_CHAR(tty)); + return send_prio_char(tty, STOP_CHAR(tty)); break; case TCION: if (START_CHAR(tty) != __DISABLED_CHAR) - send_prio_char(tty, START_CHAR(tty)); + return send_prio_char(tty, START_CHAR(tty)); break; default: return -EINVAL; @@ -537,11 +597,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file, case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; - down(&tty->termios_sem); + mutex_lock(&tty->termios_mutex); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - up(&tty->termios_sem); + mutex_unlock(&tty->termios_mutex); return 0; default: return -ENOIOCTLCMD;