diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/tty/tty_ldisc.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/tty/tty_ldisc.c')
-rw-r--r-- | drivers/tty/tty_ldisc.c | 161 |
1 files changed, 83 insertions, 78 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index c5782294e53..a76c808afad 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
@@ -1,11 +1,19 @@ | |||
1 | #include <linux/types.h> | 1 | #include <linux/types.h> |
2 | #include <linux/major.h> | ||
2 | #include <linux/errno.h> | 3 | #include <linux/errno.h> |
3 | #include <linux/kmod.h> | 4 | #include <linux/signal.h> |
5 | #include <linux/fcntl.h> | ||
4 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
5 | #include <linux/interrupt.h> | 7 | #include <linux/interrupt.h> |
6 | #include <linux/tty.h> | 8 | #include <linux/tty.h> |
7 | #include <linux/tty_driver.h> | 9 | #include <linux/tty_driver.h> |
10 | #include <linux/tty_flip.h> | ||
11 | #include <linux/devpts_fs.h> | ||
8 | #include <linux/file.h> | 12 | #include <linux/file.h> |
13 | #include <linux/console.h> | ||
14 | #include <linux/timer.h> | ||
15 | #include <linux/ctype.h> | ||
16 | #include <linux/kd.h> | ||
9 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
10 | #include <linux/string.h> | 18 | #include <linux/string.h> |
11 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
@@ -16,8 +24,18 @@ | |||
16 | #include <linux/device.h> | 24 | #include <linux/device.h> |
17 | #include <linux/wait.h> | 25 | #include <linux/wait.h> |
18 | #include <linux/bitops.h> | 26 | #include <linux/bitops.h> |
27 | #include <linux/delay.h> | ||
19 | #include <linux/seq_file.h> | 28 | #include <linux/seq_file.h> |
29 | |||
20 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <asm/system.h> | ||
32 | |||
33 | #include <linux/kbd_kern.h> | ||
34 | #include <linux/vt_kern.h> | ||
35 | #include <linux/selection.h> | ||
36 | |||
37 | #include <linux/kmod.h> | ||
38 | #include <linux/nsproxy.h> | ||
21 | #include <linux/ratelimit.h> | 39 | #include <linux/ratelimit.h> |
22 | 40 | ||
23 | /* | 41 | /* |
@@ -26,8 +44,9 @@ | |||
26 | * callers who will do ldisc lookups and cannot sleep. | 44 | * callers who will do ldisc lookups and cannot sleep. |
27 | */ | 45 | */ |
28 | 46 | ||
29 | static DEFINE_RAW_SPINLOCK(tty_ldisc_lock); | 47 | static DEFINE_SPINLOCK(tty_ldisc_lock); |
30 | static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); | 48 | static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); |
49 | static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle); | ||
31 | /* Line disc dispatch table */ | 50 | /* Line disc dispatch table */ |
32 | static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; | 51 | static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; |
33 | 52 | ||
@@ -49,22 +68,22 @@ static void put_ldisc(struct tty_ldisc *ld) | |||
49 | * If this is the last user, free the ldisc, and | 68 | * If this is the last user, free the ldisc, and |
50 | * release the ldisc ops. | 69 | * release the ldisc ops. |
51 | * | 70 | * |
52 | * We really want an "atomic_dec_and_raw_lock_irqsave()", | 71 | * We really want an "atomic_dec_and_lock_irqsave()", |
53 | * but we don't have it, so this does it by hand. | 72 | * but we don't have it, so this does it by hand. |
54 | */ | 73 | */ |
55 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); | 74 | local_irq_save(flags); |
56 | if (atomic_dec_and_test(&ld->users)) { | 75 | if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) { |
57 | struct tty_ldisc_ops *ldo = ld->ops; | 76 | struct tty_ldisc_ops *ldo = ld->ops; |
58 | 77 | ||
59 | ldo->refcount--; | 78 | ldo->refcount--; |
60 | module_put(ldo->owner); | 79 | module_put(ldo->owner); |
61 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 80 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
62 | 81 | ||
63 | kfree(ld); | 82 | kfree(ld); |
64 | return; | 83 | return; |
65 | } | 84 | } |
66 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 85 | local_irq_restore(flags); |
67 | wake_up(&ld->wq_idle); | 86 | wake_up(&tty_ldisc_idle); |
68 | } | 87 | } |
69 | 88 | ||
70 | /** | 89 | /** |
@@ -88,11 +107,11 @@ int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc) | |||
88 | if (disc < N_TTY || disc >= NR_LDISCS) | 107 | if (disc < N_TTY || disc >= NR_LDISCS) |
89 | return -EINVAL; | 108 | return -EINVAL; |
90 | 109 | ||
91 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); | 110 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
92 | tty_ldiscs[disc] = new_ldisc; | 111 | tty_ldiscs[disc] = new_ldisc; |
93 | new_ldisc->num = disc; | 112 | new_ldisc->num = disc; |
94 | new_ldisc->refcount = 0; | 113 | new_ldisc->refcount = 0; |
95 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 114 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
96 | 115 | ||
97 | return ret; | 116 | return ret; |
98 | } | 117 | } |
@@ -118,12 +137,12 @@ int tty_unregister_ldisc(int disc) | |||
118 | if (disc < N_TTY || disc >= NR_LDISCS) | 137 | if (disc < N_TTY || disc >= NR_LDISCS) |
119 | return -EINVAL; | 138 | return -EINVAL; |
120 | 139 | ||
121 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); | 140 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
122 | if (tty_ldiscs[disc]->refcount) | 141 | if (tty_ldiscs[disc]->refcount) |
123 | ret = -EBUSY; | 142 | ret = -EBUSY; |
124 | else | 143 | else |
125 | tty_ldiscs[disc] = NULL; | 144 | tty_ldiscs[disc] = NULL; |
126 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 145 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
127 | 146 | ||
128 | return ret; | 147 | return ret; |
129 | } | 148 | } |
@@ -134,7 +153,7 @@ static struct tty_ldisc_ops *get_ldops(int disc) | |||
134 | unsigned long flags; | 153 | unsigned long flags; |
135 | struct tty_ldisc_ops *ldops, *ret; | 154 | struct tty_ldisc_ops *ldops, *ret; |
136 | 155 | ||
137 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); | 156 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
138 | ret = ERR_PTR(-EINVAL); | 157 | ret = ERR_PTR(-EINVAL); |
139 | ldops = tty_ldiscs[disc]; | 158 | ldops = tty_ldiscs[disc]; |
140 | if (ldops) { | 159 | if (ldops) { |
@@ -144,7 +163,7 @@ static struct tty_ldisc_ops *get_ldops(int disc) | |||
144 | ret = ldops; | 163 | ret = ldops; |
145 | } | 164 | } |
146 | } | 165 | } |
147 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 166 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
148 | return ret; | 167 | return ret; |
149 | } | 168 | } |
150 | 169 | ||
@@ -152,10 +171,10 @@ static void put_ldops(struct tty_ldisc_ops *ldops) | |||
152 | { | 171 | { |
153 | unsigned long flags; | 172 | unsigned long flags; |
154 | 173 | ||
155 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); | 174 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
156 | ldops->refcount--; | 175 | ldops->refcount--; |
157 | module_put(ldops->owner); | 176 | module_put(ldops->owner); |
158 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 177 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
159 | } | 178 | } |
160 | 179 | ||
161 | /** | 180 | /** |
@@ -199,8 +218,6 @@ static struct tty_ldisc *tty_ldisc_get(int disc) | |||
199 | 218 | ||
200 | ld->ops = ldops; | 219 | ld->ops = ldops; |
201 | atomic_set(&ld->users, 1); | 220 | atomic_set(&ld->users, 1); |
202 | init_waitqueue_head(&ld->wq_idle); | ||
203 | |||
204 | return ld; | 221 | return ld; |
205 | } | 222 | } |
206 | 223 | ||
@@ -287,11 +304,11 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty) | |||
287 | unsigned long flags; | 304 | unsigned long flags; |
288 | struct tty_ldisc *ld; | 305 | struct tty_ldisc *ld; |
289 | 306 | ||
290 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); | 307 | spin_lock_irqsave(&tty_ldisc_lock, flags); |
291 | ld = NULL; | 308 | ld = NULL; |
292 | if (test_bit(TTY_LDISC, &tty->flags)) | 309 | if (test_bit(TTY_LDISC, &tty->flags)) |
293 | ld = get_ldisc(tty->ldisc); | 310 | ld = get_ldisc(tty->ldisc); |
294 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 311 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
295 | return ld; | 312 | return ld; |
296 | } | 313 | } |
297 | 314 | ||
@@ -413,7 +430,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush); | |||
413 | static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | 430 | static void tty_set_termios_ldisc(struct tty_struct *tty, int num) |
414 | { | 431 | { |
415 | mutex_lock(&tty->termios_mutex); | 432 | mutex_lock(&tty->termios_mutex); |
416 | tty->termios.c_line = num; | 433 | tty->termios->c_line = num; |
417 | mutex_unlock(&tty->termios_mutex); | 434 | mutex_unlock(&tty->termios_mutex); |
418 | } | 435 | } |
419 | 436 | ||
@@ -434,6 +451,7 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) | |||
434 | if (ld->ops->open) { | 451 | if (ld->ops->open) { |
435 | int ret; | 452 | int ret; |
436 | /* BTM here locks versus a hangup event */ | 453 | /* BTM here locks versus a hangup event */ |
454 | WARN_ON(!tty_locked()); | ||
437 | ret = ld->ops->open(tty); | 455 | ret = ld->ops->open(tty); |
438 | if (ret) | 456 | if (ret) |
439 | clear_bit(TTY_LDISC_OPEN, &tty->flags); | 457 | clear_bit(TTY_LDISC_OPEN, &tty->flags); |
@@ -512,7 +530,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) | |||
512 | static int tty_ldisc_halt(struct tty_struct *tty) | 530 | static int tty_ldisc_halt(struct tty_struct *tty) |
513 | { | 531 | { |
514 | clear_bit(TTY_LDISC, &tty->flags); | 532 | clear_bit(TTY_LDISC, &tty->flags); |
515 | return cancel_work_sync(&tty->port->buf.work); | 533 | return cancel_work_sync(&tty->buf.work); |
516 | } | 534 | } |
517 | 535 | ||
518 | /** | 536 | /** |
@@ -523,9 +541,9 @@ static int tty_ldisc_halt(struct tty_struct *tty) | |||
523 | */ | 541 | */ |
524 | static void tty_ldisc_flush_works(struct tty_struct *tty) | 542 | static void tty_ldisc_flush_works(struct tty_struct *tty) |
525 | { | 543 | { |
526 | flush_work(&tty->hangup_work); | 544 | flush_work_sync(&tty->hangup_work); |
527 | flush_work(&tty->SAK_work); | 545 | flush_work_sync(&tty->SAK_work); |
528 | flush_work(&tty->port->buf.work); | 546 | flush_work_sync(&tty->buf.work); |
529 | } | 547 | } |
530 | 548 | ||
531 | /** | 549 | /** |
@@ -539,8 +557,10 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) | |||
539 | static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) | 557 | static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) |
540 | { | 558 | { |
541 | long ret; | 559 | long ret; |
542 | ret = wait_event_timeout(tty->ldisc->wq_idle, | 560 | ret = wait_event_timeout(tty_ldisc_idle, |
543 | atomic_read(&tty->ldisc->users) == 1, timeout); | 561 | atomic_read(&tty->ldisc->users) == 1, timeout); |
562 | if (ret < 0) | ||
563 | return ret; | ||
544 | return ret > 0 ? 0 : -EBUSY; | 564 | return ret > 0 ? 0 : -EBUSY; |
545 | } | 565 | } |
546 | 566 | ||
@@ -568,7 +588,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
568 | if (IS_ERR(new_ldisc)) | 588 | if (IS_ERR(new_ldisc)) |
569 | return PTR_ERR(new_ldisc); | 589 | return PTR_ERR(new_ldisc); |
570 | 590 | ||
571 | tty_lock(tty); | 591 | tty_lock(); |
572 | /* | 592 | /* |
573 | * We need to look at the tty locking here for pty/tty pairs | 593 | * We need to look at the tty locking here for pty/tty pairs |
574 | * when both sides try to change in parallel. | 594 | * when both sides try to change in parallel. |
@@ -582,12 +602,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
582 | */ | 602 | */ |
583 | 603 | ||
584 | if (tty->ldisc->ops->num == ldisc) { | 604 | if (tty->ldisc->ops->num == ldisc) { |
585 | tty_unlock(tty); | 605 | tty_unlock(); |
586 | tty_ldisc_put(new_ldisc); | 606 | tty_ldisc_put(new_ldisc); |
587 | return 0; | 607 | return 0; |
588 | } | 608 | } |
589 | 609 | ||
590 | tty_unlock(tty); | 610 | tty_unlock(); |
591 | /* | 611 | /* |
592 | * Problem: What do we do if this blocks ? | 612 | * Problem: What do we do if this blocks ? |
593 | * We could deadlock here | 613 | * We could deadlock here |
@@ -595,7 +615,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
595 | 615 | ||
596 | tty_wait_until_sent(tty, 0); | 616 | tty_wait_until_sent(tty, 0); |
597 | 617 | ||
598 | tty_lock(tty); | 618 | tty_lock(); |
599 | mutex_lock(&tty->ldisc_mutex); | 619 | mutex_lock(&tty->ldisc_mutex); |
600 | 620 | ||
601 | /* | 621 | /* |
@@ -605,10 +625,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
605 | 625 | ||
606 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | 626 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { |
607 | mutex_unlock(&tty->ldisc_mutex); | 627 | mutex_unlock(&tty->ldisc_mutex); |
608 | tty_unlock(tty); | 628 | tty_unlock(); |
609 | wait_event(tty_ldisc_wait, | 629 | wait_event(tty_ldisc_wait, |
610 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); | 630 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); |
611 | tty_lock(tty); | 631 | tty_lock(); |
612 | mutex_lock(&tty->ldisc_mutex); | 632 | mutex_lock(&tty->ldisc_mutex); |
613 | } | 633 | } |
614 | 634 | ||
@@ -623,7 +643,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
623 | 643 | ||
624 | o_ldisc = tty->ldisc; | 644 | o_ldisc = tty->ldisc; |
625 | 645 | ||
626 | tty_unlock(tty); | 646 | tty_unlock(); |
627 | /* | 647 | /* |
628 | * Make sure we don't change while someone holds a | 648 | * Make sure we don't change while someone holds a |
629 | * reference to the line discipline. The TTY_LDISC bit | 649 | * reference to the line discipline. The TTY_LDISC bit |
@@ -650,7 +670,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
650 | 670 | ||
651 | retval = tty_ldisc_wait_idle(tty, 5 * HZ); | 671 | retval = tty_ldisc_wait_idle(tty, 5 * HZ); |
652 | 672 | ||
653 | tty_lock(tty); | 673 | tty_lock(); |
654 | mutex_lock(&tty->ldisc_mutex); | 674 | mutex_lock(&tty->ldisc_mutex); |
655 | 675 | ||
656 | /* handle wait idle failure locked */ | 676 | /* handle wait idle failure locked */ |
@@ -659,13 +679,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
659 | goto enable; | 679 | goto enable; |
660 | } | 680 | } |
661 | 681 | ||
662 | if (test_bit(TTY_HUPPING, &tty->flags)) { | 682 | if (test_bit(TTY_HUPPED, &tty->flags)) { |
663 | /* We were raced by the hangup method. It will have stomped | 683 | /* We were raced by the hangup method. It will have stomped |
664 | the ldisc data and closed the ldisc down */ | 684 | the ldisc data and closed the ldisc down */ |
665 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); | 685 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); |
666 | mutex_unlock(&tty->ldisc_mutex); | 686 | mutex_unlock(&tty->ldisc_mutex); |
667 | tty_ldisc_put(new_ldisc); | 687 | tty_ldisc_put(new_ldisc); |
668 | tty_unlock(tty); | 688 | tty_unlock(); |
669 | return -EIO; | 689 | return -EIO; |
670 | } | 690 | } |
671 | 691 | ||
@@ -704,11 +724,11 @@ enable: | |||
704 | /* Restart the work queue in case no characters kick it off. Safe if | 724 | /* Restart the work queue in case no characters kick it off. Safe if |
705 | already running */ | 725 | already running */ |
706 | if (work) | 726 | if (work) |
707 | schedule_work(&tty->port->buf.work); | 727 | schedule_work(&tty->buf.work); |
708 | if (o_work) | 728 | if (o_work) |
709 | schedule_work(&o_tty->port->buf.work); | 729 | schedule_work(&o_tty->buf.work); |
710 | mutex_unlock(&tty->ldisc_mutex); | 730 | mutex_unlock(&tty->ldisc_mutex); |
711 | tty_unlock(tty); | 731 | tty_unlock(); |
712 | return retval; | 732 | return retval; |
713 | } | 733 | } |
714 | 734 | ||
@@ -722,9 +742,9 @@ enable: | |||
722 | static void tty_reset_termios(struct tty_struct *tty) | 742 | static void tty_reset_termios(struct tty_struct *tty) |
723 | { | 743 | { |
724 | mutex_lock(&tty->termios_mutex); | 744 | mutex_lock(&tty->termios_mutex); |
725 | tty->termios = tty->driver->init_termios; | 745 | *tty->termios = tty->driver->init_termios; |
726 | tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); | 746 | tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); |
727 | tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); | 747 | tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); |
728 | mutex_unlock(&tty->termios_mutex); | 748 | mutex_unlock(&tty->termios_mutex); |
729 | } | 749 | } |
730 | 750 | ||
@@ -816,11 +836,11 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
816 | * need to wait for another function taking the BTM | 836 | * need to wait for another function taking the BTM |
817 | */ | 837 | */ |
818 | clear_bit(TTY_LDISC, &tty->flags); | 838 | clear_bit(TTY_LDISC, &tty->flags); |
819 | tty_unlock(tty); | 839 | tty_unlock(); |
820 | cancel_work_sync(&tty->port->buf.work); | 840 | cancel_work_sync(&tty->buf.work); |
821 | mutex_unlock(&tty->ldisc_mutex); | 841 | mutex_unlock(&tty->ldisc_mutex); |
822 | retry: | 842 | retry: |
823 | tty_lock(tty); | 843 | tty_lock(); |
824 | mutex_lock(&tty->ldisc_mutex); | 844 | mutex_lock(&tty->ldisc_mutex); |
825 | 845 | ||
826 | /* At this point we have a closed ldisc and we want to | 846 | /* At this point we have a closed ldisc and we want to |
@@ -831,7 +851,7 @@ retry: | |||
831 | if (atomic_read(&tty->ldisc->users) != 1) { | 851 | if (atomic_read(&tty->ldisc->users) != 1) { |
832 | char cur_n[TASK_COMM_LEN], tty_n[64]; | 852 | char cur_n[TASK_COMM_LEN], tty_n[64]; |
833 | long timeout = 3 * HZ; | 853 | long timeout = 3 * HZ; |
834 | tty_unlock(tty); | 854 | tty_unlock(); |
835 | 855 | ||
836 | while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { | 856 | while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { |
837 | timeout = MAX_SCHEDULE_TIMEOUT; | 857 | timeout = MAX_SCHEDULE_TIMEOUT; |
@@ -846,7 +866,7 @@ retry: | |||
846 | 866 | ||
847 | if (reset == 0) { | 867 | if (reset == 0) { |
848 | 868 | ||
849 | if (!tty_ldisc_reinit(tty, tty->termios.c_line)) | 869 | if (!tty_ldisc_reinit(tty, tty->termios->c_line)) |
850 | err = tty_ldisc_open(tty, tty->ldisc); | 870 | err = tty_ldisc_open(tty, tty->ldisc); |
851 | else | 871 | else |
852 | err = 1; | 872 | err = 1; |
@@ -894,28 +914,6 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | |||
894 | tty_ldisc_enable(tty); | 914 | tty_ldisc_enable(tty); |
895 | return 0; | 915 | return 0; |
896 | } | 916 | } |
897 | |||
898 | static void tty_ldisc_kill(struct tty_struct *tty) | ||
899 | { | ||
900 | /* There cannot be users from userspace now. But there still might be | ||
901 | * drivers holding a reference via tty_ldisc_ref. Do not steal them the | ||
902 | * ldisc until they are done. */ | ||
903 | tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT); | ||
904 | |||
905 | mutex_lock(&tty->ldisc_mutex); | ||
906 | /* | ||
907 | * Now kill off the ldisc | ||
908 | */ | ||
909 | tty_ldisc_close(tty, tty->ldisc); | ||
910 | tty_ldisc_put(tty->ldisc); | ||
911 | /* Force an oops if we mess this up */ | ||
912 | tty->ldisc = NULL; | ||
913 | |||
914 | /* Ensure the next open requests the N_TTY ldisc */ | ||
915 | tty_set_termios_ldisc(tty, N_TTY); | ||
916 | mutex_unlock(&tty->ldisc_mutex); | ||
917 | } | ||
918 | |||
919 | /** | 917 | /** |
920 | * tty_ldisc_release - release line discipline | 918 | * tty_ldisc_release - release line discipline |
921 | * @tty: tty being shut down | 919 | * @tty: tty being shut down |
@@ -934,21 +932,28 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
934 | * race with the set_ldisc code path. | 932 | * race with the set_ldisc code path. |
935 | */ | 933 | */ |
936 | 934 | ||
937 | tty_lock_pair(tty, o_tty); | 935 | tty_unlock(); |
938 | tty_ldisc_halt(tty); | 936 | tty_ldisc_halt(tty); |
939 | tty_ldisc_flush_works(tty); | 937 | tty_ldisc_flush_works(tty); |
940 | if (o_tty) { | 938 | tty_lock(); |
941 | tty_ldisc_halt(o_tty); | ||
942 | tty_ldisc_flush_works(o_tty); | ||
943 | } | ||
944 | 939 | ||
945 | /* This will need doing differently if we need to lock */ | 940 | mutex_lock(&tty->ldisc_mutex); |
946 | tty_ldisc_kill(tty); | 941 | /* |
942 | * Now kill off the ldisc | ||
943 | */ | ||
944 | tty_ldisc_close(tty, tty->ldisc); | ||
945 | tty_ldisc_put(tty->ldisc); | ||
946 | /* Force an oops if we mess this up */ | ||
947 | tty->ldisc = NULL; | ||
947 | 948 | ||
949 | /* Ensure the next open requests the N_TTY ldisc */ | ||
950 | tty_set_termios_ldisc(tty, N_TTY); | ||
951 | mutex_unlock(&tty->ldisc_mutex); | ||
952 | |||
953 | /* This will need doing differently if we need to lock */ | ||
948 | if (o_tty) | 954 | if (o_tty) |
949 | tty_ldisc_kill(o_tty); | 955 | tty_ldisc_release(o_tty, NULL); |
950 | 956 | ||
951 | tty_unlock_pair(tty, o_tty); | ||
952 | /* And the memory resources remaining (buffers, termios) will be | 957 | /* And the memory resources remaining (buffers, termios) will be |
953 | disposed of when the kref hits zero */ | 958 | disposed of when the kref hits zero */ |
954 | } | 959 | } |