diff --git a/.gitignore b/.gitignore index 8d235fc8..bec5eaa6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ cargo-config .idea vendor-* vendor_* +.vscode-ctags diff --git a/CHANGELOG.md b/CHANGELOG.md index 18b391d8..c2319347 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 + Support 8bit RGB, RGBA, 16bit Greyscalw, RGB, RGBA + add `AsusImage` type for slanted-template pixel-perfect images + `BREAKING:` plain `Image` with time period is changed and old anime configs break as a result (sorry) +- LED: + + By popular request LED prev/next cycle is added +### BREAKING CHANGES +- Graphics control: + + graphics control is pulled out of asusd and moved to new package; https://gitlab.com/asus-linux/supergfxctl +- Proflies: + + profiles now depend on power-profile-daemon plus kernel patches for support of platform_profile + - if your system supports fan-curves you will also require upcoming kernel patches for this + + profiles are now moved to a new file # [3.7.2] - 2021-08-02 ### Added diff --git a/Cargo.lock b/Cargo.lock index 0a29491a..03220719 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,19 +31,21 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "asus-notify" -version = "3.0.1" +version = "3.0.2" dependencies = [ "notify-rust", "rog_aura", "rog_dbus", "rog_profiles", - "rog_types", + "rog_supported", "serde_json", + "supergfxctl", + "zbus", ] [[package]] name = "asusctl" -version = "3.5.1" +version = "4.0.0" dependencies = [ "daemon", "gif", @@ -52,11 +54,11 @@ dependencies = [ "rog_anime", "rog_aura", "rog_dbus", - "rog_fan_curve 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rog_profiles", - "rog_types", + "rog_supported", + "supergfxctl", "tinybmp", - "yansi-term", + "zbus", ] [[package]] @@ -109,9 +111,9 @@ checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "blake2b_simd" @@ -206,7 +208,7 @@ dependencies = [ [[package]] name = "daemon" -version = "3.7.2" +version = "4.0.0" dependencies = [ "env_logger", "log", @@ -214,9 +216,8 @@ dependencies = [ "rog_anime", "rog_aura", "rog_dbus", - "rog_fan_curve 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rog_profiles", - "rog_types", + "rog_supported", "rusb", "serde", "serde_derive", @@ -236,7 +237,7 @@ dependencies = [ "dirs 3.0.2", "rog_anime", "rog_dbus", - "rog_types", + "rog_supported", "serde", "serde_derive", "serde_json", @@ -253,7 +254,7 @@ checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -305,7 +306,7 @@ checksum = "946ee94e3dbf58fdd324f9ce245c7b238d46a66f00e86a020b71996349e46cce" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -403,7 +404,7 @@ dependencies = [ "proc-macro-hack", "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -497,7 +498,7 @@ checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -524,21 +525,11 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "intel-pstate" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dbd48c2f4886e44c137f4acb6ba3cf8df15154a2c996a65ee5e57c54a04c01f" -dependencies = [ - "smart-default", - "thiserror", -] - [[package]] name = "itoa" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "lazy_static" @@ -548,9 +539,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.99" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libudev-sys" @@ -620,9 +611,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "miniz_oxide" @@ -650,7 +641,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "cc", "cfg-if 0.1.10", "libc", @@ -861,7 +852,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", ] [[package]] @@ -928,37 +919,22 @@ dependencies = [ [[package]] name = "rog_dbus" -version = "3.5.1" +version = "4.0.0" dependencies = [ "rog_anime", "rog_aura", "rog_profiles", - "rog_types", + "rog_supported", + "supergfxctl", "zbus", "zbus_macros", "zvariant", ] -[[package]] -name = "rog_fan_curve" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a810b86236d51df31d9098ba1a1876c9f470573f903d13b78f5ee48d4e99ee90" -dependencies = [ - "serde", -] - -[[package]] -name = "rog_fan_curve" -version = "0.1.10" -source = "git+https://github.com/Yarn/rog_fan_curve.git#d46ead0db7c8c4870dae960c3a43b4ac6ab57c2d" - [[package]] name = "rog_profiles" -version = "0.1.2" +version = "1.0.0" dependencies = [ - "intel-pstate", - "rog_fan_curve 0.1.10 (git+https://github.com/Yarn/rog_fan_curve.git)", "serde", "serde_derive", "zvariant", @@ -966,8 +942,8 @@ dependencies = [ ] [[package]] -name = "rog_types" -version = "3.2.0" +name = "rog_supported" +version = "4.0.0" dependencies = [ "rog_aura", "serde", @@ -1012,22 +988,22 @@ checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "serde" -version = "1.0.127" +version = "1.0.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1049,7 +1025,7 @@ checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1058,17 +1034,6 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote 1.0.9", - "syn 1.0.74", -] - [[package]] name = "socket2" version = "0.4.1" @@ -1101,6 +1066,22 @@ dependencies = [ "syn 0.11.11", ] +[[package]] +name = "supergfxctl" +version = "2.0.0" +source = "git+https://gitlab.com/asus-linux/supergfxctl.git?tag=2.0.0#3f040cd3ec334242631122cd038aa361cc860be6" +dependencies = [ + "log", + "logind-zbus", + "serde", + "serde_derive", + "serde_json", + "sysfs-class", + "zbus", + "zvariant", + "zvariant_derive", +] + [[package]] name = "syn" version = "0.11.11" @@ -1114,9 +1095,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.74" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" dependencies = [ "proc-macro2", "quote 1.0.9", @@ -1167,7 +1148,7 @@ checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" dependencies = [ "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1334,15 +1315,6 @@ dependencies = [ "bitflags 0.9.1", ] -[[package]] -name = "yansi-term" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" -dependencies = [ - "winapi", -] - [[package]] name = "zbus" version = "1.9.1" @@ -1375,7 +1347,7 @@ dependencies = [ "proc-macro-crate 0.1.5", "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] [[package]] @@ -1400,5 +1372,5 @@ dependencies = [ "proc-macro-crate 1.0.0", "proc-macro2", "quote 1.0.9", - "syn 1.0.74", + "syn 1.0.75", ] diff --git a/Cargo.toml b/Cargo.toml index 774d9f13..40cd341e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-types", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles"] +members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-supported", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles"] [profile.release] lto = true @@ -13,4 +13,4 @@ opt-level = 1 [profile.bench] debug = false -opt-level = 3 \ No newline at end of file +opt-level = 3 diff --git a/Makefile b/Makefile index 0125072d..c0e7265d 100644 --- a/Makefile +++ b/Makefile @@ -16,8 +16,6 @@ BIN_D := asusd BIN_U := asusd-user BIN_N := asus-notify LEDCFG := asusd-ledmodes.toml -X11CFG := 90-nvidia-screen-G05.conf -PMRULES := 90-asusd-nvidia-pm.rules SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs') @@ -45,14 +43,15 @@ install: $(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)" $(INSTALL_PROGRAM) "./target/release/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)" $(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)" - $(INSTALL_DATA) "./data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)" + $(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules" $(INSTALL_DATA) "./data/$(LEDCFG)" "$(DESTDIR)/etc/asusd/$(LEDCFG)" $(INSTALL_DATA) "./data/$(BIN_D).conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf" - $(INSTALL_DATA) "./data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)" + $(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service" $(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service" $(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service" + $(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png" $(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png" $(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png" @@ -63,9 +62,10 @@ install: $(INSTALL_DATA) "./data/icons/scalable/gpu-nvidia.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-nvidia.svg" $(INSTALL_DATA) "./data/icons/scalable/gpu-vfio.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-vfio.svg" $(INSTALL_DATA) "./data/icons/scalable/notification-reboot.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/notification-reboot.svg" + $(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl" $(INSTALL_DATA) "./data/completions/asusctl.fish" "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish" - cd data && find "./anime" -type f -exec install -Dm 755 "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \; + cd rog-anime/data && find "./anime" -type f -exec install -Dm 755 "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \; uninstall: rm -f "$(DESTDIR)$(bindir)/$(BIN_C)" diff --git a/asus-notify/Cargo.toml b/asus-notify/Cargo.toml index 251708a2..5bb57b2c 100644 --- a/asus-notify/Cargo.toml +++ b/asus-notify/Cargo.toml @@ -1,18 +1,20 @@ [package] name = "asus-notify" -version = "3.0.1" +version = "3.0.2" authors = ["Luke D Jones "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +zbus = "^1.9" # serialisation serde_json = "^1.0" rog_dbus = { path = "../rog-dbus" } rog_aura = { path = "../rog-aura" } -rog_types = { path = "../rog-types" } +rog_supported = { path = "../rog-supported" } rog_profiles = { path = "../rog-profiles" } +supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", tag = "2.0.0" } [dependencies.notify-rust] version = "^4.3" diff --git a/asus-notify/src/main.rs b/asus-notify/src/main.rs index 71910957..76353279 100644 --- a/asus-notify/src/main.rs +++ b/asus-notify/src/main.rs @@ -1,13 +1,15 @@ use notify_rust::{Hint, Notification, NotificationHandle}; use rog_aura::AuraEffect; use rog_dbus::{DbusProxies, Signals}; -use rog_profiles::profiles::{FanLevel, Profile}; -use rog_types::gfx_vendors::GfxRequiredUserAction; -use rog_types::gfx_vendors::GfxVendors; +use rog_profiles::Profile; use std::error::Error; -use std::process; +use std::sync::mpsc::channel; use std::thread::sleep; use std::time::Duration; +use std::{process, thread}; +use supergfxctl::gfx_vendors::{GfxRequiredUserAction, GfxVendors}; +use supergfxctl::zbus_proxy::GfxProxy; +use zbus::Connection; const NOTIF_HEADER: &str = "ROG Control"; @@ -35,6 +37,7 @@ macro_rules! base_notification { fn main() -> Result<(), Box> { println!("asus-notify version {}", env!("CARGO_PKG_VERSION")); println!(" rog-dbus version {}", rog_dbus::VERSION); + println!("supergfxctl version {}", supergfxctl::VERSION); let (proxies, conn) = DbusProxies::new()?; let signals = Signals::new(&proxies)?; @@ -43,6 +46,9 @@ fn main() -> Result<(), Box> { let recv = proxies.setup_recv(conn); let mut err_count = 0; + + gfx_thread()?; + loop { sleep(Duration::from_millis(100)); if let Err(err) = recv.next_signal() { @@ -68,39 +74,71 @@ fn main() -> Result<(), Box> { if let Ok(data) = signals.charge.try_recv() { notify!(do_charge_notif, last_notification, &data); } - if let Ok(data) = signals.gfx_vendor.try_recv() { + } +} + +fn gfx_thread() -> Result<(), Box> { + let mut last_notification: Option = None; + + let conn = Connection::new_system()?; + let proxy = GfxProxy::new(&conn)?; + + let (tx1, rx1) = channel(); + proxy.connect_notify_gfx(tx1)?; + + let (tx2, rx2) = channel(); + proxy.connect_notify_action(tx2)?; + + thread::spawn(move || loop { + if proxy + .next_signal() + .map_err(|e| println!("Error: {}", e)) + .is_err() + { + break; + } + + if let Ok(data) = rx1.try_recv() { notify!(do_gfx_notif, last_notification, &data); } - if let Ok(data) = signals.gfx_action.try_recv() { + + if let Ok(data) = rx2.try_recv() { match data { GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => { - do_gfx_action_notif(&data)?; + do_gfx_action_notif(&data) + .map_err(|e| { + println!("Error: {}", e); + }) + .ok(); } GfxRequiredUserAction::Integrated => { base_notification!( "You must be in integrated mode first to switch to the requested mode" - )?; + ) + .map_err(|e| { + println!("Error: {}", e); + }) + .ok(); } GfxRequiredUserAction::None => {} } } - } + }); + Ok(()) } fn do_thermal_notif(profile: &Profile) -> Result> { - let fan = profile.fan_preset; - let turbo = if profile.turbo { "enabled" } else { "disabled" }; - let icon = match fan { - FanLevel::Normal => "asus_notif_yellow", - FanLevel::Boost => "asus_notif_red", - FanLevel::Silent => "asus_notif_green", + let icon = match profile { + Profile::Balanced => "asus_notif_yellow", + Profile::Performance => "asus_notif_red", + Profile::Quiet => "asus_notif_green", }; + let profile: &str = (*profile).into(); let x = Notification::new() .summary("ASUS ROG") .body(&format!( - "Thermal profile changed to {}, turbo {}", - profile.name.to_uppercase(), - turbo + "Thermal profile changed to {}", + profile.to_uppercase(), )) .hint(Hint::Resident(true)) .timeout(2000) diff --git a/asusctl/Cargo.toml b/asusctl/Cargo.toml index b9cbd593..8d2fbe07 100644 --- a/asusctl/Cargo.toml +++ b/asusctl/Cargo.toml @@ -1,21 +1,21 @@ [package] name = "asusctl" -version = "3.5.1" +version = "4.0.0" authors = ["Luke D Jones "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +zbus = "^1.9.1" rog_anime = { path = "../rog-anime" } rog_aura = { path = "../rog-aura" } rog_dbus = { path = "../rog-dbus" } rog_profiles = { path = "../rog-profiles" } -rog_types = { path = "../rog-types" } +rog_supported = { path = "../rog-supported" } daemon = { path = "../daemon" } -rog_fan_curve = { version = "^0.1", features = ["serde"] } gumdrop = "^0.8" -yansi-term = "^0.1" +supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", tag = "2.0.0" } [dev-dependencies] tinybmp = "^0.2.3" diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index cf736f8c..20669e72 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -9,17 +9,17 @@ use profiles_cli::ProfileCommand; use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN}; use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClient; -use rog_profiles::profiles::Profile; -use rog_types::{ - gfx_vendors::{GfxRequiredUserAction, GfxVendors}, - supported::{ - AnimeSupportedFunctions, FanCpuSupportedFunctions, LedSupportedFunctions, - RogBiosSupportedFunctions, - }, +use rog_supported::{ + AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions, + RogBiosSupportedFunctions, }; -use std::{env::args, path::Path}; -use yansi_term::Colour::Green; -use yansi_term::Colour::Red; +use std::{env::args, path::Path, sync::mpsc::channel}; +use supergfxctl::{ + gfx_vendors::{GfxRequiredUserAction, GfxVendors}, + special::{get_asus_gsync_gfx_mode, has_asus_gsync_gfx_mode}, + zbus_proxy::GfxProxy, +}; +use zbus::Connection; #[derive(Default, Options)] struct CliStart { @@ -31,6 +31,10 @@ struct CliStart { show_supported: bool, #[options(meta = "", help = "")] kbd_bright: Option, + #[options(help = "Toggle to next keyboard brightness")] + next_kbd_bright: bool, + #[options(help = "Toggle to previous keyboard brightness")] + prev_kbd_bright: bool, #[options(meta = "", help = "<20-100>")] chg_limit: Option, #[options(command)] @@ -139,26 +143,27 @@ fn main() -> Result<(), Box> { if parsed.version { println!("\nApp and daemon versions:"); - println!(" asusctl v{}", env!("CARGO_PKG_VERSION")); - println!(" asusd v{}", daemon::VERSION); + println!(" asusctl v{}", env!("CARGO_PKG_VERSION")); + println!(" asusd v{}", daemon::VERSION); println!("\nComponent crate versions:"); - println!(" rog-anime v{}", rog_anime::VERSION); - println!(" rog-aura v{}", rog_aura::VERSION); - println!(" rog-dbus v{}", rog_dbus::VERSION); - println!("rog-profiles v{}", rog_profiles::VERSION); - println!(" rog-types v{}", rog_types::VERSION); + println!(" rog-anime v{}", rog_anime::VERSION); + println!(" rog-aura v{}", rog_aura::VERSION); + println!(" rog-dbus v{}", rog_dbus::VERSION); + println!(" rog-profiles v{}", rog_profiles::VERSION); + println!("rog-supported v{}", rog_supported::VERSION); + println!(" supergfxctl v{}", supergfxctl::VERSION); return Ok(()); } match parsed.command { Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?, - Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.fan_cpu_ctrl, &cmd)?, - Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, &supported.rog_bios_ctrl, cmd)?, + Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.platform_profile, &cmd)?, + Some(CliCommand::Graphics(cmd)) => do_gfx(cmd)?, Some(CliCommand::Anime(cmd)) => handle_anime(&dbus, &supported.anime_ctrl, &cmd)?, Some(CliCommand::Bios(cmd)) => handle_bios_option(&dbus, &supported.rog_bios_ctrl, &cmd)?, None => { - if (!parsed.show_supported && parsed.kbd_bright.is_none() && parsed.chg_limit.is_none()) - || parsed.help + if (!parsed.show_supported && parsed.kbd_bright.is_none() && parsed.chg_limit.is_none() + && !parsed.next_kbd_bright && !parsed.prev_kbd_bright) || parsed.help { println!("{}", CliStart::usage()); println!(); @@ -180,6 +185,14 @@ fn main() -> Result<(), Box> { } } + if parsed.next_kbd_bright { + dbus.proxies().led().next_led_brightness()?; + } + + if parsed.prev_kbd_bright { + dbus.proxies().led().prev_led_brightness()?; + } + if parsed.show_supported { println!("Supported laptop functions:\n\n{}", supported); } @@ -191,62 +204,67 @@ fn main() -> Result<(), Box> { Ok(()) } -fn do_gfx( - dbus: &RogDbusClient, - supported: &RogBiosSupportedFunctions, - command: GraphicsCommand, -) -> Result<(), Box> { +fn do_gfx(command: GraphicsCommand) -> Result<(), Box> { if command.mode.is_none() && !command.get && !command.pow && !command.force || command.help { println!("{}", command.self_usage()); } + let conn = Connection::new_system()?; + let proxy = GfxProxy::new(&conn)?; + + let (tx, rx) = channel(); + proxy.connect_notify_action(tx)?; + if let Some(mode) = command.mode { - if supported.dedicated_gfx_toggle && dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 { + if has_asus_gsync_gfx_mode() && get_asus_gsync_gfx_mode()? == 1 { println!("You can not change modes until you turn dedicated/G-Sync off and reboot"); std::process::exit(-1); } println!("If anything fails check `journalctl -b -u asusd`\n"); - dbus.proxies().gfx().gfx_write_mode(&mode).map_err(|err|{ + proxy.gfx_write_mode(&mode).map_err(|err|{ println!("Graphics mode change error. You may be in an invalid state."); println!("Check mode with `asusctl graphics -g` and switch to opposite\nmode to correct it, e.g: if integrated, switch to hybrid, or if nvidia, switch to integrated.\n"); err })?; - let res = dbus.gfx_wait_changed()?; - match res { - GfxRequiredUserAction::Integrated => { - println!( - "You must change to Integrated before you can change to {}", - <&str>::from(mode) - ); - } - GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => { - println!( - "Graphics mode changed to {}. User action required is: {}", - <&str>::from(mode), - <&str>::from(&res) - ); - } - GfxRequiredUserAction::None => { - println!("Graphics mode changed to {}", <&str>::from(mode)); + + loop { + proxy.next_signal()?; + + if let Ok(res) = rx.try_recv() { + match res { + GfxRequiredUserAction::Integrated => { + println!( + "You must change to Integrated before you can change to {}", + <&str>::from(mode) + ); + } + GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => { + println!( + "Graphics mode changed to {}. User action required is: {}", + <&str>::from(mode), + <&str>::from(&res) + ); + } + GfxRequiredUserAction::None => { + println!("Graphics mode changed to {}", <&str>::from(mode)); + } + } } + std::process::exit(0) } - std::process::exit(0) } + if command.get { - let res = dbus.proxies().gfx().gfx_get_mode()?; + let res = proxy.gfx_get_mode()?; println!("Current graphics mode: {}", <&str>::from(res)); } if command.pow { - let res = dbus.proxies().gfx().gfx_get_pwr()?; - match res { - rog_types::gfx_vendors::GfxPower::Active => { - println!("Current power status: {}", Red.paint(<&str>::from(&res))) - } - _ => println!("Current power status: {}", Green.paint(<&str>::from(&res))), - } + let res = proxy.gfx_get_pwr()?; + println!("Current power status: {}", <&str>::from(&res)); } + Ok(()) } @@ -384,24 +402,10 @@ fn handle_led_mode( fn handle_profile( dbus: &RogDbusClient, - supported: &FanCpuSupportedFunctions, + supported: &PlatformProfileFunctions, cmd: &ProfileCommand, ) -> Result<(), Box> { - if !cmd.next - && !cmd.create // TODO - && !cmd.list - && cmd.profile.is_none() - && !cmd.active_name - && !cmd.active_data - && !cmd.profiles_data - && cmd.remove.is_none() - && cmd.curve.is_none() // TODO - && cmd.fan_preset.is_none() // TODO - && cmd.turbo.is_none() // TODO - && cmd.max_percentage.is_none() // TODO - && cmd.min_percentage.is_none() - // TODO - { + if !cmd.next && !cmd.list && !cmd.active_name && !cmd.active_data && !cmd.profiles_data { if !cmd.help { println!("Missing arg or command\n"); } @@ -411,7 +415,7 @@ fn handle_profile( .collect(); for line in usage .iter() - .filter(|line| !line.contains("--curve") || supported.fan_curve_set) + .filter(|line| !line.contains("--curve") || supported.fan_curves) { println!("{}", line); } @@ -426,78 +430,8 @@ fn handle_profile( } if cmd.next { - dbus.proxies().profile().next_fan()?; + dbus.proxies().profile().next_profile()?; } - if let Some(profile) = &cmd.remove { - dbus.proxies().profile().remove(profile)? - } - if cmd.list { - let profile_names = dbus.proxies().profile().profile_names()?; - println!("Available profiles are {:?}", profile_names); - } - if cmd.active_name { - println!( - "Active profile: {:?}", - dbus.proxies().profile().active_name()? - ); - } - if cmd.active_data { - println!("Active profile:"); - println!("{:?}", dbus.proxies().profile().active_data()?); - } - if cmd.profiles_data { - println!("Profiles:"); - for s in dbus.proxies().profile().all_profile_data()? { - println!("{:?}", s); - } - } - - let mut set_profile = false; - let mut profile = Profile::default(); - if cmd.create { - set_profile = true; - } else if let Some(ref name) = cmd.profile { - let profiles = dbus.proxies().profile().all_profile_data()?; - for p in profiles { - if p.name == *name { - profile = p; - break; - } - } - if profile.name != *name { - println!("The requested profile doesn't exist, you may need to create it"); - std::process::exit(-1); - } - } - - if let Some(turbo) = cmd.turbo { - set_profile = true; - profile.turbo = turbo; - } - if let Some(min) = cmd.min_percentage { - set_profile = true; - profile.min_percentage = min; - } - if let Some(max) = cmd.max_percentage { - set_profile = true; - profile.max_percentage = max; - } - if let Some(preset) = cmd.fan_preset { - set_profile = true; - profile.fan_preset = preset; - } - if let Some(ref curve) = cmd.curve { - set_profile = true; - profile.fan_curve = curve.as_config_string(); - } - if let Some(ref name) = cmd.profile { - set_profile = true; - profile.name = name.clone(); - } - if set_profile { - dbus.proxies().profile().new_or_modify(&profile)?; - } - Ok(()) } diff --git a/asusctl/src/profiles_cli.rs b/asusctl/src/profiles_cli.rs index ada243f1..921ba7a2 100644 --- a/asusctl/src/profiles_cli.rs +++ b/asusctl/src/profiles_cli.rs @@ -1,6 +1,4 @@ use gumdrop::Options; -use rog_fan_curve::{Curve, Fan}; -use rog_profiles::profiles::FanLevel; #[derive(Debug, Clone, Options)] pub struct ProfileCommand { @@ -8,10 +6,6 @@ pub struct ProfileCommand { pub help: bool, #[options(help = "toggle to next profile in list")] pub next: bool, - #[options(help = "create the profile if it doesn't exist")] - pub create: bool, - #[options(meta = "", help = "remove a profile by name")] - pub remove: Option, #[options(help = "list available profiles")] pub list: bool, #[options(help = "get active profile name")] @@ -20,34 +14,4 @@ pub struct ProfileCommand { pub active_data: bool, #[options(help = "get all profile data")] pub profiles_data: bool, - - // Options for profile - #[options(meta = "", help = "enable or disable cpu turbo")] - pub turbo: Option, - #[options(meta = "", help = "set min cpu scaling (intel)")] - pub min_percentage: Option, - #[options(meta = "", help = "set max cpu scaling (intel)")] - pub max_percentage: Option, - - #[options(meta = "", help = "")] - pub fan_preset: Option, - #[options( - meta = "", - parse(try_from_str = "parse_fan_curve"), - help = "set fan curve" - )] - pub curve: Option, - #[options(free)] - pub profile: Option, -} - -fn parse_fan_curve(data: &str) -> Result { - let curve = Curve::from_config_str(data)?; - if let Err(err) = curve.check_safety(Fan::Cpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - if let Err(err) = curve.check_safety(Fan::Gpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - Ok(curve) } diff --git a/daemon-user/Cargo.toml b/daemon-user/Cargo.toml index cf7f22cd..85751dc8 100644 --- a/daemon-user/Cargo.toml +++ b/daemon-user/Cargo.toml @@ -21,7 +21,7 @@ serde_derive = "^1.0" rog_anime = { path = "../rog-anime" } rog_dbus = { path = "../rog-dbus" } -rog_types = { path = "../rog-types" } +rog_supported = { path = "../rog-supported" } dirs = "3.0.1" diff --git a/daemon-user/src/daemon.rs b/daemon-user/src/daemon.rs index 14cdc532..d105f1de 100644 --- a/daemon-user/src/daemon.rs +++ b/daemon-user/src/daemon.rs @@ -12,10 +12,10 @@ use zbus::{fdo, Connection}; use std::sync::atomic::AtomicBool; fn main() -> Result<(), Box> { - println!(" user daemon v{}", rog_user::VERSION); - println!(" rog-anime v{}", rog_anime::VERSION); - println!(" rog-dbus v{}", rog_dbus::VERSION); - println!(" rog-types v{}", rog_types::VERSION); + println!(" user daemon v{}", rog_user::VERSION); + println!(" rog-anime v{}", rog_anime::VERSION); + println!(" rog-dbus v{}", rog_dbus::VERSION); + println!("rog-supported v{}", rog_supported::VERSION); let (client, _) = RogDbusClient::new().unwrap(); let supported = client.proxies().supported().get_supported_functions()?; diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index c54010ab..cb54d5d8 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "3.7.2" +version = "4.0.0" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] @@ -20,7 +20,7 @@ path = "src/daemon.rs" [dependencies] rog_anime = { path = "../rog-anime" } rog_aura = { path = "../rog-aura" } -rog_types = { path = "../rog-types" } +rog_supported = { path = "../rog-supported" } rog_profiles = { path = "../rog-profiles" } rog_dbus = { path = "../rog-dbus" } rusb = "^0.8" @@ -43,4 +43,3 @@ toml = "^0.5" # Device control sysfs-class = "^0.1.2" # used for backlight control and baord ID -rog_fan_curve = { version = "0.1", features = ["serde"] } diff --git a/daemon/src/config.rs b/daemon/src/config.rs index b194802d..273fbcac 100644 --- a/daemon/src/config.rs +++ b/daemon/src/config.rs @@ -1,85 +1,23 @@ -use log::{error, info, warn}; -use rog_profiles::profiles::{FanLevel, Profile}; -use rog_types::gfx_vendors::GfxVendors; +use log::{error, warn}; use serde_derive::{Deserialize, Serialize}; -use std::collections::BTreeMap; use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; -use crate::config_old::*; -use crate::VERSION; - pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; -pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; #[derive(Deserialize, Serialize)] pub struct Config { - pub gfx_mode: GfxVendors, - /// Only for informational purposes. - #[serde(skip)] - pub gfx_tmp_mode: Option, - pub gfx_managed: bool, - pub gfx_vfio_enable: bool, - pub active_profile: String, - pub toggle_profiles: Vec, - #[serde(skip)] - pub curr_fan_mode: u8, + /// Save charge limit for restoring on boot pub bat_charge_limit: u8, - pub power_profiles: BTreeMap, -} - -impl Default for Config { - fn default() -> Self { - let mut pwr = BTreeMap::new(); - pwr.insert( - "normal".into(), - Profile::new( - "normal".into(), - 0, - 100, - true, - FanLevel::Normal, - "".to_string(), - ), - ); - pwr.insert( - "boost".into(), - Profile::new( - "boost".into(), - 0, - 100, - true, - FanLevel::Boost, - "".to_string(), - ), - ); - pwr.insert( - "silent".into(), - Profile::new( - "silent".into(), - 0, - 100, - false, - FanLevel::Silent, - "".to_string(), - ), - ); - - Config { - gfx_mode: GfxVendors::Hybrid, - gfx_tmp_mode: None, - gfx_managed: true, - gfx_vfio_enable: false, - active_profile: "normal".into(), - toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()], - curr_fan_mode: 0, - bat_charge_limit: 100, - power_profiles: pwr, - } - } } impl Config { + fn new() -> Self { + Config { + bat_charge_limit: 100, + } + } + /// `load` will attempt to read the config, and panic if the dir is missing pub fn load() -> Self { let mut file = OpenOptions::new() @@ -89,46 +27,20 @@ impl Config { .open(&CONFIG_PATH) .unwrap_or_else(|_| panic!("The directory /etc/asusd/ is missing")); // okay to cause panic here let mut buf = String::new(); + let config; if let Ok(read_len) = file.read_to_string(&mut buf) { if read_len == 0 { - return Config::create_default(&mut file); + config = Self::new(); + } else if let Ok(data) = serde_json::from_str(&buf) { + config = data; } else { - if let Ok(data) = serde_json::from_str(&buf) { - return data; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated config version to: {}", VERSION); - return config; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated config version to: {}", VERSION); - return config; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated config version to: {}", VERSION); - return config; - } else if let Ok(data) = serde_json::from_str::(&buf) { - let config = data.into_current(); - config.write(); - info!("Updated config version to: {}", VERSION); - return config; - } warn!("Could not deserialise {}", CONFIG_PATH); panic!("Please remove {} then restart asusd", CONFIG_PATH); } + } else { + config = Self::new() } - Config::create_default(&mut file) - } - - fn create_default(file: &mut File) -> Self { - let config = Config::default(); - // Should be okay to unwrap this as is since it is a Default - let json = serde_json::to_string_pretty(&config).unwrap(); - file.write_all(json.as_bytes()) - .unwrap_or_else(|_| panic!("Could not write {}", CONFIG_PATH)); + config.write(); config } @@ -142,12 +54,8 @@ impl Config { if l == 0 { warn!("File is empty {}", CONFIG_PATH); } else { - let mut x: Config = serde_json::from_str(&buf) + *self = serde_json::from_str(&buf) .unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH)); - // copy over serde skipped values - x.gfx_tmp_mode = self.gfx_tmp_mode; - x.curr_fan_mode = self.curr_fan_mode; - *self = x; } } } diff --git a/daemon/src/config_old.rs b/daemon/src/config_old.rs deleted file mode 100644 index 1a1fe159..00000000 --- a/daemon/src/config_old.rs +++ /dev/null @@ -1,161 +0,0 @@ -use rog_fan_curve::Curve; -use rog_profiles::profiles::Profile; -use rog_types::gfx_vendors::GfxVendors; -use serde_derive::{Deserialize, Serialize}; -use std::collections::BTreeMap; - -use crate::config::Config; - -/// for parsing old v3.1.7 config -#[allow(dead_code)] -#[derive(Deserialize)] -pub(crate) struct ConfigV317 { - pub gfx_mode: GfxVendors, - pub gfx_managed: bool, - pub active_profile: String, - pub toggle_profiles: Vec, - #[serde(skip)] - pub curr_fan_mode: u8, - pub bat_charge_limit: u8, - pub kbd_led_brightness: u8, - pub kbd_backlight_mode: u8, - #[serde(skip)] - pub kbd_backlight_modes: Option, - pub power_profiles: BTreeMap, -} - -impl ConfigV317 { - pub(crate) fn into_current(self) -> Config { - Config { - gfx_mode: self.gfx_mode, - gfx_tmp_mode: None, - gfx_managed: self.gfx_managed, - gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, - bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct ConfigV324 { - pub gfx_mode: GfxVendors, - pub gfx_managed: bool, - pub active_profile: String, - pub toggle_profiles: Vec, - #[serde(skip)] - pub curr_fan_mode: u8, - pub bat_charge_limit: u8, - pub power_profiles: BTreeMap, -} - -impl ConfigV324 { - pub(crate) fn into_current(self) -> Config { - Config { - gfx_mode: GfxVendors::Hybrid, - gfx_tmp_mode: None, - gfx_managed: self.gfx_managed, - gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, - bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct ConfigV341 { - pub gfx_mode: GfxVendors, - pub gfx_managed: bool, - pub gfx_vfio_enable: bool, - pub active_profile: String, - pub toggle_profiles: Vec, - #[serde(skip)] - pub curr_fan_mode: u8, - pub bat_charge_limit: u8, - pub power_profiles: BTreeMap, -} - -impl ConfigV341 { - pub(crate) fn into_current(self) -> Config { - Config { - gfx_mode: GfxVendors::Hybrid, - gfx_tmp_mode: None, - gfx_managed: self.gfx_managed, - gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, - bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), - } - } -} - -#[derive(Deserialize, Serialize)] -pub struct ConfigV352 { - pub gfx_mode: GfxVendors, - pub gfx_last_mode: GfxVendors, - pub gfx_managed: bool, - pub gfx_vfio_enable: bool, - pub gfx_save_compute_vfio: bool, - pub active_profile: String, - pub toggle_profiles: Vec, - #[serde(skip)] - pub curr_fan_mode: u8, - pub bat_charge_limit: u8, - pub power_profiles: BTreeMap, -} - -impl ConfigV352 { - pub(crate) fn into_current(self) -> Config { - Config { - gfx_mode: GfxVendors::Hybrid, - gfx_tmp_mode: None, - gfx_managed: self.gfx_managed, - gfx_vfio_enable: false, - active_profile: self.active_profile, - toggle_profiles: self.toggle_profiles, - curr_fan_mode: self.curr_fan_mode, - bat_charge_limit: self.bat_charge_limit, - power_profiles: ProfileV317::transform_map(self.power_profiles), - } - } -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct ProfileV317 { - pub min_percentage: u8, - pub max_percentage: u8, - pub turbo: bool, - pub fan_preset: u8, - pub fan_curve: Option, -} - -impl ProfileV317 { - fn into_current(self, name: String) -> Profile { - Profile { - name, - min_percentage: self.min_percentage, - max_percentage: self.max_percentage, - turbo: self.turbo, - fan_preset: self.fan_preset.into(), - fan_curve: self - .fan_curve - .map_or_else(|| "".to_string(), |c| c.as_config_string()), - } - } - - fn transform_map(map: BTreeMap) -> BTreeMap { - let mut new_map = BTreeMap::new(); - map.iter().for_each(|(k, v)| { - new_map.insert(k.to_string(), v.clone().into_current(k.to_string())); - }); - new_map - } -} diff --git a/daemon/src/config_anime.rs b/daemon/src/ctrl_anime/config.rs similarity index 100% rename from daemon/src/config_anime.rs rename to daemon/src/ctrl_anime/config.rs diff --git a/daemon/src/ctrl_anime.rs b/daemon/src/ctrl_anime/mod.rs similarity index 71% rename from daemon/src/ctrl_anime.rs rename to daemon/src/ctrl_anime/mod.rs index e1400f2e..e96d2dc0 100644 --- a/daemon/src/ctrl_anime.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -1,3 +1,7 @@ +pub mod config; +pub mod zbus; + +use ::zbus::Connection; use log::{error, info, warn}; use logind_zbus::ManagerProxy; use rog_anime::{ @@ -5,9 +9,9 @@ use rog_anime::{ pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID, VENDOR_ID, }, - ActionData, AnimeDataBuffer, AnimePacketType, AnimePowerStates, ANIME_DATA_LEN, + ActionData, AnimeDataBuffer, AnimePacketType, ANIME_DATA_LEN, }; -use rog_types::supported::AnimeSupportedFunctions; +use rog_supported::AnimeSupportedFunctions; use rusb::{Device, DeviceHandle}; use std::{ error::Error, @@ -18,14 +22,10 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, time::Duration, }; -use zbus::{dbus_interface, Connection}; -use zvariant::ObjectPath; -use crate::{ - config_anime::{AnimeConfig, AnimeConfigCached}, - error::RogError, - GetSupported, -}; +use crate::{error::RogError, GetSupported}; + +use self::config::{AnimeConfig, AnimeConfigCached}; impl GetSupported for CtrlAnime { type A = AnimeSupportedFunctions; @@ -327,130 +327,3 @@ impl crate::Reloadable for CtrlAnimeReloader { Ok(()) } } - -pub struct CtrlAnimeZbus(pub Arc>); - -/// The struct with the main dbus methods requires this trait -impl crate::ZbusAdd for CtrlAnimeZbus { - fn add_to_server(self, server: &mut zbus::ObjectServer) { - server - .at( - &ObjectPath::from_str_unchecked("/org/asuslinux/Anime"), - self, - ) - .map_err(|err| { - warn!("CtrlAnimeDisplay: add_to_server {}", err); - err - }) - .ok(); - } -} - -// None of these calls can be guarnateed to succeed unless we loop until okay -// If the try_lock *does* succeed then any other thread trying to lock will not grab it -// until we finish. -#[dbus_interface(name = "org.asuslinux.Daemon")] -impl CtrlAnimeZbus { - /// Writes a data stream of length. Will force system thread to exit until it is restarted - fn write(&self, input: AnimeDataBuffer) { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - lock.write_data_buffer(input); - break 'outer; - } - } - } - - /// Set the global AniMe brightness - fn set_brightness(&self, bright: f32) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - let mut bright = bright; - if bright < 0.0 { - bright = 0.0 - } else if bright > 254.0 { - bright = 254.0; - } - lock.config.brightness = bright; - lock.config.write(); - break 'outer; - } - } - } - - /// Set whether the AniMe is displaying images/data - fn set_on_off(&self, status: bool) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_on(status)); - lock.config.awake_enabled = status; - lock.config.write(); - - let states = AnimePowerStates { - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }; - self.notify_power_states(&states) - .unwrap_or_else(|err| warn!("{}", err)); - break 'outer; - } - } - } - - /// Set whether the AniMe will show boot, suspend, or off animations - fn set_boot_on_off(&self, on: bool) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_boot(on)); - lock.write_bytes(&pkt_for_apply()); - lock.config.boot_anim_enabled = on; - lock.config.write(); - - let states = AnimePowerStates { - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }; - self.notify_power_states(&states) - .unwrap_or_else(|err| warn!("{}", err)); - break 'outer; - } - } - } - - /// The main loop is the base system set action if the user isn't running - /// the user daemon - fn run_main_loop(&self, start: bool) { - if start { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false); - break 'outer; - } - } - } - } - - /// Get status of if the AniMe LEDs are on - #[dbus_interface(property)] - fn awake_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.awake_enabled; - } - true - } - - /// Get the status of if factory system-status animations are enabled - #[dbus_interface(property)] - fn boot_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.boot_anim_enabled; - } - true - } - - /// Notify listeners of the status of AniMe LED power and factory system-status animations - #[dbus_interface(signal)] - fn notify_power_states(&self, data: &AnimePowerStates) -> zbus::Result<()>; -} diff --git a/daemon/src/ctrl_anime/zbus.rs b/daemon/src/ctrl_anime/zbus.rs new file mode 100644 index 00000000..f5e28758 --- /dev/null +++ b/daemon/src/ctrl_anime/zbus.rs @@ -0,0 +1,140 @@ +use std::sync::{Arc, Mutex}; + +use log::warn; +use rog_anime::{ + usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}, + AnimeDataBuffer, AnimePowerStates, +}; +use zbus::dbus_interface; +use zvariant::ObjectPath; + +use std::sync::atomic::Ordering; + +use super::CtrlAnime; + +pub struct CtrlAnimeZbus(pub Arc>); + +/// The struct with the main dbus methods requires this trait +impl crate::ZbusAdd for CtrlAnimeZbus { + fn add_to_server(self, server: &mut zbus::ObjectServer) { + server + .at( + &ObjectPath::from_str_unchecked("/org/asuslinux/Anime"), + self, + ) + .map_err(|err| { + warn!("CtrlAnimeDisplay: add_to_server {}", err); + err + }) + .ok(); + } +} + +// None of these calls can be guarnateed to succeed unless we loop until okay +// If the try_lock *does* succeed then any other thread trying to lock will not grab it +// until we finish. +#[dbus_interface(name = "org.asuslinux.Daemon")] +impl CtrlAnimeZbus { + /// Writes a data stream of length. Will force system thread to exit until it is restarted + fn write(&self, input: AnimeDataBuffer) { + 'outer: loop { + if let Ok(lock) = self.0.try_lock() { + lock.thread_exit.store(true, Ordering::SeqCst); + lock.write_data_buffer(input); + break 'outer; + } + } + } + + /// Set the global AniMe brightness + fn set_brightness(&self, bright: f32) { + 'outer: loop { + if let Ok(mut lock) = self.0.try_lock() { + let mut bright = bright; + if bright < 0.0 { + bright = 0.0 + } else if bright > 254.0 { + bright = 254.0; + } + lock.config.brightness = bright; + lock.config.write(); + break 'outer; + } + } + } + + /// Set whether the AniMe is displaying images/data + fn set_on_off(&self, status: bool) { + 'outer: loop { + if let Ok(mut lock) = self.0.try_lock() { + lock.write_bytes(&pkt_for_set_on(status)); + lock.config.awake_enabled = status; + lock.config.write(); + + let states = AnimePowerStates { + enabled: lock.config.awake_enabled, + boot_anim_enabled: lock.config.boot_anim_enabled, + }; + self.notify_power_states(&states) + .unwrap_or_else(|err| warn!("{}", err)); + break 'outer; + } + } + } + + /// Set whether the AniMe will show boot, suspend, or off animations + fn set_boot_on_off(&self, on: bool) { + 'outer: loop { + if let Ok(mut lock) = self.0.try_lock() { + lock.write_bytes(&pkt_for_set_boot(on)); + lock.write_bytes(&pkt_for_apply()); + lock.config.boot_anim_enabled = on; + lock.config.write(); + + let states = AnimePowerStates { + enabled: lock.config.awake_enabled, + boot_anim_enabled: lock.config.boot_anim_enabled, + }; + self.notify_power_states(&states) + .unwrap_or_else(|err| warn!("{}", err)); + break 'outer; + } + } + } + + /// The main loop is the base system set action if the user isn't running + /// the user daemon + fn run_main_loop(&self, start: bool) { + if start { + 'outer: loop { + if let Ok(lock) = self.0.try_lock() { + lock.thread_exit.store(true, Ordering::SeqCst); + CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false); + break 'outer; + } + } + } + } + + /// Get status of if the AniMe LEDs are on + #[dbus_interface(property)] + fn awake_enabled(&self) -> bool { + if let Ok(ctrl) = self.0.try_lock() { + return ctrl.config.awake_enabled; + } + true + } + + /// Get the status of if factory system-status animations are enabled + #[dbus_interface(property)] + fn boot_enabled(&self) -> bool { + if let Ok(ctrl) = self.0.try_lock() { + return ctrl.config.boot_anim_enabled; + } + true + } + + /// Notify listeners of the status of AniMe LED power and factory system-status animations + #[dbus_interface(signal)] + fn notify_power_states(&self, data: &AnimePowerStates) -> zbus::Result<()>; +} diff --git a/daemon/src/config_aura.rs b/daemon/src/ctrl_aura/config.rs similarity index 100% rename from daemon/src/config_aura.rs rename to daemon/src/ctrl_aura/config.rs diff --git a/daemon/src/ctrl_leds/controller.rs b/daemon/src/ctrl_aura/controller.rs similarity index 94% rename from daemon/src/ctrl_leds/controller.rs rename to daemon/src/ctrl_aura/controller.rs index d9e0a64f..67e4b21e 100644 --- a/daemon/src/ctrl_leds/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -2,7 +2,6 @@ static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness"; use crate::{ - config_aura::AuraConfig, error::RogError, laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, CtrlTask, @@ -16,7 +15,7 @@ use rog_aura::{ }, AuraEffect, LedBrightness, LED_MSG_LEN, }; -use rog_types::supported::LedSupportedFunctions; +use rog_supported::LedSupportedFunctions; use std::io::{Read, Write}; use std::path::Path; use std::sync::Arc; @@ -26,6 +25,8 @@ use zbus::Connection; use crate::GetSupported; +use super::config::AuraConfig; + impl GetSupported for CtrlKbdLed { type A = LedSupportedFunctions; @@ -238,6 +239,28 @@ impl CtrlKbdLed { Ok(()) } + pub fn next_brightness(&mut self) -> Result<(), RogError> { + let mut bright = (self.config.brightness as u32) + 1; + if bright > 3 { + bright = 0; + } + self.config.brightness = ::from(bright); + self.config.write(); + self.set_brightness(self.config.brightness) + } + + pub fn prev_brightness(&mut self) -> Result<(), RogError> { + let mut bright = self.config.brightness as u32; + if bright == 0 { + bright = 3; + } else { + bright -= 1; + } + self.config.brightness = ::from(bright); + self.config.write(); + self.set_brightness(self.config.brightness) + } + /// Set if awake/on LED active, and/or sleep animation active pub(super) fn set_states_enabled(&self, awake: bool, sleep: bool) -> Result<(), RogError> { let bytes = if awake && sleep { diff --git a/daemon/src/ctrl_leds/mod.rs b/daemon/src/ctrl_aura/mod.rs similarity index 68% rename from daemon/src/ctrl_leds/mod.rs rename to daemon/src/ctrl_aura/mod.rs index 65359c9f..85a4d229 100644 --- a/daemon/src/ctrl_leds/mod.rs +++ b/daemon/src/ctrl_aura/mod.rs @@ -1,2 +1,3 @@ +pub mod config; pub mod controller; pub mod zbus; diff --git a/daemon/src/ctrl_leds/zbus.rs b/daemon/src/ctrl_aura/zbus.rs similarity index 93% rename from daemon/src/ctrl_leds/zbus.rs rename to daemon/src/ctrl_aura/zbus.rs index d96fa095..eeab2619 100644 --- a/daemon/src/ctrl_leds/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -105,6 +105,20 @@ impl CtrlKbdLedZbus { } } + fn next_led_brightness(&self) { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.next_brightness() + .unwrap_or_else(|err| warn!("{}", err)); + } + } + + fn prev_led_brightness(&self) { + if let Ok(mut ctrl) = self.0.try_lock() { + ctrl.prev_brightness() + .unwrap_or_else(|err| warn!("{}", err)); + } + } + #[dbus_interface(property)] fn awake_enabled(&self) -> bool { if let Ok(ctrl) = self.0.try_lock() { diff --git a/daemon/src/ctrl_charge.rs b/daemon/src/ctrl_charge.rs index dbd7202d..ba50bc94 100644 --- a/daemon/src/ctrl_charge.rs +++ b/daemon/src/ctrl_charge.rs @@ -1,7 +1,7 @@ use crate::{config::Config, error::RogError, GetSupported}; //use crate::dbus::DbusEvents; use log::{info, warn}; -use rog_types::supported::ChargeSupportedFunctions; +use rog_supported::ChargeSupportedFunctions; use std::fs::OpenOptions; use std::io::Write; use std::path::Path; @@ -10,7 +10,9 @@ use std::sync::Mutex; use zbus::dbus_interface; use zvariant::ObjectPath; -static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold"; +static BAT_CHARGE_PATH0: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold"; +static BAT_CHARGE_PATH1: &str = "/sys/class/power_supply/BAT1/charge_control_end_threshold"; +static BAT_CHARGE_PATH2: &str = "/sys/class/power_supply/BAT2/charge_control_end_threshold"; impl GetSupported for CtrlCharge { type A = ChargeSupportedFunctions; @@ -88,8 +90,12 @@ impl CtrlCharge { } fn get_battery_path() -> Result<&'static str, RogError> { - if Path::new(BAT_CHARGE_PATH).exists() { - Ok(BAT_CHARGE_PATH) + if Path::new(BAT_CHARGE_PATH0).exists() { + Ok(BAT_CHARGE_PATH0) + } else if Path::new(BAT_CHARGE_PATH1).exists() { + Ok(BAT_CHARGE_PATH1) + } else if Path::new(BAT_CHARGE_PATH2).exists() { + Ok(BAT_CHARGE_PATH2) } else { Err(RogError::MissingFunction( "Charge control not available, you may require a v5.8.10 series kernel or newer" @@ -106,12 +112,14 @@ impl CtrlCharge { ); } + let path = Self::get_battery_path()?; + let mut file = OpenOptions::new() .write(true) - .open(BAT_CHARGE_PATH) - .map_err(|err| RogError::Path(BAT_CHARGE_PATH.into(), err))?; + .open(path) + .map_err(|err| RogError::Path(path.into(), err))?; file.write_all(limit.to_string().as_bytes()) - .map_err(|err| RogError::Write(BAT_CHARGE_PATH.into(), err))?; + .map_err(|err| RogError::Write(path.into(), err))?; info!("Battery charge limit: {}", limit); config.read(); diff --git a/daemon/src/ctrl_gfx/controller.rs b/daemon/src/ctrl_gfx/controller.rs deleted file mode 100644 index 6a2f23b2..00000000 --- a/daemon/src/ctrl_gfx/controller.rs +++ /dev/null @@ -1,702 +0,0 @@ -use ::zbus::Connection; -use ctrl_gfx::error::GfxError; -use ctrl_gfx::*; -use ctrl_rog_bios::CtrlRogBios; -use log::{error, info, warn}; -use logind_zbus::{ - types::{SessionClass, SessionInfo, SessionState, SessionType}, - ManagerProxy, SessionProxy, -}; -use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; -use std::{io::Write, ops::Add, path::Path, time::Instant}; -use std::{process::Command, thread::sleep, time::Duration}; -use std::{str::FromStr, sync::mpsc}; -use std::{sync::Arc, sync::Mutex}; -use sysfs_class::RuntimePM; -use sysfs_class::{PciDevice, SysClass}; -use system::{GraphicsDevice, PciBus}; - -use crate::*; - -const THREAD_TIMEOUT_MSG: &str = "GFX: thread time exceeded 3 minutes, exiting"; - -pub struct CtrlGraphics { - bus: PciBus, - _amd: Vec, - _intel: Vec, - nvidia: Vec, - #[allow(dead_code)] - other: Vec, - config: Arc>, - thread_kill: Arc>>>, -} - -impl Reloadable for CtrlGraphics { - fn reload(&mut self) -> Result<(), RogError> { - self.auto_power()?; - info!("GFX: Reloaded gfx mode: {:?}", self.get_gfx_mode()?); - Ok(()) - } -} - -impl CtrlGraphics { - pub fn new(config: Arc>) -> std::io::Result { - let bus = PciBus::new()?; - info!("GFX: Rescanning PCI bus"); - bus.rescan()?; - let devs = PciDevice::all()?; - - let functions = |parent: &PciDevice| -> Vec { - let mut functions = Vec::new(); - if let Some(parent_slot) = parent.id().split('.').next() { - for func in devs.iter() { - if let Some(func_slot) = func.id().split('.').next() { - if func_slot == parent_slot { - info!("GFX: {}: Function for {}", func.id(), parent.id()); - functions.push(func.clone()); - } - } - } - } - functions - }; - - let mut amd = Vec::new(); - let mut intel = Vec::new(); - let mut nvidia = Vec::new(); - let mut other = Vec::new(); - for dev in devs.iter() { - let c = dev.class().map_err(|err| { - error!( - "GFX: device error: {}, {}", - dev.path().to_string_lossy(), - err - ); - err - })?; - if 0x03 == (c >> 16) & 0xFF { - match dev.vendor()? { - 0x1002 => { - info!("GFX: {}: AMD graphics", dev.id()); - amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(dev))); - } - 0x10DE => { - info!("GFX: {}: NVIDIA graphics", dev.id()); - dev.set_runtime_pm(sysfs_class::RuntimePowerManagement::On)?; - nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(dev))); - } - 0x8086 => { - info!("GFX: {}: Intel graphics", dev.id()); - intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(dev))); - } - vendor => { - info!("GFX: {}: Other({:X}) graphics", dev.id(), vendor); - other.push(GraphicsDevice::new(dev.id().to_owned(), functions(dev))); - } - } - } - } - - Ok(CtrlGraphics { - bus, - _amd: amd, - _intel: intel, - nvidia, - other, - config, - thread_kill: Arc::new(Mutex::new(None)), - }) - } - - pub fn bus(&self) -> PciBus { - self.bus.clone() - } - - pub fn devices(&self) -> Vec { - self.nvidia.clone() - } - - /// Save the selected `Vendor` mode to config - fn save_gfx_mode(vendor: GfxVendors, config: Arc>) { - if let Ok(mut config) = config.lock() { - config.gfx_mode = vendor; - config.write(); - } - } - - /// Associated method to get which vendor mode is set - pub(super) fn get_gfx_mode(&self) -> Result { - if let Ok(config) = self.config.lock() { - if let Some(mode) = config.gfx_tmp_mode { - return Ok(mode); - } - return Ok(config.gfx_mode); - } - // TODO: Error here - Ok(GfxVendors::Hybrid) - } - - pub(super) fn get_runtime_status() -> Result { - let path = Path::new("/sys/bus/pci/devices/0000:01:00.0/power/runtime_status"); - if path.exists() { - let buf = std::fs::read_to_string(path).map_err(|err| { - RogError::Read( - "/sys/bus/pci/devices/0000:01:00.0/power/runtime_status".to_string(), - err, - ) - })?; - Ok(GfxPower::from_str(&buf)?) - } else { - Ok(GfxPower::Off) - } - } - - /// Some systems have a fallback service to load nouveau if nvidia fails - fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> { - let action = if vendor == GfxVendors::Nvidia { - info!("GFX: Enabling nvidia-fallback.service"); - "enable" - } else { - info!("GFX: Disabling nvidia-fallback.service"); - "disable" - }; - - let status = Command::new("systemctl") - .arg(action) - .arg("nvidia-fallback.service") - .status() - .map_err(|err| RogError::Command("systemctl".into(), err))?; - - if !status.success() { - // Error is ignored in case this service is removed - warn!( - "systemctl: {} (ignore warning if service does not exist!)", - status - ); - } - - Ok(()) - } - - /// Write the appropriate xorg config for the chosen mode - fn write_xorg_conf(vendor: GfxVendors) -> Result<(), RogError> { - let text = if vendor == GfxVendors::Nvidia { - [PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat() - } else { - [PRIMARY_GPU_BEGIN, PRIMARY_GPU_END].concat() - }; - - if !Path::new(XORG_PATH).exists() { - std::fs::create_dir(XORG_PATH).map_err(|err| RogError::Write(XORG_PATH.into(), err))?; - } - - let file = XORG_PATH.to_string().add(XORG_FILE); - info!("GFX: Writing {}", file); - let mut file = std::fs::OpenOptions::new() - .create(true) - .truncate(true) - .write(true) - .open(&file) - .map_err(|err| RogError::Write(file, err))?; - - file.write_all(&text) - .and_then(|_| file.sync_all()) - .map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?; - Ok(()) - } - - /// Creates the full modprobe.conf required for vfio pass-through - fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec { - let mut vifo = MODPROBE_VFIO.to_vec(); - for (d_count, dev) in devices.iter().enumerate() { - for (f_count, func) in dev.functions().iter().enumerate() { - let vendor = func.vendor().unwrap(); - let device = func.device().unwrap(); - unsafe { - vifo.append(format!("{:x}", vendor).as_mut_vec()); - } - vifo.append(&mut vec![b':']); - unsafe { - vifo.append(format!("{:x}", device).as_mut_vec()); - } - if f_count < dev.functions().len() - 1 { - vifo.append(&mut vec![b',']); - } - } - if d_count < dev.functions().len() - 1 { - vifo.append(&mut vec![b',']); - } - } - let mut conf = MODPROBE_INTEGRATED.to_vec(); - conf.append(&mut vifo); - conf - } - - fn write_modprobe_conf(vendor: GfxVendors, devices: &[GraphicsDevice]) -> Result<(), RogError> { - info!("GFX: Writing {}", MODPROBE_PATH); - let content = match vendor { - GfxVendors::Nvidia | GfxVendors::Hybrid => { - let mut base = MODPROBE_BASE.to_vec(); - base.append(&mut MODPROBE_DRM_MODESET.to_vec()); - base - } - GfxVendors::Vfio => Self::get_vfio_conf(devices), - GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(), - GfxVendors::Compute => MODPROBE_BASE.to_vec(), - }; - - let mut file = std::fs::OpenOptions::new() - .create(true) - .truncate(true) - .write(true) - .open(MODPROBE_PATH) - .map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?; - - file.write_all(&content) - .and_then(|_| file.sync_all()) - .map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?; - - Ok(()) - } - - fn unbind_remove_nvidia(devices: &[GraphicsDevice]) -> Result<(), RogError> { - // Unbind NVIDIA graphics devices and their functions - let unbinds = devices.iter().map(|dev| dev.unbind()); - // Remove NVIDIA graphics devices and their functions - let removes = devices.iter().map(|dev| dev.remove()); - unbinds.chain(removes).collect::>() - .map_err(|err| RogError::Command("device unbind error".into(), err)) - } - - fn unbind_only(devices: &[GraphicsDevice]) -> Result<(), RogError> { - let unbinds = devices.iter().map(|dev| dev.unbind()); - unbinds.collect::>() - .map_err(|err| RogError::Command("device unbind error".into(), err)) - } - - /// Add or remove driver modules - fn do_driver_action(driver: &str, action: &str) -> Result<(), GfxError> { - let mut cmd = Command::new(action); - cmd.arg(driver); - - let mut count = 0; - const MAX_TRIES: i32 = 6; - loop { - if count > MAX_TRIES { - let msg = format!("{} {} failed for unknown reason", action, driver); - error!("GFX: {}", msg); - return Ok(()); //Err(RogError::Modprobe(msg)); - } - - let output = cmd - .output() - .map_err(|err| GfxError::Command(format!("{:?}", cmd), err))?; - if !output.status.success() { - if output - .stderr - .ends_with("is not currently loaded\n".as_bytes()) - { - return Ok(()); - } - if output.stderr.ends_with("is builtin.\n".as_bytes()) { - return Err(GfxError::VfioBuiltin); - } - if output.stderr.ends_with("Permission denied\n".as_bytes()) { - warn!( - "{} {} failed: {:?}", - action, - driver, - String::from_utf8_lossy(&output.stderr) - ); - warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep {}` to confirm modules loaded", driver); - return Ok(()); - } - if String::from_utf8_lossy(&output.stderr) - .contains(&format!("Module {} not found", driver)) - { - return Err(GfxError::MissingModule(driver.into())); - } - if count >= MAX_TRIES { - let msg = format!( - "{} {} failed: {:?}", - action, - driver, - String::from_utf8_lossy(&output.stderr) - ); - return Err(GfxError::Modprobe(msg)); - } - } else if output.status.success() { - return Ok(()); - } - - count += 1; - std::thread::sleep(std::time::Duration::from_millis(50)); - } - } - - fn do_display_manager_action(action: &str) -> Result<(), RogError> { - let mut cmd = Command::new("systemctl"); - cmd.arg(action); - cmd.arg(DISPLAY_MANAGER); - - let status = cmd - .status() - .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; - if !status.success() { - let msg = format!( - "systemctl {} {} failed: {:?}", - action, DISPLAY_MANAGER, status - ); - return Err(GfxError::DisplayManagerAction(msg, status).into()); - } - Ok(()) - } - - fn wait_display_manager_state(state: &str) -> Result<(), RogError> { - let mut cmd = Command::new("systemctl"); - cmd.arg("is-active"); - cmd.arg(DISPLAY_MANAGER); - - let mut count = 0; - - while count <= (4 * 3) { - // 3 seconds max - let output = cmd - .output() - .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; - if output.stdout.starts_with(state.as_bytes()) { - return Ok(()); - } - std::thread::sleep(std::time::Duration::from_millis(250)); - count += 1; - } - Err(GfxError::DisplayManagerTimeout(state.into()).into()) - } - - /// Determine if we need to logout/thread. Integrated<->Vfio mode does not - /// require logout. - fn is_logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction { - if let Ok(config) = self.config.lock() { - let current = config.gfx_mode; - // Modes that can switch without logout - if matches!( - current, - GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute - ) && matches!( - vendor, - GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute - ) { - return GfxRequiredUserAction::None; - } - // Modes that require a switch to integrated first - if matches!(current, GfxVendors::Nvidia | GfxVendors::Hybrid) - && matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio) - { - return GfxRequiredUserAction::Integrated; - } - } - GfxRequiredUserAction::Logout - } - - /// Do a full setup flow for the chosen mode: - /// - /// Tasks: - /// - rescan for devices - /// - write xorg config - /// - write modprobe config - /// + add drivers - /// + or remove drivers and devices - /// - /// The daemon needs direct access to this function when it detects that the - /// bios has G-Sync switch is enabled - pub fn do_mode_setup_tasks( - vendor: GfxVendors, - vfio_enable: bool, - devices: &[GraphicsDevice], - bus: &PciBus, - ) -> Result<(), RogError> { - // Rescan before doing remove or add drivers - bus.rescan()?; - // Make sure the power management is set to auto for nvidia devices - let devs = PciDevice::all()?; - for dev in devs.iter() { - let c = dev.class().map_err(|err| { - error!( - "GFX: device error: {}, {}", - dev.path().to_string_lossy(), - err - ); - err - })?; - if 0x03 == (c >> 16) & 0xFF && dev.vendor()? == 0x10DE { - info!("GFX: {}: NVIDIA graphics, setting PM to auto", dev.id()); - dev.set_runtime_pm(sysfs_class::RuntimePowerManagement::On)?; - } - } - // Only these modes should have xorg config - if matches!( - vendor, - GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Integrated - ) { - Self::write_xorg_conf(vendor)?; - } - - // Write different modprobe to enable boot control to work - Self::write_modprobe_conf(vendor, devices)?; - - match vendor { - GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => { - if vfio_enable { - for driver in VFIO_DRIVERS.iter() { - Self::do_driver_action(driver, "rmmod")?; - } - } - for driver in NVIDIA_DRIVERS.iter() { - Self::do_driver_action(driver, "modprobe")?; - } - } - GfxVendors::Vfio => { - if vfio_enable { - Self::do_driver_action("nouveau", "rmmod")?; - for driver in NVIDIA_DRIVERS.iter() { - Self::do_driver_action(driver, "rmmod")?; - } - Self::unbind_only(devices)?; - Self::do_driver_action("vfio-pci", "modprobe")?; - } else { - return Err(GfxError::VfioDisabled.into()); - } - } - GfxVendors::Integrated => { - Self::do_driver_action("nouveau", "rmmod")?; - if vfio_enable { - for driver in VFIO_DRIVERS.iter() { - Self::do_driver_action(driver, "rmmod")?; - } - } - for driver in NVIDIA_DRIVERS.iter() { - Self::do_driver_action(driver, "rmmod")?; - } - Self::unbind_remove_nvidia(devices)?; - } - } - Ok(()) - } - - /// Check if the user has any graphical uiser sessions that are active or online - fn graphical_user_sessions_exist( - connection: &Connection, - sessions: &[SessionInfo], - ) -> Result { - for session in sessions { - let session_proxy = SessionProxy::new(connection, session)?; - if session_proxy.get_class()? == SessionClass::User { - match session_proxy.get_type()? { - SessionType::X11 | SessionType::Wayland | SessionType::MIR => { - match session_proxy.get_state()? { - SessionState::Online | SessionState::Active => return Ok(true), - SessionState::Closing | SessionState::Invalid => {} - } - } - _ => {} - } - } - } - Ok(false) - } - - /// Spools until all user sessions are ended then switches to requested mode - fn create_mode_change_thread( - vendor: GfxVendors, - devices: Vec, - bus: PciBus, - thread_stop: mpsc::Receiver, - config: Arc>, - ) -> Result { - info!("GFX: display-manager thread started"); - - const SLEEP_PERIOD: Duration = Duration::from_millis(100); - let start_time = Instant::now(); - - let connection = Connection::new_system()?; - let manager = ManagerProxy::new(&connection)?; - let mut sessions = manager.list_sessions()?; - - loop { - let tmp = manager.list_sessions()?; - if !tmp.iter().eq(&sessions) { - info!("GFX thread: Sessions list changed"); - sessions = tmp; - } - - if !Self::graphical_user_sessions_exist(&connection, &sessions)? { - break; - } - - if let Ok(stop) = thread_stop.try_recv() { - if stop { - return Ok("Graphics mode change was cancelled".into()); - } - } - // exit if 3 minutes pass - if Instant::now().duration_since(start_time).as_secs() > 180 { - warn!("{}", THREAD_TIMEOUT_MSG); - return Ok(THREAD_TIMEOUT_MSG.into()); - } - - // Don't spin at max speed - sleep(SLEEP_PERIOD); - } - - info!("GFX thread: all graphical user sessions ended, continuing"); - Self::do_display_manager_action("stop")?; - Self::wait_display_manager_state("inactive")?; - - let mut mode_to_save = vendor; - // Need to change to integrated before we can change to vfio or compute - if let Ok(mut config) = config.try_lock() { - // Since we have a lock, reset tmp to none. This thread should only ever run - // for Integrated, Hybrid, or Nvidia. Tmp is also only for informational - config.gfx_tmp_mode = None; - // - let vfio_enable = config.gfx_vfio_enable; - - // Failsafe. In the event this loop is run with a switch from nvidia in use - // to vfio or compute do a forced switch to integrated instead to prevent issues - if matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio) - && matches!(config.gfx_mode, GfxVendors::Nvidia | GfxVendors::Hybrid) - { - Self::do_mode_setup_tasks(GfxVendors::Integrated, vfio_enable, &devices, &bus)?; - Self::do_display_manager_action("restart")?; - mode_to_save = GfxVendors::Integrated; - } else { - Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; - Self::do_display_manager_action("restart")?; - } - } - - // Save selected mode in case of reboot - Self::save_gfx_mode(mode_to_save, config); - info!("GFX thread: display-manager started"); - - let v: &str = vendor.into(); - info!("GFX thread: Graphics mode changed to {} successfully", v); - Ok(format!("Graphics mode changed to {} successfully", v)) - } - - /// Before starting a new thread the old one *must* be cancelled - fn cancel_mode_change_thread(&self) { - if let Ok(lock) = self.thread_kill.lock() { - if let Some(tx) = lock.as_ref() { - // Cancel the running thread - info!("GFX: Cancelling previous thread"); - tx.send(true) - .map_err(|err| { - warn!("GFX thread: {}", err); - }) - .ok(); - } - } - } - - /// The thread is used only in cases where a logout is required - fn setup_mode_change_thread(&mut self, vendor: GfxVendors) { - let config = self.config.clone(); - let devices = self.nvidia.clone(); - let bus = self.bus.clone(); - let (tx, rx) = mpsc::channel(); - if let Ok(mut lock) = self.thread_kill.lock() { - *lock = Some(tx); - } - let thread_kill = self.thread_kill.clone(); - - std::thread::spawn(move || { - Self::create_mode_change_thread(vendor, devices, bus, rx, config) - .map_err(|err| { - error!("GFX: {}", err); - }) - .ok(); - // clear the tx/rx when done - if let Ok(mut lock) = thread_kill.try_lock() { - *lock = None; - } - }); - } - - /// Initiates a mode change by starting a thread that will wait until all - /// graphical sessions are exited before performing the tasks required - /// to switch modes. - /// - /// For manually calling (not on boot/startup) via dbus - pub fn set_gfx_mode(&mut self, vendor: GfxVendors) -> Result { - if let Ok(gsync) = CtrlRogBios::get_gfx_mode() { - if gsync == 1 { - return Err(GfxError::GsyncModeActive.into()); - } - } - - let vfio_enable = if let Ok(config) = self.config.try_lock() { - config.gfx_vfio_enable - } else { - false - }; - - if !vfio_enable && matches!(vendor, GfxVendors::Vfio) { - return Err(GfxError::VfioDisabled.into()); - } - - // Must always cancel any thread running - self.cancel_mode_change_thread(); - // determine which method we need here - let action_required = self.is_logout_required(vendor); - - match action_required { - GfxRequiredUserAction::Logout => { - info!("GFX: mode change requires a logout to complete"); - self.setup_mode_change_thread(vendor); - } - GfxRequiredUserAction::Reboot => { - info!("GFX: mode change requires reboot"); - let devices = self.nvidia.clone(); - let bus = self.bus.clone(); - Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; - info!("GFX: Graphics mode changed to {}", <&str>::from(vendor)); - } - GfxRequiredUserAction::Integrated => { - info!("GFX: mode change requires user to be in Integrated mode first"); - } - GfxRequiredUserAction::None => { - info!("GFX: mode change does not require logout"); - let devices = self.nvidia.clone(); - let bus = self.bus.clone(); - Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; - info!("GFX: Graphics mode changed to {}", <&str>::from(vendor)); - if let Ok(mut config) = self.config.try_lock() { - config.gfx_tmp_mode = None; - if matches!(vendor, GfxVendors::Vfio | GfxVendors::Compute) { - config.gfx_tmp_mode = Some(vendor); - } - } - } - } - - Ok(action_required) - } - - /// Used only on boot to set correct mode - fn auto_power(&mut self) -> Result<(), RogError> { - let vendor = self.get_gfx_mode()?; - let devices = self.nvidia.clone(); - let bus = self.bus.clone(); - - let vfio_enable = if let Ok(config) = self.config.try_lock() { - config.gfx_vfio_enable - } else { - false - }; - - Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?; - Self::toggle_fallback_service(vendor)?; - Ok(()) - } -} diff --git a/daemon/src/ctrl_gfx/error.rs b/daemon/src/ctrl_gfx/error.rs deleted file mode 100644 index ec765653..00000000 --- a/daemon/src/ctrl_gfx/error.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::fmt; -use std::{error, process::ExitStatus}; - -use crate::error::RogError; - -#[derive(Debug)] -pub enum GfxError { - ParseVendor, - ParsePower, - Bus(String, std::io::Error), - DisplayManagerAction(String, ExitStatus), - DisplayManagerTimeout(String), - GsyncModeActive, - VfioBuiltin, - VfioDisabled, - MissingModule(String), - Modprobe(String), - Command(String, std::io::Error), -} - -impl fmt::Display for GfxError { - // This trait requires `fmt` with this exact signature. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - GfxError::ParseVendor => write!(f, "Could not parse vendor name"), - GfxError::ParsePower => write!(f, "Could not parse dGPU power status"), - GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error), - GfxError::DisplayManagerAction(action, status) => { - write!(f, "Display-manager action {} failed: {}", action, status) - } - GfxError::DisplayManagerTimeout(state) => { - write!(f, "Timed out waiting for display-manager {} state", state) - } - GfxError::GsyncModeActive => write!( - f, - "Can not switch gfx modes when dedicated/G-Sync mode is active" - ), - GfxError::VfioBuiltin => write!( - f, - "Can not switch to vfio mode if the modules are built in to kernel" - ), - GfxError::VfioDisabled => { - write!(f, "Can not switch to vfio mode if disabled in config file") - } - GfxError::MissingModule(m) => write!(f, "The module {} is missing", m), - GfxError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), - GfxError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error), - } - } -} - -impl error::Error for GfxError {} - -impl From for RogError { - fn from(err: GfxError) -> Self { - RogError::GfxSwitching(err) - } -} diff --git a/daemon/src/ctrl_gfx/mod.rs b/daemon/src/ctrl_gfx/mod.rs deleted file mode 100644 index 2a2e997b..00000000 --- a/daemon/src/ctrl_gfx/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -pub mod error; - -pub mod controller; - -pub mod system; - -pub mod zbus_gfx; - -const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"]; - -const VFIO_DRIVERS: [&str; 5] = [ - "vfio-pci", - "vfio_iommu_type1", - "vfio_virqfd", - "vfio_mdev", - "vfio", -]; - -const DISPLAY_MANAGER: &str = "display-manager.service"; - -const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf"; - -static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd -# If you have issues with i2c_nvidia_gpu, copy the 2 lines below to a -# new blacklist file and uncomment -#blacklist i2c_nvidia_gpu -#alias i2c_nvidia_gpu off -blacklist nouveau -alias nouveau off -options nvidia NVreg_DynamicPowerManagement=0x02 -"#; - -static MODPROBE_DRM_MODESET: &[u8] = br#" -options nvidia-drm modeset=1 -"#; - -static MODPROBE_INTEGRATED: &[u8] = br#"# Automatically generated by asusd -blacklist i2c_nvidia_gpu -blacklist nvidia -blacklist nvidia-drm -blacklist nvidia-modeset -blacklist nouveau -alias nouveau off -"#; - -static MODPROBE_VFIO: &[u8] = br#"options vfio-pci ids="#; - -const XORG_FILE: &str = "90-nvidia-primary.conf"; -const XORG_PATH: &str = "/etc/X11/xorg.conf.d/"; - -static PRIMARY_GPU_BEGIN: &[u8] = br#"# Automatically generated by asusd -Section "OutputClass" - Identifier "nvidia" - MatchDriver "nvidia-drm" - Driver "nvidia" - Option "AllowEmptyInitialConfiguration" "true""#; - -static PRIMARY_GPU_NVIDIA: &[u8] = br#" - Option "PrimaryGPU" "true""#; - -static PRIMARY_GPU_END: &[u8] = br#" -EndSection"#; diff --git a/daemon/src/ctrl_gfx/system.rs b/daemon/src/ctrl_gfx/system.rs deleted file mode 100644 index ce1ddf67..00000000 --- a/daemon/src/ctrl_gfx/system.rs +++ /dev/null @@ -1,160 +0,0 @@ -use log::{error, info, warn}; -use std::fs::read_to_string; -use std::{fs::write, io, path::PathBuf}; -use sysfs_class::{PciDevice, SysClass}; - -pub struct Module { - pub name: String, -} - -impl Module { - fn parse(line: &str) -> io::Result { - let mut parts = line.split(' '); - - let name = parts - .next() - .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "module name not found"))?; - - Ok(Module { - name: name.to_string(), - }) - } - - pub fn all() -> io::Result> { - let mut modules = Vec::new(); - - let data = read_to_string("/proc/modules")?; - for line in data.lines() { - let module = Module::parse(line)?; - modules.push(module); - } - - Ok(modules) - } -} - -#[derive(Clone)] -pub struct PciBus { - path: PathBuf, -} - -impl PciBus { - pub fn new() -> io::Result { - let path = PathBuf::from("/sys/bus/pci"); - if path.is_dir() { - Ok(PciBus { path }) - } else { - Err(io::Error::new( - io::ErrorKind::NotFound, - "pci directory not found", - )) - } - } - - /// Will rescan the device tree, which adds all removed devices back - pub fn rescan(&self) -> io::Result<()> { - write(self.path.join("rescan"), "1") - } -} - -#[derive(Clone)] -pub struct GraphicsDevice { - _id: String, - functions: Vec, -} - -impl GraphicsDevice { - pub fn new(id: String, functions: Vec) -> GraphicsDevice { - GraphicsDevice { _id: id, functions } - } - - pub fn exists(&self) -> bool { - self.functions.iter().any(|func| func.path().exists()) - } - - pub fn functions(&self) -> &[PciDevice] { - &self.functions - } - - pub fn unbind(&self) -> Result<(), std::io::Error> { - for func in self.functions.iter() { - if func.path().exists() { - match func.driver() { - Ok(driver) => { - info!("{}: Unbinding {}", driver.id(), func.id()); - unsafe { - driver.unbind(func).map_err(|err| { - error!("gfx unbind: {}", err); - err - })?; - } - } - Err(err) => match err.kind() { - io::ErrorKind::NotFound => (), - _ => { - error!("gfx driver: {:?}, {}", func.path(), err); - return Err(err); - } - }, - } - } - } - Ok(()) - } - - pub fn rebind(&self) -> Result<(), std::io::Error> { - for func in self.functions.iter() { - if func.path().exists() { - match func.driver() { - Ok(driver) => { - info!("{}: Binding {}", driver.id(), func.id()); - unsafe { - driver.bind(func).map_err(|err| { - error!("gfx bind: {}", err); - err - })?; - } - } - Err(err) => match err.kind() { - io::ErrorKind::NotFound => (), - _ => { - error!("gfx driver: {:?}, {}", func.path(), err); - return Err(err); - } - }, - } - } - } - Ok(()) - } - - pub fn remove(&self) -> Result<(), std::io::Error> { - for func in self.functions.iter() { - if func.path().exists() { - match func.driver() { - Ok(driver) => { - error!("{}: in use by {}", func.id(), driver.id()); - } - Err(why) => match why.kind() { - std::io::ErrorKind::NotFound => { - info!("{}: Removing", func.id()); - unsafe { - // ignore errors and carry on - if let Err(err) = func.remove() { - error!("gfx remove: {}", err); - } - } - } - _ => { - error!("Remove device failed"); - } - }, - } - } else { - warn!("{}: Already removed", func.id()); - } - } - info!("Removed all gfx devices"); - Ok(()) - } -} diff --git a/daemon/src/ctrl_gfx/zbus_gfx.rs b/daemon/src/ctrl_gfx/zbus_gfx.rs deleted file mode 100644 index 8c66ac1d..00000000 --- a/daemon/src/ctrl_gfx/zbus_gfx.rs +++ /dev/null @@ -1,56 +0,0 @@ -use ::zbus::dbus_interface; -use log::{error, info, warn}; -use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; -use zvariant::ObjectPath; - -use crate::ZbusAdd; - -use super::controller::CtrlGraphics; - -#[dbus_interface(name = "org.asuslinux.Daemon")] -impl CtrlGraphics { - fn vendor(&self) -> zbus::fdo::Result { - self.get_gfx_mode().map_err(|err| { - error!("GFX: {}", err); - zbus::fdo::Error::Failed(format!("GFX fail: {}", err)) - }) - } - - fn power(&self) -> zbus::fdo::Result { - Self::get_runtime_status().map_err(|err| { - error!("GFX: {}", err); - zbus::fdo::Error::Failed(format!("GFX fail: {}", err)) - }) - } - - fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result { - info!("GFX: Switching gfx mode to {}", <&str>::from(vendor)); - let msg = self.set_gfx_mode(vendor).map_err(|err| { - error!("GFX: {}", err); - zbus::fdo::Error::Failed(format!("GFX fail: {}", err)) - })?; - self.notify_gfx(&vendor) - .unwrap_or_else(|err| warn!("GFX: {}", err)); - self.notify_action(&msg) - .unwrap_or_else(|err| warn!("GFX: {}", err)); - Ok(msg) - } - - #[dbus_interface(signal)] - fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {} - - #[dbus_interface(signal)] - fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {} -} - -impl ZbusAdd for CtrlGraphics { - fn add_to_server(self, server: &mut zbus::ObjectServer) { - server - .at(&ObjectPath::from_str_unchecked("/org/asuslinux/Gfx"), self) - .map_err(|err| { - warn!("GFX: CtrlGraphics: add_to_server {}", err); - err - }) - .ok(); - } -} diff --git a/daemon/src/ctrl_profiles/config.rs b/daemon/src/ctrl_profiles/config.rs new file mode 100644 index 00000000..9907ba5f --- /dev/null +++ b/daemon/src/ctrl_profiles/config.rs @@ -0,0 +1,92 @@ +use log::{error, warn}; +use rog_profiles::error::ProfileError; +use rog_profiles::{FanCurves, Profile}; +use serde_derive::{Deserialize, Serialize}; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; + +#[derive(Deserialize, Serialize, Debug)] +pub struct ProfileConfig { + #[serde(skip)] + config_path: String, + /// For restore on boot + pub active: Profile, + /// States to restore + pub fan_curves: Option, +} + +impl ProfileConfig { + fn new(config_path: String) -> Result { + let mut platform = ProfileConfig { + config_path, + active: Profile::Balanced, + fan_curves: None, + }; + + if !Profile::is_platform_profile_supported() { + return Err(ProfileError::NotSupported); + } + + if FanCurves::is_fan_curves_supported() { + let mut curves = FanCurves::default(); + curves.update_from_platform(); + platform.fan_curves = Some(curves); + } + Ok(platform) + } +} + +impl ProfileConfig { + pub fn load(config_path: String) -> Self { + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&config_path) + .unwrap_or_else(|_| panic!("The directory /etc/asusd/ is missing")); // okay to cause panic here + let mut buf = String::new(); + let mut config; + if let Ok(read_len) = file.read_to_string(&mut buf) { + if read_len == 0 { + config = Self::new(config_path).unwrap(); + } else if let Ok(data) = serde_json::from_str(&buf) { + config = data; + config.config_path = config_path; + } else { + warn!("Could not deserialise {}", config_path); + panic!("Please remove {} then restart service", config_path); + } + } else { + config = Self::new(config_path).unwrap() + } + config.write(); + config + } + + pub fn read(&mut self) { + let mut file = OpenOptions::new() + .read(true) + .open(&self.config_path) + .unwrap_or_else(|err| panic!("Error reading {}: {}", self.config_path, err)); + + let mut buf = String::new(); + if let Ok(l) = file.read_to_string(&mut buf) { + if l == 0 { + warn!("File is empty {}", self.config_path); + } else { + let mut data: ProfileConfig = serde_json::from_str(&buf) + .unwrap_or_else(|_| panic!("Could not deserialise {}", self.config_path)); + // copy over serde skipped values + data.config_path = self.config_path.clone(); + *self = data; + } + } + } + + pub fn write(&self) { + let mut file = File::create(&self.config_path).expect("Couldn't overwrite config"); + let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed"); + file.write_all(json.as_bytes()) + .unwrap_or_else(|err| error!("Could not write config: {}", err)); + } +} diff --git a/daemon/src/ctrl_profiles/controller.rs b/daemon/src/ctrl_profiles/controller.rs index e6cd3791..3faffcec 100644 --- a/daemon/src/ctrl_profiles/controller.rs +++ b/daemon/src/ctrl_profiles/controller.rs @@ -1,116 +1,118 @@ use crate::error::RogError; -use crate::{config::Config, GetSupported}; +use crate::GetSupported; use log::{info, warn}; -use rog_profiles::profiles::Profile; -use rog_types::supported::FanCpuSupportedFunctions; +use rog_profiles::error::ProfileError; +use rog_profiles::{FanCurves, Profile}; +use rog_supported::PlatformProfileFunctions; use std::sync::Arc; use std::sync::Mutex; -pub struct CtrlFanAndCpu { - pub config: Arc>, +use super::config::ProfileConfig; + +pub struct CtrlPlatformTask { + config: Arc>, } -impl GetSupported for CtrlFanAndCpu { - type A = FanCpuSupportedFunctions; +impl CtrlPlatformTask { + pub fn new(config: Arc>) -> Self { + Self { config } + } +} + +impl crate::CtrlTask for CtrlPlatformTask { + fn do_task(&self) -> Result<(), RogError> { + if let Ok(mut lock) = self.config.try_lock() { + // Refresh the config in-case the user has edited it + if let Some(curves) = &mut lock.fan_curves { + curves.update_from_platform(); + } + } + Ok(()) + } +} + +pub struct CtrlPlatformProfile { + pub config: Arc>, +} + +impl GetSupported for CtrlPlatformProfile { + type A = PlatformProfileFunctions; fn get_supported() -> Self::A { - FanCpuSupportedFunctions { - stock_fan_modes: Profile::get_fan_path().is_ok(), - min_max_freq: Profile::get_intel_supported(), - fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(), + if !Profile::is_platform_profile_supported() { + warn!( + r#" +platform_profile kernel interface not found, your laptop does not support this, or the iterface is missing. +To enable profile support you require a kernel with the following patch applied: +https://lkml.org/lkml/2021/8/18/1022 +"# + ); + } + if !FanCurves::is_fan_curves_supported() { + info!( + r#" +fan curves kernel interface not found, your laptop does not support this, or the iterface is missing. +To enable fan-curve support you require a kernel with the following patch applied: +https://lkml.org/lkml/2021/8/20/232 +Please note that as of 24/08/2021 this is not final. +"# + ); + } + PlatformProfileFunctions { + platform_profile: Profile::is_platform_profile_supported(), + fan_curves: FanCurves::is_fan_curves_supported(), } } } -impl crate::Reloadable for CtrlFanAndCpu { - /// Fetcht he active profile and use that to set all related components up +impl crate::Reloadable for CtrlPlatformProfile { + /// Fetch the active profile and use that to set all related components up fn reload(&mut self) -> Result<(), RogError> { - if let Ok(mut cfg) = self.config.clone().try_lock() { - let active = cfg.active_profile.clone(); - if let Some(existing) = cfg.power_profiles.get_mut(&active) { - existing.set_system_all()?; + if let Ok(cfg) = self.config.clone().try_lock() { + if let Some(curves) = &cfg.fan_curves { + curves.update_platform(); } } Ok(()) } } -impl CtrlFanAndCpu { - pub fn new(config: Arc>) -> Result { - Profile::get_fan_path()?; - info!("Device has fan control available"); - Ok(CtrlFanAndCpu { config }) +impl CtrlPlatformProfile { + pub fn new(config: Arc>) -> Result { + if Profile::is_platform_profile_supported() { + info!("Device has profile control available"); + return Ok(CtrlPlatformProfile { config }); + } + Err(ProfileError::NotSupported.into()) } - /// Toggle to next profile in list - pub(super) fn do_next_profile(&mut self) -> Result<(), RogError> { + pub fn save_config(&self) { + if let Ok(lock) = self.config.lock() { + lock.write(); + } + } + + /// Toggle to next profile in list. This will first read the config, switch, then write out + pub(super) fn set_next_profile(&mut self) -> Result<(), RogError> { if let Ok(mut config) = self.config.clone().try_lock() { // Read first just incase the user has modified the config before calling this config.read(); - let mut toggle_index = config - .toggle_profiles - .binary_search(&config.active_profile) - .unwrap_or(0) - + 1; - if toggle_index >= config.toggle_profiles.len() { - toggle_index = 0; + match config.active { + Profile::Balanced => { + Profile::set_profile(Profile::Performance); + config.active = Profile::Performance; + } + Profile::Performance => { + Profile::set_profile(Profile::Quiet); + config.active = Profile::Quiet; + } + Profile::Quiet => { + Profile::set_profile(Profile::Balanced); + config.active = Profile::Balanced; + } } - let profile = config.toggle_profiles[toggle_index].clone(); - - if let Some(existing) = config.power_profiles.get(&profile) { - existing.set_system_all()?; - config.active_profile = existing.name.clone(); - config.write(); - info!("Profile was changed to: {}", &profile); - } else { - warn!( - "toggle_profile {} does not exist in power_profiles", - &profile - ); - return Err(RogError::MissingProfile(profile.to_string())); - } - } - Ok(()) - } - - pub(super) fn set_active(&mut self, profile: &str) -> Result<(), RogError> { - if let Ok(mut config) = self.config.clone().try_lock() { - // Read first just incase the user has modified the config before calling this - config.read(); - if let Some(existing) = config.power_profiles.get(profile) { - existing.set_system_all()?; - config.active_profile = existing.name.clone(); - config.write(); - info!("Profile was changed to: {}", profile); - } else { - warn!( - "toggle_profile {} does not exist in power_profiles", - profile - ); - return Err(RogError::MissingProfile(profile.to_string())); - } - } - Ok(()) - } - - /// Create a new profile if the requested name doesn't exist, or modify existing - pub(super) fn new_or_modify(&mut self, profile: &Profile) -> Result<(), RogError> { - if let Ok(mut config) = self.config.clone().try_lock() { - config.read(); - - if let Some(existing) = config.power_profiles.get_mut(&profile.name) { - *existing = profile.clone(); - existing.set_system_all()?; - } else { - config - .power_profiles - .insert(profile.name.clone(), profile.clone()); - profile.set_system_all()?; - } - - config.active_profile = profile.name.clone(); config.write(); } Ok(()) diff --git a/daemon/src/ctrl_profiles/mod.rs b/daemon/src/ctrl_profiles/mod.rs index 7df7470d..85a4d229 100644 --- a/daemon/src/ctrl_profiles/mod.rs +++ b/daemon/src/ctrl_profiles/mod.rs @@ -1,3 +1,3 @@ -pub mod zbus; - +pub mod config; pub mod controller; +pub mod zbus; diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/zbus.rs index 84c7da2b..4f26d79a 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/zbus.rs @@ -1,58 +1,54 @@ use log::warn; -use rog_profiles::profiles::Profile; +use rog_profiles::FanCurve; +use rog_profiles::Profile; use std::sync::Arc; use std::sync::Mutex; use zbus::{dbus_interface, fdo::Error}; use zvariant::ObjectPath; -use super::controller::CtrlFanAndCpu; +use super::controller::CtrlPlatformProfile; -pub struct FanAndCpuZbus { - inner: Arc>, +static UNSUPPORTED_MSG: &str = + "Fan curves are not supported on this laptop or you require a patched kernel"; + +pub struct ProfileZbus { + inner: Arc>, } -impl FanAndCpuZbus { - pub fn new(inner: Arc>) -> Self { +impl ProfileZbus { + pub fn new(inner: Arc>) -> Self { Self { inner } } } #[dbus_interface(name = "org.asuslinux.Daemon")] -impl FanAndCpuZbus { - /// Create new profile and make active - fn set_profile(&self, profile: String) { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.set_active(&profile) - .unwrap_or_else(|err| warn!("{}", err)); +impl ProfileZbus { + /// Fetch profile names + fn profiles(&mut self) -> zbus::fdo::Result> { + if let Ok(profiles) = Profile::get_profile_names() { + return Ok(profiles); } - self.do_notification(); + Err(Error::Failed( + "Failed to get all profile details".to_string(), + )) } - /// New or modify profile details and make active, will create if it does not exist - fn new_or_modify(&self, profile: Profile) { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.new_or_modify(&profile) - .unwrap_or_else(|err| warn!("{}", err)); - } - self.do_notification(); - } - - /// Fetch the active profile name + /// Toggle to next platform_profile. Names provided by `Profiles` fn next_profile(&mut self) { if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.do_next_profile() + ctrl.set_next_profile() .unwrap_or_else(|err| warn!("{}", err)); } self.do_notification(); } /// Fetch the active profile name - fn active_name(&mut self) -> zbus::fdo::Result { + fn active_profile(&mut self) -> zbus::fdo::Result { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - return Ok(cfg.active_profile.clone()); + return Ok(cfg.active); } } Err(Error::Failed( @@ -60,94 +56,96 @@ impl FanAndCpuZbus { )) } - // TODO: Profile can't implement Type because of Curve - /// Fetch the active profile details - fn active_data(&mut self) -> zbus::fdo::Result { + /// Set this platform_profile name as active + fn set_active_profile(&self, profile: Profile) { + if let Ok(ctrl) = self.inner.try_lock() { + if let Ok(mut cfg) = ctrl.config.try_lock() { + // Read first just incase the user has modified the config before calling this + cfg.read(); + Profile::set_profile(profile); + cfg.active = profile; + } + ctrl.save_config(); + } + self.do_notification(); + } + + /// Get a list of profiles that have fan-curves enabled. + fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result> { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) { - return Ok(profile.clone()); + if let Some(curves) = &cfg.fan_curves { + return Ok(curves.get_enabled_curve_names().to_vec()); } + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } } Err(Error::Failed( - "Failed to get active profile details".to_string(), + "Failed to get enabled fan curve names".to_string(), )) } - /// Fetch all profile data - fn profiles(&mut self) -> zbus::fdo::Result> { + /// Get the fan-curve data for the currently active Profile + fn active_fan_curve_data(&mut self) -> zbus::fdo::Result { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - return Ok(cfg.power_profiles.values().cloned().collect()); + if let Some(curves) = &cfg.fan_curves { + return Ok((*curves.get_active_fan_curves()).clone()); + } + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } } - Err(Error::Failed( - "Failed to get all profile details".to_string(), - )) + Err(Error::Failed("Failed to get fan curve data".to_string())) } - fn profile_names(&self) -> zbus::fdo::Result> { + /// Get fan-curve data for each Profile as an array of objects + fn fan_curves(&self) -> zbus::fdo::Result> { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - let profile_names = cfg.power_profiles.keys().cloned().collect::>(); - return Ok(profile_names); + if let Some(curves) = &cfg.fan_curves { + return Ok(curves.get_all_fan_curves()); + } + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } } - - Err(Error::Failed("Failed to get all profile names".to_string())) + Err(Error::Failed("Failed to get all fan curves".to_string())) } - fn remove(&self, profile: &str) -> zbus::fdo::Result<()> { + /// Set this fan-curve data + fn set_fan_curve(&self, curve: FanCurve) -> zbus::fdo::Result<()> { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(mut cfg) = ctrl.config.try_lock() { cfg.read(); - - if !cfg.power_profiles.contains_key(profile) { - return Err(Error::Failed("Invalid profile specified".to_string())); + if let Some(curves) = &mut cfg.fan_curves { + curves.set_fan_curve(curve); } - - if cfg.power_profiles.keys().len() == 1 { - return Err(Error::Failed("Cannot delete the last profile".to_string())); - } - - if cfg.active_profile == *profile { - return Err(Error::Failed( - "Cannot delete the active profile".to_string(), - )); - } - - cfg.power_profiles.remove(profile); - cfg.write(); - - return Ok(()); + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } + ctrl.save_config(); } - Err(Error::Failed("Failed to lock configuration".to_string())) + Err(Error::Failed("Failed to set fan curves".to_string())) } #[dbus_interface(signal)] fn notify_profile(&self, profile: &Profile) -> zbus::Result<()> {} } -impl FanAndCpuZbus { +impl ProfileZbus { fn do_notification(&self) { if let Ok(ctrl) = self.inner.try_lock() { if let Ok(cfg) = ctrl.config.clone().try_lock() { - if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) { - self.notify_profile(profile) - .unwrap_or_else(|err| warn!("{}", err)); - } + self.notify_profile(&cfg.active) + .unwrap_or_else(|err| warn!("{}", err)); } } } } -impl crate::ZbusAdd for FanAndCpuZbus { +impl crate::ZbusAdd for ProfileZbus { fn add_to_server(self, server: &mut zbus::ObjectServer) { server .at( diff --git a/daemon/src/ctrl_rog_bios.rs b/daemon/src/ctrl_rog_bios.rs index e2817e8b..d9fbef7c 100644 --- a/daemon/src/ctrl_rog_bios.rs +++ b/daemon/src/ctrl_rog_bios.rs @@ -1,6 +1,6 @@ use crate::{config::Config, error::RogError, GetSupported}; use log::{error, info, warn}; -use rog_types::supported::RogBiosSupportedFunctions; +use rog_supported::RogBiosSupportedFunctions; use std::fs::OpenOptions; use std::io::BufRead; use std::io::{Read, Write}; diff --git a/daemon/src/ctrl_supported.rs b/daemon/src/ctrl_supported.rs index 60fedf07..6c1a04e6 100644 --- a/daemon/src/ctrl_supported.rs +++ b/daemon/src/ctrl_supported.rs @@ -5,20 +5,20 @@ use zvariant::ObjectPath; use zvariant_derive::Type; use crate::{ - ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::controller::CtrlKbdLed, - ctrl_profiles::controller::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios, GetSupported, + ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_charge::CtrlCharge, + ctrl_profiles::controller::CtrlPlatformProfile, ctrl_rog_bios::CtrlRogBios, GetSupported, }; -use rog_types::supported::{ - AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions, - LedSupportedFunctions, RogBiosSupportedFunctions, +use rog_supported::{ + AnimeSupportedFunctions, ChargeSupportedFunctions, LedSupportedFunctions, + PlatformProfileFunctions, RogBiosSupportedFunctions, }; #[derive(Serialize, Deserialize, Type)] pub struct SupportedFunctions { pub anime_ctrl: AnimeSupportedFunctions, pub charge_ctrl: ChargeSupportedFunctions, - pub fan_cpu_ctrl: FanCpuSupportedFunctions, + pub platform_profile: PlatformProfileFunctions, pub keyboard_led: LedSupportedFunctions, pub rog_bios_ctrl: RogBiosSupportedFunctions, } @@ -53,7 +53,7 @@ impl GetSupported for SupportedFunctions { anime_ctrl: CtrlAnime::get_supported(), keyboard_led: CtrlKbdLed::get_supported(), charge_ctrl: CtrlCharge::get_supported(), - fan_cpu_ctrl: CtrlFanAndCpu::get_supported(), + platform_profile: CtrlPlatformProfile::get_supported(), rog_bios_ctrl: CtrlRogBios::get_supported(), } } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 4bd8c604..78318fc6 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -1,32 +1,35 @@ -use daemon::ctrl_leds::controller::{ +use daemon::ctrl_anime::config::AnimeConfig; +use daemon::ctrl_anime::zbus::CtrlAnimeZbus; +use daemon::ctrl_anime::*; +use daemon::ctrl_aura::config::AuraConfig; +use daemon::ctrl_aura::controller::{ CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus, }; +use daemon::ctrl_charge::CtrlCharge; +use daemon::ctrl_profiles::config::ProfileConfig; +use daemon::ctrl_profiles::controller::CtrlPlatformTask; use daemon::{ config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported, }; -use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge}; -use daemon::{ctrl_anime::*, ctrl_gfx::controller::CtrlGraphics}; use daemon::{ - ctrl_profiles::{controller::CtrlFanAndCpu, zbus::FanAndCpuZbus}, + ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus}, laptops::LaptopLedData, }; +use ::zbus::{fdo, Connection, ObjectServer}; use daemon::{CtrlTask, Reloadable, ZbusAdd}; use log::LevelFilter; use log::{error, info, warn}; use rog_dbus::DBUS_NAME; -use rog_types::gfx_vendors::GfxVendors; +use std::env; use std::error::Error; use std::io::Write; use std::sync::Arc; use std::sync::Mutex; -use std::env; use daemon::ctrl_rog_bios::CtrlRogBios; -use std::convert::Into; -use zbus::fdo; -use zbus::Connection; -use zvariant::ObjectPath; + +static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf"; pub fn main() -> Result<(), Box> { let mut logger = env_logger::Builder::new(); @@ -43,17 +46,19 @@ pub fn main() -> Result<(), Box> { if !is_service { println!("asusd schould be only run from the right systemd service"); - println!("do not run in your terminal, if you need an logs please use journalctl -b -u asusd"); + println!( + "do not run in your terminal, if you need an logs please use journalctl -b -u asusd" + ); println!("asusd will now exit"); return Ok(()); } - info!(" daemon v{}", daemon::VERSION); - info!(" rog-anime v{}", rog_anime::VERSION); - info!(" rog-aura v{}", rog_aura::VERSION); - info!(" rog-dbus v{}", rog_dbus::VERSION); - info!("rog-profiles v{}", rog_profiles::VERSION); - info!(" rog-types v{}", rog_types::VERSION); + info!(" daemon v{}", daemon::VERSION); + info!(" rog-anime v{}", rog_anime::VERSION); + info!(" rog-aura v{}", rog_aura::VERSION); + info!(" rog-dbus v{}", rog_dbus::VERSION); + info!(" rog-profiles v{}", rog_profiles::VERSION); + info!("rog-supported v{}", rog_supported::VERSION); start_daemon()?; Ok(()) @@ -71,10 +76,9 @@ fn start_daemon() -> Result<(), Box> { let connection = Connection::new_system()?; fdo::DBusProxy::new(&connection)? .request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?; - let mut object_server = zbus::ObjectServer::new(&connection); + let mut object_server = ObjectServer::new(&connection); let config = Config::load(); - let enable_gfx_switching = config.gfx_managed; let config = Arc::new(Mutex::new(config)); supported.add_to_server(&mut object_server); @@ -92,7 +96,7 @@ fn start_daemon() -> Result<(), Box> { } } - match CtrlCharge::new(config.clone()) { + match CtrlCharge::new(config) { Ok(mut ctrl) => { // Do a reload of any settings ctrl.reload() @@ -105,12 +109,16 @@ fn start_daemon() -> Result<(), Box> { } } - match CtrlFanAndCpu::new(config.clone()) { + let profile_config = Arc::new(Mutex::new(ProfileConfig::load(PROFILE_CONFIG_PATH.into()))); + match CtrlPlatformProfile::new(profile_config.clone()) { Ok(mut ctrl) => { ctrl.reload() .unwrap_or_else(|err| warn!("Profile control: {}", err)); + let tmp = Arc::new(Mutex::new(ctrl)); - FanAndCpuZbus::new(tmp).add_to_server(&mut object_server); + ProfileZbus::new(tmp).add_to_server(&mut object_server); + + tasks.push(Box::new(CtrlPlatformTask::new(profile_config))); } Err(err) => { error!("Profile control: {}", err); @@ -156,48 +164,6 @@ fn start_daemon() -> Result<(), Box> { } } - // Graphics switching requires some checks on boot specifically for g-sync capable laptops - if enable_gfx_switching { - match CtrlGraphics::new(config.clone()) { - Ok(mut ctrl) => { - // Need to check if a laptop has the dedicated gfx switch - if CtrlRogBios::has_dedicated_gfx_toggle() { - if let Ok(ded) = CtrlRogBios::get_gfx_mode() { - if let Ok(config) = config.lock() { - if ded == 1 { - warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode"); - let devices = ctrl.devices(); - let bus = ctrl.bus(); - CtrlGraphics::do_mode_setup_tasks( - GfxVendors::Nvidia, - false, - &devices, - &bus, - )?; - } else if ded == 0 { - info!("Dedicated GFX toggle is off"); - let devices = ctrl.devices(); - let bus = ctrl.bus(); - CtrlGraphics::do_mode_setup_tasks( - config.gfx_mode, - false, - &devices, - &bus, - )?; - } - } - } - } - ctrl.reload() - .unwrap_or_else(|err| error!("Gfx controller: {}", err)); - ctrl.add_to_server(&mut object_server); - } - Err(err) => { - error!("Gfx control: {}", err); - } - } - } - // TODO: implement messaging between threads to check fails // Run tasks @@ -216,18 +182,18 @@ fn start_daemon() -> Result<(), Box> { }); // Run zbus server - object_server - .with( - &ObjectPath::from_str_unchecked("/org/asuslinux/Charge"), - |obj: &CtrlCharge| { - let x = obj.limit(); - obj.notify_charge(x as u8) - }, - ) - .map_err(|err| { - warn!("object_server notify_charge error: {}", err); - }) - .ok(); + // object_server + // .with( + // &ObjectPath::from_str_unchecked("/org/asuslinux/Charge"), + // |obj: &CtrlCharge| { + // let x = obj.limit(); + // obj.notify_charge(x as u8) + // }, + // ) + // .map_err(|err| { + // warn!("object_server notify_charge error: {}", err); + // }) + // .ok(); // Loop to check errors and iterate zbus server loop { diff --git a/daemon/src/error.rs b/daemon/src/error.rs index fa61f61e..bcfb9111 100644 --- a/daemon/src/error.rs +++ b/daemon/src/error.rs @@ -1,11 +1,7 @@ -use rog_fan_curve::CurveError; use rog_profiles::error::ProfileError; -use rog_types::error::GraphicsError; use std::convert::From; use std::fmt; -use crate::ctrl_gfx::error::GfxError; - #[derive(Debug)] pub enum RogError { ParseVendor, @@ -17,16 +13,13 @@ pub enum RogError { Write(String, std::io::Error), NotSupported, NotFound(String), - FanCurve(CurveError), DoTask(String), MissingFunction(String), MissingLedBrightNode(String, std::io::Error), ReloadFail(String), - GfxSwitching(GfxError), Profiles(ProfileError), Initramfs(String), Modprobe(String), - Command(String, std::io::Error), Io(std::io::Error), Zbus(zbus::Error), } @@ -44,16 +37,13 @@ impl fmt::Display for RogError { RogError::Write(path, error) => write!(f, "Write {}: {}", path, error), RogError::NotSupported => write!(f, "Not supported"), RogError::NotFound(deets) => write!(f, "Not found: {}", deets), - RogError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err), RogError::DoTask(deets) => write!(f, "Task error: {}", deets), RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets), - RogError::GfxSwitching(deets) => write!(f, "Graphics switching error: {}", deets), RogError::Profiles(deets) => write!(f, "Profile error: {}", deets), RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail), RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), - RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error), RogError::Io(detail) => write!(f, "std::io error: {}", detail), RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail), } @@ -62,21 +52,6 @@ impl fmt::Display for RogError { impl std::error::Error for RogError {} -impl From for RogError { - fn from(err: CurveError) -> Self { - RogError::FanCurve(err) - } -} - -impl From for RogError { - fn from(err: GraphicsError) -> Self { - match err { - GraphicsError::ParseVendor => RogError::GfxSwitching(GfxError::ParseVendor), - GraphicsError::ParsePower => RogError::GfxSwitching(GfxError::ParsePower), - } - } -} - impl From for RogError { fn from(err: ProfileError) -> Self { RogError::Profiles(err) diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index c331569a..766f9cd7 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -1,17 +1,12 @@ #![deny(unused_must_use)] /// Configuration loading, saving pub mod config; -pub mod config_anime; -pub mod config_aura; -pub(crate) mod config_old; /// Control of AniMe matrix display pub mod ctrl_anime; +/// Keyboard LED brightness control, RGB, and LED display modes +pub mod ctrl_aura; /// Control of battery charge level pub mod ctrl_charge; -/// GPU switching and power -pub mod ctrl_gfx; -/// Keyboard LED brightness control, RGB, and LED display modes -pub mod ctrl_leds; /// Control CPU min/max freq and turbo, fan mode, fan curves /// /// Intel machines can control: diff --git a/data/90-asusd-nvidia-pm.rules b/data/90-asusd-nvidia-pm.rules deleted file mode 100644 index ba3cefef..00000000 --- a/data/90-asusd-nvidia-pm.rules +++ /dev/null @@ -1,7 +0,0 @@ -# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind -ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto" -ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto" - -# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind -ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on" -ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on" diff --git a/data/90-nvidia-screen-G05.conf b/data/90-nvidia-screen-G05.conf deleted file mode 100644 index 7e561fc5..00000000 --- a/data/90-nvidia-screen-G05.conf +++ /dev/null @@ -1,4 +0,0 @@ -Section "ServerLayout" - Identifier "layout" - Option "AllowNVIDIAGPUScreens" -EndSection diff --git a/data/asusd.service b/data/asusd.service index 37d17010..9f0ee849 100644 --- a/data/asusd.service +++ b/data/asusd.service @@ -2,7 +2,7 @@ Description=ASUS Notebook Control StartLimitInterval=200 StartLimitBurst=2 -Before=display-manager.service +Before=multi-user.target [Service] Environment=IS_SERVICE=1 diff --git a/data/user-example.json b/data/user-example.json deleted file mode 100644 index 9f3600e9..00000000 --- a/data/user-example.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "anime": [ - { - "AsusAnimation": { - "file": "/usr/share/asusd/anime/asus/rog/Sunset.gif", - "time": { - "Cycles": 1 - }, - "brightness": 0.5 - } - }, - { - "ImageAnimation": { - "file": "/usr/share/asusd/anime/custom/sonic-run.gif", - "scale": 0.9, - "angle": 0.65, - "translation": [ - 0.0, - 0.0 - ], - "time": { - "Time": { - "secs": 5, - "nanos": 0 - } - }, - "brightness": 0.5 - } - }, - { - "Image": { - "file": "/usr/share/asusd/anime/custom/rust.png", - "scale": 1.0, - "angle": 0.0, - "translation": [ - 0.0, - 0.0 - ], - "brightness": 0.6 - } - }, - { - "Pause": { - "secs": 6, - "nanos": 0 - } - }, - { - "ImageAnimation": { - "file": "/usr/share/asusd/anime/custom/sonic-wait.gif", - "scale": 0.9, - "angle": 0.0, - "translation": [ - 3.0, - 2.0 - ], - "time": { - "Cycles": 2 - }, - "brightness": 0.5 - } - } - ] -} diff --git a/data/anime/asus/festive/Cupid.gif b/rog-anime/data/anime/asus/festive/Cupid.gif similarity index 100% rename from data/anime/asus/festive/Cupid.gif rename to rog-anime/data/anime/asus/festive/Cupid.gif diff --git a/data/anime/asus/festive/Firework.gif b/rog-anime/data/anime/asus/festive/Firework.gif similarity index 100% rename from data/anime/asus/festive/Firework.gif rename to rog-anime/data/anime/asus/festive/Firework.gif diff --git a/data/anime/asus/festive/Halloween.gif b/rog-anime/data/anime/asus/festive/Halloween.gif similarity index 100% rename from data/anime/asus/festive/Halloween.gif rename to rog-anime/data/anime/asus/festive/Halloween.gif diff --git a/data/anime/asus/festive/Happy Holiday.gif b/rog-anime/data/anime/asus/festive/Happy Holiday.gif similarity index 100% rename from data/anime/asus/festive/Happy Holiday.gif rename to rog-anime/data/anime/asus/festive/Happy Holiday.gif diff --git a/data/anime/asus/festive/Happy new year.gif b/rog-anime/data/anime/asus/festive/Happy new year.gif similarity index 100% rename from data/anime/asus/festive/Happy new year.gif rename to rog-anime/data/anime/asus/festive/Happy new year.gif diff --git a/data/anime/asus/festive/Lantern.gif b/rog-anime/data/anime/asus/festive/Lantern.gif similarity index 100% rename from data/anime/asus/festive/Lantern.gif rename to rog-anime/data/anime/asus/festive/Lantern.gif diff --git a/rog-anime/data/anime/asus/festive/Love u mom.gif b/rog-anime/data/anime/asus/festive/Love u mom.gif new file mode 100755 index 00000000..8fd6d363 Binary files /dev/null and b/rog-anime/data/anime/asus/festive/Love u mom.gif differ diff --git a/rog-anime/data/anime/asus/festive/Mother's day.gif b/rog-anime/data/anime/asus/festive/Mother's day.gif new file mode 100755 index 00000000..e95d0243 Binary files /dev/null and b/rog-anime/data/anime/asus/festive/Mother's day.gif differ diff --git a/data/anime/asus/festive/Valentine's Day.gif b/rog-anime/data/anime/asus/festive/Valentine's Day.gif similarity index 100% rename from data/anime/asus/festive/Valentine's Day.gif rename to rog-anime/data/anime/asus/festive/Valentine's Day.gif diff --git a/data/anime/asus/festive/Year of the Ox.gif b/rog-anime/data/anime/asus/festive/Year of the Ox.gif similarity index 100% rename from data/anime/asus/festive/Year of the Ox.gif rename to rog-anime/data/anime/asus/festive/Year of the Ox.gif diff --git a/data/anime/asus/gaming/Bird.gif b/rog-anime/data/anime/asus/gaming/Bird.gif similarity index 100% rename from data/anime/asus/gaming/Bird.gif rename to rog-anime/data/anime/asus/gaming/Bird.gif diff --git a/data/anime/asus/gaming/Controller.gif b/rog-anime/data/anime/asus/gaming/Controller.gif similarity index 100% rename from data/anime/asus/gaming/Controller.gif rename to rog-anime/data/anime/asus/gaming/Controller.gif diff --git a/data/anime/asus/gaming/FPS.gif b/rog-anime/data/anime/asus/gaming/FPS.gif similarity index 100% rename from data/anime/asus/gaming/FPS.gif rename to rog-anime/data/anime/asus/gaming/FPS.gif diff --git a/data/anime/asus/gaming/Fight.gif b/rog-anime/data/anime/asus/gaming/Fight.gif similarity index 100% rename from data/anime/asus/gaming/Fight.gif rename to rog-anime/data/anime/asus/gaming/Fight.gif diff --git a/data/anime/asus/gaming/Keyboard.gif b/rog-anime/data/anime/asus/gaming/Keyboard.gif similarity index 100% rename from data/anime/asus/gaming/Keyboard.gif rename to rog-anime/data/anime/asus/gaming/Keyboard.gif diff --git a/data/anime/asus/gaming/MOBA.gif b/rog-anime/data/anime/asus/gaming/MOBA.gif similarity index 100% rename from data/anime/asus/gaming/MOBA.gif rename to rog-anime/data/anime/asus/gaming/MOBA.gif diff --git a/data/anime/asus/gaming/UFO.gif b/rog-anime/data/anime/asus/gaming/UFO.gif similarity index 100% rename from data/anime/asus/gaming/UFO.gif rename to rog-anime/data/anime/asus/gaming/UFO.gif diff --git a/data/anime/asus/music/DJ.gif b/rog-anime/data/anime/asus/music/DJ.gif similarity index 100% rename from data/anime/asus/music/DJ.gif rename to rog-anime/data/anime/asus/music/DJ.gif diff --git a/rog-anime/data/anime/asus/music/Diamond.gif b/rog-anime/data/anime/asus/music/Diamond.gif new file mode 100755 index 00000000..cc2da200 Binary files /dev/null and b/rog-anime/data/anime/asus/music/Diamond.gif differ diff --git a/data/anime/asus/music/Music-player.gif b/rog-anime/data/anime/asus/music/Music-player.gif similarity index 100% rename from data/anime/asus/music/Music-player.gif rename to rog-anime/data/anime/asus/music/Music-player.gif diff --git a/data/anime/asus/rog/For-those-who-dare.gif b/rog-anime/data/anime/asus/rog/For-those-who-dare.gif similarity index 100% rename from data/anime/asus/rog/For-those-who-dare.gif rename to rog-anime/data/anime/asus/rog/For-those-who-dare.gif diff --git a/data/anime/asus/rog/For-those-who-dare_2.gif b/rog-anime/data/anime/asus/rog/For-those-who-dare_2.gif similarity index 100% rename from data/anime/asus/rog/For-those-who-dare_2.gif rename to rog-anime/data/anime/asus/rog/For-those-who-dare_2.gif diff --git a/data/anime/asus/rog/Fragment.gif b/rog-anime/data/anime/asus/rog/Fragment.gif similarity index 100% rename from data/anime/asus/rog/Fragment.gif rename to rog-anime/data/anime/asus/rog/Fragment.gif diff --git a/data/anime/asus/rog/Infinite-triangle.gif b/rog-anime/data/anime/asus/rog/Infinite-triangle.gif similarity index 100% rename from data/anime/asus/rog/Infinite-triangle.gif rename to rog-anime/data/anime/asus/rog/Infinite-triangle.gif diff --git a/data/anime/asus/rog/Kaleidoscope1.gif b/rog-anime/data/anime/asus/rog/Kaleidoscope1.gif similarity index 100% rename from data/anime/asus/rog/Kaleidoscope1.gif rename to rog-anime/data/anime/asus/rog/Kaleidoscope1.gif diff --git a/data/anime/asus/rog/Kaleidoscope2.gif b/rog-anime/data/anime/asus/rog/Kaleidoscope2.gif similarity index 100% rename from data/anime/asus/rog/Kaleidoscope2.gif rename to rog-anime/data/anime/asus/rog/Kaleidoscope2.gif diff --git a/data/anime/asus/rog/Kaleidoscope2.png b/rog-anime/data/anime/asus/rog/Kaleidoscope2.png similarity index 100% rename from data/anime/asus/rog/Kaleidoscope2.png rename to rog-anime/data/anime/asus/rog/Kaleidoscope2.png diff --git a/data/anime/asus/rog/ROG city.gif b/rog-anime/data/anime/asus/rog/ROG city.gif similarity index 100% rename from data/anime/asus/rog/ROG city.gif rename to rog-anime/data/anime/asus/rog/ROG city.gif diff --git a/data/anime/asus/rog/ROG glitch.gif b/rog-anime/data/anime/asus/rog/ROG glitch.gif similarity index 100% rename from data/anime/asus/rog/ROG glitch.gif rename to rog-anime/data/anime/asus/rog/ROG glitch.gif diff --git a/data/anime/asus/rog/Sunset.gif b/rog-anime/data/anime/asus/rog/Sunset.gif similarity index 100% rename from data/anime/asus/rog/Sunset.gif rename to rog-anime/data/anime/asus/rog/Sunset.gif diff --git a/data/anime/asus/trend/Dog.gif b/rog-anime/data/anime/asus/trend/Dog.gif similarity index 100% rename from data/anime/asus/trend/Dog.gif rename to rog-anime/data/anime/asus/trend/Dog.gif diff --git a/rog-anime/data/anime/asus/trend/Hero.gif b/rog-anime/data/anime/asus/trend/Hero.gif new file mode 100755 index 00000000..61ecfdb4 Binary files /dev/null and b/rog-anime/data/anime/asus/trend/Hero.gif differ diff --git a/data/anime/asus/trend/Ski.gif b/rog-anime/data/anime/asus/trend/Ski.gif similarity index 100% rename from data/anime/asus/trend/Ski.gif rename to rog-anime/data/anime/asus/trend/Ski.gif diff --git a/data/anime/asus/trend/The scream.gif b/rog-anime/data/anime/asus/trend/The scream.gif similarity index 100% rename from data/anime/asus/trend/The scream.gif rename to rog-anime/data/anime/asus/trend/The scream.gif diff --git a/data/anime/asus/trend/Wave.gif b/rog-anime/data/anime/asus/trend/Wave.gif similarity index 100% rename from data/anime/asus/trend/Wave.gif rename to rog-anime/data/anime/asus/trend/Wave.gif diff --git a/data/anime/custom/nyancat_zombie.gif b/rog-anime/data/anime/custom/nyancat_zombie.gif similarity index 100% rename from data/anime/custom/nyancat_zombie.gif rename to rog-anime/data/anime/custom/nyancat_zombie.gif diff --git a/data/anime/custom/rust.png b/rog-anime/data/anime/custom/rust.png similarity index 100% rename from data/anime/custom/rust.png rename to rog-anime/data/anime/custom/rust.png diff --git a/data/anime/custom/sonic-run.gif b/rog-anime/data/anime/custom/sonic-run.gif similarity index 100% rename from data/anime/custom/sonic-run.gif rename to rog-anime/data/anime/custom/sonic-run.gif diff --git a/data/anime/custom/sonic-wait.gif b/rog-anime/data/anime/custom/sonic-wait.gif similarity index 100% rename from data/anime/custom/sonic-wait.gif rename to rog-anime/data/anime/custom/sonic-wait.gif diff --git a/rog-dbus/Cargo.toml b/rog-dbus/Cargo.toml index 46e080ac..81b7a443 100644 --- a/rog-dbus/Cargo.toml +++ b/rog-dbus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog_dbus" -version = "3.5.1" +version = "4.0.0" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] @@ -13,7 +13,8 @@ edition = "2018" rog_anime = { path = "../rog-anime" } rog_aura = { path = "../rog-aura" } rog_profiles = { path = "../rog-profiles" } -rog_types = { path = "../rog-types" } +rog_supported = { path = "../rog-supported" } +supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", tag = "2.0.0" } zbus = "^1.9" zbus_macros = "^1.9" -zvariant = "^2.5" +zvariant = "^2.8" diff --git a/rog-dbus/src/lib.rs b/rog-dbus/src/lib.rs index ae692cfb..458f4501 100644 --- a/rog-dbus/src/lib.rs +++ b/rog-dbus/src/lib.rs @@ -1,10 +1,10 @@ pub static DBUS_NAME: &str = "org.asuslinux.Daemon"; +pub static DBUS_NAME_GFX: &str = "org.supergfxctl.Daemon"; pub static DBUS_PATH: &str = "/org/asuslinux/Daemon"; pub static DBUS_IFACE: &str = "org.asuslinux.Daemon"; pub mod zbus_anime; pub mod zbus_charge; -pub mod zbus_gfx; pub mod zbus_led; pub mod zbus_profile; pub mod zbus_rogbios; @@ -12,8 +12,7 @@ pub mod zbus_supported; use rog_anime::AnimePowerStates; use rog_aura::{AuraEffect, LedPowerStates}; -use rog_profiles::profiles::Profile; -use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors}; +use rog_profiles::Profile; use std::sync::mpsc::{channel, Receiver}; use zbus::{Connection, Result, SignalReceiver}; @@ -21,7 +20,6 @@ pub static VERSION: &str = env!("CARGO_PKG_VERSION"); pub struct DbusProxies<'a> { anime: zbus_anime::AnimeProxy<'a>, charge: zbus_charge::ChargeProxy<'a>, - gfx: zbus_gfx::GfxProxy<'a>, led: zbus_led::LedProxy<'a>, profile: zbus_profile::ProfileProxy<'a>, rog_bios: zbus_rogbios::RogBiosProxy<'a>, @@ -38,7 +36,6 @@ impl<'a> DbusProxies<'a> { anime: zbus_anime::AnimeProxy::new(&conn)?, led: zbus_led::LedProxy::new(&conn)?, charge: zbus_charge::ChargeProxy::new(&conn)?, - gfx: zbus_gfx::GfxProxy::new(&conn)?, profile: zbus_profile::ProfileProxy::new(&conn)?, rog_bios: zbus_rogbios::RogBiosProxy::new(&conn)?, supported: zbus_supported::SupportProxy::new(&conn)?, @@ -52,7 +49,6 @@ impl<'a> DbusProxies<'a> { recv.receive_for(self.anime.proxy()); recv.receive_for(self.led.proxy()); recv.receive_for(self.charge.proxy()); - recv.receive_for(self.gfx.proxy()); recv.receive_for(self.profile.proxy()); recv.receive_for(self.rog_bios.proxy()); recv.receive_for(self.supported.proxy()); @@ -67,10 +63,6 @@ impl<'a> DbusProxies<'a> { &self.charge } - pub fn gfx(&self) -> &zbus_gfx::GfxProxy<'a> { - &self.gfx - } - pub fn led(&self) -> &zbus_led::LedProxy<'a> { &self.led } @@ -90,8 +82,6 @@ impl<'a> DbusProxies<'a> { // Signals separated out pub struct Signals { - pub gfx_vendor: Receiver, - pub gfx_action: Receiver, pub profile: Receiver, pub led_mode: Receiver, pub led_power_state: Receiver, @@ -105,16 +95,6 @@ impl Signals { #[inline] pub fn new(proxies: &DbusProxies) -> Result { Ok(Signals { - gfx_vendor: { - let (tx, rx) = channel(); - proxies.gfx.connect_notify_gfx(tx)?; - rx - }, - gfx_action: { - let (tx, rx) = channel(); - proxies.gfx.connect_notify_action(tx)?; - rx - }, profile: { let (tx, rx) = channel(); proxies.profile.connect_notify_profile(tx)?; @@ -182,26 +162,9 @@ impl<'a> RogDbusClient<'a> { recv.receive_for(self.proxies.anime.proxy()); recv.receive_for(self.proxies.led.proxy()); recv.receive_for(self.proxies.charge.proxy()); - recv.receive_for(self.proxies.gfx.proxy()); recv.receive_for(self.proxies.profile.proxy()); recv.receive_for(self.proxies.rog_bios.proxy()); recv.receive_for(self.proxies.supported.proxy()); recv } - - /* - * GFX - */ - pub fn gfx_wait_changed(&self) -> Result { - loop { - if let Ok(res) = self.proxies.gfx.proxy().next_signal() { - if res.is_none() { - if let Ok(stuff) = self.signals.gfx_action.try_recv() { - return Ok(stuff); - } - // return Ok("Failed for unknown reason".to_owned()); - } - } - } - } } diff --git a/rog-dbus/src/zbus_gfx.rs b/rog-dbus/src/zbus_gfx.rs deleted file mode 100644 index d60e6c02..00000000 --- a/rog-dbus/src/zbus_gfx.rs +++ /dev/null @@ -1,98 +0,0 @@ -//! # DBus interface proxy for: `org.asuslinux.Gfx` -//! -//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data. -//! Source: `Interface '/org/asuslinux/Gfx' from service 'org.asuslinux.Daemon' on system bus`. -//! -//! You may prefer to adapt it, instead of using it verbatim. -//! -//! More information can be found in the -//! [Writing a client proxy](https://zeenix.pages.freedesktop.org/zbus/client.html) -//! section of the zbus documentation. -//! -//! This DBus object implements -//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html), -//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used: -//! -//! * [`zbus::fdo::PropertiesProxy`] -//! * [`zbus::fdo::IntrospectableProxy`] -//! * [`zbus::fdo::PeerProxy`] -//! -//! …consequently `zbus-xmlgen` did not generate code for the above interfaces. - -use std::sync::mpsc::Sender; - -use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors}; -use zbus::{dbus_proxy, Connection, Result}; - -#[dbus_proxy( - interface = "org.asuslinux.Daemon", - default_path = "/org/asuslinux/Gfx" -)] -trait Daemon { - /// Power method - fn power(&self) -> zbus::Result; - - /// SetVendor method - fn set_vendor(&self, vendor: &GfxVendors) -> zbus::Result; - - /// Vendor method - fn vendor(&self) -> zbus::Result; - - /// NotifyAction signal - #[dbus_proxy(signal)] - fn notify_action(&self, action: GfxRequiredUserAction) -> zbus::Result<()>; - - /// NotifyGfx signal - #[dbus_proxy(signal)] - fn notify_gfx(&self, vendor: GfxVendors) -> zbus::Result<()>; -} - -pub struct GfxProxy<'a>(DaemonProxy<'a>); - -impl<'a> GfxProxy<'a> { - #[inline] - pub fn new(conn: &Connection) -> Result { - Ok(GfxProxy(DaemonProxy::new(conn)?)) - } - - #[inline] - pub fn proxy(&self) -> &DaemonProxy<'a> { - &self.0 - } - - #[inline] - pub fn gfx_get_pwr(&self) -> Result { - self.0.power() - } - - #[inline] - pub fn gfx_get_mode(&self) -> Result { - self.0.vendor() - } - - #[inline] - pub fn gfx_write_mode(&self, vendor: &GfxVendors) -> Result { - self.0.set_vendor(vendor) - } - - #[inline] - pub fn connect_notify_action( - &self, - send: Sender, - ) -> zbus::fdo::Result<()> { - self.0.connect_notify_action(move |data| { - send.send(data) - .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?; - Ok(()) - }) - } - - #[inline] - pub fn connect_notify_gfx(&self, send: Sender) -> zbus::fdo::Result<()> { - self.0.connect_notify_gfx(move |data| { - send.send(data) - .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?; - Ok(()) - }) - } -} diff --git a/rog-dbus/src/zbus_led.rs b/rog-dbus/src/zbus_led.rs index 675a4143..5440961f 100644 --- a/rog-dbus/src/zbus_led.rs +++ b/rog-dbus/src/zbus_led.rs @@ -38,6 +38,12 @@ trait Daemon { /// PrevLedMode method fn prev_led_mode(&self) -> zbus::Result<()>; + /// Toggle to next led brightness + fn next_led_brightness(&self) -> zbus::Result<()>; + + /// Toggle to previous led brightness + fn prev_led_brightness(&self) -> zbus::Result<()>; + /// SetBrightness method fn set_brightness(&self, brightness: LedBrightness) -> zbus::Result<()>; @@ -124,6 +130,16 @@ impl<'a> LedProxy<'a> { self.0.prev_led_mode() } + #[inline] + pub fn next_led_brightness(&self) -> Result<()> { + self.0.next_led_brightness() + } + + #[inline] + pub fn prev_led_brightness(&self) -> Result<()> { + self.0.prev_led_brightness() + } + #[inline] pub fn set_led_mode(&self, mode: &AuraEffect) -> Result<()> { self.0.set_led_mode(mode) diff --git a/rog-dbus/src/zbus_profile.rs b/rog-dbus/src/zbus_profile.rs index 38d8c7e2..7e5247ac 100644 --- a/rog-dbus/src/zbus_profile.rs +++ b/rog-dbus/src/zbus_profile.rs @@ -21,7 +21,7 @@ use std::sync::mpsc::Sender; -use rog_profiles::profiles::Profile; +use rog_profiles::{FanCurve, Profile}; use zbus::{dbus_proxy, Connection, Result}; #[dbus_proxy( @@ -29,26 +29,29 @@ use zbus::{dbus_proxy, Connection, Result}; default_path = "/org/asuslinux/Profile" )] trait Daemon { + /// Profiles method + fn profiles(&self) -> zbus::Result>; + /// NextProfile method fn next_profile(&self) -> zbus::Result<()>; /// Profile, get the active profile - fn active_name(&self) -> zbus::Result; + fn active_profile(&self) -> zbus::Result; + + /// Set the specific profile as active + fn set_active_profile(&self, profile: Profile) -> zbus::Result<()>; + + /// Get enabled fan curves + fn enabled_fan_profiles(&self) -> zbus::Result>; /// Get the active `Profile` data - fn active_data(&self) -> zbus::Result; + fn active_fan_data(&self) -> zbus::Result; - /// Profiles method - fn profiles(&self) -> zbus::Result>; + /// Get all fan curve data + fn fan_curves(&self) -> zbus::Result>; - /// ProfileNames method - fn profile_names(&self) -> zbus::Result>; - - /// Remove method - fn remove(&self, profile: &str) -> zbus::Result<()>; - - /// SetProfile method - fn new_or_modify(&self, profile: &Profile) -> zbus::Result<()>; + /// Set a fan curve. If a field is empty then the exisiting saved curve is used + fn set_fan_curve(&self, curve: FanCurve) -> zbus::Result<()>; /// NotifyProfile signal #[dbus_proxy(signal)] @@ -69,40 +72,15 @@ impl<'a> ProfileProxy<'a> { } #[inline] - pub fn active_name(&self) -> Result { - self.0.active_name() - } - - #[inline] - pub fn active_data(&self) -> Result { - self.0.active_data() - } - - #[inline] - pub fn all_profile_data(&self) -> Result> { + pub fn profiles(&self) -> Result> { self.0.profiles() } #[inline] - pub fn next_fan(&self) -> Result<()> { + pub fn next_profile(&self) -> Result<()> { self.0.next_profile() } - #[inline] - pub fn profile_names(&self) -> Result> { - self.0.profile_names() - } - - #[inline] - pub fn remove(&self, profile: &str) -> Result<()> { - self.0.remove(profile) - } - - #[inline] - pub fn new_or_modify(&self, profile: &Profile) -> Result<()> { - self.0.new_or_modify(profile) - } - #[inline] pub fn connect_notify_profile(&self, send: Sender) -> zbus::fdo::Result<()> { self.0.connect_notify_profile(move |data| { diff --git a/rog-dbus/src/zbus_supported.rs b/rog-dbus/src/zbus_supported.rs index 565d7e92..54c06fb8 100644 --- a/rog-dbus/src/zbus_supported.rs +++ b/rog-dbus/src/zbus_supported.rs @@ -19,7 +19,7 @@ //! //! …consequently `zbus-xmlgen` did not generate code for the above interfaces. -use rog_types::supported::SupportedFunctions; +use rog_supported::SupportedFunctions; use zbus::{dbus_proxy, Connection, Result}; #[dbus_proxy( diff --git a/rog-profiles/Cargo.toml b/rog-profiles/Cargo.toml index bc434fce..dec19f61 100644 --- a/rog-profiles/Cargo.toml +++ b/rog-profiles/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rog_profiles" -version = "0.1.2" +version = "1.0.0" authors = ["Luke D. Jones "] edition = "2018" @@ -9,10 +9,8 @@ default = ["dbus"] dbus = ["zvariant", "zvariant_derive"] [dependencies] -rog_fan_curve = { git = "https://github.com/Yarn/rog_fan_curve.git" } serde = "^1.0" serde_derive = "^1.0" -intel-pstate = "^0.2" zvariant = { version = "^2.6", optional = true } zvariant_derive = { version = "^2.6", optional = true } \ No newline at end of file diff --git a/rog-profiles/src/error.rs b/rog-profiles/src/error.rs index c5dc7c12..f057e040 100644 --- a/rog-profiles/src/error.rs +++ b/rog-profiles/src/error.rs @@ -1,18 +1,12 @@ use std::fmt; -use intel_pstate::PStateError; -use rog_fan_curve::CurveError; - #[derive(Debug)] pub enum ProfileError { - ParseFanLevel, Path(String, std::io::Error), Read(String, std::io::Error), Write(String, std::io::Error), NotSupported, NotFound(String), - IntelPstate(PStateError), - FanCurve(CurveError), Io(std::io::Error), //Zbus(zbus::Error), } @@ -21,14 +15,11 @@ impl fmt::Display for ProfileError { // This trait requires `fmt` with this exact signature. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - ProfileError::ParseFanLevel => write!(f, "Parse profile error"), ProfileError::Path(path, error) => write!(f, "Path {}: {}", path, error), ProfileError::Read(path, error) => write!(f, "Read {}: {}", path, error), ProfileError::Write(path, error) => write!(f, "Write {}: {}", path, error), ProfileError::NotSupported => write!(f, "Not supported"), ProfileError::NotFound(deets) => write!(f, "Not found: {}", deets), - ProfileError::IntelPstate(err) => write!(f, "Intel pstate error: {}", err), - ProfileError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err), ProfileError::Io(detail) => write!(f, "std::io error: {}", detail), //Error::Zbus(detail) => write!(f, "Zbus error: {}", detail), } @@ -36,15 +27,3 @@ impl fmt::Display for ProfileError { } impl std::error::Error for ProfileError {} - -impl From for ProfileError { - fn from(err: PStateError) -> Self { - ProfileError::IntelPstate(err) - } -} - -impl From for ProfileError { - fn from(err: CurveError) -> Self { - ProfileError::FanCurve(err) - } -} diff --git a/rog-profiles/src/lib.rs b/rog-profiles/src/lib.rs index 96d68664..eaa12415 100644 --- a/rog-profiles/src/lib.rs +++ b/rog-profiles/src/lib.rs @@ -1,8 +1,284 @@ pub mod error; -pub mod profiles; -static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy"; -static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode"; -static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost"; +use std::{ + fs::OpenOptions, + io::{Read, Write}, + path::{Path, PathBuf}, +}; + +use error::ProfileError; +use serde_derive::{Deserialize, Serialize}; + +#[cfg(feature = "dbus")] +use zvariant_derive::Type; + +pub static PLATFORM_PROFILE: &str = "/sys/firmware/acpi/platform_profile"; +pub static PLATFORM_PROFILES: &str = "/sys/firmware/acpi/platform_profile_choices"; + +pub static FAN_CURVE_BASE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/"; +pub static FAN_CURVE_ACTIVE_FILE: &str = "enabled_fan_curve_profiles"; +pub static FAN_CURVE_FILENAME_PART: &str = "_fan_curve_"; pub static VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Deserialize, Serialize, Debug, Clone, Copy)] +pub enum Profile { + Balanced, + Performance, + Quiet, +} + +impl Profile { + pub fn is_platform_profile_supported() -> bool { + Path::new(PLATFORM_PROFILES).exists() + } + + pub fn get_active_profile() -> Result { + let mut file = OpenOptions::new() + .read(true) + .open(&PLATFORM_PROFILE) + .unwrap_or_else(|_| panic!("{} not found", &PLATFORM_PROFILE)); + + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + Ok(buf.as_str().into()) + } + + pub fn get_profile_names() -> Result, ProfileError> { + let mut file = OpenOptions::new() + .read(true) + .open(&PLATFORM_PROFILES) + .unwrap_or_else(|_| panic!("{} not found", &PLATFORM_PROFILES)); + + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + Ok(buf.rsplit(' ').map(|p| p.into()).collect()) + } + + pub fn set_profile(profile: Profile) { + let mut file = OpenOptions::new() + .write(true) + .open(PLATFORM_PROFILE) + .unwrap_or_else(|_| panic!("{} not found", PLATFORM_PROFILE)); + + file.write_all(<&str>::from(profile).as_bytes()).unwrap(); + } +} + +impl Default for Profile { + fn default() -> Self { + Self::Balanced + } +} + +impl From for &str { + fn from(profile: Profile) -> &'static str { + match profile { + Profile::Balanced => "balanced", + Profile::Performance => "performance", + Profile::Quiet => "quiet", + } + } +} + +impl From<&str> for Profile { + fn from(profile: &str) -> Profile { + match profile.to_ascii_lowercase().trim() { + "balanced" => Profile::Balanced, + "performance" => Profile::Performance, + "quiet" => Profile::Quiet, + _ => Profile::Balanced, + } + } +} + +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Deserialize, Serialize, Debug, Clone, Copy)] +pub enum FanCurvePU { + CPU, + GPU, +} + +impl From for &str { + fn from(pu: FanCurvePU) -> &'static str { + match pu { + FanCurvePU::CPU => "cpu", + FanCurvePU::GPU => "gpu", + } + } +} + +impl Default for FanCurvePU { + fn default() -> Self { + Self::CPU + } +} + +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Deserialize, Serialize, Default, Debug, Clone)] +pub struct FanCurve { + pub profile: Profile, + pub cpu: String, + pub gpu: String, +} + +/// Main purpose of `FanCurves` is to enable retoring state on system boot +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Deserialize, Serialize, Debug)] +pub struct FanCurves { + active_curves: Vec, + balanced: FanCurve, + performance: FanCurve, + quiet: FanCurve, +} + +impl Default for FanCurves { + fn default() -> Self { + let mut curves = Self { + active_curves: Default::default(), + balanced: Default::default(), + performance: Default::default(), + quiet: Default::default(), + }; + curves.balanced.profile = Profile::Balanced; + curves.performance.profile = Profile::Performance; + curves.quiet.profile = Profile::Quiet; + curves + } +} + +impl FanCurves { + pub fn is_fan_curves_supported() -> bool { + let mut path = PathBuf::new(); + path.push(FAN_CURVE_BASE_PATH); + path.push(FAN_CURVE_ACTIVE_FILE); + path.exists() + } + + pub fn update_from_platform(&mut self) { + self.balanced.cpu = Self::get_fan_curve_from_file(Profile::Balanced, FanCurvePU::CPU); + self.balanced.gpu = Self::get_fan_curve_from_file(Profile::Balanced, FanCurvePU::GPU); + + self.performance.cpu = Self::get_fan_curve_from_file(Profile::Performance, FanCurvePU::CPU); + self.performance.gpu = Self::get_fan_curve_from_file(Profile::Performance, FanCurvePU::GPU); + + self.quiet.cpu = Self::get_fan_curve_from_file(Profile::Quiet, FanCurvePU::CPU); + self.quiet.gpu = Self::get_fan_curve_from_file(Profile::Quiet, FanCurvePU::GPU); + } + + pub fn update_platform(&self) { + Self::set_fan_curve_for_platform(Profile::Balanced, FanCurvePU::CPU, &self.balanced.cpu); + Self::set_fan_curve_for_platform(Profile::Balanced, FanCurvePU::GPU, &self.balanced.gpu); + + Self::set_fan_curve_for_platform( + Profile::Performance, + FanCurvePU::CPU, + &self.performance.cpu, + ); + Self::set_fan_curve_for_platform( + Profile::Performance, + FanCurvePU::GPU, + &self.performance.gpu, + ); + + Self::set_fan_curve_for_platform(Profile::Quiet, FanCurvePU::CPU, &self.quiet.cpu); + Self::set_fan_curve_for_platform(Profile::Quiet, FanCurvePU::GPU, &self.quiet.gpu); + } + + pub fn get_enabled_curve_names(&self) -> &[Profile] { + &self.active_curves + } + + pub fn get_all_fan_curves(&self) -> Vec { + vec![ + self.balanced.clone(), + self.performance.clone(), + self.quiet.clone(), + ] + } + + pub fn get_active_fan_curves(&self) -> &FanCurve { + match Profile::get_active_profile().unwrap() { + Profile::Balanced => &self.balanced, + Profile::Performance => &self.performance, + Profile::Quiet => &self.quiet, + } + } + + pub fn get_fan_curves_for(&self, name: Profile) -> &FanCurve { + match name { + Profile::Balanced => &self.balanced, + Profile::Performance => &self.performance, + Profile::Quiet => &self.quiet, + } + } + + fn get_fan_curve_from_file(name: Profile, pu: FanCurvePU) -> String { + let mut file: String = FAN_CURVE_BASE_PATH.into(); + file.push_str(pu.into()); + file.push_str(FAN_CURVE_FILENAME_PART); + file.push_str(name.into()); + + let mut file = OpenOptions::new() + .read(true) + .open(&file) + .unwrap_or_else(|_| panic!("{} not found", &file)); + + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + buf.trim().to_string() + } + + pub fn get_fan_curve_for(&self, name: &Profile, pu: &FanCurvePU) -> &str { + match name { + Profile::Balanced => match pu { + FanCurvePU::CPU => &self.balanced.cpu, + FanCurvePU::GPU => &self.balanced.gpu, + }, + Profile::Performance => match pu { + FanCurvePU::CPU => &self.balanced.cpu, + FanCurvePU::GPU => &self.balanced.gpu, + }, + Profile::Quiet => match pu { + FanCurvePU::CPU => &self.balanced.cpu, + FanCurvePU::GPU => &self.balanced.gpu, + }, + } + } + + fn set_fan_curve_for_platform(name: Profile, pu: FanCurvePU, curve: &str) { + let mut file: String = FAN_CURVE_BASE_PATH.into(); + file.push_str(pu.into()); + file.push_str(FAN_CURVE_FILENAME_PART); + file.push_str(name.into()); + + let mut file = OpenOptions::new() + .write(true) + .open(&file) + .unwrap_or_else(|_| panic!("{} not found", &file)); + + file.write_all(curve.as_bytes()).unwrap(); + } + + pub fn set_fan_curve(&mut self, curve: FanCurve) { + // First, set the profiles. + Self::set_fan_curve_for_platform(curve.profile, FanCurvePU::CPU, &curve.cpu); + match curve.profile { + Profile::Balanced => self.balanced.cpu = curve.cpu, + Profile::Performance => self.performance.cpu = curve.cpu, + Profile::Quiet => self.quiet.cpu = curve.cpu, + }; + + Self::set_fan_curve_for_platform(curve.profile, FanCurvePU::GPU, &curve.gpu); + match curve.profile { + Profile::Balanced => self.balanced.gpu = curve.gpu, + Profile::Performance => self.performance.gpu = curve.gpu, + Profile::Quiet => self.quiet.cpu = curve.gpu, + }; + + // Any curve that was blank will have been reset, so repopulate the settings + // Note: successfully set curves will just be re-read in. + self.update_from_platform(); + } +} diff --git a/rog-profiles/src/profiles.rs b/rog-profiles/src/profiles.rs deleted file mode 100644 index 53754dc8..00000000 --- a/rog-profiles/src/profiles.rs +++ /dev/null @@ -1,185 +0,0 @@ -use rog_fan_curve::{Curve, Fan}; -use serde_derive::{Deserialize, Serialize}; -use std::io::Write; -use std::{fs::OpenOptions, path::Path, str::FromStr}; -#[cfg(feature = "dbus")] -use zvariant_derive::Type; - -use crate::{error::ProfileError, AMD_BOOST_PATH, FAN_TYPE_1_PATH, FAN_TYPE_2_PATH}; - -#[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Profile { - pub name: String, - pub min_percentage: u8, - pub max_percentage: u8, - pub turbo: bool, - pub fan_preset: FanLevel, - pub fan_curve: String, -} - -impl Default for Profile { - fn default() -> Self { - Profile { - name: "new".into(), - min_percentage: 0, - max_percentage: 100, - turbo: false, - fan_preset: FanLevel::Normal, - fan_curve: "".to_string(), - } - } -} - -impl Profile { - pub fn new( - name: String, - min_percentage: u8, - max_percentage: u8, - turbo: bool, - fan_preset: FanLevel, - fan_curve: String, - ) -> Self { - Profile { - name, - min_percentage, - max_percentage, - turbo, - fan_preset, - fan_curve, - } - } - - pub fn get_intel_supported() -> bool { - intel_pstate::PState::new().is_ok() - } - - pub fn get_fan_path() -> Result<&'static str, ProfileError> { - if Path::new(FAN_TYPE_1_PATH).exists() { - Ok(FAN_TYPE_1_PATH) - } else if Path::new(FAN_TYPE_2_PATH).exists() { - Ok(FAN_TYPE_2_PATH) - } else { - Err(ProfileError::NotSupported) - } - } - - pub fn set_system_pstate(&self) -> Result<(), ProfileError> { - // Set CPU pstate - if let Ok(pstate) = intel_pstate::PState::new() { - pstate.set_min_perf_pct(self.min_percentage)?; - pstate.set_max_perf_pct(self.max_percentage)?; - pstate.set_no_turbo(!self.turbo)?; - } else { - // must be AMD CPU - let mut file = OpenOptions::new() - .write(true) - .open(AMD_BOOST_PATH) - .map_err(|err| ProfileError::Path(AMD_BOOST_PATH.into(), err))?; - - let boost = if self.turbo { "1" } else { "0" }; // opposite of Intel - file.write_all(boost.as_bytes()) - .map_err(|err| ProfileError::Write(AMD_BOOST_PATH.into(), err))?; - } - Ok(()) - } - - pub fn set_system_fan_mode(&self) -> Result<(), ProfileError> { - let path = Profile::get_fan_path()?; - let mut fan_ctrl = OpenOptions::new() - .write(true) - .open(path) - .map_err(|err| ProfileError::Path(path.into(), err))?; - fan_ctrl - .write_all(format!("{}\n", ::from(self.fan_preset)).as_bytes()) - .map_err(|err| ProfileError::Write(path.into(), err))?; - Ok(()) - } - - pub fn set_system_fan_curve(&self) -> Result<(), ProfileError> { - if !self.fan_curve.is_empty() { - if let Ok(curve) = Profile::parse_fan_curve(&self.fan_curve) { - use rog_fan_curve::Board; - if let Some(board) = Board::from_board_name() { - curve.apply(board, Fan::Cpu)?; - curve.apply(board, Fan::Gpu)?; - } - } - } - - Ok(()) - } - - pub fn set_system_all(&self) -> Result<(), ProfileError> { - self.set_system_pstate()?; - if self.fan_curve.is_empty() { - self.set_system_fan_mode()?; - } else { - self.set_system_fan_curve()?; - } - Ok(()) - } - - fn parse_fan_curve(data: &str) -> Result { - let curve = Curve::from_config_str(data)?; - if let Err(err) = curve.check_safety(Fan::Cpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - if let Err(err) = curve.check_safety(Fan::Gpu) { - return Err(format!("Unsafe curve {:?}", err)); - } - Ok(curve) - } -} - -#[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] -pub enum FanLevel { - Normal, - Boost, - Silent, -} - -impl FromStr for FanLevel { - type Err = &'static str; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "normal" => Ok(FanLevel::Normal), - "boost" => Ok(FanLevel::Boost), - "silent" => Ok(FanLevel::Silent), - _ => Err("Invalid fan level"), - } - } -} - -impl From for FanLevel { - fn from(n: u8) -> Self { - match n { - 0 => FanLevel::Normal, - 1 => FanLevel::Boost, - 2 => FanLevel::Silent, - _ => FanLevel::Normal, - } - } -} - -impl From for u8 { - fn from(n: FanLevel) -> Self { - match n { - FanLevel::Normal => 0, - FanLevel::Boost => 1, - FanLevel::Silent => 2, - } - } -} - -impl From<&FanLevel> for u8 { - fn from(n: &FanLevel) -> Self { - match n { - FanLevel::Normal => 0, - FanLevel::Boost => 1, - FanLevel::Silent => 2, - } - } -} diff --git a/rog-types/Cargo.toml b/rog-supported/Cargo.toml similarity index 75% rename from rog-types/Cargo.toml rename to rog-supported/Cargo.toml index 34d07c45..461bc729 100644 --- a/rog-types/Cargo.toml +++ b/rog-supported/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "rog_types" -version = "3.2.0" +name = "rog_supported" +version = "4.0.0" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] repository = "https://gitlab.com/asus-linux/asus-nb-ctrl" homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl" -description = "A small library of effect types and conversions for ROG Aura" +description = "Helper to determine what is supported by asus laptops" edition = "2018" [dependencies] diff --git a/rog-types/src/supported.rs b/rog-supported/src/lib.rs similarity index 83% rename from rog-types/src/supported.rs rename to rog-supported/src/lib.rs index e8e3fef8..203b0390 100644 --- a/rog-types/src/supported.rs +++ b/rog-supported/src/lib.rs @@ -1,3 +1,5 @@ +pub static VERSION: &str = env!("CARGO_PKG_VERSION"); + use rog_aura::AuraModeNum; use serde_derive::{Deserialize, Serialize}; use std::fmt; @@ -7,7 +9,7 @@ use zvariant_derive::Type; pub struct SupportedFunctions { pub anime_ctrl: AnimeSupportedFunctions, pub charge_ctrl: ChargeSupportedFunctions, - pub fan_cpu_ctrl: FanCpuSupportedFunctions, + pub platform_profile: PlatformProfileFunctions, pub keyboard_led: LedSupportedFunctions, pub rog_bios_ctrl: RogBiosSupportedFunctions, } @@ -21,10 +23,9 @@ pub struct ChargeSupportedFunctions { } #[derive(Serialize, Deserialize, Type, Debug)] -pub struct FanCpuSupportedFunctions { - pub stock_fan_modes: bool, - pub min_max_freq: bool, - pub fan_curve_set: bool, +pub struct PlatformProfileFunctions { + pub platform_profile: bool, + pub fan_curves: bool, } #[derive(Serialize, Deserialize, Type, Debug)] @@ -45,7 +46,7 @@ impl fmt::Display for SupportedFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "{}", self.anime_ctrl)?; writeln!(f, "{}", self.charge_ctrl)?; - writeln!(f, "{}", self.fan_cpu_ctrl)?; + writeln!(f, "{}", self.platform_profile)?; writeln!(f, "{}", self.keyboard_led)?; writeln!(f, "{}", self.rog_bios_ctrl) } @@ -67,12 +68,11 @@ impl fmt::Display for ChargeSupportedFunctions { ) } } -impl fmt::Display for FanCpuSupportedFunctions { +impl fmt::Display for PlatformProfileFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "Fan:")?; - writeln!(f, "\tStock fan modes: {}", self.stock_fan_modes)?; - writeln!(f, "\tMin/max frequency: {}", self.min_max_freq)?; - writeln!(f, "\tFan curve control: {}", self.fan_curve_set) + writeln!(f, "Platform profiles:")?; + writeln!(f, "\tplatform: {}", self.platform_profile)?; + writeln!(f, "\tfan curves: {}", self.fan_curves) } } impl fmt::Display for LedSupportedFunctions { diff --git a/rog-types/src/error.rs b/rog-types/src/error.rs deleted file mode 100644 index 432772f0..00000000 --- a/rog-types/src/error.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::error::Error; -use std::fmt; - -#[derive(Debug)] -pub enum GraphicsError { - ParseVendor, - ParsePower, -} - -impl fmt::Display for GraphicsError { - // This trait requires `fmt` with this exact signature. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - GraphicsError::ParseVendor => write!(f, "Could not parse vendor name"), - GraphicsError::ParsePower => write!(f, "Could not parse dGPU power status"), - } - } -} - -impl Error for GraphicsError {} diff --git a/rog-types/src/gfx_vendors.rs b/rog-types/src/gfx_vendors.rs deleted file mode 100644 index 86636b55..00000000 --- a/rog-types/src/gfx_vendors.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::error::GraphicsError; -use serde_derive::{Deserialize, Serialize}; -use std::str::FromStr; -use zvariant_derive::Type; - -#[derive(Debug, Type, PartialEq, Copy, Clone, Deserialize, Serialize)] -pub enum GfxPower { - Active, - Suspended, - Off, - Unknown, -} - -impl FromStr for GfxPower { - type Err = GraphicsError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().trim() { - "active" => Ok(GfxPower::Active), - "suspended" => Ok(GfxPower::Suspended), - "off" => Ok(GfxPower::Off), - _ => Ok(GfxPower::Unknown), - } - } -} - -impl From<&GfxPower> for &str { - fn from(gfx: &GfxPower) -> &'static str { - match gfx { - GfxPower::Active => "active", - GfxPower::Suspended => "suspended", - GfxPower::Off => "off", - GfxPower::Unknown => "unknown", - } - } -} - -#[derive(Debug, Type, PartialEq, Copy, Clone, Deserialize, Serialize)] -pub enum GfxVendors { - Nvidia, - Integrated, - Compute, - Vfio, - Hybrid, -} - -impl FromStr for GfxVendors { - type Err = GraphicsError; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "nvidia" => Ok(GfxVendors::Nvidia), - "hybrid" => Ok(GfxVendors::Hybrid), - "compute" => Ok(GfxVendors::Compute), - "vfio" => Ok(GfxVendors::Vfio), - "integrated" => Ok(GfxVendors::Integrated), - "nvidia\n" => Ok(GfxVendors::Nvidia), - "hybrid\n" => Ok(GfxVendors::Hybrid), - "compute\n" => Ok(GfxVendors::Compute), - "vfio\n" => Ok(GfxVendors::Vfio), - "integrated\n" => Ok(GfxVendors::Integrated), - _ => Err(GraphicsError::ParseVendor), - } - } -} - -impl From<&GfxVendors> for &str { - fn from(gfx: &GfxVendors) -> &'static str { - match gfx { - GfxVendors::Nvidia => "nvidia", - GfxVendors::Hybrid => "hybrid", - GfxVendors::Compute => "compute", - GfxVendors::Vfio => "vfio", - GfxVendors::Integrated => "integrated", - } - } -} - -impl From for &str { - fn from(gfx: GfxVendors) -> &'static str { - (&gfx).into() - } -} - -#[derive(Debug, Type, PartialEq, Copy, Clone, Deserialize, Serialize)] -pub enum GfxRequiredUserAction { - Logout, - Reboot, - Integrated, - None, -} - -impl From<&GfxRequiredUserAction> for &str { - fn from(gfx: &GfxRequiredUserAction) -> &'static str { - match gfx { - GfxRequiredUserAction::Logout => "logout", - GfxRequiredUserAction::Reboot => "reboot", - GfxRequiredUserAction::Integrated => "switch to integrated first", - GfxRequiredUserAction::None => "no action", - } - } -} diff --git a/rog-types/src/lib.rs b/rog-types/src/lib.rs deleted file mode 100644 index 15078b86..00000000 --- a/rog-types/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! This crate is intended for shared types (eg, between daemon and CLI), or -//! for types that might be useful in third-party crates perhaps for -//! sending messages over dbus wire - -pub static DBUS_NAME: &str = "org.asuslinux.Daemon"; -pub static DBUS_PATH: &str = "/org/asuslinux/Daemon"; -pub static DBUS_IFACE: &str = "org.asuslinux.Daemon"; - -pub mod gfx_vendors; - -pub mod supported; - -pub mod error; - -pub static VERSION: &str = env!("CARGO_PKG_VERSION");