aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/boot/vesa.h79
-rw-r--r--arch/i386/boot/video-bios.c125
-rw-r--r--arch/i386/boot/video-vesa.c284
-rw-r--r--arch/i386/boot/video-vga.c260
-rw-r--r--arch/i386/boot/video.c456
-rw-r--r--arch/i386/boot/video.h145
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
16typedef struct {
17 u16 off, seg;
18} far_ptr;
19
20/* VESA General Information table */
21struct 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
41struct 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 */
25static int set_bios_mode(u8 mode);
26
27static int bios_set_mode(struct mode_info *mi)
28{
29 return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS);
30}
31
32static 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
65static 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 */
22static struct vesa_general_info vginfo;
23static struct vesa_mode_info vminfo;
24
25__videocard video_vesa;
26
27static void vesa_store_mode_params_graphics(void);
28
29static 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
103static 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 */
155static 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 */
186static 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 */
206static 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 */
235void 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
20static 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
30static struct mode_info ega_modes[] = {
31 { VIDEO_80x25, 80, 25 },
32 { VIDEO_8POINT, 80, 43 },
33};
34
35static struct mode_info cga_modes[] = {
36 { VIDEO_80x25, 80, 25 },
37};
38
39__videocard video_vga;
40
41/* Set basic 80x25 mode */
42static 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
83static 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
100static 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
114static 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 */
128u16 vga_crtc(void)
129{
130 return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
131}
132
133static 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
153static void vga_set_80x30(void)
154{
155 vga_set_480_scanlines(0xdf);
156}
157
158static void vga_set_80x34(void)
159{
160 vga_set_14font();
161 vga_set_480_scanlines(0xdb);
162}
163
164static void vga_set_80x60(void)
165{
166 vga_set_8font();
167 vga_set_480_scanlines(0xdf);
168}
169
170static 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 */
210static 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 */
24static struct card_info cards[]; /* List of cards to probe for */
25
26/*
27 * Common variables
28 */
29int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
30u16 video_segment;
31int force_x, force_y; /* Don't query the BIOS for cols/rows */
32
33int do_restore = 0; /* Screen contents changed during mode flip */
34int graphic_mode; /* Graphic mode with linear frame buffer */
35
36static 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
51static 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 */
73static 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. */
111static 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 */
132int 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) */
150static 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 */
194static 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) */
218static 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
240static 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
279static 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
315static 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 */
349struct saved_screen {
350 int x, y;
351 int curx, cury;
352 u16 *data;
353} saved;
354
355static 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
372static 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
431void 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
74void 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
84struct mode_info {
85 u16 mode; /* Mode number (vga= style) */
86 u8 x, y; /* Width, height */
87};
88
89struct 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")))
101extern struct card_info video_cards[], video_cards_end[];
102
103int 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
110extern int adapter;
111extern u16 video_segment;
112extern int force_x, force_y; /* Don't query the BIOS for cols/rows */
113extern int do_restore; /* Restore screen contents */
114extern 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 */
124static inline u8 in_idx(u16 port, u8 index)
125{
126 outb(index, port);
127 return inb(port+1);
128}
129
130static 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 */
136static 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 */
143u16 vga_crtc(void); /* video-vga.c */
144
145#endif /* BOOT_VIDEO_H */