Merge branch 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / arch / x86 / boot / video-vga.c
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 volatile(INT10
51                              : : "a" (0x1202), "b" (0x0030)
52                              : "ecx", "edx", "esi", "edi");
53         }
54 #endif
55
56         ax = 0x0f00;
57         asm volatile(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         ax = mode;
77         asm volatile(INT10
78                      : "+a" (ax)
79                      : : "ebx", "ecx", "edx", "esi", "edi");
80         do_restore = 1;
81         return mode;
82 }
83
84 static void vga_set_8font(void)
85 {
86         /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
87
88         /* Set 8x8 font */
89         asm volatile(INT10 : : "a" (0x1112), "b" (0));
90
91         /* Use alternate print screen */
92         asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
93
94         /* Turn off cursor emulation */
95         asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
96
97         /* Cursor is scan lines 6-7 */
98         asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
99 }
100
101 static void vga_set_14font(void)
102 {
103         /* Set 9x14 font - 80x28 on VGA */
104
105         /* Set 9x14 font */
106         asm volatile(INT10 : : "a" (0x1111), "b" (0));
107
108         /* Turn off cursor emulation */
109         asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
110
111         /* Cursor is scan lines 11-12 */
112         asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
113 }
114
115 static void vga_set_80x43(void)
116 {
117         /* Set 80x43 mode on VGA (not EGA) */
118
119         /* Set 350 scans */
120         asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
121
122         /* Reset video mode */
123         asm volatile(INT10 : : "a" (0x0003));
124
125         vga_set_8font();
126 }
127
128 /* I/O address of the VGA CRTC */
129 u16 vga_crtc(void)
130 {
131         return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
132 }
133
134 static void vga_set_480_scanlines(int end)
135 {
136         u16 crtc;
137         u8  csel;
138
139         crtc = vga_crtc();
140
141         out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
142         out_idx(0x0b, crtc, 0x06); /* Vertical total */
143         out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
144         out_idx(0xea, crtc, 0x10); /* Vertical sync start */
145         out_idx(end, crtc, 0x12); /* Vertical display end */
146         out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
147         out_idx(0x04, crtc, 0x16); /* Vertical blank end */
148         csel = inb(0x3cc);
149         csel &= 0x0d;
150         csel |= 0xe2;
151         outb(csel, 0x3cc);
152 }
153
154 static void vga_set_80x30(void)
155 {
156         vga_set_480_scanlines(0xdf);
157 }
158
159 static void vga_set_80x34(void)
160 {
161         vga_set_14font();
162         vga_set_480_scanlines(0xdb);
163 }
164
165 static void vga_set_80x60(void)
166 {
167         vga_set_8font();
168         vga_set_480_scanlines(0xdf);
169 }
170
171 static int vga_set_mode(struct mode_info *mode)
172 {
173         /* Set the basic mode */
174         vga_set_basic_mode();
175
176         /* Override a possibly broken BIOS */
177         force_x = mode->x;
178         force_y = mode->y;
179
180         switch (mode->mode) {
181         case VIDEO_80x25:
182                 break;
183         case VIDEO_8POINT:
184                 vga_set_8font();
185                 break;
186         case VIDEO_80x43:
187                 vga_set_80x43();
188                 break;
189         case VIDEO_80x28:
190                 vga_set_14font();
191                 break;
192         case VIDEO_80x30:
193                 vga_set_80x30();
194                 break;
195         case VIDEO_80x34:
196                 vga_set_80x34();
197                 break;
198         case VIDEO_80x60:
199                 vga_set_80x60();
200                 break;
201         }
202
203         return 0;
204 }
205
206 /*
207  * Note: this probe includes basic information required by all
208  * systems.  It should be executed first, by making sure
209  * video-vga.c is listed first in the Makefile.
210  */
211 static int vga_probe(void)
212 {
213         static const char *card_name[] = {
214                 "CGA/MDA/HGC", "EGA", "VGA"
215         };
216         static struct mode_info *mode_lists[] = {
217                 cga_modes,
218                 ega_modes,
219                 vga_modes,
220         };
221         static int mode_count[] = {
222                 sizeof(cga_modes)/sizeof(struct mode_info),
223                 sizeof(ega_modes)/sizeof(struct mode_info),
224                 sizeof(vga_modes)/sizeof(struct mode_info),
225         };
226         u8 vga_flag;
227
228         asm(INT10
229             : "=b" (boot_params.screen_info.orig_video_ega_bx)
230             : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
231             : "ecx", "edx", "esi", "edi");
232
233         /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
234         if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) {
235                 /* EGA/VGA */
236                 asm(INT10
237                     : "=a" (vga_flag)
238                     : "a" (0x1a00)
239                     : "ebx", "ecx", "edx", "esi", "edi");
240
241                 if (vga_flag == 0x1a) {
242                         adapter = ADAPTER_VGA;
243                         boot_params.screen_info.orig_video_isVGA = 1;
244                 } else {
245                         adapter = ADAPTER_EGA;
246                 }
247         } else {
248                 adapter = ADAPTER_CGA;
249         }
250
251         video_vga.modes = mode_lists[adapter];
252         video_vga.card_name = card_name[adapter];
253         return mode_count[adapter];
254 }
255
256 __videocard video_vga =
257 {
258         .card_name      = "VGA",
259         .probe          = vga_probe,
260         .set_mode       = vga_set_mode,
261 };