Major update to supergfx and others

This commit is contained in:
Luke D. Jones
2021-08-26 11:43:47 +12:00
parent 60b7f3be69
commit 498e604531
33 changed files with 535 additions and 278 deletions

15
Cargo.lock generated
View File

@@ -40,6 +40,7 @@ dependencies = [
"rog_types",
"serde_json",
"supergfxctl",
"zbus",
]
[[package]]
@@ -57,7 +58,7 @@ dependencies = [
"rog_types",
"supergfxctl",
"tinybmp",
"yansi-term",
"zbus",
]
[[package]]
@@ -221,7 +222,6 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"supergfxctl",
"sysfs-class",
"toml",
"udev",
@@ -1070,6 +1070,8 @@ dependencies = [
name = "supergfxctl"
version = "1.1.0"
dependencies = [
"env_logger",
"gumdrop",
"log",
"logind-zbus",
"serde",
@@ -1314,15 +1316,6 @@ dependencies = [
"bitflags 0.9.1",
]
[[package]]
name = "yansi-term"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
dependencies = [
"winapi",
]
[[package]]
name = "zbus"
version = "1.9.1"

View File

@@ -15,6 +15,8 @@ BIN_C := asusctl
BIN_D := asusd
BIN_U := asusd-user
BIN_N := asus-notify
BIN_SD := supergfxd
BIN_SC := supergfxctl
LEDCFG := asusd-ledmodes.toml
X11CFG := 90-nvidia-screen-G05.conf
PMRULES := 90-asusd-nvidia-pm.rules
@@ -45,14 +47,15 @@ install:
$(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
$(INSTALL_DATA) "./data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
$(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
$(INSTALL_DATA) "./data/$(LEDCFG)" "$(DESTDIR)/etc/asusd/$(LEDCFG)"
$(INSTALL_DATA) "./data/$(BIN_D).conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
$(INSTALL_DATA) "./data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
$(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
$(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
$(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service"
$(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
$(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
$(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
@@ -63,10 +66,18 @@ install:
$(INSTALL_DATA) "./data/icons/scalable/gpu-nvidia.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-nvidia.svg"
$(INSTALL_DATA) "./data/icons/scalable/gpu-vfio.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-vfio.svg"
$(INSTALL_DATA) "./data/icons/scalable/notification-reboot.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/notification-reboot.svg"
$(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl"
$(INSTALL_DATA) "./data/completions/asusctl.fish" "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
cd data && find "./anime" -type f -exec install -Dm 755 "{}" "$(DESTDIR)$(datarootdir)/asusd/{}" \;
$(INSTALL_PROGRAM) "./target/release/$(BIN_SD)" "$(DESTDIR)$(bindir)/$(BIN_SD)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_SC)" "$(DESTDIR)$(bindir)/$(BIN_SC)"
$(INSTALL_DATA) "./supergfx/data/$(BIN_SD).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_SD).service"
$(INSTALL_DATA) "./supergfx/data/org.supergfxctl.Daemon.conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/org.supergfxctl.Daemon.conf"
$(INSTALL_DATA) "./supergfx/data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
$(INSTALL_DATA) "./supergfx/data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
@@ -90,6 +101,10 @@ uninstall:
rm -f "$(DESTDIR)$(zshcpl)/_asusctl"
rm -f "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
rm -rf "$(DESTDIR)$(datarootdir)/asusd"
rm -f "$(DESTDIR)$(bindir)/$(BIN_SC)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_SD)"
rm -f "$(DESTDIR)$(libdir)/systemd/system/$(BIN_SD).service"
rm -f "$(DESTDIR)$(datarootdir)/dbus-1/system.d/org.supergfxctl.Daemon.conf"
update:
cargo update

View File

@@ -7,6 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
zbus = "^1.9"
# serialisation
serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" }

View File

@@ -2,11 +2,14 @@ use notify_rust::{Hint, Notification, NotificationHandle};
use rog_aura::AuraEffect;
use rog_dbus::{DbusProxies, Signals};
use rog_profiles::Profile;
use supergfxctl::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use std::error::Error;
use std::process;
use std::sync::mpsc::channel;
use std::thread::sleep;
use std::time::Duration;
use std::{process, thread};
use supergfxctl::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use supergfxctl::zbus_proxy::GfxProxy;
use zbus::Connection;
const NOTIF_HEADER: &str = "ROG Control";
@@ -42,6 +45,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let recv = proxies.setup_recv(conn);
let mut err_count = 0;
gfx_thread()?;
loop {
sleep(Duration::from_millis(100));
if let Err(err) = recv.next_signal() {
@@ -67,23 +73,57 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if let Ok(data) = signals.charge.try_recv() {
notify!(do_charge_notif, last_notification, &data);
}
if let Ok(data) = signals.gfx_vendor.try_recv() {
}
}
fn gfx_thread() -> Result<(), Box<dyn std::error::Error>> {
let mut last_notification: Option<NotificationHandle> = None;
let conn = Connection::new_system()?;
let proxy = GfxProxy::new(&conn)?;
let (tx1, rx1) = channel();
proxy.connect_notify_gfx(tx1)?;
let (tx2, rx2) = channel();
proxy.connect_notify_action(tx2)?;
thread::spawn(move || loop {
if proxy
.next_signal()
.map_err(|e| println!("Error: {}", e))
.is_err()
{
break;
}
if let Ok(data) = rx1.try_recv() {
notify!(do_gfx_notif, last_notification, &data);
}
if let Ok(data) = signals.gfx_action.try_recv() {
if let Ok(data) = rx2.try_recv() {
match data {
GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => {
do_gfx_action_notif(&data)?;
do_gfx_action_notif(&data)
.map_err(|e| {
println!("Error: {}", e);
})
.ok();
}
GfxRequiredUserAction::Integrated => {
base_notification!(
"You must be in integrated mode first to switch to the requested mode"
)?;
)
.map_err(|e| {
println!("Error: {}", e);
})
.ok();
}
GfxRequiredUserAction::None => {}
}
}
}
});
Ok(())
}
fn do_thermal_notif(profile: &Profile) -> Result<NotificationHandle, Box<dyn Error>> {

View File

@@ -7,6 +7,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
zbus = "^1.9.1"
rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" }
rog_dbus = { path = "../rog-dbus" }
@@ -14,7 +15,6 @@ rog_profiles = { path = "../rog-profiles" }
rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" }
gumdrop = "^0.8"
yansi-term = "^0.1"
supergfxctl = { path = "../supergfx" }
[dev-dependencies]

View File

@@ -9,16 +9,17 @@ use profiles_cli::ProfileCommand;
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN};
use rog_aura::{self, AuraEffect};
use rog_dbus::RogDbusClient;
use rog_types::{
supported::{
AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions,
RogBiosSupportedFunctions,
},
use rog_types::supported::{
AnimeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions,
RogBiosSupportedFunctions,
};
use supergfxctl::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
use std::{env::args, path::Path};
use yansi_term::Colour::Green;
use yansi_term::Colour::Red;
use std::{env::args, path::Path, sync::mpsc::channel};
use supergfxctl::{
gfx_vendors::{GfxRequiredUserAction, GfxVendors},
special::{get_asus_gsync_gfx_mode, has_asus_gsync_gfx_mode},
zbus_proxy::GfxProxy,
};
use zbus::Connection;
#[derive(Default, Options)]
struct CliStart {
@@ -152,7 +153,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
match parsed.command {
Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?,
Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.platform_profile, &cmd)?,
Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, &supported.rog_bios_ctrl, cmd)?,
Some(CliCommand::Graphics(cmd)) => do_gfx(cmd)?,
Some(CliCommand::Anime(cmd)) => handle_anime(&dbus, &supported.anime_ctrl, &cmd)?,
Some(CliCommand::Bios(cmd)) => handle_bios_option(&dbus, &supported.rog_bios_ctrl, &cmd)?,
None => {
@@ -190,62 +191,67 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
}
fn do_gfx(
dbus: &RogDbusClient,
supported: &RogBiosSupportedFunctions,
command: GraphicsCommand,
) -> Result<(), Box<dyn std::error::Error>> {
fn do_gfx(command: GraphicsCommand) -> Result<(), Box<dyn std::error::Error>> {
if command.mode.is_none() && !command.get && !command.pow && !command.force || command.help {
println!("{}", command.self_usage());
}
let conn = Connection::new_system()?;
let proxy = GfxProxy::new(&conn)?;
let (tx, rx) = channel();
proxy.connect_notify_action(tx)?;
if let Some(mode) = command.mode {
if supported.dedicated_gfx_toggle && dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 {
if has_asus_gsync_gfx_mode() && get_asus_gsync_gfx_mode()? == 1 {
println!("You can not change modes until you turn dedicated/G-Sync off and reboot");
std::process::exit(-1);
}
println!("If anything fails check `journalctl -b -u asusd`\n");
dbus.proxies().gfx().gfx_write_mode(&mode).map_err(|err|{
proxy.gfx_write_mode(&mode).map_err(|err|{
println!("Graphics mode change error. You may be in an invalid state.");
println!("Check mode with `asusctl graphics -g` and switch to opposite\nmode to correct it, e.g: if integrated, switch to hybrid, or if nvidia, switch to integrated.\n");
err
})?;
let res = dbus.gfx_wait_changed()?;
match res {
GfxRequiredUserAction::Integrated => {
println!(
"You must change to Integrated before you can change to {}",
<&str>::from(mode)
);
}
GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => {
println!(
"Graphics mode changed to {}. User action required is: {}",
<&str>::from(mode),
<&str>::from(&res)
);
}
GfxRequiredUserAction::None => {
println!("Graphics mode changed to {}", <&str>::from(mode));
loop {
proxy.next_signal()?;
if let Ok(res) = rx.try_recv() {
match res {
GfxRequiredUserAction::Integrated => {
println!(
"You must change to Integrated before you can change to {}",
<&str>::from(mode)
);
}
GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => {
println!(
"Graphics mode changed to {}. User action required is: {}",
<&str>::from(mode),
<&str>::from(&res)
);
}
GfxRequiredUserAction::None => {
println!("Graphics mode changed to {}", <&str>::from(mode));
}
}
}
std::process::exit(0)
}
std::process::exit(0)
}
if command.get {
let res = dbus.proxies().gfx().gfx_get_mode()?;
let res = proxy.gfx_get_mode()?;
println!("Current graphics mode: {}", <&str>::from(res));
}
if command.pow {
let res = dbus.proxies().gfx().gfx_get_pwr()?;
match res {
GfxPower::Active => {
println!("Current power status: {}", Red.paint(<&str>::from(&res)))
}
_ => println!("Current power status: {}", Green.paint(<&str>::from(&res))),
}
let res = proxy.gfx_get_pwr()?;
println!("Current power status: {}", <&str>::from(&res));
}
Ok(())
}

View File

@@ -23,7 +23,6 @@ rog_aura = { path = "../rog-aura" }
rog_types = { path = "../rog-types" }
rog_profiles = { path = "../rog-profiles" }
rog_dbus = { path = "../rog-dbus" }
supergfxctl = { path = "../supergfx" }
rusb = "^0.8"
udev = "^0.6"

View File

@@ -3,7 +3,6 @@ use serde_derive::{Deserialize, Serialize};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use crate::config_old::*;
use crate::VERSION;
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
@@ -36,9 +35,6 @@ impl Config {
config = Self::new();
} else if let Ok(data) = serde_json::from_str(&buf) {
config = data;
} else if let Ok(data) = serde_json::from_str::<ConfigV352>(&buf) {
config = data.into_current();
info!("Updated config version to: {}", VERSION);
} else {
warn!("Could not deserialise {}", CONFIG_PATH);
panic!("Please remove {} then restart asusd", CONFIG_PATH);

View File

@@ -1,53 +0,0 @@
use serde_derive::{Deserialize, Serialize};
use supergfxctl::gfx_vendors::GfxVendors;
use std::collections::BTreeMap;
use crate::config::Config;
#[derive(Deserialize, Serialize)]
pub struct ConfigV352 {
pub gfx_mode: GfxVendors,
pub gfx_last_mode: GfxVendors,
pub gfx_managed: bool,
pub gfx_vfio_enable: bool,
pub gfx_save_compute_vfio: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub power_profiles: BTreeMap<String, ProfileV317>,
}
impl ConfigV352 {
pub(crate) fn into_current(self) -> Config {
Config {
bat_charge_limit: self.bat_charge_limit,
}
}
}
#[derive(Deserialize, Serialize)]
pub struct ConfigV372 {
pub gfx_mode: GfxVendors,
/// Only for informational purposes.
#[serde(skip)]
pub gfx_tmp_mode: Option<GfxVendors>,
pub gfx_managed: bool,
pub gfx_vfio_enable: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub power_profiles: BTreeMap<String, ProfileV317>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ProfileV317 {
pub min_percentage: u8,
pub max_percentage: u8,
pub turbo: bool,
pub fan_preset: u8,
pub fan_curve: Option<()>,
}

View File

@@ -40,19 +40,23 @@ impl GetSupported for CtrlPlatformProfile {
fn get_supported() -> Self::A {
if !Profile::is_platform_profile_supported() {
warn!(r#"
warn!(
r#"
platform_profile kernel interface not found, your laptop does not support this, or the iterface is missing.
To enable profile support you require a kernel with the following patch applied:
https://lkml.org/lkml/2021/8/18/1022
"#);
"#
);
}
if !FanCurves::is_fan_curves_supported() {
info!(r#"
info!(
r#"
fan curves kernel interface not found, your laptop does not support this, or the iterface is missing.
To enable fan-curve support you require a kernel with the following patch applied:
https://lkml.org/lkml/2021/8/20/232
Please note that as of 24/08/2021 this is not final.
"#);
"#
);
}
PlatformProfileFunctions {
platform_profile: Profile::is_platform_profile_supported(),

View File

@@ -1,5 +1,6 @@
use daemon::ctrl_anime::config::AnimeConfig;
use daemon::ctrl_anime::zbus::CtrlAnimeZbus;
use daemon::ctrl_anime::*;
use daemon::ctrl_aura::config::AuraConfig;
use daemon::ctrl_aura::controller::{
CtrlKbdLed, CtrlKbdLedReloader, CtrlKbdLedTask, CtrlKbdLedZbus,
@@ -10,15 +11,11 @@ use daemon::ctrl_profiles::controller::CtrlPlatformTask;
use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
};
use daemon::{ctrl_anime::*};
use daemon::{
ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus},
laptops::LaptopLedData,
};
use supergfxctl::config::GfxConfig;
use supergfxctl::controller::CtrlGraphics;
use supergfxctl::gfx_vendors::GfxVendors;
use ::zbus::{fdo, Connection, ObjectServer};
use daemon::{CtrlTask, Reloadable, ZbusAdd};
use log::LevelFilter;
@@ -34,7 +31,6 @@ use daemon::ctrl_rog_bios::CtrlRogBios;
use zvariant::ObjectPath;
static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf";
static GFX_CONFIG_PATH: &str = "/etc/asusd/supergfx.conf";
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
@@ -86,10 +82,6 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
let config = Config::load();
let config = Arc::new(Mutex::new(config));
let gfx_config = GfxConfig::load(GFX_CONFIG_PATH.into());
let enable_gfx_switching = gfx_config.gfx_managed;
let gfx_config = Arc::new(Mutex::new(gfx_config));
supported.add_to_server(&mut object_server);
match CtrlRogBios::new(config.clone()) {
@@ -105,7 +97,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
match CtrlCharge::new(config.clone()) {
match CtrlCharge::new(config) {
Ok(mut ctrl) => {
// Do a reload of any settings
ctrl.reload()
@@ -173,48 +165,6 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
// Graphics switching requires some checks on boot specifically for g-sync capable laptops
if enable_gfx_switching {
match CtrlGraphics::new(gfx_config.clone()) {
Ok(mut ctrl) => {
// Need to check if a laptop has the dedicated gfx switch
if CtrlRogBios::has_dedicated_gfx_toggle() {
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
if let Ok(config) = gfx_config.lock() {
if ded == 1 {
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
let devices = ctrl.devices();
let bus = ctrl.bus();
CtrlGraphics::do_mode_setup_tasks(
GfxVendors::Nvidia,
false,
&devices,
&bus,
)?;
} else if ded == 0 {
info!("Dedicated GFX toggle is off");
let devices = ctrl.devices();
let bus = ctrl.bus();
CtrlGraphics::do_mode_setup_tasks(
config.gfx_mode,
false,
&devices,
&bus,
)?;
}
}
}
}
ctrl.reload()
.unwrap_or_else(|err| error!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
}
}
}
// TODO: implement messaging between threads to check fails
// Run tasks

View File

@@ -1,6 +1,4 @@
use rog_profiles::error::ProfileError;
use rog_types::error::GraphicsError;
use supergfxctl::error::GfxError;
use std::convert::From;
use std::fmt;
@@ -19,7 +17,6 @@ pub enum RogError {
MissingFunction(String),
MissingLedBrightNode(String, std::io::Error),
ReloadFail(String),
GfxSwitching(GfxError),
Profiles(ProfileError),
Initramfs(String),
Modprobe(String),
@@ -44,7 +41,6 @@ impl fmt::Display for RogError {
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error),
RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets),
RogError::GfxSwitching(deets) => write!(f, "Graphics switching error: {}", deets),
RogError::Profiles(deets) => write!(f, "Profile error: {}", deets),
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
@@ -56,15 +52,6 @@ impl fmt::Display for RogError {
impl std::error::Error for RogError {}
impl From<GraphicsError> for RogError {
fn from(err: GraphicsError) -> Self {
match err {
GraphicsError::ParseVendor => RogError::GfxSwitching(GfxError::ParseVendor),
GraphicsError::ParsePower => RogError::GfxSwitching(GfxError::ParsePower),
}
}
}
impl From<ProfileError> for RogError {
fn from(err: ProfileError) -> Self {
RogError::Profiles(err)

View File

@@ -1,7 +1,6 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
pub(crate) mod config_old;
/// Control of AniMe matrix display
pub mod ctrl_anime;
/// Keyboard LED brightness control, RGB, and LED display modes

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
data/anime/asus/music/Diamond.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
data/anime/asus/trend/Hero.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -1,10 +1,10 @@
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
pub static DBUS_NAME_GFX: &str = "org.supergfxctl.Daemon";
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
pub mod zbus_anime;
pub mod zbus_charge;
pub mod zbus_gfx;
pub mod zbus_led;
pub mod zbus_profile;
pub mod zbus_rogbios;
@@ -13,7 +13,6 @@ pub mod zbus_supported;
use rog_anime::AnimePowerStates;
use rog_aura::{AuraEffect, LedPowerStates};
use rog_profiles::Profile;
use supergfxctl::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use std::sync::mpsc::{channel, Receiver};
use zbus::{Connection, Result, SignalReceiver};
@@ -21,7 +20,6 @@ pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub struct DbusProxies<'a> {
anime: zbus_anime::AnimeProxy<'a>,
charge: zbus_charge::ChargeProxy<'a>,
gfx: zbus_gfx::GfxProxy<'a>,
led: zbus_led::LedProxy<'a>,
profile: zbus_profile::ProfileProxy<'a>,
rog_bios: zbus_rogbios::RogBiosProxy<'a>,
@@ -38,7 +36,6 @@ impl<'a> DbusProxies<'a> {
anime: zbus_anime::AnimeProxy::new(&conn)?,
led: zbus_led::LedProxy::new(&conn)?,
charge: zbus_charge::ChargeProxy::new(&conn)?,
gfx: zbus_gfx::GfxProxy::new(&conn)?,
profile: zbus_profile::ProfileProxy::new(&conn)?,
rog_bios: zbus_rogbios::RogBiosProxy::new(&conn)?,
supported: zbus_supported::SupportProxy::new(&conn)?,
@@ -52,7 +49,6 @@ impl<'a> DbusProxies<'a> {
recv.receive_for(self.anime.proxy());
recv.receive_for(self.led.proxy());
recv.receive_for(self.charge.proxy());
recv.receive_for(self.gfx.proxy());
recv.receive_for(self.profile.proxy());
recv.receive_for(self.rog_bios.proxy());
recv.receive_for(self.supported.proxy());
@@ -67,10 +63,6 @@ impl<'a> DbusProxies<'a> {
&self.charge
}
pub fn gfx(&self) -> &zbus_gfx::GfxProxy<'a> {
&self.gfx
}
pub fn led(&self) -> &zbus_led::LedProxy<'a> {
&self.led
}
@@ -90,8 +82,6 @@ impl<'a> DbusProxies<'a> {
// Signals separated out
pub struct Signals {
pub gfx_vendor: Receiver<GfxVendors>,
pub gfx_action: Receiver<GfxRequiredUserAction>,
pub profile: Receiver<Profile>,
pub led_mode: Receiver<AuraEffect>,
pub led_power_state: Receiver<LedPowerStates>,
@@ -105,16 +95,6 @@ impl Signals {
#[inline]
pub fn new(proxies: &DbusProxies) -> Result<Self> {
Ok(Signals {
gfx_vendor: {
let (tx, rx) = channel();
proxies.gfx.connect_notify_gfx(tx)?;
rx
},
gfx_action: {
let (tx, rx) = channel();
proxies.gfx.connect_notify_action(tx)?;
rx
},
profile: {
let (tx, rx) = channel();
proxies.profile.connect_notify_profile(tx)?;
@@ -182,26 +162,9 @@ impl<'a> RogDbusClient<'a> {
recv.receive_for(self.proxies.anime.proxy());
recv.receive_for(self.proxies.led.proxy());
recv.receive_for(self.proxies.charge.proxy());
recv.receive_for(self.proxies.gfx.proxy());
recv.receive_for(self.proxies.profile.proxy());
recv.receive_for(self.proxies.rog_bios.proxy());
recv.receive_for(self.proxies.supported.proxy());
recv
}
/*
* GFX
*/
pub fn gfx_wait_changed(&self) -> Result<GfxRequiredUserAction> {
loop {
if let Ok(res) = self.proxies.gfx.proxy().next_signal() {
if res.is_none() {
if let Ok(stuff) = self.signals.gfx_action.try_recv() {
return Ok(stuff);
}
// return Ok("Failed for unknown reason".to_owned());
}
}
}
}
}

View File

@@ -1,20 +0,0 @@
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub enum GraphicsError {
ParseVendor,
ParsePower,
}
impl fmt::Display for GraphicsError {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GraphicsError::ParseVendor => write!(f, "Could not parse vendor name"),
GraphicsError::ParsePower => write!(f, "Could not parse dGPU power status"),
}
}
}
impl Error for GraphicsError {}

View File

@@ -8,6 +8,4 @@ pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
pub mod supported;
pub mod error;
pub static VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@@ -12,6 +12,26 @@ keywords = ["graphics", "nvidia", "switching"]
edition = "2018"
exclude = ["data"]
[features]
daemon = ["env_logger"]
cli = ["gumdrop"]
default = ["daemon", "cli"]
[lib]
name = "supergfxctl"
path = "src/lib.rs"
[[bin]]
name = "supergfxd"
path = "src/daemon.rs"
required-features = ["daemon"]
[[bin]]
name = "supergfxctl"
path = "src/cli.rs"
required-features = ["cli"]
default-features = ["cli"]
[dependencies]
serde = "^1.0"
serde_derive = "^1.0"
@@ -23,4 +43,7 @@ zvariant = "^2.8"
zvariant_derive = "^2.8"
logind-zbus = "^0.7.1"
sysfs-class = "^0.1.2"
sysfs-class = "^0.1.2"
env_logger = { version = "^0.8", optional = true }
gumdrop = { version = "^0.8", optional = true }

74
supergfx/Makefile Normal file
View File

@@ -0,0 +1,74 @@
VERSION := $(shell grep -Pm1 'version = "(\d.\d.\d)"' daemon/Cargo.toml | cut -d'"' -f2)
INSTALL = install
INSTALL_PROGRAM = ${INSTALL} -D -m 0755
INSTALL_DATA = ${INSTALL} -D -m 0644
prefix = /usr
exec_prefix = $(prefix)
bindir = $(exec_prefix)/bin
datarootdir = $(prefix)/share
libdir = $(exec_prefix)/lib
BIN_SD := supergfxd
BIN_SC := supergfxctl
X11CFG := 90-nvidia-screen-G05.conf
PMRULES := 90-asusd-nvidia-pm.rules
SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs')
DEBUG ?= 0
ifeq ($(DEBUG),0)
ARGS += --release
TARGET = release
endif
VENDORED ?= 0
ifeq ($(VENDORED),1)
ARGS += --frozen
endif
all: build
clean:
cargo clean
distclean:
rm -rf .cargo vendor vendor.tar.xz
install:
$(INSTALL_PROGRAM) "./target/release/$(BIN_SD)" "$(DESTDIR)$(bindir)/$(BIN_SD)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_SC)" "$(DESTDIR)$(bindir)/$(BIN_SC)"
$(INSTALL_DATA) "./data/$(BIN_SD).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_SD).service"
$(INSTALL_DATA) "./data/org.supergfxctl.Daemon.conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/org.supergfxctl.Daemon.conf"
$(INSTALL_DATA) "./data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
$(INSTALL_DATA) "./data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_SC)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_SD)"
rm -f "$(DESTDIR)$(libdir)/systemd/system/$(BIN_SD).service"
rm -f "$(DESTDIR)$(datarootdir)/dbus-1/system.d/org.supergfxctl.Daemon.conf"
rm -f "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
rm -f "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
update:
cargo update
vendor:
mkdir -p .cargo
cargo vendor | head -n -1 > .cargo/config
echo 'directory = "vendor"' >> .cargo/config
mv .cargo/config ./cargo-config
rm -rf .cargo
tar pcfJ vendor_asusctl_$(VERSION).tar.xz vendor
rm -rf vendor
build:
ifeq ($(VENDORED),1)
@echo "version = $(VERSION)"
tar pxf vendor_asusctl_$(VERSION).tar.xz
endif
cargo build $(ARGS)
.PHONY: all clean distclean install uninstall update build

View File

@@ -0,0 +1,26 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<policy group="adm">
<allow send_destination="org.supergfxctl.Daemon"/>
<allow receive_sender="org.supergfxctl.Daemon"/>
</policy>
<policy group="sudo">
<allow send_destination="org.supergfxctl.Daemon"/>
<allow receive_sender="org.supergfxctl.Daemon"/>
</policy>
<policy group="users">
<allow send_destination="org.supergfxctl.Daemon"/>
<allow receive_sender="org.supergfxctl.Daemon"/>
</policy>
<policy group="wheel">
<allow send_destination="org.supergfxctl.Daemon"/>
<allow receive_sender="org.supergfxctl.Daemon"/>
</policy>
<policy user="root">
<allow own="org.supergfxctl.Daemon"/>
<allow send_destination="org.supergfxctl.Daemon"/>
<allow receive_sender="org.supergfxctl.Daemon"/>
</policy>
</busconfig>

View File

@@ -0,0 +1,16 @@
[Unit]
Description=SUPERGFX
StartLimitInterval=200
StartLimitBurst=2
Before=display-manager.service
[Service]
Environment=IS_SUPERGFX_SERVICE=1
ExecStart=/usr/bin/supergfxd
Restart=on-failure
Restart=always
RestartSec=1
Type=dbus
BusName=org.supergfxctl.Daemon
SELinuxContext=system_u:system_r:unconfined_t:s0
#SELinuxContext=system_u:object_r:modules_object_t:s0

105
supergfx/src/cli.rs Normal file
View File

@@ -0,0 +1,105 @@
use std::{env::args, sync::mpsc::channel};
use supergfxctl::{
gfx_vendors::{GfxRequiredUserAction, GfxVendors},
special::{get_asus_gsync_gfx_mode, has_asus_gsync_gfx_mode},
zbus_proxy::GfxProxy,
};
use gumdrop::Options;
use zbus::Connection;
#[derive(Default, Options)]
struct CliStart {
#[options(help = "print help message")]
help: bool,
#[options(
meta = "",
help = "Set graphics mode: <nvidia, hybrid, compute, integrated>"
)]
mode: Option<GfxVendors>,
#[options(help = "Get the current mode")]
get: bool,
#[options(help = "Get the current power status")]
pow: bool,
#[options(help = "Do not ask for confirmation")]
force: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = args().skip(1).collect();
match CliStart::parse_args_default(&args) {
Ok(command) => {
do_gfx(command)?;
}
Err(err) => {
eprintln!("source {}", err);
std::process::exit(2);
}
}
Ok(())
}
fn do_gfx(command: CliStart) -> Result<(), Box<dyn std::error::Error>> {
if command.mode.is_none() && !command.get && !command.pow && !command.force || command.help {
println!("{}", command.self_usage());
}
let conn = Connection::new_system()?;
let proxy = GfxProxy::new(&conn)?;
let (tx, rx) = channel();
proxy.connect_notify_action(tx)?;
if let Some(mode) = command.mode {
if has_asus_gsync_gfx_mode() && get_asus_gsync_gfx_mode()? == 1 {
println!("You can not change modes until you turn dedicated/G-Sync off and reboot");
std::process::exit(-1);
}
println!("If anything fails check `journalctl -b -u supergfxd`\n");
proxy.gfx_write_mode(&mode).map_err(|err|{
println!("Graphics mode change error. You may be in an invalid state.");
println!("Check mode with `-g` and switch to opposite\nmode to correct it, e.g: if integrated, switch to hybrid, or if nvidia, switch to integrated.\n");
err
})?;
loop {
proxy.next_signal()?;
if let Ok(res) = rx.try_recv() {
match res {
GfxRequiredUserAction::Integrated => {
println!(
"You must change to Integrated before you can change to {}",
<&str>::from(mode)
);
}
GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => {
println!(
"Graphics mode changed to {}. User action required is: {}",
<&str>::from(mode),
<&str>::from(&res)
);
}
GfxRequiredUserAction::None => {
println!("Graphics mode changed to {}", <&str>::from(mode));
}
}
}
std::process::exit(0)
}
}
if command.get {
let res = proxy.gfx_get_mode()?;
println!("Current graphics mode: {}", <&str>::from(res));
}
if command.pow {
let res = proxy.gfx_get_pwr()?;
println!("Current power status: {}", <&str>::from(&res));
}
Ok(())
}

105
supergfx/src/daemon.rs Normal file
View File

@@ -0,0 +1,105 @@
use std::{
env,
error::Error,
sync::{Arc, Mutex},
};
use log::{error, info, warn, LevelFilter};
use std::io::Write;
use supergfxctl::{
config::GfxConfig,
controller::CtrlGraphics,
error::GfxError,
gfx_vendors::GfxVendors,
special::{get_asus_gsync_gfx_mode, has_asus_gsync_gfx_mode},
DBUS_DEST_NAME, GFX_CONFIG_PATH,
};
use zbus::{fdo, Connection, ObjectServer};
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
.target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.filter(None, LevelFilter::Info)
.init();
let is_service = match env::var_os("IS_SUPERGFX_SERVICE") {
Some(val) => val == "1",
None => false,
};
if !is_service {
println!("supergfxd schould be only run from the right systemd service");
println!(
"do not run in your terminal, if you need an logs please use journalctl -b -u supergfxd"
);
println!("supergfxd will now exit");
return Ok(());
}
start_daemon()
}
fn start_daemon() -> Result<(), Box<dyn Error>> {
// Start zbus server
let connection = Connection::new_system()?;
fdo::DBusProxy::new(&connection)?.request_name(
DBUS_DEST_NAME,
fdo::RequestNameFlags::ReplaceExisting.into(),
)?;
let mut object_server = ObjectServer::new(&connection);
let config = GfxConfig::load(GFX_CONFIG_PATH.into());
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
// Graphics switching requires some checks on boot specifically for g-sync capable laptops
if enable_gfx_switching {
match CtrlGraphics::new(config.clone()) {
Ok(mut ctrl) => {
// Need to check if a laptop has the dedicated gfx switch
if has_asus_gsync_gfx_mode() {
do_asus_laptop_checks(&ctrl, config)?;
}
ctrl.reload()
.unwrap_or_else(|err| error!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
}
}
}
// Loop to check errors and iterate zbus server
loop {
if let Err(err) = object_server.try_handle_next() {
error!("{}", err);
}
}
}
fn do_asus_laptop_checks(
ctrl: &CtrlGraphics,
config: Arc<Mutex<GfxConfig>>,
) -> Result<(), GfxError> {
if let Ok(ded) = get_asus_gsync_gfx_mode() {
if let Ok(config) = config.lock() {
if ded == 1 {
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
let devices = ctrl.devices();
let bus = ctrl.bus();
CtrlGraphics::do_mode_setup_tasks(GfxVendors::Nvidia, false, &devices, &bus)?;
} else if ded == 0 {
info!("Dedicated GFX toggle is off");
let devices = ctrl.devices();
let bus = ctrl.bus();
CtrlGraphics::do_mode_setup_tasks(config.gfx_mode, false, &devices, &bus)?;
}
}
}
Ok(())
}

View File

@@ -69,4 +69,4 @@ impl From<std::io::Error> for GfxError {
fn from(err: std::io::Error) -> Self {
GfxError::Io(err)
}
}
}

View File

@@ -1,12 +1,17 @@
pub mod error;
pub mod config;
pub mod gfx_vendors;
pub mod controller;
pub mod system;
pub mod error;
pub mod gfx_vendors;
/// Special-case functions for check/read/write of key functions on unique laptops
/// such as the G-Sync mode available on some ASUS ROG laptops
pub(crate) mod special;
pub mod zbus;
pub mod special;
pub mod system;
pub mod zbus_iface;
pub mod zbus_proxy;
pub const GFX_CONFIG_PATH: &str = "/etc/supergfxd.conf";
pub const DBUS_DEST_NAME: &str = "org.supergfxctl.Daemon";
pub const DBUS_IFACE_PATH: &str = "/org/supergfxctl/Gfx";
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];

View File

@@ -5,11 +5,11 @@ use crate::error::GfxError;
static ASUS_SWITCH_GRAPHIC_MODE: &str =
"/sys/firmware/efi/efivars/AsusSwitchGraphicMode-607005d5-3f75-4b2e-98f0-85ba66797a3e";
pub(crate) fn has_asus_gsync_gfx_mode() -> bool {
pub fn has_asus_gsync_gfx_mode() -> bool {
Path::new(ASUS_SWITCH_GRAPHIC_MODE).exists()
}
pub(crate) fn get_asus_gsync_gfx_mode() -> Result<i8, GfxError> {
pub fn get_asus_gsync_gfx_mode() -> Result<i8, GfxError> {
let path = ASUS_SWITCH_GRAPHIC_MODE;
let mut file = OpenOptions::new()
.read(true)
@@ -22,4 +22,4 @@ pub(crate) fn get_asus_gsync_gfx_mode() -> Result<i8, GfxError> {
let idx = data.len() - 1;
Ok(data[idx] as i8)
}
}

View File

@@ -1,12 +1,15 @@
use ::zbus::dbus_interface;
use log::{error, info, warn};
use zvariant::ObjectPath;
use ::zbus::dbus_interface;
use crate::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
use crate::{
gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors},
DBUS_IFACE_PATH,
};
use super::controller::CtrlGraphics;
#[dbus_interface(name = "org.asuslinux.Daemon")]
#[dbus_interface(name = "org.supergfxctl.Daemon")]
impl CtrlGraphics {
fn vendor(&self) -> zbus::fdo::Result<GfxVendors> {
self.get_gfx_mode().map_err(|err| {
@@ -28,10 +31,13 @@ impl CtrlGraphics {
error!("GFX: {}", err);
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
})?;
self.notify_gfx(&vendor)
.unwrap_or_else(|err| warn!("GFX: {}", err));
self.notify_action(&msg)
.unwrap_or_else(|err| warn!("GFX: {}", err));
self.notify_gfx(&vendor)
.unwrap_or_else(|err| warn!("GFX: {}", err));
Ok(msg)
}
@@ -45,7 +51,7 @@ impl CtrlGraphics {
impl CtrlGraphics {
pub fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at(&ObjectPath::from_str_unchecked("/org/asuslinux/Gfx"), self)
.at(&ObjectPath::from_str_unchecked(DBUS_IFACE_PATH), self)
.map_err(|err| {
warn!("GFX: CtrlGraphics: add_to_server {}", err);
err

View File

@@ -1,7 +1,7 @@
//! # DBus interface proxy for: `org.asuslinux.Gfx`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data.
//! Source: `Interface '/org/asuslinux/Gfx' from service 'org.asuslinux.Daemon' on system bus`.
//! Source: `Interface '/org/supergfxctl/Gfx' from service 'org.asuslinux.Daemon' on system bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
@@ -19,15 +19,16 @@
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
use std::sync::mpsc::Sender;
use std::sync::mpsc::{Receiver, Sender};
use supergfxctl::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
use zbus::{dbus_proxy, Connection, Result};
use zbus::{dbus_proxy, Connection, Message, Result};
#[dbus_proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Gfx"
)]
use crate::{
gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors},
DBUS_IFACE_PATH,
};
#[dbus_proxy(interface = "org.supergfxctl.Daemon")]
trait Daemon {
/// Power method
fn power(&self) -> zbus::Result<GfxPower>;
@@ -47,12 +48,25 @@ trait Daemon {
fn notify_gfx(&self, vendor: GfxVendors) -> zbus::Result<()>;
}
pub struct GfxProxy<'a>(DaemonProxy<'a>);
pub struct GfxProxy<'a>(pub DaemonProxy<'a>);
impl<'a> GfxProxy<'a> {
#[inline]
pub fn new(conn: &Connection) -> Result<Self> {
Ok(GfxProxy(DaemonProxy::new(conn)?))
let proxy = DaemonProxy::new_for(conn, "org.supergfxctl.Daemon", DBUS_IFACE_PATH)?;
Ok(GfxProxy(proxy))
}
#[inline]
pub fn new_for(conn: &Connection, destination: &'a str, path: &'a str) -> Result<Self> {
let proxy = DaemonProxy::new_for(conn, destination, path)?;
Ok(GfxProxy(proxy))
}
#[inline]
pub fn new_for_owned(conn: Connection, destination: String, path: String) -> Result<Self> {
let proxy = DaemonProxy::new_for_owned(conn, destination, path)?;
Ok(GfxProxy(proxy))
}
#[inline]
@@ -95,4 +109,9 @@ impl<'a> GfxProxy<'a> {
Ok(())
})
}
#[inline]
pub fn next_signal(&self) -> Result<Option<Message>> {
self.0.next_signal()
}
}