From: Alexey Dobriyan It's a bit strange to see tty_register_ldisc call in modules' exit functions. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton --- Documentation/tty.txt | 2 +- drivers/char/tty_io.c | 37 ++++++++++++++++++++++++------------- include/linux/tty.h | 1 + 3 files changed, 26 insertions(+), 14 deletions(-) diff -puN Documentation/tty.txt~introduce-tty_unregister_ldisc Documentation/tty.txt --- 25/Documentation/tty.txt~introduce-tty_unregister_ldisc 2005-06-15 14:41:19.000000000 -0700 +++ 25-akpm/Documentation/tty.txt 2005-06-15 14:41:19.000000000 -0700 @@ -22,7 +22,7 @@ copy of the structure. You must not re-r discipline even with the same data or your computer again will be eaten by demons. -In order to remove a line discipline call tty_register_ldisc passing NULL. +In order to remove a line discipline call tty_unregister_ldisc(). In ancient times this always worked. In modern times the function will return -EBUSY if the ldisc is currently in use. Since the ldisc referencing code manages the module counts this should not usually be a concern. diff -puN drivers/char/tty_io.c~introduce-tty_unregister_ldisc drivers/char/tty_io.c --- 25/drivers/char/tty_io.c~introduce-tty_unregister_ldisc 2005-06-15 14:41:19.000000000 -0700 +++ 25-akpm/drivers/char/tty_io.c 2005-06-15 14:42:01.000000000 -0700 @@ -251,7 +251,7 @@ static void tty_set_termios_ldisc(struct static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); -static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ +static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { @@ -262,24 +262,35 @@ int tty_register_ldisc(int disc, struct return -EINVAL; spin_lock_irqsave(&tty_ldisc_lock, flags); - if (new_ldisc) { - tty_ldiscs[disc] = *new_ldisc; - tty_ldiscs[disc].num = disc; - tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; - tty_ldiscs[disc].refcount = 0; - } else { - if(tty_ldiscs[disc].refcount) - ret = -EBUSY; - else - tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; - } + tty_ldiscs[disc] = *new_ldisc; + tty_ldiscs[disc].num = disc; + tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; + tty_ldiscs[disc].refcount = 0; spin_unlock_irqrestore(&tty_ldisc_lock, flags); return ret; } - EXPORT_SYMBOL(tty_register_ldisc); +int tty_unregister_ldisc(int disc) +{ + unsigned long flags; + int ret = 0; + + if (disc < N_TTY || disc >= NR_LDISCS) + return -EINVAL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if (tty_ldiscs[disc].refcount) + ret = -EBUSY; + else + tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + + return ret; +} +EXPORT_SYMBOL(tty_unregister_ldisc); + struct tty_ldisc *tty_ldisc_get(int disc) { unsigned long flags; diff -puN include/linux/tty.h~introduce-tty_unregister_ldisc include/linux/tty.h --- 25/include/linux/tty.h~introduce-tty_unregister_ldisc 2005-06-15 14:41:19.000000000 -0700 +++ 25-akpm/include/linux/tty.h 2005-06-15 14:41:19.000000000 -0700 @@ -345,6 +345,7 @@ extern int tty_check_change(struct tty_s extern void stop_tty(struct tty_struct * tty); extern void start_tty(struct tty_struct * tty); extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); +extern int tty_unregister_ldisc(int disc); extern int tty_register_driver(struct tty_driver *driver); extern int tty_unregister_driver(struct tty_driver *driver); extern void tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev); _