mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Refactor dameon gfx
This commit is contained in:
@@ -23,7 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Enable basic multiple user anime configs (asusd-user must still be restarted)
|
- Enable basic multiple user anime configs (asusd-user must still be restarted)
|
||||||
+ Profiles:
|
+ Profiles:
|
||||||
- Enable dbus methods for freq min/max, fan curve, fan preset, CPU turbo enable.
|
- Enable dbus methods for freq min/max, fan curve, fan preset, CPU turbo enable.
|
||||||
These options will apply to the active profile if no profile name is specified.
|
These options will apply to the active profile if no profile name is specified.
|
||||||
|
|
||||||
# [3.4.1] - 2021-04-11
|
# [3.4.1] - 2021-04-11
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ use std::{str::FromStr, sync::mpsc};
|
|||||||
use std::{sync::Arc, sync::Mutex};
|
use std::{sync::Arc, sync::Mutex};
|
||||||
use sysfs_class::{PciDevice, SysClass};
|
use sysfs_class::{PciDevice, SysClass};
|
||||||
use system::{GraphicsDevice, PciBus};
|
use system::{GraphicsDevice, PciBus};
|
||||||
use zbus::{dbus_interface, Connection};
|
use ::zbus::{Connection};
|
||||||
use zvariant::ObjectPath;
|
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
@@ -32,62 +31,6 @@ pub struct CtrlGraphics {
|
|||||||
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
|
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Dbus {
|
|
||||||
fn vendor(&self) -> zbus::fdo::Result<GfxVendors>;
|
|
||||||
fn power(&self) -> zbus::fdo::Result<GfxPower>;
|
|
||||||
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction>;
|
|
||||||
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()>;
|
|
||||||
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
|
||||||
impl Dbus for 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_config(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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Reloadable for CtrlGraphics {
|
impl Reloadable for CtrlGraphics {
|
||||||
fn reload(&mut self) -> Result<(), RogError> {
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
self.auto_power()?;
|
self.auto_power()?;
|
||||||
@@ -183,7 +126,7 @@ impl CtrlGraphics {
|
|||||||
Ok(GfxVendors::Hybrid)
|
Ok(GfxVendors::Hybrid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_runtime_status() -> Result<GfxPower, RogError> {
|
pub(super) fn get_runtime_status() -> Result<GfxPower, RogError> {
|
||||||
let path = Path::new("/sys/bus/pci/devices/0000:01:00.0/power/runtime_status");
|
let path = Path::new("/sys/bus/pci/devices/0000:01:00.0/power/runtime_status");
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
let buf = std::fs::read_to_string(path).map_err(|err| {
|
let buf = std::fs::read_to_string(path).map_err(|err| {
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
pub mod gfx;
|
pub mod controller;
|
||||||
|
|
||||||
pub mod system;
|
pub mod system;
|
||||||
|
|
||||||
|
pub mod zbus_gfx;
|
||||||
|
|
||||||
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
|
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
|
||||||
|
|
||||||
const VFIO_DRIVERS: [&str; 5] = [
|
const VFIO_DRIVERS: [&str; 5] = [
|
||||||
|
|||||||
56
daemon/src/ctrl_gfx/zbus_gfx.rs
Normal file
56
daemon/src/ctrl_gfx/zbus_gfx.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
|
||||||
|
use ::zbus::{dbus_interface};
|
||||||
|
use zvariant::ObjectPath;
|
||||||
|
use log::{error, warn, info};
|
||||||
|
|
||||||
|
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_config(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();
|
||||||
|
}
|
||||||
|
}
|
||||||
240
daemon/src/ctrl_profiles/controller.rs
Normal file
240
daemon/src/ctrl_profiles/controller.rs
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
use crate::error::RogError;
|
||||||
|
use crate::{config::Config, GetSupported};
|
||||||
|
use log::{info, warn};
|
||||||
|
use rog_types::{
|
||||||
|
profile::{FanLevel, Profile, ProfileEvent},
|
||||||
|
supported::FanCpuSupportedFunctions,
|
||||||
|
};
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct CtrlFanAndCpu {
|
||||||
|
pub path: &'static str,
|
||||||
|
pub config: Arc<Mutex<Config>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetSupported for CtrlFanAndCpu {
|
||||||
|
type A = FanCpuSupportedFunctions;
|
||||||
|
|
||||||
|
fn get_supported() -> Self::A {
|
||||||
|
FanCpuSupportedFunctions {
|
||||||
|
stock_fan_modes: CtrlFanAndCpu::get_fan_path().is_ok(),
|
||||||
|
min_max_freq: intel_pstate::PState::new().is_ok(),
|
||||||
|
fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlFanAndCpu {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||||
|
let profile = config.active_profile.clone();
|
||||||
|
self.set(&profile, &mut config)?;
|
||||||
|
// info!(
|
||||||
|
// "Reloaded fan mode: {:?}",
|
||||||
|
// FanLevel::from(config.power_profile)
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlFanAndCpu {
|
||||||
|
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||||
|
let path = CtrlFanAndCpu::get_fan_path()?;
|
||||||
|
info!("Device has thermal throttle control");
|
||||||
|
Ok(CtrlFanAndCpu { path, config })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_fan_path() -> Result<&'static str, RogError> {
|
||||||
|
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(RogError::MissingFunction(
|
||||||
|
"Fan mode not available, you may require a v5.8.10 series kernel or newer".into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggle to next profile in list
|
||||||
|
pub(super) fn do_next_profile(&mut self, config: &mut Config) -> Result<(), RogError> {
|
||||||
|
config.read();
|
||||||
|
|
||||||
|
let mut i = config
|
||||||
|
.toggle_profiles
|
||||||
|
.iter()
|
||||||
|
.position(|x| x == &config.active_profile)
|
||||||
|
.map(|i| i + 1)
|
||||||
|
.unwrap_or(0);
|
||||||
|
if i >= config.toggle_profiles.len() {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_profile = config
|
||||||
|
.toggle_profiles
|
||||||
|
.get(i)
|
||||||
|
.unwrap_or(&config.active_profile)
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
self.set(&new_profile, config)?;
|
||||||
|
|
||||||
|
info!("Profile was changed: {}", &new_profile);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
|
||||||
|
let mode = config.active_profile.clone();
|
||||||
|
let mut fan_ctrl = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(self.path)
|
||||||
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
|
config.read();
|
||||||
|
let mut mode_config = config
|
||||||
|
.power_profiles
|
||||||
|
.get_mut(&mode)
|
||||||
|
.ok_or_else(|| RogError::MissingProfile(mode.clone()))?;
|
||||||
|
config.curr_fan_mode = preset;
|
||||||
|
mode_config.fan_preset = preset;
|
||||||
|
config.write();
|
||||||
|
fan_ctrl
|
||||||
|
.write_all(format!("{}\n", preset).as_bytes())
|
||||||
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
|
info!("Fan mode set to: {:?}", FanLevel::from(preset));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn handle_profile_event(
|
||||||
|
&mut self,
|
||||||
|
event: &ProfileEvent,
|
||||||
|
config: &mut Config,
|
||||||
|
) -> Result<(), RogError> {
|
||||||
|
match event {
|
||||||
|
ProfileEvent::Toggle => self.do_next_profile(config)?,
|
||||||
|
ProfileEvent::ChangeMode(mode) => {
|
||||||
|
self.set_fan_mode(*mode, config)?;
|
||||||
|
let mode = config.active_profile.clone();
|
||||||
|
self.set_pstate_for_fan_mode(&mode, config)?;
|
||||||
|
self.set_fan_curve_for_fan_mode(&mode, config)?;
|
||||||
|
}
|
||||||
|
ProfileEvent::Cli(command) => {
|
||||||
|
let profile_key = match command.profile.as_ref() {
|
||||||
|
Some(k) => k.clone(),
|
||||||
|
None => config.active_profile.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut profile = if command.create {
|
||||||
|
config
|
||||||
|
.power_profiles
|
||||||
|
.entry(profile_key.clone())
|
||||||
|
.or_insert_with(Profile::default)
|
||||||
|
} else {
|
||||||
|
config
|
||||||
|
.power_profiles
|
||||||
|
.get_mut(&profile_key)
|
||||||
|
.ok_or_else(|| RogError::MissingProfile(profile_key.clone()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
if command.turbo.is_some() {
|
||||||
|
profile.turbo = command.turbo.unwrap();
|
||||||
|
}
|
||||||
|
if let Some(min_perc) = command.min_percentage {
|
||||||
|
profile.min_percentage = min_perc;
|
||||||
|
}
|
||||||
|
if let Some(max_perc) = command.max_percentage {
|
||||||
|
profile.max_percentage = max_perc;
|
||||||
|
}
|
||||||
|
if let Some(ref preset) = command.fan_preset {
|
||||||
|
profile.fan_preset = preset.into();
|
||||||
|
}
|
||||||
|
if let Some(ref curve) = command.curve {
|
||||||
|
profile.fan_curve = Some(curve.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set(&profile_key, config)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
|
||||||
|
let mode_config = config
|
||||||
|
.power_profiles
|
||||||
|
.get(profile)
|
||||||
|
.ok_or_else(|| RogError::MissingProfile(profile.into()))?;
|
||||||
|
let mut fan_ctrl = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(self.path)
|
||||||
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
|
config.curr_fan_mode = mode_config.fan_preset;
|
||||||
|
fan_ctrl
|
||||||
|
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
|
||||||
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
|
|
||||||
|
self.set_pstate_for_fan_mode(profile, config)?;
|
||||||
|
self.set_fan_curve_for_fan_mode(profile, config)?;
|
||||||
|
|
||||||
|
config.active_profile = profile.into();
|
||||||
|
|
||||||
|
config.write();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_pstate_for_fan_mode(&self, mode: &str, config: &mut Config) -> Result<(), RogError> {
|
||||||
|
info!("Setting pstate");
|
||||||
|
let mode_config = config
|
||||||
|
.power_profiles
|
||||||
|
.get(mode)
|
||||||
|
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
|
||||||
|
|
||||||
|
// Set CPU pstate
|
||||||
|
if let Ok(pstate) = intel_pstate::PState::new() {
|
||||||
|
pstate.set_min_perf_pct(mode_config.min_percentage)?;
|
||||||
|
pstate.set_max_perf_pct(mode_config.max_percentage)?;
|
||||||
|
pstate.set_no_turbo(!mode_config.turbo)?;
|
||||||
|
info!(
|
||||||
|
"Intel CPU Power: min: {}%, max: {}%, turbo: {}",
|
||||||
|
mode_config.min_percentage, mode_config.max_percentage, mode_config.turbo
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!("Setting pstate for AMD CPU");
|
||||||
|
// must be AMD CPU
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(AMD_BOOST_PATH)
|
||||||
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
|
|
||||||
|
let boost = if mode_config.turbo { "1" } else { "0" }; // opposite of Intel
|
||||||
|
file.write_all(boost.as_bytes())
|
||||||
|
.map_err(|err| RogError::Write(AMD_BOOST_PATH.into(), err))?;
|
||||||
|
info!("AMD CPU Turbo: {}", boost);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_fan_curve_for_fan_mode(&self, mode: &str, config: &Config) -> Result<(), RogError> {
|
||||||
|
let mode_config = &config
|
||||||
|
.power_profiles
|
||||||
|
.get(mode)
|
||||||
|
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
|
||||||
|
|
||||||
|
if let Some(ref curve) = mode_config.fan_curve {
|
||||||
|
use rog_fan_curve::{Board, Fan};
|
||||||
|
if let Some(board) = Board::from_board_name() {
|
||||||
|
curve.apply(board, Fan::Cpu)?;
|
||||||
|
curve.apply(board, Fan::Gpu)?;
|
||||||
|
} else {
|
||||||
|
warn!("Fan curve unsupported on this board.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,243 +1,7 @@
|
|||||||
pub mod zbus;
|
pub mod zbus;
|
||||||
|
|
||||||
use crate::error::RogError;
|
pub mod controller;
|
||||||
use crate::{config::Config, GetSupported};
|
|
||||||
use log::{info, warn};
|
|
||||||
use rog_types::{
|
|
||||||
profile::{FanLevel, Profile, ProfileEvent},
|
|
||||||
supported::FanCpuSupportedFunctions,
|
|
||||||
};
|
|
||||||
use std::fs::OpenOptions;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
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 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";
|
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
|
||||||
|
|
||||||
pub struct CtrlFanAndCpu {
|
|
||||||
pub path: &'static str,
|
|
||||||
config: Arc<Mutex<Config>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GetSupported for CtrlFanAndCpu {
|
|
||||||
type A = FanCpuSupportedFunctions;
|
|
||||||
|
|
||||||
fn get_supported() -> Self::A {
|
|
||||||
FanCpuSupportedFunctions {
|
|
||||||
stock_fan_modes: CtrlFanAndCpu::get_fan_path().is_ok(),
|
|
||||||
min_max_freq: intel_pstate::PState::new().is_ok(),
|
|
||||||
fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::Reloadable for CtrlFanAndCpu {
|
|
||||||
fn reload(&mut self) -> Result<(), RogError> {
|
|
||||||
if let Ok(mut config) = self.config.clone().try_lock() {
|
|
||||||
let profile = config.active_profile.clone();
|
|
||||||
self.set(&profile, &mut config)?;
|
|
||||||
// info!(
|
|
||||||
// "Reloaded fan mode: {:?}",
|
|
||||||
// FanLevel::from(config.power_profile)
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CtrlFanAndCpu {
|
|
||||||
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
|
||||||
let path = CtrlFanAndCpu::get_fan_path()?;
|
|
||||||
info!("Device has thermal throttle control");
|
|
||||||
Ok(CtrlFanAndCpu { path, config })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_fan_path() -> Result<&'static str, RogError> {
|
|
||||||
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(RogError::MissingFunction(
|
|
||||||
"Fan mode not available, you may require a v5.8.10 series kernel or newer".into(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Toggle to next profile in list
|
|
||||||
pub(super) fn do_next_profile(&mut self, config: &mut Config) -> Result<(), RogError> {
|
|
||||||
config.read();
|
|
||||||
|
|
||||||
let mut i = config
|
|
||||||
.toggle_profiles
|
|
||||||
.iter()
|
|
||||||
.position(|x| x == &config.active_profile)
|
|
||||||
.map(|i| i + 1)
|
|
||||||
.unwrap_or(0);
|
|
||||||
if i >= config.toggle_profiles.len() {
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_profile = config
|
|
||||||
.toggle_profiles
|
|
||||||
.get(i)
|
|
||||||
.unwrap_or(&config.active_profile)
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
self.set(&new_profile, config)?;
|
|
||||||
|
|
||||||
info!("Profile was changed: {}", &new_profile);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
|
|
||||||
let mode = config.active_profile.clone();
|
|
||||||
let mut fan_ctrl = OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.open(self.path)
|
|
||||||
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
|
||||||
config.read();
|
|
||||||
let mut mode_config = config
|
|
||||||
.power_profiles
|
|
||||||
.get_mut(&mode)
|
|
||||||
.ok_or_else(|| RogError::MissingProfile(mode.clone()))?;
|
|
||||||
config.curr_fan_mode = preset;
|
|
||||||
mode_config.fan_preset = preset;
|
|
||||||
config.write();
|
|
||||||
fan_ctrl
|
|
||||||
.write_all(format!("{}\n", preset).as_bytes())
|
|
||||||
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
|
||||||
info!("Fan mode set to: {:?}", FanLevel::from(preset));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_profile_event(
|
|
||||||
&mut self,
|
|
||||||
event: &ProfileEvent,
|
|
||||||
config: &mut Config,
|
|
||||||
) -> Result<(), RogError> {
|
|
||||||
match event {
|
|
||||||
ProfileEvent::Toggle => self.do_next_profile(config)?,
|
|
||||||
ProfileEvent::ChangeMode(mode) => {
|
|
||||||
self.set_fan_mode(*mode, config)?;
|
|
||||||
let mode = config.active_profile.clone();
|
|
||||||
self.set_pstate_for_fan_mode(&mode, config)?;
|
|
||||||
self.set_fan_curve_for_fan_mode(&mode, config)?;
|
|
||||||
}
|
|
||||||
ProfileEvent::Cli(command) => {
|
|
||||||
let profile_key = match command.profile.as_ref() {
|
|
||||||
Some(k) => k.clone(),
|
|
||||||
None => config.active_profile.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut profile = if command.create {
|
|
||||||
config
|
|
||||||
.power_profiles
|
|
||||||
.entry(profile_key.clone())
|
|
||||||
.or_insert_with(Profile::default)
|
|
||||||
} else {
|
|
||||||
config
|
|
||||||
.power_profiles
|
|
||||||
.get_mut(&profile_key)
|
|
||||||
.ok_or_else(|| RogError::MissingProfile(profile_key.clone()))?
|
|
||||||
};
|
|
||||||
|
|
||||||
if command.turbo.is_some() {
|
|
||||||
profile.turbo = command.turbo.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(min_perc) = command.min_percentage {
|
|
||||||
profile.min_percentage = min_perc;
|
|
||||||
}
|
|
||||||
if let Some(max_perc) = command.max_percentage {
|
|
||||||
profile.max_percentage = max_perc;
|
|
||||||
}
|
|
||||||
if let Some(ref preset) = command.fan_preset {
|
|
||||||
profile.fan_preset = preset.into();
|
|
||||||
}
|
|
||||||
if let Some(ref curve) = command.curve {
|
|
||||||
profile.fan_curve = Some(curve.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self.set(&profile_key, config)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
|
|
||||||
let mode_config = config
|
|
||||||
.power_profiles
|
|
||||||
.get(profile)
|
|
||||||
.ok_or_else(|| RogError::MissingProfile(profile.into()))?;
|
|
||||||
let mut fan_ctrl = OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.open(self.path)
|
|
||||||
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
|
||||||
config.curr_fan_mode = mode_config.fan_preset;
|
|
||||||
fan_ctrl
|
|
||||||
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
|
|
||||||
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
|
||||||
|
|
||||||
self.set_pstate_for_fan_mode(profile, config)?;
|
|
||||||
self.set_fan_curve_for_fan_mode(profile, config)?;
|
|
||||||
|
|
||||||
config.active_profile = profile.into();
|
|
||||||
|
|
||||||
config.write();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_pstate_for_fan_mode(&self, mode: &str, config: &mut Config) -> Result<(), RogError> {
|
|
||||||
info!("Setting pstate");
|
|
||||||
let mode_config = config
|
|
||||||
.power_profiles
|
|
||||||
.get(mode)
|
|
||||||
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
|
|
||||||
|
|
||||||
// Set CPU pstate
|
|
||||||
if let Ok(pstate) = intel_pstate::PState::new() {
|
|
||||||
pstate.set_min_perf_pct(mode_config.min_percentage)?;
|
|
||||||
pstate.set_max_perf_pct(mode_config.max_percentage)?;
|
|
||||||
pstate.set_no_turbo(!mode_config.turbo)?;
|
|
||||||
info!(
|
|
||||||
"Intel CPU Power: min: {}%, max: {}%, turbo: {}",
|
|
||||||
mode_config.min_percentage, mode_config.max_percentage, mode_config.turbo
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
info!("Setting pstate for AMD CPU");
|
|
||||||
// must be AMD CPU
|
|
||||||
let mut file = OpenOptions::new()
|
|
||||||
.write(true)
|
|
||||||
.open(AMD_BOOST_PATH)
|
|
||||||
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
|
||||||
|
|
||||||
let boost = if mode_config.turbo { "1" } else { "0" }; // opposite of Intel
|
|
||||||
file.write_all(boost.as_bytes())
|
|
||||||
.map_err(|err| RogError::Write(AMD_BOOST_PATH.into(), err))?;
|
|
||||||
info!("AMD CPU Turbo: {}", boost);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_fan_curve_for_fan_mode(&self, mode: &str, config: &Config) -> Result<(), RogError> {
|
|
||||||
let mode_config = &config
|
|
||||||
.power_profiles
|
|
||||||
.get(mode)
|
|
||||||
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
|
|
||||||
|
|
||||||
if let Some(ref curve) = mode_config.fan_curve {
|
|
||||||
use rog_fan_curve::{Board, Fan};
|
|
||||||
if let Some(board) = Board::from_board_name() {
|
|
||||||
curve.apply(board, Fan::Cpu)?;
|
|
||||||
curve.apply(board, Fan::Gpu)?;
|
|
||||||
} else {
|
|
||||||
warn!("Fan curve unsupported on this board.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::sync::Mutex;
|
|||||||
use zbus::{dbus_interface, fdo::Error};
|
use zbus::{dbus_interface, fdo::Error};
|
||||||
use zvariant::ObjectPath;
|
use zvariant::ObjectPath;
|
||||||
|
|
||||||
use super::CtrlFanAndCpu;
|
use super::controller::CtrlFanAndCpu;
|
||||||
|
|
||||||
pub struct FanAndCpuZbus {
|
pub struct FanAndCpuZbus {
|
||||||
inner: Arc<Mutex<CtrlFanAndCpu>>,
|
inner: Arc<Mutex<CtrlFanAndCpu>>,
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
use zbus::dbus_interface;
|
use zbus::dbus_interface;
|
||||||
use zvariant::ObjectPath;
|
use zvariant::ObjectPath;
|
||||||
|
|
||||||
use crate::{
|
use crate::{GetSupported, ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::CtrlKbdLed, ctrl_profiles::controller::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios};
|
||||||
ctrl_anime::CtrlAnime, ctrl_charge::CtrlCharge, ctrl_leds::CtrlKbdLed,
|
|
||||||
ctrl_profiles::CtrlFanAndCpu, ctrl_rog_bios::CtrlRogBios, GetSupported,
|
|
||||||
};
|
|
||||||
|
|
||||||
use rog_types::supported::{
|
use rog_types::supported::{
|
||||||
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
|
AnimeSupportedFunctions, ChargeSupportedFunctions, FanCpuSupportedFunctions,
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use daemon::{
|
|||||||
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||||
};
|
};
|
||||||
use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
use daemon::{config_anime::AnimeConfig, config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
||||||
use daemon::{ctrl_anime::*, ctrl_gfx::gfx::CtrlGraphics};
|
use daemon::{ctrl_anime::*, ctrl_gfx::controller::CtrlGraphics};
|
||||||
use daemon::{
|
use daemon::{
|
||||||
ctrl_profiles::{zbus::FanAndCpuZbus, CtrlFanAndCpu},
|
ctrl_profiles::{zbus::FanAndCpuZbus, controller::CtrlFanAndCpu},
|
||||||
laptops::LaptopLedData,
|
laptops::LaptopLedData,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user