X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Fchar%2Fpty.c;h=112a6ba9a96fef2b3fec186bbaddce9944df752f;hb=923a789b49c7269a0245d5af6afe486188d940df;hp=a391badef52a12feb48547498a19699b42c39bb5;hpb=15f1a6338ddd4e69fff965d4b3a0e1bfb7a13d9c;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/pty.c b/drivers/char/pty.c index a391badef52..112a6ba9a96 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -5,13 +5,13 @@ * * Added support for a Unix98-style ptmx device. * -- C. Scott Ananian , 14-Jan-1998 - * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to - * waiting writers -- Sapan Bhatia - * * + * When reading this code see also fs/devpts. In particular note that the + * driver_data field is used by the devpts side as a binding to the devpts + * inode. */ -#include /* For EXPORT_SYMBOL */ +#include #include #include @@ -24,26 +24,24 @@ #include #include #include - -#include -#include +#include #include #include +#include + /* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS struct tty_driver *ptm_driver; static struct tty_driver *pts_driver; #endif -static void pty_close(struct tty_struct * tty, struct file * filp) +static void pty_close(struct tty_struct *tty, struct file *filp) { - if (!tty) - return; - if (tty->driver->subtype == PTY_TYPE_MASTER) { - if (tty->count > 1) - printk("master pty_close: count = %d!!\n", tty->count); - } else { + BUG_ON(!tty); + if (tty->driver->subtype == PTY_TYPE_MASTER) + WARN_ON(tty->count > 1); + else { if (tty->count > 2) return; } @@ -70,13 +68,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp) * The unthrottle routine is called by the line discipline to signal * that it can receive more characters. For PTY's, the TTY_THROTTLED * flag is always set, to force the line discipline to always call the - * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE + * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE * characters in the queue. This is necessary since each time this * happens, we need to wake up any sleeping processes that could be * (1) trying to send data to the pty, or (2) waiting in wait_until_sent() * for the pty buffer to be drained. */ -static void pty_unthrottle(struct tty_struct * tty) +static void pty_unthrottle(struct tty_struct *tty) { struct tty_struct *o_tty = tty->link; @@ -88,7 +86,7 @@ static void pty_unthrottle(struct tty_struct * tty) } /* - * WSH 05/24/97: modified to + * WSH 05/24/97: modified to * (1) use space in tty->flip instead of a shared temp buffer * The flip buffers aren't being used for a pty, so there's lots * of space available. The buffer is protected by a per-pty @@ -101,7 +99,8 @@ static void pty_unthrottle(struct tty_struct * tty) * not our partners. We can't just take the other one blindly without * risking deadlocks. */ -static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count) +static int pty_write(struct tty_struct *tty, const unsigned char *buf, + int count) { struct tty_struct *to = tty->link; int c; @@ -113,7 +112,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun if (c > count) c = count; to->ldisc.ops->receive_buf(to, buf, NULL, c); - + return c; } @@ -129,17 +128,17 @@ static int pty_write_room(struct tty_struct *tty) /* * WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior - * The chars_in_buffer() value is used by the ldisc select() function + * The chars_in_buffer() value is used by the ldisc select() function * to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256). * The pty driver chars_in_buffer() Master/Slave must behave differently: * * The Master side needs to allow typed-ahead commands to accumulate * while being canonicalized, so we report "our buffer" as empty until * some threshold is reached, and then report the count. (Any count > - * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock - * the count returned must be 0 if no canonical data is available to be + * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock + * the count returned must be 0 if no canonical data is available to be * read. (The N_TTY ldisc.chars_in_buffer now knows this.) - * + * * The Slave side passes all characters in raw mode to the Master side's * buffer where they can be read immediately, so in this case we can * return the true count in the buffer. @@ -156,21 +155,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty) /* The ldisc must report 0 if no characters available to be read */ count = to->ldisc.ops->chars_in_buffer(to); - if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; + if (tty->driver->subtype == PTY_TYPE_SLAVE) + return count; - /* Master side driver ... if the other side's read buffer is less than + /* Master side driver ... if the other side's read buffer is less than * half full, return 0 to allow writers to proceed; otherwise return - * the count. This leaves a comfortable margin to avoid overflow, + * the count. This leaves a comfortable margin to avoid overflow, * and still allows half a buffer's worth of typed-ahead commands. */ - return ((count < N_TTY_BUF_SIZE/2) ? 0 : count); + return (count < N_TTY_BUF_SIZE/2) ? 0 : count; } /* Set the lock flag on a pty */ -static int pty_set_lock(struct tty_struct *tty, int __user * arg) +static int pty_set_lock(struct tty_struct *tty, int __user *arg) { int val; - if (get_user(val,arg)) + if (get_user(val, arg)) return -EFAULT; if (val) set_bit(TTY_PTY_LOCK, &tty->flags); @@ -183,13 +183,13 @@ static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; unsigned long flags; - + if (!to) return; - + if (to->ldisc.ops->flush_buffer) to->ldisc.ops->flush_buffer(to); - + if (to->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status |= TIOCPKT_FLUSHWRITE; @@ -198,7 +198,7 @@ static void pty_flush_buffer(struct tty_struct *tty) } } -static int pty_open(struct tty_struct *tty, struct file * filp) +static int pty_open(struct tty_struct *tty, struct file *filp) { int retval = -ENODEV; @@ -215,16 +215,65 @@ static int pty_open(struct tty_struct *tty, struct file * filp) clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); retval = 0; out: return retval; } -static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void pty_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) { - tty->termios->c_cflag &= ~(CSIZE | PARENB); - tty->termios->c_cflag |= (CS8 | CREAD); + tty->termios->c_cflag &= ~(CSIZE | PARENB); + tty->termios->c_cflag |= (CS8 | CREAD); +} + +/** + * pty_do_resize - resize event + * @tty: tty being resized + * @real_tty: real tty (not the same as tty if using a pty/tty pair) + * @rows: rows (character) + * @cols: cols (character) + * + * Update the termios variables and send the neccessary signals to + * peform a terminal resize correctly + */ + +int pty_resize(struct tty_struct *tty, struct winsize *ws) +{ + struct pid *pgrp, *rpgrp; + unsigned long flags; + struct tty_struct *pty = tty->link; + + /* For a PTY we need to lock the tty side */ + mutex_lock(&tty->termios_mutex); + if (!memcmp(ws, &tty->winsize, sizeof(*ws))) + goto done; + + /* Get the PID values and reference them so we can + avoid holding the tty ctrl lock while sending signals. + We need to lock these individually however. */ + + spin_lock_irqsave(&tty->ctrl_lock, flags); + pgrp = get_pid(tty->pgrp); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + + spin_lock_irqsave(&pty->ctrl_lock, flags); + rpgrp = get_pid(pty->pgrp); + spin_unlock_irqrestore(&pty->ctrl_lock, flags); + + if (pgrp) + kill_pgrp(pgrp, SIGWINCH, 1); + if (rpgrp != pgrp && rpgrp) + kill_pgrp(rpgrp, SIGWINCH, 1); + + put_pid(pgrp); + put_pid(rpgrp); + + tty->winsize = *ws; + pty->winsize = *ws; /* Never used so will go away soon */ +done: + mutex_unlock(&tty->termios_mutex); + return 0; } static int pty_install(struct tty_driver *driver, struct tty_struct *tty) @@ -254,7 +303,7 @@ static int pty_install(struct tty_driver *driver, struct tty_struct *tty) tty_free_termios(tty); goto free_mem_out; } - + /* * Everything allocated ... set up the o_tty structure. */ @@ -287,6 +336,7 @@ static const struct tty_operations pty_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, + .resize = pty_resize }; /* Traditional BSD devices */ @@ -316,6 +366,7 @@ static const struct tty_operations pty_ops_bsd = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_bsd_ioctl, + .resize = pty_resize }; static void __init legacy_pty_init(void) @@ -381,9 +432,9 @@ static inline void legacy_pty_init(void) { } * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */ int pty_limit = NR_UNIX98_PTY_DEFAULT; -static int pty_limit_min = 0; +static int pty_limit_min; static int pty_limit_max = NR_UNIX98_PTY_MAX; -static int pty_count = 0; +static int pty_count; static struct cdev ptmx_cdev; @@ -485,7 +536,6 @@ static void pty_unix98_shutdown(struct tty_struct *tty) { /* We have our own method as we don't use the tty index */ kfree(tty->termios); - kfree(tty->termios_locked); } /* We have no need to install and remove our tty objects as devpts does all @@ -506,20 +556,17 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) } initialize_tty_struct(o_tty, driver->other, idx); - tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL); + tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); if (tty->termios == NULL) goto free_mem_out; *tty->termios = driver->init_termios; - tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL); - if (tty->termios_locked == NULL) - goto free_mem_out; - o_tty->termios = kmalloc(sizeof(struct ktermios), GFP_KERNEL); + tty->termios_locked = tty->termios + 1; + + o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); if (o_tty->termios == NULL) goto free_mem_out; *o_tty->termios = driver->other->init_termios; - o_tty->termios_locked = kzalloc(sizeof(struct ktermios), GFP_KERNEL); - if (o_tty->termios_locked == NULL) - goto free_mem_out; + o_tty->termios_locked = o_tty->termios + 1; tty_driver_kref_get(driver->other); if (driver->subtype == PTY_TYPE_MASTER) @@ -540,10 +587,7 @@ free_mem_out: kfree(o_tty->termios); module_put(o_tty->driver->owner); free_tty_struct(o_tty); - kfree(tty->termios_locked); kfree(tty->termios); - free_tty_struct(tty); - module_put(driver->owner); return -ENOMEM; } @@ -565,7 +609,8 @@ static const struct tty_operations ptm_unix98_ops = { .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, .ioctl = pty_unix98_ioctl, - .shutdown = pty_unix98_shutdown + .shutdown = pty_unix98_shutdown, + .resize = pty_resize }; static const struct tty_operations pty_unix98_ops = { @@ -691,13 +736,13 @@ static void __init unix98_pty_init(void) TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; tty_set_operations(pts_driver, &pty_unix98_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"); - register_sysctl_table(pty_root_table); + register_sysctl_table(pty_root_table); /* Now create the /dev/ptmx special device */ tty_default_fops(&ptmx_fops);