diff options
Diffstat (limited to 'drivers/char/tty_io.c')
| -rw-r--r-- | drivers/char/tty_io.c | 336 | 
1 files changed, 213 insertions, 123 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 047a17339f8..54c4ada460e 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -95,8 +95,9 @@  #include <linux/wait.h>  #include <linux/bitops.h>  #include <linux/delay.h> +#include <linux/seq_file.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h>  #include <asm/system.h>  #include <linux/kbd_kern.h> @@ -682,7 +683,7 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)  static DEFINE_SPINLOCK(tty_ldisc_lock);  static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);  /* Line disc dispatch table */ -static struct tty_ldisc tty_ldiscs[NR_LDISCS]; +static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];  /**   *	tty_register_ldisc	-	install a line discipline @@ -697,7 +698,7 @@ static struct tty_ldisc tty_ldiscs[NR_LDISCS];   *		takes tty_ldisc_lock to guard against ldisc races   */ -int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) +int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)  {  	unsigned long flags;  	int ret = 0; @@ -706,10 +707,9 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)  		return -EINVAL;  	spin_lock_irqsave(&tty_ldisc_lock, flags); -	tty_ldiscs[disc] = *new_ldisc; -	tty_ldiscs[disc].num = disc; -	tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; -	tty_ldiscs[disc].refcount = 0; +	tty_ldiscs[disc] = new_ldisc; +	new_ldisc->num = disc; +	new_ldisc->refcount = 0;  	spin_unlock_irqrestore(&tty_ldisc_lock, flags);  	return ret; @@ -737,19 +737,56 @@ int tty_unregister_ldisc(int disc)  		return -EINVAL;  	spin_lock_irqsave(&tty_ldisc_lock, flags); -	if (tty_ldiscs[disc].refcount) +	if (tty_ldiscs[disc]->refcount)  		ret = -EBUSY;  	else -		tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; +		tty_ldiscs[disc] = NULL;  	spin_unlock_irqrestore(&tty_ldisc_lock, flags);  	return ret;  }  EXPORT_SYMBOL(tty_unregister_ldisc); + +/** + *	tty_ldisc_try_get	-	try and reference an ldisc + *	@disc: ldisc number + *	@ld: tty ldisc structure to complete + * + *	Attempt to open and lock a line discipline into place. Return + *	the line discipline refcounted and assigned in ld. On an error + *	report the error code back + */ + +static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld) +{ +	unsigned long flags; +	struct tty_ldisc_ops *ldops; +	int err = -EINVAL; +	 +	spin_lock_irqsave(&tty_ldisc_lock, flags); +	ld->ops = NULL; +	ldops = tty_ldiscs[disc]; +	/* Check the entry is defined */ +	if (ldops) { +		/* If the module is being unloaded we can't use it */ +		if (!try_module_get(ldops->owner)) +			err = -EAGAIN; +		else { +			/* lock it */ +			ldops->refcount++; +			ld->ops = ldops; +			err = 0; +		} +	} +	spin_unlock_irqrestore(&tty_ldisc_lock, flags); +	return err; +} +  /**   *	tty_ldisc_get		-	take a reference to an ldisc   *	@disc: ldisc number + *	@ld: tty line discipline structure to use   *   *	Takes a reference to a line discipline. Deals with refcounts and   *	module locking counts. Returns NULL if the discipline is not available. @@ -760,32 +797,20 @@ EXPORT_SYMBOL(tty_unregister_ldisc);   *		takes tty_ldisc_lock to guard against ldisc races   */ -struct tty_ldisc *tty_ldisc_get(int disc) +static int tty_ldisc_get(int disc, struct tty_ldisc *ld)  { -	unsigned long flags; -	struct tty_ldisc *ld; +	int err;  	if (disc < N_TTY || disc >= NR_LDISCS) -		return NULL; - -	spin_lock_irqsave(&tty_ldisc_lock, flags); - -	ld = &tty_ldiscs[disc]; -	/* Check the entry is defined */ -	if (ld->flags & LDISC_FLAG_DEFINED) { -		/* If the module is being unloaded we can't use it */ -		if (!try_module_get(ld->owner)) -			ld = NULL; -		else /* lock it */ -			ld->refcount++; -	} else -		ld = NULL; -	spin_unlock_irqrestore(&tty_ldisc_lock, flags); -	return ld; +		return -EINVAL; +	err = tty_ldisc_try_get(disc, ld); +	if (err == -EAGAIN) { +		request_module("tty-ldisc-%d", disc); +		err = tty_ldisc_try_get(disc, ld); +	} +	return err;  } -EXPORT_SYMBOL_GPL(tty_ldisc_get); -  /**   *	tty_ldisc_put		-	drop ldisc reference   *	@disc: ldisc number @@ -797,22 +822,67 @@ EXPORT_SYMBOL_GPL(tty_ldisc_get);   *		takes tty_ldisc_lock to guard against ldisc races   */ -void tty_ldisc_put(int disc) +static void tty_ldisc_put(struct tty_ldisc_ops *ld)  { -	struct tty_ldisc *ld;  	unsigned long flags; +	int disc = ld->num;  	BUG_ON(disc < N_TTY || disc >= NR_LDISCS);  	spin_lock_irqsave(&tty_ldisc_lock, flags); -	ld = &tty_ldiscs[disc]; +	ld = tty_ldiscs[disc];  	BUG_ON(ld->refcount == 0);  	ld->refcount--;  	module_put(ld->owner);  	spin_unlock_irqrestore(&tty_ldisc_lock, flags);  } -EXPORT_SYMBOL_GPL(tty_ldisc_put); +static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) +{ +	return (*pos < NR_LDISCS) ? pos : NULL; +} + +static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ +	(*pos)++; +	return (*pos < NR_LDISCS) ? pos : NULL; +} + +static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) +{ +} + +static int tty_ldiscs_seq_show(struct seq_file *m, void *v) +{ +	int i = *(loff_t *)v; +	struct tty_ldisc ld; +	 +	if (tty_ldisc_get(i, &ld) < 0) +		return 0; +	seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i); +	tty_ldisc_put(ld.ops); +	return 0; +} + +static const struct seq_operations tty_ldiscs_seq_ops = { +	.start	= tty_ldiscs_seq_start, +	.next	= tty_ldiscs_seq_next, +	.stop	= tty_ldiscs_seq_stop, +	.show	= tty_ldiscs_seq_show, +}; + +static int proc_tty_ldiscs_open(struct inode *inode, struct file *file) +{ +	return seq_open(file, &tty_ldiscs_seq_ops); +} + +const struct file_operations tty_ldiscs_proc_fops = { +	.owner		= THIS_MODULE, +	.open		= proc_tty_ldiscs_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +};  /**   *	tty_ldisc_assign	-	set ldisc on a tty @@ -829,8 +899,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_put);  static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)  { +	ld->refcount = 0;  	tty->ldisc = *ld; -	tty->ldisc.refcount = 0;  }  /** @@ -954,6 +1024,41 @@ static void tty_ldisc_enable(struct tty_struct *tty)  }  /** + *	tty_ldisc_restore	-	helper for tty ldisc change + *	@tty: tty to recover + *	@old: previous ldisc + * + *	Restore the previous line discipline or N_TTY when a line discipline + *	change fails due to an open error + */ + +static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) +{ +	char buf[64]; +	struct tty_ldisc new_ldisc; + +	/* There is an outstanding reference here so this is safe */ +	tty_ldisc_get(old->ops->num, old); +	tty_ldisc_assign(tty, old); +	tty_set_termios_ldisc(tty, old->ops->num); +	if (old->ops->open && (old->ops->open(tty) < 0)) { +		tty_ldisc_put(old->ops); +		/* This driver is always present */ +		if (tty_ldisc_get(N_TTY, &new_ldisc) < 0) +			panic("n_tty: get"); +		tty_ldisc_assign(tty, &new_ldisc); +		tty_set_termios_ldisc(tty, N_TTY); +		if (new_ldisc.ops->open) { +			int r = new_ldisc.ops->open(tty); +				if (r < 0) +				panic("Couldn't open N_TTY ldisc for " +				      "%s --- error %d.", +				      tty_name(tty, buf), r); +		} +	} +} + +/**   *	tty_set_ldisc		-	set line discipline   *	@tty: the terminal to set   *	@ldisc: the line discipline @@ -967,28 +1072,18 @@ static void tty_ldisc_enable(struct tty_struct *tty)  static int tty_set_ldisc(struct tty_struct *tty, int ldisc)  { -	int retval = 0; -	struct tty_ldisc o_ldisc; -	char buf[64]; +	int retval; +	struct tty_ldisc o_ldisc, new_ldisc;  	int work;  	unsigned long flags; -	struct tty_ldisc *ld;  	struct tty_struct *o_tty; -	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) -		return -EINVAL; -  restart: - -	ld = tty_ldisc_get(ldisc); -	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */ -	/* Cyrus Durgin <cider@speakeasy.org> */ -	if (ld == NULL) { -		request_module("tty-ldisc-%d", ldisc); -		ld = tty_ldisc_get(ldisc); -	} -	if (ld == NULL) -		return -EINVAL; +	/* This is a bit ugly for now but means we can break the 'ldisc +	   is part of the tty struct' assumption later */ +	retval = tty_ldisc_get(ldisc, &new_ldisc); +	if (retval) +		return retval;  	/*  	 *	Problem: What do we do if this blocks ? @@ -996,8 +1091,8 @@ restart:  	tty_wait_until_sent(tty, 0); -	if (tty->ldisc.num == ldisc) { -		tty_ldisc_put(ldisc); +	if (tty->ldisc.ops->num == ldisc) { +		tty_ldisc_put(new_ldisc.ops);  		return 0;  	} @@ -1024,7 +1119,7 @@ restart:  			/* Free the new ldisc we grabbed. Must drop the lock  			   first. */  			spin_unlock_irqrestore(&tty_ldisc_lock, flags); -			tty_ldisc_put(ldisc); +			tty_ldisc_put(o_ldisc.ops);  			/*  			 * There are several reasons we may be busy, including  			 * random momentary I/O traffic. We must therefore @@ -1038,7 +1133,7 @@ restart:  		}  		if (o_tty && o_tty->ldisc.refcount) {  			spin_unlock_irqrestore(&tty_ldisc_lock, flags); -			tty_ldisc_put(ldisc); +			tty_ldisc_put(o_tty->ldisc.ops);  			if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)  				return -ERESTARTSYS;  			goto restart; @@ -1049,8 +1144,9 @@ restart:  	 *	another ldisc change  	 */  	if (!test_bit(TTY_LDISC, &tty->flags)) { +		struct tty_ldisc *ld;  		spin_unlock_irqrestore(&tty_ldisc_lock, flags); -		tty_ldisc_put(ldisc); +		tty_ldisc_put(new_ldisc.ops);  		ld = tty_ldisc_ref_wait(tty);  		tty_ldisc_deref(ld);  		goto restart; @@ -1060,7 +1156,7 @@ restart:  	if (o_tty)  		clear_bit(TTY_LDISC, &o_tty->flags);  	spin_unlock_irqrestore(&tty_ldisc_lock, flags); - +	  	/*  	 *	From this point on we know nobody has an ldisc  	 *	usage reference, nor can they obtain one until @@ -1070,45 +1166,30 @@ restart:  	work = cancel_delayed_work(&tty->buf.work);  	/*  	 * Wait for ->hangup_work and ->buf.work handlers to terminate +	 * MUST NOT hold locks here.  	 */  	flush_scheduled_work();  	/* Shutdown the current discipline. */ -	if (tty->ldisc.close) -		(tty->ldisc.close)(tty); +	if (o_ldisc.ops->close) +		(o_ldisc.ops->close)(tty);  	/* Now set up the new line discipline. */ -	tty_ldisc_assign(tty, ld); +	tty_ldisc_assign(tty, &new_ldisc);  	tty_set_termios_ldisc(tty, ldisc); -	if (tty->ldisc.open) -		retval = (tty->ldisc.open)(tty); +	if (new_ldisc.ops->open) +		retval = (new_ldisc.ops->open)(tty);  	if (retval < 0) { -		tty_ldisc_put(ldisc); -		/* There is an outstanding reference here so this is safe */ -		tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num)); -		tty_set_termios_ldisc(tty, tty->ldisc.num); -		if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { -			tty_ldisc_put(o_ldisc.num); -			/* This driver is always present */ -			tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); -			tty_set_termios_ldisc(tty, N_TTY); -			if (tty->ldisc.open) { -				int r = tty->ldisc.open(tty); - -				if (r < 0) -					panic("Couldn't open N_TTY ldisc for " -					      "%s --- error %d.", -					      tty_name(tty, buf), r); -			} -		} +		tty_ldisc_put(new_ldisc.ops); +		tty_ldisc_restore(tty, &o_ldisc);  	}  	/* At this point we hold a reference to the new ldisc and a  	   a reference to the old ldisc. If we ended up flipping back  	   to the existing ldisc we have two references to it */ -	if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc) +	if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)  		tty->ops->set_ldisc(tty); -	tty_ldisc_put(o_ldisc.num); +	tty_ldisc_put(o_ldisc.ops);  	/*  	 *	Allow ldisc referencing to occur as soon as the driver @@ -1335,8 +1416,8 @@ void tty_wakeup(struct tty_struct *tty)  	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {  		ld = tty_ldisc_ref(tty);  		if (ld) { -			if (ld->write_wakeup) -				ld->write_wakeup(tty); +			if (ld->ops->write_wakeup) +				ld->ops->write_wakeup(tty);  			tty_ldisc_deref(ld);  		}  	} @@ -1357,8 +1438,8 @@ void tty_ldisc_flush(struct tty_struct *tty)  {  	struct tty_ldisc *ld = tty_ldisc_ref(tty);  	if (ld) { -		if (ld->flush_buffer) -			ld->flush_buffer(tty); +		if (ld->ops->flush_buffer) +			ld->ops->flush_buffer(tty);  		tty_ldisc_deref(ld);  	}  	tty_buffer_flush(tty); @@ -1386,7 +1467,7 @@ static void tty_reset_termios(struct tty_struct *tty)   *	do_tty_hangup		-	actual handler for hangup events   *	@work: tty device   * - *	This can be called by the "eventd" kernel thread.  That is process +k *	This can be called by the "eventd" kernel thread.  That is process   *	synchronous but doesn't hold any locks, so we need to make sure we   *	have the appropriate locks for what we're doing.   * @@ -1449,14 +1530,14 @@ static void do_tty_hangup(struct work_struct *work)  	ld = tty_ldisc_ref(tty);  	if (ld != NULL) {  		/* We may have no line discipline at this point */ -		if (ld->flush_buffer) -			ld->flush_buffer(tty); +		if (ld->ops->flush_buffer) +			ld->ops->flush_buffer(tty);  		tty_driver_flush_buffer(tty);  		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && -		    ld->write_wakeup) -			ld->write_wakeup(tty); -		if (ld->hangup) -			ld->hangup(tty); +		    ld->ops->write_wakeup) +			ld->ops->write_wakeup(tty); +		if (ld->ops->hangup) +			ld->ops->hangup(tty);  	}  	/*  	 * FIXME: Once we trust the LDISC code better we can wait here for @@ -1825,8 +1906,8 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,  	/* We want to wait for the line discipline to sort out in this  	   situation */  	ld = tty_ldisc_ref_wait(tty); -	if (ld->read) -		i = (ld->read)(tty, file, buf, count); +	if (ld->ops->read) +		i = (ld->ops->read)(tty, file, buf, count);  	else  		i = -EIO;  	tty_ldisc_deref(ld); @@ -1978,10 +2059,10 @@ static ssize_t tty_write(struct file *file, const char __user *buf,  		printk(KERN_ERR "tty driver %s lacks a write_room method.\n",  			tty->driver->name);  	ld = tty_ldisc_ref_wait(tty); -	if (!ld->write) +	if (!ld->ops->write)  		ret = -EIO;  	else -		ret = do_tty_write(ld->write, tty, file, buf, count); +		ret = do_tty_write(ld->ops->write, tty, file, buf, count);  	tty_ldisc_deref(ld);  	return ret;  } @@ -2076,6 +2157,7 @@ static int init_dev(struct tty_driver *driver, int idx,  	struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc;  	struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;  	int retval = 0; +	struct tty_ldisc *ld;  	/* check whether we're reopening an existing tty */  	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { @@ -2224,17 +2306,19 @@ static int init_dev(struct tty_driver *driver, int idx,  	 * If we fail here just call release_tty to clean up.  No need  	 * to decrement the use counts, as release_tty doesn't care.  	 */ +	  +	ld = &tty->ldisc; -	if (tty->ldisc.open) { -		retval = (tty->ldisc.open)(tty); +	if (ld->ops->open) { +		retval = (ld->ops->open)(tty);  		if (retval)  			goto release_mem_out;  	} -	if (o_tty && o_tty->ldisc.open) { -		retval = (o_tty->ldisc.open)(o_tty); +	if (o_tty && o_tty->ldisc.ops->open) { +		retval = (o_tty->ldisc.ops->open)(o_tty);  		if (retval) { -			if (tty->ldisc.close) -				(tty->ldisc.close)(tty); +			if (ld->ops->close) +				(ld->ops->close)(tty);  			goto release_mem_out;  		}  		tty_ldisc_enable(o_tty); @@ -2378,6 +2462,7 @@ static void release_tty(struct tty_struct *tty, int idx)  static void release_dev(struct file *filp)  {  	struct tty_struct *tty, *o_tty; +	struct tty_ldisc ld;  	int	pty_master, tty_closing, o_tty_closing, do_sleep;  	int	devpts;  	int	idx; @@ -2611,26 +2696,27 @@ static void release_dev(struct file *filp)  	spin_unlock_irqrestore(&tty_ldisc_lock, flags);  	/*  	 * Shutdown the current line discipline, and reset it to N_TTY. -	 * N.B. why reset ldisc when we're releasing the memory??  	 *  	 * FIXME: this MUST get fixed for the new reflocking  	 */ -	if (tty->ldisc.close) -		(tty->ldisc.close)(tty); -	tty_ldisc_put(tty->ldisc.num); +	if (tty->ldisc.ops->close) +		(tty->ldisc.ops->close)(tty); +	tty_ldisc_put(tty->ldisc.ops);  	/*  	 *	Switch the line discipline back  	 */ -	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); +	WARN_ON(tty_ldisc_get(N_TTY, &ld)); +	tty_ldisc_assign(tty, &ld);  	tty_set_termios_ldisc(tty, N_TTY);  	if (o_tty) {  		/* FIXME: could o_tty be in setldisc here ? */  		clear_bit(TTY_LDISC, &o_tty->flags); -		if (o_tty->ldisc.close) -			(o_tty->ldisc.close)(o_tty); -		tty_ldisc_put(o_tty->ldisc.num); -		tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); +		if (o_tty->ldisc.ops->close) +			(o_tty->ldisc.ops->close)(o_tty); +		tty_ldisc_put(o_tty->ldisc.ops); +		WARN_ON(tty_ldisc_get(N_TTY, &ld)); +		tty_ldisc_assign(o_tty, &ld);  		tty_set_termios_ldisc(o_tty, N_TTY);  	}  	/* @@ -2899,8 +2985,8 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)  		return 0;  	ld = tty_ldisc_ref_wait(tty); -	if (ld->poll) -		ret = (ld->poll)(tty, filp, wait); +	if (ld->ops->poll) +		ret = (ld->ops->poll)(tty, filp, wait);  	tty_ldisc_deref(ld);  	return ret;  } @@ -2974,7 +3060,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)  	if (get_user(ch, p))  		return -EFAULT;  	ld = tty_ldisc_ref_wait(tty); -	ld->receive_buf(tty, &ch, &mbz, 1); +	ld->ops->receive_buf(tty, &ch, &mbz, 1);  	tty_ldisc_deref(ld);  	return 0;  } @@ -3528,7 +3614,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  	case TIOCGSID:  		return tiocgsid(tty, real_tty, p);  	case TIOCGETD: -		return put_user(tty->ldisc.num, (int __user *)p); +		return put_user(tty->ldisc.ops->num, (int __user *)p);  	case TIOCSETD:  		return tiocsetd(tty, p);  #ifdef CONFIG_VT @@ -3581,8 +3667,8 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  	}  	ld = tty_ldisc_ref_wait(tty);  	retval = -EINVAL; -	if (ld->ioctl) { -		retval = ld->ioctl(tty, file, cmd, arg); +	if (ld->ops->ioctl) { +		retval = ld->ops->ioctl(tty, file, cmd, arg);  		if (retval == -ENOIOCTLCMD)  			retval = -EINVAL;  	} @@ -3609,8 +3695,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,  	}  	ld = tty_ldisc_ref_wait(tty); -	if (ld->compat_ioctl) -		retval = ld->compat_ioctl(tty, file, cmd, arg); +	if (ld->ops->compat_ioctl) +		retval = ld->ops->compat_ioctl(tty, file, cmd, arg);  	tty_ldisc_deref(ld);  	return retval; @@ -3782,7 +3868,8 @@ static void flush_to_ldisc(struct work_struct *work)  			flag_buf = head->flag_buf_ptr + head->read;  			head->read += count;  			spin_unlock_irqrestore(&tty->buf.lock, flags); -			disc->receive_buf(tty, char_buf, flag_buf, count); +			disc->ops->receive_buf(tty, char_buf, +							flag_buf, count);  			spin_lock_irqsave(&tty->buf.lock, flags);  		}  		/* Restore the queue head */ @@ -3843,9 +3930,12 @@ EXPORT_SYMBOL(tty_flip_buffer_push);  static void initialize_tty_struct(struct tty_struct *tty)  { +	struct tty_ldisc ld;  	memset(tty, 0, sizeof(struct tty_struct));  	tty->magic = TTY_MAGIC; -	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); +	if (tty_ldisc_get(N_TTY, &ld) < 0) +		panic("n_tty: init_tty"); +	tty_ldisc_assign(tty, &ld);  	tty->session = NULL;  	tty->pgrp = NULL;  	tty->overrun_time = jiffies;  |