diff --git a/data/platforms/jupiter.toml b/data/platforms/jupiter.toml index ae106df..7acfffe 100644 --- a/data/platforms/jupiter.toml +++ b/data/platforms/jupiter.toml @@ -16,3 +16,6 @@ script = "/usr/lib/hwsupport/format-device.sh" label_flag = "--label" device_flag = "--device" no_validate_flag = "--skip-validation" + +[fan_control] +systemd = "jupiter-fan-control.service" diff --git a/src/hardware.rs b/src/hardware.rs index 1c222ea..63ac601 100644 --- a/src/hardware.rs +++ b/src/hardware.rs @@ -5,14 +5,15 @@ * SPDX-License-Identifier: MIT */ -use anyhow::{anyhow, bail, Error, Result}; +use anyhow::{anyhow, bail, ensure, Error, Result}; use std::fmt; use std::str::FromStr; use tokio::fs; use zbus::Connection; use crate::path; -use crate::process::script_exit_code; +use crate::platform::{platform_config, ServiceConfig}; +use crate::process::{run_script, script_exit_code}; use crate::systemd::SystemdUnit; const BOARD_VENDOR_PATH: &str = "/sys/class/dmi/id/board_vendor"; @@ -148,22 +149,57 @@ impl FanControl { } pub async fn get_state(&self) -> Result { - let jupiter_fan_control = - SystemdUnit::new(self.connection.clone(), "jupiter-fan-control.service").await?; - let active = jupiter_fan_control.active().await?; - Ok(match active { - true => FanControlState::Os, - false => FanControlState::Bios, - }) + let config = platform_config().await?; + match config + .as_ref() + .and_then(|config| config.fan_control.as_ref()) + { + Some(ServiceConfig::Systemd(service)) => { + let jupiter_fan_control = + SystemdUnit::new(self.connection.clone(), service).await?; + let active = jupiter_fan_control.active().await?; + Ok(match active { + true => FanControlState::Os, + false => FanControlState::Bios, + }) + } + Some(ServiceConfig::Script { + start: _, + stop: _, + status, + }) => { + let res = script_exit_code(&status.script, &status.script_args).await?; + ensure!(res >= 0, "Script exited abnormally"); + FanControlState::try_from(res as u32) + } + None => bail!("Fan control not configured"), + } } pub async fn set_state(&self, state: FanControlState) -> Result<()> { // Run what steamos-polkit-helpers/jupiter-fan-control does - let jupiter_fan_control = - SystemdUnit::new(self.connection.clone(), "jupiter-fan-control.service").await?; - match state { - FanControlState::Os => jupiter_fan_control.start().await, - FanControlState::Bios => jupiter_fan_control.stop().await, + let config = platform_config().await?; + match config + .as_ref() + .and_then(|config| config.fan_control.as_ref()) + { + Some(ServiceConfig::Systemd(service)) => { + let jupiter_fan_control = + SystemdUnit::new(self.connection.clone(), service).await?; + match state { + FanControlState::Os => jupiter_fan_control.start().await, + FanControlState::Bios => jupiter_fan_control.stop().await, + } + } + Some(ServiceConfig::Script { + start, + stop, + status: _, + }) => match state { + FanControlState::Os => run_script(&start.script, &start.script_args).await, + FanControlState::Bios => run_script(&stop.script, &stop.script_args).await, + }, + None => bail!("Fan control not configured"), } } } @@ -172,6 +208,7 @@ impl FanControl { pub mod test { use super::*; use crate::error::to_zbus_fdo_error; + use crate::platform::{PlatformConfig, ServiceConfig}; use crate::{enum_roundtrip, testing}; use std::time::Duration; use tokio::fs::{create_dir_all, write}; @@ -322,6 +359,16 @@ pub mod test { sleep(Duration::from_millis(10)).await; + h.test.platform_config.replace(Some(PlatformConfig { + factory_reset: None, + update_bios: None, + update_dock: None, + storage: None, + fan_control: Some(ServiceConfig::Systemd(String::from( + "jupiter-fan-control.service", + ))), + })); + let fan_control = FanControl::new(connection); assert_eq!( fan_control.get_state().await.unwrap(), diff --git a/src/manager/user.rs b/src/manager/user.rs index 9cc69c3..e678689 100644 --- a/src/manager/user.rs +++ b/src/manager/user.rs @@ -582,7 +582,12 @@ pub(crate) async fn create_interfaces( object_server.at(MANAGER_PATH, factory_reset).await?; } - object_server.at(MANAGER_PATH, fan_control).await?; + if config + .as_ref() + .is_some_and(|config| config.fan_control.is_some()) + { + object_server.at(MANAGER_PATH, fan_control).await?; + } if !get_available_gpu_performance_levels() .await @@ -645,7 +650,7 @@ mod test { use crate::daemon::user::UserContext; use crate::hardware::test::fake_model; use crate::hardware::HardwareVariant; - use crate::platform::{PlatformConfig, ScriptConfig, StorageConfig}; + use crate::platform::{PlatformConfig, ScriptConfig, ServiceConfig, StorageConfig}; use crate::{power, testing}; use std::time::Duration; @@ -664,6 +669,9 @@ mod test { update_bios: Some(ScriptConfig::default()), update_dock: Some(ScriptConfig::default()), storage: Some(StorageConfig::default()), + fan_control: Some(ServiceConfig::Systemd(String::from( + "jupiter-fan-control.service", + ))), }) } @@ -767,6 +775,13 @@ mod test { .unwrap()); } + #[tokio::test] + async fn interface_missing_fan_control1() { + let test = start(None).await.expect("start"); + + assert!(test_interface_missing::(&test.connection).await); + } + #[tokio::test] async fn interface_matches_gpu_performance_level1() { let test = start(all_config()).await.expect("start"); diff --git a/src/platform.rs b/src/platform.rs index 8e74072..d279bd0 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -25,6 +25,7 @@ pub(crate) struct PlatformConfig { pub update_bios: Option, pub update_dock: Option, pub storage: Option, + pub fan_control: Option, } #[derive(Clone, Default, Deserialize, Debug)] @@ -34,6 +35,18 @@ pub(crate) struct ScriptConfig { pub script_args: Vec, } +#[derive(Clone, Deserialize, Debug)] +pub(crate) enum ServiceConfig { + #[serde(rename = "systemd")] + Systemd(String), + #[serde(rename = "script")] + Script { + start: ScriptConfig, + stop: ScriptConfig, + status: ScriptConfig, + }, +} + #[derive(Clone, Default, Deserialize, Debug)] pub(crate) struct StorageConfig { pub trim_devices: ScriptConfig,