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