forked from NG-SD-Plugins/PowerTools
Create basic generic (placeholder) driver
This commit is contained in:
parent
5d2937af6f
commit
d1d5265224
7 changed files with 528 additions and 0 deletions
|
@ -9,6 +9,8 @@ pub enum DriverJson {
|
|||
SteamDeck,
|
||||
#[serde(rename = "steam-deck-oc", alias = "gabe-boy-advance")]
|
||||
SteamDeckAdvance,
|
||||
#[serde(rename = "generic")]
|
||||
Generic,
|
||||
#[serde(rename = "unknown")]
|
||||
Unknown,
|
||||
}
|
||||
|
|
|
@ -26,6 +26,8 @@ fn auto_detect() -> DriverJson {
|
|||
} else {
|
||||
DriverJson::SteamDeckAdvance
|
||||
}
|
||||
} else if let Some(_) = lscpu.find("model name\t: AMD Ryzen") {
|
||||
DriverJson::Generic
|
||||
} else {
|
||||
DriverJson::Unknown
|
||||
}
|
||||
|
@ -88,6 +90,17 @@ impl Driver {
|
|||
gpu: Box::new(super::steam_deck_adv::Gpu::from_json(settings.gpu, settings.version)),
|
||||
battery: Box::new(super::steam_deck::Battery::from_json(settings.battery, settings.version)),
|
||||
}),
|
||||
DriverJson::Generic => Ok(Self {
|
||||
general: Box::new(General {
|
||||
persistent: settings.persistent,
|
||||
path: json_path,
|
||||
name: settings.name,
|
||||
driver: DriverJson::Unknown,
|
||||
}),
|
||||
cpus: Box::new(super::generic::Cpus::from_json(settings.cpus, settings.version)),
|
||||
gpu: Box::new(super::generic::Gpu::from_json(settings.gpu, settings.version)),
|
||||
battery: Box::new(super::generic::Battery),
|
||||
}),
|
||||
DriverJson::Unknown => Ok(Self {
|
||||
general: Box::new(General {
|
||||
persistent: settings.persistent,
|
||||
|
@ -127,6 +140,17 @@ impl Driver {
|
|||
gpu: Box::new(super::steam_deck_adv::Gpu::system_default()),
|
||||
battery: Box::new(super::steam_deck::Battery::system_default()),
|
||||
},
|
||||
DriverJson::Generic => Self {
|
||||
general: Box::new(General {
|
||||
persistent: false,
|
||||
path: json_path,
|
||||
name: crate::consts::DEFAULT_SETTINGS_NAME.to_owned(),
|
||||
driver: DriverJson::Unknown,
|
||||
}),
|
||||
cpus: Box::new(super::generic::Cpus::system_default()),
|
||||
gpu: Box::new(super::generic::Gpu::system_default()),
|
||||
battery: Box::new(super::generic::Battery),
|
||||
},
|
||||
DriverJson::Unknown => Self {
|
||||
general: Box::new(General {
|
||||
persistent: false,
|
||||
|
@ -159,6 +183,7 @@ pub fn maybe_do_button() {
|
|||
std::thread::sleep(period);
|
||||
}
|
||||
},
|
||||
DriverJson::Generic => log::warn!("You need to come up with something fun on generic"),
|
||||
DriverJson::Unknown => log::warn!("Can't do button activities on unknown platform"),
|
||||
}
|
||||
}
|
||||
|
|
115
backend/src/settings/generic/battery.rs
Normal file
115
backend/src/settings/generic/battery.rs
Normal file
|
@ -0,0 +1,115 @@
|
|||
use std::convert::Into;
|
||||
|
||||
use crate::settings::{OnResume, OnSet, SettingError};
|
||||
use crate::settings::TBattery;
|
||||
use crate::persist::BatteryJson;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Battery;
|
||||
|
||||
impl Into<BatteryJson> for Battery {
|
||||
#[inline]
|
||||
fn into(self) -> BatteryJson {
|
||||
BatteryJson {
|
||||
charge_rate: None,
|
||||
charge_mode: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Battery {
|
||||
fn read_f64<P: AsRef<std::path::Path>>(path: P) -> Result<f64, SettingError> {
|
||||
let path = path.as_ref();
|
||||
match usdpl_back::api::files::read_single::<_, f64, _>(path) {
|
||||
Err((Some(e), None)) => Err(SettingError {
|
||||
msg: format!("Failed to read from `{}`: {}", path.display(), e),
|
||||
setting: crate::settings::SettingVariant::Battery,
|
||||
}),
|
||||
Err((None, Some(e))) => Err(SettingError {
|
||||
msg: format!("Failed to read from `{}`: {}", path.display(), e),
|
||||
setting: crate::settings::SettingVariant::Battery,
|
||||
}),
|
||||
Err(_) => panic!(
|
||||
"Invalid error while reading from `{}`",
|
||||
path.display()
|
||||
),
|
||||
// this value is in uA, while it's set in mA
|
||||
// so convert this to mA for consistency
|
||||
Ok(val) => Ok(val / 1000.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OnSet for Battery {
|
||||
fn on_set(&mut self) -> Result<(), SettingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OnResume for Battery {
|
||||
fn on_resume(&self) -> Result<(), SettingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TBattery for Battery {
|
||||
fn limits(&self) -> crate::api::BatteryLimits {
|
||||
crate::api::BatteryLimits {
|
||||
charge_current: None,
|
||||
charge_current_step: 50,
|
||||
charge_modes: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn json(&self) -> crate::persist::BatteryJson {
|
||||
self.clone().into()
|
||||
}
|
||||
|
||||
fn charge_rate(&mut self, _rate: Option<u64>) {
|
||||
}
|
||||
|
||||
fn get_charge_rate(&self) -> Option<u64> {
|
||||
None
|
||||
}
|
||||
|
||||
fn charge_mode(&mut self, _rate: Option<String>) {
|
||||
}
|
||||
|
||||
fn get_charge_mode(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
fn read_charge_full(&self) -> Option<f64> {
|
||||
match Self::read_f64("/sys/class/power_supply/BAT0/energy_full") {
|
||||
Ok(x) => Some(x),
|
||||
Err(e) => {
|
||||
log::warn!("read_charge_full err: {}", e.msg);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_charge_now(&self) -> Option<f64> {
|
||||
match Self::read_f64("/sys/class/power_supply/BAT0/energy_now") {
|
||||
Ok(x) => Some(x),
|
||||
Err(e) => {
|
||||
log::warn!("read_charge_now err: {}", e.msg);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_charge_design(&self) -> Option<f64> {
|
||||
match Self::read_f64("/sys/class/power_supply/BAT0/energy_design") {
|
||||
Ok(x) => Some(x),
|
||||
Err(e) => {
|
||||
log::warn!("read_charge_design err: {}", e.msg);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_current_now(&self) -> Option<f64> {
|
||||
None
|
||||
}
|
||||
}
|
289
backend/src/settings/generic/cpu.rs
Normal file
289
backend/src/settings/generic/cpu.rs
Normal file
|
@ -0,0 +1,289 @@
|
|||
use std::convert::Into;
|
||||
|
||||
use crate::settings::MinMax;
|
||||
use crate::settings::{OnResume, OnSet, SettingError};
|
||||
use crate::settings::{TCpus, TCpu};
|
||||
use crate::persist::CpuJson;
|
||||
|
||||
const CPU_PRESENT_PATH: &str = "/sys/devices/system/cpu/present";
|
||||
const CPU_SMT_PATH: &str = "/sys/devices/system/cpu/smt/control";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Cpus {
|
||||
pub cpus: Vec<Cpu>,
|
||||
pub smt: bool,
|
||||
pub smt_capable: bool,
|
||||
}
|
||||
|
||||
impl OnSet for Cpus {
|
||||
fn on_set(&mut self) -> Result<(), SettingError> {
|
||||
if self.smt_capable {
|
||||
// toggle SMT
|
||||
if self.smt {
|
||||
usdpl_back::api::files::write_single(CPU_SMT_PATH, "on").map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `on` to `{}`: {}",
|
||||
CPU_SMT_PATH, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
} else {
|
||||
usdpl_back::api::files::write_single(CPU_SMT_PATH, "off").map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `off` to `{}`: {}",
|
||||
CPU_SMT_PATH, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
}
|
||||
}
|
||||
for (i, cpu) in self.cpus.as_mut_slice().iter_mut().enumerate() {
|
||||
cpu.state.do_set_online = self.smt || i % 2 == 0;
|
||||
cpu.on_set()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OnResume for Cpus {
|
||||
fn on_resume(&self) -> Result<(), SettingError> {
|
||||
for cpu in &self.cpus {
|
||||
cpu.on_resume()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Cpus {
|
||||
pub fn cpu_count() -> Option<usize> {
|
||||
let mut data: String = usdpl_back::api::files::read_single(CPU_PRESENT_PATH)
|
||||
.unwrap_or_else(|_| "0-7".to_string() /* Steam Deck's default */);
|
||||
if let Some(dash_index) = data.find('-') {
|
||||
let data = data.split_off(dash_index + 1);
|
||||
if let Ok(max_cpu) = data.parse::<usize>() {
|
||||
return Some(max_cpu + 1);
|
||||
}
|
||||
}
|
||||
log::warn!("Failed to parse CPU info from kernel, is Tux evil?");
|
||||
None
|
||||
}
|
||||
|
||||
fn system_smt_capabilities() -> (bool, bool) {
|
||||
match usdpl_back::api::files::read_single::<_, String, _>(CPU_SMT_PATH) {
|
||||
Ok(val) => (val.trim().to_lowercase() == "on", true),
|
||||
Err(_) => (false, false)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn system_default() -> Self {
|
||||
if let Some(max_cpu) = Self::cpu_count() {
|
||||
let mut sys_cpus = Vec::with_capacity(max_cpu);
|
||||
for i in 0..max_cpu {
|
||||
sys_cpus.push(Cpu::from_sys(i));
|
||||
}
|
||||
let (smt_status, can_smt) = Self::system_smt_capabilities();
|
||||
Self {
|
||||
cpus: sys_cpus,
|
||||
smt: smt_status,
|
||||
smt_capable: can_smt,
|
||||
}
|
||||
} else {
|
||||
Self {
|
||||
cpus: vec![],
|
||||
smt: false,
|
||||
smt_capable: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_json(mut other: Vec<CpuJson>, version: u64) -> Self {
|
||||
let (_, can_smt) = Self::system_smt_capabilities();
|
||||
let mut result = Vec::with_capacity(other.len());
|
||||
let max_cpus = Self::cpu_count();
|
||||
for (i, cpu) in other.drain(..).enumerate() {
|
||||
// prevent having more CPUs than available
|
||||
if let Some(max_cpus) = max_cpus {
|
||||
if i == max_cpus {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.push(Cpu::from_json(cpu, version, i));
|
||||
}
|
||||
if let Some(max_cpus) = max_cpus {
|
||||
if result.len() != max_cpus {
|
||||
let mut sys_cpus = Cpus::system_default();
|
||||
for i in result.len()..sys_cpus.cpus.len() {
|
||||
result.push(sys_cpus.cpus.remove(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
Self {
|
||||
cpus: result,
|
||||
smt: true,
|
||||
smt_capable: can_smt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TCpus for Cpus {
|
||||
fn limits(&self) -> crate::api::CpusLimits {
|
||||
crate::api::CpusLimits {
|
||||
cpus: self.cpus.iter().map(|x| x.limits()).collect(),
|
||||
count: self.cpus.len(),
|
||||
smt_capable: self.smt_capable,
|
||||
}
|
||||
}
|
||||
|
||||
fn json(&self) -> Vec<crate::persist::CpuJson> {
|
||||
self.cpus.iter().map(|x| x.to_owned().into()).collect()
|
||||
}
|
||||
|
||||
fn cpus(&mut self) -> Vec<&mut dyn TCpu> {
|
||||
self.cpus.iter_mut().map(|x| x as &mut dyn TCpu).collect()
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.cpus.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Cpu {
|
||||
pub online: bool,
|
||||
pub governor: String,
|
||||
index: usize,
|
||||
state: crate::state::steam_deck::Cpu,
|
||||
}
|
||||
|
||||
|
||||
impl Cpu {
|
||||
#[inline]
|
||||
pub fn from_json(other: CpuJson, version: u64, i: usize) -> Self {
|
||||
match version {
|
||||
0 => Self {
|
||||
online: other.online,
|
||||
governor: other.governor,
|
||||
index: i,
|
||||
state: crate::state::steam_deck::Cpu::default(),
|
||||
},
|
||||
_ => Self {
|
||||
online: other.online,
|
||||
governor: other.governor,
|
||||
index: i,
|
||||
state: crate::state::steam_deck::Cpu::default(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn set_all(&mut self) -> Result<(), SettingError> {
|
||||
// set cpu online/offline
|
||||
if self.index != 0 && self.state.do_set_online { // cpu0 cannot be disabled
|
||||
let online_path = cpu_online_path(self.index);
|
||||
usdpl_back::api::files::write_single(&online_path, self.online as u8).map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!("Failed to write to `{}`: {}", &online_path, e),
|
||||
setting: crate::settings::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
// set governor
|
||||
if self.index == 0 || self.online {
|
||||
let governor_path = cpu_governor_path(self.index);
|
||||
usdpl_back::api::files::write_single(&governor_path, &self.governor).map_err(|e| {
|
||||
SettingError {
|
||||
msg: format!(
|
||||
"Failed to write `{}` to `{}`: {}",
|
||||
&self.governor, &governor_path, e
|
||||
),
|
||||
setting: crate::settings::SettingVariant::Cpu,
|
||||
}
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn from_sys(cpu_index: usize) -> Self {
|
||||
Self {
|
||||
online: usdpl_back::api::files::read_single(cpu_online_path(cpu_index)).unwrap_or(1u8) != 0,
|
||||
governor: usdpl_back::api::files::read_single(cpu_governor_path(cpu_index))
|
||||
.unwrap_or("schedutil".to_owned()),
|
||||
index: cpu_index,
|
||||
state: crate::state::steam_deck::Cpu::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn limits(&self) -> crate::api::CpuLimits {
|
||||
crate::api::CpuLimits {
|
||||
clock_min_limits: None,
|
||||
clock_max_limits: None,
|
||||
clock_step: 100,
|
||||
governors: vec![], // TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<CpuJson> for Cpu {
|
||||
#[inline]
|
||||
fn into(self) -> CpuJson {
|
||||
CpuJson {
|
||||
online: self.online,
|
||||
clock_limits: None,
|
||||
governor: self.governor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OnSet for Cpu {
|
||||
fn on_set(&mut self) -> Result<(), SettingError> {
|
||||
//self.clamp_all();
|
||||
self.set_all()
|
||||
}
|
||||
}
|
||||
|
||||
impl OnResume for Cpu {
|
||||
fn on_resume(&self) -> Result<(), SettingError> {
|
||||
let mut copy = self.clone();
|
||||
copy.state.is_resuming = true;
|
||||
copy.set_all()
|
||||
}
|
||||
}
|
||||
|
||||
impl TCpu for Cpu {
|
||||
fn online(&mut self) -> &mut bool {
|
||||
&mut self.online
|
||||
}
|
||||
|
||||
fn governor(&mut self, governor: String) {
|
||||
self.governor = governor;
|
||||
}
|
||||
|
||||
fn get_governor(&self) -> &'_ str {
|
||||
&self.governor
|
||||
}
|
||||
|
||||
fn clock_limits(&mut self, _limits: Option<MinMax<u64>>) {
|
||||
}
|
||||
|
||||
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cpu_online_path(index: usize) -> String {
|
||||
format!("/sys/devices/system/cpu/cpu{}/online", index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cpu_governor_path(index: usize) -> String {
|
||||
format!(
|
||||
"/sys/devices/system/cpu/cpu{}/cpufreq/scaling_governor",
|
||||
index
|
||||
)
|
||||
}
|
89
backend/src/settings/generic/gpu.rs
Normal file
89
backend/src/settings/generic/gpu.rs
Normal file
|
@ -0,0 +1,89 @@
|
|||
use std::convert::Into;
|
||||
|
||||
use crate::settings::MinMax;
|
||||
use crate::settings::{OnResume, OnSet, SettingError};
|
||||
use crate::settings::TGpu;
|
||||
use crate::persist::GpuJson;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Gpu {
|
||||
slow_memory: bool, // ignored
|
||||
}
|
||||
|
||||
impl Gpu {
|
||||
#[inline]
|
||||
pub fn from_json(_other: GpuJson, _version: u64) -> Self {
|
||||
Self {
|
||||
slow_memory: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn system_default() -> Self {
|
||||
Self {
|
||||
slow_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<GpuJson> for Gpu {
|
||||
#[inline]
|
||||
fn into(self) -> GpuJson {
|
||||
GpuJson {
|
||||
fast_ppt: None,
|
||||
slow_ppt: None,
|
||||
clock_limits: None,
|
||||
slow_memory: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OnSet for Gpu {
|
||||
fn on_set(&mut self) -> Result<(), SettingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OnResume for Gpu {
|
||||
fn on_resume(&self) -> Result<(), SettingError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TGpu for Gpu {
|
||||
fn limits(&self) -> crate::api::GpuLimits {
|
||||
crate::api::GpuLimits {
|
||||
fast_ppt_limits: None,
|
||||
slow_ppt_limits: None,
|
||||
ppt_step: 1_000_000,
|
||||
tdp_limits: None,
|
||||
tdp_boost_limits: None,
|
||||
tdp_step: 42,
|
||||
clock_min_limits: None,
|
||||
clock_max_limits: None,
|
||||
clock_step: 100,
|
||||
memory_control_capable: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn json(&self) -> crate::persist::GpuJson {
|
||||
self.clone().into()
|
||||
}
|
||||
|
||||
fn ppt(&mut self, _fast: Option<u64>, _slow: Option<u64>) {
|
||||
}
|
||||
|
||||
fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
|
||||
(None, None)
|
||||
}
|
||||
|
||||
fn clock_limits(&mut self, _limits: Option<MinMax<u64>>) {
|
||||
}
|
||||
|
||||
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn slow_memory(&mut self) -> &mut bool {
|
||||
&mut self.slow_memory
|
||||
}
|
||||
}
|
7
backend/src/settings/generic/mod.rs
Normal file
7
backend/src/settings/generic/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
mod battery;
|
||||
mod cpu;
|
||||
mod gpu;
|
||||
|
||||
pub use battery::Battery;
|
||||
pub use cpu::{Cpu, Cpus};
|
||||
pub use gpu::Gpu;
|
|
@ -4,6 +4,7 @@ mod general;
|
|||
mod min_max;
|
||||
mod traits;
|
||||
|
||||
pub mod generic;
|
||||
pub mod steam_deck;
|
||||
pub mod steam_deck_adv;
|
||||
pub mod unknown;
|
||||
|
|
Loading…
Reference in a new issue