From fd62057c470411c5044a17386be453118a2fb6ec Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 9 Apr 2025 16:54:24 +0200 Subject: [PATCH] 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 --- repos/libports/recipes/src/vesa_fb/used_apis | 1 + .../driver/framebuffer/vesa/framebuffer.cc | 107 ++++++++++++++---- .../framebuffer/vesa/include/framebuffer.h | 6 +- .../src/driver/framebuffer/vesa/main.cc | 73 +++++++++--- .../raw/drivers_interactive-pc/drivers.config | 1 + 5 files changed, 149 insertions(+), 39 deletions(-) diff --git a/repos/libports/recipes/src/vesa_fb/used_apis b/repos/libports/recipes/src/vesa_fb/used_apis index 7bf66d0271..e7f78490cf 100644 --- a/repos/libports/recipes/src/vesa_fb/used_apis +++ b/repos/libports/recipes/src/vesa_fb/used_apis @@ -5,3 +5,4 @@ format platform_session timer_session capture_session +report_session diff --git a/repos/libports/src/driver/framebuffer/vesa/framebuffer.cc b/repos/libports/src/driver/framebuffer/vesa/framebuffer.cc index 101f108db3..300e86c30c 100644 --- a/repos/libports/src/driver/framebuffer/vesa/framebuffer.cc +++ b/repos/libports/src/driver/framebuffer/vesa/framebuffer.cc @@ -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(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(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(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(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; } diff --git a/repos/libports/src/driver/framebuffer/vesa/include/framebuffer.h b/repos/libports/src/driver/framebuffer/vesa/include/framebuffer.h index 249682c198..cb0cd8573d 100644 --- a/repos/libports/src/driver/framebuffer/vesa/include/framebuffer.h +++ b/repos/libports/src/driver/framebuffer/vesa/include/framebuffer.h @@ -17,6 +17,7 @@ #include #include +#include #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) diff --git a/repos/libports/src/driver/framebuffer/vesa/main.cc b/repos/libports/src/driver/framebuffer/vesa/main.cc index 635794bdd3..ee0359120c 100644 --- a/repos/libports/src/driver/framebuffer/vesa/main.cc +++ b/repos/libports/src/driver/framebuffer/vesa/main.cc @@ -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
_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); } diff --git a/repos/os/recipes/raw/drivers_interactive-pc/drivers.config b/repos/os/recipes/raw/drivers_interactive-pc/drivers.config index 2f0a376ea2..dec144198f 100644 --- a/repos/os/recipes/raw/drivers_interactive-pc/drivers.config +++ b/repos/os/recipes/raw/drivers_interactive-pc/drivers.config @@ -87,6 +87,7 @@ +