diff options
author | Pavel Machek <pavel@suse.cz> | 2008-04-10 17:28:10 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-04-17 11:41:37 -0400 |
commit | e44b7b7525ad9d43163ab5e60c784325419e0ea6 (patch) | |
tree | e2918917a97b4c9de4367e8778ed78afc762b9f8 /arch/x86/boot/video-mode.c | |
parent | f49688d459c5eaa62db3597cbfd3cb13e361d415 (diff) |
x86: move suspend wakeup code to C
Move wakeup code to .c, so that video mode setting code can be shared
between boot and wakeup. Remove nasty assembly code in 64-bit case by
re-using trampoline code. Stack setup was fixed to clear high 16bits
of %esp, maybe that fixes some machines.
.c code sharing and morse code was done H. Peter Anvin, Sam Ravnborg
reviewed kbuild related stuff, and it seems okay to him. Rafael did
some cleanups.
[rjw:
* Made the patch stop breaking compilation on x86-32
* Added arch/x86/kernel/acpi/sleep.h
* Got rid of compiler warnings in arch/x86/kernel/acpi/sleep.c
* Fixed 32-bit compilation on x86-64 systems
* Added include/asm-x86/trampoline.h and fixed the non-SMP
compilation on 64-bit x86
* Removed arch/x86/kernel/acpi/sleep_32.c which was not used
* Fixed some breakage caused by the integration of smpboot.c done
under us in the meantime]
Signed-off-by: Pavel Machek <pavel@suse.cz>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/boot/video-mode.c')
-rw-r--r-- | arch/x86/boot/video-mode.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/arch/x86/boot/video-mode.c b/arch/x86/boot/video-mode.c new file mode 100644 index 000000000000..748e8d06290a --- /dev/null +++ b/arch/x86/boot/video-mode.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
4 | * Copyright 2007-2008 rPath, Inc. - All Rights Reserved | ||
5 | * | ||
6 | * This file is part of the Linux kernel, and is made available under | ||
7 | * the terms of the GNU General Public License version 2. | ||
8 | * | ||
9 | * ----------------------------------------------------------------------- */ | ||
10 | |||
11 | /* | ||
12 | * arch/i386/boot/video-mode.c | ||
13 | * | ||
14 | * Set the video mode. This is separated out into a different | ||
15 | * file in order to be shared with the ACPI wakeup code. | ||
16 | */ | ||
17 | |||
18 | #include "boot.h" | ||
19 | #include "video.h" | ||
20 | #include "vesa.h" | ||
21 | |||
22 | /* | ||
23 | * Common variables | ||
24 | */ | ||
25 | int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ | ||
26 | u16 video_segment; | ||
27 | int force_x, force_y; /* Don't query the BIOS for cols/rows */ | ||
28 | |||
29 | int do_restore; /* Screen contents changed during mode flip */ | ||
30 | int graphic_mode; /* Graphic mode with linear frame buffer */ | ||
31 | |||
32 | /* Probe the video drivers and have them generate their mode lists. */ | ||
33 | void probe_cards(int unsafe) | ||
34 | { | ||
35 | struct card_info *card; | ||
36 | static u8 probed[2]; | ||
37 | |||
38 | if (probed[unsafe]) | ||
39 | return; | ||
40 | |||
41 | probed[unsafe] = 1; | ||
42 | |||
43 | for (card = video_cards; card < video_cards_end; card++) { | ||
44 | if (card->unsafe == unsafe) { | ||
45 | if (card->probe) | ||
46 | card->nmodes = card->probe(); | ||
47 | else | ||
48 | card->nmodes = 0; | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
53 | /* Test if a mode is defined */ | ||
54 | int mode_defined(u16 mode) | ||
55 | { | ||
56 | struct card_info *card; | ||
57 | struct mode_info *mi; | ||
58 | int i; | ||
59 | |||
60 | for (card = video_cards; card < video_cards_end; card++) { | ||
61 | mi = card->modes; | ||
62 | for (i = 0; i < card->nmodes; i++, mi++) { | ||
63 | if (mi->mode == mode) | ||
64 | return 1; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /* Set mode (without recalc) */ | ||
72 | static int raw_set_mode(u16 mode, u16 *real_mode) | ||
73 | { | ||
74 | int nmode, i; | ||
75 | struct card_info *card; | ||
76 | struct mode_info *mi; | ||
77 | |||
78 | /* Drop the recalc bit if set */ | ||
79 | mode &= ~VIDEO_RECALC; | ||
80 | |||
81 | /* Scan for mode based on fixed ID, position, or resolution */ | ||
82 | nmode = 0; | ||
83 | for (card = video_cards; card < video_cards_end; card++) { | ||
84 | mi = card->modes; | ||
85 | for (i = 0; i < card->nmodes; i++, mi++) { | ||
86 | int visible = mi->x || mi->y; | ||
87 | |||
88 | if ((mode == nmode && visible) || | ||
89 | mode == mi->mode || | ||
90 | mode == (mi->y << 8)+mi->x) { | ||
91 | *real_mode = mi->mode; | ||
92 | return card->set_mode(mi); | ||
93 | } | ||
94 | |||
95 | if (visible) | ||
96 | nmode++; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /* Nothing found? Is it an "exceptional" (unprobed) mode? */ | ||
101 | for (card = video_cards; card < video_cards_end; card++) { | ||
102 | if (mode >= card->xmode_first && | ||
103 | mode < card->xmode_first+card->xmode_n) { | ||
104 | struct mode_info mix; | ||
105 | *real_mode = mix.mode = mode; | ||
106 | mix.x = mix.y = 0; | ||
107 | return card->set_mode(&mix); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* Otherwise, failure... */ | ||
112 | return -1; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Recalculate the vertical video cutoff (hack!) | ||
117 | */ | ||
118 | static void vga_recalc_vertical(void) | ||
119 | { | ||
120 | unsigned int font_size, rows; | ||
121 | u16 crtc; | ||
122 | u8 pt, ov; | ||
123 | |||
124 | set_fs(0); | ||
125 | font_size = rdfs8(0x485); /* BIOS: font size (pixels) */ | ||
126 | rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */ | ||
127 | |||
128 | rows *= font_size; /* Visible scan lines */ | ||
129 | rows--; /* ... minus one */ | ||
130 | |||
131 | crtc = vga_crtc(); | ||
132 | |||
133 | pt = in_idx(crtc, 0x11); | ||
134 | pt &= ~0x80; /* Unlock CR0-7 */ | ||
135 | out_idx(pt, crtc, 0x11); | ||
136 | |||
137 | out_idx((u8)rows, crtc, 0x12); /* Lower height register */ | ||
138 | |||
139 | ov = in_idx(crtc, 0x07); /* Overflow register */ | ||
140 | ov &= 0xbd; | ||
141 | ov |= (rows >> (8-1)) & 0x02; | ||
142 | ov |= (rows >> (9-6)) & 0x40; | ||
143 | out_idx(ov, crtc, 0x07); | ||
144 | } | ||
145 | |||
146 | /* Set mode (with recalc if specified) */ | ||
147 | int set_mode(u16 mode) | ||
148 | { | ||
149 | int rv; | ||
150 | u16 real_mode; | ||
151 | |||
152 | /* Very special mode numbers... */ | ||
153 | if (mode == VIDEO_CURRENT_MODE) | ||
154 | return 0; /* Nothing to do... */ | ||
155 | else if (mode == NORMAL_VGA) | ||
156 | mode = VIDEO_80x25; | ||
157 | else if (mode == EXTENDED_VGA) | ||
158 | mode = VIDEO_8POINT; | ||
159 | |||
160 | rv = raw_set_mode(mode, &real_mode); | ||
161 | if (rv) | ||
162 | return rv; | ||
163 | |||
164 | if (mode & VIDEO_RECALC) | ||
165 | vga_recalc_vertical(); | ||
166 | |||
167 | /* Save the canonical mode number for the kernel, not | ||
168 | an alias, size specification or menu position */ | ||
169 | #ifndef _WAKEUP | ||
170 | boot_params.hdr.vid_mode = real_mode; | ||
171 | #endif | ||
172 | return 0; | ||
173 | } | ||