Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
video-vesa.c
Go to the documentation of this file.
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  * VESA text modes
14  */
15 
16 #include "boot.h"
17 #include "video.h"
18 #include "vesa.h"
19 
20 /* VESA information */
21 static struct vesa_general_info vginfo;
22 static struct vesa_mode_info vminfo;
23 
24 static __videocard video_vesa;
25 
26 #ifndef _WAKEUP
27 static void vesa_store_mode_params_graphics(void);
28 #else /* _WAKEUP */
29 static inline void vesa_store_mode_params_graphics(void) {}
30 #endif /* _WAKEUP */
31 
32 static int vesa_probe(void)
33 {
34  struct biosregs ireg, oreg;
35  u16 mode;
36  addr_t mode_ptr;
37  struct mode_info *mi;
38  int nmodes = 0;
39 
40  video_vesa.modes = GET_HEAP(struct mode_info, 0);
41 
42  initregs(&ireg);
43  ireg.ax = 0x4f00;
44  ireg.di = (size_t)&vginfo;
45  intcall(0x10, &ireg, &oreg);
46 
47  if (oreg.ax != 0x004f ||
48  vginfo.signature != VESA_MAGIC ||
49  vginfo.version < 0x0102)
50  return 0; /* Not present */
51 
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  ireg.ax = 0x4f01;
67  ireg.cx = mode;
68  ireg.di = (size_t)&vminfo;
69  intcall(0x10, &ireg, &oreg);
70 
71  if (oreg.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->depth = 0; /* text */
80  mi->x = vminfo.h_res;
81  mi->y = vminfo.v_res;
82  nmodes++;
83  } else if ((vminfo.mode_attr & 0x99) == 0x99 &&
84  (vminfo.memory_layout == 4 ||
85  vminfo.memory_layout == 6) &&
86  vminfo.memory_planes == 1) {
87 #ifdef CONFIG_FB_BOOT_VESA_SUPPORT
88  /* Graphics mode, color, linear frame buffer
89  supported. Only register the mode if
90  if framebuffer is configured, however,
91  otherwise the user will be left without a screen. */
92  mi = GET_HEAP(struct mode_info, 1);
93  mi->mode = mode + VIDEO_FIRST_VESA;
94  mi->depth = vminfo.bpp;
95  mi->x = vminfo.h_res;
96  mi->y = vminfo.v_res;
97  nmodes++;
98 #endif
99  }
100  }
101 
102  return nmodes;
103 }
104 
105 static int vesa_set_mode(struct mode_info *mode)
106 {
107  struct biosregs ireg, oreg;
108  int is_graphic;
110 
111  memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
112 
113  initregs(&ireg);
114  ireg.ax = 0x4f01;
115  ireg.cx = vesa_mode;
116  ireg.di = (size_t)&vminfo;
117  intcall(0x10, &ireg, &oreg);
118 
119  if (oreg.ax != 0x004f)
120  return -1;
121 
122  if ((vminfo.mode_attr & 0x15) == 0x05) {
123  /* It's a supported text mode */
124  is_graphic = 0;
125 #ifdef CONFIG_FB_BOOT_VESA_SUPPORT
126  } else if ((vminfo.mode_attr & 0x99) == 0x99) {
127  /* It's a graphics mode with linear frame buffer */
128  is_graphic = 1;
129  vesa_mode |= 0x4000; /* Request linear frame buffer */
130 #endif
131  } else {
132  return -1; /* Invalid mode */
133  }
134 
135 
136  initregs(&ireg);
137  ireg.ax = 0x4f02;
138  ireg.bx = vesa_mode;
139  intcall(0x10, &ireg, &oreg);
140 
141  if (oreg.ax != 0x004f)
142  return -1;
143 
144  graphic_mode = is_graphic;
145  if (!is_graphic) {
146  /* Text mode */
147  force_x = mode->x;
148  force_y = mode->y;
149  do_restore = 1;
150  } else {
151  /* Graphics mode */
152  vesa_store_mode_params_graphics();
153  }
154 
155  return 0;
156 }
157 
158 
159 #ifndef _WAKEUP
160 
161 /* Switch DAC to 8-bit mode */
162 static void vesa_dac_set_8bits(void)
163 {
164  struct biosregs ireg, oreg;
165  u8 dac_size = 6;
166 
167  /* If possible, switch the DAC to 8-bit mode */
168  if (vginfo.capabilities & 1) {
169  initregs(&ireg);
170  ireg.ax = 0x4f08;
171  ireg.bh = 0x08;
172  intcall(0x10, &ireg, &oreg);
173  if (oreg.ax == 0x004f)
174  dac_size = oreg.bh;
175  }
176 
177  /* Set the color sizes to the DAC size, and offsets to 0 */
178  boot_params.screen_info.red_size = dac_size;
179  boot_params.screen_info.green_size = dac_size;
180  boot_params.screen_info.blue_size = dac_size;
181  boot_params.screen_info.rsvd_size = dac_size;
182 
183  boot_params.screen_info.red_pos = 0;
184  boot_params.screen_info.green_pos = 0;
185  boot_params.screen_info.blue_pos = 0;
186  boot_params.screen_info.rsvd_pos = 0;
187 }
188 
189 /* Save the VESA protected mode info */
190 static void vesa_store_pm_info(void)
191 {
192  struct biosregs ireg, oreg;
193 
194  initregs(&ireg);
195  ireg.ax = 0x4f0a;
196  intcall(0x10, &ireg, &oreg);
197 
198  if (oreg.ax != 0x004f)
199  return;
200 
201  boot_params.screen_info.vesapm_seg = oreg.es;
202  boot_params.screen_info.vesapm_off = oreg.di;
203 }
204 
205 /*
206  * Save video mode parameters for graphics mode
207  */
208 static void vesa_store_mode_params_graphics(void)
209 {
210  /* Tell the kernel we're in VESA graphics mode */
211  boot_params.screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
212 
213  /* Mode parameters */
214  boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
215  boot_params.screen_info.lfb_linelength = vminfo.logical_scan;
216  boot_params.screen_info.lfb_width = vminfo.h_res;
217  boot_params.screen_info.lfb_height = vminfo.v_res;
218  boot_params.screen_info.lfb_depth = vminfo.bpp;
219  boot_params.screen_info.pages = vminfo.image_planes;
220  boot_params.screen_info.lfb_base = vminfo.lfb_ptr;
221  memcpy(&boot_params.screen_info.red_size,
222  &vminfo.rmask, 8);
223 
224  /* General parameters */
225  boot_params.screen_info.lfb_size = vginfo.total_memory;
226 
227  if (vminfo.bpp <= 8)
228  vesa_dac_set_8bits();
229 
230  vesa_store_pm_info();
231 }
232 
233 /*
234  * Save EDID information for the kernel; this is invoked, separately,
235  * after mode-setting.
236  */
237 void vesa_store_edid(void)
238 {
239 #ifdef CONFIG_FIRMWARE_EDID
240  struct biosregs ireg, oreg;
241 
242  /* Apparently used as a nonsense token... */
244 
245  if (vginfo.version < 0x0200)
246  return; /* EDID requires VBE 2.0+ */
247 
248  initregs(&ireg);
249  ireg.ax = 0x4f15; /* VBE DDC */
250  /* ireg.bx = 0x0000; */ /* Report DDC capabilities */
251  /* ireg.cx = 0; */ /* Controller 0 */
252  ireg.es = 0; /* ES:DI must be 0 by spec */
253  intcall(0x10, &ireg, &oreg);
254 
255  if (oreg.ax != 0x004f)
256  return; /* No EDID */
257 
258  /* BH = time in seconds to transfer EDD information */
259  /* BL = DDC level supported */
260 
261  ireg.ax = 0x4f15; /* VBE DDC */
262  ireg.bx = 0x0001; /* Read EDID */
263  /* ireg.cx = 0; */ /* Controller 0 */
264  /* ireg.dx = 0; */ /* EDID block number */
265  ireg.es = ds();
266  ireg.di =(size_t)&boot_params.edid_info; /* (ES:)Pointer to block */
267  intcall(0x10, &ireg, &oreg);
268 #endif /* CONFIG_FIRMWARE_EDID */
269 }
270 
271 #endif /* not _WAKEUP */
272 
273 static __videocard video_vesa =
274 {
275  .card_name = "VESA",
276  .probe = vesa_probe,
277  .set_mode = vesa_set_mode,
278  .xmode_first = VIDEO_FIRST_VESA,
279  .xmode_n = 0x200,
280 };