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