1 /******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation
3 * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * IBM Corporation - initial implementation
33 *****************************************************************************/
35 #include <boot/coreboot_tables.h>
36 #include <framebuffer_info.h>
44 #include <x86emu/x86emu.h>
45 #include <x86emu/regs.h>
46 #include "../x86emu/prim_ops.h"
51 #include "interrupt.h"
58 // these structs only store a subset of the VBE defined fields
65 u16 video_mode_list
[256]; // lets hope we never have more than
70 // pointer to VBEInfoBuffer, set by vbe_prepare
71 u8
*vbe_info_buffer
= 0;
73 // virtual BIOS Memory
77 #if CONFIG(FRAMEBUFFER_SET_VESA_MODE)
81 vbe_info_buffer
= biosmem
+ (VBE_SEGMENT
<< 4); // segment:offset off VBE Data Area
83 memset(vbe_info_buffer
, 0, 512);
84 //set VbeSignature to "VBE2" to indicate VBE 2.0+ request
85 vbe_info_buffer
[0] = 'V';
86 vbe_info_buffer
[1] = 'B';
87 vbe_info_buffer
[2] = 'E';
88 vbe_info_buffer
[3] = '2';
89 // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above...
91 M
.x86
.R_ES
= VBE_SEGMENT
;
93 return 0; // successful init
98 vbe_info(vbe_info_t
* info
)
101 // call VBE function 00h (Info Function)
102 M
.x86
.R_EAX
= 0x4f00;
105 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
108 // run VESA Interrupt
111 if (M
.x86
.R_AL
!= 0x4f) {
112 DEBUG_PRINTF_VBE("%s: VBE Info Function NOT supported! AL=%x\n",
113 __func__
, M
.x86
.R_AL
);
117 if (M
.x86
.R_AH
!= 0x0) {
119 ("%s: VBE Info Function Return Code NOT OK! AH=%x\n",
120 __func__
, M
.x86
.R_AH
);
123 //printf("VBE Info Dump:");
124 //dump(vbe_info_buffer, 64);
126 //offset 0: signature
127 info
->signature
[0] = vbe_info_buffer
[0];
128 info
->signature
[1] = vbe_info_buffer
[1];
129 info
->signature
[2] = vbe_info_buffer
[2];
130 info
->signature
[3] = vbe_info_buffer
[3];
132 // offset 4: 16bit le containing VbeVersion
133 info
->version
= in16le(vbe_info_buffer
+ 4);
135 // offset 6: 32bit le containing segment:offset of OEM String in virtual Mem.
136 info
->oem_string_ptr
=
137 biosmem
+ ((in16le(vbe_info_buffer
+ 8) << 4) +
138 in16le(vbe_info_buffer
+ 6));
140 // offset 10: 32bit le capabilities
141 info
->capabilities
= in32le(vbe_info_buffer
+ 10);
143 // offset 14: 32 bit le containing segment:offset of supported video mode table
147 ((in16le(vbe_info_buffer
+ 16) << 4) +
148 in16le(vbe_info_buffer
+ 14)));
151 info
->video_mode_list
[i
] = in16le(video_mode_ptr
+ i
);
155 (sizeof(info
->video_mode_list
) /
156 sizeof(info
->video_mode_list
[0])))
157 && (info
->video_mode_list
[i
- 1] != 0xFFFF));
159 //offset 18: 16bit le total memory in 64KB blocks
160 info
->total_memory
= in16le(vbe_info_buffer
+ 18);
165 static int mode_info_valid
;
169 vbe_get_mode_info(vbe_mode_info_t
* mode_info
)
172 // call VBE function 01h (Return VBE Mode Info Function)
173 M
.x86
.R_EAX
= 0x4f01;
174 M
.x86
.R_CX
= mode_info
->video_mode
;
177 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
180 // run VESA Interrupt
183 if (M
.x86
.R_AL
!= 0x4f) {
185 ("%s: VBE Return Mode Info Function NOT supported! AL=%x\n",
186 __func__
, M
.x86
.R_AL
);
190 if (M
.x86
.R_AH
!= 0x0) {
192 ("%s: VBE Return Mode Info (mode: %04x) Function Return Code NOT OK! AH=%02x\n",
193 __func__
, mode_info
->video_mode
, M
.x86
.R_AH
);
197 //pointer to mode_info_block is in ES:DI
198 memcpy(mode_info
->mode_info_block
,
199 biosmem
+ ((M
.x86
.R_ES
<< 4) + M
.x86
.R_DI
),
200 sizeof(mode_info
->mode_info_block
));
203 //printf("Mode Info Dump:");
204 //dump(mode_info_block, 64);
211 vbe_set_mode(vbe_mode_info_t
* mode_info
)
214 // call VBE function 02h (Set VBE Mode Function)
215 M
.x86
.R_EAX
= 0x4f02;
216 M
.x86
.R_BX
= mode_info
->video_mode
;
217 M
.x86
.R_BX
|= 0x4000; // set bit 14 to request linear framebuffer mode
218 M
.x86
.R_BX
&= 0x7FFF; // clear bit 15 to request clearing of framebuffer
220 DEBUG_PRINTF_VBE("%s: setting mode: 0x%04x\n", __func__
,
224 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
227 // run VESA Interrupt
230 if (M
.x86
.R_AL
!= 0x4f) {
232 ("%s: VBE Set Mode Function NOT supported! AL=%x\n",
233 __func__
, M
.x86
.R_AL
);
237 if (M
.x86
.R_AH
!= 0x0) {
239 ("%s: mode: %x VBE Set Mode Function Return Code NOT OK! AH=%x\n",
240 __func__
, mode_info
->video_mode
, M
.x86
.R_AH
);
249 vbe_set_palette_format(u8 format
)
252 // call VBE function 09h (Set/Get Palette Data Function)
253 M
.x86
.R_EAX
= 0x4f08;
254 M
.x86
.R_BL
= 0x00; // set format
257 DEBUG_PRINTF_VBE("%s: setting palette format: %d\n", __func__
,
261 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
264 // run VESA Interrupt
267 if (M
.x86
.R_AL
!= 0x4f) {
269 ("%s: VBE Set Palette Format Function NOT supported! AL=%x\n",
270 __func__
, M
.x86
.R_AL
);
274 if (M
.x86
.R_AH
!= 0x0) {
276 ("%s: VBE Set Palette Format Function Return Code NOT OK! AH=%x\n",
277 __func__
, M
.x86
.R_AH
);
285 vbe_set_color(u16 color_number
, u32 color_value
)
288 // call VBE function 09h (Set/Get Palette Data Function)
289 M
.x86
.R_EAX
= 0x4f09;
290 M
.x86
.R_BL
= 0x00; // set color
291 M
.x86
.R_CX
= 0x01; // set only one entry
292 M
.x86
.R_DX
= color_number
;
293 // ES:DI is address where color_value is stored, we store it at 2000:0000
297 // store color value at ES:DI
298 out32le(biosmem
+ (M
.x86
.R_ES
<< 4) + M
.x86
.R_DI
, color_value
);
300 DEBUG_PRINTF_VBE("%s: setting color #%x: 0x%04x\n", __func__
,
301 color_number
, color_value
);
304 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
307 // run VESA Interrupt
310 if (M
.x86
.R_AL
!= 0x4f) {
312 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
313 __func__
, M
.x86
.R_AL
);
317 if (M
.x86
.R_AH
!= 0x0) {
319 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
320 __func__
, M
.x86
.R_AH
);
327 vbe_get_color(u16 color_number
, u32
*color_value
)
330 // call VBE function 09h (Set/Get Palette Data Function)
331 M
.x86
.R_EAX
= 0x4f09;
332 M
.x86
.R_BL
= 0x00; // get color
333 M
.x86
.R_CX
= 0x01; // get only one entry
334 M
.x86
.R_DX
= color_number
;
335 // ES:DI is address where color_value is stored, we store it at 2000:0000
340 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
343 // run VESA Interrupt
346 if (M
.x86
.R_AL
!= 0x4f) {
348 ("%s: VBE Set Palette Function NOT supported! AL=%x\n",
349 __func__
, M
.x86
.R_AL
);
353 if (M
.x86
.R_AH
!= 0x0) {
355 ("%s: VBE Set Palette Function Return Code NOT OK! AH=%x\n",
356 __func__
, M
.x86
.R_AH
);
359 // read color value from ES:DI
360 *color_value
= in32le(biosmem
+ (M
.x86
.R_ES
<< 4) + M
.x86
.R_DI
);
362 DEBUG_PRINTF_VBE("%s: getting color #%x --> 0x%04x\n", __func__
,
363 color_number
, *color_value
);
370 vbe_get_ddc_info(vbe_ddc_info_t
* ddc_info
)
373 // call VBE function 15h (DDC Info Function)
374 M
.x86
.R_EAX
= 0x4f15;
375 M
.x86
.R_BL
= 0x00; // get DDC Info
376 M
.x86
.R_CX
= ddc_info
->port_number
;
381 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
384 // run VESA Interrupt
387 if (M
.x86
.R_AL
!= 0x4f) {
389 ("%s: VBE Get DDC Info Function NOT supported! AL=%x\n",
390 __func__
, M
.x86
.R_AL
);
394 if (M
.x86
.R_AH
!= 0x0) {
396 ("%s: port: %x VBE Get DDC Info Function Return Code NOT OK! AH=%x\n",
397 __func__
, ddc_info
->port_number
, M
.x86
.R_AH
);
400 // BH = approx. time in seconds to transfer one EDID block
401 ddc_info
->edid_transfer_time
= M
.x86
.R_BH
;
403 ddc_info
->ddc_level
= M
.x86
.R_BL
;
406 // call VBE function 15h (DDC Info Function)
407 M
.x86
.R_EAX
= 0x4f15;
408 M
.x86
.R_BL
= 0x01; // read EDID
409 M
.x86
.R_CX
= ddc_info
->port_number
;
410 M
.x86
.R_DX
= 0x0; // block number
411 // ES:DI is address where EDID is stored, we store it at 2000:0000
416 CHECK_DBG(DEBUG_TRACE_X86EMU
) {
419 // run VESA Interrupt
422 if (M
.x86
.R_AL
!= 0x4f) {
424 ("%s: VBE Read EDID Function NOT supported! AL=%x\n",
425 __func__
, M
.x86
.R_AL
);
429 if (M
.x86
.R_AH
!= 0x0) {
431 ("%s: port: %x VBE Read EDID Function Return Code NOT OK! AH=%x\n",
432 __func__
, ddc_info
->port_number
, M
.x86
.R_AH
);
436 memcpy(ddc_info
->edid_block_zero
,
437 biosmem
+ (M
.x86
.R_ES
<< 4) + M
.x86
.R_DI
,
438 sizeof(ddc_info
->edid_block_zero
));
449 // XXX FIXME these need to be filled with sane values
451 // get a copy of input struct...
452 screen_info_input_t input
;
453 // output is pointer to the address passed as argv[4]
454 screen_info_t local_output
;
455 screen_info_t
*output
= &local_output
;
457 memset(&input
, 0, sizeof(screen_info_input_t
));
459 memset(&output
, 0, sizeof(screen_info_t
));
462 rval
= vbe_info(&info
);
466 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info
.signature
);
467 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info
.version
);
468 DEBUG_PRINTF_VBE("OemString: %s\n", info
.oem_string_ptr
);
469 DEBUG_PRINTF_VBE("Capabilities:\n");
470 DEBUG_PRINTF_VBE("\tDAC: %s\n",
471 (info
.capabilities
& 0x1) ==
472 0 ? "fixed 6bit" : "switchable 6/8bit");
473 DEBUG_PRINTF_VBE("\tVGA: %s\n",
474 (info
.capabilities
& 0x2) ==
475 0 ? "compatible" : "not compatible");
476 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
477 (info
.capabilities
& 0x4) ==
478 0 ? "normal" : "use blank bit in Function 09h");
480 // argv[4] may be a pointer with enough space to return screen_info_t
481 // as input, it must contain a screen_info_input_t with the following content:
482 // byte[0:3] = "DDC\0" (zero-terminated signature header)
483 // byte[4:5] = reserved space for the return struct... just in case we ever change
484 // the struct and don't have reserved enough memory (and let's hope the struct
485 // never gets larger than 64KB)
486 // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors...
487 // byte[7:8] = max. screen width (OF may want to limit this)
488 // byte[9] = required color depth in bpp
489 if (strncmp((char *) input
.signature
, "DDC", 4) != 0) {
491 ("%s: Invalid input signature! expected: %s, is: %s\n",
492 __func__
, "DDC", input
.signature
);
495 if (input
.size_reserved
!= sizeof(screen_info_t
)) {
497 ("%s: Size of return struct is wrong, required: %d, available: %d\n",
498 __func__
, (int) sizeof(screen_info_t
),
499 input
.size_reserved
);
503 vbe_ddc_info_t ddc_info
;
504 ddc_info
.port_number
= input
.monitor_number
;
505 vbe_get_ddc_info(&ddc_info
);
508 DEBUG_PRINTF_VBE("DDC: edid_transfer_time: %d\n",
509 ddc_info
.edid_transfer_time
);
510 DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info
.ddc_level
);
511 DEBUG_PRINTF_VBE("DDC: EDID:\n");
512 CHECK_DBG(DEBUG_VBE
) {
513 dump(ddc_info
.edid_block_zero
,
514 sizeof(ddc_info
.edid_block_zero
));
517 /* This could fail because of alignment issues, so use a longer form.
518 *((u64 *) ddc_info.edid_block_zero) != (u64) 0x00FFFFFFFFFFFF00ULL
520 if (ddc_info
.edid_block_zero
[0] != 0x00 ||
521 ddc_info
.edid_block_zero
[1] != 0xFF ||
522 ddc_info
.edid_block_zero
[2] != 0xFF ||
523 ddc_info
.edid_block_zero
[3] != 0xFF ||
524 ddc_info
.edid_block_zero
[4] != 0xFF ||
525 ddc_info
.edid_block_zero
[5] != 0xFF ||
526 ddc_info
.edid_block_zero
[6] != 0xFF ||
527 ddc_info
.edid_block_zero
[7] != 0x00 ) {
528 // invalid EDID signature... probably no monitor
530 output
->display_type
= 0x0;
532 } else if ((ddc_info
.edid_block_zero
[20] & 0x80) != 0) {
534 output
->display_type
= 2;
537 output
->display_type
= 1;
539 DEBUG_PRINTF_VBE("DDC: found display type %d\n", output
->display_type
);
540 memcpy(output
->edid_block_zero
, ddc_info
.edid_block_zero
,
541 sizeof(ddc_info
.edid_block_zero
));
543 vbe_mode_info_t mode_info
;
544 vbe_mode_info_t best_mode_info
;
545 // initialize best_mode to 0
546 memset(&best_mode_info
, 0, sizeof(best_mode_info
));
547 while ((mode_info
.video_mode
= info
.video_mode_list
[i
]) != 0xFFFF) {
548 //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode);
549 vbe_get_mode_info(&mode_info
);
551 // FIXME all these values are little endian!
553 DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n",
554 mode_info
.video_mode
,
555 (le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x1) ==
556 0 ? "not supported" : "supported");
557 DEBUG_PRINTF_VBE("\tTTY: %s\n",
558 (le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x4) ==
560 DEBUG_PRINTF_VBE("\tMode: %s %s\n",
561 (le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x8) ==
562 0 ? "monochrome" : "color",
563 (le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x10) ==
564 0 ? "text" : "graphics");
565 DEBUG_PRINTF_VBE("\tVGA: %s\n",
566 (le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x20) ==
567 0 ? "compatible" : "not compatible");
568 DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n",
569 (le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x40) ==
571 DEBUG_PRINTF_VBE("\tFramebuffer: %s\n",
572 (le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x80) ==
574 DEBUG_PRINTF_VBE("\tResolution: %dx%d\n",
575 le16_to_cpu(mode_info
.vesa
.x_resolution
),
576 le16_to_cpu(mode_info
.vesa
.y_resolution
));
577 DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n",
578 mode_info
.vesa
.x_charsize
, mode_info
.vesa
.y_charsize
);
579 DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n",
580 mode_info
.vesa
.bits_per_pixel
);
581 DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n",
582 mode_info
.vesa
.memory_model
);
583 DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n",
584 le32_to_cpu(mode_info
.vesa
.phys_base_ptr
));
586 if ((mode_info
.vesa
.bits_per_pixel
== input
.color_depth
)
587 && (le16_to_cpu(mode_info
.vesa
.x_resolution
) <= input
.max_screen_width
)
588 && ((le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x80) != 0) // framebuffer mode
589 && ((le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x10) != 0) // graphics
590 && ((le16_to_cpu(mode_info
.vesa
.mode_attributes
) & 0x8) != 0) // color
591 && (le16_to_cpu(mode_info
.vesa
.x_resolution
) > le16_to_cpu(best_mode_info
.vesa
.x_resolution
))) // better than previous best_mode
593 // yiiiihaah... we found a new best mode
594 memcpy(&best_mode_info
, &mode_info
, sizeof(mode_info
));
599 if (best_mode_info
.video_mode
!= 0) {
601 ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n",
602 best_mode_info
.video_mode
,
603 best_mode_info
.vesa
.x_resolution
,
604 best_mode_info
.vesa
.y_resolution
,
605 best_mode_info
.vesa
.bits_per_pixel
,
606 le32_to_cpu(best_mode_info
.vesa
.phys_base_ptr
));
608 //printf("Mode Info Dump:");
609 //dump(best_mode_info.mode_info_block, 64);
611 // set the video mode
612 vbe_set_mode(&best_mode_info
);
614 if ((info
.capabilities
& 0x1) != 0) {
615 // switch to 8 bit palette format
616 vbe_set_palette_format(8);
619 // - first 216 colors are mixed colors for each component in 6 steps
621 // - then 10 shades of the three primary colors
622 // - then 10 shades of grey
626 // - finally black is color 0 and white color FF (because SLOF expects it
628 // this resembles the palette that the kernel/X Server seems to expect...
630 u8 mixed_color_values
[6] =
631 { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 };
632 u8 primary_color_values
[10] =
633 { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F,
636 u8 mc_size
= sizeof(mixed_color_values
);
637 u8 prim_size
= sizeof(primary_color_values
);
644 for (r
= 0; r
< mc_size
; r
++) {
645 for (g
= 0; g
< mc_size
; g
++) {
646 for (b
= 0; b
< mc_size
; b
++) {
648 (r
* mc_size
* mc_size
) +
651 curr_color
|= ((u32
) mixed_color_values
[r
]) << 16; //red value
652 curr_color
|= ((u32
) mixed_color_values
[g
]) << 8; //green value
653 curr_color
|= (u32
) mixed_color_values
[b
]; //blue value
654 vbe_set_color(curr_color_index
,
660 // 10 shades of each primary color
662 for (r
= 0; r
< prim_size
; r
++) {
663 curr_color_index
= mc_size
* mc_size
* mc_size
+ r
;
664 curr_color
= ((u32
) primary_color_values
[r
]) << 16;
665 vbe_set_color(curr_color_index
, curr_color
);
668 for (g
= 0; g
< prim_size
; g
++) {
670 mc_size
* mc_size
* mc_size
+ prim_size
+ g
;
671 curr_color
= ((u32
) primary_color_values
[g
]) << 8;
672 vbe_set_color(curr_color_index
, curr_color
);
675 for (b
= 0; b
< prim_size
; b
++) {
677 mc_size
* mc_size
* mc_size
+ prim_size
* 2 + b
;
678 curr_color
= (u32
) primary_color_values
[b
];
679 vbe_set_color(curr_color_index
, curr_color
);
682 for (i
= 0; i
< prim_size
; i
++) {
684 mc_size
* mc_size
* mc_size
+ prim_size
* 3 + i
;
686 curr_color
|= ((u32
) primary_color_values
[i
]) << 16; //red
687 curr_color
|= ((u32
) primary_color_values
[i
]) << 8; //green
688 curr_color
|= ((u32
) primary_color_values
[i
]); //blue
689 vbe_set_color(curr_color_index
, curr_color
);
692 // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen...
693 vbe_set_color(0x00, 0x00000000);
694 vbe_set_color(0xFF, 0x00FFFFFF);
696 output
->screen_width
= le16_to_cpu(best_mode_info
.vesa
.x_resolution
);
697 output
->screen_height
= le16_to_cpu(best_mode_info
.vesa
.y_resolution
);
698 output
->screen_linebytes
= le16_to_cpu(best_mode_info
.vesa
.bytes_per_scanline
);
699 output
->color_depth
= best_mode_info
.vesa
.bits_per_pixel
;
700 output
->framebuffer_address
=
701 le32_to_cpu(best_mode_info
.vesa
.phys_base_ptr
);
703 printf("%s: No suitable video mode found!\n", __func__
);
704 //unset display_type...
705 output
->display_type
= 0;
711 static vbe_mode_info_t mode_info
;
713 const vbe_mode_info_t
*vbe_mode_info(void)
715 if (!mode_info_valid
|| !mode_info
.vesa
.phys_base_ptr
)
720 void vbe_set_graphics(void)
725 rval
= vbe_info(&info
);
729 DEBUG_PRINTF_VBE("VbeSignature: %s\n", info
.signature
);
730 DEBUG_PRINTF_VBE("VbeVersion: 0x%04x\n", info
.version
);
731 DEBUG_PRINTF_VBE("OemString: %s\n", info
.oem_string_ptr
);
732 DEBUG_PRINTF_VBE("Capabilities:\n");
733 DEBUG_PRINTF_VBE("\tDAC: %s\n",
734 (info
.capabilities
& 0x1) ==
735 0 ? "fixed 6bit" : "switchable 6/8bit");
736 DEBUG_PRINTF_VBE("\tVGA: %s\n",
737 (info
.capabilities
& 0x2) ==
738 0 ? "compatible" : "not compatible");
739 DEBUG_PRINTF_VBE("\tRAMDAC: %s\n",
740 (info
.capabilities
& 0x4) ==
741 0 ? "normal" : "use blank bit in Function 09h");
743 mode_info
.video_mode
= (1 << 14) | CONFIG_FRAMEBUFFER_VESA_MODE
;
744 vbe_get_mode_info(&mode_info
);
745 vbe_set_mode(&mode_info
);
747 const struct lb_framebuffer fb
= {
748 .physical_address
= mode_info
.vesa
.phys_base_ptr
,
749 .x_resolution
= le16_to_cpu(mode_info
.vesa
.x_resolution
),
750 .y_resolution
= le16_to_cpu(mode_info
.vesa
.y_resolution
),
751 .bytes_per_line
= le16_to_cpu(mode_info
.vesa
.bytes_per_scanline
),
752 .bits_per_pixel
= mode_info
.vesa
.bits_per_pixel
,
753 .red_mask_pos
= mode_info
.vesa
.red_mask_pos
,
754 .red_mask_size
= mode_info
.vesa
.red_mask_size
,
755 .green_mask_pos
= mode_info
.vesa
.green_mask_pos
,
756 .green_mask_size
= mode_info
.vesa
.green_mask_size
,
757 .blue_mask_pos
= mode_info
.vesa
.blue_mask_pos
,
758 .blue_mask_size
= mode_info
.vesa
.blue_mask_size
,
759 .reserved_mask_pos
= mode_info
.vesa
.reserved_mask_pos
,
760 .reserved_mask_size
= mode_info
.vesa
.reserved_mask_size
,
761 .orientation
= LB_FB_ORIENTATION_NORMAL
,
764 fb_add_framebuffer_info_ex(&fb
);
767 void vbe_textmode_console(void)
769 /* Wait, just a little bit more, pleeeease ;-) */
772 M
.x86
.R_EAX
= 0x0003;