Merge branch 'for-2.6.31' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux-2.6] / arch / x86 / boot / video-bios.c
1 /* -*- linux-c -*- ------------------------------------------------------- *
2  *
3  *   Copyright (C) 1991, 1992 Linus Torvalds
4  *   Copyright 2007 rPath, Inc. - All Rights Reserved
5  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
6  *
7  *   This file is part of the Linux kernel, and is made available under
8  *   the terms of the GNU General Public License version 2.
9  *
10  * ----------------------------------------------------------------------- */
11
12 /*
13  * Standard video BIOS modes
14  *
15  * We have two options for this; silent and scanned.
16  */
17
18 #include "boot.h"
19 #include "video.h"
20
21 static __videocard video_bios;
22
23 /* Set a conventional BIOS mode */
24 static int set_bios_mode(u8 mode);
25
26 static int bios_set_mode(struct mode_info *mi)
27 {
28         return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS);
29 }
30
31 static int set_bios_mode(u8 mode)
32 {
33         struct biosregs ireg, oreg;
34         u8 new_mode;
35
36         initregs(&ireg);
37         ireg.al = mode;         /* AH=0x00 Set Video Mode */
38         intcall(0x10, &ireg, NULL);
39
40
41         ireg.ah = 0x0f;         /* Get Current Video Mode */
42         intcall(0x10, &ireg, &oreg);
43
44         do_restore = 1;         /* Assume video contents were lost */
45
46         /* Not all BIOSes are clean with the top bit */
47         new_mode = ireg.al & 0x7f;
48
49         if (new_mode == mode)
50                 return 0;       /* Mode change OK */
51
52 #ifndef _WAKEUP
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                 ireg.ax = boot_params.screen_info.orig_video_mode;
58                 intcall(0x10, &ireg, NULL);
59         }
60 #endif
61         return -1;
62 }
63
64 static int bios_probe(void)
65 {
66         u8 mode;
67 #ifdef _WAKEUP
68         u8 saved_mode = 0x03;
69 #else
70         u8 saved_mode = boot_params.screen_info.orig_video_mode;
71 #endif
72         u16 crtc;
73         struct mode_info *mi;
74         int nmodes = 0;
75
76         if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA)
77                 return 0;
78
79         set_fs(0);
80         crtc = vga_crtc();
81
82         video_bios.modes = GET_HEAP(struct mode_info, 0);
83
84         for (mode = 0x14; mode <= 0x7f; mode++) {
85                 if (!heap_free(sizeof(struct mode_info)))
86                         break;
87
88                 if (mode_defined(VIDEO_FIRST_BIOS+mode))
89                         continue;
90
91                 if (set_bios_mode(mode))
92                         continue;
93
94                 /* Try to verify that it's a text mode. */
95
96                 /* Attribute Controller: make graphics controller disabled */
97                 if (in_idx(0x3c0, 0x10) & 0x01)
98                         continue;
99
100                 /* Graphics Controller: verify Alpha addressing enabled */
101                 if (in_idx(0x3ce, 0x06) & 0x01)
102                         continue;
103
104                 /* CRTC cursor location low should be zero(?) */
105                 if (in_idx(crtc, 0x0f))
106                         continue;
107
108                 mi = GET_HEAP(struct mode_info, 1);
109                 mi->mode = VIDEO_FIRST_BIOS+mode;
110                 mi->depth = 0;  /* text */
111                 mi->x = rdfs16(0x44a);
112                 mi->y = rdfs8(0x484)+1;
113                 nmodes++;
114         }
115
116         set_bios_mode(saved_mode);
117
118         return nmodes;
119 }
120
121 static __videocard video_bios =
122 {
123         .card_name      = "BIOS",
124         .probe          = bios_probe,
125         .set_mode       = bios_set_mode,
126         .unsafe         = 1,
127         .xmode_first    = VIDEO_FIRST_BIOS,
128         .xmode_n        = 0x80,
129 };