hardware: Move DeviceConfig and allow for auto-matching based on file contents

This commit is contained in:
Vicki Pfau 2025-06-11 18:44:30 -07:00
parent ee9d2332aa
commit dd9b000e4b
10 changed files with 375 additions and 263 deletions

View file

@ -8,30 +8,22 @@
use anyhow::Result;
use nix::errno::Errno;
use nix::unistd::{access, AccessFlags};
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use serde::Deserialize;
use std::io::ErrorKind;
use std::num::NonZeroU32;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use strum::VariantNames;
use tokio::fs::{metadata, read_to_string};
#[cfg(not(test))]
use tokio::sync::OnceCell;
use tokio::task::spawn_blocking;
use zbus::Connection;
#[cfg(not(test))]
use crate::hardware::{device_type, DeviceType};
#[cfg(test)]
use crate::path;
use crate::power::TdpLimitingMethod;
use crate::systemd::SystemdUnit;
#[cfg(not(test))]
static PLATFORM_CONFIG: OnceCell<Option<PlatformConfig>> = OnceCell::const_new();
#[cfg(not(test))]
static DEVICE_CONFIG: OnceCell<Option<DeviceConfig>> = OnceCell::const_new();
#[derive(Clone, Default, Deserialize, Debug)]
#[serde(default)]
@ -43,23 +35,6 @@ pub(crate) struct PlatformConfig {
pub fan_control: Option<ServiceConfig>,
}
#[derive(Clone, Default, Deserialize, Debug)]
#[serde(default)]
pub(crate) struct DeviceConfig {
pub tdp_limit: Option<TdpLimitConfig>,
pub gpu_clocks: Option<RangeConfig<u32>>,
pub battery_charge_limit: Option<BatteryChargeLimitConfig>,
pub performance_profile: Option<PerformanceProfileConfig>,
}
#[derive(Clone, Deserialize, Debug)]
pub(crate) struct RangeConfig<T: Clone> {
pub min: T,
pub max: T,
}
impl<T> Copy for RangeConfig<T> where T: Copy {}
#[derive(Clone, Default, Deserialize, Debug)]
pub(crate) struct ScriptConfig {
pub script: PathBuf,
@ -151,34 +126,6 @@ impl StorageConfig {
}
}
#[derive(Clone, Deserialize, Debug)]
pub(crate) struct BatteryChargeLimitConfig {
pub suggested_minimum_limit: Option<i32>,
pub hwmon_name: String,
pub attribute: String,
}
#[derive(Clone, Deserialize, Debug)]
pub(crate) struct FirmwareAttributeConfig {
pub attribute: String,
pub performance_profile: Option<String>,
}
#[derive(Clone, Deserialize, Debug)]
pub(crate) struct PerformanceProfileConfig {
pub suggested_default: String,
pub platform_profile_name: String,
}
#[derive(Clone, Deserialize, Debug)]
pub(crate) struct TdpLimitConfig {
#[serde(deserialize_with = "de_tdp_limiter_method")]
pub method: TdpLimitingMethod,
pub range: Option<RangeConfig<u32>>,
pub download_mode_limit: Option<NonZeroU32>,
pub firmware_attribute: Option<FirmwareAttributeConfig>,
}
#[derive(Clone, Default, Deserialize, Debug)]
pub(crate) struct FormatDeviceConfig {
pub script: PathBuf,
@ -223,13 +170,6 @@ impl FormatDeviceConfig {
}
}
impl<T: Clone> RangeConfig<T> {
#[allow(unused)]
pub(crate) fn new(min: T, max: T) -> RangeConfig<T> {
RangeConfig { min, max }
}
}
impl PlatformConfig {
#[cfg(not(test))]
async fn load() -> Result<Option<PlatformConfig>> {
@ -271,46 +211,11 @@ impl PlatformConfig {
}
}
impl DeviceConfig {
#[cfg(not(test))]
async fn load() -> Result<Option<DeviceConfig>> {
let platform = match device_type().await? {
DeviceType::SteamDeck => "jupiter",
DeviceType::LegionGo => "legion-go-series",
DeviceType::LegionGoS => "legion-go-series",
DeviceType::RogAlly => "rog-ally-series",
DeviceType::RogAllyX => "rog-ally-series",
DeviceType::ZotacGamingZone => "zotac-gaming-zone",
_ => return Ok(None),
};
let config = read_to_string(format!(
"/usr/share/steamos-manager/devices/{platform}.toml"
))
.await?;
Ok(Some(toml::from_str(config.as_ref())?))
}
}
fn de_tdp_limiter_method<'de, D>(deserializer: D) -> Result<TdpLimitingMethod, D::Error>
where
D: Deserializer<'de>,
D::Error: Error,
{
let string = String::deserialize(deserializer)?;
TdpLimitingMethod::try_from(string.as_str())
.map_err(|_| D::Error::unknown_variant(string.as_str(), TdpLimitingMethod::VARIANTS))
}
#[cfg(not(test))]
pub(crate) async fn platform_config() -> Result<&'static Option<PlatformConfig>> {
PLATFORM_CONFIG.get_or_try_init(PlatformConfig::load).await
}
#[cfg(not(test))]
pub(crate) async fn device_config() -> Result<&'static Option<DeviceConfig>> {
DEVICE_CONFIG.get_or_try_init(DeviceConfig::load).await
}
#[cfg(test)]
pub(crate) async fn platform_config() -> Result<Option<PlatformConfig>> {
let test = crate::testing::current();
@ -318,13 +223,6 @@ pub(crate) async fn platform_config() -> Result<Option<PlatformConfig>> {
Ok(config)
}
#[cfg(test)]
pub(crate) async fn device_config() -> Result<Option<DeviceConfig>> {
let test = crate::testing::current();
let config = test.device_config.borrow().clone();
Ok(config)
}
#[cfg(test)]
mod test {
use super::*;