diff options
author | Antonino A. Daplas <adaplas@gmail.com> | 2006-06-26 03:27:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:32 -0400 |
commit | 1c8ce271fe707d26b7bca4e490067fe65694b363 (patch) | |
tree | 42fc5fa81161065874b9aa751773d15465a8de9b /drivers/char | |
parent | 50ec42edd9784fad6a37b05be03064ea24098db6 (diff) |
[PATCH] Detaching fbcon: fix give_up_console()
To allow for detaching fbcon, it must be able to give up the console.
However, the function give_up_console() is plain broken. It just sets the
entries in the console driver map to NULL, it leaves the vt layer without a
console driver, and does not decrement the module reference count. Calling
give_up_console() is guaranteed to hang the machine..
To fix this problem, ensure that the virtual consoles are not left dangling
without a driver. All systems have a default boot driver (either vgacon or
dummycon) which is never unloaded. For those vt's that lost their driver, the
default boot driver is reassigned back to them.
Signed-off-by: Antonino Daplas <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/vt.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index eb27eed48a86..d7ff7fdb6fe3 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
@@ -100,6 +100,7 @@ | |||
100 | 100 | ||
101 | 101 | ||
102 | const struct consw *conswitchp; | 102 | const struct consw *conswitchp; |
103 | static struct consw *defcsw; /* default console */ | ||
103 | 104 | ||
104 | /* A bitmap for codes <32. A bit of 1 indicates that the code | 105 | /* A bitmap for codes <32. A bit of 1 indicates that the code |
105 | * corresponding to that bit number invokes some special action | 106 | * corresponding to that bit number invokes some special action |
@@ -2673,17 +2674,23 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2673 | if (!try_module_get(owner)) | 2674 | if (!try_module_get(owner)) |
2674 | return -ENODEV; | 2675 | return -ENODEV; |
2675 | 2676 | ||
2676 | acquire_console_sem(); | 2677 | /* save default console, for possible recovery later on */ |
2678 | if (!defcsw) | ||
2679 | defcsw = (struct consw *) conswitchp; | ||
2677 | 2680 | ||
2681 | acquire_console_sem(); | ||
2678 | desc = csw->con_startup(); | 2682 | desc = csw->con_startup(); |
2683 | |||
2679 | if (!desc) { | 2684 | if (!desc) { |
2680 | release_console_sem(); | 2685 | release_console_sem(); |
2681 | module_put(owner); | 2686 | module_put(owner); |
2682 | return -ENODEV; | 2687 | return -ENODEV; |
2683 | } | 2688 | } |
2689 | |||
2684 | if (deflt) { | 2690 | if (deflt) { |
2685 | if (conswitchp) | 2691 | if (conswitchp) |
2686 | module_put(conswitchp->owner); | 2692 | module_put(conswitchp->owner); |
2693 | |||
2687 | __module_get(owner); | 2694 | __module_get(owner); |
2688 | conswitchp = csw; | 2695 | conswitchp = csw; |
2689 | } | 2696 | } |
@@ -2701,6 +2708,7 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2701 | continue; | 2708 | continue; |
2702 | 2709 | ||
2703 | j = i; | 2710 | j = i; |
2711 | |||
2704 | if (CON_IS_VISIBLE(vc)) { | 2712 | if (CON_IS_VISIBLE(vc)) { |
2705 | k = i; | 2713 | k = i; |
2706 | save_screen(vc); | 2714 | save_screen(vc); |
@@ -2709,10 +2717,8 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2709 | old_was_color = vc->vc_can_do_color; | 2717 | old_was_color = vc->vc_can_do_color; |
2710 | vc->vc_sw->con_deinit(vc); | 2718 | vc->vc_sw->con_deinit(vc); |
2711 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; | 2719 | vc->vc_origin = (unsigned long)vc->vc_screenbuf; |
2712 | vc->vc_visible_origin = vc->vc_origin; | ||
2713 | vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size; | ||
2714 | vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x; | ||
2715 | visual_init(vc, i, 0); | 2720 | visual_init(vc, i, 0); |
2721 | set_origin(vc); | ||
2716 | update_attr(vc); | 2722 | update_attr(vc); |
2717 | 2723 | ||
2718 | /* If the console changed between mono <-> color, then | 2724 | /* If the console changed between mono <-> color, then |
@@ -2741,22 +2747,29 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) | |||
2741 | printk("to %s\n", desc); | 2747 | printk("to %s\n", desc); |
2742 | 2748 | ||
2743 | release_console_sem(); | 2749 | release_console_sem(); |
2744 | |||
2745 | module_put(owner); | 2750 | module_put(owner); |
2746 | return 0; | 2751 | return 0; |
2747 | } | 2752 | } |
2748 | 2753 | ||
2749 | void give_up_console(const struct consw *csw) | 2754 | void give_up_console(const struct consw *csw) |
2750 | { | 2755 | { |
2751 | int i; | 2756 | int i, first = -1, last = -1, deflt = 0; |
2752 | 2757 | ||
2753 | for(i = 0; i < MAX_NR_CONSOLES; i++) | 2758 | for (i = 0; i < MAX_NR_CONSOLES; i++) |
2754 | if (con_driver_map[i] == csw) { | 2759 | if (con_driver_map[i] == csw) { |
2760 | if (first == -1) | ||
2761 | first = i; | ||
2762 | last = i; | ||
2755 | module_put(csw->owner); | 2763 | module_put(csw->owner); |
2756 | con_driver_map[i] = NULL; | 2764 | con_driver_map[i] = NULL; |
2757 | } | 2765 | } |
2758 | } | ||
2759 | 2766 | ||
2767 | if (first != -1 && defcsw) { | ||
2768 | if (first == 0 && last == MAX_NR_CONSOLES - 1) | ||
2769 | deflt = 1; | ||
2770 | take_over_console(defcsw, first, last, deflt); | ||
2771 | } | ||
2772 | } | ||
2760 | #endif | 2773 | #endif |
2761 | 2774 | ||
2762 | /* | 2775 | /* |