[go: nahoru, domu]

101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/types.h>
201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/errno.h>
38b3ffa173ffa13ac47c1d7524af92d4b2c95abfcJiri Slaby#include <linux/kmod.h>
401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/sched.h>
501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/interrupt.h>
601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/tty.h>
701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/tty_driver.h>
801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/file.h>
901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/mm.h>
1001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/string.h>
1101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/slab.h>
1201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/poll.h>
1301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/proc_fs.h>
1401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/module.h>
1501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/device.h>
1601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/wait.h>
1701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/bitops.h>
1801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/seq_file.h>
1901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/uaccess.h>
200c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby#include <linux/ratelimit.h>
2101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
22fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley#undef LDISC_DEBUG_HANGUP
23fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley
24fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley#ifdef LDISC_DEBUG_HANGUP
25fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley#define tty_ldisc_debug(tty, f, args...) ({				       \
26fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley	char __b[64];							       \
27fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley	printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \
28fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley})
29fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley#else
30fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley#define tty_ldisc_debug(tty, f, args...)
31fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley#endif
32fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley
33d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley/* lockdep nested classes for tty->ldisc_sem */
34d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleyenum {
35d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	LDISC_SEM_NORMAL,
36d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	LDISC_SEM_OTHER,
37d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley};
38d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
39d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
4001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/*
4101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	This guards the refcounted line discipline lists. The lock
4201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	must be taken with irqs off because there are hangup path
4301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	callers who will do ldisc lookups and cannot sleep.
4401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
4501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
46137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurleystatic DEFINE_RAW_SPINLOCK(tty_ldiscs_lock);
4701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/* Line disc dispatch table */
4801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
4901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
5001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
5101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_register_ldisc	-	install a line discipline
5201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@disc: ldisc number
5301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@new_ldisc: pointer to the ldisc object
5401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
5501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Installs a new line discipline into the kernel. The discipline
5601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	is set up as unreferenced and then made available to the kernel
5701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	from this point onwards.
5801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
5901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Locking:
60137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley *		takes tty_ldiscs_lock to guard against ldisc races
6101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
6201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
6301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
6401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
6501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	unsigned long flags;
6601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	int ret = 0;
6701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
6801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	if (disc < N_TTY || disc >= NR_LDISCS)
6901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		return -EINVAL;
7001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
71137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
7201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	tty_ldiscs[disc] = new_ldisc;
7301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	new_ldisc->num = disc;
7401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	new_ldisc->refcount = 0;
75137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
7601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
7701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return ret;
7801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
7901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL(tty_register_ldisc);
8001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
8101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
8201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_unregister_ldisc	-	unload a line discipline
8301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@disc: ldisc number
8401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@new_ldisc: pointer to the ldisc object
8501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
8601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Remove a line discipline from the kernel providing it is not
8701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	currently in use.
8801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
8901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Locking:
90137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley *		takes tty_ldiscs_lock to guard against ldisc races
9101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
9201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
9301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_unregister_ldisc(int disc)
9401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
9501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	unsigned long flags;
9601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	int ret = 0;
9701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
9801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	if (disc < N_TTY || disc >= NR_LDISCS)
9901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		return -EINVAL;
10001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
101137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
10201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	if (tty_ldiscs[disc]->refcount)
10301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		ret = -EBUSY;
10401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	else
10501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		tty_ldiscs[disc] = NULL;
106137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
10701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
10801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return ret;
10901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
11001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL(tty_unregister_ldisc);
11101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
112f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvaldsstatic struct tty_ldisc_ops *get_ldops(int disc)
113f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds{
114f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	unsigned long flags;
115f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	struct tty_ldisc_ops *ldops, *ret;
116f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds
117137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
118f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	ret = ERR_PTR(-EINVAL);
119f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	ldops = tty_ldiscs[disc];
120f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	if (ldops) {
121f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds		ret = ERR_PTR(-EAGAIN);
122f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds		if (try_module_get(ldops->owner)) {
123f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds			ldops->refcount++;
124f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds			ret = ldops;
125f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds		}
126f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	}
127137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
128f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	return ret;
129f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds}
130f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds
131f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvaldsstatic void put_ldops(struct tty_ldisc_ops *ldops)
132f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds{
133f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	unsigned long flags;
134f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds
135137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
136f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	ldops->refcount--;
137f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	module_put(ldops->owner);
138137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley	raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
139f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds}
14001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
14101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
14201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_get		-	take a reference to an ldisc
14301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@disc: ldisc number
14401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
14501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Takes a reference to a line discipline. Deals with refcounts and
14601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	module locking counts. Returns NULL if the discipline is not available.
14701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Returns a pointer to the discipline and bumps the ref count if it is
14801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	available
14901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
15001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Locking:
151137084bbaddf4f6dde948ef3a14e18ba0754cc0dPeter Hurley *		takes tty_ldiscs_lock to guard against ldisc races
15201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
15301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
15436697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurleystatic struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
15501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
156c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	struct tty_ldisc *ld;
157182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	struct tty_ldisc_ops *ldops;
15801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
15901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	if (disc < N_TTY || disc >= NR_LDISCS)
160c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		return ERR_PTR(-EINVAL);
161182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds
162182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	/*
163182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	 * Get the ldisc ops - we may need to request them to be loaded
164182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	 * dynamically and try again.
165182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	 */
166182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	ldops = get_ldops(disc);
167182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	if (IS_ERR(ldops)) {
16801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		request_module("tty-ldisc-%d", disc);
169182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds		ldops = get_ldops(disc);
170182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds		if (IS_ERR(ldops))
171182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds			return ERR_CAST(ldops);
172182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	}
173182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds
174182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
175182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	if (ld == NULL) {
176182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds		put_ldops(ldops);
177182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds		return ERR_PTR(-ENOMEM);
17801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	}
179182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds
180182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds	ld->ops = ldops;
18136697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	ld->tty = tty;
1821541f845d123a48fbca3cee32b2963b3fb3da83aIvo Sieben
183c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	return ld;
18401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
18501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
186734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley/**
187734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley *	tty_ldisc_put		-	release the ldisc
188734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley *
189734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley *	Complement of tty_ldisc_get().
190734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley */
191734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurleystatic inline void tty_ldisc_put(struct tty_ldisc *ld)
192734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley{
193734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley	if (WARN_ON_ONCE(!ld))
194734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley		return;
195734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley
19636697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	put_ldops(ld->ops);
197734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley	kfree(ld);
198734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley}
199734de249fbe2fbf594c30202a343f0772b6d18fePeter Hurley
200852e99d22f2231d232c45216b027565e3bae7addAlan Coxstatic void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
20101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
20201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return (*pos < NR_LDISCS) ? pos : NULL;
20301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
20401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
205852e99d22f2231d232c45216b027565e3bae7addAlan Coxstatic void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
20601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
20701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	(*pos)++;
20801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return (*pos < NR_LDISCS) ? pos : NULL;
20901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
21001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
21101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
21201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
21301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
21401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
21501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic int tty_ldiscs_seq_show(struct seq_file *m, void *v)
21601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
21701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	int i = *(loff_t *)v;
218f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	struct tty_ldisc_ops *ldops;
219852e99d22f2231d232c45216b027565e3bae7addAlan Cox
220f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	ldops = get_ldops(i);
221f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	if (IS_ERR(ldops))
22201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		return 0;
223f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
224f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds	put_ldops(ldops);
22501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return 0;
22601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
22701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
22801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic const struct seq_operations tty_ldiscs_seq_ops = {
22901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.start	= tty_ldiscs_seq_start,
23001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.next	= tty_ldiscs_seq_next,
23101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.stop	= tty_ldiscs_seq_stop,
23201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.show	= tty_ldiscs_seq_show,
23301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox};
23401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
23501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
23601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
23701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return seq_open(file, &tty_ldiscs_seq_ops);
23801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
23901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
24001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxconst struct file_operations tty_ldiscs_proc_fops = {
24101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.owner		= THIS_MODULE,
24201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.open		= proc_tty_ldiscs_open,
24301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.read		= seq_read,
24401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.llseek		= seq_lseek,
24501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	.release	= seq_release,
24601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox};
24701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
24801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
24901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_ref_wait	-	wait for the tty ldisc
25001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: tty device
25101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
25201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Dereference the line discipline for the terminal and take a
25301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	reference to it. If the line discipline is in flux then
25401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	wait patiently until it changes.
25501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
25601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Note: Must not be called from an IRQ/timer context. The caller
25701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	must also be careful not to hold other locks that will deadlock
25801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	against a discipline change, such as an existing ldisc reference
25901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	(which we check for)
26001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
26136697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley *	Note: only callable from a file_operations routine (which
26236697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley *	guarantees tty->ldisc != NULL when the lock is acquired).
26301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
26401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
26501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstruct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
26601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
26736697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT);
26836697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	WARN_ON(!tty->ldisc);
26936697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	return tty->ldisc;
27001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
27101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
27201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
27301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
27401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_ref		-	get the tty ldisc
27501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: tty device
27601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
27701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Dereference the line discipline for the terminal and take a
27801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	reference to it. If the line discipline is in flux then
27901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	return NULL. Can be called from IRQ and timer functions.
28001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
28101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
28201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstruct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
28301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
28436697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	struct tty_ldisc *ld = NULL;
28536697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley
28636697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	if (ldsem_down_read_trylock(&tty->ldisc_sem)) {
28736697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley		ld = tty->ldisc;
28836697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley		if (!ld)
28936697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley			ldsem_up_read(&tty->ldisc_sem);
29036697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	}
29136697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	return ld;
29201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
29301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL_GPL(tty_ldisc_ref);
29401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
29501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
29601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_deref		-	free a tty ldisc reference
29701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@ld: reference to free up
29801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
29901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
30001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	be called in IRQ context.
30101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
30201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
30301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_deref(struct tty_ldisc *ld)
30401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
30536697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	ldsem_up_read(&ld->tty->ldisc_sem);
30601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
30701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL_GPL(tty_ldisc_deref);
30801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
309d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
310d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleystatic inline int __lockfunc
311d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleytty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
312d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley{
313d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	return ldsem_down_write(&tty->ldisc_sem, timeout);
314d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley}
315d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
316d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleystatic inline int __lockfunc
317d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleytty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
318d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley{
319d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	return ldsem_down_write_nested(&tty->ldisc_sem,
320d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley				       LDISC_SEM_OTHER, timeout);
321d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley}
322d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
323d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleystatic inline void tty_ldisc_unlock(struct tty_struct *tty)
324d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley{
325d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	return ldsem_up_write(&tty->ldisc_sem);
326d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley}
327d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
328d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleystatic int __lockfunc
329d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleytty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
330d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley			    unsigned long timeout)
331d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley{
332d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	int ret;
333d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
334d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	if (tty < tty2) {
335d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		ret = tty_ldisc_lock(tty, timeout);
336d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		if (ret) {
337d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley			ret = tty_ldisc_lock_nested(tty2, timeout);
338d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley			if (!ret)
339d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley				tty_ldisc_unlock(tty);
340d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		}
341d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	} else {
342d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		/* if this is possible, it has lots of implications */
343d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		WARN_ON_ONCE(tty == tty2);
344d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		if (tty2 && tty != tty2) {
345d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley			ret = tty_ldisc_lock(tty2, timeout);
346d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley			if (ret) {
347d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley				ret = tty_ldisc_lock_nested(tty, timeout);
348d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley				if (!ret)
349d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley					tty_ldisc_unlock(tty2);
350d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley			}
351d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		} else
352d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley			ret = tty_ldisc_lock(tty, timeout);
353d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	}
354d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
355d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	if (!ret)
356d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		return -EBUSY;
357d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
358d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	set_bit(TTY_LDISC_HALTED, &tty->flags);
359d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	if (tty2)
360d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		set_bit(TTY_LDISC_HALTED, &tty2->flags);
361d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	return 0;
362d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley}
363d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
364d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleystatic void __lockfunc
365d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleytty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
366d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley{
367d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT);
368d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley}
369d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
370d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleystatic void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
371d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley					     struct tty_struct *tty2)
372d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley{
373d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	tty_ldisc_unlock(tty);
374d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	if (tty2)
375d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		tty_ldisc_unlock(tty2);
376d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley}
377d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
378d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurleystatic void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
379d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley					     struct tty_struct *tty2)
380d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley{
381d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	clear_bit(TTY_LDISC_HALTED, &tty->flags);
382d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	if (tty2)
383d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley		clear_bit(TTY_LDISC_HALTED, &tty2->flags);
384d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
385d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley	tty_ldisc_unlock_pair(tty, tty2);
386d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley}
387d2c438905f9f718b3d9f5d89ce163fc22bd33995Peter Hurley
38801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
389f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox *	tty_ldisc_flush	-	flush line discipline queue
390f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox *	@tty: tty
391f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox *
392f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox *	Flush the line discipline queue (if any) for this tty. If there
393f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox *	is no line discipline active this is a no-op.
394f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox */
395f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox
396f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Coxvoid tty_ldisc_flush(struct tty_struct *tty)
397f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox{
398f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox	struct tty_ldisc *ld = tty_ldisc_ref(tty);
399f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox	if (ld) {
400f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox		if (ld->ops->flush_buffer)
401f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox			ld->ops->flush_buffer(tty);
402f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox		tty_ldisc_deref(ld);
403f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox	}
404f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox	tty_buffer_flush(tty);
405f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox}
406f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan CoxEXPORT_SYMBOL_GPL(tty_ldisc_flush);
407f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox
408f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox/**
40901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_set_termios_ldisc		-	set ldisc field
41001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: tty structure
41101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@num: line discipline number
41201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
41301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	This is probably overkill for real world processors but
41401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	they are not on hot paths so a little discipline won't do
41501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	any harm.
41601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
4176a1c0680cf3ba94356ecd58833e1540c93472a57Peter Hurley *	Locking: takes termios_rwsem
41801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
41901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
42001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic void tty_set_termios_ldisc(struct tty_struct *tty, int num)
42101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
4226a1c0680cf3ba94356ecd58833e1540c93472a57Peter Hurley	down_write(&tty->termios_rwsem);
423adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	tty->termios.c_line = num;
4246a1c0680cf3ba94356ecd58833e1540c93472a57Peter Hurley	up_write(&tty->termios_rwsem);
42501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
42601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
427c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/**
428c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	tty_ldisc_open		-	open a line discipline
429c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	@tty: tty we are opening the ldisc on
430c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	@ld: discipline to open
431c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *
432c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	A helper opening method. Also a convenient debugging and check
433c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	point.
434ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann *
435ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann *	Locking: always called with BTM already held.
436c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */
437c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
438c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
439c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{
440c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
441f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox	if (ld->ops->open) {
442f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox		int ret;
443ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann                /* BTM here locks versus a hangup event */
444f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox		ret = ld->ops->open(tty);
4457f90cfc505d613f4faf096e0d84ffe99208057d9Jiri Slaby		if (ret)
4467f90cfc505d613f4faf096e0d84ffe99208057d9Jiri Slaby			clear_bit(TTY_LDISC_OPEN, &tty->flags);
447f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox		return ret;
448f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox	}
449c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	return 0;
450c65c9bc3efa5589f691276bb9db689119a711222Alan Cox}
451c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
452c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/**
453c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	tty_ldisc_close		-	close a line discipline
454c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	@tty: tty we are opening the ldisc on
455c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	@ld: discipline to close
456c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *
457c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	A helper close method. Also a convenient debugging and check
458c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	point.
459c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */
460c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
461c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
462c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{
463c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
464c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	clear_bit(TTY_LDISC_OPEN, &tty->flags);
465c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (ld->ops->close)
466c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		ld->ops->close(tty);
467c65c9bc3efa5589f691276bb9db689119a711222Alan Cox}
46801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
46901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
47001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_restore	-	helper for tty ldisc change
47101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: tty to recover
47201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@old: previous ldisc
47301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
47401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Restore the previous line discipline or N_TTY when a line discipline
47501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	change fails due to an open error
47601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
47701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
47801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
47901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
48001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	char buf[64];
481c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	struct tty_ldisc *new_ldisc;
482c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	int r;
48301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
48401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	/* There is an outstanding reference here so this is safe */
48536697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	old = tty_ldisc_get(tty, old->ops->num);
486c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	WARN_ON(IS_ERR(old));
487f48070457c728a1ff8f327240e70483cebabf83bPeter Hurley	tty->ldisc = old;
48801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	tty_set_termios_ldisc(tty, old->ops->num);
489c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (tty_ldisc_open(tty, old) < 0) {
490c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		tty_ldisc_put(old);
49101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		/* This driver is always present */
49236697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley		new_ldisc = tty_ldisc_get(tty, N_TTY);
493c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		if (IS_ERR(new_ldisc))
49401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox			panic("n_tty: get");
495f48070457c728a1ff8f327240e70483cebabf83bPeter Hurley		tty->ldisc = new_ldisc;
49601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		tty_set_termios_ldisc(tty, N_TTY);
497c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		r = tty_ldisc_open(tty, new_ldisc);
498c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		if (r < 0)
499c65c9bc3efa5589f691276bb9db689119a711222Alan Cox			panic("Couldn't open N_TTY ldisc for "
500c65c9bc3efa5589f691276bb9db689119a711222Alan Cox			      "%s --- error %d.",
501c65c9bc3efa5589f691276bb9db689119a711222Alan Cox			      tty_name(tty, buf), r);
50201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	}
50301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
50401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
50501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
50601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_set_ldisc		-	set line discipline
50701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: the terminal to set
50801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@ldisc: the line discipline
50901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
51001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Set the discipline of a tty line. Must be called from a process
511c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	context. The ldisc change logic has to protect itself against any
512c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	overlapping ldisc change (including on the other end of pty pairs),
513c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	the close of one side of a tty/pty pair, and eventually hangup.
51401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
51501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
51601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_set_ldisc(struct tty_struct *tty, int ldisc)
51701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
51801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	int retval;
5199fbfa34c18b31978bf6bab26148f84d7a4b3cceaPeter Hurley	struct tty_ldisc *old_ldisc, *new_ldisc;
52036697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	struct tty_struct *o_tty = tty->link;
52101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
52236697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	new_ldisc = tty_ldisc_get(tty, ldisc);
523c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (IS_ERR(new_ldisc))
524c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		return PTR_ERR(new_ldisc);
52501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
52636697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
52736697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	if (retval) {
52836697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley		tty_ldisc_put(new_ldisc);
52936697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley		return retval;
53036697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	}
53101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
532c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	/*
533c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	 *	Check the no-op case
534c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	 */
535c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
536c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (tty->ldisc->ops->num == ldisc) {
53736697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley		tty_ldisc_enable_pair(tty, o_tty);
538c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		tty_ldisc_put(new_ldisc);
53901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		return 0;
54001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	}
54101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
5429fbfa34c18b31978bf6bab26148f84d7a4b3cceaPeter Hurley	old_ldisc = tty->ldisc;
54389c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty_lock(tty);
544100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby
545e97733ca677878d0ecf08af17f4661eb83e268bcPeter Hurley	if (test_bit(TTY_HUPPING, &tty->flags) ||
546e97733ca677878d0ecf08af17f4661eb83e268bcPeter Hurley	    test_bit(TTY_HUPPED, &tty->flags)) {
547c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		/* We were raced by the hangup method. It will have stomped
548c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		   the ldisc data and closed the ldisc down */
54936697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley		tty_ldisc_enable_pair(tty, o_tty);
550c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		tty_ldisc_put(new_ldisc);
55189c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox		tty_unlock(tty);
552c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		return -EIO;
553c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	}
554c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
5559fbfa34c18b31978bf6bab26148f84d7a4b3cceaPeter Hurley	/* Shutdown the old discipline. */
5569fbfa34c18b31978bf6bab26148f84d7a4b3cceaPeter Hurley	tty_ldisc_close(tty, old_ldisc);
55701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
55801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	/* Now set up the new line discipline. */
559f48070457c728a1ff8f327240e70483cebabf83bPeter Hurley	tty->ldisc = new_ldisc;
56001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	tty_set_termios_ldisc(tty, ldisc);
561c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
562c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	retval = tty_ldisc_open(tty, new_ldisc);
56301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	if (retval < 0) {
564c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		/* Back to the old one or N_TTY if we can't */
565c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		tty_ldisc_put(new_ldisc);
5669fbfa34c18b31978bf6bab26148f84d7a4b3cceaPeter Hurley		tty_ldisc_restore(tty, old_ldisc);
56701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	}
568c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
5699fbfa34c18b31978bf6bab26148f84d7a4b3cceaPeter Hurley	if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc)
57001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		tty->ops->set_ldisc(tty);
57101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
572b0e95858238d95f32edf00ff4a0375165129d0c6Peter Hurley	/* At this point we hold a reference to the new ldisc and a
573b0e95858238d95f32edf00ff4a0375165129d0c6Peter Hurley	   reference to the old ldisc, or we hold two references to
574b0e95858238d95f32edf00ff4a0375165129d0c6Peter Hurley	   the old ldisc (if it was restored as part of error cleanup
575b0e95858238d95f32edf00ff4a0375165129d0c6Peter Hurley	   above). In either case, releasing a single reference from
576b0e95858238d95f32edf00ff4a0375165129d0c6Peter Hurley	   the old ldisc is correct. */
577b0e95858238d95f32edf00ff4a0375165129d0c6Peter Hurley
5789fbfa34c18b31978bf6bab26148f84d7a4b3cceaPeter Hurley	tty_ldisc_put(old_ldisc);
57901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
58001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	/*
581c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	 *	Allow ldisc referencing to occur again
58201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	 */
58336697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	tty_ldisc_enable_pair(tty, o_tty);
58401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
585c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	/* Restart the work queue in case no characters kick it off. Safe if
58601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	   already running */
5874f98d4675166fc1991dbad7dd2af634df7c14061Peter Hurley	schedule_work(&tty->port->buf.work);
5884f98d4675166fc1991dbad7dd2af634df7c14061Peter Hurley	if (o_tty)
589ecbbfd44a08fa80e0d664814efd4c187721b85f6Jiri Slaby		schedule_work(&o_tty->port->buf.work);
5904f98d4675166fc1991dbad7dd2af634df7c14061Peter Hurley
59189c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty_unlock(tty);
59201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return retval;
59301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
59401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
595c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/**
596c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	tty_reset_termios	-	reset terminal state
597c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	@tty: tty to reset
598c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *
599c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	Restore a terminal to the driver default state.
600c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */
601c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
602c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic void tty_reset_termios(struct tty_struct *tty)
603c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{
6046a1c0680cf3ba94356ecd58833e1540c93472a57Peter Hurley	down_write(&tty->termios_rwsem);
605adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	tty->termios = tty->driver->init_termios;
606adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
607adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox	tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
6086a1c0680cf3ba94356ecd58833e1540c93472a57Peter Hurley	up_write(&tty->termios_rwsem);
609c65c9bc3efa5589f691276bb9db689119a711222Alan Cox}
610c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
611c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
612c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/**
613c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	tty_ldisc_reinit	-	reinitialise the tty ldisc
614c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	@tty: tty to reinit
615638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox *	@ldisc: line discipline to reinitialize
616c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *
617638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox *	Switch the tty to a line discipline and leave the ldisc
618638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox *	state closed
619c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */
620c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
6211c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornazstatic int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
622c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{
62336697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	struct tty_ldisc *ld = tty_ldisc_get(tty, ldisc);
6241c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz
6251c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz	if (IS_ERR(ld))
6261c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz		return -1;
627c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
628c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	tty_ldisc_close(tty, tty->ldisc);
629c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	tty_ldisc_put(tty->ldisc);
630c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	/*
631c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	 *	Switch the line discipline back
632c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	 */
633f48070457c728a1ff8f327240e70483cebabf83bPeter Hurley	tty->ldisc = ld;
634638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox	tty_set_termios_ldisc(tty, ldisc);
6351c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz
6361c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz	return 0;
637c65c9bc3efa5589f691276bb9db689119a711222Alan Cox}
638c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
639c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/**
640c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	tty_ldisc_hangup		-	hangup ldisc reset
641c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	@tty: tty being hung up
642c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *
643c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	Some tty devices reset their termios when they receive a hangup
644c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	event. In that situation we must also switch back to N_TTY properly
645c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	before we reset the termios data.
646c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *
647c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	Locking: We can take the ldisc mutex as the rest of the code is
648c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	careful to allow for this.
649c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *
650c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	In the pty pair case this occurs in the close() path of the
651c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	tty itself so we must be careful about locking rules.
652c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */
653c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
654c65c9bc3efa5589f691276bb9db689119a711222Alan Coxvoid tty_ldisc_hangup(struct tty_struct *tty)
655c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{
656c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	struct tty_ldisc *ld;
657638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox	int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
658638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox	int err = 0;
659c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
660fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley	tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
661fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley
662c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	ld = tty_ldisc_ref(tty);
663c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (ld != NULL) {
664c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		if (ld->ops->flush_buffer)
665c65c9bc3efa5589f691276bb9db689119a711222Alan Cox			ld->ops->flush_buffer(tty);
666c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		tty_driver_flush_buffer(tty);
667c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
668c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		    ld->ops->write_wakeup)
669c65c9bc3efa5589f691276bb9db689119a711222Alan Cox			ld->ops->write_wakeup(tty);
670c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		if (ld->ops->hangup)
671c65c9bc3efa5589f691276bb9db689119a711222Alan Cox			ld->ops->hangup(tty);
672c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		tty_ldisc_deref(ld);
673c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	}
67436697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley
675c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
676c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	wake_up_interruptible_poll(&tty->read_wait, POLLIN);
67736697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley
67836697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	tty_unlock(tty);
67936697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley
680c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	/*
681c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	 * Shutdown the current line discipline, and reset it to
682638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox	 * N_TTY if need be.
683638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox	 *
684638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox	 * Avoid racing set_ldisc or tty_ldisc_release
685c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	 */
68636697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	tty_ldisc_lock_pair(tty, tty->link);
68736697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	tty_lock(tty);
68860af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann
68936697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	if (tty->ldisc) {
690c8785241741d4bc3ee6da2ff415a9a1b3df2b4cbPeter Hurley
691c8785241741d4bc3ee6da2ff415a9a1b3df2b4cbPeter Hurley		/* At this point we have a halted ldisc; we want to close it and
692c8785241741d4bc3ee6da2ff415a9a1b3df2b4cbPeter Hurley		   reopen a new ldisc. We could defer the reopen to the next
693c8785241741d4bc3ee6da2ff415a9a1b3df2b4cbPeter Hurley		   open but it means auditing a lot of other paths so this is
694c8785241741d4bc3ee6da2ff415a9a1b3df2b4cbPeter Hurley		   a FIXME */
695638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox		if (reset == 0) {
6961c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz
697adc8d746caa67fff4b53ba3e5163a6cbacc3b523Alan Cox			if (!tty_ldisc_reinit(tty, tty->termios.c_line))
6981c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz				err = tty_ldisc_open(tty, tty->ldisc);
6991c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz			else
7001c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz				err = 1;
701638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox		}
702638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox		/* If the re-open fails or we reset then go to N_TTY. The
703638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox		   N_TTY open cannot fail */
704638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox		if (reset || err) {
7051c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz			BUG_ON(tty_ldisc_reinit(tty, N_TTY));
706c8d50041734534e0a4b0ea13df36ed5857fccd56Alan Cox			WARN_ON(tty_ldisc_open(tty, tty->ldisc));
707c8d50041734534e0a4b0ea13df36ed5857fccd56Alan Cox		}
708c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	}
70936697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	tty_ldisc_enable_pair(tty, tty->link);
710638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox	if (reset)
711638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox		tty_reset_termios(tty);
712fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley
713fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley	tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc);
714c65c9bc3efa5589f691276bb9db689119a711222Alan Cox}
71501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
71601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
71701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_setup			-	open line discipline
71801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: tty being shut down
71901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@o_tty: pair tty for pty/tty pairs
72001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
72101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Called during the initial open of a tty/pty pair in order to set up the
722c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	line disciplines and bind them to the tty. This has no locking issues
723c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	as the device isn't yet active.
72401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
72501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
72601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
72701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
728c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	struct tty_ldisc *ld = tty->ldisc;
72901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	int retval;
73001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
731c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	retval = tty_ldisc_open(tty, ld);
732c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (retval)
733c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		return retval;
734c65c9bc3efa5589f691276bb9db689119a711222Alan Cox
735c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (o_tty) {
736c65c9bc3efa5589f691276bb9db689119a711222Alan Cox		retval = tty_ldisc_open(o_tty, o_tty->ldisc);
73701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		if (retval) {
738c65c9bc3efa5589f691276bb9db689119a711222Alan Cox			tty_ldisc_close(tty, ld);
73901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox			return retval;
74001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		}
74101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	}
74201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	return 0;
74301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
74489c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox
74589c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Coxstatic void tty_ldisc_kill(struct tty_struct *tty)
74689c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox{
74789c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	/*
74889c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	 * Now kill off the ldisc
74989c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	 */
75089c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty_ldisc_close(tty, tty->ldisc);
75189c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty_ldisc_put(tty->ldisc);
75289c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	/* Force an oops if we mess this up */
75389c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty->ldisc = NULL;
75489c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox
75589c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	/* Ensure the next open requests the N_TTY ldisc */
75689c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty_set_termios_ldisc(tty, N_TTY);
75789c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox}
75889c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox
75901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
76001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_release		-	release line discipline
76101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: tty being shut down
76201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@o_tty: pair tty for pty/tty pairs
76301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
764852e99d22f2231d232c45216b027565e3bae7addAlan Cox *	Called during the final close of a tty/pty pair in order to shut down
765852e99d22f2231d232c45216b027565e3bae7addAlan Cox *	the line discpline layer. On exit the ldisc assigned is N_TTY and the
766c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *	ldisc has not been opened.
76701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
76801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
76901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
77001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
77101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	/*
772a2965b7bee00a01731ae79de34c26e146cbd08cfPeter Hurley	 * Shutdown this line discipline. As this is the final close,
773a2965b7bee00a01731ae79de34c26e146cbd08cfPeter Hurley	 * it does not race with the set_ldisc code path.
77401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	 */
77501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
776fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley	tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
777fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley
77836697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	tty_ldisc_lock_pair(tty, o_tty);
779852e4a8152b427c3f318bb0e1b5e938d64dcdc32Sebastian Andrzej Siewior	tty_lock_pair(tty, o_tty);
78036697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley
78189c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty_ldisc_kill(tty);
782c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (o_tty)
78389c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox		tty_ldisc_kill(o_tty);
784aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox
78589c8d91e31f267703e365593f6bfebb9f6d2ad01Alan Cox	tty_unlock_pair(tty, o_tty);
78636697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	tty_ldisc_unlock_pair(tty, o_tty);
78736697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley
788aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox	/* And the memory resources remaining (buffers, termios) will be
789aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox	   disposed of when the kref hits zero */
790fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley
791fc575ee6eadbcac757e3216e230b6fab1ba5b140Peter Hurley	tty_ldisc_debug(tty, "ldisc closed\n");
79201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
79301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
79401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/**
79501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	tty_ldisc_init		-	ldisc setup for new tty
79601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	@tty: tty being allocated
79701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *
79801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	Set up the line discipline objects for a newly allocated tty. Note that
79901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox *	the tty structure is not completely set up when this call is made.
80001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */
80101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
80201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_init(struct tty_struct *tty)
80301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
80436697529b5bbe36911e39a6309e7a7c9250d280aPeter Hurley	struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY);
805c65c9bc3efa5589f691276bb9db689119a711222Alan Cox	if (IS_ERR(ld))
80601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox		panic("n_tty: init_tty");
807f48070457c728a1ff8f327240e70483cebabf83bPeter Hurley	tty->ldisc = ld;
80801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
80901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox
8106716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby/**
8116716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby *	tty_ldisc_init		-	ldisc cleanup for new tty
8126716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby *	@tty: tty that was allocated recently
8136716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby *
8146716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby *	The tty structure must not becompletely set up (tty_ldisc_setup) when
8156716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby *      this call is made.
8166716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby */
8176716671d8c1c07a8072098764d1b7cbfef7412adJiri Slabyvoid tty_ldisc_deinit(struct tty_struct *tty)
8186716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby{
819ebc9baed42e42f9b51cf61672b7afb72f068d523Peter Hurley	tty_ldisc_put(tty->ldisc);
820f48070457c728a1ff8f327240e70483cebabf83bPeter Hurley	tty->ldisc = NULL;
8216716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby}
8226716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby
82301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_begin(void)
82401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{
82501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	/* Setup the default TTY line discipline. */
82601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox	(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
82701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}
828