diff options
-rw-r--r-- | arch/i386/boot/vesa.h | 79 | ||||
-rw-r--r-- | arch/i386/boot/video-bios.c | 125 | ||||
-rw-r--r-- | arch/i386/boot/video-vesa.c | 284 | ||||
-rw-r--r-- | arch/i386/boot/video-vga.c | 260 | ||||
-rw-r--r-- | arch/i386/boot/video.c | 456 | ||||
-rw-r--r-- | arch/i386/boot/video.h | 145 |
6 files changed, 1349 insertions, 0 deletions
diff --git a/arch/i386/boot/vesa.h b/arch/i386/boot/vesa.h new file mode 100644 index 000000000000..ff5b73cd406f --- /dev/null +++ b/arch/i386/boot/vesa.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* ----------------------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright 1999-2007 H. Peter Anvin - All Rights Reserved | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation, Inc., 53 Temple Place Ste 330, | ||
8 | * Boston MA 02111-1307, USA; either version 2 of the License, or | ||
9 | * (at your option) any later version; incorporated herein by reference. | ||
10 | * | ||
11 | * ----------------------------------------------------------------------- */ | ||
12 | |||
13 | #ifndef BOOT_VESA_H | ||
14 | #define BOOT_VESA_H | ||
15 | |||
16 | typedef struct { | ||
17 | u16 off, seg; | ||
18 | } far_ptr; | ||
19 | |||
20 | /* VESA General Information table */ | ||
21 | struct vesa_general_info { | ||
22 | u32 signature; /* 0 Magic number = "VESA" */ | ||
23 | u16 version; /* 4 */ | ||
24 | far_ptr vendor_string; /* 6 */ | ||
25 | u32 capabilities; /* 10 */ | ||
26 | far_ptr video_mode_ptr; /* 14 */ | ||
27 | u16 total_memory; /* 18 */ | ||
28 | |||
29 | u16 oem_software_rev; /* 20 */ | ||
30 | far_ptr oem_vendor_name_ptr; /* 22 */ | ||
31 | far_ptr oem_product_name_ptr; /* 26 */ | ||
32 | far_ptr oem_product_rev_ptr; /* 30 */ | ||
33 | |||
34 | u8 reserved[222]; /* 34 */ | ||
35 | u8 oem_data[256]; /* 256 */ | ||
36 | } __attribute__ ((packed)); | ||
37 | |||
38 | #define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24)) | ||
39 | #define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24)) | ||
40 | |||
41 | struct vesa_mode_info { | ||
42 | u16 mode_attr; /* 0 */ | ||
43 | u8 win_attr[2]; /* 2 */ | ||
44 | u16 win_grain; /* 4 */ | ||
45 | u16 win_size; /* 6 */ | ||
46 | u16 win_seg[2]; /* 8 */ | ||
47 | far_ptr win_scheme; /* 12 */ | ||
48 | u16 logical_scan; /* 16 */ | ||
49 | |||
50 | u16 h_res; /* 18 */ | ||
51 | u16 v_res; /* 20 */ | ||
52 | u8 char_width; /* 22 */ | ||
53 | u8 char_height; /* 23 */ | ||
54 | u8 memory_planes; /* 24 */ | ||
55 | u8 bpp; /* 25 */ | ||
56 | u8 banks; /* 26 */ | ||
57 | u8 memory_layout; /* 27 */ | ||
58 | u8 bank_size; /* 28 */ | ||
59 | u8 image_planes; /* 29 */ | ||
60 | u8 page_function; /* 30 */ | ||
61 | |||
62 | u8 rmask; /* 31 */ | ||
63 | u8 rpos; /* 32 */ | ||
64 | u8 gmask; /* 33 */ | ||
65 | u8 gpos; /* 34 */ | ||
66 | u8 bmask; /* 35 */ | ||
67 | u8 bpos; /* 36 */ | ||
68 | u8 resv_mask; /* 37 */ | ||
69 | u8 resv_pos; /* 38 */ | ||
70 | u8 dcm_info; /* 39 */ | ||
71 | |||
72 | u32 lfb_ptr; /* 40 Linear frame buffer address */ | ||
73 | u32 offscreen_ptr; /* 44 Offscreen memory address */ | ||
74 | u16 offscreen_size; /* 48 */ | ||
75 | |||
76 | u8 reserved[206]; /* 50 */ | ||
77 | } __attribute__ ((packed)); | ||
78 | |||
79 | #endif /* LIB_SYS_VESA_H */ | ||
diff --git a/arch/i386/boot/video-bios.c b/arch/i386/boot/video-bios.c new file mode 100644 index 000000000000..afea46c500cc --- /dev/null +++ b/arch/i386/boot/video-bios.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
4 | * Copyright 2007 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-bios.c | ||
13 | * | ||
14 | * Standard video BIOS modes | ||
15 | * | ||
16 | * We have two options for this; silent and scanned. | ||
17 | */ | ||
18 | |||
19 | #include "boot.h" | ||
20 | #include "video.h" | ||
21 | |||
22 | __videocard video_bios; | ||
23 | |||
24 | /* Set a conventional BIOS mode */ | ||
25 | static int set_bios_mode(u8 mode); | ||
26 | |||
27 | static int bios_set_mode(struct mode_info *mi) | ||
28 | { | ||
29 | return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS); | ||
30 | } | ||
31 | |||
32 | static int set_bios_mode(u8 mode) | ||
33 | { | ||
34 | u16 ax; | ||
35 | u8 new_mode; | ||
36 | |||
37 | ax = mode; /* AH=0x00 Set Video Mode */ | ||
38 | asm volatile(INT10 | ||
39 | : "+a" (ax) | ||
40 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
41 | |||
42 | ax = 0x0f00; /* Get Current Video Mode */ | ||
43 | asm volatile(INT10 | ||
44 | : "+a" (ax) | ||
45 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
46 | |||
47 | do_restore = 1; /* Assume video contents was lost */ | ||
48 | new_mode = ax & 0x7f; /* Not all BIOSes are clean with the top bit */ | ||
49 | |||
50 | if (new_mode == mode) | ||
51 | return 0; /* Mode change OK */ | ||
52 | |||
53 | if (new_mode != boot_params.screen_info.orig_video_mode) { | ||
54 | /* Mode setting failed, but we didn't end up where we | ||
55 | started. That's bad. Try to revert to the original | ||
56 | video mode. */ | ||
57 | ax = boot_params.screen_info.orig_video_mode; | ||
58 | asm volatile(INT10 | ||
59 | : "+a" (ax) | ||
60 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
61 | } | ||
62 | return -1; | ||
63 | } | ||
64 | |||
65 | static int bios_probe(void) | ||
66 | { | ||
67 | u8 mode; | ||
68 | u8 saved_mode = boot_params.screen_info.orig_video_mode; | ||
69 | u16 crtc; | ||
70 | struct mode_info *mi; | ||
71 | int nmodes = 0; | ||
72 | |||
73 | if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA) | ||
74 | return 0; | ||
75 | |||
76 | set_fs(0); | ||
77 | crtc = vga_crtc(); | ||
78 | |||
79 | video_bios.modes = GET_HEAP(struct mode_info, 0); | ||
80 | |||
81 | for (mode = 0x14; mode <= 0x7f; mode++) { | ||
82 | if (heap_free() < sizeof(struct mode_info)) | ||
83 | break; | ||
84 | |||
85 | if (mode_defined(VIDEO_FIRST_BIOS+mode)) | ||
86 | continue; | ||
87 | |||
88 | if (set_bios_mode(mode)) | ||
89 | continue; | ||
90 | |||
91 | /* Try to verify that it's a text mode. */ | ||
92 | |||
93 | /* Attribute Controller: make graphics controller disabled */ | ||
94 | if (in_idx(0x3c0, 0x10) & 0x01) | ||
95 | continue; | ||
96 | |||
97 | /* Graphics Controller: verify Alpha addressing enabled */ | ||
98 | if (in_idx(0x3ce, 0x06) & 0x01) | ||
99 | continue; | ||
100 | |||
101 | /* CRTC cursor location low should be zero(?) */ | ||
102 | if (in_idx(crtc, 0x0f)) | ||
103 | continue; | ||
104 | |||
105 | mi = GET_HEAP(struct mode_info, 1); | ||
106 | mi->mode = VIDEO_FIRST_BIOS+mode; | ||
107 | mi->x = rdfs16(0x44a); | ||
108 | mi->y = rdfs8(0x484)+1; | ||
109 | nmodes++; | ||
110 | } | ||
111 | |||
112 | set_bios_mode(saved_mode); | ||
113 | |||
114 | return nmodes; | ||
115 | } | ||
116 | |||
117 | __videocard video_bios = | ||
118 | { | ||
119 | .card_name = "BIOS (scanned)", | ||
120 | .probe = bios_probe, | ||
121 | .set_mode = bios_set_mode, | ||
122 | .unsafe = 1, | ||
123 | .xmode_first = VIDEO_FIRST_BIOS, | ||
124 | .xmode_n = 0x80, | ||
125 | }; | ||
diff --git a/arch/i386/boot/video-vesa.c b/arch/i386/boot/video-vesa.c new file mode 100644 index 000000000000..e6aa9eb8d93a --- /dev/null +++ b/arch/i386/boot/video-vesa.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
4 | * Copyright 2007 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-vesa.c | ||
13 | * | ||
14 | * VESA text modes | ||
15 | */ | ||
16 | |||
17 | #include "boot.h" | ||
18 | #include "video.h" | ||
19 | #include "vesa.h" | ||
20 | |||
21 | /* VESA information */ | ||
22 | static struct vesa_general_info vginfo; | ||
23 | static struct vesa_mode_info vminfo; | ||
24 | |||
25 | __videocard video_vesa; | ||
26 | |||
27 | static void vesa_store_mode_params_graphics(void); | ||
28 | |||
29 | static int vesa_probe(void) | ||
30 | { | ||
31 | #if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID) | ||
32 | u16 ax; | ||
33 | u16 mode; | ||
34 | addr_t mode_ptr; | ||
35 | struct mode_info *mi; | ||
36 | int nmodes = 0; | ||
37 | |||
38 | video_vesa.modes = GET_HEAP(struct mode_info, 0); | ||
39 | |||
40 | vginfo.signature = VBE2_MAGIC; | ||
41 | |||
42 | /* Optimistically assume a VESA BIOS is register-clean... */ | ||
43 | ax = 0x4f00; | ||
44 | asm("int $0x10" : "+a" (ax), "=m" (vginfo) : "D" (&vginfo)); | ||
45 | |||
46 | if (ax != 0x004f || | ||
47 | vginfo.signature != VESA_MAGIC || | ||
48 | vginfo.version < 0x0102) | ||
49 | return 0; /* Not present */ | ||
50 | #endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */ | ||
51 | #ifdef CONFIG_VIDEO_VESA | ||
52 | set_fs(vginfo.video_mode_ptr.seg); | ||
53 | mode_ptr = vginfo.video_mode_ptr.off; | ||
54 | |||
55 | while ((mode = rdfs16(mode_ptr)) != 0xffff) { | ||
56 | mode_ptr += 2; | ||
57 | |||
58 | if (heap_free() < sizeof(struct mode_info)) | ||
59 | break; /* Heap full, can't save mode info */ | ||
60 | |||
61 | if (mode & ~0x1ff) | ||
62 | continue; | ||
63 | |||
64 | memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ | ||
65 | |||
66 | ax = 0x4f01; | ||
67 | asm("int $0x10" | ||
68 | : "+a" (ax), "=m" (vminfo) | ||
69 | : "c" (mode), "D" (&vminfo)); | ||
70 | |||
71 | if (ax != 0x004f) | ||
72 | continue; | ||
73 | |||
74 | if ((vminfo.mode_attr & 0x15) == 0x05) { | ||
75 | /* Text Mode, TTY BIOS supported, | ||
76 | supported by hardware */ | ||
77 | mi = GET_HEAP(struct mode_info, 1); | ||
78 | mi->mode = mode + VIDEO_FIRST_VESA; | ||
79 | mi->x = vminfo.h_res; | ||
80 | mi->y = vminfo.v_res; | ||
81 | nmodes++; | ||
82 | } else if ((vminfo.mode_attr & 0x99) == 0x99) { | ||
83 | #ifdef CONFIG_FB | ||
84 | /* Graphics mode, color, linear frame buffer | ||
85 | supported -- register the mode but hide from | ||
86 | the menu. Only do this if framebuffer is | ||
87 | configured, however, otherwise the user will | ||
88 | be left without a screen. */ | ||
89 | mi = GET_HEAP(struct mode_info, 1); | ||
90 | mi->mode = mode + VIDEO_FIRST_VESA; | ||
91 | mi->x = mi->y = 0; | ||
92 | nmodes++; | ||
93 | #endif | ||
94 | } | ||
95 | } | ||
96 | |||
97 | return nmodes; | ||
98 | #else | ||
99 | return 0; | ||
100 | #endif /* CONFIG_VIDEO_VESA */ | ||
101 | } | ||
102 | |||
103 | static int vesa_set_mode(struct mode_info *mode) | ||
104 | { | ||
105 | u16 ax; | ||
106 | int is_graphic; | ||
107 | u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA; | ||
108 | |||
109 | memset(&vminfo, 0, sizeof vminfo); /* Just in case... */ | ||
110 | |||
111 | ax = 0x4f01; | ||
112 | asm("int $0x10" | ||
113 | : "+a" (ax), "=m" (vminfo) | ||
114 | : "c" (vesa_mode), "D" (&vminfo)); | ||
115 | |||
116 | if (ax != 0x004f) | ||
117 | return -1; | ||
118 | |||
119 | if ((vminfo.mode_attr & 0x15) == 0x05) { | ||
120 | /* It's a supported text mode */ | ||
121 | is_graphic = 0; | ||
122 | } else if ((vminfo.mode_attr & 0x99) == 0x99) { | ||
123 | /* It's a graphics mode with linear frame buffer */ | ||
124 | is_graphic = 1; | ||
125 | vesa_mode |= 0x4000; /* Request linear frame buffer */ | ||
126 | } else { | ||
127 | return -1; /* Invalid mode */ | ||
128 | } | ||
129 | |||
130 | |||
131 | ax = 0x4f02; | ||
132 | asm volatile("int $0x10" | ||
133 | : "+a" (ax) | ||
134 | : "b" (vesa_mode), "D" (0)); | ||
135 | |||
136 | if (ax != 0x004f) | ||
137 | return -1; | ||
138 | |||
139 | graphic_mode = is_graphic; | ||
140 | if (!is_graphic) { | ||
141 | /* Text mode */ | ||
142 | force_x = mode->x; | ||
143 | force_y = mode->y; | ||
144 | do_restore = 1; | ||
145 | } else { | ||
146 | /* Graphics mode */ | ||
147 | vesa_store_mode_params_graphics(); | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | |||
154 | /* Switch DAC to 8-bit mode */ | ||
155 | static void vesa_dac_set_8bits(void) | ||
156 | { | ||
157 | u8 dac_size = 6; | ||
158 | |||
159 | /* If possible, switch the DAC to 8-bit mode */ | ||
160 | if (vginfo.capabilities & 1) { | ||
161 | u16 ax, bx; | ||
162 | |||
163 | ax = 0x4f08; | ||
164 | bx = 0x0800; | ||
165 | asm volatile(INT10 | ||
166 | : "+a" (ax), "+b" (bx) | ||
167 | : : "ecx", "edx", "esi", "edi"); | ||
168 | |||
169 | if (ax == 0x004f) | ||
170 | dac_size = bx >> 8; | ||
171 | } | ||
172 | |||
173 | /* Set the color sizes to the DAC size, and offsets to 0 */ | ||
174 | boot_params.screen_info.red_size = dac_size; | ||
175 | boot_params.screen_info.green_size = dac_size; | ||
176 | boot_params.screen_info.blue_size = dac_size; | ||
177 | boot_params.screen_info.rsvd_size = dac_size; | ||
178 | |||
179 | boot_params.screen_info.red_pos = 0; | ||
180 | boot_params.screen_info.green_pos = 0; | ||
181 | boot_params.screen_info.blue_pos = 0; | ||
182 | boot_params.screen_info.rsvd_pos = 0; | ||
183 | } | ||
184 | |||
185 | /* Save the VESA protected mode info */ | ||
186 | static void vesa_store_pm_info(void) | ||
187 | { | ||
188 | u16 ax, bx, di, es; | ||
189 | |||
190 | ax = 0x4f0a; | ||
191 | bx = di = 0; | ||
192 | asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es" | ||
193 | : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di) | ||
194 | : : "ecx", "esi"); | ||
195 | |||
196 | if (ax != 0x004f) | ||
197 | return; | ||
198 | |||
199 | boot_params.screen_info.vesapm_seg = es; | ||
200 | boot_params.screen_info.vesapm_off = di; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Save video mode parameters for graphics mode | ||
205 | */ | ||
206 | static void vesa_store_mode_params_graphics(void) | ||
207 | { | ||
208 | /* Tell the kernel we're in VESA graphics mode */ | ||
209 | boot_params.screen_info.orig_video_isVGA = 0x23; | ||
210 | |||
211 | /* Mode parameters */ | ||
212 | boot_params.screen_info.vesa_attributes = vminfo.mode_attr; | ||
213 | boot_params.screen_info.lfb_linelength = vminfo.logical_scan; | ||
214 | boot_params.screen_info.lfb_width = vminfo.h_res; | ||
215 | boot_params.screen_info.lfb_height = vminfo.v_res; | ||
216 | boot_params.screen_info.lfb_depth = vminfo.bpp; | ||
217 | boot_params.screen_info.pages = vminfo.image_planes; | ||
218 | boot_params.screen_info.lfb_base = vminfo.lfb_ptr; | ||
219 | memcpy(&boot_params.screen_info.red_size, | ||
220 | &vminfo.rmask, 8); | ||
221 | |||
222 | /* General parameters */ | ||
223 | boot_params.screen_info.lfb_size = vginfo.total_memory; | ||
224 | |||
225 | if (vminfo.bpp <= 8) | ||
226 | vesa_dac_set_8bits(); | ||
227 | |||
228 | vesa_store_pm_info(); | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * Save EDID information for the kernel; this is invoked, separately, | ||
233 | * after mode-setting. | ||
234 | */ | ||
235 | void vesa_store_edid(void) | ||
236 | { | ||
237 | #ifdef CONFIG_FIRMWARE_EDID | ||
238 | u16 ax, bx, cx, dx, di; | ||
239 | |||
240 | /* Apparently used as a nonsense token... */ | ||
241 | memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info); | ||
242 | |||
243 | if (vginfo.version < 0x0200) | ||
244 | return; /* EDID requires VBE 2.0+ */ | ||
245 | |||
246 | ax = 0x4f15; /* VBE DDC */ | ||
247 | bx = 0x0000; /* Report DDC capabilities */ | ||
248 | cx = 0; /* Controller 0 */ | ||
249 | di = 0; /* ES:DI must be 0 by spec */ | ||
250 | |||
251 | /* Note: The VBE DDC spec is different from the main VESA spec; | ||
252 | we genuinely have to assume all registers are destroyed here. */ | ||
253 | |||
254 | asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" | ||
255 | : "+a" (ax), "+b" (bx) | ||
256 | : "c" (cx), "D" (di) | ||
257 | : "esi"); | ||
258 | |||
259 | if (ax != 0x004f) | ||
260 | return; /* No EDID */ | ||
261 | |||
262 | /* BH = time in seconds to transfer EDD information */ | ||
263 | /* BL = DDC level supported */ | ||
264 | |||
265 | ax = 0x4f15; /* VBE DDC */ | ||
266 | bx = 0x0001; /* Read EDID */ | ||
267 | cx = 0; /* Controller 0 */ | ||
268 | dx = 0; /* EDID block number */ | ||
269 | di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */ | ||
270 | asm(INT10 | ||
271 | : "+a" (ax), "+b" (bx), "+d" (dx) | ||
272 | : "c" (cx), "D" (di) | ||
273 | : "esi"); | ||
274 | #endif /* CONFIG_FIRMWARE_EDID */ | ||
275 | } | ||
276 | |||
277 | __videocard video_vesa = | ||
278 | { | ||
279 | .card_name = "VESA", | ||
280 | .probe = vesa_probe, | ||
281 | .set_mode = vesa_set_mode, | ||
282 | .xmode_first = VIDEO_FIRST_VESA, | ||
283 | .xmode_n = 0x200, | ||
284 | }; | ||
diff --git a/arch/i386/boot/video-vga.c b/arch/i386/boot/video-vga.c new file mode 100644 index 000000000000..700d09a9c9b3 --- /dev/null +++ b/arch/i386/boot/video-vga.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
4 | * Copyright 2007 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-vga.c | ||
13 | * | ||
14 | * Common all-VGA modes | ||
15 | */ | ||
16 | |||
17 | #include "boot.h" | ||
18 | #include "video.h" | ||
19 | |||
20 | static struct mode_info vga_modes[] = { | ||
21 | { VIDEO_80x25, 80, 25 }, | ||
22 | { VIDEO_8POINT, 80, 50 }, | ||
23 | { VIDEO_80x43, 80, 43 }, | ||
24 | { VIDEO_80x28, 80, 28 }, | ||
25 | { VIDEO_80x30, 80, 30 }, | ||
26 | { VIDEO_80x34, 80, 34 }, | ||
27 | { VIDEO_80x60, 80, 60 }, | ||
28 | }; | ||
29 | |||
30 | static struct mode_info ega_modes[] = { | ||
31 | { VIDEO_80x25, 80, 25 }, | ||
32 | { VIDEO_8POINT, 80, 43 }, | ||
33 | }; | ||
34 | |||
35 | static struct mode_info cga_modes[] = { | ||
36 | { VIDEO_80x25, 80, 25 }, | ||
37 | }; | ||
38 | |||
39 | __videocard video_vga; | ||
40 | |||
41 | /* Set basic 80x25 mode */ | ||
42 | static u8 vga_set_basic_mode(void) | ||
43 | { | ||
44 | u16 ax; | ||
45 | u8 rows; | ||
46 | u8 mode; | ||
47 | |||
48 | #ifdef CONFIG_VIDEO_400_HACK | ||
49 | if (adapter >= ADAPTER_VGA) { | ||
50 | asm(INT10 | ||
51 | : : "a" (0x1202), "b" (0x0030) | ||
52 | : "ecx", "edx", "esi", "edi"); | ||
53 | } | ||
54 | #endif | ||
55 | |||
56 | ax = 0x0f00; | ||
57 | asm(INT10 | ||
58 | : "+a" (ax) | ||
59 | : : "ebx", "ecx", "edx", "esi", "edi"); | ||
60 | |||
61 | mode = (u8)ax; | ||
62 | |||
63 | set_fs(0); | ||
64 | rows = rdfs8(0x484); /* rows minus one */ | ||
65 | |||
66 | #ifndef CONFIG_VIDEO_400_HACK | ||
67 | if ((ax == 0x5003 || ax == 0x5007) && | ||
68 | (rows == 0 || rows == 24)) | ||
69 | return mode; | ||
70 | #endif | ||
71 | |||
72 | if (mode != 3 && mode != 7) | ||
73 | mode = 3; | ||
74 | |||
75 | /* Set the mode */ | ||
76 | asm volatile(INT10 | ||
77 | : : "a" (mode) | ||
78 | : "ebx", "ecx", "edx", "esi", "edi"); | ||
79 | do_restore = 1; | ||
80 | return mode; | ||
81 | } | ||
82 | |||
83 | static void vga_set_8font(void) | ||
84 | { | ||
85 | /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */ | ||
86 | |||
87 | /* Set 8x8 font */ | ||
88 | asm volatile(INT10 : : "a" (0x1112), "b" (0)); | ||
89 | |||
90 | /* Use alternate print screen */ | ||
91 | asm volatile(INT10 : : "a" (0x1200), "b" (0x20)); | ||
92 | |||
93 | /* Turn off cursor emulation */ | ||
94 | asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); | ||
95 | |||
96 | /* Cursor is scan lines 6-7 */ | ||
97 | asm volatile(INT10 : : "a" (0x0100), "c" (0x0607)); | ||
98 | } | ||
99 | |||
100 | static void vga_set_14font(void) | ||
101 | { | ||
102 | /* Set 9x14 font - 80x28 on VGA */ | ||
103 | |||
104 | /* Set 9x14 font */ | ||
105 | asm volatile(INT10 : : "a" (0x1111), "b" (0)); | ||
106 | |||
107 | /* Turn off cursor emulation */ | ||
108 | asm volatile(INT10 : : "a" (0x1201), "b" (0x34)); | ||
109 | |||
110 | /* Cursor is scan lines 11-12 */ | ||
111 | asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c)); | ||
112 | } | ||
113 | |||
114 | static void vga_set_80x43(void) | ||
115 | { | ||
116 | /* Set 80x43 mode on VGA (not EGA) */ | ||
117 | |||
118 | /* Set 350 scans */ | ||
119 | asm volatile(INT10 : : "a" (0x1201), "b" (0x30)); | ||
120 | |||
121 | /* Reset video mode */ | ||
122 | asm volatile(INT10 : : "a" (0x0003)); | ||
123 | |||
124 | vga_set_8font(); | ||
125 | } | ||
126 | |||
127 | /* I/O address of the VGA CRTC */ | ||
128 | u16 vga_crtc(void) | ||
129 | { | ||
130 | return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4; | ||
131 | } | ||
132 | |||
133 | static void vga_set_480_scanlines(int end) | ||
134 | { | ||
135 | u16 crtc; | ||
136 | u8 csel; | ||
137 | |||
138 | crtc = vga_crtc(); | ||
139 | |||
140 | out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */ | ||
141 | out_idx(0x0b, crtc, 0x06); /* Vertical total */ | ||
142 | out_idx(0x3e, crtc, 0x07); /* Vertical overflow */ | ||
143 | out_idx(0xea, crtc, 0x10); /* Vertical sync start */ | ||
144 | out_idx(end, crtc, 0x12); /* Vertical display end */ | ||
145 | out_idx(0xe7, crtc, 0x15); /* Vertical blank start */ | ||
146 | out_idx(0x04, crtc, 0x16); /* Vertical blank end */ | ||
147 | csel = inb(0x3cc); | ||
148 | csel &= 0x0d; | ||
149 | csel |= 0xe2; | ||
150 | outb(csel, 0x3cc); | ||
151 | } | ||
152 | |||
153 | static void vga_set_80x30(void) | ||
154 | { | ||
155 | vga_set_480_scanlines(0xdf); | ||
156 | } | ||
157 | |||
158 | static void vga_set_80x34(void) | ||
159 | { | ||
160 | vga_set_14font(); | ||
161 | vga_set_480_scanlines(0xdb); | ||
162 | } | ||
163 | |||
164 | static void vga_set_80x60(void) | ||
165 | { | ||
166 | vga_set_8font(); | ||
167 | vga_set_480_scanlines(0xdf); | ||
168 | } | ||
169 | |||
170 | static int vga_set_mode(struct mode_info *mode) | ||
171 | { | ||
172 | /* Set the basic mode */ | ||
173 | vga_set_basic_mode(); | ||
174 | |||
175 | /* Override a possibly broken BIOS */ | ||
176 | force_x = mode->x; | ||
177 | force_y = mode->y; | ||
178 | |||
179 | switch (mode->mode) { | ||
180 | case VIDEO_80x25: | ||
181 | break; | ||
182 | case VIDEO_8POINT: | ||
183 | vga_set_8font(); | ||
184 | break; | ||
185 | case VIDEO_80x43: | ||
186 | vga_set_80x43(); | ||
187 | break; | ||
188 | case VIDEO_80x28: | ||
189 | vga_set_14font(); | ||
190 | break; | ||
191 | case VIDEO_80x30: | ||
192 | vga_set_80x30(); | ||
193 | break; | ||
194 | case VIDEO_80x34: | ||
195 | vga_set_80x34(); | ||
196 | break; | ||
197 | case VIDEO_80x60: | ||
198 | vga_set_80x60(); | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Note: this probe includes basic information required by all | ||
207 | * systems. It should be executed first, by making sure | ||
208 | * video-vga.c is listed first in the Makefile. | ||
209 | */ | ||
210 | static int vga_probe(void) | ||
211 | { | ||
212 | static const char *card_name[] = { | ||
213 | "CGA/MDA/HGC", "EGA", "VGA" | ||
214 | }; | ||
215 | static struct mode_info *mode_lists[] = { | ||
216 | cga_modes, | ||
217 | ega_modes, | ||
218 | vga_modes, | ||
219 | }; | ||
220 | static int mode_count[] = { | ||
221 | sizeof(cga_modes)/sizeof(struct mode_info), | ||
222 | sizeof(ega_modes)/sizeof(struct mode_info), | ||
223 | sizeof(vga_modes)/sizeof(struct mode_info), | ||
224 | }; | ||
225 | u8 vga_flag; | ||
226 | |||
227 | asm(INT10 | ||
228 | : "=b" (boot_params.screen_info.orig_video_ega_bx) | ||
229 | : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ | ||
230 | : "ecx", "edx", "esi", "edi"); | ||
231 | |||
232 | /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ | ||
233 | if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) { | ||
234 | /* EGA/VGA */ | ||
235 | asm(INT10 | ||
236 | : "=a" (vga_flag) | ||
237 | : "a" (0x1a00) | ||
238 | : "ebx", "ecx", "edx", "esi", "edi"); | ||
239 | |||
240 | if (vga_flag == 0x1a) { | ||
241 | adapter = ADAPTER_VGA; | ||
242 | boot_params.screen_info.orig_video_isVGA = 1; | ||
243 | } else { | ||
244 | adapter = ADAPTER_EGA; | ||
245 | } | ||
246 | } else { | ||
247 | adapter = ADAPTER_CGA; | ||
248 | } | ||
249 | |||
250 | video_vga.modes = mode_lists[adapter]; | ||
251 | video_vga.card_name = card_name[adapter]; | ||
252 | return mode_count[adapter]; | ||
253 | } | ||
254 | |||
255 | __videocard video_vga = | ||
256 | { | ||
257 | .card_name = "VGA", | ||
258 | .probe = vga_probe, | ||
259 | .set_mode = vga_set_mode, | ||
260 | }; | ||
diff --git a/arch/i386/boot/video.c b/arch/i386/boot/video.c new file mode 100644 index 000000000000..3bb3573cd6a1 --- /dev/null +++ b/arch/i386/boot/video.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
4 | * Copyright 2007 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.c | ||
13 | * | ||
14 | * Select video mode | ||
15 | */ | ||
16 | |||
17 | #include "boot.h" | ||
18 | #include "video.h" | ||
19 | #include "vesa.h" | ||
20 | |||
21 | /* | ||
22 | * Mode list variables | ||
23 | */ | ||
24 | static struct card_info cards[]; /* List of cards to probe for */ | ||
25 | |||
26 | /* | ||
27 | * Common variables | ||
28 | */ | ||
29 | int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */ | ||
30 | u16 video_segment; | ||
31 | int force_x, force_y; /* Don't query the BIOS for cols/rows */ | ||
32 | |||
33 | int do_restore = 0; /* Screen contents changed during mode flip */ | ||
34 | int graphic_mode; /* Graphic mode with linear frame buffer */ | ||
35 | |||
36 | static void store_cursor_position(void) | ||
37 | { | ||
38 | u16 curpos; | ||
39 | u16 ax, bx; | ||
40 | |||
41 | ax = 0x0300; | ||
42 | bx = 0; | ||
43 | asm(INT10 | ||
44 | : "=d" (curpos), "+a" (ax), "+b" (bx) | ||
45 | : : "ecx", "esi", "edi"); | ||
46 | |||
47 | boot_params.screen_info.orig_x = curpos; | ||
48 | boot_params.screen_info.orig_y = curpos >> 8; | ||
49 | } | ||
50 | |||
51 | static void store_video_mode(void) | ||
52 | { | ||
53 | u16 ax, page; | ||
54 | |||
55 | /* N.B.: the saving of the video page here is a bit silly, | ||
56 | since we pretty much assume page 0 everywhere. */ | ||
57 | ax = 0x0f00; | ||
58 | asm(INT10 | ||
59 | : "+a" (ax), "=b" (page) | ||
60 | : : "ecx", "edx", "esi", "edi"); | ||
61 | |||
62 | /* Not all BIOSes are clean with respect to the top bit */ | ||
63 | boot_params.screen_info.orig_video_mode = ax & 0x7f; | ||
64 | boot_params.screen_info.orig_video_page = page; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Store the video mode parameters for later usage by the kernel. | ||
69 | * This is done by asking the BIOS except for the rows/columns | ||
70 | * parameters in the default 80x25 mode -- these are set directly, | ||
71 | * because some very obscure BIOSes supply insane values. | ||
72 | */ | ||
73 | static void store_mode_params(void) | ||
74 | { | ||
75 | u16 font_size; | ||
76 | int x, y; | ||
77 | |||
78 | /* For graphics mode, it is up to the mode-setting driver | ||
79 | (currently only video-vesa.c) to store the parameters */ | ||
80 | if (graphic_mode) | ||
81 | return; | ||
82 | |||
83 | store_cursor_position(); | ||
84 | store_video_mode(); | ||
85 | |||
86 | if (boot_params.screen_info.orig_video_mode == 0x07) { | ||
87 | /* MDA, HGC, or VGA in monochrome mode */ | ||
88 | video_segment = 0xb000; | ||
89 | } else { | ||
90 | /* CGA, EGA, VGA and so forth */ | ||
91 | video_segment = 0xb800; | ||
92 | } | ||
93 | |||
94 | set_fs(0); | ||
95 | font_size = rdfs16(0x485); /* Font size, BIOS area */ | ||
96 | boot_params.screen_info.orig_video_points = font_size; | ||
97 | |||
98 | x = rdfs16(0x44a); | ||
99 | y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1; | ||
100 | |||
101 | if (force_x) | ||
102 | x = force_x; | ||
103 | if (force_y) | ||
104 | y = force_y; | ||
105 | |||
106 | boot_params.screen_info.orig_video_cols = x; | ||
107 | boot_params.screen_info.orig_video_lines = y; | ||
108 | } | ||
109 | |||
110 | /* Probe the video drivers and have them generate their mode lists. */ | ||
111 | static void probe_cards(int unsafe) | ||
112 | { | ||
113 | struct card_info *card; | ||
114 | static u8 probed[2]; | ||
115 | |||
116 | if (probed[unsafe]) | ||
117 | return; | ||
118 | |||
119 | probed[unsafe] = 1; | ||
120 | |||
121 | for (card = video_cards; card < video_cards_end; card++) { | ||
122 | if (card->unsafe == unsafe) { | ||
123 | if (card->probe) | ||
124 | card->nmodes = card->probe(); | ||
125 | else | ||
126 | card->nmodes = 0; | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | /* Test if a mode is defined */ | ||
132 | int mode_defined(u16 mode) | ||
133 | { | ||
134 | struct card_info *card; | ||
135 | struct mode_info *mi; | ||
136 | int i; | ||
137 | |||
138 | for (card = video_cards; card < video_cards_end; card++) { | ||
139 | mi = card->modes; | ||
140 | for (i = 0; i < card->nmodes; i++, mi++) { | ||
141 | if (mi->mode == mode) | ||
142 | return 1; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* Set mode (without recalc) */ | ||
150 | static int raw_set_mode(u16 mode) | ||
151 | { | ||
152 | int nmode, i; | ||
153 | struct card_info *card; | ||
154 | struct mode_info *mi; | ||
155 | |||
156 | /* Drop the recalc bit if set */ | ||
157 | mode &= ~VIDEO_RECALC; | ||
158 | |||
159 | /* Scan for mode based on fixed ID, position, or resolution */ | ||
160 | nmode = 0; | ||
161 | for (card = video_cards; card < video_cards_end; card++) { | ||
162 | mi = card->modes; | ||
163 | for (i = 0; i < card->nmodes; i++, mi++) { | ||
164 | int visible = mi->x || mi->y; | ||
165 | |||
166 | if ((mode == nmode && visible) || | ||
167 | mode == mi->mode || | ||
168 | mode == (mi->y << 8)+mi->x) | ||
169 | return card->set_mode(mi); | ||
170 | |||
171 | if (visible) | ||
172 | nmode++; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | /* Nothing found? Is it an "exceptional" (unprobed) mode? */ | ||
177 | for (card = video_cards; card < video_cards_end; card++) { | ||
178 | if (mode >= card->xmode_first && | ||
179 | mode < card->xmode_first+card->xmode_n) { | ||
180 | struct mode_info mix; | ||
181 | mix.mode = mode; | ||
182 | mix.x = mix.y = 0; | ||
183 | return card->set_mode(&mix); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | /* Otherwise, failure... */ | ||
188 | return -1; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * Recalculate the vertical video cutoff (hack!) | ||
193 | */ | ||
194 | static void vga_recalc_vertical(void) | ||
195 | { | ||
196 | unsigned int font_size, rows; | ||
197 | u16 crtc; | ||
198 | u8 ov; | ||
199 | |||
200 | set_fs(0); | ||
201 | font_size = rdfs8(0x485); /* BIOS: font size (pixels) */ | ||
202 | rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */ | ||
203 | |||
204 | rows *= font_size; /* Visible scan lines */ | ||
205 | rows--; /* ... minus one */ | ||
206 | |||
207 | crtc = vga_crtc(); | ||
208 | |||
209 | out_idx((u8)rows, crtc, 0x12); /* Lower height register */ | ||
210 | ov = in_idx(crtc, 0x07); /* Overflow register */ | ||
211 | ov &= 0xbd; | ||
212 | ov |= (rows >> (8-1)) & 0x02; | ||
213 | ov |= (rows >> (9-6)) & 0x40; | ||
214 | out_idx(ov, crtc, 0x07); | ||
215 | } | ||
216 | |||
217 | /* Set mode (with recalc if specified) */ | ||
218 | static int set_mode(u16 mode) | ||
219 | { | ||
220 | int rv; | ||
221 | |||
222 | /* Very special mode numbers... */ | ||
223 | if (mode == VIDEO_CURRENT_MODE) | ||
224 | return 0; /* Nothing to do... */ | ||
225 | else if (mode == NORMAL_VGA) | ||
226 | mode = VIDEO_80x25; | ||
227 | else if (mode == EXTENDED_VGA) | ||
228 | mode = VIDEO_8POINT; | ||
229 | |||
230 | rv = raw_set_mode(mode); | ||
231 | if (rv) | ||
232 | return rv; | ||
233 | |||
234 | if (mode & VIDEO_RECALC) | ||
235 | vga_recalc_vertical(); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static unsigned int get_entry(void) | ||
241 | { | ||
242 | char entry_buf[4]; | ||
243 | int i, len = 0; | ||
244 | int key; | ||
245 | unsigned int v; | ||
246 | |||
247 | do { | ||
248 | key = getchar(); | ||
249 | |||
250 | if (key == '\b') { | ||
251 | if (len > 0) { | ||
252 | puts("\b \b"); | ||
253 | len--; | ||
254 | } | ||
255 | } else if ((key >= '0' && key <= '9') || | ||
256 | (key >= 'A' && key <= 'Z') || | ||
257 | (key >= 'a' && key <= 'z')) { | ||
258 | if (len < sizeof entry_buf) { | ||
259 | entry_buf[len++] = key; | ||
260 | putchar(key); | ||
261 | } | ||
262 | } | ||
263 | } while (key != '\r'); | ||
264 | putchar('\n'); | ||
265 | |||
266 | if (len == 0) | ||
267 | return VIDEO_CURRENT_MODE; /* Default */ | ||
268 | |||
269 | v = 0; | ||
270 | for (i = 0; i < len; i++) { | ||
271 | v <<= 4; | ||
272 | key = entry_buf[i] | 0x20; | ||
273 | v += (key > '9') ? key-'a'+10 : key-'0'; | ||
274 | } | ||
275 | |||
276 | return v; | ||
277 | } | ||
278 | |||
279 | static void display_menu(void) | ||
280 | { | ||
281 | struct card_info *card; | ||
282 | struct mode_info *mi; | ||
283 | char ch; | ||
284 | int i; | ||
285 | |||
286 | puts("Mode: COLSxROWS:\n"); | ||
287 | |||
288 | ch = '0'; | ||
289 | for (card = video_cards; card < video_cards_end; card++) { | ||
290 | mi = card->modes; | ||
291 | for (i = 0; i < card->nmodes; i++, mi++) { | ||
292 | int visible = mi->x && mi->y; | ||
293 | u16 mode_id = mi->mode ? mi->mode : | ||
294 | (mi->y << 8)+mi->x; | ||
295 | |||
296 | if (!visible) | ||
297 | continue; /* Hidden mode */ | ||
298 | |||
299 | printf("%c %04X %3dx%-3d %s\n", | ||
300 | ch, mode_id, mi->x, mi->y, card->card_name); | ||
301 | |||
302 | if (ch == '9') | ||
303 | ch = 'a'; | ||
304 | else if (ch == 'z' || ch == ' ') | ||
305 | ch = ' '; /* Out of keys... */ | ||
306 | else | ||
307 | ch++; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | #define H(x) ((x)-'a'+10) | ||
313 | #define SCAN ((H('s')<<12)+(H('c')<<8)+(H('a')<<4)+H('n')) | ||
314 | |||
315 | static unsigned int mode_menu(void) | ||
316 | { | ||
317 | int key; | ||
318 | unsigned int sel; | ||
319 | |||
320 | puts("Press <ENTER> to see video modes available, " | ||
321 | "<SPACE> to continue, or wait 30 sec\n"); | ||
322 | |||
323 | kbd_flush(); | ||
324 | while (1) { | ||
325 | key = getchar_timeout(); | ||
326 | if (key == ' ' || key == 0) | ||
327 | return VIDEO_CURRENT_MODE; /* Default */ | ||
328 | if (key == '\r') | ||
329 | break; | ||
330 | putchar('\a'); /* Beep! */ | ||
331 | } | ||
332 | |||
333 | |||
334 | for (;;) { | ||
335 | display_menu(); | ||
336 | |||
337 | puts("Enter a video mode or \"scan\" to scan for " | ||
338 | "additional modes: "); | ||
339 | sel = get_entry(); | ||
340 | if (sel != SCAN) | ||
341 | return sel; | ||
342 | |||
343 | probe_cards(1); | ||
344 | } | ||
345 | } | ||
346 | |||
347 | #ifdef CONFIG_VIDEO_RETAIN | ||
348 | /* Save screen content to the heap */ | ||
349 | struct saved_screen { | ||
350 | int x, y; | ||
351 | int curx, cury; | ||
352 | u16 *data; | ||
353 | } saved; | ||
354 | |||
355 | static void save_screen(void) | ||
356 | { | ||
357 | /* Should be called after store_mode_params() */ | ||
358 | saved.x = boot_params.screen_info.orig_video_cols; | ||
359 | saved.y = boot_params.screen_info.orig_video_lines; | ||
360 | saved.curx = boot_params.screen_info.orig_x; | ||
361 | saved.cury = boot_params.screen_info.orig_y; | ||
362 | |||
363 | if (heap_free() < saved.x*saved.y*sizeof(u16)+512) | ||
364 | return; /* Not enough heap to save the screen */ | ||
365 | |||
366 | saved.data = GET_HEAP(u16, saved.x*saved.y); | ||
367 | |||
368 | set_fs(video_segment); | ||
369 | copy_from_fs(saved.data, 0, saved.x*saved.y*sizeof(u16)); | ||
370 | } | ||
371 | |||
372 | static void restore_screen(void) | ||
373 | { | ||
374 | /* Should be called after store_mode_params() */ | ||
375 | int xs = boot_params.screen_info.orig_video_cols; | ||
376 | int ys = boot_params.screen_info.orig_video_lines; | ||
377 | int y; | ||
378 | addr_t dst = 0; | ||
379 | u16 *src = saved.data; | ||
380 | u16 ax, bx, dx; | ||
381 | |||
382 | if (graphic_mode) | ||
383 | return; /* Can't restore onto a graphic mode */ | ||
384 | |||
385 | if (!src) | ||
386 | return; /* No saved screen contents */ | ||
387 | |||
388 | /* Restore screen contents */ | ||
389 | |||
390 | set_fs(video_segment); | ||
391 | for (y = 0; y < ys; y++) { | ||
392 | int npad; | ||
393 | |||
394 | if (y < saved.y) { | ||
395 | int copy = (xs < saved.x) ? xs : saved.x; | ||
396 | copy_to_fs(dst, src, copy*sizeof(u16)); | ||
397 | dst += copy*sizeof(u16); | ||
398 | src += saved.x; | ||
399 | npad = (xs < saved.x) ? 0 : xs-saved.x; | ||
400 | } else { | ||
401 | npad = xs; | ||
402 | } | ||
403 | |||
404 | /* Writes "npad" blank characters to | ||
405 | video_segment:dst and advances dst */ | ||
406 | asm volatile("pushw %%es ; " | ||
407 | "movw %2,%%es ; " | ||
408 | "shrw %%cx ; " | ||
409 | "jnc 1f ; " | ||
410 | "stosw \n\t" | ||
411 | "1: rep;stosl ; " | ||
412 | "popw %%es" | ||
413 | : "+D" (dst), "+c" (npad) | ||
414 | : "bdSm" (video_segment), | ||
415 | "a" (0x07200720)); | ||
416 | } | ||
417 | |||
418 | /* Restore cursor position */ | ||
419 | ax = 0x0200; /* Set cursor position */ | ||
420 | bx = 0; /* Page number (<< 8) */ | ||
421 | dx = (saved.cury << 8)+saved.curx; | ||
422 | asm volatile(INT10 | ||
423 | : "+a" (ax), "+b" (bx), "+d" (dx) | ||
424 | : : "ecx", "esi", "edi"); | ||
425 | } | ||
426 | #else | ||
427 | #define save_screen() ((void)0) | ||
428 | #define restore_screen() ((void)0) | ||
429 | #endif | ||
430 | |||
431 | void set_video(void) | ||
432 | { | ||
433 | u16 mode = boot_params.hdr.vid_mode; | ||
434 | |||
435 | RESET_HEAP(); | ||
436 | |||
437 | store_mode_params(); | ||
438 | save_screen(); | ||
439 | probe_cards(0); | ||
440 | |||
441 | for (;;) { | ||
442 | if (mode == ASK_VGA) | ||
443 | mode = mode_menu(); | ||
444 | |||
445 | if (!set_mode(mode)) | ||
446 | break; | ||
447 | |||
448 | printf("Undefined video mode number: %x\n", mode); | ||
449 | mode = ASK_VGA; | ||
450 | } | ||
451 | vesa_store_edid(); | ||
452 | store_mode_params(); | ||
453 | |||
454 | if (do_restore) | ||
455 | restore_screen(); | ||
456 | } | ||
diff --git a/arch/i386/boot/video.h b/arch/i386/boot/video.h new file mode 100644 index 000000000000..29eca1710b2c --- /dev/null +++ b/arch/i386/boot/video.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* -*- linux-c -*- ------------------------------------------------------- * | ||
2 | * | ||
3 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
4 | * Copyright 2007 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.h | ||
13 | * | ||
14 | * Header file for the real-mode video probing code | ||
15 | */ | ||
16 | |||
17 | #ifndef BOOT_VIDEO_H | ||
18 | #define BOOT_VIDEO_H | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | |||
22 | /* Enable autodetection of SVGA adapters and modes. */ | ||
23 | #undef CONFIG_VIDEO_SVGA | ||
24 | |||
25 | /* Enable autodetection of VESA modes */ | ||
26 | #define CONFIG_VIDEO_VESA | ||
27 | |||
28 | /* Retain screen contents when switching modes */ | ||
29 | #define CONFIG_VIDEO_RETAIN | ||
30 | |||
31 | /* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */ | ||
32 | #undef CONFIG_VIDEO_400_HACK | ||
33 | |||
34 | /* This code uses an extended set of video mode numbers. These include: | ||
35 | * Aliases for standard modes | ||
36 | * NORMAL_VGA (-1) | ||
37 | * EXTENDED_VGA (-2) | ||
38 | * ASK_VGA (-3) | ||
39 | * Video modes numbered by menu position -- NOT RECOMMENDED because of lack | ||
40 | * of compatibility when extending the table. These are between 0x00 and 0xff. | ||
41 | */ | ||
42 | #define VIDEO_FIRST_MENU 0x0000 | ||
43 | |||
44 | /* Standard BIOS video modes (BIOS number + 0x0100) */ | ||
45 | #define VIDEO_FIRST_BIOS 0x0100 | ||
46 | |||
47 | /* VESA BIOS video modes (VESA number + 0x0200) */ | ||
48 | #define VIDEO_FIRST_VESA 0x0200 | ||
49 | |||
50 | /* Video7 special modes (BIOS number + 0x0900) */ | ||
51 | #define VIDEO_FIRST_V7 0x0900 | ||
52 | |||
53 | /* Special video modes */ | ||
54 | #define VIDEO_FIRST_SPECIAL 0x0f00 | ||
55 | #define VIDEO_80x25 0x0f00 | ||
56 | #define VIDEO_8POINT 0x0f01 | ||
57 | #define VIDEO_80x43 0x0f02 | ||
58 | #define VIDEO_80x28 0x0f03 | ||
59 | #define VIDEO_CURRENT_MODE 0x0f04 | ||
60 | #define VIDEO_80x30 0x0f05 | ||
61 | #define VIDEO_80x34 0x0f06 | ||
62 | #define VIDEO_80x60 0x0f07 | ||
63 | #define VIDEO_GFX_HACK 0x0f08 | ||
64 | #define VIDEO_LAST_SPECIAL 0x0f09 | ||
65 | |||
66 | /* Video modes given by resolution */ | ||
67 | #define VIDEO_FIRST_RESOLUTION 0x1000 | ||
68 | |||
69 | /* The "recalculate timings" flag */ | ||
70 | #define VIDEO_RECALC 0x8000 | ||
71 | |||
72 | /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ | ||
73 | #ifdef CONFIG_VIDEO_RETAIN | ||
74 | void store_screen(void); | ||
75 | #define DO_STORE() store_screen() | ||
76 | #else | ||
77 | #define DO_STORE() ((void)0) | ||
78 | #endif /* CONFIG_VIDEO_RETAIN */ | ||
79 | |||
80 | /* | ||
81 | * Mode table structures | ||
82 | */ | ||
83 | |||
84 | struct mode_info { | ||
85 | u16 mode; /* Mode number (vga= style) */ | ||
86 | u8 x, y; /* Width, height */ | ||
87 | }; | ||
88 | |||
89 | struct card_info { | ||
90 | const char *card_name; | ||
91 | int (*set_mode)(struct mode_info *mode); | ||
92 | int (*probe)(void); | ||
93 | struct mode_info *modes; | ||
94 | int nmodes; /* Number of probed modes so far */ | ||
95 | int unsafe; /* Probing is unsafe, only do after "scan" */ | ||
96 | u16 xmode_first; /* Unprobed modes to try to call anyway */ | ||
97 | u16 xmode_n; /* Size of unprobed mode range */ | ||
98 | }; | ||
99 | |||
100 | #define __videocard struct card_info __attribute__((section(".videocards"))) | ||
101 | extern struct card_info video_cards[], video_cards_end[]; | ||
102 | |||
103 | int mode_defined(u16 mode); /* video.c */ | ||
104 | |||
105 | /* Basic video information */ | ||
106 | #define ADAPTER_CGA 0 /* CGA/MDA/HGC */ | ||
107 | #define ADAPTER_EGA 1 | ||
108 | #define ADAPTER_VGA 2 | ||
109 | |||
110 | extern int adapter; | ||
111 | extern u16 video_segment; | ||
112 | extern int force_x, force_y; /* Don't query the BIOS for cols/rows */ | ||
113 | extern int do_restore; /* Restore screen contents */ | ||
114 | extern int graphic_mode; /* Graphics mode with linear frame buffer */ | ||
115 | |||
116 | /* | ||
117 | * int $0x10 is notorious for touching registers it shouldn't. | ||
118 | * gcc doesn't like %ebp being clobbered, so define it as a push/pop | ||
119 | * sequence here. | ||
120 | */ | ||
121 | #define INT10 "pushl %%ebp; int $0x10; popl %%ebp" | ||
122 | |||
123 | /* Accessing VGA indexed registers */ | ||
124 | static inline u8 in_idx(u16 port, u8 index) | ||
125 | { | ||
126 | outb(index, port); | ||
127 | return inb(port+1); | ||
128 | } | ||
129 | |||
130 | static inline void out_idx(u8 v, u16 port, u8 index) | ||
131 | { | ||
132 | outw(index+(v << 8), port); | ||
133 | } | ||
134 | |||
135 | /* Writes a value to an indexed port and then reads the port again */ | ||
136 | static inline u8 tst_idx(u8 v, u16 port, u8 index) | ||
137 | { | ||
138 | out_idx(port, index, v); | ||
139 | return in_idx(port, index); | ||
140 | } | ||
141 | |||
142 | /* Get the I/O port of the VGA CRTC */ | ||
143 | u16 vga_crtc(void); /* video-vga.c */ | ||
144 | |||
145 | #endif /* BOOT_VIDEO_H */ | ||