From 9e69c7301ad1bea5b86f53d5a547c73287109b3d Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 18 Apr 2024 14:18:58 +0200 Subject: [PATCH] sculpt: safeguard the offering of suspend/resume The USB host controller gets restarted during the suspend-resume cycle. Hence, don't offer suspend while any USB storage device is in use, in particular when deploying Sculpt from a USB stick. Suspend/resume is not supposed to work with any framebuffer driver other than intel_fb. Therefore, offer the suspend feature only when using intel_fb. Issue #5174 --- repos/gems/src/app/sculpt_manager/driver/fb.h | 7 +++++++ repos/gems/src/app/sculpt_manager/driver/usb.h | 14 +++++++++++--- repos/gems/src/app/sculpt_manager/drivers.cc | 7 +++++++ repos/gems/src/app/sculpt_manager/drivers.h | 4 ++++ repos/gems/src/app/sculpt_manager/main.cc | 2 +- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/repos/gems/src/app/sculpt_manager/driver/fb.h b/repos/gems/src/app/sculpt_manager/driver/fb.h index 279489df1e..f6360b65ac 100644 --- a/repos/gems/src/app/sculpt_manager/driver/fb.h +++ b/repos/gems/src/app/sculpt_manager/driver/fb.h @@ -141,6 +141,13 @@ struct Sculpt::Fb_driver : private Noncopyable _boot_fb.construct(registry, "boot_fb", Priority::MULTIMEDIA, mode.ram_quota(), Cap_quota { 100 }); }); } + + static bool suspend_supported(Board_info const &board_info) + { + /* offer suspend/resume only when using intel graphics */ + return board_info.detected.intel_gfx + && !board_info.options.suppress.intel_gpu; + } }; #endif /* _DRIVER__FB_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/driver/usb.h b/repos/gems/src/app/sculpt_manager/driver/usb.h index 5a0a9fc984..0584525241 100644 --- a/repos/gems/src/app/sculpt_manager/driver/usb.h +++ b/repos/gems/src/app/sculpt_manager/driver/usb.h @@ -37,21 +37,27 @@ struct Sculpt::Usb_driver : private Noncopyable Constructible _hcd { }, _hid { }, _net { }; - static constexpr unsigned CLASS_HID = 3, CLASS_NET = 2; + static constexpr unsigned CLASS_HID = 3, CLASS_NET = 2, CLASS_STORAGE = 8; struct Detected { bool hid, net; + bool storage_aquired; static Detected from_xml(Xml_node const &devices) { Detected result { }; devices.for_each_sub_node("device", [&] (Xml_node const &device) { + bool const acquired = device.attribute_value("acquired", false); device.for_each_sub_node("config", [&] (Xml_node const &config) { config.for_each_sub_node("interface", [&] (Xml_node const &interface) { unsigned const class_id = interface.attribute_value("class", 0u); - result.hid |= (class_id == CLASS_HID); - result.net |= (class_id == CLASS_NET); }); }); }); + result.hid |= (class_id == CLASS_HID); + result.net |= (class_id == CLASS_NET); + result.storage_aquired |= (class_id == CLASS_STORAGE) && acquired; + }); + }); + }); return result; } @@ -183,6 +189,8 @@ struct Sculpt::Usb_driver : private Noncopyable _devices.with_xml([&] (Xml_node const &devices) { fn(_hcd.constructed() ? devices : Xml_node("")); }); } + + bool suspend_supported() const { return !_detected.storage_aquired; } }; #endif /* _DRIVER__USB_H_ */ diff --git a/repos/gems/src/app/sculpt_manager/drivers.cc b/repos/gems/src/app/sculpt_manager/drivers.cc index ac68c58cb4..fde82b5e28 100644 --- a/repos/gems/src/app/sculpt_manager/drivers.cc +++ b/repos/gems/src/app/sculpt_manager/drivers.cc @@ -165,6 +165,12 @@ class Sculpt::Drivers::Instance : Noncopyable, void with(With_board_info::Callback const &fn) const { fn(_board_info); } void with(With_platform_info::Callback const &fn) const { fn(_platform.xml()); } + bool suspend_supported() const + { + return _fb_driver.suspend_supported(_board_info) + && _usb_driver.suspend_supported(); + } + bool ready_for_suspend() const { return !_board_info.used.any(); } Resumed resumed() const { return _resumed; } @@ -201,6 +207,7 @@ void Drivers::update_options(Board_info::Options opt) { _instance.update_options void Drivers::gen_start_nodes(Xml_generator &xml) const { _instance.gen_start_nodes(xml); } +bool Drivers::suspend_supported() const { return _instance.suspend_supported(); }; bool Drivers::ready_for_suspend() const { return _instance.ready_for_suspend(); }; Drivers::Resumed Drivers::resumed() const { return _instance.resumed(); }; diff --git a/repos/gems/src/app/sculpt_manager/drivers.h b/repos/gems/src/app/sculpt_manager/drivers.h index 750bcfce01..09bea3fa25 100644 --- a/repos/gems/src/app/sculpt_manager/drivers.h +++ b/repos/gems/src/app/sculpt_manager/drivers.h @@ -73,6 +73,10 @@ class Sculpt::Drivers : Noncopyable void with_board_info (auto const &fn) const { _with(With_board_info::Fn { fn }); } void with_platform_info (auto const &fn) const { _with(With_platform_info::Fn { fn }); } + /* true if hardware is suspend/resume capable */ + bool suspend_supported() const; + + /* true once 'Board_info::Option::suspending' phase is compete */ bool ready_for_suspend() const; struct Resumed { unsigned count; }; diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc index 4e82f20b5d..e87315d6f4 100644 --- a/repos/gems/src/app/sculpt_manager/main.cc +++ b/repos/gems/src/app/sculpt_manager/main.cc @@ -2204,7 +2204,7 @@ void Sculpt::Main::_handle_runtime_state(Xml_node const &state) bool const acpi_support = _runtime_state.present_in_runtime("acpi_support"); Power_features const orig_power_features = _power_features; _power_features.poweroff = acpi_support; - _power_features.suspend = acpi_support; + _power_features.suspend = acpi_support && _drivers.suspend_supported();; if (orig_power_features != _power_features) _system_dialog.refresh(); }