drop COREBOOT_V2 and COREBOOT_V4 define. We're not sharing code with v3
[coreboot.git] / util / x86emu / yabel / vbe.c
1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
3  * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
4  * All rights reserved.
5  * This program and the accompanying materials
6  * are made available under the terms of the BSD License
7  * which accompanies this distribution, and is available at
8  * http://www.opensource.org/licenses/bsd-license.php
9  *
10  * Contributors:
11  *     IBM Corporation - initial implementation
12  *****************************************************************************/
13
14 #include <string.h>
15 #include <types.h>
16
17 #include "debug.h"
18
19 #include <x86emu/x86emu.h>
20 #include <x86emu/regs.h>
21 #include "../x86emu/prim_ops.h"
22
23 #include "biosemu.h"
24 #include "io.h"
25 #include "mem.h"
26 #include "interrupt.h"
27 #include "device.h"
28
29 static X86EMU_memFuncs my_mem_funcs = {
30         my_rdb, my_rdw, my_rdl,
31         my_wrb, my_wrw, my_wrl
32 };
33
34 static X86EMU_pioFuncs my_pio_funcs = {
35         my_inb, my_inw, my_inl,
36         my_outb, my_outw, my_outl
37 };
38
39 // pointer to VBEInfoBuffer, set by vbe_prepare
40 u8 *vbe_info_buffer = 0;
41 // virtual BIOS Memory
42 u8 *biosmem;
43 u32 biosmem_size;
44
45 // these structs are for input from and output to OF
46 typedef struct {
47         u8 display_type;        // 0=NONE, 1= analog, 2=digital
48         u16 screen_width;
49         u16 screen_height;
50         u16 screen_linebytes;   // bytes per line in framebuffer, may be more than screen_width
51         u8 color_depth; // color depth in bpp
52         u32 framebuffer_address;
53         u8 edid_block_zero[128];
54 } __attribute__ ((__packed__)) screen_info_t;
55
56 typedef struct {
57         u8 signature[4];
58         u16 size_reserved;
59         u8 monitor_number;
60         u16 max_screen_width;
61         u8 color_depth;
62 } __attribute__ ((__packed__)) screen_info_input_t;
63
64 // these structs only store a subset of the VBE defined fields
65 // only those needed.
66 typedef struct {
67         char signature[4];
68         u16 version;
69         u8 *oem_string_ptr;
70         u32 capabilities;
71         u16 video_mode_list[256];       // lets hope we never have more than 256 video modes...
72         u16 total_memory;
73 } vbe_info_t;
74
75 typedef struct {
76         u16 video_mode;
77         u8 mode_info_block[256];
78         u16 attributes;
79         u16 linebytes;
80         u16 x_resolution;
81         u16 y_resolution;
82         u8 x_charsize;
83         u8 y_charsize;
84         u8 bits_per_pixel;
85         u8 memory_model;
86         u32 framebuffer_address;
87 } vbe_mode_info_t;
88
89 typedef struct {
90         u8 port_number; // i.e. monitor number
91         u8 edid_transfer_time;
92         u8 ddc_level;
93         u8 edid_block_zero[128];
94 } vbe_ddc_info_t;
95
96 static inline u8
97 vbe_prepare()
98 {
99         vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area
100         //clear buffer
101         memset(vbe_info_buffer, 0, 512);
102         //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
103         vbe_info_buffer[0] = 'V';
104         vbe_info_buffer[0] = 'B';
105         vbe_info_buffer[0] = 'E';
106         vbe_info_buffer[0] = '2';
107         // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
108         M.x86.R_EDI = 0x0;
109         M.x86.R_ES = VBE_SEGMENT;
110
111         return 0;               // successfull init
112 }
113
114 // VBE Function 00h
115 u8
116 vbe_info(vbe_info_t * info)
117 {
118         vbe_prepare();
119         // call VBE function 00h (Info Function)
120         M.x86.R_EAX = 0x4f00;
121
122         // enable trace
123         CHECK_DBG(DEBUG_TRACE_X86EMU) {
124                 X86EMU_trace_on();
125         }
126         // run VESA Interrupt
127         runInt10();
128
129         if (M.x86.R_AL != 0x4f) {
130                 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
131                                  __func__, M.x86.R_AL);
132                 return -1;
133         }
134
135         if (M.x86.R_AH != 0x0) {
136                 DEBUG_PRINTF_VBE
137                     ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
138                      __func__, M.x86.R_AH);
139                 return M.x86.R_AH;
140         }
141         //printf("VBE Info Dump:");
142         //dump(vbe_info_buffer, 64);
143
144         //offset 0: signature
145         info->signature[0] = vbe_info_buffer[0];
146         info->signature[1] = vbe_info_buffer[1];
147         info->signature[2] = vbe_info_buffer[2];
148         info->signature[3] = vbe_info_buffer[3];
149
150         // offset 4: 16bit le containing VbeVersion
151         info->version = in16le(vbe_info_buffer + 4);
152
153         // offset 6: 32bit le containg segment:offset of OEM String in virtual Mem.
154         info->oem_string_ptr =
155             biosmem + ((in16le(vbe_info_buffer + 8) << 4) +
156                        in16le(vbe_info_buffer + 6));
157
158         // offset 10: 32bit le capabilities
159         info->capabilities = in32le(vbe_info_buffer + 10);
160
161         // offset 14: 32 bit le containing segment:offset of supported video mode table
162         u16 *video_mode_ptr;
163         video_mode_ptr =
164             (u16 *) (biosmem +
165                           ((in16le(vbe_info_buffer + 16) << 4) +
166                            in16le(vbe_info_buffer + 14)));
167         u32 i = 0;
168         do {
169                 info->video_mode_list[i] = in16le(video_mode_ptr + i);
170                 i++;
171         }
172         while ((i <
173                 (sizeof(info->video_mode_list) /
174                  sizeof(info->video_mode_list[0])))
175                && (info->video_mode_list[i - 1] != 0xFFFF));
176
177         //offset 18: 16bit le total memory in 64KB blocks
178         info->total_memory = in16le(vbe_info_buffer + 18);
179
180         return 0;
181 }
182
183 // VBE Function 01h
184 u8
185 vbe_get_mode_info(vbe_mode_info_t * mode_info)
186 {
187         vbe_prepare();
188         // call VBE function 01h (Return VBE Mode Info Function)
189         M.x86.R_EAX = 0x4f01;
190         M.x86.R_CX = mode_info->video_mode;
191
192         // enable trace
193         CHECK_DBG(DEBUG_TRACE_X86EMU) {
194                 X86EMU_trace_on();
195         }
196         // run VESA Interrupt
197         runInt10();
198
199         if (M.x86.R_AL != 0x4f) {
200                 DEBUG_PRINTF_VBE
201                     ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
202                      __func__, M.x86.R_AL);
203                 return -1;
204         }
205
206         if (M.x86.R_AH != 0x0) {
207                 DEBUG_PRINTF_VBE
208                     ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
209                      __func__, mode_info->video_mode, M.x86.R_AH);
210                 return M.x86.R_AH;
211         }
212         //pointer to mode_info_block is in ES:DI
213         memcpy(mode_info->mode_info_block,
214                biosmem + ((M.x86.R_ES << 4) + M.x86.R_DI),
215                sizeof(mode_info->mode_info_block));
216
217         //printf("Mode Info Dump:");
218         //dump(mode_info_block, 64);
219
220         // offset 0: 16bit le mode attributes
221         mode_info->attributes = in16le(mode_info->mode_info_block);
222
223         // offset 16: 16bit le bytes per scan line
224         mode_info->linebytes = in16le(mode_info->mode_info_block + 16);
225
226         // offset 18: 16bit le x resolution
227         mode_info->x_resolution = in16le(mode_info->mode_info_block + 18);
228
229         // offset 20: 16bit le y resolution
230         mode_info->y_resolution = in16le(mode_info->mode_info_block + 20);
231
232         // offset 22: 8bit le x charsize
233         mode_info->x_charsize = *(mode_info->mode_info_block + 22);
234
235         // offset 23: 8bit le y charsize
236         mode_info->y_charsize = *(mode_info->mode_info_block + 23);
237
238         // offset 25: 8bit le bits per pixel
239         mode_info->bits_per_pixel = *(mode_info->mode_info_block + 25);
240
241         // offset 27: 8bit le memory model
242         mode_info->memory_model = *(mode_info->mode_info_block + 27);
243
244         // offset 40: 32bit le containg offset of frame buffer memory ptr
245         mode_info->framebuffer_address =
246             in32le(mode_info->mode_info_block + 40);
247
248         return 0;
249 }
250
251 // VBE Function 02h
252 u8
253 vbe_set_mode(vbe_mode_info_t * mode_info)
254 {
255         vbe_prepare();
256         // call VBE function 02h (Set VBE Mode Function)
257         M.x86.R_EAX = 0x4f02;
258         M.x86.R_BX = mode_info->video_mode;
259         M.x86.R_BX |= 0x4000;   // set bit 14 to request linear framebuffer mode
260         M.x86.R_BX &= 0x7FFF;   // clear bit 15 to request clearing of framebuffer
261
262         DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__,
263                          M.x86.R_BX);
264
265         // enable trace
266         CHECK_DBG(DEBUG_TRACE_X86EMU) {
267                 X86EMU_trace_on();
268         }
269         // run VESA Interrupt
270         runInt10();
271
272         if (M.x86.R_AL != 0x4f) {
273                 DEBUG_PRINTF_VBE
274                     ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
275                      __func__, M.x86.R_AL);
276                 return -1;
277         }
278
279         if (M.x86.R_AH != 0x0) {
280                 DEBUG_PRINTF_VBE
281                     ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
282                      __func__, mode_info->video_mode, M.x86.R_AH);
283                 return M.x86.R_AH;
284         }
285         return 0;
286 }
287
288 //VBE Function 08h
289 u8
290 vbe_set_palette_format(u8 format)
291 {
292         vbe_prepare();
293         // call VBE function 09h (Set/Get Palette Data Function)
294         M.x86.R_EAX = 0x4f08;
295         M.x86.R_BL = 0x00;      // set format
296         M.x86.R_BH = format;
297
298         DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__,
299                          format);
300
301         // enable trace
302         CHECK_DBG(DEBUG_TRACE_X86EMU) {
303                 X86EMU_trace_on();
304         }
305         // run VESA Interrupt
306         runInt10();
307
308         if (M.x86.R_AL != 0x4f) {
309                 DEBUG_PRINTF_VBE
310                     ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
311                      __func__, M.x86.R_AL);
312                 return -1;
313         }
314
315         if (M.x86.R_AH != 0x0) {
316                 DEBUG_PRINTF_VBE
317                     ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
318                      __func__, M.x86.R_AH);
319                 return M.x86.R_AH;
320         }
321         return 0;
322 }
323
324 // VBE Function 09h
325 u8
326 vbe_set_color(u16 color_number, u32 color_value)
327 {
328         vbe_prepare();
329         // call VBE function 09h (Set/Get Palette Data Function)
330         M.x86.R_EAX = 0x4f09;
331         M.x86.R_BL = 0x00;      // set color
332         M.x86.R_CX = 0x01;      // set only one entry
333         M.x86.R_DX = color_number;
334         // ES:DI is address where color_value is stored, we store it at 2000:0000
335         M.x86.R_ES = 0x2000;
336         M.x86.R_DI = 0x0;
337
338         // store color value at ES:DI
339         out32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI, color_value);
340
341         DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__,
342                          color_number, color_value);
343
344         // enable trace
345         CHECK_DBG(DEBUG_TRACE_X86EMU) {
346                 X86EMU_trace_on();
347         }
348         // run VESA Interrupt
349         runInt10();
350
351         if (M.x86.R_AL != 0x4f) {
352                 DEBUG_PRINTF_VBE
353                     ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
354                      __func__, M.x86.R_AL);
355                 return -1;
356         }
357
358         if (M.x86.R_AH != 0x0) {
359                 DEBUG_PRINTF_VBE
360                     ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
361                      __func__, M.x86.R_AH);
362                 return M.x86.R_AH;
363         }
364         return 0;
365 }
366
367 u8
368 vbe_get_color(u16 color_number, u32 * color_value)
369 {
370         vbe_prepare();
371         // call VBE function 09h (Set/Get Palette Data Function)
372         M.x86.R_EAX = 0x4f09;
373         M.x86.R_BL = 0x00;      // get color
374         M.x86.R_CX = 0x01;      // get only one entry
375         M.x86.R_DX = color_number;
376         // ES:DI is address where color_value is stored, we store it at 2000:0000
377         M.x86.R_ES = 0x2000;
378         M.x86.R_DI = 0x0;
379
380         // enable trace
381         CHECK_DBG(DEBUG_TRACE_X86EMU) {
382                 X86EMU_trace_on();
383         }
384         // run VESA Interrupt
385         runInt10();
386
387         if (M.x86.R_AL != 0x4f) {
388                 DEBUG_PRINTF_VBE
389                     ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
390                      __func__, M.x86.R_AL);
391                 return -1;
392         }
393
394         if (M.x86.R_AH != 0x0) {
395                 DEBUG_PRINTF_VBE
396                     ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
397                      __func__, M.x86.R_AH);
398                 return M.x86.R_AH;
399         }
400         // read color value from ES:DI
401         *color_value = in32le(biosmem + (M.x86.R_ES << 4) + M.x86.R_DI);
402
403         DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__,
404                          color_number, *color_value);
405
406         return 0;
407 }
408
409 // VBE Function 15h
410 u8
411 vbe_get_ddc_info(vbe_ddc_info_t * ddc_info)
412 {
413         vbe_prepare();
414         // call VBE function 15h (DDC Info Function)
415         M.x86.R_EAX = 0x4f15;
416         M.x86.R_BL = 0x00;      // get DDC Info
417         M.x86.R_CX = ddc_info->port_number;
418         M.x86.R_ES = 0x0;
419         M.x86.R_DI = 0x0;
420
421         // enable trace
422         CHECK_DBG(DEBUG_TRACE_X86EMU) {
423                 X86EMU_trace_on();
424         }
425         // run VESA Interrupt
426         runInt10();
427
428         if (M.x86.R_AL != 0x4f) {
429                 DEBUG_PRINTF_VBE
430                     ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
431                      __func__, M.x86.R_AL);
432                 return -1;
433         }
434
435         if (M.x86.R_AH != 0x0) {
436                 DEBUG_PRINTF_VBE
437                     ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
438                      __func__, ddc_info->port_number, M.x86.R_AH);
439                 return M.x86.R_AH;
440         }
441         // BH = approx. time in seconds to transfer one EDID block
442         ddc_info->edid_transfer_time = M.x86.R_BH;
443         // BL = DDC Level
444         ddc_info->ddc_level = M.x86.R_BL;
445
446         vbe_prepare();
447         // call VBE function 15h (DDC Info Function)
448         M.x86.R_EAX = 0x4f15;
449         M.x86.R_BL = 0x01;      // read EDID
450         M.x86.R_CX = ddc_info->port_number;
451         M.x86.R_DX = 0x0;       // block number
452         // ES:DI is address where EDID is stored, we store it at 2000:0000
453         M.x86.R_ES = 0x2000;
454         M.x86.R_DI = 0x0;
455
456         // enable trace
457         CHECK_DBG(DEBUG_TRACE_X86EMU) {
458                 X86EMU_trace_on();
459         }
460         // run VESA Interrupt
461         runInt10();
462
463         if (M.x86.R_AL != 0x4f) {
464                 DEBUG_PRINTF_VBE
465                     ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
466                      __func__, M.x86.R_AL);
467                 return -1;
468         }
469
470         if (M.x86.R_AH != 0x0) {
471                 DEBUG_PRINTF_VBE
472                     ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
473                      __func__, ddc_info->port_number, M.x86.R_AH);
474                 return M.x86.R_AH;
475         }
476
477         memcpy(ddc_info->edid_block_zero,
478                biosmem + (M.x86.R_ES << 4) + M.x86.R_DI,
479                sizeof(ddc_info->edid_block_zero));
480
481         return 0;
482 }
483
484 u32
485 vbe_get_info(u8 argc, char ** argv)
486 {
487         u8 rval;
488         u32 i;
489         if (argc < 4) {
490                 printf
491                     ("Usage %s <vmem_base> <device_path> <address of screen_info_t>\n",
492                      argv[0]);
493                 int i = 0;
494                 for (i = 0; i < argc; i++) {
495                         printf("argv[%d]: %s\n", i, argv[i]);
496                 }
497                 return -1;
498         }
499         // get a copy of input struct...
500         screen_info_input_t input =
501             *((screen_info_input_t *) strtoul((char *) argv[4], 0, 16));
502         // output is pointer to the address passed as argv[4]
503         screen_info_t *output =
504             (screen_info_t *) strtoul((char *) argv[4], 0, 16);
505         // zero output
506         memset(output, 0, sizeof(screen_info_t));
507
508         // argv[1] is address of virtual BIOS mem...
509         // argv[2] is the size
510         biosmem = (u8 *) strtoul(argv[1], 0, 16);
511         biosmem_size = strtoul(argv[2], 0, 16);;
512         if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) {
513                 printf("Error: Not enough virtual memory: %x, required: %x!\n",
514                        biosmem_size, MIN_REQUIRED_VMEM_SIZE);
515                 return -1;
516         }
517         // argv[3] is the device to open and use...
518         if (dev_init((char *) argv[3]) != 0) {
519                 printf("Error initializing device!\n");
520                 return -1;
521         }
522         //setup interrupt handler
523         X86EMU_intrFuncs intrFuncs[256];
524         for (i = 0; i < 256; i++)
525                 intrFuncs[i] = handleInterrupt;
526         X86EMU_setupIntrFuncs(intrFuncs);
527         X86EMU_setupPioFuncs(&my_pio_funcs);
528         X86EMU_setupMemFuncs(&my_mem_funcs);
529
530         // set mem_base
531         M.mem_base = (long) biosmem;
532         M.mem_size = biosmem_size;
533         DEBUG_PRINTF_VBE("membase set: %08x, size: %08x\n", (int) M.mem_base,
534                          (int) M.mem_size);
535
536         vbe_info_t info;
537         rval = vbe_info(&info);
538         if (rval != 0)
539                 return rval;
540
541         DEBUG_PRINTF_VBE("VbeSignature: %s\n", info.signature);
542         DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info.version);
543         DEBUG_PRINTF_VBE("OemString: %s\n", info.oem_string_ptr);
544         DEBUG_PRINTF_VBE("Capabilities:\n");
545         DEBUG_PRINTF_VBE("\tDAC: %s\n",
546                          (info.capabilities & 0x1) ==
547                          0 ? "fixed 6bit" : "switchable 6/8bit");
548         DEBUG_PRINTF_VBE("\tVGA: %s\n",
549                          (info.capabilities & 0x2) ==
550                          0 ? "compatible" : "not compatible");
551         DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
552                          (info.capabilities & 0x4) ==
553                          0 ? "normal" : "use blank bit in Function 09h");
554
555         // argv[4] may be a pointer with enough space to return screen_info_t
556         // as input, it must contain a screen_info_input_t with the following content:
557         // byte[0:3] = "DDC\0" (zero-terminated signature header)
558         // byte[4:5] = reserved space for the return struct... just in case we ever change
559         //             the struct and dont have reserved enough memory (and let's hope the struct
560         //             never gets larger than 64KB)
561         // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
562         // byte[7:8] = max. screen width (OF may want to limit this)
563         // byte[9] = required color depth in bpp
564         if (strncmp((char *) input.signature, "DDC", 4) != 0) {
565                 printf
566                     ("%s: Invalid input signature! expected: %s, is: %s\n",
567                      __func__, "DDC", input.signature);
568                 return -1;
569         }
570         if (input.size_reserved != sizeof(screen_info_t)) {
571                 printf
572                     ("%s: Size of return struct is wrong, required: %d, available: %d\n",
573                      __func__, (int) sizeof(screen_info_t),
574                      input.size_reserved);
575                 return -1;
576         }
577
578         vbe_ddc_info_t ddc_info;
579         ddc_info.port_number = input.monitor_number;
580         vbe_get_ddc_info(&ddc_info);
581
582 #if 0
583         DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n",
584                          ddc_info.edid_transfer_time);
585         DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level);
586         DEBUG_PRINTF_VBE("DDC: EDID: \n");
587         CHECK_DBG(DEBUG_VBE) {
588                 dump(ddc_info.edid_block_zero,
589                      sizeof(ddc_info.edid_block_zero));
590         }
591 #endif
592         if (*((u64 *) ddc_info.edid_block_zero) !=
593             (u64) 0x00FFFFFFFFFFFF00) {
594                 // invalid EDID signature... probably no monitor
595
596                 output->display_type = 0x0;
597                 return 0;
598         } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) {
599                 // digital display
600                 output->display_type = 2;
601         } else {
602                 // analog
603                 output->display_type = 1;
604         }
605         DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type);
606         memcpy(output->edid_block_zero, ddc_info.edid_block_zero,
607                sizeof(ddc_info.edid_block_zero));
608         i = 0;
609         vbe_mode_info_t mode_info;
610         vbe_mode_info_t best_mode_info;
611         // initialize best_mode to 0
612         memset(&best_mode_info, 0, sizeof(best_mode_info));
613         while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) {
614                 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
615                 vbe_get_mode_info(&mode_info);
616 #if 0
617                 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
618                                  mode_info.video_mode,
619                                  (mode_info.attributes & 0x1) ==
620                                  0 ? "not supported" : "supported");
621                 DEBUG_PRINTF_VBE("\tTTY: %s\n",
622                                  (mode_info.attributes & 0x4) ==
623                                  0 ? "no" : "yes");
624                 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
625                                  (mode_info.attributes & 0x8) ==
626                                  0 ? "monochrome" : "color",
627                                  (mode_info.attributes & 0x10) ==
628                                  0 ? "text" : "graphics");
629                 DEBUG_PRINTF_VBE("\tVGA: %s\n",
630                                  (mode_info.attributes & 0x20) ==
631                                  0 ? "compatible" : "not compatible");
632                 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
633                                  (mode_info.attributes & 0x40) ==
634                                  0 ? "yes" : "no");
635                 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
636                                  (mode_info.attributes & 0x80) ==
637                                  0 ? "no" : "yes");
638                 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
639                                  mode_info.x_resolution,
640                                  mode_info.y_resolution);
641                 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
642                                  mode_info.x_charsize, mode_info.y_charsize);
643                 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
644                                  mode_info.bits_per_pixel);
645                 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
646                                  mode_info.memory_model);
647                 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
648                                  mode_info.framebuffer_address);
649 #endif
650                 if ((mode_info.bits_per_pixel == input.color_depth)
651                     && (mode_info.x_resolution <= input.max_screen_width)
652                     && ((mode_info.attributes & 0x80) != 0)     // framebuffer mode
653                     && ((mode_info.attributes & 0x10) != 0)     // graphics
654                     && ((mode_info.attributes & 0x8) != 0)      // color
655                     && (mode_info.x_resolution > best_mode_info.x_resolution))  // better than previous best_mode
656                 {
657                         // yiiiihaah... we found a new best mode
658                         memcpy(&best_mode_info, &mode_info, sizeof(mode_info));
659                 }
660                 i++;
661         }
662
663         if (best_mode_info.video_mode != 0) {
664                 DEBUG_PRINTF_VBE
665                     ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
666                      best_mode_info.video_mode,
667                      best_mode_info.x_resolution,
668                      best_mode_info.y_resolution,
669                      best_mode_info.bits_per_pixel,
670                      best_mode_info.framebuffer_address);
671
672                 //printf("Mode Info Dump:");
673                 //dump(best_mode_info.mode_info_block, 64);
674
675                 // set the video mode
676                 vbe_set_mode(&best_mode_info);
677
678                 if ((info.capabilities & 0x1) != 0) {
679                         // switch to 8 bit palette format
680                         vbe_set_palette_format(8);
681                 }
682                 // setup a palette:
683                 // - first 216 colors are mixed colors for each component in 6 steps
684                 //   (6*6*6=216)
685                 // - then 10 shades of the three primary colors
686                 // - then 10 shades of grey
687                 // -------
688                 // = 256 colors
689                 //
690                 // - finally black is color 0 and white color FF (because SLOF expects it
691                 //   this way...)
692                 // this resembles the palette that the kernel/X Server seems to expect...
693
694                 u8 mixed_color_values[6] =
695                     { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
696                 u8 primary_color_values[10] =
697                     { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
698                         0x27
699                 };
700                 u8 mc_size = sizeof(mixed_color_values);
701                 u8 prim_size = sizeof(primary_color_values);
702
703                 u8 curr_color_index;
704                 u32 curr_color;
705
706                 u8 r, g, b;
707                 // 216 mixed colors
708                 for (r = 0; r < mc_size; r++) {
709                         for (g = 0; g < mc_size; g++) {
710                                 for (b = 0; b < mc_size; b++) {
711                                         curr_color_index =
712                                             (r * mc_size * mc_size) +
713                                             (g * mc_size) + b;
714                                         curr_color = 0;
715                                         curr_color |= ((u32) mixed_color_values[r]) << 16;      //red value
716                                         curr_color |= ((u32) mixed_color_values[g]) << 8;       //green value
717                                         curr_color |= (u32) mixed_color_values[b];      //blue value
718                                         vbe_set_color(curr_color_index,
719                                                       curr_color);
720                                 }
721                         }
722                 }
723
724                 // 10 shades of each primary color
725                 // red
726                 for (r = 0; r < prim_size; r++) {
727                         curr_color_index = mc_size * mc_size * mc_size + r;
728                         curr_color = ((u32) primary_color_values[r]) << 16;
729                         vbe_set_color(curr_color_index, curr_color);
730                 }
731                 //green
732                 for (g = 0; g < prim_size; g++) {
733                         curr_color_index =
734                             mc_size * mc_size * mc_size + prim_size + g;
735                         curr_color = ((u32) primary_color_values[g]) << 8;
736                         vbe_set_color(curr_color_index, curr_color);
737                 }
738                 //blue
739                 for (b = 0; b < prim_size; b++) {
740                         curr_color_index =
741                             mc_size * mc_size * mc_size + prim_size * 2 + b;
742                         curr_color = (u32) primary_color_values[b];
743                         vbe_set_color(curr_color_index, curr_color);
744                 }
745                 // 10 shades of grey
746                 for (i = 0; i < prim_size; i++) {
747                         curr_color_index =
748                             mc_size * mc_size * mc_size + prim_size * 3 + i;
749                         curr_color = 0;
750                         curr_color |= ((u32) primary_color_values[i]) << 16;    //red
751                         curr_color |= ((u32) primary_color_values[i]) << 8;     //green
752                         curr_color |= ((u32) primary_color_values[i]);  //blue
753                         vbe_set_color(curr_color_index, curr_color);
754                 }
755
756                 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
757                 vbe_set_color(0x00, 0x00000000);
758                 vbe_set_color(0xFF, 0x00FFFFFF);
759
760                 output->screen_width = best_mode_info.x_resolution;
761                 output->screen_height = best_mode_info.y_resolution;
762                 output->screen_linebytes = best_mode_info.linebytes;
763                 output->color_depth = best_mode_info.bits_per_pixel;
764                 output->framebuffer_address =
765                     best_mode_info.framebuffer_address;
766         } else {
767                 printf("%s: No suitable video mode found!\n", __func__);
768                 //unset display_type...
769                 output->display_type = 0;
770         }
771         return 0;
772 }