mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
116 lines
4.4 KiB
Rust
116 lines
4.4 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use log::{info, warn};
|
|
|
|
use crate::error::{PlatformError, Result};
|
|
use crate::{attr_num, to_device};
|
|
|
|
/// The "platform" device provides access to things like:
|
|
/// - `dgpu_disable`
|
|
/// - `egpu_enable`
|
|
/// - `panel_od`
|
|
/// - `gpu_mux`
|
|
/// - `keyboard_mode`, set keyboard RGB mode and speed
|
|
/// - `keyboard_state`, set keyboard power states
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone)]
|
|
pub struct AsusPower {
|
|
mains: PathBuf,
|
|
battery: PathBuf,
|
|
usb: Option<PathBuf>,
|
|
}
|
|
|
|
impl AsusPower {
|
|
attr_num!("charge_control_end_threshold", battery, u8);
|
|
|
|
attr_num!("online", mains, u8);
|
|
|
|
/// When checking for battery this will look in order:
|
|
/// - if attr `manufacturer` contains `asus`
|
|
/// - if attr `charge_control_end_threshold` exists and `energy_full_design`
|
|
/// >= 50 watt
|
|
/// - if syspath end conatins `BAT`
|
|
/// - if attr `type` is `battery` (last resort)
|
|
pub fn new() -> Result<Self> {
|
|
let mut mains = PathBuf::new();
|
|
let mut battery = None;
|
|
let mut usb = None;
|
|
|
|
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
|
warn!("{}", err);
|
|
PlatformError::Udev("enumerator failed".into(), err)
|
|
})?;
|
|
enumerator.match_subsystem("power_supply").map_err(|err| {
|
|
warn!("{}", err);
|
|
PlatformError::Udev("match_subsystem failed".into(), err)
|
|
})?;
|
|
|
|
for device in enumerator.scan_devices().map_err(|err| {
|
|
warn!("{}", err);
|
|
PlatformError::Udev("scan_devices failed".into(), err)
|
|
})? {
|
|
if let Some(attr) = device.attribute_value("type") {
|
|
info!("Power: Checking {:?}", device.syspath());
|
|
match attr.to_string_lossy().to_ascii_lowercase().trim() {
|
|
"mains" => {
|
|
info!("Found mains power at {:?}", device.sysname());
|
|
mains = device.syspath().to_path_buf();
|
|
}
|
|
"battery" => {
|
|
// Priortised list of checks
|
|
info!("Found a battery");
|
|
if battery.is_none() {
|
|
info!("Checking battery attributes");
|
|
if let Some(current) =
|
|
device.attribute_value("charge_control_end_threshold")
|
|
{
|
|
info!(
|
|
"Found battery power at {:?}, matched \
|
|
charge_control_end_threshold. Current level: {current:?}",
|
|
device.sysname()
|
|
);
|
|
battery = Some(device.syspath().to_path_buf());
|
|
} else if device.sysname().to_string_lossy().starts_with("BAT") {
|
|
info!(
|
|
"Found battery power at {:?}, sysfs path ended with BAT<n>",
|
|
device.sysname()
|
|
);
|
|
battery = Some(device.syspath().to_path_buf());
|
|
} else {
|
|
info!(
|
|
"Last resort: Found battery power at {:?} using type = Battery",
|
|
device.sysname()
|
|
);
|
|
battery = Some(device.syspath().to_path_buf());
|
|
}
|
|
}
|
|
}
|
|
"usb" => {
|
|
info!("Found USB-C power at {:?}", device.sysname());
|
|
usb = Some(device.syspath().to_path_buf());
|
|
}
|
|
_ => {}
|
|
};
|
|
}
|
|
}
|
|
|
|
if let Some(battery) = battery {
|
|
return Ok(Self {
|
|
mains,
|
|
battery,
|
|
usb,
|
|
});
|
|
}
|
|
|
|
// No battery found. Return an AsusPower with an empty battery path so
|
|
// callers can still be constructed and query `has_*` methods which
|
|
// will correctly report absence. This avoids hard-failing on systems
|
|
// where the asus-nb-wmi driver loads on desktops with no battery.
|
|
info!("Did not find a battery, continuing without battery support");
|
|
Ok(Self {
|
|
mains,
|
|
battery: PathBuf::new(),
|
|
usb,
|
|
})
|
|
}
|
|
}
|