VESA driver: choose highest resolution video mode

With this patch, the VESA driver chooses the video mode with the highest
resolution from the list of available modes if no resolution is
explicitly configured.

Fixes #1263.
This commit is contained in:
Christian Prochaska 2014-09-25 18:30:50 +02:00 committed by Christian Helmuth
parent b32b6948c7
commit 4d4d3cb9bb
3 changed files with 49 additions and 67 deletions

View File

@ -46,9 +46,11 @@ static inline uint32_t to_phys(uint32_t addr)
static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info,
unsigned long width, unsigned long height,
unsigned long &width, unsigned long &height,
unsigned long depth, bool verbose)
{
bool choose_highest_resolution_mode = ((width == 0) || (height == 0));
uint16_t ret = 0;
if (verbose)
@ -72,10 +74,22 @@ static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info
mode_info->y_resolution,
mode_info->bits_per_pixel);
if (mode_info->x_resolution == width &&
mode_info->y_resolution == height &&
mode_info->bits_per_pixel == depth)
ret = *MODE_PTR(off);
if (choose_highest_resolution_mode) {
if ((mode_info->bits_per_pixel == depth) &&
((mode_info->x_resolution > width) ||
((mode_info->x_resolution == width) &&
(mode_info->y_resolution > height)))) {
width = mode_info->x_resolution;
height = mode_info->y_resolution;
ret = *MODE_PTR(off);
}
} else {
if (mode_info->x_resolution == width &&
mode_info->y_resolution == height &&
mode_info->bits_per_pixel == depth)
ret = *MODE_PTR(off);
}
}
#undef MODE_PTR
@ -85,6 +99,19 @@ static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info
if (verbose)
PWRN("Searching in default vesa modes");
if (choose_highest_resolution_mode) {
/*
* We did not find any mode for the given color depth so far.
* Default to 1024x768 for now.
*/
ret = get_default_vesa_mode(1024, 768, depth);
if (ret != 0) {
width = 1024;
height = 768;
}
return ret;
}
return get_default_vesa_mode(width, height, depth);
}
@ -124,52 +151,7 @@ int Framebuffer_drv::map_io_mem(addr_t base, size_t size, bool write_combined,
}
int Framebuffer_drv::use_current_mode()
{
mb_vbe_ctrl_t *ctrl_info;
mb_vbe_mode_t *mode_info;
/* set location of data types */
ctrl_info = reinterpret_cast<mb_vbe_ctrl_t*>(X86emu::x86_mem.data_addr()
+ VESA_CTRL_OFFS);
mode_info = reinterpret_cast<mb_vbe_mode_t*>(X86emu::x86_mem.data_addr()
+ VESA_MODE_OFFS);
/* retrieve controller information */
if (X86emu::x86emu_cmd(VBE_CONTROL_FUNC, 0, 0, VESA_CTRL_OFFS) != VBE_SUPPORTED) {
PWRN("VBE Bios not present");
return -1;
}
/* retrieve current video mode */
uint16_t vesa_mode = 0;
if (X86emu::x86emu_cmd(VBE_GMODE_FUNC, 0, 0, 0, &vesa_mode) != VBE_SUPPORTED) {
PWRN("VBE Bios not present");
return -1;
}
vesa_mode &= 0x3fff;
/* retrieve framebuffer info for current mode */
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode, VESA_MODE_OFFS) != VBE_SUPPORTED) {
PWRN("VBE Info function failed");
return -2;
}
if (!io_mem_cap.valid()) {
printf("Found: physical frame buffer at 0x%08x size: 0x%08x\n",
mode_info->phys_base,
ctrl_info->total_memory << 16);
void *fb;
map_io_mem(mode_info->phys_base, ctrl_info->total_memory << 16, true,
&fb, 0, &io_mem_cap);
}
return 0;
}
int Framebuffer_drv::set_mode(unsigned long width, unsigned long height,
int Framebuffer_drv::set_mode(unsigned long &width, unsigned long &height,
unsigned long mode)
{
mb_vbe_ctrl_t *ctrl_info;
@ -195,7 +177,8 @@ int Framebuffer_drv::set_mode(unsigned long width, unsigned long height,
/* retrieve vesa mode hex value */
if (!(vesa_mode = get_vesa_mode(ctrl_info, mode_info, width, height, mode, verbose))) {
PWRN("graphics mode %lux%lu@%lu not found", width, height, mode);
get_vesa_mode(ctrl_info, mode_info, 0, 0, 0, true);
/* print available modes */
get_vesa_mode(ctrl_info, mode_info, width, height, mode, true);
return -2;
}
@ -220,7 +203,8 @@ int Framebuffer_drv::set_mode(unsigned long width, unsigned long height,
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode, VESA_MODE_OFFS) != VBE_SUPPORTED
|| (mode_info->mode_attributes & 0x91) != 0x91) {
PWRN("graphics mode %lux%lu@%lu not supported", width, height, mode);
get_vesa_mode(ctrl_info, mode_info, 0, 0, 0, true);
/* print available modes */
get_vesa_mode(ctrl_info, mode_info, width, height, mode, true);
return -4;
}

View File

@ -35,12 +35,14 @@ namespace Framebuffer_drv {
/**
* Set video, initialize framebuffer dataspace
*
* If either 'width' or 'height' is 0, the mode with the highest resolution
* for the given color depth is chosen and 'width' and 'height' are updated
* accordingly.
*
* \return 0 on success,
* non-zero otherwise
*/
int set_mode(unsigned long width, unsigned long height, unsigned long mode);
int use_current_mode();
int set_mode(unsigned long &width, unsigned long &height, unsigned long mode);
/**
* Map given device memory, return out_addr (map address)

View File

@ -209,23 +209,19 @@ namespace Framebuffer {
Session_component *_create_session(const char *args) override
{
unsigned long scr_width = session_arg("width", args, "fb_width", 1024),
scr_height = session_arg("height", args, "fb_height", 768),
scr_mode = session_arg("depth", args, "fb_mode", 16);
bool buffered = config_attribute("buffered");
bool use_current_mode = config_attribute("preinit");
unsigned long scr_width = session_arg("width", args, "fb_width", 0),
scr_height = session_arg("height", args, "fb_height", 0),
scr_mode = session_arg("depth", args, "fb_mode", 16);
bool buffered = config_attribute("buffered");
if (use_current_mode) {
if (Framebuffer_drv::use_current_mode()) {
PWRN("Could not use preinitialized VESA mode");
throw Root::Invalid_args();
}
} else if (Framebuffer_drv::set_mode(scr_width, scr_height, scr_mode)) {
if (Framebuffer_drv::set_mode(scr_width, scr_height, scr_mode) != 0) {
PWRN("Could not set vesa mode %lux%lu@%lu", scr_width, scr_height,
scr_mode);
throw Root::Invalid_args();
}
printf("Using video mode: %lu x %lu x %lu\n", scr_width, scr_height, scr_mode);
return new (md_alloc()) Session_component(scr_width, scr_height, scr_mode,
Framebuffer_drv::hw_framebuffer(),
buffered);