mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-16 07:27:35 +00:00
vesa_fb: support mode reporting and configuration
in the same format as the intel/display driver. With this commit vesa_fb can be configured and used by the sculpt_manager similar to the intel/display in Sculpt OS. Issue #5501
This commit is contained in:
parent
238b7935b2
commit
fd62057c47
@ -5,3 +5,4 @@ format
|
||||
platform_session
|
||||
timer_session
|
||||
capture_session
|
||||
report_session
|
||||
|
@ -47,6 +47,24 @@ static inline uint32_t to_phys(uint32_t addr)
|
||||
}
|
||||
|
||||
|
||||
static void for_each_mode(mb_vbe_ctrl_t const & ctrl_info, auto const & fn)
|
||||
{
|
||||
/*
|
||||
* The virtual address of the ctrl_info mapping may change on x86_cmd
|
||||
* execution. Therefore, we resolve the address on each iteration.
|
||||
*/
|
||||
#define MODE_PTR(off) (X86emu::virt_addr<uint16_t>(to_phys(ctrl_info.video_mode)) + off)
|
||||
for (unsigned off = 0; *MODE_PTR(off) != 0xFFFF; ++off) {
|
||||
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, *MODE_PTR(off), VESA_MODE_OFFS) != VBE_SUPPORTED)
|
||||
continue;
|
||||
|
||||
fn(*MODE_PTR(off));
|
||||
|
||||
}
|
||||
#undef MODE_PTR
|
||||
}
|
||||
|
||||
|
||||
static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info,
|
||||
unsigned &width, unsigned &height, unsigned depth,
|
||||
bool verbose)
|
||||
@ -58,21 +76,14 @@ static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info
|
||||
if (verbose)
|
||||
log("Supported mode list");
|
||||
|
||||
/*
|
||||
* The virtual address of the ctrl_info mapping may change on x86_cmd
|
||||
* execution. Therefore, we resolve the address on each iteration.
|
||||
*/
|
||||
#define MODE_PTR(off) (X86emu::virt_addr<uint16_t>(to_phys(ctrl_info->video_mode)) + off)
|
||||
for (unsigned off = 0; *MODE_PTR(off) != 0xFFFF; ++off) {
|
||||
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, *MODE_PTR(off), VESA_MODE_OFFS) != VBE_SUPPORTED)
|
||||
continue;
|
||||
auto const & fn = [&](auto const & mode) {
|
||||
|
||||
enum { DIRECT_COLOR = 0x06 };
|
||||
if (mode_info->memory_model != DIRECT_COLOR)
|
||||
continue;
|
||||
return;
|
||||
|
||||
if (verbose)
|
||||
log(" ", Hex((short)*MODE_PTR(off), Hex::PREFIX, Hex::PAD), " ",
|
||||
log(" ", Hex((short)mode, Hex::PREFIX, Hex::PAD), " ",
|
||||
(unsigned)mode_info->x_resolution, "x",
|
||||
(unsigned)mode_info->y_resolution, "@",
|
||||
(unsigned)mode_info->bits_per_pixel);
|
||||
@ -94,7 +105,7 @@ static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info
|
||||
*/
|
||||
width = mode_info->bytes_per_scanline / (mode_info->bits_per_pixel / 8);
|
||||
height = mode_info->y_resolution;
|
||||
ret = *MODE_PTR(off);
|
||||
ret = mode;
|
||||
}
|
||||
} else {
|
||||
if (mode_info->x_resolution == width &&
|
||||
@ -111,11 +122,12 @@ static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info
|
||||
* visible.
|
||||
*/
|
||||
width = mode_info->bytes_per_scanline / (mode_info->bits_per_pixel / 8);
|
||||
ret = *MODE_PTR(off);
|
||||
ret = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
#undef MODE_PTR
|
||||
};
|
||||
|
||||
for_each_mode(*ctrl_info, fn);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -140,6 +152,45 @@ static uint16_t get_vesa_mode(mb_vbe_ctrl_t *ctrl_info, mb_vbe_mode_t *mode_info
|
||||
}
|
||||
|
||||
|
||||
static void generate_report(Xml_generator & xml,
|
||||
mb_vbe_ctrl_t const & ctrl_info,
|
||||
mb_vbe_mode_t const & mode_info,
|
||||
unsigned const depth,
|
||||
uint16_t const vesa_mode)
|
||||
{
|
||||
xml.node("merge", [&]() {
|
||||
xml.attribute("name", "mirror");
|
||||
|
||||
xml.node("connector", [&] () {
|
||||
xml.attribute("connected", true);
|
||||
xml.attribute("name", "VESA");
|
||||
|
||||
for_each_mode(ctrl_info, [&](auto const & mode) {
|
||||
|
||||
enum { DIRECT_COLOR = 0x06 };
|
||||
if (mode_info.memory_model != DIRECT_COLOR)
|
||||
return;
|
||||
|
||||
if (mode_info.bits_per_pixel != depth)
|
||||
return;
|
||||
|
||||
auto name = String<32>(mode_info.x_resolution, "x",
|
||||
mode_info.y_resolution);
|
||||
|
||||
xml.node("mode", [&] () {
|
||||
xml.attribute( "id", mode);
|
||||
xml.attribute( "width", mode_info.x_resolution);
|
||||
xml.attribute("height", mode_info.y_resolution);
|
||||
xml.attribute( "name", name);
|
||||
if (mode == vesa_mode)
|
||||
xml.attribute("used", true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
** Driver API **
|
||||
****************/
|
||||
@ -187,12 +238,13 @@ int Framebuffer::map_io_mem(addr_t base, size_t size, bool write_combined,
|
||||
}
|
||||
|
||||
|
||||
int Framebuffer::set_mode(unsigned &width, unsigned &height, unsigned mode)
|
||||
int Framebuffer::set_mode(unsigned &width, unsigned &height,
|
||||
unsigned const depth,
|
||||
Expanding_reporter & reporter)
|
||||
{
|
||||
mb_vbe_ctrl_t *ctrl_info;
|
||||
mb_vbe_mode_t *mode_info;
|
||||
char * oem_string;
|
||||
uint16_t vesa_mode;
|
||||
|
||||
/* set location of data types */
|
||||
ctrl_info = reinterpret_cast<mb_vbe_ctrl_t*>(X86emu::x86_mem.data_addr()
|
||||
@ -210,15 +262,17 @@ int Framebuffer::set_mode(unsigned &width, unsigned &height, unsigned mode)
|
||||
}
|
||||
|
||||
/* retrieve vesa mode hex value */
|
||||
if (!(vesa_mode = get_vesa_mode(ctrl_info, mode_info, width, height, mode, verbose))) {
|
||||
warning("graphics mode ", width, "x", height, "@", mode, " not found");
|
||||
auto const vesa_mode = get_vesa_mode(ctrl_info, mode_info, width, height,
|
||||
depth, verbose);
|
||||
if (!vesa_mode) {
|
||||
warning("graphics mode ", width, "x", height, "@", depth, " not found");
|
||||
/* print available modes */
|
||||
get_vesa_mode(ctrl_info, mode_info, width, height, mode, true);
|
||||
get_vesa_mode(ctrl_info, mode_info, width, height, depth, true);
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* use current refresh rate, set flat framebuffer model */
|
||||
vesa_mode = (vesa_mode & VBE_CUR_REFRESH_MASK) | VBE_SET_FLAT_FB;
|
||||
auto const vesa_mode_cmd = (vesa_mode & VBE_CUR_REFRESH_MASK) | VBE_SET_FLAT_FB;
|
||||
|
||||
/* determine VBE version and OEM string */
|
||||
oem_string = X86emu::virt_addr<char>(to_phys(ctrl_info->oem_string));
|
||||
@ -235,16 +289,16 @@ int Framebuffer::set_mode(unsigned &width, unsigned &height, unsigned mode)
|
||||
/* get mode info */
|
||||
/* 0x91 tests MODE SUPPORTED (0x1) | GRAPHICS MODE (0x10) | LINEAR
|
||||
* FRAME BUFFER (0x80) bits */
|
||||
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode, VESA_MODE_OFFS) != VBE_SUPPORTED
|
||||
if (X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode_cmd, VESA_MODE_OFFS) != VBE_SUPPORTED
|
||||
|| (mode_info->mode_attributes & 0x91) != 0x91) {
|
||||
warning("graphics mode ", width, "x", height, "@", mode, " not supported");
|
||||
warning("graphics mode ", width, "x", height, "@", depth, " not supported");
|
||||
/* print available modes */
|
||||
get_vesa_mode(ctrl_info, mode_info, width, height, mode, true);
|
||||
get_vesa_mode(ctrl_info, mode_info, width, height, depth, true);
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* set mode */
|
||||
if ((X86emu::x86emu_cmd(VBE_MODE_FUNC, vesa_mode) & 0xFF00) != VBE_SUCCESS) {
|
||||
if ((X86emu::x86emu_cmd(VBE_MODE_FUNC, vesa_mode_cmd) & 0xFF00) != VBE_SUCCESS) {
|
||||
error("VBE SET error");
|
||||
return -5;
|
||||
}
|
||||
@ -252,7 +306,7 @@ int Framebuffer::set_mode(unsigned &width, unsigned &height, unsigned mode)
|
||||
/* map framebuffer */
|
||||
void *fb;
|
||||
if (!io_mem_cap.valid()) {
|
||||
X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode, VESA_MODE_OFFS);
|
||||
X86emu::x86emu_cmd(VBE_INFO_FUNC, 0, vesa_mode_cmd, VESA_MODE_OFFS);
|
||||
|
||||
log("Found: physical frame buffer at ", Hex(mode_info->phys_base), " "
|
||||
"size: ", ctrl_info->total_memory << 16);
|
||||
@ -263,6 +317,9 @@ int Framebuffer::set_mode(unsigned &width, unsigned &height, unsigned mode)
|
||||
if (verbose)
|
||||
X86emu::print_regions();
|
||||
|
||||
reporter.generate([&] (auto & xml) {
|
||||
generate_report(xml, *ctrl_info, *mode_info, depth, vesa_mode); });
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include <dataspace/capability.h>
|
||||
#include <base/stdint.h>
|
||||
#include <os/reporter.h>
|
||||
|
||||
#include "vbe.h"
|
||||
|
||||
@ -27,6 +28,8 @@ namespace Genode {
|
||||
|
||||
namespace Framebuffer {
|
||||
|
||||
using Genode::Expanding_reporter;
|
||||
|
||||
struct Fatal { }; /* exception */
|
||||
|
||||
/**
|
||||
@ -49,7 +52,8 @@ namespace Framebuffer {
|
||||
* \return 0 on success,
|
||||
* non-zero otherwise
|
||||
*/
|
||||
int set_mode(unsigned &width, unsigned &height, unsigned mode);
|
||||
int set_mode(unsigned &width, unsigned &height, unsigned mode,
|
||||
Expanding_reporter &);
|
||||
|
||||
/**
|
||||
* Map given device memory, return out_addr (map address)
|
||||
|
@ -46,11 +46,13 @@ struct Vesa_driver::Main
|
||||
* Config
|
||||
*/
|
||||
|
||||
Attached_rom_dataspace _config { _env, "config" };
|
||||
Attached_rom_dataspace _config { _env, "config" };
|
||||
Expanding_reporter _reporter { _env, "connectors", "connectors" };
|
||||
|
||||
Area _size { 1, 1 };
|
||||
|
||||
void _handle_config();
|
||||
Area _configured_size(Xml_node const &);
|
||||
|
||||
Signal_handler<Main> _config_handler { _env.ep(), *this, &Main::_handle_config };
|
||||
|
||||
@ -104,23 +106,62 @@ void Vesa_driver::Main::_handle_timer()
|
||||
}
|
||||
|
||||
|
||||
Capture::Area Vesa_driver::Main::_configured_size(Xml_node const & config)
|
||||
{
|
||||
Area area { config.attribute_value( "width", 0U),
|
||||
config.attribute_value("height", 0U) };
|
||||
|
||||
auto with_connector = [&](auto const &node) {
|
||||
|
||||
bool enabled = node.attribute_value("enabled", true);
|
||||
|
||||
if (!enabled || node.attribute_value("name", String<5>("none")) != "VESA")
|
||||
return;
|
||||
|
||||
auto width = node.attribute_value("width" , 0U);
|
||||
auto height = node.attribute_value("height" , 0U);
|
||||
|
||||
area = { width, height };
|
||||
};
|
||||
|
||||
/* lookup config of discrete connectors */
|
||||
config.for_each_sub_node("connector", [&] (auto const &conn) {
|
||||
with_connector(conn);
|
||||
});
|
||||
|
||||
/* lookup config of mirrored connectors */
|
||||
config.with_optional_sub_node("merge", [&] (auto const & merge) {
|
||||
merge.for_each_sub_node("connector", [&] (auto const & conn) {
|
||||
with_connector(conn);
|
||||
});
|
||||
});
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
|
||||
void Vesa_driver::Main::_handle_config()
|
||||
{
|
||||
_config.update();
|
||||
|
||||
Xml_node const config = _config.xml();
|
||||
if (!_config.valid())
|
||||
return;
|
||||
|
||||
auto const & config = _config.xml();
|
||||
auto const period_ms = config.attribute_value("period_ms", 20UL);
|
||||
Area const configured_size = _configured_size(config);
|
||||
|
||||
Area const configured_size { config.attribute_value("width", 0U),
|
||||
config.attribute_value("height", 0U) };
|
||||
if (configured_size == _size)
|
||||
return;
|
||||
|
||||
_size = Area { };
|
||||
auto const old_size = _size;
|
||||
|
||||
_size = { };
|
||||
_fb_ds.destruct();
|
||||
_timer.trigger_periodic(0);
|
||||
|
||||
/* set VESA mode */
|
||||
{
|
||||
auto apply_mode = [&] (auto const configure) {
|
||||
enum { BITS_PER_PIXEL = 32 };
|
||||
|
||||
struct Pretty_mode
|
||||
@ -130,22 +171,29 @@ void Vesa_driver::Main::_handle_config()
|
||||
Genode::print(out, "VESA mode ", size, "@", (int)BITS_PER_PIXEL); }
|
||||
};
|
||||
|
||||
unsigned width = configured_size.w,
|
||||
height = configured_size.h;
|
||||
unsigned width = configure.w,
|
||||
height = configure.h;
|
||||
|
||||
if (Framebuffer::set_mode(width, height, BITS_PER_PIXEL) != 0) {
|
||||
warning("could not set ", Pretty_mode{configured_size});
|
||||
return;
|
||||
if (Framebuffer::set_mode(width, height, BITS_PER_PIXEL, _reporter) != 0) {
|
||||
warning("could not set ", Pretty_mode{configure});
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Framebuffer::set_mode may return a size different from the passed
|
||||
* argument. In paricular, when passing a size of (0,0), the function
|
||||
* argument. In particular, when passing a size of (0,0), the function
|
||||
* sets and returns the highest screen mode possible.
|
||||
*/
|
||||
_size = Area { width, height };
|
||||
|
||||
log("using ", Pretty_mode{_size});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!apply_mode(configured_size)) {
|
||||
/* in case of failure try to re-setup previous mode */
|
||||
apply_mode(old_size);
|
||||
}
|
||||
|
||||
/* enable pixel capturing */
|
||||
@ -159,7 +207,6 @@ void Vesa_driver::Main::_handle_config()
|
||||
.rotate = { },
|
||||
.flip = { } });
|
||||
|
||||
unsigned long const period_ms = config.attribute_value("period_ms", 20U);
|
||||
_timer.trigger_periodic(period_ms*1000);
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,7 @@
|
||||
<binary name="vesa_fb"/>
|
||||
<route>
|
||||
<service name="ROM" label="config"> <parent label="fb.config"/> </service>
|
||||
<service name="Report"> <child name="report_rom"/> </service>
|
||||
<service name="Platform"> <child name="platform"/> </service>
|
||||
<service name="IO_PORT"> <parent/> </service>
|
||||
<service name="IO_MEM"> <parent/> </service>
|
||||
|
Loading…
x
Reference in New Issue
Block a user