aboutsummaryrefslogtreecommitdiff
path: root/kernel/kapi/devices/power.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kapi/devices/power.cpp')
-rw-r--r--kernel/kapi/devices/power.cpp93
1 files changed, 93 insertions, 0 deletions
diff --git a/kernel/kapi/devices/power.cpp b/kernel/kapi/devices/power.cpp
new file mode 100644
index 00000000..3bc66848
--- /dev/null
+++ b/kernel/kapi/devices/power.cpp
@@ -0,0 +1,93 @@
+#include <kapi/devices/power.hpp>
+
+#include <kapi/devices.hpp>
+
+#include <kstd/memory.hpp>
+#include <kstd/print.hpp>
+#include <kstd/result.hpp>
+#include <kstd/vector.hpp>
+
+#include <ranges>
+
+namespace kapi::devices
+{
+
+ namespace
+ {
+ auto resume_subtree(device & node) -> void;
+
+ // NOLINTNEXTLINE(misc-no-recursion)
+ auto suspend_subtree(device & node) -> kstd::result<void>
+ {
+ auto suspended_children = kstd::vector<kstd::shared_ptr<device>>{};
+
+ if (auto as_bus = node.facet<bus>())
+ {
+ for (auto const & child : as_bus->children())
+ {
+ auto result = suspend_subtree(*child);
+ if (!result)
+ {
+ for (auto const & already_suspended : std::views::reverse(suspended_children))
+ {
+ resume_subtree(*already_suspended);
+ }
+
+ return result;
+ }
+
+ suspended_children.push_back(child);
+ }
+ }
+
+ if (auto driver = node.bound_driver())
+ {
+ auto result = driver->suspend(node);
+ if (!result)
+ {
+ for (auto const & already_suspended : std::views::reverse(suspended_children))
+ {
+ resume_subtree(*already_suspended);
+ }
+
+ return result;
+ }
+ }
+
+ return kstd::success();
+ }
+
+ // NOLINTNEXTLINE(misc-no-recursion)
+ auto resume_subtree(device & node) -> void
+ {
+ if (auto driver = node.bound_driver())
+ {
+ auto result = driver->resume(node);
+ if (!result)
+ {
+ kstd::println(kstd::print_sink::stderr, "[OS:PM] failed to resume device '{}': {}", node.name(),
+ result.error().message());
+ }
+ }
+
+ if (auto as_bus = node.facet<bus>())
+ {
+ for (auto const & child : as_bus->children())
+ {
+ resume_subtree(*child);
+ }
+ }
+ }
+ } // namespace
+
+ auto suspend_tree(bus & root) -> kstd::result<void>
+ {
+ return suspend_subtree(root);
+ }
+
+ auto resume_tree(bus & root) -> void
+ {
+ resume_subtree(root);
+ }
+
+} // namespace kapi::devices \ No newline at end of file