mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a63dce85f | |||
| 01386599f4 | |||
| 4310b4b742 | |||
| 89f4dd6ec4 | |||
| 85e0b79fb9 | |||
| fba5f26f7e |
@@ -5,6 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
# [3.1.6] - 2021-03-11
|
||||||
|
### Changed
|
||||||
|
- Graphics switching will now wait until all users logged out before switching
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Further tweaks to gfx switching
|
||||||
|
- More logging on gfx switching
|
||||||
|
- Filter bios help according to supported modes
|
||||||
|
- Prevent gfx mode switching if in dedicated/G-Sync mode
|
||||||
|
|
||||||
# [3.1.4] - 2021-03-10
|
# [3.1.4] - 2021-03-10
|
||||||
### Changed
|
### Changed
|
||||||
- Notify through dbus if user changes profile manually
|
- Notify through dbus if user changes profile manually
|
||||||
|
|||||||
Generated
+2
-2
@@ -33,7 +33,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asusctl"
|
name = "asusctl"
|
||||||
version = "3.1.1"
|
version = "3.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"daemon",
|
"daemon",
|
||||||
"gumdrop",
|
"gumdrop",
|
||||||
@@ -188,7 +188,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daemon"
|
name = "daemon"
|
||||||
version = "3.1.4"
|
version = "3.1.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"intel-pstate",
|
"intel-pstate",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asusctl"
|
name = "asusctl"
|
||||||
version = "3.1.1"
|
version = "3.1.3"
|
||||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
+124
-91
@@ -1,15 +1,10 @@
|
|||||||
use daemon::{
|
use daemon::{
|
||||||
ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions,
|
ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions,
|
||||||
ctrl_supported::SupportedFunctions,
|
ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions,
|
||||||
};
|
};
|
||||||
use gumdrop::{Opt, Options};
|
use gumdrop::{Opt, Options};
|
||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::{
|
use rog_types::{anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN}, aura_modes::AuraModes, cli_options::{AniMeActions, AniMeStatusValue, LedBrightness, SetAuraBuiltin}, gfx_vendors::GfxVendors, profile::{FanLevel, ProfileCommand, ProfileEvent}};
|
||||||
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
|
|
||||||
cli_options::{AniMeActions, AniMeStatusValue, LedBrightness, SetAuraBuiltin},
|
|
||||||
gfx_vendors::GfxVendors,
|
|
||||||
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
|
||||||
};
|
|
||||||
use std::env::args;
|
use std::env::args;
|
||||||
use yansi_term::Colour::Green;
|
use yansi_term::Colour::Green;
|
||||||
use yansi_term::Colour::Red;
|
use yansi_term::Colour::Red;
|
||||||
@@ -97,11 +92,15 @@ struct AniMeCommand {
|
|||||||
struct BiosCommand {
|
struct BiosCommand {
|
||||||
#[options(help = "print help message")]
|
#[options(help = "print help message")]
|
||||||
help: bool,
|
help: bool,
|
||||||
#[options(meta = "", no_long, help = "toggle bios POST sound")]
|
#[options(meta = "", no_long, help = "set bios POST sound <true/false>")]
|
||||||
post_sound_set: Option<bool>,
|
post_sound_set: Option<bool>,
|
||||||
#[options(no_long, help = "read bios POST sound")]
|
#[options(no_long, help = "read bios POST sound")]
|
||||||
post_sound_get: bool,
|
post_sound_get: bool,
|
||||||
#[options(meta = "", no_long, help = "toggle GPU to/from dedicated mode")]
|
#[options(
|
||||||
|
meta = "",
|
||||||
|
no_long,
|
||||||
|
help = "activate dGPU dedicated/G-Sync <true/false>"
|
||||||
|
)]
|
||||||
dedicated_gfx_set: Option<bool>,
|
dedicated_gfx_set: Option<bool>,
|
||||||
#[options(no_long, help = "get GPU mode")]
|
#[options(no_long, help = "get GPU mode")]
|
||||||
dedicated_gfx_get: bool,
|
dedicated_gfx_get: bool,
|
||||||
@@ -149,7 +148,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
match parsed.command {
|
match parsed.command {
|
||||||
Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?,
|
Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?,
|
||||||
Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.fan_cpu_ctrl, &cmd)?,
|
Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.fan_cpu_ctrl, &cmd)?,
|
||||||
Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, cmd)?,
|
Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, &supported.rog_bios_ctrl, cmd)?,
|
||||||
Some(CliCommand::AniMe(cmd)) => {
|
Some(CliCommand::AniMe(cmd)) => {
|
||||||
if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help {
|
if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help {
|
||||||
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||||
@@ -173,43 +172,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(CliCommand::Bios(cmd)) => {
|
Some(CliCommand::Bios(cmd)) => handle_bios_option(&dbus, &supported.rog_bios_ctrl, &cmd)?,
|
||||||
if (cmd.dedicated_gfx_set.is_none()
|
|
||||||
&& !cmd.dedicated_gfx_get
|
|
||||||
&& cmd.post_sound_set.is_none()
|
|
||||||
&& !cmd.post_sound_get)
|
|
||||||
|| cmd.help
|
|
||||||
{
|
|
||||||
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
|
||||||
if let Some(lst) = cmd.self_command_list() {
|
|
||||||
println!("\n{}", lst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(opt) = cmd.post_sound_set {
|
|
||||||
dbus.proxies().rog_bios().set_post_sound(opt)?;
|
|
||||||
}
|
|
||||||
if cmd.post_sound_get {
|
|
||||||
let res = if dbus.proxies().rog_bios().get_post_sound()? == 1 {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
println!("Bios POST sound on: {}", res);
|
|
||||||
}
|
|
||||||
if let Some(opt) = cmd.dedicated_gfx_set {
|
|
||||||
dbus.proxies().rog_bios().set_dedicated_gfx(opt)?;
|
|
||||||
}
|
|
||||||
if cmd.dedicated_gfx_get {
|
|
||||||
let res = if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
println!("Bios dedicated GPU on: {}", res);
|
|
||||||
println!("You must reboot your system to activate dedicated Nvidia mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
if (!parsed.show_supported
|
if (!parsed.show_supported
|
||||||
&& parsed.kbd_bright.is_none()
|
&& parsed.kbd_bright.is_none()
|
||||||
@@ -268,13 +231,19 @@ fn print_supported_help(supported: &SupportedFunctions, parsed: &CLIStart) {
|
|||||||
let commands: Vec<String> = CliCommand::usage().lines().map(|s| s.to_string()).collect();
|
let commands: Vec<String> = CliCommand::usage().lines().map(|s| s.to_string()).collect();
|
||||||
println!("\nCommands available");
|
println!("\nCommands available");
|
||||||
for line in commands.iter().filter(|line| {
|
for line in commands.iter().filter(|line| {
|
||||||
if line.contains("profile") && !supported.fan_cpu_ctrl.stock_fan_modes && !supported.fan_cpu_ctrl.fan_curve_set {
|
if line.contains("profile")
|
||||||
|
&& !supported.fan_cpu_ctrl.stock_fan_modes
|
||||||
|
&& !supported.fan_cpu_ctrl.fan_curve_set
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if line.contains("led-mode") && supported.keyboard_led.stock_led_modes.is_none() {
|
if line.contains("led-mode") && supported.keyboard_led.stock_led_modes.is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if line.contains("bios") && (!supported.rog_bios_ctrl.dedicated_gfx_toggle || !supported.rog_bios_ctrl.post_sound_toggle) {
|
if line.contains("bios")
|
||||||
|
&& (!supported.rog_bios_ctrl.dedicated_gfx_toggle
|
||||||
|
|| !supported.rog_bios_ctrl.post_sound_toggle)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if line.contains("anime") && !supported.anime_ctrl.0 {
|
if line.contains("anime") && !supported.anime_ctrl.0 {
|
||||||
@@ -294,35 +263,38 @@ fn print_supported_help(supported: &SupportedFunctions, parsed: &CLIStart) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn do_gfx(
|
fn do_gfx(
|
||||||
dbus_client: &AuraDbusClient,
|
dbus: &AuraDbusClient,
|
||||||
|
supported: &RogBiosSupportedFunctions,
|
||||||
command: GraphicsCommand,
|
command: GraphicsCommand,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if command.mode.is_none() || command.help {
|
if command.mode.is_none() && !command.get && !command.pow && !command.force || command.help {
|
||||||
println!("{}", command.self_usage());
|
println!("{}", command.self_usage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mode) = command.mode {
|
if let Some(mode) = command.mode {
|
||||||
println!("Changing graphics modes...");
|
if supported.dedicated_gfx_toggle {
|
||||||
println!("If this takes longer than 30s, ctrl+c then check `journalctl -b -u asusd`");
|
if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 {
|
||||||
|
println!("You can not change modes until you turn dedicated/G-Sync off and reboot");
|
||||||
if do_gfx_action(
|
std::process::exit(-1);
|
||||||
command.force,
|
}
|
||||||
"This will restart your display-manager. Please save all work!",
|
|
||||||
"Setting graphics mode...",
|
|
||||||
) {
|
|
||||||
dbus_client.proxies().gfx().gfx_write_mode(mode.into())?;
|
|
||||||
let res = dbus_client.gfx_wait_changed()?;
|
|
||||||
println!("{}", res);
|
|
||||||
std::process::exit(1)
|
|
||||||
}
|
}
|
||||||
std::process::exit(-1)
|
|
||||||
|
println!(
|
||||||
|
"Your display-manager will restart in requested mode when all users are logged out"
|
||||||
|
);
|
||||||
|
println!("If anything fails check `journalctl -b -u asusd`");
|
||||||
|
|
||||||
|
dbus.proxies().gfx().gfx_write_mode(mode.into())?;
|
||||||
|
let res = dbus.gfx_wait_changed()?;
|
||||||
|
println!("{}", res);
|
||||||
|
std::process::exit(0)
|
||||||
}
|
}
|
||||||
if command.get {
|
if command.get {
|
||||||
let res = dbus_client.proxies().gfx().gfx_get_mode()?;
|
let res = dbus.proxies().gfx().gfx_get_mode()?;
|
||||||
println!("Current graphics mode: {}", res);
|
println!("Current graphics mode: {}", res);
|
||||||
}
|
}
|
||||||
if command.pow {
|
if command.pow {
|
||||||
let res = dbus_client.proxies().gfx().gfx_get_pwr()?;
|
let res = dbus.proxies().gfx().gfx_get_pwr()?;
|
||||||
if res.contains("active") {
|
if res.contains("active") {
|
||||||
println!("Current power status: {}", Red.paint(&format!("{}", res)));
|
println!("Current power status: {}", Red.paint(&format!("{}", res)));
|
||||||
} else {
|
} else {
|
||||||
@@ -332,21 +304,6 @@ fn do_gfx(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_gfx_action(no_confirm: bool, ask_msg: &str, ok_msg: &str) -> bool {
|
|
||||||
println!("{}", Red.paint(&format!("{} Continue?", ask_msg)));
|
|
||||||
|
|
||||||
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' || no_confirm {
|
|
||||||
println!("{}", Green.paint(&format!("{}", ok_msg)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_led_mode(
|
fn handle_led_mode(
|
||||||
dbus: &AuraDbusClient,
|
dbus: &AuraDbusClient,
|
||||||
supported: &LedSupportedFunctions,
|
supported: &LedSupportedFunctions,
|
||||||
@@ -359,10 +316,14 @@ fn handle_led_mode(
|
|||||||
println!("{}\n", mode.self_usage());
|
println!("{}\n", mode.self_usage());
|
||||||
println!("Commands available");
|
println!("Commands available");
|
||||||
|
|
||||||
let commands: Vec<String> = LedModeCommand::command_list().unwrap().lines().map(|s| s.to_string()).collect();
|
let commands: Vec<String> = LedModeCommand::command_list()
|
||||||
|
.unwrap()
|
||||||
|
.lines()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect();
|
||||||
for (_, command) in commands.iter().enumerate().filter(|(mode_num, _)| {
|
for (_, command) in commands.iter().enumerate().filter(|(mode_num, _)| {
|
||||||
if let Some(modes) = supported.stock_led_modes.as_ref() {
|
if let Some(modes) = supported.stock_led_modes.as_ref() {
|
||||||
return modes.contains(&(*mode_num as u8))
|
return modes.contains(&(*mode_num as u8));
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}) {
|
}) {
|
||||||
@@ -370,17 +331,23 @@ fn handle_led_mode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
println!("\nHelp can also be requested on modes, e.g: static --help");
|
println!("\nHelp can also be requested on modes, e.g: static --help");
|
||||||
std::process::exit(1);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode.next_mode && mode.prev_mode {
|
if mode.next_mode && mode.prev_mode {
|
||||||
println!("Please specify either next or previous")
|
println!("Please specify either next or previous");
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
if mode.next_mode {
|
if mode.next_mode {
|
||||||
dbus.proxies().led().next_led_mode()?;
|
dbus.proxies().led().next_led_mode()?;
|
||||||
} else if mode.prev_mode {
|
} else if mode.prev_mode {
|
||||||
dbus.proxies().led().prev_led_mode()?;
|
dbus.proxies().led().prev_led_mode()?;
|
||||||
} else if let Some(command) = mode.command.as_ref() {
|
} else if let Some(mode) = mode.command.as_ref() {
|
||||||
dbus.proxies().led().set_led_mode(&command.into())?
|
if mode.help_requested() {
|
||||||
|
println!("{}", mode.self_usage());
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
dbus.proxies().led().set_led_mode(&<AuraModes>::from(mode))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -402,10 +369,14 @@ fn handle_profile(
|
|||||||
if !cmd.help {
|
if !cmd.help {
|
||||||
println!("Missing arg or command\n");
|
println!("Missing arg or command\n");
|
||||||
}
|
}
|
||||||
let usage: Vec<String> = ProfileCommand::usage().lines().map(|s| s.to_string()).collect();
|
let usage: Vec<String> = ProfileCommand::usage()
|
||||||
for line in usage.iter().filter(|line| {
|
.lines()
|
||||||
!(line.contains("--curve") && !supported.fan_curve_set)
|
.map(|s| s.to_string())
|
||||||
}) {
|
.collect();
|
||||||
|
for line in usage
|
||||||
|
.iter()
|
||||||
|
.filter(|line| !(line.contains("--curve") && !supported.fan_curve_set))
|
||||||
|
{
|
||||||
println!("{}", line);
|
println!("{}", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,3 +395,65 @@ fn handle_profile(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_bios_option(
|
||||||
|
dbus: &AuraDbusClient,
|
||||||
|
supported: &RogBiosSupportedFunctions,
|
||||||
|
cmd: &BiosCommand,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
{
|
||||||
|
if (cmd.dedicated_gfx_set.is_none()
|
||||||
|
&& !cmd.dedicated_gfx_get
|
||||||
|
&& cmd.post_sound_set.is_none()
|
||||||
|
&& !cmd.post_sound_get)
|
||||||
|
|| cmd.help
|
||||||
|
{
|
||||||
|
println!("Missing arg or command\n");
|
||||||
|
|
||||||
|
let usage: Vec<String> = BiosCommand::usage()
|
||||||
|
.lines()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for line in usage.iter().filter(|line| {
|
||||||
|
!(line.contains("sound") && !supported.post_sound_toggle)
|
||||||
|
|| !(line.contains("GPU") && !supported.dedicated_gfx_toggle)
|
||||||
|
}) {
|
||||||
|
println!("{}", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(opt) = cmd.post_sound_set {
|
||||||
|
dbus.proxies().rog_bios().set_post_sound(opt)?;
|
||||||
|
}
|
||||||
|
if cmd.post_sound_get {
|
||||||
|
let res = if dbus.proxies().rog_bios().get_post_sound()? == 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
println!("Bios POST sound on: {}", res);
|
||||||
|
}
|
||||||
|
if let Some(opt) = cmd.dedicated_gfx_set {
|
||||||
|
println!("Rebuilding initrd to include drivers");
|
||||||
|
dbus.proxies().rog_bios().set_dedicated_gfx(opt)?;
|
||||||
|
println!("The mode change is not active until you reboot, on boot the bios will make the required change");
|
||||||
|
if opt {
|
||||||
|
println!(
|
||||||
|
"NOTE: on reboot your display manager will be forced to use Nvidia drivers"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("NOTE: after reboot you can then select regular graphics modes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cmd.dedicated_gfx_get {
|
||||||
|
let res = if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
println!("Bios dedicated GPU on: {}", res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "daemon"
|
name = "daemon"
|
||||||
version = "3.1.4"
|
version = "3.1.6"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["Luke <luke@ljones.dev>"]
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
@@ -40,4 +40,4 @@ toml = "^0.5"
|
|||||||
sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
||||||
rog_fan_curve = { version = "0.1", features = ["serde"] }
|
rog_fan_curve = { version = "0.1", features = ["serde"] }
|
||||||
# cpu power management
|
# cpu power management
|
||||||
intel-pstate = "^0.2"
|
intel-pstate = "^0.2"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use std::error;
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::{error, process::ExitStatus};
|
||||||
|
|
||||||
use crate::error::RogError;
|
use crate::error::RogError;
|
||||||
|
|
||||||
@@ -7,7 +7,9 @@ use crate::error::RogError;
|
|||||||
pub enum GfxError {
|
pub enum GfxError {
|
||||||
ParseVendor,
|
ParseVendor,
|
||||||
Bus(String, std::io::Error),
|
Bus(String, std::io::Error),
|
||||||
DisplayManager(String),
|
DisplayManagerAction(String, ExitStatus),
|
||||||
|
DisplayManagerTimeout(String),
|
||||||
|
GsyncModeActive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for GfxError {
|
impl fmt::Display for GfxError {
|
||||||
@@ -16,7 +18,16 @@ impl fmt::Display for GfxError {
|
|||||||
match self {
|
match self {
|
||||||
GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
|
GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
|
||||||
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
|
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
|
||||||
GfxError::DisplayManager(detail) => write!(f, "Display manager: {}", detail),
|
GfxError::DisplayManagerAction(action, status) => {
|
||||||
|
write!(f, "Display-manager action {} failed: {}", action, status)
|
||||||
|
}
|
||||||
|
GfxError::DisplayManagerTimeout(state) => {
|
||||||
|
write!(f, "Timed out waiting for display-manager {} state", state)
|
||||||
|
}
|
||||||
|
GfxError::GsyncModeActive => write!(
|
||||||
|
f,
|
||||||
|
"Can not switch gfx modes when dedicated/G-Sync mode is active"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+185
-55
@@ -1,11 +1,13 @@
|
|||||||
use ctrl_gfx::error::GfxError;
|
use ctrl_gfx::error::GfxError;
|
||||||
use ctrl_gfx::*;
|
use ctrl_gfx::*;
|
||||||
|
use ctrl_rog_bios::CtrlRogBios;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_types::gfx_vendors::GfxVendors;
|
use rog_types::gfx_vendors::GfxVendors;
|
||||||
use std::iter::FromIterator;
|
use session_manager::{are_gfx_sessions_alive, get_sessions};
|
||||||
use std::process::Command;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::{io::Write, ops::Add, path::Path};
|
use std::{io::Write, ops::Add, path::Path};
|
||||||
|
use std::{iter::FromIterator, thread::JoinHandle};
|
||||||
|
use std::{process::Command, thread::sleep, time::Duration};
|
||||||
|
use std::{str::FromStr, sync::mpsc};
|
||||||
use std::{sync::Arc, sync::Mutex};
|
use std::{sync::Arc, sync::Mutex};
|
||||||
use sysfs_class::{PciDevice, SysClass};
|
use sysfs_class::{PciDevice, SysClass};
|
||||||
use system::{GraphicsDevice, PciBus};
|
use system::{GraphicsDevice, PciBus};
|
||||||
@@ -21,6 +23,7 @@ pub struct CtrlGraphics {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
other: Vec<GraphicsDevice>,
|
other: Vec<GraphicsDevice>,
|
||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
|
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Dbus {
|
trait Dbus {
|
||||||
@@ -47,15 +50,15 @@ impl Dbus for CtrlGraphics {
|
|||||||
|
|
||||||
fn set_vendor(&mut self, vendor: String) {
|
fn set_vendor(&mut self, vendor: String) {
|
||||||
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
|
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
|
||||||
info!("Switching gfx mode to {}", vendor);
|
info!("GFX: Switching gfx mode to {}", vendor);
|
||||||
let msg = self.set_gfx_config(tmp).unwrap_or_else(|err| {
|
let msg = self.set_gfx_config(tmp).unwrap_or_else(|err| {
|
||||||
error!("{}", err);
|
error!("GFX: {}", err);
|
||||||
format!("Failed: {}", err.to_string())
|
format!("Failed: {}", err.to_string())
|
||||||
});
|
});
|
||||||
self.notify_gfx(&vendor)
|
self.notify_gfx(&vendor)
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||||
self.notify_action(&msg)
|
self.notify_action(&msg)
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("GFX: {}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +79,7 @@ impl ZbusAdd for CtrlGraphics {
|
|||||||
self,
|
self,
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
warn!("CtrlGraphics: add_to_server {}", err);
|
warn!("GFX: CtrlGraphics: add_to_server {}", err);
|
||||||
err
|
err
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
@@ -86,7 +89,7 @@ impl ZbusAdd for CtrlGraphics {
|
|||||||
impl Reloadable for CtrlGraphics {
|
impl Reloadable for CtrlGraphics {
|
||||||
fn reload(&mut self) -> Result<(), RogError> {
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
self.auto_power()?;
|
self.auto_power()?;
|
||||||
info!("Reloaded gfx mode: {:?}", self.get_gfx_mode()?);
|
info!("GFX: Reloaded gfx mode: {:?}", self.get_gfx_mode()?);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +98,7 @@ impl CtrlGraphics {
|
|||||||
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
|
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
|
||||||
let bus = PciBus::new()?;
|
let bus = PciBus::new()?;
|
||||||
|
|
||||||
info!("Rescanning PCI bus");
|
info!("GFX: Rescanning PCI bus");
|
||||||
bus.rescan()?;
|
bus.rescan()?;
|
||||||
|
|
||||||
let devs = PciDevice::all()?;
|
let devs = PciDevice::all()?;
|
||||||
@@ -106,7 +109,7 @@ impl CtrlGraphics {
|
|||||||
for func in devs.iter() {
|
for func in devs.iter() {
|
||||||
if let Some(func_slot) = func.id().split('.').next() {
|
if let Some(func_slot) = func.id().split('.').next() {
|
||||||
if func_slot == parent_slot {
|
if func_slot == parent_slot {
|
||||||
info!("{}: Function for {}", func.id(), parent.id());
|
info!("GFX: {}: Function for {}", func.id(), parent.id());
|
||||||
functions.push(func.clone());
|
functions.push(func.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,19 +127,19 @@ impl CtrlGraphics {
|
|||||||
if 0x03 == (c >> 16) & 0xFF {
|
if 0x03 == (c >> 16) & 0xFF {
|
||||||
match dev.vendor()? {
|
match dev.vendor()? {
|
||||||
0x1002 => {
|
0x1002 => {
|
||||||
info!("{}: AMD graphics", dev.id());
|
info!("GFX: {}: AMD graphics", dev.id());
|
||||||
amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
}
|
}
|
||||||
0x10DE => {
|
0x10DE => {
|
||||||
info!("{}: NVIDIA graphics", dev.id());
|
info!("GFX: {}: NVIDIA graphics", dev.id());
|
||||||
nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
}
|
}
|
||||||
0x8086 => {
|
0x8086 => {
|
||||||
info!("{}: Intel graphics", dev.id());
|
info!("GFX: {}: Intel graphics", dev.id());
|
||||||
intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
}
|
}
|
||||||
vendor => {
|
vendor => {
|
||||||
info!("{}: Other({:X}) graphics", dev.id(), vendor);
|
info!("GFX: {}: Other({:X}) graphics", dev.id(), vendor);
|
||||||
other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,11 +153,20 @@ impl CtrlGraphics {
|
|||||||
nvidia,
|
nvidia,
|
||||||
other,
|
other,
|
||||||
config,
|
config,
|
||||||
|
thread_kill: Arc::new(Mutex::new(None)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_gfx_mode(&self, vendor: GfxVendors) -> Result<(), RogError> {
|
pub fn bus(&self) -> PciBus {
|
||||||
if let Ok(mut config) = self.config.lock() {
|
self.bus.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn devices(&self) -> Vec<GraphicsDevice> {
|
||||||
|
self.nvidia.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) -> Result<(), RogError> {
|
||||||
|
if let Ok(mut config) = config.lock() {
|
||||||
config.gfx_mode = vendor.clone();
|
config.gfx_mode = vendor.clone();
|
||||||
config.write();
|
config.write();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -180,10 +192,10 @@ impl CtrlGraphics {
|
|||||||
|
|
||||||
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
|
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
|
||||||
let action = if vendor == GfxVendors::Nvidia {
|
let action = if vendor == GfxVendors::Nvidia {
|
||||||
info!("Enabling nvidia-fallback.service");
|
info!("GFX: Enabling nvidia-fallback.service");
|
||||||
"enable"
|
"enable"
|
||||||
} else {
|
} else {
|
||||||
info!("Disabling nvidia-fallback.service");
|
info!("GFX: Disabling nvidia-fallback.service");
|
||||||
"disable"
|
"disable"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -216,7 +228,7 @@ impl CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let file = XORG_PATH.to_string().add(XORG_FILE);
|
let file = XORG_PATH.to_string().add(XORG_FILE);
|
||||||
info!("Writing {}", file);
|
info!("GFX: Writing {}", file);
|
||||||
let mut file = std::fs::OpenOptions::new()
|
let mut file = std::fs::OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.truncate(true)
|
.truncate(true)
|
||||||
@@ -231,7 +243,7 @@ impl CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_modprobe_conf() -> Result<(), RogError> {
|
fn write_modprobe_conf() -> Result<(), RogError> {
|
||||||
info!("Writing {}", MODPROBE_PATH);
|
info!("GFX: Writing {}", MODPROBE_PATH);
|
||||||
|
|
||||||
let mut file = std::fs::OpenOptions::new()
|
let mut file = std::fs::OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
@@ -247,12 +259,12 @@ impl CtrlGraphics {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unbind_remove_nvidia(&self) -> Result<(), RogError> {
|
fn unbind_remove_nvidia(devices: &[GraphicsDevice]) -> Result<(), RogError> {
|
||||||
// Unbind NVIDIA graphics devices and their functions
|
// Unbind NVIDIA graphics devices and their functions
|
||||||
let unbinds = self.nvidia.iter().map(|dev| dev.unbind());
|
let unbinds = devices.iter().map(|dev| dev.unbind());
|
||||||
|
|
||||||
// Remove NVIDIA graphics devices and their functions
|
// Remove NVIDIA graphics devices and their functions
|
||||||
let removes = self.nvidia.iter().map(|dev| dev.remove());
|
let removes = devices.iter().map(|dev| dev.remove());
|
||||||
|
|
||||||
Result::from_iter(unbinds.chain(removes))
|
Result::from_iter(unbinds.chain(removes))
|
||||||
.map_err(|err| RogError::Command("device unbind error".into(), err))?;
|
.map_err(|err| RogError::Command("device unbind error".into(), err))?;
|
||||||
@@ -260,8 +272,28 @@ impl CtrlGraphics {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn log_uses_of_nvidia() {
|
||||||
|
// lsof /dev/nvidia*
|
||||||
|
let mut cmd = Command::new("lsof");
|
||||||
|
cmd.arg("/dev/nvidia*");
|
||||||
|
|
||||||
|
match cmd.output() {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
error!(
|
||||||
|
"Failed to list uses of nvidia devices: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
} else if output.status.success() {
|
||||||
|
warn!("GFX: {}", String::from_utf8_lossy(&output.stdout));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => error!("GFX: Failed to list uses of nvidia devices: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> {
|
fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> {
|
||||||
let mut cmd= Command::new(action);
|
let mut cmd = Command::new(action);
|
||||||
cmd.arg(driver);
|
cmd.arg(driver);
|
||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
@@ -269,29 +301,42 @@ impl CtrlGraphics {
|
|||||||
loop {
|
loop {
|
||||||
if count > MAX_TRIES {
|
if count > MAX_TRIES {
|
||||||
let msg = format!("{} {} failed for unknown reason", action, driver);
|
let msg = format!("{} {} failed for unknown reason", action, driver);
|
||||||
error!("{}", msg);
|
error!("GFX: {}", msg);
|
||||||
return Ok(()) //Err(RogError::Modprobe(msg));
|
return Ok(()); //Err(RogError::Modprobe(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = cmd
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
if output.stderr.ends_with("is not currently loaded\n".as_bytes()) {
|
if output
|
||||||
return Ok(())
|
.stderr
|
||||||
|
.ends_with("is not currently loaded\n".as_bytes())
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
|
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
|
||||||
let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr));
|
let msg = format!(
|
||||||
warn!("{}", msg);
|
"{} {} failed: {:?}",
|
||||||
warn!("It may be safe to ignore the above error, run `lsmod |grep nvidia` to confirm modules loaded");
|
action,
|
||||||
return Ok(())
|
driver,
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
warn!("GFX: {}", msg);
|
||||||
|
warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep nvidia` to confirm modules loaded");
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
if count >= MAX_TRIES {
|
if count >= MAX_TRIES {
|
||||||
let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr));
|
let msg = format!(
|
||||||
|
"{} {} failed: {:?}",
|
||||||
|
action,
|
||||||
|
driver,
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
return Err(RogError::Modprobe(msg));
|
return Err(RogError::Modprobe(msg));
|
||||||
}
|
}
|
||||||
} else if output.status.success() {
|
} else if output.status.success() {
|
||||||
return Ok(())
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
count += 1;
|
count += 1;
|
||||||
@@ -312,7 +357,7 @@ impl CtrlGraphics {
|
|||||||
"systemctl {} {} failed: {:?}",
|
"systemctl {} {} failed: {:?}",
|
||||||
action, DISPLAY_MANAGER, status
|
action, DISPLAY_MANAGER, status
|
||||||
);
|
);
|
||||||
return Err(GfxError::DisplayManager(msg).into());
|
return Err(GfxError::DisplayManagerAction(msg, status).into());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -334,24 +379,28 @@ impl CtrlGraphics {
|
|||||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
return Err(
|
return Err(GfxError::DisplayManagerTimeout(state.into()).into());
|
||||||
GfxError::DisplayManager(format!("display-manager timed out waiting for {} state", state).into()).into(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_vendor_tasks(&mut self, vendor: GfxVendors) -> Result<(), RogError> {
|
pub fn do_vendor_tasks(
|
||||||
|
vendor: GfxVendors,
|
||||||
|
devices: &[GraphicsDevice],
|
||||||
|
bus: &PciBus,
|
||||||
|
) -> Result<(), RogError> {
|
||||||
Self::write_xorg_conf(vendor)?;
|
Self::write_xorg_conf(vendor)?;
|
||||||
Self::write_modprobe_conf()?; // TODO: Not required here, should put in startup?
|
Self::write_modprobe_conf()?; // TODO: Not required here, should put in startup?
|
||||||
|
|
||||||
// Rescan before doing remove or add drivers
|
// Rescan before doing remove or add drivers
|
||||||
self.bus
|
bus.rescan()
|
||||||
.rescan()
|
|
||||||
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?;
|
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?;
|
||||||
|
|
||||||
match vendor {
|
match vendor {
|
||||||
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
|
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
|
||||||
for driver in NVIDIA_DRIVERS.iter() {
|
for driver in NVIDIA_DRIVERS.iter() {
|
||||||
Self::do_driver_action(driver, "modprobe")?;
|
Self::do_driver_action(driver, "modprobe").map_err(|err| {
|
||||||
|
Self::log_uses_of_nvidia();
|
||||||
|
err
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: compute mode, needs different setup
|
// TODO: compute mode, needs different setup
|
||||||
@@ -360,26 +409,105 @@ impl CtrlGraphics {
|
|||||||
for driver in NVIDIA_DRIVERS.iter() {
|
for driver in NVIDIA_DRIVERS.iter() {
|
||||||
Self::do_driver_action(driver, "rmmod")?;
|
Self::do_driver_action(driver, "rmmod")?;
|
||||||
}
|
}
|
||||||
self.unbind_remove_nvidia()?;
|
Self::unbind_remove_nvidia(&devices)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.save_gfx_mode(vendor)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Spools until all user sessions are ended
|
||||||
|
fn fire_starter(
|
||||||
|
vendor: GfxVendors,
|
||||||
|
devices: Vec<GraphicsDevice>,
|
||||||
|
bus: PciBus,
|
||||||
|
sessions: Vec<session_manager::Session>,
|
||||||
|
killer: mpsc::Receiver<bool>,
|
||||||
|
) -> Result<String, RogError> {
|
||||||
|
info!("GFX: display-manager thread started");
|
||||||
|
while are_gfx_sessions_alive(&sessions) {
|
||||||
|
if let Ok(stop) = killer.try_recv() {
|
||||||
|
if stop {
|
||||||
|
return Ok("Graphics mode change was cancelled".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sleep(Duration::from_millis(300));
|
||||||
|
}
|
||||||
|
info!("GFX: all graphical user sessions ended, continuing");
|
||||||
|
Self::do_display_manager_action("stop")?;
|
||||||
|
|
||||||
|
match Self::wait_display_manager_state("inactive") {
|
||||||
|
Ok(_) => info!("GFX: display-manager stopped"),
|
||||||
|
Err(err) => {
|
||||||
|
warn!("GFX: {}", err);
|
||||||
|
warn!("GFX: Retry stop display manager");
|
||||||
|
Self::do_display_manager_action("stop")?;
|
||||||
|
Self::wait_display_manager_state("inactive")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::do_vendor_tasks(vendor, &devices, &bus)?;
|
||||||
|
Self::do_display_manager_action("start")?;
|
||||||
|
|
||||||
|
if Self::wait_display_manager_state("active").is_err() {
|
||||||
|
error!("GFX: display-manager failed to start normally, attempting restart");
|
||||||
|
Self::do_display_manager_action("restart")?;
|
||||||
|
Self::wait_display_manager_state("active")?;
|
||||||
|
}
|
||||||
|
info!("GFX: display-manager started");
|
||||||
|
|
||||||
|
let v: &str = vendor.into();
|
||||||
|
info!("GFX: Graphics mode changed to {} successfully", v);
|
||||||
|
Ok(format!("Graphics mode changed to {} successfully", v))
|
||||||
|
}
|
||||||
|
|
||||||
/// For manually calling (not on boot/startup)
|
/// For manually calling (not on boot/startup)
|
||||||
///
|
///
|
||||||
/// Will stop and start display manager without warning
|
/// Will stop and start display manager without warning
|
||||||
pub fn set_gfx_config(&mut self, vendor: GfxVendors) -> Result<String, RogError> {
|
pub fn set_gfx_config(&mut self, vendor: GfxVendors) -> Result<String, RogError> {
|
||||||
Self::do_display_manager_action("stop")?;
|
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
|
||||||
Self::wait_display_manager_state("inactive")?;
|
if gsync == 1 {
|
||||||
self.do_vendor_tasks(vendor)?;
|
return Err(GfxError::GsyncModeActive.into());
|
||||||
Self::do_display_manager_action("start")?;
|
}
|
||||||
if Self::wait_display_manager_state("active").is_err() {
|
|
||||||
Self::do_display_manager_action("restart")?;
|
|
||||||
}
|
}
|
||||||
Self::wait_display_manager_state("active")?;
|
|
||||||
|
if let Ok(lock) = self.thread_kill.lock() {
|
||||||
|
if let Some(tx) = lock.as_ref() {
|
||||||
|
// Cancel the running thread
|
||||||
|
info!("GFX: Cancelling previous thread");
|
||||||
|
tx.send(true)
|
||||||
|
.map_err(|err| {
|
||||||
|
warn!("GFX: {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let devices = self.nvidia.clone();
|
||||||
|
let bus = self.bus.clone();
|
||||||
|
let sessions = get_sessions().unwrap();
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
if let Ok(mut lock) = self.thread_kill.lock() {
|
||||||
|
*lock = Some(tx);
|
||||||
|
}
|
||||||
|
let killer = self.thread_kill.clone();
|
||||||
|
|
||||||
|
// Save selected mode in case of reboot
|
||||||
|
Self::save_gfx_mode(vendor, self.config.clone())?;
|
||||||
|
|
||||||
|
let _join: JoinHandle<()> = std::thread::spawn(move || {
|
||||||
|
Self::fire_starter(vendor, devices, bus, sessions, rx)
|
||||||
|
.map_err(|err| {
|
||||||
|
error!("GFX: {}", err);
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
// clear the tx/rx when done
|
||||||
|
if let Ok(mut lock) = killer.try_lock() {
|
||||||
|
*lock = None;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: undo if failed? Save last mode, catch errors...
|
// TODO: undo if failed? Save last mode, catch errors...
|
||||||
let v: &str = vendor.into();
|
let v: &str = vendor.into();
|
||||||
Ok(format!("Graphics mode changed to {} successfully", v))
|
Ok(format!("Graphics mode changed to {} successfully", v))
|
||||||
@@ -390,12 +518,12 @@ impl CtrlGraphics {
|
|||||||
// // Switch to dedicated if config says to do so
|
// // Switch to dedicated if config says to do so
|
||||||
// if config.gfx_nv_mode_is_dedicated && vendor == GfxVendors::Nvidia {
|
// if config.gfx_nv_mode_is_dedicated && vendor == GfxVendors::Nvidia {
|
||||||
// CtrlRogBios::set_gfx_mode(true)
|
// CtrlRogBios::set_gfx_mode(true)
|
||||||
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
// .unwrap_or_else(|err| warn!("GFX: Gfx controller: {}", err));
|
||||||
// } else if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
// } else if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
||||||
// // otherwise if switching to non-Nvidia mode turn off dedicated mode
|
// // otherwise if switching to non-Nvidia mode turn off dedicated mode
|
||||||
// if ded == 1 && vendor != GfxVendors::Nvidia {
|
// if ded == 1 && vendor != GfxVendors::Nvidia {
|
||||||
// CtrlRogBios::set_gfx_mode(false)
|
// CtrlRogBios::set_gfx_mode(false)
|
||||||
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
// .unwrap_or_else(|err| warn!("GFX: Gfx controller: {}", err));
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
@@ -403,7 +531,9 @@ impl CtrlGraphics {
|
|||||||
|
|
||||||
fn auto_power(&mut self) -> Result<(), RogError> {
|
fn auto_power(&mut self) -> Result<(), RogError> {
|
||||||
let vendor = self.get_gfx_mode()?;
|
let vendor = self.get_gfx_mode()?;
|
||||||
self.do_vendor_tasks(vendor)?;
|
let devices = self.nvidia.clone();
|
||||||
|
let bus = self.bus.clone();
|
||||||
|
Self::do_vendor_tasks(vendor, &devices, &bus)?;
|
||||||
Self::toggle_fallback_service(vendor)?;
|
Self::toggle_fallback_service(vendor)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ const DISPLAY_MANAGER: &str = "display-manager.service";
|
|||||||
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
|
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
|
||||||
|
|
||||||
static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd
|
static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd
|
||||||
|
# If you have issues with i2c_nvidia_gpu, copy the 2 lines below to a
|
||||||
|
# new blacklist file and uncomment
|
||||||
#blacklist i2c_nvidia_gpu
|
#blacklist i2c_nvidia_gpu
|
||||||
#alias i2c_nvidia_gpu off
|
#alias i2c_nvidia_gpu off
|
||||||
blacklist nouveau
|
blacklist nouveau
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ impl Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct PciBus {
|
pub struct PciBus {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
@@ -56,6 +57,7 @@ impl PciBus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct GraphicsDevice {
|
pub struct GraphicsDevice {
|
||||||
_id: String,
|
_id: String,
|
||||||
functions: Vec<PciDevice>,
|
functions: Vec<PciDevice>,
|
||||||
|
|||||||
@@ -136,9 +136,7 @@ impl CtrlRogBios {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(CtrlRogBios {
|
Ok(CtrlRogBios { _config: config })
|
||||||
_config: config,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_path_mutable(path: &str) -> Result<(), RogError> {
|
fn set_path_mutable(path: &str) -> Result<(), RogError> {
|
||||||
@@ -271,6 +269,7 @@ impl CtrlRogBios {
|
|||||||
} else if Path::new(DRACUT_PATH).exists() {
|
} else if Path::new(DRACUT_PATH).exists() {
|
||||||
let mut cmd = Command::new("dracut");
|
let mut cmd = Command::new("dracut");
|
||||||
cmd.arg("-f");
|
cmd.arg("-f");
|
||||||
|
cmd.arg("-q");
|
||||||
initfs_cmd = Some(cmd);
|
initfs_cmd = Some(cmd);
|
||||||
info!("Using initramfs update command 'dracut'");
|
info!("Using initramfs update command 'dracut'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,9 +111,10 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
|
||||||
if let Ok(vendor) = ctrl.get_gfx_mode() {
|
if let Ok(vendor) = ctrl.get_gfx_mode() {
|
||||||
if ded == 1 && vendor != GfxVendors::Nvidia {
|
if ded == 1 && vendor != GfxVendors::Nvidia {
|
||||||
error!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||||
error!("You must reboot to enable Nvidia driver");
|
let devices = ctrl.devices();
|
||||||
ctrl.do_vendor_tasks(GfxVendors::Nvidia)?;
|
let bus = ctrl.bus();
|
||||||
|
CtrlGraphics::do_vendor_tasks(GfxVendors::Nvidia, &devices, &bus)?;
|
||||||
} else if ded == 0 {
|
} else if ded == 0 {
|
||||||
info!("Dedicated GFX toggle is off");
|
info!("Dedicated GFX toggle is off");
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -4,7 +4,7 @@ use rog_types::error::GraphicsError;
|
|||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::ctrl_gfx::error::GfxError;
|
use crate::{ctrl_gfx::error::GfxError, session_manager::SessionError};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RogError {
|
pub enum RogError {
|
||||||
@@ -28,6 +28,7 @@ pub enum RogError {
|
|||||||
Initramfs(String),
|
Initramfs(String),
|
||||||
Modprobe(String),
|
Modprobe(String),
|
||||||
Command(String, std::io::Error),
|
Command(String, std::io::Error),
|
||||||
|
Session(SessionError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for RogError {
|
impl fmt::Display for RogError {
|
||||||
@@ -54,6 +55,7 @@ impl fmt::Display for RogError {
|
|||||||
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
|
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
|
||||||
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
|
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
|
||||||
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
|
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
|
||||||
|
RogError::Session(detail) => write!(f, "Session error: {}", detail),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ pub mod laptops;
|
|||||||
/// Fetch all supported functions for the laptop
|
/// Fetch all supported functions for the laptop
|
||||||
pub mod ctrl_supported;
|
pub mod ctrl_supported;
|
||||||
|
|
||||||
|
pub mod session_manager;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
use crate::error::RogError;
|
use crate::error::RogError;
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
use log::{error, warn};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum SessionType {
|
||||||
|
X11,
|
||||||
|
Wayland,
|
||||||
|
TTY,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct UserSession {
|
||||||
|
pub session: String,
|
||||||
|
pub uid: u32,
|
||||||
|
pub user: String,
|
||||||
|
pub seat: String,
|
||||||
|
pub tty: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Session {
|
||||||
|
session_id: String,
|
||||||
|
session_type: SessionType,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn are_gfx_sessions_alive(sessions: &[Session]) -> bool {
|
||||||
|
for session in sessions {
|
||||||
|
match is_gfx_alive(session) {
|
||||||
|
Ok(alive) => {
|
||||||
|
if alive {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => warn!("Error checking sessions: {}", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_sessions() -> Result<Vec<Session>, SessionError> {
|
||||||
|
// loginctl list-sessions --no-legend
|
||||||
|
let mut cmd = Command::new("loginctl");
|
||||||
|
cmd.arg("list-sessions");
|
||||||
|
cmd.arg("--output");
|
||||||
|
cmd.arg("json");
|
||||||
|
|
||||||
|
let mut sessions = Vec::new();
|
||||||
|
|
||||||
|
match cmd.output() {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
error!(
|
||||||
|
"Couldn't get sessions: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
} else if output.status.success() {
|
||||||
|
if let Ok(data) = serde_json::from_slice::<Vec<UserSession>>(&output.stdout) {
|
||||||
|
for s in &data {
|
||||||
|
if let Ok(t) = get_session_type(&s.session) {
|
||||||
|
sessions.push(Session {
|
||||||
|
session_id: s.session.to_owned(),
|
||||||
|
session_type: t,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(sessions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => error!("Couldn't get sessions: {}", err),
|
||||||
|
}
|
||||||
|
Err(SessionError::NoSessions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_gfx_alive(session: &Session) -> Result<bool, SessionError> {
|
||||||
|
if session.session_type == SessionType::TTY {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let session_id = session.session_id.to_owned();
|
||||||
|
let mut cmd = Command::new("loginctl");
|
||||||
|
cmd.arg("show-session");
|
||||||
|
cmd.arg(&session_id);
|
||||||
|
cmd.arg("--property");
|
||||||
|
cmd.arg("Type");
|
||||||
|
|
||||||
|
match cmd.output() {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
let msg = String::from_utf8_lossy(&output.stderr);
|
||||||
|
if msg.contains("No session") {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
error!(
|
||||||
|
"Couldn't get session: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
} else if output.status.success() {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => error!("Couldn't get session: {}", err),
|
||||||
|
}
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_session_type(session_id: &str) -> Result<SessionType, SessionError> {
|
||||||
|
//loginctl show-session 2 --property Type
|
||||||
|
let mut cmd = Command::new("loginctl");
|
||||||
|
cmd.arg("show-session");
|
||||||
|
cmd.arg(session_id);
|
||||||
|
cmd.arg("--property");
|
||||||
|
cmd.arg("Type");
|
||||||
|
cmd.arg("--property");
|
||||||
|
cmd.arg("Class");
|
||||||
|
|
||||||
|
match cmd.output() {
|
||||||
|
Ok(output) => {
|
||||||
|
if !output.status.success() {
|
||||||
|
let msg = String::from_utf8_lossy(&output.stderr);
|
||||||
|
if msg.contains("No session") {
|
||||||
|
return Err(SessionError::NoSession(session_id.into()));
|
||||||
|
}
|
||||||
|
error!(
|
||||||
|
"Couldn't get session: {}",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
} else if output.status.success() {
|
||||||
|
let what = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let mut stype = SessionType::TTY;
|
||||||
|
let mut user = false;
|
||||||
|
for line in what.lines() {
|
||||||
|
if let Some(is_it) = line.split("=").last() {
|
||||||
|
match is_it.trim() {
|
||||||
|
"user" => user = true,
|
||||||
|
"wayland" => stype = SessionType::Wayland,
|
||||||
|
"x11" => stype = SessionType::X11,
|
||||||
|
"tty" => stype = SessionType::TTY,
|
||||||
|
_ => return Err(SessionError::NoSession(session_id.into())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if user {
|
||||||
|
return Ok(stype);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => error!("Couldn't get session: {}", err),
|
||||||
|
}
|
||||||
|
Err(SessionError::NoSession(session_id.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum SessionError {
|
||||||
|
NoSession(String),
|
||||||
|
NoSessions,
|
||||||
|
Command(String, std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for SessionError {
|
||||||
|
// This trait requires `fmt` with this exact signature.
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
SessionError::NoSession(id) => write!(f, "Session {} not active", id),
|
||||||
|
SessionError::NoSessions => write!(f, "No active sessions"),
|
||||||
|
SessionError::Command(func, error) => {
|
||||||
|
write!(f, "Command exec error: {}: {}", func, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for SessionError {}
|
||||||
+17
-17
@@ -204,28 +204,28 @@ pub enum AuraModes {
|
|||||||
|
|
||||||
impl From<SetAuraBuiltin> for AuraModes {
|
impl From<SetAuraBuiltin> for AuraModes {
|
||||||
fn from(mode: SetAuraBuiltin) -> Self {
|
fn from(mode: SetAuraBuiltin) -> Self {
|
||||||
match mode {
|
(&mode).into()
|
||||||
SetAuraBuiltin::Static(x) => AuraModes::Static(x),
|
|
||||||
SetAuraBuiltin::Breathe(x) => AuraModes::Breathe(x),
|
|
||||||
SetAuraBuiltin::Strobe(x) => AuraModes::Strobe(x),
|
|
||||||
SetAuraBuiltin::Rainbow(x) => AuraModes::Rainbow(x),
|
|
||||||
SetAuraBuiltin::Star(x) => AuraModes::Star(x),
|
|
||||||
SetAuraBuiltin::Rain(x) => AuraModes::Rain(x),
|
|
||||||
SetAuraBuiltin::Highlight(x) => AuraModes::Highlight(x),
|
|
||||||
SetAuraBuiltin::Laser(x) => AuraModes::Laser(x),
|
|
||||||
SetAuraBuiltin::Ripple(x) => AuraModes::Ripple(x),
|
|
||||||
SetAuraBuiltin::Pulse(x) => AuraModes::Pulse(x),
|
|
||||||
SetAuraBuiltin::Comet(x) => AuraModes::Comet(x),
|
|
||||||
SetAuraBuiltin::Flash(x) => AuraModes::Flash(x),
|
|
||||||
SetAuraBuiltin::MultiStatic(x) => AuraModes::MultiStatic(x),
|
|
||||||
SetAuraBuiltin::MultiBreathe(x) => AuraModes::MultiBreathe(x),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&SetAuraBuiltin> for AuraModes {
|
impl From<&SetAuraBuiltin> for AuraModes {
|
||||||
fn from(mode: &SetAuraBuiltin) -> Self {
|
fn from(mode: &SetAuraBuiltin) -> Self {
|
||||||
mode.clone().into()
|
match mode {
|
||||||
|
SetAuraBuiltin::Static(x) => AuraModes::Static(x.clone()),
|
||||||
|
SetAuraBuiltin::Breathe(x) => AuraModes::Breathe(x.clone()),
|
||||||
|
SetAuraBuiltin::Strobe(x) => AuraModes::Strobe(x.clone()),
|
||||||
|
SetAuraBuiltin::Rainbow(x) => AuraModes::Rainbow(x.clone()),
|
||||||
|
SetAuraBuiltin::Star(x) => AuraModes::Star(x.clone()),
|
||||||
|
SetAuraBuiltin::Rain(x) => AuraModes::Rain(x.clone()),
|
||||||
|
SetAuraBuiltin::Highlight(x) => AuraModes::Highlight(x.clone()),
|
||||||
|
SetAuraBuiltin::Laser(x) => AuraModes::Laser(x.clone()),
|
||||||
|
SetAuraBuiltin::Ripple(x) => AuraModes::Ripple(x.clone()),
|
||||||
|
SetAuraBuiltin::Pulse(x) => AuraModes::Pulse(x.clone()),
|
||||||
|
SetAuraBuiltin::Comet(x) => AuraModes::Comet(x.clone()),
|
||||||
|
SetAuraBuiltin::Flash(x) => AuraModes::Flash(x.clone()),
|
||||||
|
SetAuraBuiltin::MultiStatic(x) => AuraModes::MultiStatic(x.clone()),
|
||||||
|
SetAuraBuiltin::MultiBreathe(x) => AuraModes::MultiBreathe(x.clone()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,11 @@ pub struct ProfileCommand {
|
|||||||
|
|
||||||
#[options(meta = "", help = "<silent, normal, boost>")]
|
#[options(meta = "", help = "<silent, normal, boost>")]
|
||||||
pub fan_preset: Option<FanLevel>,
|
pub fan_preset: Option<FanLevel>,
|
||||||
#[options(meta = "", parse(try_from_str = "parse_fan_curve"), help = "set fan curve")]
|
#[options(
|
||||||
|
meta = "",
|
||||||
|
parse(try_from_str = "parse_fan_curve"),
|
||||||
|
help = "set fan curve"
|
||||||
|
)]
|
||||||
pub curve: Option<Curve>,
|
pub curve: Option<Curve>,
|
||||||
#[options(free)]
|
#[options(free)]
|
||||||
pub profile: Option<String>,
|
pub profile: Option<String>,
|
||||||
|
|||||||
Reference in New Issue
Block a user