1 //=============================================================================
5 // eCos support for a PC display using SVGA/VESA
7 //=============================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //=============================================================================
41 //#####DESCRIPTIONBEGIN####
45 // Purpose: Implement a screen driver for PC's with a VESA video BIOS
47 // PC graphics cards are problematical. Many graphic cards are still more
48 // or less compatible with ancient VGA hardware, but this provides access
49 // only to rather low resolutions. There is no other hardware compatibility,
50 // and many different graphics card all needing their own driver.
52 // Each graphics card comes with a video BIOS @ 0x000C0000, which can be
53 // invoked via int 0x10 to do useful operations like querying the
54 // available video modes and setting the desired one. However the video
55 // BIOS can normally only be called in x86 real mode, not protected mode,
56 // Currently eCos only runs in protected mode, and has no support for
57 // briefly switching back into real mode.
59 // Current VESA VBE2 compliant graphics cards do offer some protected
60 // mode entry points, but not enough to perform mode switches etc.
61 // VBE3 is supposed to provide additional support for protected mode
62 // applications, but does not appear to be widely implemented yet.
64 // So for now the only solution is to perform the mode switching
65 // during bootstrap, and specifically inside RedBoot. This is controlled
66 // by an option in the RedBoot configuration, which has the side
67 // effect of disabling RedBoot's own use of the screen and keyboard.
68 // SVGA graphics modes are not completely standardized, so it is the
69 // user's responsibility to pick a suitable mode.
71 // Because RedBoot is a separate application, it is not guaranteed
72 // that the appropriate mode switch has actually occurred by the
73 // time this code runs. Therefore RedBoot also places the main SVGA
74 // info block at location 0x000A0000, normally a window into video
75 // memory, since that memory is not being used for anything else
76 // right now. Similarly the mode info block for the current mode
77 // is placed @ 0x000A0200, and to make it easier to find out what
78 // modes are available on the current hardware and allow RedBoot to
79 // be reconfigured appropriately, all the mode info blocks are
80 // stored @ 0x000A0400 at 256-byte boundaries. The main info block
81 // can be used to find out which modes are actually available.
83 //####DESCRIPTIONEND####
84 //=============================================================================
87 #include <pkgconf/system.h>
88 #include <pkgconf/microwindows.h>
89 #include <cyg/infra/cyg_ass.h>
90 #include <cyg/infra/diag.h>
91 #include <microwin/device.h>
98 // ----------------------------------------------------------------------------
99 // Information about the current mode and all available video modes,
100 // should have been provided by RedBoot.
101 struct VBESVGAInfoBlock {
102 unsigned char signature[4]; /* VESA */
103 unsigned short version;
104 char* oem_string_ptr;
105 unsigned char capabilities[4];
106 unsigned short* video_mode_ptr;
107 unsigned short total_memory;
108 unsigned short oem_software_rev;
109 char* oem_vendor_name_ptr;
110 char* oem_product_name_ptr;
111 char* oem_product_rev_ptr;
112 /* Reserved data here */
113 } __attribute__((packed));
115 struct VBEModeInfoBlock {
116 unsigned short mode_attributes;
117 unsigned char win_a_atributes;
118 unsigned char win_b_attributes;
119 unsigned short win_granularity;
120 unsigned short win_size;
121 unsigned short win_a_segment;
122 unsigned short win_b_segment;
123 unsigned int win_func_ptr;
124 unsigned short bytes_per_scanline;
125 unsigned short x_resolution;
126 unsigned short y_resolution;
127 unsigned char x_char_size;
128 unsigned char y_char_size;
129 unsigned char number_of_planes;
130 unsigned char bits_per_pixel;
131 unsigned char number_of_banks;
132 unsigned char memory_model;
133 unsigned char bank_size;
134 unsigned char number_of_image_pages;
135 unsigned char reserved;
136 unsigned char red_mask_size;
137 unsigned char red_field_position;
138 unsigned char green_mask_size;
139 unsigned char green_field_position;
140 unsigned char blue_mask_size;
141 unsigned char blue_field_position;
142 unsigned char reserved_mask_size;
143 unsigned char reserved_field_position;
144 unsigned char direct_color_mode_info;
145 void* physical_base_ptr;
146 unsigned int offscreen_memory_offset;
147 unsigned short offscreen_memory_size;
148 } __attribute__((packed));
150 #if defined(CYGDBG_MICROWINDOWS_PCSVGA_VERBOSE)
152 segoff_to_phys(void* addr)
155 int segment = (x >> 12) & 0x0FFFF0;
156 int offset = x & 0x0FFFF;
157 return (void*) (segment | offset);
161 // ----------------------------------------------------------------------------
162 static PSD ecos_pcsvga_open(PSD);
163 static void ecos_pcsvga_close(PSD);
164 static void ecos_pcsvga_setportrait(PSD, int);
165 static void ecos_pcsvga_setpalette(PSD, int, int, MWPALENTRY*);
166 static void ecos_pcsvga_getscreeninfo(PSD , PMWSCREENINFO);
168 SCREENDEVICE scrdev = {
176 #if defined(CYGIMP_MICROWINDOWS_PCSVGA32)
179 pixtype: MWPF_TRUECOLOR0888,
180 #elif defined(CYGIMP_MICROWINDOWS_PCSVGA16)
183 pixtype: MWPF_TRUECOLOR565,
185 # error Unsupported video mode.
187 flags: PSF_SCREEN | PSF_HAVEBLIT,
190 Open: &ecos_pcsvga_open,
191 Close: &ecos_pcsvga_close,
192 GetScreenInfo: &ecos_pcsvga_getscreeninfo,
193 SetPalette: &ecos_pcsvga_setpalette,
199 builtin_fonts: gen_fonts,
203 SetIOPermissions: NULL,
204 AllocateMemGC: &gen_allocatememgc,
205 MapMemGC: &fb_mapmemgc,
206 FreeMemGC: &gen_freememgc,
208 SetPortrait: &ecos_pcsvga_setportrait,
209 portrait: MWPORTRAIT_NONE,
214 ecos_pcsvga_open(PSD psd)
216 struct VBESVGAInfoBlock* vesa_info_block;
217 struct VBEModeInfoBlock* vesa_current_mode;
219 // Detect repeated invocations. The information in the video
220 // memory will be blown away after the first call, so can
221 // only be consulted once.
222 static int opened = 0;
223 static PSD result = NULL;
229 // First make sure that there is valid video information in video
230 // memory, i.e. that the system was booted by means of a suitable
231 // RedBoot instance, that nothing has overwritten video memory
232 // yet, and that we are running at the desired screen depth.
233 vesa_info_block = (struct VBESVGAInfoBlock*) 0x000A0000;
234 vesa_current_mode = (struct VBEModeInfoBlock*) 0x000A0200;
235 if (('V' != vesa_info_block->signature[0]) || ('E' != vesa_info_block->signature[1]) ||
236 ('S' != vesa_info_block->signature[2]) || ('A' != vesa_info_block->signature[3])) {
237 EPRINTF("No Video BIOS information at location 0x000A0000\n"
238 "Please use a suitably configured RedBoot for bootstrap\n");
242 // Optionally, provide lots of information about the graphics card,
243 // the various modes available, and the current mode.
244 #ifdef CYGDBG_MICROWINDOWS_PCSVGA_VERBOSE
246 diag_printf("VESA info: %c%c%c%c\n", vesa_info_block->signature[0], vesa_info_block->signature[1],
247 vesa_info_block->signature[2], vesa_info_block->signature[3]);
248 diag_printf("Version %04x\n", vesa_info_block->version);
249 if (NULL != vesa_info_block->oem_string_ptr) {
250 vesa_info_block->oem_string_ptr = segoff_to_phys(vesa_info_block->oem_string_ptr);
251 diag_printf("OEM %s\n", vesa_info_block->oem_string_ptr);
253 diag_printf("Total memory %dK\n", 64 * vesa_info_block->total_memory);
254 diag_printf("OEM software rev %04x\n", vesa_info_block->oem_software_rev);
255 if (NULL != vesa_info_block->oem_vendor_name_ptr) {
256 vesa_info_block->oem_vendor_name_ptr = segoff_to_phys(vesa_info_block->oem_vendor_name_ptr);
257 diag_printf("OEM vendor %s\n", vesa_info_block->oem_vendor_name_ptr);
259 if (NULL != vesa_info_block->oem_product_name_ptr) {
260 vesa_info_block->oem_product_name_ptr = segoff_to_phys(vesa_info_block->oem_product_name_ptr);
261 diag_printf("OEM product name %s\n", vesa_info_block->oem_product_name_ptr);
263 if (NULL != vesa_info_block->oem_product_rev_ptr) {
264 vesa_info_block->oem_product_rev_ptr = segoff_to_phys(vesa_info_block->oem_product_rev_ptr);
265 diag_printf("OEM product revision %s\n", vesa_info_block->oem_product_rev_ptr);
267 diag_printf("Capabilities: %02x, %02x, %02x, %02x\n",
268 vesa_info_block->capabilities[0], vesa_info_block->capabilities[1],
269 vesa_info_block->capabilities[2], vesa_info_block->capabilities[3]);
270 vesa_info_block->video_mode_ptr = (unsigned short*) segoff_to_phys((char*) vesa_info_block->video_mode_ptr);
271 for (i = 0; 0x0FFFF != vesa_info_block->video_mode_ptr[i]; i++) {
272 int mode = vesa_info_block->video_mode_ptr[i];
273 struct VBEModeInfoBlock* mode_data = (struct VBEModeInfoBlock*) (0x0A0400 + (0x100 * i));
274 diag_printf("Mode %04x: %4d*%4d @ %2dbpp, %4d bytes/line, fb %s 0x%08x\n", mode,
275 mode_data->x_resolution, mode_data->y_resolution, mode_data->bits_per_pixel,
276 mode_data->bytes_per_scanline,
277 (0 == (mode_data->mode_attributes & 0x0080)) ? "no " : "yes",
278 mode_data->physical_base_ptr);
279 if (32 == mode_data->bits_per_pixel) {
280 diag_printf(" red %d bits << %d, green %d bits << %d, blue %d bits << %d, reserved %d bits << %d\n",
281 mode_data->red_mask_size, mode_data->red_field_position,
282 mode_data->green_mask_size, mode_data->green_field_position,
283 mode_data->blue_mask_size, mode_data->blue_field_position,
284 mode_data->reserved_mask_size, mode_data->reserved_field_position);
288 diag_printf("Current mode: %4d*%4d @ %2dbpp, %4d bytes/line, fb %s 0x%08x\n",
289 vesa_current_mode->x_resolution, vesa_current_mode->y_resolution, vesa_current_mode->bits_per_pixel,
290 vesa_current_mode->bytes_per_scanline,
291 (0 == (vesa_current_mode->mode_attributes & 0x0080)) ? "no" : "yes",
292 vesa_current_mode->physical_base_ptr);
293 if (32 == vesa_current_mode->bits_per_pixel) {
294 diag_printf(" red %d bits << %d, green %d bits << %d, blue %d bits << %d, reserved %d bits << %d\n",
295 vesa_current_mode->red_mask_size, vesa_current_mode->red_field_position,
296 vesa_current_mode->green_mask_size, vesa_current_mode->green_field_position,
297 vesa_current_mode->blue_mask_size, vesa_current_mode->blue_field_position,
298 vesa_current_mode->reserved_mask_size, vesa_current_mode->reserved_field_position);
303 #if defined(CYGIMP_MICROWINDOWS_PCSVGA32)
304 // A 32-bit displays, 0888
305 if ((32 != vesa_current_mode->bits_per_pixel) ||
306 (8 != vesa_current_mode->red_mask_size) || (16 != vesa_current_mode->red_field_position) ||
307 (8 != vesa_current_mode->green_mask_size) || ( 8 != vesa_current_mode->green_field_position) ||
308 (8 != vesa_current_mode->blue_mask_size) || ( 0 != vesa_current_mode->blue_field_position)) {
310 EPRINTF("RedBoot has not set up a valid initial graphics mode.\n"
311 "This screen driver requires 32 bits per pixel, 0RGB.\n",
312 "Configuration option CYGDBG_MICROWINDOWS_PCSVGA_VERBOSE can be used to\n"
313 "get information about the available video modes.\n");
316 #elif defined(CYGIMP_MICROWINDOWS_PCSVGA16)
317 // A 16-bit display, 565
318 if ((16 != vesa_current_mode->bits_per_pixel) ||
319 (5 != vesa_current_mode->red_mask_size) || (11 != vesa_current_mode->red_field_position) ||
320 (6 != vesa_current_mode->green_mask_size) || ( 5 != vesa_current_mode->green_field_position) ||
321 (5 != vesa_current_mode->blue_mask_size) || ( 0 != vesa_current_mode->blue_field_position)) {
323 EPRINTF("RedBoot has not set up a valid initial graphics mode.\n"
324 "This screen driver requires 16 bits per pixel, RGB=565.\n",
325 "Configuration option CYGDBG_MICROWINDOWS_PCSVGA_VERBOSE can be used to\n"
326 "get information about the available video modes.\n");
331 if ((0 == (vesa_current_mode->mode_attributes & 0x0080)) || (NULL == vesa_current_mode->physical_base_ptr)) {
332 EPRINTF("RedBoot has not set up a valid initial graphics mode.\n"
333 "The frame buffer is not linearly accessible.\n");
338 // OK, we are at the expected depth. Fill in the resolution etc. based
339 // on the current video mode.
340 psd->xres = vesa_current_mode->x_resolution;
341 psd->yres = vesa_current_mode->y_resolution;
342 psd->xvirtres = vesa_current_mode->x_resolution;
343 psd->yvirtres = vesa_current_mode->y_resolution;
344 psd->linelen = vesa_current_mode->bytes_per_scanline;
345 psd->addr = vesa_current_mode->physical_base_ptr;
346 // The remaining parameters in the structure are statically
347 // initialized for now, e.g. 32bpp, pixtype TRUECOLOR0888
349 // Use one of the standard framebuffer subdrivers.
350 psd->orgsubdriver = select_fb_subdriver(psd);
351 if (NULL == psd->orgsubdriver) {
352 EPRINTF("There is no standard framebuffer driver for the current video mode.\n");
355 if (!set_subdriver(psd, psd->orgsubdriver, TRUE)) {
356 EPRINTF("Framebuffer subdriver initialization failed.\n");
360 // That should be all for now.
365 // Close is a no-op, no resources have been allocated.
366 // The open() code detects multiple invocations.
368 ecos_pcsvga_close(PSD psd)
370 CYG_UNUSED_PARAM(PSD, psd);
373 // Setting the palette is a no-op for now since only true color
374 // modes are supported.
376 ecos_pcsvga_setpalette(PSD psd, int first, int count, MWPALENTRY* pal)
378 CYG_UNUSED_PARAM(PSD, psd);
379 CYG_UNUSED_PARAM(int, first);
380 CYG_UNUSED_PARAM(int, count);
381 CYG_UNUSED_PARAM(MWPALENTRY*, pal);
384 // Setting the portrait mode. There are standard subdrivers to
385 // cope with this, manipulating the arguments and then calling
386 // the original subdriver.
388 extern SUBDRIVER fbportrait_left, fbportrait_right, fbportrait_down;
391 ecos_pcsvga_setportrait(PSD psd, int portrait_mode)
393 psd->portrait = portrait_mode;
394 if (portrait_mode & (MWPORTRAIT_LEFT | MWPORTRAIT_RIGHT)) {
395 psd->xvirtres = psd->yres;
396 psd->yvirtres = psd->xres;
398 psd->xvirtres = psd->xres;
399 psd->yvirtres = psd->yres;
402 if (portrait_mode == MWPORTRAIT_LEFT) {
403 set_subdriver(psd, &fbportrait_left, FALSE);
404 } else if (portrait_mode == MWPORTRAIT_RIGHT) {
405 set_subdriver(psd, &fbportrait_right, FALSE);
406 } else if (portrait_mode == MWPORTRAIT_DOWN) {
407 set_subdriver(psd, &fbportrait_down, FALSE);
409 set_subdriver(psd, psd->orgsubdriver, FALSE);
413 // Getting screen info. It is not clear why this is part of the driver
414 // since nearly all the information is already available in psd.
416 ecos_pcsvga_getscreeninfo(PSD psd, PMWSCREENINFO psi)
418 psi->rows = psd->yvirtres;
419 psi->cols = psd->xvirtres;
420 psi->planes = psd->planes;
422 psi->ncolors = psd->ncolors;
423 psi->portrait = psd->portrait;
424 psi->fbdriver = TRUE;
425 psi->pixtype = psd->pixtype;
426 #if defined(CYGIMP_MICROWINDOWS_PCSVGA32)
427 psi->rmask = 0x00FF0000;
428 psi->gmask = 0x0000FF00;
429 psi->bmask = 0x000000FF;
430 #elif defined(CYGIMP_MICROWINDOWS_PCSVGA16)
431 psi->rmask = 0x0000F800;
432 psi->gmask = 0x000007E0;
433 psi->bmask = 0x0000001F;
436 // The screen dimensions are not readily available.
437 // Assume an 18' monitor (actual visible diameter),
438 // which corresponds ~ to 36cm by 28cm
439 psi->xdpcm = psd->xres / 36;
440 psi->ydpcm = psd->yres / 28;
442 psi->fonts = NUMBER_FONTS;
444 // Remaining information such as keyboard modifiers etc. cannot be