Merge branch 'next' into for-linus
[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  * Common all-VGA modes
13  */
14
15 #include "boot.h"
16 #include "video.h"
17
18 static struct mode_info vga_modes[] = {
19         { VIDEO_80x25,  80, 25, 0 },
20         { VIDEO_8POINT, 80, 50, 0 },
21         { VIDEO_80x43,  80, 43, 0 },
22         { VIDEO_80x28,  80, 28, 0 },
23         { VIDEO_80x30,  80, 30, 0 },
24         { VIDEO_80x34,  80, 34, 0 },
25         { VIDEO_80x60,  80, 60, 0 },
26 };
27
28 static struct mode_info ega_modes[] = {
29         { VIDEO_80x25,  80, 25, 0 },
30         { VIDEO_8POINT, 80, 43, 0 },
31 };
32
33 static struct mode_info cga_modes[] = {
34         { VIDEO_80x25,  80, 25, 0 },
35 };
36
37 static __videocard video_vga;
38
39 /* Set basic 80x25 mode */
40 static u8 vga_set_basic_mode(void)
41 {
42         u16 ax;
43         u8 rows;
44         u8 mode;
45
46 #ifdef CONFIG_VIDEO_400_HACK
47         if (adapter >= ADAPTER_VGA) {
48                 asm volatile(INT10
49                              : : "a" (0x1202), "b" (0x0030)
50                              : "ecx", "edx", "esi", "edi");
51         }
52 #endif
53
54         ax = 0x0f00;
55         asm volatile(INT10
56                      : "+a" (ax)
57                      : : "ebx", "ecx", "edx", "esi", "edi");
58
59         mode = (u8)ax;
60
61         set_fs(0);
62         rows = rdfs8(0x484);    /* rows minus one */
63
64 #ifndef CONFIG_VIDEO_400_HACK
65         if ((ax == 0x5003 || ax == 0x5007) &&
66             (rows == 0 || rows == 24))
67                 return mode;
68 #endif
69
70         if (mode != 3 && mode != 7)
71                 mode = 3;
72
73         /* Set the mode */
74         ax = mode;
75         asm volatile(INT10
76                      : "+a" (ax)
77                      : : "ebx", "ecx", "edx", "esi", "edi");
78         do_restore = 1;
79         return mode;
80 }
81
82 static void vga_set_8font(void)
83 {
84         /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
85
86         /* Set 8x8 font */
87         asm volatile(INT10 : : "a" (0x1112), "b" (0));
88
89         /* Use alternate print screen */
90         asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
91
92         /* Turn off cursor emulation */
93         asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
94
95         /* Cursor is scan lines 6-7 */
96         asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
97 }
98
99 static void vga_set_14font(void)
100 {
101         /* Set 9x14 font - 80x28 on VGA */
102
103         /* Set 9x14 font */
104         asm volatile(INT10 : : "a" (0x1111), "b" (0));
105
106         /* Turn off cursor emulation */
107         asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
108
109         /* Cursor is scan lines 11-12 */
110         asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
111 }
112
113 static void vga_set_80x43(void)
114 {
115         /* Set 80x43 mode on VGA (not EGA) */
116
117         /* Set 350 scans */
118         asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
119
120         /* Reset video mode */
121         asm volatile(INT10 : : "a" (0x0003));
122
123         vga_set_8font();
124 }
125
126 /* I/O address of the VGA CRTC */
127 u16 vga_crtc(void)
128 {
129         return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
130 }
131
132 static void vga_set_480_scanlines(int end)
133 {
134         u16 crtc;
135         u8  csel;
136
137         crtc = vga_crtc();
138
139         out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
140         out_idx(0x0b, crtc, 0x06); /* Vertical total */
141         out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
142         out_idx(0xea, crtc, 0x10); /* Vertical sync start */
143         out_idx(end, crtc, 0x12); /* Vertical display end */
144         out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
145         out_idx(0x04, crtc, 0x16); /* Vertical blank end */
146         csel = inb(0x3cc);
147         csel &= 0x0d;
148         csel |= 0xe2;
149         outb(csel, 0x3cc);
150 }
151
152 static void vga_set_80x30(void)
153 {
154         vga_set_480_scanlines(0xdf);
155 }
156
157 static void vga_set_80x34(void)
158 {
159         vga_set_14font();
160         vga_set_480_scanlines(0xdb);
161 }
162
163 static void vga_set_80x60(void)
164 {
165         vga_set_8font();
166         vga_set_480_scanlines(0xdf);
167 }
168
169 static int vga_set_mode(struct mode_info *mode)
170 {
171         /* Set the basic mode */
172         vga_set_basic_mode();
173
174         /* Override a possibly broken BIOS */
175         force_x = mode->x;
176         force_y = mode->y;
177
178         switch (mode->mode) {
179         case VIDEO_80x25:
180                 break;
181         case VIDEO_8POINT:
182                 vga_set_8font();
183                 break;
184         case VIDEO_80x43:
185                 vga_set_80x43();
186                 break;
187         case VIDEO_80x28:
188                 vga_set_14font();
189                 break;
190         case VIDEO_80x30:
191                 vga_set_80x30();
192                 break;
193         case VIDEO_80x34:
194                 vga_set_80x34();
195                 break;
196         case VIDEO_80x60:
197                 vga_set_80x60();
198                 break;
199         }
200
201         return 0;
202 }
203
204 /*
205  * Note: this probe includes basic information required by all
206  * systems.  It should be executed first, by making sure
207  * video-vga.c is listed first in the Makefile.
208  */
209 static int vga_probe(void)
210 {
211         u16 ega_bx;
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" (ega_bx)
230             : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
231             : "ecx", "edx", "esi", "edi");
232
233 #ifndef _WAKEUP
234         boot_params.screen_info.orig_video_ega_bx = ega_bx;
235 #endif
236
237         /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
238         if ((u8)ega_bx != 0x10) {
239                 /* EGA/VGA */
240                 asm(INT10
241                     : "=a" (vga_flag)
242                     : "a" (0x1a00)
243                     : "ebx", "ecx", "edx", "esi", "edi");
244
245                 if (vga_flag == 0x1a) {
246                         adapter = ADAPTER_VGA;
247 #ifndef _WAKEUP
248                         boot_params.screen_info.orig_video_isVGA = 1;
249 #endif
250                 } else {
251                         adapter = ADAPTER_EGA;
252                 }
253         } else {
254                 adapter = ADAPTER_CGA;
255         }
256
257         video_vga.modes = mode_lists[adapter];
258         video_vga.card_name = card_name[adapter];
259         return mode_count[adapter];
260 }
261
262 static __videocard video_vga = {
263         .card_name      = "VGA",
264         .probe          = vga_probe,
265         .set_mode       = vga_set_mode,
266 };