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/init.h> 1501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/module.h> 1601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/device.h> 1701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/wait.h> 1801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/bitops.h> 1901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/seq_file.h> 2001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox#include <linux/uaccess.h> 210c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby#include <linux/ratelimit.h> 2201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 2301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/* 2401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * This guards the refcounted line discipline lists. The lock 2501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * must be taken with irqs off because there are hangup path 2601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * callers who will do ldisc lookups and cannot sleep. 2701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 2801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 2901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic DEFINE_SPINLOCK(tty_ldisc_lock); 3001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); 31100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slabystatic DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle); 3201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/* Line disc dispatch table */ 3301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; 3401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 3565b770468e98941e45e19780dff9283e663e6b8bLinus Torvaldsstatic inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld) 3665b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds{ 3765b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds if (ld) 3865b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds atomic_inc(&ld->users); 3965b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds return ld; 4065b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds} 4165b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds 42cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvaldsstatic void put_ldisc(struct tty_ldisc *ld) 4365b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds{ 44cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds unsigned long flags; 45cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds 4665b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds if (WARN_ON_ONCE(!ld)) 4765b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds return; 4865b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds 4965b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds /* 5065b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds * If this is the last user, free the ldisc, and 5165b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds * release the ldisc ops. 52cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds * 53cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds * We really want an "atomic_dec_and_lock_irqsave()", 54cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds * but we don't have it, so this does it by hand. 5565b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds */ 56cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds local_irq_save(flags); 57cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) { 5865b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds struct tty_ldisc_ops *ldo = ld->ops; 5965b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds 6065b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds ldo->refcount--; 6165b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds module_put(ldo->owner); 6265b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds spin_unlock_irqrestore(&tty_ldisc_lock, flags); 63cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds 64cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds kfree(ld); 65cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds return; 6665b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds } 67cbe9352fa08f90aa03b4dbf1bbabfc95d196e562Linus Torvalds local_irq_restore(flags); 68100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby wake_up(&tty_ldisc_idle); 6965b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds} 7065b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds 7101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 7201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_register_ldisc - install a line discipline 7301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @disc: ldisc number 7401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @new_ldisc: pointer to the ldisc object 7501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 7601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Installs a new line discipline into the kernel. The discipline 7701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * is set up as unreferenced and then made available to the kernel 7801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * from this point onwards. 7901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 8001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: 8101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * takes tty_ldisc_lock to guard against ldisc races 8201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 8301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 8401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc) 8501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 8601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox unsigned long flags; 8701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox int ret = 0; 8801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 8901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (disc < N_TTY || disc >= NR_LDISCS) 9001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return -EINVAL; 9101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 9201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox spin_lock_irqsave(&tty_ldisc_lock, flags); 9301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_ldiscs[disc] = new_ldisc; 9401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox new_ldisc->num = disc; 9501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox new_ldisc->refcount = 0; 9601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox spin_unlock_irqrestore(&tty_ldisc_lock, flags); 9701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 9801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return ret; 9901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 10001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL(tty_register_ldisc); 10101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 10201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 10301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_unregister_ldisc - unload a line discipline 10401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @disc: ldisc number 10501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @new_ldisc: pointer to the ldisc object 10601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 10701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Remove a line discipline from the kernel providing it is not 10801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * currently in use. 10901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 11001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: 11101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * takes tty_ldisc_lock to guard against ldisc races 11201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 11301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 11401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_unregister_ldisc(int disc) 11501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 11601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox unsigned long flags; 11701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox int ret = 0; 11801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 11901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (disc < N_TTY || disc >= NR_LDISCS) 12001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return -EINVAL; 12101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 12201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox spin_lock_irqsave(&tty_ldisc_lock, flags); 12301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (tty_ldiscs[disc]->refcount) 12401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox ret = -EBUSY; 12501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox else 12601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_ldiscs[disc] = NULL; 12701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox spin_unlock_irqrestore(&tty_ldisc_lock, flags); 12801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 12901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return ret; 13001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 13101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL(tty_unregister_ldisc); 13201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 133f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvaldsstatic struct tty_ldisc_ops *get_ldops(int disc) 134f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds{ 135f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds unsigned long flags; 136f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds struct tty_ldisc_ops *ldops, *ret; 137f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds 138f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds spin_lock_irqsave(&tty_ldisc_lock, flags); 139f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds ret = ERR_PTR(-EINVAL); 140f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds ldops = tty_ldiscs[disc]; 141f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds if (ldops) { 142f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds ret = ERR_PTR(-EAGAIN); 143f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds if (try_module_get(ldops->owner)) { 144f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds ldops->refcount++; 145f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds ret = ldops; 146f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds } 147f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds } 148f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds spin_unlock_irqrestore(&tty_ldisc_lock, flags); 149f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds return ret; 150f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds} 151f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds 152f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvaldsstatic void put_ldops(struct tty_ldisc_ops *ldops) 153f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds{ 154f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds unsigned long flags; 155f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds 156f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds spin_lock_irqsave(&tty_ldisc_lock, flags); 157f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds ldops->refcount--; 158f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds module_put(ldops->owner); 159f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds spin_unlock_irqrestore(&tty_ldisc_lock, flags); 160f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds} 16101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 16201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 16301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_get - take a reference to an ldisc 16401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @disc: ldisc number 16501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 16601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Takes a reference to a line discipline. Deals with refcounts and 16701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * module locking counts. Returns NULL if the discipline is not available. 16801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Returns a pointer to the discipline and bumps the ref count if it is 16901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * available 17001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 17101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: 17201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * takes tty_ldisc_lock to guard against ldisc races 17301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 17401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 175c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic struct tty_ldisc *tty_ldisc_get(int disc) 17601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 177c65c9bc3efa5589f691276bb9db689119a711222Alan Cox struct tty_ldisc *ld; 178182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds struct tty_ldisc_ops *ldops; 17901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 18001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (disc < N_TTY || disc >= NR_LDISCS) 181c65c9bc3efa5589f691276bb9db689119a711222Alan Cox return ERR_PTR(-EINVAL); 182182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds 183182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds /* 184182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds * Get the ldisc ops - we may need to request them to be loaded 185182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds * dynamically and try again. 186182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds */ 187182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds ldops = get_ldops(disc); 188182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds if (IS_ERR(ldops)) { 18901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox request_module("tty-ldisc-%d", disc); 190182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds ldops = get_ldops(disc); 191182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds if (IS_ERR(ldops)) 192182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds return ERR_CAST(ldops); 193182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds } 194182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds 195182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); 196182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds if (ld == NULL) { 197182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds put_ldops(ldops); 198182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds return ERR_PTR(-ENOMEM); 19901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox } 200182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds 201182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds ld->ops = ldops; 202182274f85fc26ec3aa8c78dba8b0e7763af3c586Linus Torvalds atomic_set(&ld->users, 1); 203c65c9bc3efa5589f691276bb9db689119a711222Alan Cox return ld; 20401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 20501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 206852e99d22f2231d232c45216b027565e3bae7addAlan Coxstatic void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) 20701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 20801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return (*pos < NR_LDISCS) ? pos : NULL; 20901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 21001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 211852e99d22f2231d232c45216b027565e3bae7addAlan Coxstatic void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) 21201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 21301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox (*pos)++; 21401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return (*pos < NR_LDISCS) ? pos : NULL; 21501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 21601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 21701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic void tty_ldiscs_seq_stop(struct seq_file *m, void *v) 21801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 21901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 22001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 22101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic int tty_ldiscs_seq_show(struct seq_file *m, void *v) 22201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 22301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox int i = *(loff_t *)v; 224f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds struct tty_ldisc_ops *ldops; 225852e99d22f2231d232c45216b027565e3bae7addAlan Cox 226f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds ldops = get_ldops(i); 227f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds if (IS_ERR(ldops)) 22801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return 0; 229f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i); 230f0de0e8d3565ee7feba6228d99763d4cea2087a6Linus Torvalds put_ldops(ldops); 23101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return 0; 23201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 23301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 23401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic const struct seq_operations tty_ldiscs_seq_ops = { 23501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .start = tty_ldiscs_seq_start, 23601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .next = tty_ldiscs_seq_next, 23701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .stop = tty_ldiscs_seq_stop, 23801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .show = tty_ldiscs_seq_show, 23901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}; 24001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 24101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic int proc_tty_ldiscs_open(struct inode *inode, struct file *file) 24201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 24301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return seq_open(file, &tty_ldiscs_seq_ops); 24401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 24501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 24601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxconst struct file_operations tty_ldiscs_proc_fops = { 24701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .owner = THIS_MODULE, 24801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .open = proc_tty_ldiscs_open, 24901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .read = seq_read, 25001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .llseek = seq_lseek, 25101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox .release = seq_release, 25201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox}; 25301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 25401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 25501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_assign - set ldisc on a tty 25601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty to assign 25701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @ld: line discipline 25801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 25901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Install an instance of a line discipline into a tty structure. The 2608d2ead743dd54dff1fe3d0f4933e5da8bfe07472Alan Cox * ldisc must have a reference count above zero to ensure it remains. 26101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * The tty instance refcount starts at zero. 26201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 26301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: 26401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Caller must hold references 26501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 26601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 26701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) 26801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 269c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty->ldisc = ld; 27001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 27101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 27201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 27301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_try - internal helper 27401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: the tty 27501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 27601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Make a single attempt to grab and bump the refcount on 27701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * the tty ldisc. Return 0 on failure or 1 on success. This is 27801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * used to implement both the waiting and non waiting versions 27901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * of tty_ldisc_ref 28001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 28101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: takes tty_ldisc_lock 28201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 28301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 28465b770468e98941e45e19780dff9283e663e6b8bLinus Torvaldsstatic struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty) 28501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 28601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox unsigned long flags; 28701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox struct tty_ldisc *ld; 28801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 28901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox spin_lock_irqsave(&tty_ldisc_lock, flags); 29065b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds ld = NULL; 29165b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds if (test_bit(TTY_LDISC, &tty->flags)) 29265b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds ld = get_ldisc(tty->ldisc); 29301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox spin_unlock_irqrestore(&tty_ldisc_lock, flags); 29465b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds return ld; 29501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 29601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 29701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 29801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_ref_wait - wait for the tty ldisc 29901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty device 30001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 30101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Dereference the line discipline for the terminal and take a 30201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * reference to it. If the line discipline is in flux then 30301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * wait patiently until it changes. 30401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 30501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Note: Must not be called from an IRQ/timer context. The caller 30601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * must also be careful not to hold other locks that will deadlock 30701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * against a discipline change, such as an existing ldisc reference 30801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * (which we check for) 30901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 31001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: call functions take tty_ldisc_lock 31101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 31201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 31301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstruct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 31401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 31565b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds struct tty_ldisc *ld; 31665b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds 31701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* wait_event is a macro */ 31865b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL); 31965b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds return ld; 32001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 32101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 32201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 32301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 32401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_ref - get the tty ldisc 32501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty device 32601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 32701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Dereference the line discipline for the terminal and take a 32801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * reference to it. If the line discipline is in flux then 32901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * return NULL. Can be called from IRQ and timer functions. 33001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 33101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: called functions take tty_ldisc_lock 33201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 33301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 33401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstruct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) 33501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 33665b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds return tty_ldisc_try(tty); 33701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 33801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL_GPL(tty_ldisc_ref); 33901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 34001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 34101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_deref - free a tty ldisc reference 34201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @ld: reference to free up 34301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 34401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May 34501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * be called in IRQ context. 34601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 34701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: takes tty_ldisc_lock 34801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 34901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 35001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_deref(struct tty_ldisc *ld) 35101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 35265b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds put_ldisc(ld); 35301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 35401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan CoxEXPORT_SYMBOL_GPL(tty_ldisc_deref); 35501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 35665b770468e98941e45e19780dff9283e663e6b8bLinus Torvaldsstatic inline void tty_ldisc_put(struct tty_ldisc *ld) 35765b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds{ 35865b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds put_ldisc(ld); 35965b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds} 36065b770468e98941e45e19780dff9283e663e6b8bLinus Torvalds 36101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 36201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_enable - allow ldisc use 36301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: terminal to activate ldisc on 36401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 36501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Set the TTY_LDISC flag when the line discipline can be called 366c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * again. Do necessary wakeups for existing sleepers. Clear the LDISC 367c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * changing flag to indicate any ldisc change is now over. 36801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 369c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * Note: nobody should set the TTY_LDISC bit except via this function. 370c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * Clearing directly is allowed. 37101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 37201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 37301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_enable(struct tty_struct *tty) 37401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 37501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox set_bit(TTY_LDISC, &tty->flags); 376c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox clear_bit(TTY_LDISC_CHANGING, &tty->flags); 37701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox wake_up(&tty_ldisc_wait); 37801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 37901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 38001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 381f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox * tty_ldisc_flush - flush line discipline queue 382f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox * @tty: tty 383f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox * 384f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox * Flush the line discipline queue (if any) for this tty. If there 385f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox * is no line discipline active this is a no-op. 386f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox */ 387f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox 388f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Coxvoid tty_ldisc_flush(struct tty_struct *tty) 389f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox{ 390f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox struct tty_ldisc *ld = tty_ldisc_ref(tty); 391f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox if (ld) { 392f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox if (ld->ops->flush_buffer) 393f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox ld->ops->flush_buffer(tty); 394f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox tty_ldisc_deref(ld); 395f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox } 396f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox tty_buffer_flush(tty); 397f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox} 398f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan CoxEXPORT_SYMBOL_GPL(tty_ldisc_flush); 399f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox 400f2c4c65c8350d885d74dcdea7061dcecc1223c36Alan Cox/** 40101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_set_termios_ldisc - set ldisc field 40201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty structure 40301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @num: line discipline number 40401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 40501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * This is probably overkill for real world processors but 40601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * they are not on hot paths so a little discipline won't do 40701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * any harm. 40801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 40901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Locking: takes termios_mutex 41001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 41101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 41201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic void tty_set_termios_ldisc(struct tty_struct *tty, int num) 41301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 41401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox mutex_lock(&tty->termios_mutex); 41501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty->termios->c_line = num; 41601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox mutex_unlock(&tty->termios_mutex); 41701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 41801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 419c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/** 420c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * tty_ldisc_open - open a line discipline 421c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * @tty: tty we are opening the ldisc on 422c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * @ld: discipline to open 423c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * 424c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * A helper opening method. Also a convenient debugging and check 425c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * point. 426ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann * 427ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann * Locking: always called with BTM already held. 428c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 429c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 430c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) 431c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{ 432c65c9bc3efa5589f691276bb9db689119a711222Alan Cox WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); 433f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox if (ld->ops->open) { 434f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox int ret; 435ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann /* BTM here locks versus a hangup event */ 436f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox ret = ld->ops->open(tty); 4377f90cfc505d613f4faf096e0d84ffe99208057d9Jiri Slaby if (ret) 4387f90cfc505d613f4faf096e0d84ffe99208057d9Jiri Slaby clear_bit(TTY_LDISC_OPEN, &tty->flags); 439f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox return ret; 440f18f9498e90327b9b0e245e191029e6e1996d203Alan Cox } 441c65c9bc3efa5589f691276bb9db689119a711222Alan Cox return 0; 442c65c9bc3efa5589f691276bb9db689119a711222Alan Cox} 443c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 444c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/** 445c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * tty_ldisc_close - close a line discipline 446c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * @tty: tty we are opening the ldisc on 447c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * @ld: discipline to close 448c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * 449c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * A helper close method. Also a convenient debugging and check 450c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * point. 451c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 452c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 453c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) 454c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{ 455c65c9bc3efa5589f691276bb9db689119a711222Alan Cox WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); 456c65c9bc3efa5589f691276bb9db689119a711222Alan Cox clear_bit(TTY_LDISC_OPEN, &tty->flags); 457c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (ld->ops->close) 458c65c9bc3efa5589f691276bb9db689119a711222Alan Cox ld->ops->close(tty); 459c65c9bc3efa5589f691276bb9db689119a711222Alan Cox} 46001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 46101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 46201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_restore - helper for tty ldisc change 46301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty to recover 46401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @old: previous ldisc 46501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 46601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Restore the previous line discipline or N_TTY when a line discipline 46701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * change fails due to an open error 46801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 46901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 47001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxstatic void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) 47101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 47201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox char buf[64]; 473c65c9bc3efa5589f691276bb9db689119a711222Alan Cox struct tty_ldisc *new_ldisc; 474c65c9bc3efa5589f691276bb9db689119a711222Alan Cox int r; 47501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 47601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* There is an outstanding reference here so this is safe */ 477c65c9bc3efa5589f691276bb9db689119a711222Alan Cox old = tty_ldisc_get(old->ops->num); 478c65c9bc3efa5589f691276bb9db689119a711222Alan Cox WARN_ON(IS_ERR(old)); 47901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_ldisc_assign(tty, old); 48001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_set_termios_ldisc(tty, old->ops->num); 481c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (tty_ldisc_open(tty, old) < 0) { 482c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_put(old); 48301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* This driver is always present */ 484852e99d22f2231d232c45216b027565e3bae7addAlan Cox new_ldisc = tty_ldisc_get(N_TTY); 485c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (IS_ERR(new_ldisc)) 48601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox panic("n_tty: get"); 487c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_assign(tty, new_ldisc); 48801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_set_termios_ldisc(tty, N_TTY); 489c65c9bc3efa5589f691276bb9db689119a711222Alan Cox r = tty_ldisc_open(tty, new_ldisc); 490c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (r < 0) 491c65c9bc3efa5589f691276bb9db689119a711222Alan Cox panic("Couldn't open N_TTY ldisc for " 492c65c9bc3efa5589f691276bb9db689119a711222Alan Cox "%s --- error %d.", 493c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_name(tty, buf), r); 49401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox } 49501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 49601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 49701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 498c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * tty_ldisc_halt - shut down the line discipline 499e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox * @tty: tty device 500e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox * 501e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox * Shut down the line discipline and work queue for this tty device. 502e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox * The TTY_LDISC flag being cleared ensures no further references can 503e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox * be obtained while the delayed work queue halt ensures that no more 504e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox * data is fed to the ldisc. 505e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox * 5065c58ceff103d8a654f24769bb1baaf84a841b0ccLinus Torvalds * You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex) 5075c58ceff103d8a654f24769bb1baaf84a841b0ccLinus Torvalds * in order to make sure any currently executing ldisc work is also 5085c58ceff103d8a654f24769bb1baaf84a841b0ccLinus Torvalds * flushed. 509e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox */ 510e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox 511c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic int tty_ldisc_halt(struct tty_struct *tty) 512e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox{ 513e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox clear_bit(TTY_LDISC, &tty->flags); 514f23eb2b2b28547fc70df82dd5049eb39bec5ba12Linus Torvalds return cancel_work_sync(&tty->buf.work); 515e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox} 516e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox 517e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox/** 5180a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo * tty_ldisc_flush_works - flush all works of a tty 5190a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo * @tty: tty device to flush works for 5200a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo * 5210a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo * Sync flush all works belonging to @tty. 5220a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo */ 5230a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heostatic void tty_ldisc_flush_works(struct tty_struct *tty) 5240a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo{ 5250a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo flush_work_sync(&tty->hangup_work); 5260a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo flush_work_sync(&tty->SAK_work); 527f23eb2b2b28547fc70df82dd5049eb39bec5ba12Linus Torvalds flush_work_sync(&tty->buf.work); 5280a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo} 5290a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo 5300a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo/** 531100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby * tty_ldisc_wait_idle - wait for the ldisc to become idle 532100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby * @tty: tty to wait for 533df92d0561de364de53c42abc5d43e04ab6f326a5Jiri Slaby * @timeout: for how long to wait at most 534100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby * 535100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby * Wait for the line discipline to become idle. The discipline must 536100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby * have been halted for this to guarantee it remains idle. 537100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby */ 538df92d0561de364de53c42abc5d43e04ab6f326a5Jiri Slabystatic int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) 539100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby{ 540df92d0561de364de53c42abc5d43e04ab6f326a5Jiri Slaby long ret; 54192f6fa09bd453ffe3351fa1f1377a1b7cfa911e6Jiri Slaby ret = wait_event_timeout(tty_ldisc_idle, 542df92d0561de364de53c42abc5d43e04ab6f326a5Jiri Slaby atomic_read(&tty->ldisc->users) == 1, timeout); 543100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby return ret > 0 ? 0 : -EBUSY; 544100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby} 545100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby 546100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby/** 54701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_set_ldisc - set line discipline 54801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: the terminal to set 54901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @ldisc: the line discipline 55001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 55101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Set the discipline of a tty line. Must be called from a process 552c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * context. The ldisc change logic has to protect itself against any 553c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * overlapping ldisc change (including on the other end of pty pairs), 554c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * the close of one side of a tty/pty pair, and eventually hangup. 55501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 556c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Locking: takes tty_ldisc_lock, termios_mutex 55701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 55801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 55901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_set_ldisc(struct tty_struct *tty, int ldisc) 56001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 56101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox int retval; 562c65c9bc3efa5589f691276bb9db689119a711222Alan Cox struct tty_ldisc *o_ldisc, *new_ldisc; 563c65c9bc3efa5589f691276bb9db689119a711222Alan Cox int work, o_work = 0; 56401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox struct tty_struct *o_tty; 56501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 566c65c9bc3efa5589f691276bb9db689119a711222Alan Cox new_ldisc = tty_ldisc_get(ldisc); 567c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (IS_ERR(new_ldisc)) 568c65c9bc3efa5589f691276bb9db689119a711222Alan Cox return PTR_ERR(new_ldisc); 56901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 570ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_lock(); 57101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* 572c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * We need to look at the tty locking here for pty/tty pairs 573c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * when both sides try to change in parallel. 57401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 57501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 576c65c9bc3efa5589f691276bb9db689119a711222Alan Cox o_tty = tty->link; /* o_tty is the pty side or NULL */ 577c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 57801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 579c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* 580c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Check the no-op case 581c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 582c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 583c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (tty->ldisc->ops->num == ldisc) { 584ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 585c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_put(new_ldisc); 58601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return 0; 58701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox } 58801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 589ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 59001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* 591c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Problem: What do we do if this blocks ? 592c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * We could deadlock here 593c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 594c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 595c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_wait_until_sent(tty, 0); 596c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 59760af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann tty_lock(); 598c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_lock(&tty->ldisc_mutex); 599c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 600c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* 601c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * We could be midstream of another ldisc change which has 602c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * dropped the lock during processing. If so we need to wait. 603c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 604c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 605c65c9bc3efa5589f691276bb9db689119a711222Alan Cox while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { 606c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_unlock(&tty->ldisc_mutex); 60760af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann tty_unlock(); 608c65c9bc3efa5589f691276bb9db689119a711222Alan Cox wait_event(tty_ldisc_wait, 609c65c9bc3efa5589f691276bb9db689119a711222Alan Cox test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); 61060af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann tty_lock(); 611c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_lock(&tty->ldisc_mutex); 612c65c9bc3efa5589f691276bb9db689119a711222Alan Cox } 613eeb89d918c2fa2b809e464136bbafdaec2aacb30Alan Cox 614c65c9bc3efa5589f691276bb9db689119a711222Alan Cox set_bit(TTY_LDISC_CHANGING, &tty->flags); 615852e99d22f2231d232c45216b027565e3bae7addAlan Cox 616c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* 61701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * No more input please, we are switching. The new ldisc 61801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * will update this value in the ldisc open function 61901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 62001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 62101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty->receive_room = 0; 62201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 62301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox o_ldisc = tty->ldisc; 624eeb89d918c2fa2b809e464136bbafdaec2aacb30Alan Cox 625ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 62601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* 62701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Make sure we don't change while someone holds a 62801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * reference to the line discipline. The TTY_LDISC bit 62901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * prevents anyone taking a reference once it is clear. 63001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * We need the lock to avoid racing reference takers. 631c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * 632c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * We must clear the TTY_LDISC bit here to avoid a livelock 633c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * with a userspace app continually trying to use the tty in 634c9b3976e3fec266be25c5001a70aa0a890b6c476Alan Cox * parallel to the change and re-referencing the tty. 63501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 63601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 637c65c9bc3efa5589f691276bb9db689119a711222Alan Cox work = tty_ldisc_halt(tty); 63801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (o_tty) 639c65c9bc3efa5589f691276bb9db689119a711222Alan Cox o_work = tty_ldisc_halt(o_tty); 64001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 64101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* 642c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Wait for ->hangup_work and ->buf.work handlers to terminate. 643c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * We must drop the mutex here in case a hangup is also in process. 64401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 645c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 646c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_unlock(&tty->ldisc_mutex); 647c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 6480a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo tty_ldisc_flush_works(tty); 649c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 650df92d0561de364de53c42abc5d43e04ab6f326a5Jiri Slaby retval = tty_ldisc_wait_idle(tty, 5 * HZ); 651100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby 652ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_lock(); 65360af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann mutex_lock(&tty->ldisc_mutex); 654100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby 655100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby /* handle wait idle failure locked */ 656100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby if (retval) { 657100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby tty_ldisc_put(new_ldisc); 658100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby goto enable; 659100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby } 660100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slaby 661c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (test_bit(TTY_HUPPED, &tty->flags)) { 662c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* We were raced by the hangup method. It will have stomped 663c65c9bc3efa5589f691276bb9db689119a711222Alan Cox the ldisc data and closed the ldisc down */ 664c65c9bc3efa5589f691276bb9db689119a711222Alan Cox clear_bit(TTY_LDISC_CHANGING, &tty->flags); 665c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_unlock(&tty->ldisc_mutex); 666c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_put(new_ldisc); 667ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 668c65c9bc3efa5589f691276bb9db689119a711222Alan Cox return -EIO; 669c65c9bc3efa5589f691276bb9db689119a711222Alan Cox } 670c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 67101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* Shutdown the current discipline. */ 672c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_close(tty, o_ldisc); 67301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 67401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* Now set up the new line discipline. */ 675c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_assign(tty, new_ldisc); 67601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_set_termios_ldisc(tty, ldisc); 677c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 678c65c9bc3efa5589f691276bb9db689119a711222Alan Cox retval = tty_ldisc_open(tty, new_ldisc); 67901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (retval < 0) { 680c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* Back to the old one or N_TTY if we can't */ 681c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_put(new_ldisc); 682c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_restore(tty, o_ldisc); 68301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox } 684c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 68501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* At this point we hold a reference to the new ldisc and a 68601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox a reference to the old ldisc. If we ended up flipping back 68701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox to the existing ldisc we have two references to it */ 68801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 689c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc) 69001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty->ops->set_ldisc(tty); 69101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 692c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_put(o_ldisc); 69301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 694100eeae2c5ce23b4db93ff320ee330ef1d740151Jiri Slabyenable: 69501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* 696c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Allow ldisc referencing to occur again 69701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 69801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 69901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_ldisc_enable(tty); 70001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (o_tty) 70101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_ldisc_enable(o_tty); 70201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 703c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* Restart the work queue in case no characters kick it off. Safe if 70401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox already running */ 70501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (work) 706f23eb2b2b28547fc70df82dd5049eb39bec5ba12Linus Torvalds schedule_work(&tty->buf.work); 707c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (o_work) 708f23eb2b2b28547fc70df82dd5049eb39bec5ba12Linus Torvalds schedule_work(&o_tty->buf.work); 709c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_unlock(&tty->ldisc_mutex); 710ec79d6056de58511d8e46d9ae59d3878f958dc3eArnd Bergmann tty_unlock(); 71101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return retval; 71201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 71301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 714c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/** 715c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * tty_reset_termios - reset terminal state 716c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * @tty: tty to reset 717c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * 718c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Restore a terminal to the driver default state. 719c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 720c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 721c65c9bc3efa5589f691276bb9db689119a711222Alan Coxstatic void tty_reset_termios(struct tty_struct *tty) 722c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{ 723c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_lock(&tty->termios_mutex); 724c65c9bc3efa5589f691276bb9db689119a711222Alan Cox *tty->termios = tty->driver->init_termios; 725c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); 726c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); 727c65c9bc3efa5589f691276bb9db689119a711222Alan Cox mutex_unlock(&tty->termios_mutex); 728c65c9bc3efa5589f691276bb9db689119a711222Alan Cox} 729c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 730c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 731c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/** 732c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * tty_ldisc_reinit - reinitialise the tty ldisc 733c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * @tty: tty to reinit 734638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox * @ldisc: line discipline to reinitialize 735c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * 736638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox * Switch the tty to a line discipline and leave the ldisc 737638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox * state closed 738c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 739c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 7401c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornazstatic int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) 741c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{ 7421c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz struct tty_ldisc *ld = tty_ldisc_get(ldisc); 7431c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz 7441c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz if (IS_ERR(ld)) 7451c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz return -1; 746c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 747c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_close(tty, tty->ldisc); 748c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_put(tty->ldisc); 749c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty->ldisc = NULL; 750c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* 751c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Switch the line discipline back 752c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 753c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_assign(tty, ld); 754638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox tty_set_termios_ldisc(tty, ldisc); 7551c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz 7561c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz return 0; 757c65c9bc3efa5589f691276bb9db689119a711222Alan Cox} 758c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 759c65c9bc3efa5589f691276bb9db689119a711222Alan Cox/** 760c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * tty_ldisc_hangup - hangup ldisc reset 761c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * @tty: tty being hung up 762c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * 763c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Some tty devices reset their termios when they receive a hangup 764c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * event. In that situation we must also switch back to N_TTY properly 765c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * before we reset the termios data. 766c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * 767c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Locking: We can take the ldisc mutex as the rest of the code is 768c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * careful to allow for this. 769c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * 770c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * In the pty pair case this occurs in the close() path of the 771c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * tty itself so we must be careful about locking rules. 772c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 773c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 774c65c9bc3efa5589f691276bb9db689119a711222Alan Coxvoid tty_ldisc_hangup(struct tty_struct *tty) 775c65c9bc3efa5589f691276bb9db689119a711222Alan Cox{ 776c65c9bc3efa5589f691276bb9db689119a711222Alan Cox struct tty_ldisc *ld; 777638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; 778638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox int err = 0; 779c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 780c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* 781c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * FIXME! What are the locking issues here? This may me overdoing 782c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * things... This question is especially important now that we've 783c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * removed the irqlock. 784c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 785c65c9bc3efa5589f691276bb9db689119a711222Alan Cox ld = tty_ldisc_ref(tty); 786c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (ld != NULL) { 787c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* We may have no line discipline at this point */ 788c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (ld->ops->flush_buffer) 789c65c9bc3efa5589f691276bb9db689119a711222Alan Cox ld->ops->flush_buffer(tty); 790c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_driver_flush_buffer(tty); 791c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && 792c65c9bc3efa5589f691276bb9db689119a711222Alan Cox ld->ops->write_wakeup) 793c65c9bc3efa5589f691276bb9db689119a711222Alan Cox ld->ops->write_wakeup(tty); 794c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (ld->ops->hangup) 795c65c9bc3efa5589f691276bb9db689119a711222Alan Cox ld->ops->hangup(tty); 796c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_deref(ld); 797c65c9bc3efa5589f691276bb9db689119a711222Alan Cox } 798c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* 799c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * FIXME: Once we trust the LDISC code better we can wait here for 800c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * ldisc completion and fix the driver call race 801c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 802c65c9bc3efa5589f691276bb9db689119a711222Alan Cox wake_up_interruptible_poll(&tty->write_wait, POLLOUT); 803c65c9bc3efa5589f691276bb9db689119a711222Alan Cox wake_up_interruptible_poll(&tty->read_wait, POLLIN); 804c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* 805c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * Shutdown the current line discipline, and reset it to 806638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox * N_TTY if need be. 807638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox * 808638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox * Avoid racing set_ldisc or tty_ldisc_release 809c65c9bc3efa5589f691276bb9db689119a711222Alan Cox */ 810638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox mutex_lock(&tty->ldisc_mutex); 81160af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann 81260af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann /* 81360af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann * this is like tty_ldisc_halt, but we need to give up 814f23eb2b2b28547fc70df82dd5049eb39bec5ba12Linus Torvalds * the BTM before calling cancel_work_sync, which may 815f23eb2b2b28547fc70df82dd5049eb39bec5ba12Linus Torvalds * need to wait for another function taking the BTM 81660af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann */ 81760af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann clear_bit(TTY_LDISC, &tty->flags); 81860af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann tty_unlock(); 819f23eb2b2b28547fc70df82dd5049eb39bec5ba12Linus Torvalds cancel_work_sync(&tty->buf.work); 82060af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann mutex_unlock(&tty->ldisc_mutex); 8210c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slabyretry: 82260af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann tty_lock(); 82360af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann mutex_lock(&tty->ldisc_mutex); 82460af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann 825638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox /* At this point we have a closed ldisc and we want to 826638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox reopen it. We could defer this to the next open but 827638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox it means auditing a lot of other paths so this is 828638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox a FIXME */ 829638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox if (tty->ldisc) { /* Not yet closed */ 8300c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby if (atomic_read(&tty->ldisc->users) != 1) { 8310c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby char cur_n[TASK_COMM_LEN], tty_n[64]; 8320c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby long timeout = 3 * HZ; 8330c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby tty_unlock(); 8340c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby 8350c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { 8360c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby timeout = MAX_SCHEDULE_TIMEOUT; 8370c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby printk_ratelimited(KERN_WARNING 8380c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby "%s: waiting (%s) for %s took too long, but we keep waiting...\n", 8390c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby __func__, get_task_comm(cur_n, current), 8400c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby tty_name(tty, tty_n)); 8410c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby } 8420c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby mutex_unlock(&tty->ldisc_mutex); 8430c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby goto retry; 8440c73c08ec73dbe080b9ec56696ee21d32754d918Jiri Slaby } 845300420722e0734a4254f3b634e0f82664495d210Jiri Slaby 846638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox if (reset == 0) { 8471c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz 8481c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz if (!tty_ldisc_reinit(tty, tty->termios->c_line)) 8491c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz err = tty_ldisc_open(tty, tty->ldisc); 8501c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz else 8511c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz err = 1; 852638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox } 853638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox /* If the re-open fails or we reset then go to N_TTY. The 854638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox N_TTY open cannot fail */ 855638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox if (reset || err) { 8561c95ba1e1de7edffc0c4e275e147f1a9eb1f81aePhilippe Rétornaz BUG_ON(tty_ldisc_reinit(tty, N_TTY)); 857c8d50041734534e0a4b0ea13df36ed5857fccd56Alan Cox WARN_ON(tty_ldisc_open(tty, tty->ldisc)); 858c8d50041734534e0a4b0ea13df36ed5857fccd56Alan Cox } 859638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox tty_ldisc_enable(tty); 860c65c9bc3efa5589f691276bb9db689119a711222Alan Cox } 861638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox mutex_unlock(&tty->ldisc_mutex); 862638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox if (reset) 863638b9648ab51c9c549ff5735d3de519ef6199df3Alan Cox tty_reset_termios(tty); 864c65c9bc3efa5589f691276bb9db689119a711222Alan Cox} 86501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 86601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 86701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_setup - open line discipline 86801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty being shut down 86901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @o_tty: pair tty for pty/tty pairs 87001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 87101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Called during the initial open of a tty/pty pair in order to set up the 872c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * line disciplines and bind them to the tty. This has no locking issues 873c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * as the device isn't yet active. 87401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 87501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 87601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxint tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) 87701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 878c65c9bc3efa5589f691276bb9db689119a711222Alan Cox struct tty_ldisc *ld = tty->ldisc; 87901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox int retval; 88001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 881c65c9bc3efa5589f691276bb9db689119a711222Alan Cox retval = tty_ldisc_open(tty, ld); 882c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (retval) 883c65c9bc3efa5589f691276bb9db689119a711222Alan Cox return retval; 884c65c9bc3efa5589f691276bb9db689119a711222Alan Cox 885c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (o_tty) { 886c65c9bc3efa5589f691276bb9db689119a711222Alan Cox retval = tty_ldisc_open(o_tty, o_tty->ldisc); 88701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox if (retval) { 888c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_close(tty, ld); 88901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return retval; 89001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox } 89101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_ldisc_enable(o_tty); 89201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox } 89301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox tty_ldisc_enable(tty); 89401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox return 0; 89501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 89601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 89701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_release - release line discipline 89801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty being shut down 89901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @o_tty: pair tty for pty/tty pairs 90001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 901852e99d22f2231d232c45216b027565e3bae7addAlan Cox * Called during the final close of a tty/pty pair in order to shut down 902852e99d22f2231d232c45216b027565e3bae7addAlan Cox * the line discpline layer. On exit the ldisc assigned is N_TTY and the 903c65c9bc3efa5589f691276bb9db689119a711222Alan Cox * ldisc has not been opened. 90401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 90501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 90601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) 90701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 90801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* 90901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Prevent flush_to_ldisc() from rescheduling the work for later. Then 91001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * kill any delayed work. As this is the final close it does not 91101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * race with the set_ldisc code path. 91201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 91301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 91460af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann tty_unlock(); 915e8b70e7d3e86319a8b2aaabde3866833d92cd80fAlan Cox tty_ldisc_halt(tty); 9160a1f1a0b626d79071ee9fe91b7fcd28be6332677Tejun Heo tty_ldisc_flush_works(tty); 91760af22d2ed490554cc92c8d0fed0b5b9cf687568Arnd Bergmann tty_lock(); 91801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 919c8d50041734534e0a4b0ea13df36ed5857fccd56Alan Cox mutex_lock(&tty->ldisc_mutex); 92001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* 921aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox * Now kill off the ldisc 92201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 923aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox tty_ldisc_close(tty, tty->ldisc); 924aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox tty_ldisc_put(tty->ldisc); 925aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox /* Force an oops if we mess this up */ 926aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox tty->ldisc = NULL; 927aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox 928aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox /* Ensure the next open requests the N_TTY ldisc */ 929aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox tty_set_termios_ldisc(tty, N_TTY); 930c8d50041734534e0a4b0ea13df36ed5857fccd56Alan Cox mutex_unlock(&tty->ldisc_mutex); 93101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 932c65c9bc3efa5589f691276bb9db689119a711222Alan Cox /* This will need doing differently if we need to lock */ 933c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (o_tty) 934c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_release(o_tty, NULL); 935aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox 936aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox /* And the memory resources remaining (buffers, termios) will be 937aef29bc2603014cb28dfe39bab8d888546fe18e7Alan Cox disposed of when the kref hits zero */ 93801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 93901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 94001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox/** 94101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * tty_ldisc_init - ldisc setup for new tty 94201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * @tty: tty being allocated 94301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * 94401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * Set up the line discipline objects for a newly allocated tty. Note that 94501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox * the tty structure is not completely set up when this call is made. 94601e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox */ 94701e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 94801e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_init(struct tty_struct *tty) 94901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 950c65c9bc3efa5589f691276bb9db689119a711222Alan Cox struct tty_ldisc *ld = tty_ldisc_get(N_TTY); 951c65c9bc3efa5589f691276bb9db689119a711222Alan Cox if (IS_ERR(ld)) 95201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox panic("n_tty: init_tty"); 953c65c9bc3efa5589f691276bb9db689119a711222Alan Cox tty_ldisc_assign(tty, ld); 95401e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 95501e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox 9566716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby/** 9576716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby * tty_ldisc_init - ldisc cleanup for new tty 9586716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby * @tty: tty that was allocated recently 9596716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby * 9606716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby * The tty structure must not becompletely set up (tty_ldisc_setup) when 9616716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby * this call is made. 9626716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby */ 9636716671d8c1c07a8072098764d1b7cbfef7412adJiri Slabyvoid tty_ldisc_deinit(struct tty_struct *tty) 9646716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby{ 9656716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby put_ldisc(tty->ldisc); 9666716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby tty_ldisc_assign(tty, NULL); 9676716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby} 9686716671d8c1c07a8072098764d1b7cbfef7412adJiri Slaby 96901e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Coxvoid tty_ldisc_begin(void) 97001e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox{ 97101e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox /* Setup the default TTY line discipline. */ 97201e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); 97301e1abb2c27e43339b8829a2e3b1c6f53806b77aAlan Cox} 974