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