Merge branch 'fluke/platform_curves' into 'main'
platform_profile + fan curve support Closes #129 and #128 See merge request asus-linux/asusctl!75
1
.gitignore
vendored
@@ -4,3 +4,4 @@ cargo-config
|
||||
.idea
|
||||
vendor-*
|
||||
vendor_*
|
||||
.vscode-ctags
|
||||
|
||||
@@ -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
|
||||
|
||||
144
Cargo.lock
generated
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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
|
||||
opt-level = 3
|
||||
|
||||
10
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)"
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
[package]
|
||||
name = "asus-notify"
|
||||
version = "3.0.1"
|
||||
version = "3.0.2"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
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"
|
||||
|
||||
@@ -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<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
|
||||
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<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
let mut last_notification: Option<NotificationHandle> = 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<NotificationHandle, Box<dyn Error>> {
|
||||
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)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
[package]
|
||||
name = "asusctl"
|
||||
version = "3.5.1"
|
||||
version = "4.0.0"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
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"
|
||||
|
||||
@@ -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 = "<off, low, med, high>")]
|
||||
kbd_bright: Option<LedBrightness>,
|
||||
#[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<u8>,
|
||||
#[options(command)]
|
||||
@@ -139,26 +143,27 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
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<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
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<dyn std::error::Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_gfx(
|
||||
dbus: &RogDbusClient,
|
||||
supported: &RogBiosSupportedFunctions,
|
||||
command: GraphicsCommand,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn do_gfx(command: GraphicsCommand) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String>,
|
||||
#[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<bool>,
|
||||
#[options(meta = "", help = "set min cpu scaling (intel)")]
|
||||
pub min_percentage: Option<u8>,
|
||||
#[options(meta = "", help = "set max cpu scaling (intel)")]
|
||||
pub max_percentage: Option<u8>,
|
||||
|
||||
#[options(meta = "", help = "<silent, normal, boost>")]
|
||||
pub fan_preset: Option<FanLevel>,
|
||||
#[options(
|
||||
meta = "",
|
||||
parse(try_from_str = "parse_fan_curve"),
|
||||
help = "set fan curve"
|
||||
)]
|
||||
pub curve: Option<Curve>,
|
||||
#[options(free)]
|
||||
pub profile: Option<String>,
|
||||
}
|
||||
|
||||
fn parse_fan_curve(data: &str) -> Result<Curve, String> {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ use zbus::{fdo, Connection};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
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()?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "daemon"
|
||||
version = "3.7.2"
|
||||
version = "4.0.0"
|
||||
license = "MPL-2.0"
|
||||
readme = "README.md"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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<GfxVendors>,
|
||||
pub gfx_managed: bool,
|
||||
pub gfx_vfio_enable: bool,
|
||||
pub active_profile: String,
|
||||
pub toggle_profiles: Vec<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
/// Save charge limit for restoring on boot
|
||||
pub bat_charge_limit: u8,
|
||||
pub power_profiles: BTreeMap<String, Profile>,
|
||||
}
|
||||
|
||||
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::<ConfigV352>(&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::<ConfigV341>(&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::<ConfigV324>(&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::<ConfigV317>(&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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String>,
|
||||
#[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<bool>,
|
||||
pub power_profiles: BTreeMap<String, ProfileV317>,
|
||||
}
|
||||
|
||||
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<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub power_profiles: BTreeMap<String, ProfileV317>,
|
||||
}
|
||||
|
||||
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<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub power_profiles: BTreeMap<String, ProfileV317>,
|
||||
}
|
||||
|
||||
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<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub power_profiles: BTreeMap<String, ProfileV317>,
|
||||
}
|
||||
|
||||
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<Curve>,
|
||||
}
|
||||
|
||||
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<String, ProfileV317>) -> BTreeMap<String, Profile> {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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<Mutex<CtrlAnime>>);
|
||||
|
||||
/// 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<()>;
|
||||
}
|
||||
140
daemon/src/ctrl_anime/zbus.rs
Normal file
@@ -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<Mutex<CtrlAnime>>);
|
||||
|
||||
/// 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<()>;
|
||||
}
|
||||
@@ -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 = <LedBrightness>::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 = <LedBrightness>::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 {
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod config;
|
||||
pub mod controller;
|
||||
pub mod zbus;
|
||||
@@ -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() {
|
||||
@@ -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();
|
||||
|
||||
@@ -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<GraphicsDevice>,
|
||||
_intel: Vec<GraphicsDevice>,
|
||||
nvidia: Vec<GraphicsDevice>,
|
||||
#[allow(dead_code)]
|
||||
other: Vec<GraphicsDevice>,
|
||||
config: Arc<Mutex<Config>>,
|
||||
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
|
||||
}
|
||||
|
||||
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<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
|
||||
let bus = PciBus::new()?;
|
||||
info!("GFX: Rescanning PCI bus");
|
||||
bus.rescan()?;
|
||||
let devs = PciDevice::all()?;
|
||||
|
||||
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
|
||||
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<GraphicsDevice> {
|
||||
self.nvidia.clone()
|
||||
}
|
||||
|
||||
/// Save the selected `Vendor` mode to config
|
||||
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
|
||||
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<GfxVendors, RogError> {
|
||||
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<GfxPower, RogError> {
|
||||
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<u8> {
|
||||
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::<Result<_, _>>()
|
||||
.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::<Result<_, _>>()
|
||||
.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<bool, RogError> {
|
||||
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<GraphicsDevice>,
|
||||
bus: PciBus,
|
||||
thread_stop: mpsc::Receiver<bool>,
|
||||
config: Arc<Mutex<Config>>,
|
||||
) -> Result<String, RogError> {
|
||||
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<GfxRequiredUserAction, RogError> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -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<GfxError> for RogError {
|
||||
fn from(err: GfxError) -> Self {
|
||||
RogError::GfxSwitching(err)
|
||||
}
|
||||
}
|
||||
@@ -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"#;
|
||||
@@ -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<Module> {
|
||||
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<Vec<Module>> {
|
||||
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<PciBus> {
|
||||
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<PciDevice>,
|
||||
}
|
||||
|
||||
impl GraphicsDevice {
|
||||
pub fn new(id: String, functions: Vec<PciDevice>) -> 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(())
|
||||
}
|
||||
}
|
||||
@@ -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<GfxVendors> {
|
||||
self.get_gfx_mode().map_err(|err| {
|
||||
error!("GFX: {}", err);
|
||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||
})
|
||||
}
|
||||
|
||||
fn power(&self) -> zbus::fdo::Result<GfxPower> {
|
||||
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<GfxRequiredUserAction> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
92
daemon/src/ctrl_profiles/config.rs
Normal file
@@ -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<FanCurves>,
|
||||
}
|
||||
|
||||
impl ProfileConfig {
|
||||
fn new(config_path: String) -> Result<Self, ProfileError> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -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<Mutex<Config>>,
|
||||
use super::config::ProfileConfig;
|
||||
|
||||
pub struct CtrlPlatformTask {
|
||||
config: Arc<Mutex<ProfileConfig>>,
|
||||
}
|
||||
|
||||
impl GetSupported for CtrlFanAndCpu {
|
||||
type A = FanCpuSupportedFunctions;
|
||||
impl CtrlPlatformTask {
|
||||
pub fn new(config: Arc<Mutex<ProfileConfig>>) -> 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<Mutex<ProfileConfig>>,
|
||||
}
|
||||
|
||||
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<Mutex<Config>>) -> Result<Self, RogError> {
|
||||
Profile::get_fan_path()?;
|
||||
info!("Device has fan control available");
|
||||
Ok(CtrlFanAndCpu { config })
|
||||
impl CtrlPlatformProfile {
|
||||
pub fn new(config: Arc<Mutex<ProfileConfig>>) -> Result<Self, RogError> {
|
||||
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(())
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pub mod zbus;
|
||||
|
||||
pub mod config;
|
||||
pub mod controller;
|
||||
pub mod zbus;
|
||||
|
||||
@@ -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<Mutex<CtrlFanAndCpu>>,
|
||||
static UNSUPPORTED_MSG: &str =
|
||||
"Fan curves are not supported on this laptop or you require a patched kernel";
|
||||
|
||||
pub struct ProfileZbus {
|
||||
inner: Arc<Mutex<CtrlPlatformProfile>>,
|
||||
}
|
||||
|
||||
impl FanAndCpuZbus {
|
||||
pub fn new(inner: Arc<Mutex<CtrlFanAndCpu>>) -> Self {
|
||||
impl ProfileZbus {
|
||||
pub fn new(inner: Arc<Mutex<CtrlPlatformProfile>>) -> 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<Vec<Profile>> {
|
||||
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<String> {
|
||||
fn active_profile(&mut self) -> zbus::fdo::Result<Profile> {
|
||||
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<Profile> {
|
||||
/// 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<Vec<Profile>> {
|
||||
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<Vec<Profile>> {
|
||||
/// Get the fan-curve data for the currently active Profile
|
||||
fn active_fan_curve_data(&mut self) -> zbus::fdo::Result<FanCurve> {
|
||||
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<Vec<String>> {
|
||||
/// Get fan-curve data for each Profile as an array of objects
|
||||
fn fan_curves(&self) -> zbus::fdo::Result<Vec<FanCurve>> {
|
||||
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::<Vec<String>>();
|
||||
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(
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<dyn std::error::Error>> {
|
||||
let mut logger = env_logger::Builder::new();
|
||||
@@ -43,17 +46,19 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
||||
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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
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<dyn Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
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<dyn Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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<dyn Error>> {
|
||||
});
|
||||
|
||||
// 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 {
|
||||
|
||||
@@ -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<CurveError> for RogError {
|
||||
fn from(err: CurveError) -> Self {
|
||||
RogError::FanCurve(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GraphicsError> for RogError {
|
||||
fn from(err: GraphicsError) -> Self {
|
||||
match err {
|
||||
GraphicsError::ParseVendor => RogError::GfxSwitching(GfxError::ParseVendor),
|
||||
GraphicsError::ParsePower => RogError::GfxSwitching(GfxError::ParsePower),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ProfileError> for RogError {
|
||||
fn from(err: ProfileError) -> Self {
|
||||
RogError::Profiles(err)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
@@ -1,4 +0,0 @@
|
||||
Section "ServerLayout"
|
||||
Identifier "layout"
|
||||
Option "AllowNVIDIAGPUScreens"
|
||||
EndSection
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 85 KiB |
BIN
rog-anime/data/anime/asus/festive/Love u mom.gif
Executable file
|
After Width: | Height: | Size: 153 KiB |
BIN
rog-anime/data/anime/asus/festive/Mother's day.gif
Executable file
|
After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 234 KiB After Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
BIN
rog-anime/data/anime/asus/music/Diamond.gif
Executable file
|
After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 108 KiB After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 120 KiB |
BIN
rog-anime/data/anime/asus/trend/Hero.gif
Executable file
|
After Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
@@ -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 <luke@ljones.dev>"]
|
||||
@@ -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"
|
||||
|
||||
@@ -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<GfxVendors>,
|
||||
pub gfx_action: Receiver<GfxRequiredUserAction>,
|
||||
pub profile: Receiver<Profile>,
|
||||
pub led_mode: Receiver<AuraEffect>,
|
||||
pub led_power_state: Receiver<LedPowerStates>,
|
||||
@@ -105,16 +95,6 @@ impl Signals {
|
||||
#[inline]
|
||||
pub fn new(proxies: &DbusProxies) -> Result<Self> {
|
||||
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<GfxRequiredUserAction> {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<GfxPower>;
|
||||
|
||||
/// SetVendor method
|
||||
fn set_vendor(&self, vendor: &GfxVendors) -> zbus::Result<GfxRequiredUserAction>;
|
||||
|
||||
/// Vendor method
|
||||
fn vendor(&self) -> zbus::Result<GfxVendors>;
|
||||
|
||||
/// 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<Self> {
|
||||
Ok(GfxProxy(DaemonProxy::new(conn)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn proxy(&self) -> &DaemonProxy<'a> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn gfx_get_pwr(&self) -> Result<GfxPower> {
|
||||
self.0.power()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn gfx_get_mode(&self) -> Result<GfxVendors> {
|
||||
self.0.vendor()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn gfx_write_mode(&self, vendor: &GfxVendors) -> Result<GfxRequiredUserAction> {
|
||||
self.0.set_vendor(vendor)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn connect_notify_action(
|
||||
&self,
|
||||
send: Sender<GfxRequiredUserAction>,
|
||||
) -> 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<GfxVendors>) -> zbus::fdo::Result<()> {
|
||||
self.0.connect_notify_gfx(move |data| {
|
||||
send.send(data)
|
||||
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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<Vec<Profile>>;
|
||||
|
||||
/// NextProfile method
|
||||
fn next_profile(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Profile, get the active profile
|
||||
fn active_name(&self) -> zbus::Result<String>;
|
||||
fn active_profile(&self) -> zbus::Result<Profile>;
|
||||
|
||||
/// 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<Vec<Profile>>;
|
||||
|
||||
/// Get the active `Profile` data
|
||||
fn active_data(&self) -> zbus::Result<Profile>;
|
||||
fn active_fan_data(&self) -> zbus::Result<FanCurve>;
|
||||
|
||||
/// Profiles method
|
||||
fn profiles(&self) -> zbus::Result<Vec<Profile>>;
|
||||
/// Get all fan curve data
|
||||
fn fan_curves(&self) -> zbus::Result<Vec<FanCurve>>;
|
||||
|
||||
/// ProfileNames method
|
||||
fn profile_names(&self) -> zbus::Result<Vec<String>>;
|
||||
|
||||
/// 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<String> {
|
||||
self.0.active_name()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn active_data(&self) -> Result<Profile> {
|
||||
self.0.active_data()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn all_profile_data(&self) -> Result<Vec<Profile>> {
|
||||
pub fn profiles(&self) -> Result<Vec<Profile>> {
|
||||
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<Vec<String>> {
|
||||
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<Profile>) -> zbus::fdo::Result<()> {
|
||||
self.0.connect_notify_profile(move |data| {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "rog_profiles"
|
||||
version = "0.1.2"
|
||||
version = "1.0.0"
|
||||
authors = ["Luke D. Jones <luke@ljones.dev>"]
|
||||
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 }
|
||||
@@ -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<PStateError> for ProfileError {
|
||||
fn from(err: PStateError) -> Self {
|
||||
ProfileError::IntelPstate(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CurveError> for ProfileError {
|
||||
fn from(err: CurveError) -> Self {
|
||||
ProfileError::FanCurve(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Profile, ProfileError> {
|
||||
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<Vec<Profile>, 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<Profile> 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<FanCurvePU> 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<Profile>,
|
||||
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<FanCurve> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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", <u8>::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<Curve, String> {
|
||||
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<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"normal" => Ok(FanLevel::Normal),
|
||||
"boost" => Ok(FanLevel::Boost),
|
||||
"silent" => Ok(FanLevel::Silent),
|
||||
_ => Err("Invalid fan level"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for FanLevel {
|
||||
fn from(n: u8) -> Self {
|
||||
match n {
|
||||
0 => FanLevel::Normal,
|
||||
1 => FanLevel::Boost,
|
||||
2 => FanLevel::Silent,
|
||||
_ => FanLevel::Normal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FanLevel> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 <luke@ljones.dev>"]
|
||||
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]
|
||||
@@ -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 {
|
||||
@@ -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 {}
|
||||
@@ -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<Self, GraphicsError> {
|
||||
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<Self, GraphicsError> {
|
||||
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<GfxVendors> 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",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||