mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-01-22 17:33:19 +01:00
376 lines
11 KiB
Rust
376 lines
11 KiB
Rust
use crate::{config::Config, error::RogError, GetSupported};
|
|
use crate::{task_watch_item, CtrlTask};
|
|
use async_trait::async_trait;
|
|
use log::{info, warn};
|
|
use rog_platform::platform::{AsusPlatform, GpuMode};
|
|
use rog_platform::supported::RogBiosSupportedFunctions;
|
|
use std::fs::OpenOptions;
|
|
use std::io::{Read, Write};
|
|
use std::path::Path;
|
|
use std::process::Command;
|
|
use std::sync::Arc;
|
|
use zbus::export::futures_util::lock::Mutex;
|
|
use zbus::Connection;
|
|
use zbus::{dbus_interface, SignalContext};
|
|
|
|
const ZBUS_PATH: &str = "/org/asuslinux/Platform";
|
|
const ASUS_POST_LOGO_SOUND: &str =
|
|
"/sys/firmware/efi/efivars/AsusPostLogoSound-607005d5-3f75-4b2e-98f0-85ba66797a3e";
|
|
|
|
#[derive(Clone)]
|
|
pub struct CtrlPlatform {
|
|
platform: AsusPlatform,
|
|
config: Arc<Mutex<Config>>,
|
|
}
|
|
|
|
impl GetSupported for CtrlPlatform {
|
|
type A = RogBiosSupportedFunctions;
|
|
|
|
fn get_supported() -> Self::A {
|
|
let mut panel_overdrive = false;
|
|
let mut dgpu_disable = false;
|
|
let mut egpu_enable = false;
|
|
let mut gpu_mux = false;
|
|
|
|
if let Ok(platform) = AsusPlatform::new() {
|
|
panel_overdrive = platform.has_panel_od();
|
|
dgpu_disable = platform.has_dgpu_disable();
|
|
egpu_enable = platform.has_egpu_enable();
|
|
gpu_mux = platform.has_gpu_mux_mode();
|
|
}
|
|
|
|
RogBiosSupportedFunctions {
|
|
post_sound: Path::new(ASUS_POST_LOGO_SOUND).exists(),
|
|
gpu_mux,
|
|
panel_overdrive,
|
|
dgpu_disable,
|
|
egpu_enable,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CtrlPlatform {
|
|
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
|
let platform = AsusPlatform::new()?;
|
|
|
|
if !platform.has_gpu_mux_mode() {
|
|
info!("G-Sync Switchable Graphics or GPU MUX not detected");
|
|
info!("Standard graphics switching will still work.");
|
|
}
|
|
|
|
if Path::new(ASUS_POST_LOGO_SOUND).exists() {
|
|
CtrlPlatform::set_path_mutable(ASUS_POST_LOGO_SOUND)?;
|
|
} else {
|
|
info!("Switch for POST boot sound not detected");
|
|
}
|
|
|
|
Ok(CtrlPlatform { platform, config })
|
|
}
|
|
|
|
fn set_path_mutable(path: &str) -> Result<(), RogError> {
|
|
let output = Command::new("/usr/bin/chattr")
|
|
.arg("-i")
|
|
.arg(path)
|
|
.output()
|
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
|
info!("Set {} writeable: status: {}", path, output.status);
|
|
Ok(())
|
|
}
|
|
|
|
fn set_gfx_mode(&self, mode: GpuMode) -> Result<(), RogError> {
|
|
self.platform.set_gpu_mux_mode(mode.to_mux_attr())?;
|
|
// self.update_initramfs(enable)?;
|
|
if mode == GpuMode::Discrete {
|
|
info!("Set system-level graphics mode: Dedicated Nvidia");
|
|
} else {
|
|
info!("Set system-level graphics mode: Optimus");
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn get_boot_sound() -> Result<i8, RogError> {
|
|
let path = ASUS_POST_LOGO_SOUND;
|
|
let mut file = OpenOptions::new()
|
|
.read(true)
|
|
.open(path)
|
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
|
|
|
let mut data = Vec::new();
|
|
file.read_to_end(&mut data)
|
|
.map_err(|err| RogError::Read(path.into(), err))?;
|
|
|
|
let idx = data.len() - 1;
|
|
Ok(data[idx] as i8)
|
|
}
|
|
|
|
pub(super) fn set_boot_sound(on: bool) -> Result<(), RogError> {
|
|
let path = ASUS_POST_LOGO_SOUND;
|
|
let mut file = OpenOptions::new()
|
|
.read(true)
|
|
.write(true)
|
|
.open(path)
|
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
|
|
|
let mut data = Vec::new();
|
|
file.read_to_end(&mut data)
|
|
.map_err(|err| RogError::Read(path.into(), err))?;
|
|
|
|
let idx = data.len() - 1;
|
|
if on {
|
|
data[idx] = 1;
|
|
info!("Set boot POST sound on");
|
|
} else {
|
|
data[idx] = 0;
|
|
info!("Set boot POST sound off");
|
|
}
|
|
file.write_all(&data)
|
|
.map_err(|err| RogError::Path(path.into(), err))?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn set_panel_overdrive(&self, enable: bool) -> Result<(), RogError> {
|
|
self.platform.set_panel_od(enable).map_err(|err| {
|
|
warn!("CtrlRogBios: set_panel_overdrive {}", err);
|
|
err
|
|
})?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
|
impl CtrlPlatform {
|
|
async fn set_gpu_mux_mode(
|
|
&mut self,
|
|
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
|
mode: GpuMode,
|
|
) {
|
|
self.set_gfx_mode(mode)
|
|
.map_err(|err| {
|
|
warn!("CtrlRogBios: set_gpu_mux_mode {}", err);
|
|
err
|
|
})
|
|
.ok();
|
|
Self::notify_gpu_mux_mode(&ctxt, mode).await.ok();
|
|
}
|
|
|
|
fn gpu_mux_mode(&self) -> GpuMode {
|
|
match self.platform.get_gpu_mux_mode() {
|
|
Ok(m) => GpuMode::from_mux(m as u8),
|
|
Err(e) => {
|
|
warn!("CtrlRogBios: get_gfx_mode {}", e);
|
|
GpuMode::Error
|
|
}
|
|
}
|
|
}
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn notify_gpu_mux_mode(
|
|
signal_ctxt: &SignalContext<'_>,
|
|
mode: GpuMode,
|
|
) -> zbus::Result<()> {
|
|
}
|
|
|
|
async fn set_post_boot_sound(
|
|
&mut self,
|
|
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
|
on: bool,
|
|
) {
|
|
Self::set_boot_sound(on)
|
|
.map_err(|err| {
|
|
warn!("CtrlRogBios: set_post_boot_sound {}", err);
|
|
err
|
|
})
|
|
.ok();
|
|
Self::notify_post_boot_sound(&ctxt, on).await.ok();
|
|
}
|
|
|
|
fn post_boot_sound(&self) -> i8 {
|
|
Self::get_boot_sound()
|
|
.map_err(|err| {
|
|
warn!("CtrlRogBios: get_boot_sound {}", err);
|
|
err
|
|
})
|
|
.unwrap_or(-1)
|
|
}
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn notify_post_boot_sound(ctxt: &SignalContext<'_>, on: bool) -> zbus::Result<()> {}
|
|
|
|
async fn set_panel_od(
|
|
&mut self,
|
|
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
|
overdrive: bool,
|
|
) {
|
|
match self.platform.set_panel_od(overdrive) {
|
|
Ok(_) => {
|
|
if let Some(mut lock) = self.config.try_lock() {
|
|
lock.panel_od = overdrive;
|
|
lock.write();
|
|
}
|
|
Self::notify_panel_od(&ctxt, overdrive).await.ok();
|
|
}
|
|
Err(err) => warn!("CtrlRogBios: set_panel_overdrive {}", err),
|
|
};
|
|
}
|
|
|
|
/// Get the `panel_od` value from platform. Updates the stored value in internal config also.
|
|
fn panel_od(&self) -> bool {
|
|
let od = self
|
|
.platform
|
|
.get_panel_od()
|
|
.map_err(|err| {
|
|
warn!("CtrlRogBios: get_panel_od {}", err);
|
|
err
|
|
})
|
|
.unwrap_or(false);
|
|
if let Some(mut lock) = self.config.try_lock() {
|
|
lock.panel_od = od;
|
|
lock.write();
|
|
}
|
|
od
|
|
}
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn notify_panel_od(signal_ctxt: &SignalContext<'_>, overdrive: bool) -> zbus::Result<()> {
|
|
}
|
|
|
|
async fn set_dgpu_disable(
|
|
&mut self,
|
|
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
|
disable: bool,
|
|
) {
|
|
match self.platform.set_dgpu_disable(disable) {
|
|
Ok(_) => {
|
|
Self::notify_dgpu_disable(&ctxt, disable).await.ok();
|
|
}
|
|
Err(err) => warn!("CtrlRogBios: set_dgpu_disable {}", err),
|
|
};
|
|
}
|
|
|
|
fn dgpu_disable(&self) -> bool {
|
|
self.platform
|
|
.get_dgpu_disable()
|
|
.map_err(|err| {
|
|
warn!("CtrlRogBios: get_dgpu_disable {}", err);
|
|
err
|
|
})
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn notify_dgpu_disable(
|
|
signal_ctxt: &SignalContext<'_>,
|
|
disable: bool,
|
|
) -> zbus::Result<()> {
|
|
}
|
|
|
|
async fn set_egpu_enable(
|
|
&mut self,
|
|
#[zbus(signal_context)] ctxt: SignalContext<'_>,
|
|
enable: bool,
|
|
) {
|
|
match self.platform.set_egpu_enable(enable) {
|
|
Ok(_) => {
|
|
Self::notify_egpu_enable(&ctxt, enable).await.ok();
|
|
}
|
|
Err(err) => warn!("CtrlRogBios: set_egpu_enable {}", err),
|
|
};
|
|
}
|
|
|
|
fn egpu_enable(&self) -> bool {
|
|
self.platform
|
|
.get_egpu_enable()
|
|
.map_err(|err| {
|
|
warn!("CtrlRogBios: get_egpu_enable {}", err);
|
|
err
|
|
})
|
|
.unwrap_or(false)
|
|
}
|
|
|
|
#[dbus_interface(signal)]
|
|
async fn notify_egpu_enable(signal_ctxt: &SignalContext<'_>, enable: bool) -> zbus::Result<()> {
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl crate::ZbusRun for CtrlPlatform {
|
|
async fn add_to_server(self, server: &mut Connection) {
|
|
Self::add_to_server_helper(self, "/org/asuslinux/Platform", server).await;
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
impl crate::Reloadable for CtrlPlatform {
|
|
async fn reload(&mut self) -> Result<(), RogError> {
|
|
if self.platform.has_panel_od() {
|
|
let p = if let Some(lock) = self.config.try_lock() {
|
|
lock.panel_od
|
|
} else {
|
|
false
|
|
};
|
|
self.set_panel_overdrive(p)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl CtrlPlatform {
|
|
task_watch_item!(panel_od platform);
|
|
task_watch_item!(dgpu_disable platform);
|
|
task_watch_item!(egpu_enable platform);
|
|
task_watch_item!(gpu_mux_mode platform);
|
|
}
|
|
|
|
#[async_trait]
|
|
impl CtrlTask for CtrlPlatform {
|
|
fn zbus_path() -> &'static str {
|
|
ZBUS_PATH
|
|
}
|
|
|
|
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
|
let platform1 = self.clone();
|
|
let platform2 = self.clone();
|
|
self.create_sys_event_tasks(
|
|
move || {},
|
|
move || {
|
|
info!("CtrlRogBios reloading panel_od");
|
|
if let Some(lock) = platform1.config.try_lock() {
|
|
if platform1.platform.has_panel_od() {
|
|
platform1
|
|
.set_panel_overdrive(lock.panel_od)
|
|
.map_err(|err| {
|
|
warn!("CtrlCharge: set_limit {}", err);
|
|
err
|
|
})
|
|
.ok();
|
|
}
|
|
}
|
|
},
|
|
move || {},
|
|
move || {
|
|
info!("CtrlRogBios reloading panel_od");
|
|
if let Some(lock) = platform2.config.try_lock() {
|
|
if platform2.platform.has_panel_od() {
|
|
platform2
|
|
.set_panel_overdrive(lock.panel_od)
|
|
.map_err(|err| {
|
|
warn!("CtrlCharge: set_limit {}", err);
|
|
err
|
|
})
|
|
.ok();
|
|
}
|
|
}
|
|
},
|
|
)
|
|
.await;
|
|
|
|
self.watch_panel_od(signal_ctxt.clone()).await?;
|
|
self.watch_dgpu_disable(signal_ctxt.clone()).await?;
|
|
self.watch_egpu_enable(signal_ctxt.clone()).await?;
|
|
self.watch_gpu_mux_mode(signal_ctxt.clone()).await?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|