Compare commits

...

4 Commits
2.0.1 ... 2.0.2

Author SHA1 Message Date
Luke Jones
24962eedc1 Merge branch 'testing' into 'next'
Bugfixes and improvements

Closes #11

See merge request asus-linux/asus-nb-ctrl!4
2020-09-23 01:05:15 +00:00
Luke D Jones
368d279ca5 Add "info" output for gfx driver check 2020-09-23 12:59:15 +12:00
Luke D Jones
9e4cc329ed Add "info" output for gfx driver check 2020-09-22 09:54:37 +12:00
Luke D Jones
d4702a166a Support Zephyrus M GU502GV
closes #11
2020-09-22 09:47:20 +12:00
16 changed files with 324 additions and 135 deletions

View File

@@ -6,6 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
# [2.0.0] - 2020-09-21
### Changed
- graphics options via CLI are now a command block:
+ `asusctl graphics`
+ -m Mode <nvidia, hybrid, compute, integrated>
+ -g Get current mode
+ -f Force reboot or restart display manager without confirmation
# [2.0.0] - 2020-09-21
### Changed
- Code refactor to spawn less tasks. Main loop will run only as fast as

6
Cargo.lock generated
View File

@@ -29,7 +29,7 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "asus-nb"
version = "2.0.1"
version = "2.0.2"
dependencies = [
"ctrl-gfx",
"dbus",
@@ -46,7 +46,7 @@ dependencies = [
[[package]]
name = "asus-nb-ctrl"
version = "2.0.1"
version = "2.0.2"
dependencies = [
"asus-nb",
"ctrl-gfx",
@@ -189,7 +189,7 @@ dependencies = [
[[package]]
name = "ctrl-gfx"
version = "2.0.0"
version = "2.1.0"
dependencies = [
"log",
"sysfs-class",

View File

@@ -16,7 +16,7 @@ BIN_D=asusd
BIN_N=asus-notify
LEDCFG=asusd-ledmodes.toml
X11CFG=90-nvidia-screen-G05.conf
UDEVRULES=90-nvidia-pm.rules
PMRULES=90-asusd-nvidia-pm.rules
VERSION:=$(shell grep -Pm1 'version = "(\d.\d.\d)"' asus-nb-ctrl/Cargo.toml | cut -d'"' -f2)
DEBUG ?= 0
@@ -42,8 +42,9 @@ install: all
install -D -m 0755 "target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
install -D -m 0755 "target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
install -D -m 0755 "target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
install -D -m 0644 "data/$(UDEVRULES)" "$(DESTDIR)/lib/udev/rules.d/$(UDEVRULES)"
install -D -m 0644 "data/$(PMRULES)" "$(DESTDIR)/lib/udev/rules.d/$(PMRULES)"
install -D -m 0644 "data/$(BIN_D).rules" "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
install -D -m 0644 "data/$(PMRULES).rules" "$(DESTDIR)/lib/udev/rules.d/$(PMRULES).rules"
install -D -m 0644 "data/$(LEDCFG)" "$(DESTDIR)$(sysconfdir)/asusd/$(LEDCFG)"
install -D -m 0644 "data/$(BIN_D).conf" "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
install -D -m 0644 "data/$(X11CFG)" "$(DESTDIR)$(sysconfdir)/X11/xorg.conf.d/$(X11CFG)"
@@ -57,8 +58,9 @@ uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
rm -f "$(DESTDIR)/lib/udev/rules.d/$(UDEVRULES)"
rm -f "$(DESTDIR)/lib/udev/rules.d/$(PMRULES)"
rm -f "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
rm -f "$(DESTDIR)/lib/udev/rules.d/$(PMRULES).rules"
rm -f "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
rm -f "$(DESTDIR)$(sysconfdir)/X11/xorg.conf.d/$(X11CFG)"
rm -f "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"

View File

@@ -1,5 +1,8 @@
# ASUS NB Ctrl
`asusd` is a utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features.
**NOTICE:**
This program requires the kernel patch [here](https://www.spinics.net/lists/linux-input/msg68977.html) to be applied.
@@ -12,17 +15,12 @@ The patch enables the following in kernel:
- Control of keyboard brightness using FN+Key combos (not RGB)
- FN+F5 (fan) to toggle fan modes
You will not get RGB control in kernel (yet), and asusd is still required to
change modes and RGB settings. The previous version of this program is named
`rog-core` and takes full control of the interfaces required - if you can't
apply the kernel patches then `rog-core` is still highly usable.
You will not get RGB control in kernel (yet), and `asusd` + `asusctl` is required
to change modes and RGB settings.
Many other patches for these laptops, AMD and Intel based, are working their way
in to the kernel.
---
asusd is a utility for Linux to control many aspects of various ASUS laptops.
## Discord
[Discord server link](https://discord.gg/PVyFzWj)
@@ -54,9 +52,9 @@ will probably suffer another rename once it becomes generic enough to do so.
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
## FUNCTIONS
# FUNCTIONS
### Graphics switching
## Graphics switching
A new feature has been added to enable switching graphics modes. This can be disabled
in the config with `"manage_gfx": false,`. Please be aware it is a work in progress.
@@ -64,7 +62,37 @@ in the config with `"manage_gfx": false,`. Please be aware it is a work in progr
The CLI option for this does not require root until it asks for it, and provides
instructions.
### KEYBOARD BACKLIGHT MODES
This switcher conflicts with other gpu switchers like optimus-manager, suse-prime
or ubuntu-prime, system76-power, and bbswitch. If you have issues with `asusd`
always defaulting to `integrated` mode on boot then you will need to check for
stray configs blocking nvidia modules from loading in:
- `/etc/modprobe.d/`
- `/usr/lib/modprope.d/`
### Power management udev rule
If you have installed the Nvidia driver manually you will require the
`data/90-asusd-nvidia-pm.rules` udev rule to be installed in `/etc/udev/rules.d/`.
The above seems to also apply to Arch in general as it leaves a lot of things up
to the user.
### fedora and openSUSE
You *may* need a file `/etc/dracut.conf.d/90-nvidia-dracut-G05.conf` installed
to stop dracut including the nvidia modules in the ramdisk.
```
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
# Omit the nvidia driver from the ramdisk, to avoid needing to regenerate
# the ramdisk on updates, and to ensure the power-management udev rules run
# on module load
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
```
and run `dracut -f` after creating it.
## KEYBOARD BACKLIGHT MODES
Models GA401, GA502, GU502 support LED brightness change only (no RGB).
@@ -90,7 +118,9 @@ If you model isn't getting the correct led modes, you can edit the file
use `cat /sys/class/dmi/id/product_name` to get details about your laptop.
## Requirements for compiling
# BUILDING
Requirements are:
- `rustc` + `cargo` + `make`
- `libusb-1.0-0-dev`
@@ -120,6 +150,11 @@ $ systemctl daemon-reload && systemctl restart asusd
You may also need to activate the service for debian install. If running Pop!_OS, I suggest disabling `system76-power` gnome-shell extension and systemd service.
If you would like to run this daemon on another non-ASUS laptop you can. You'll
have all features available except the LED and AniMe control (further controllers
can be added on request). You will need to install the alternative service from
`data/asusd-alt.service`.
## Uninstalling
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
@@ -130,7 +165,7 @@ If there has been a config file format change your config will be overwritten. T
become less of an issue once the feature set is nailed down. Work is happening to enable
parsing of older configs and transferring settings to new.
# Usage
# USAGE
**NOTE! Fan mode toggling requires a newer kernel**. I'm unsure when the patches
required for it got merged - I've tested with the 5.6.6 kernel and above only.
@@ -180,7 +215,7 @@ Daemon mode creates a config file at `/etc/asusd/asusd.conf` which you can edit
little of. Most parts will be byte arrays, but you can adjust things like
`mode_performance`.
## User daemon for notification via dbus
## User NOTIFICATIONS via dbus
If you have a notifications handler set up, or are using KDE or Gnome then you
can enable the user service to get basic notifications when something changes.
@@ -189,7 +224,7 @@ can enable the user service to get basic notifications when something changes.
systemctl --user enable asus-notify.service
systemctl --user start asus-notify.service
```
# Other
# OTHER
## DBUS Input
@@ -208,6 +243,14 @@ Please file a support request.
- If charge limit or fan modes are not working, then you may require a kernel newer than 5.6.10.
- AniMe device check is performed on start, if your device has one it will be detected.
- GA14/GA401 and GA15/GA502/GU502, You will need kernel [patches](https://lab.retarded.farm/zappel/asus-rog-zephyrus-g14/-/tree/master/kernel_patches), these are on their way to the kernel upstream.
- On fedora manually installed Nvidia driver requires a dracut config as follows:
```
# filename/etc/dracut.conf.d/90-nvidia-dracut-G05.conf
# Omit the nvidia driver from the ramdisk, to avoid needing to regenerate
# the ramdisk on updates, and to ensure the power-management udev rules run
# on module load
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
```
# License

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-nb-ctrl"
version = "2.0.1"
version = "2.0.2"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]

View File

@@ -19,7 +19,7 @@ use config::Config;
use crate::error::RogError;
use zbus::ObjectServer;
pub static VERSION: &str = "2.0.1";
pub static VERSION: &str = "2.0.2";
pub trait Reloadable {
fn reload(&mut self) -> Result<(), RogError>;

View File

@@ -8,6 +8,7 @@ use daemon::ctrl_fan_cpu::FanLevel;
use gumdrop::Options;
use log::LevelFilter;
use std::io::Write;
use std::process::Command;
use yansi_term::Colour::Green;
use yansi_term::Colour::Red;
@@ -23,18 +24,18 @@ struct CLIStart {
pwr_profile: Option<FanLevel>,
#[options(meta = "CHRG", help = "<20-100>")]
chg_limit: Option<u8>,
#[options(help = "Set graphics mode: <nvidia, hybrid, compute, integrated>")]
graphics: Option<GfxVendors>,
#[options(command)]
command: Option<Command>,
command: Option<CliCommand>,
}
#[derive(Options)]
enum Command {
enum CliCommand {
#[options(help = "Set the keyboard lighting from built-in modes")]
LedMode(LedModeCommand),
#[options(help = "Create and configure profiles")]
Profile(ProfileCommand),
#[options(help = "Set the graphics mode")]
Graphics(GraphicsCommand),
}
#[derive(Options)]
@@ -45,6 +46,20 @@ struct LedModeCommand {
command: Option<SetAuraBuiltin>,
}
#[derive(Options)]
struct GraphicsCommand {
#[options(help = "print help message")]
help: bool,
#[options(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 mut logger = env_logger::Builder::new();
logger
@@ -62,14 +77,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let writer = AuraDbusClient::new()?;
match parsed.command {
Some(Command::LedMode(mode)) => {
Some(CliCommand::LedMode(mode)) => {
if let Some(command) = mode.command {
writer.write_builtin_mode(&command.into())?
}
}
Some(Command::Profile(command)) => {
Some(CliCommand::Profile(command)) => {
writer.write_profile_command(&ProfileEvent::Cli(command))?
}
Some(CliCommand::Graphics(command)) => do_gfx(command, &writer)?,
None => (),
}
@@ -82,52 +98,94 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if let Some(chg_limit) = parsed.chg_limit {
writer.write_charge_limit(chg_limit)?;
}
if let Some(gfx) = parsed.graphics {
Ok(())
}
fn do_gfx(
command: GraphicsCommand,
writer: &AuraDbusClient,
) -> Result<(), Box<dyn std::error::Error>> {
if let Some(mode) = command.mode {
println!("Updating settings, please wait...");
println!("If this takes longer than 30s, ctrl+c then check journalctl");
writer.write_gfx_mode(gfx)?;
writer.write_gfx_mode(mode)?;
let res = writer.wait_gfx_changed()?;
match res.as_str() {
"reboot" => println!(
"{}\n{}",
Green.paint("\nGraphics vendor mode changed successfully\n"),
Red.paint("\nPlease reboot to complete switch\n")
),
"reboot" => {
println!(
"{}",
Green.paint("\nGraphics vendor mode changed successfully\n"),
);
do_gfx_action(
command.force,
Command::new("systemctl").arg("reboot"),
"Reboot Linux PC",
"Please reboot when ready",
)?;
}
"restartx" => {
println!(
"{}",
Green.paint("\nGraphics vendor mode changed successfully\n")
);
restart_x()?;
do_gfx_action(
command.force,
Command::new("systemctl")
.arg("restart")
.arg("display-manager.service"),
"Restart display-manager server",
"Please restart display-manager when ready",
)?;
std::process::exit(1)
}
_ => std::process::exit(-1),
}
std::process::exit(-1)
}
Ok(())
}
fn restart_x() -> Result<(), Box<dyn std::error::Error>> {
println!("Restart X server? y/n");
let mut buf = String::new();
std::io::stdin().read_line(&mut buf).expect("Input failed");
let input = buf.chars().next().unwrap() as char;
if input == 'Y' || input == 'y' {
println!("Restarting X server");
let status = std::process::Command::new("systemctl")
.arg("restart")
.arg("display-manager.service")
.status()?;
if !status.success() {
println!("systemctl: display-manager returned with {}", status);
if command.get {
let res = writer.get_gfx_mode()?;
println!("Current graphics mode: {}", res);
}
if command.pow {
let res = writer.get_gfx_pwr()?;
if res.contains("active") {
println!("Current power status: {}", Red.paint(&format!("{}", res)));
} else {
println!("Current power status: {}", Green.paint(&format!("{}", res)));
}
} else {
println!("{}", Red.paint("Cancelled. Please restart X when ready"));
}
Ok(())
}
fn do_gfx_action(
no_confirm: bool,
command: &mut Command,
ask_msg: &str,
cancel_msg: &str,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{}? y/n", ask_msg);
let mut buf = String::new();
if no_confirm {
let status = command.status()?;
if !status.success() {
println!("systemctl: returned with {}", status);
}
}
std::io::stdin().read_line(&mut buf).expect("Input failed");
let input = buf.chars().next().unwrap() as char;
if input == 'Y' || input == 'y' || no_confirm {
let status = command.status()?;
if !status.success() {
println!("systemctl: returned with {}", status);
}
} else {
println!("{}", Red.paint(&format!("{}", cancel_msg)));
}
Ok(())
}

View File

@@ -1,6 +1,6 @@
[package]
name = "asus-nb"
version = "2.0.1"
version = "2.0.2"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]

View File

@@ -2,7 +2,6 @@ use super::*;
use crate::fancy::KeyColourArray;
use crate::profile::ProfileEvent;
use ctrl_gfx::vendors::GfxVendors;
use dbus::channel::Sender;
use dbus::{blocking::Connection, Message};
use std::error::Error;
use std::sync::{
@@ -11,10 +10,17 @@ use std::sync::{
};
use std::{thread, time::Duration};
use crate::dbus_gfx::{OrgAsuslinuxDaemonNotifyGfx, OrgAsuslinuxDaemonNotifyAction};
use crate::dbus_ledmode::OrgAsuslinuxDaemonNotifyLed;
use crate::dbus_profile::OrgAsuslinuxDaemonNotifyProfile;
use crate::dbus_charge::OrgAsuslinuxDaemonNotifyCharge;
use crate::dbus_charge::{OrgAsuslinuxDaemonNotifyCharge, OrgAsuslinuxDaemon as OrgAsuslinuxDaemonCharge};
use crate::dbus_gfx::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonGfx, OrgAsuslinuxDaemonNotifyAction,
OrgAsuslinuxDaemonNotifyGfx,
};
use crate::dbus_ledmode::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonLed, OrgAsuslinuxDaemonNotifyLed,
};
use crate::dbus_profile::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonProfile, OrgAsuslinuxDaemonNotifyProfile,
};
// Signals separated out
pub struct CtrlSignals {
@@ -111,7 +117,7 @@ impl CtrlSignals {
let _x = proxy.match_signal(
move |sig: OrgAsuslinuxDaemonNotifyCharge, _: &Connection, _: &Message| {
if let Ok(mut lock) = charge_res1.lock() {
*lock = Some(sig.limit);
*lock = Some(sig.limit);
}
true
},
@@ -176,11 +182,12 @@ impl AuraDbusClient {
#[inline]
pub fn init_effect(&self) -> Result<(), Box<dyn std::error::Error>> {
let mode = AuraModes::PerKey(vec![vec![]]);
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
.append1(serde_json::to_string(&mode)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_millis(5000),
);
proxy.set_led_mode(&serde_json::to_string(&mode)?)?;
Ok(())
}
@@ -199,13 +206,12 @@ impl AuraDbusClient {
vecs.push(v.to_vec());
}
let mode = AuraModes::PerKey(vecs);
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
.append1(serde_json::to_string(&mode)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
self.write_keyboard_leds(&mode)?;
thread::sleep(Duration::from_micros(self.block_time));
self.connection.process(Duration::from_micros(500))?;
if self.stop.load(Ordering::Relaxed) {
println!("Keyboard backlight was changed, exiting");
std::process::exit(1)
@@ -215,35 +221,56 @@ impl AuraDbusClient {
#[inline]
pub fn write_keyboard_leds(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
.append1(serde_json::to_string(mode)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_millis(5000),
);
proxy.set_led_mode(&serde_json::to_string(mode)?)?;
Ok(())
}
#[inline]
pub fn get_gfx_pwr(&self) -> Result<String, Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_millis(5000),
);
let x = proxy.power().unwrap();
Ok(x)
}
#[inline]
pub fn get_gfx_mode(&self) -> Result<String, Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_millis(5000),
);
let x = proxy.vendor().unwrap();
Ok(x)
}
#[inline]
pub fn write_gfx_mode(&self, vendor: GfxVendors) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Gfx",
Duration::from_millis(5000),
);
proxy.set_vendor(<&str>::from(&vendor))?;
Ok(())
}
#[inline]
pub fn write_fan_mode(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
let mut msg = Message::new_method_call(
DBUS_NAME,
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
DBUS_IFACE,
"SetProfile",
)?
.append1(serde_json::to_string(&ProfileEvent::ChangeMode(level))?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
Ok(())
}
#[inline]
pub fn write_gfx_mode(&self, vendor: GfxVendors) -> Result<(), Box<dyn std::error::Error>> {
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Gfx", DBUS_IFACE, "SetVendor")?
.append1(<&str>::from(&vendor));
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
Duration::from_millis(5000),
);
proxy.set_profile(&serde_json::to_string(&ProfileEvent::ChangeMode(level))?)?;
Ok(())
}
@@ -252,25 +279,23 @@ impl AuraDbusClient {
&self,
cmd: &ProfileEvent,
) -> Result<(), Box<dyn std::error::Error>> {
let mut msg = Message::new_method_call(
DBUS_NAME,
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
DBUS_IFACE,
"SetProfile",
)?
.append1(serde_json::to_string(cmd)?);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
Duration::from_millis(5000),
);
proxy.set_profile(&serde_json::to_string(cmd)?)?;
Ok(())
}
#[inline]
pub fn write_charge_limit(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Charge", DBUS_IFACE, "SetLimit")?
.append1(level);
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Charge",
Duration::from_millis(5000),
);
proxy.set_limit(level)?;
Ok(())
}

View File

@@ -5,11 +5,23 @@ use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn vendor(&self) -> Result<String, dbus::Error>;
fn power(&self) -> Result<String, dbus::Error>;
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
fn vendor(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Vendor", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn power(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Power", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetVendor", (vendor, ))
}

View File

@@ -1,6 +1,6 @@
[package]
name = "ctrl-gfx"
version = "2.0.0"
version = "2.1.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]

View File

@@ -14,8 +14,8 @@ use crate::{error::GfxError, system::*};
pub struct CtrlGraphics {
bus: PciBus,
amd: Vec<GraphicsDevice>,
intel: Vec<GraphicsDevice>,
_amd: Vec<GraphicsDevice>,
_intel: Vec<GraphicsDevice>,
nvidia: Vec<GraphicsDevice>,
#[allow(dead_code)]
other: Vec<GraphicsDevice>,
@@ -23,6 +23,8 @@ pub struct CtrlGraphics {
}
trait Dbus {
fn vendor(&self) -> String;
fn power(&self) -> String;
fn set_vendor(&mut self, vendor: String);
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
fn notify_action(&self, action: &str) -> zbus::Result<()>;
@@ -34,6 +36,18 @@ use std::convert::TryInto;
#[cfg(feature = "use-zbus")]
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlGraphics {
fn vendor(&self) -> String {
Self::get_vendor()
.map_err(|err| format!("Get vendor failed: {}", err))
.unwrap()
}
fn power(&self) -> String {
Self::get_runtime_status()
.map_err(|err| format!("Get power status failed: {}", err))
.unwrap()
}
fn set_vendor(&mut self, vendor: String) {
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
let action = self.set(tmp).unwrap_or_else(|err| {
@@ -113,17 +127,18 @@ impl CtrlGraphics {
cmd.arg("-u");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'update-initramfs'");
} else if Path::new(DRACUT_PATH).exists() {
let mut cmd = Command::new("dracut");
cmd.arg("-f");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'dracut'");
}
// } else if Path::new(DRACUT_PATH).exists() {
// let mut cmd = Command::new("dracut");
// cmd.arg("-f");
// initfs_cmd = Some(cmd);
// info!("Using initramfs update command 'dracut'");
// }
Ok(CtrlGraphics {
bus,
amd,
intel,
_amd: amd,
_intel: intel,
nvidia,
other,
initfs_cmd,
@@ -143,9 +158,9 @@ impl CtrlGraphics {
Ok(())
}
fn can_switch(&self) -> bool {
!self.nvidia.is_empty() && (!self.intel.is_empty() || !self.amd.is_empty())
}
// fn can_switch(&self) -> bool {
// !self.nvidia.is_empty() && (!self.intel.is_empty() || !self.amd.is_empty())
// }
fn get_prime_discrete() -> Result<String, GfxError> {
let s = std::fs::read_to_string(PRIME_DISCRETE_PATH)
@@ -168,6 +183,7 @@ impl CtrlGraphics {
.iter()
.any(|module| module.name == "nouveau" || module.name == "nvidia")
{
info!("nvidia or nouveau module found");
let mode = match Self::get_prime_discrete() {
Ok(m) => m,
Err(_) => "nvidia".to_string(),
@@ -181,6 +197,7 @@ impl CtrlGraphics {
"nvidia".to_string()
}
} else {
info!("No dGPU driver (nouveau or nvidia) loaded");
"integrated".to_string()
};
@@ -212,10 +229,10 @@ impl CtrlGraphics {
// Switching from hybrid to/from nvidia shouldn't require a ramdisk update
// or a reboot.
let switching_prime_modes = Self::is_switching_prime_modes(&vendor)?;
let no_reboot = Self::is_switching_prime_modes(&vendor)?;
{
info!("Creating {}", MODPROBE_PATH);
info!("Writing {}", MODPROBE_PATH);
let mut file = std::fs::OpenOptions::new()
.create(true)
@@ -239,7 +256,7 @@ impl CtrlGraphics {
.map_err(|err| GfxError::Write(MODPROBE_PATH.into(), err))?;
}
info!("Creating {}", PRIMARY_GPU_XORG_PATH);
info!("Writing {}", PRIMARY_GPU_XORG_PATH);
// begin section for non-separated Nvidia xorg modules
// eg, not put in their own directory
@@ -283,7 +300,7 @@ impl CtrlGraphics {
}
let mut required_action = GfxCtrlAction::None;
if !switching_prime_modes {
if !no_reboot {
info!("Updating initramfs");
if let Some(cmd) = self.initfs_cmd.as_mut() {
let status = cmd
@@ -296,18 +313,24 @@ impl CtrlGraphics {
}
}
required_action = GfxCtrlAction::Reboot;
} else if switching_prime_modes {
} else if no_reboot {
required_action = GfxCtrlAction::RestartX;
}
Ok(required_action.into())
}
pub fn get_power(&self) -> Option<bool> {
if self.can_switch() {
return Some(self.nvidia.iter().any(GraphicsDevice::exists));
}
None
// pub fn get_power(&self) -> Option<bool> {
// if self.can_switch() {
// return Some(self.nvidia.iter().any(GraphicsDevice::exists));
// }
// None
// }
pub fn get_runtime_status() -> Result<String, GfxError> {
const PATH: &str = "/sys/bus/pci/devices/0000:01:00.0/power/runtime_status";
let buf = std::fs::read_to_string(PATH)
.map_err(|err| GfxError::Read(PATH.into(), err))?;
Ok(buf)
}
fn set_power(&self, power: bool) -> Result<(), GfxError> {

View File

@@ -9,7 +9,7 @@ pub mod system;
const PRIME_DISCRETE_PATH: &str = "/etc/prime-discrete";
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
const DRACUT_PATH: &str = "/usr/bin/dracut";
//const DRACUT_PATH: &str = "/usr/bin/dracut";
static MODPROBE_NVIDIA: &[u8] = MODPROBE_HYBRID;
@@ -54,4 +54,5 @@ static PRIMARY_GPU_NVIDIA: &[u8] = br#"
Option "PrimaryGPU" "true""#;
static PRIMARY_GPU_END: &[u8] = br#"
EndSection"#;
EndSection"#;

12
data/asusd-alt.service Normal file
View File

@@ -0,0 +1,12 @@
[Unit]
Description=ASUS Notebook Control
After=basic.target syslog.target
[Service]
ExecStart=/usr/bin/asusd
Restart=on-failure
Type=dbus
BusName=org.asuslinux.Daemon
[Install]
WantedBy=multi-user.target

View File

@@ -3,6 +3,11 @@ prod_family = "Zephyrus S"
board_names = ["GX502", "GX701", "G531", "GL531", "G532"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
[[led_modes]]
prod_family = "Zephyrus M"
board_names = ["GU502GV"]
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
[[led_modes]]
prod_family = "Zephyrus"
board_names = ["GM501GM", "GX531"]