Compare commits

...

12 Commits

Author SHA1 Message Date
Luke Jones 4eeacea832 Merge branch 'fluke/vfio' into 'main'
Bugfix vfio/integrated

See merge request asus-linux/asus-nb-ctrl!41
2021-03-24 23:04:23 +00:00
Luke D Jones 6bf0fdd117 Bugfix vfio/integrated 2021-03-25 11:14:59 +13:00
Luke Jones 7fcde7df17 Merge branch 'fluke/vfio-builtin' into 'main'
Fluke/vfio builtin

See merge request asus-linux/asus-nb-ctrl!40
2021-03-24 06:45:35 +00:00
Luke D Jones 543b0b817f Try remove nouveau 2021-03-24 19:44:40 +13:00
Luke D Jones 5a7d31fdf6 Bugfixes to session handler. Add extra profile commands
- Better handling of session tracking
- List all profile data
- Get active profile name
- Get active profile data
2021-03-24 16:30:13 +13:00
Luke D Jones 301c532b65 Formatting 2021-03-23 13:45:57 +13:00
Luke D Jones df7ae4d014 Fix: non-rgb keyboard backlight control 2021-03-23 13:44:07 +13:00
Luke D Jones 96ceef1bdb Prep v3.2.1 2021-03-22 16:45:05 +13:00
Luke Jones bc72b93625 Merge branch 'fluke/led-work' into 'main'
Fluke/led work

See merge request asus-linux/asus-nb-ctrl!39
2021-03-22 03:43:05 +00:00
Luke D Jones 03b338bdfa Strongly type the Led brightness 2021-03-22 16:36:10 +13:00
Luke D Jones 7a51cd1c70 Cleaned up 2021-03-22 11:03:56 +13:00
Luke D Jones 0449a4b06b Initial cleanup 2021-03-22 10:24:28 +13:00
27 changed files with 414 additions and 581 deletions
+21
View File
@@ -6,6 +6,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
# [3.2.4] - 2021-03-24
### Changed
- Ignore vfio-builtin error if switching to integrated
# [3.2.3] - 2021-03-24
### Changed
- Better handling of session tracking
### Added
- List all profile data
- Get active profile name
- Get active profile data
# [3.2.2] - 2021-03-23
### Changed
- Fix brightness control, again, for non-RGB keyboards
# [3.2.1] - 2021-03-21
### Changed
- Fix brightness control
- Large cleanup of code relating to LED controls
# [3.2.0] - 2021-03-21
### Changed
- Refactor keyboard LED handling
Generated
+5 -4
View File
@@ -28,12 +28,13 @@ dependencies = [
"daemon",
"notify-rust",
"rog_dbus",
"rog_types",
"serde_json",
]
[[package]]
name = "asusctl"
version = "3.1.4"
version = "3.1.5"
dependencies = [
"daemon",
"gumdrop",
@@ -196,7 +197,7 @@ dependencies = [
[[package]]
name = "daemon"
version = "3.2.0"
version = "3.2.4"
dependencies = [
"env_logger",
"intel-pstate",
@@ -887,7 +888,7 @@ checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "rog_dbus"
version = "3.0.0"
version = "3.1.0"
dependencies = [
"rog_fan_curve",
"rog_types",
@@ -908,7 +909,7 @@ dependencies = [
[[package]]
name = "rog_types"
version = "3.1.0"
version = "3.2.0"
dependencies = [
"gumdrop",
"rog_fan_curve",
+48 -95
View File
@@ -5,29 +5,26 @@
`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:**
## Goals
This app is developed and tested on fedora only. Support is not provided for Arch or Arch based distros.
1. To provide an interface for rootless control of some system functions most users wish to control such as fan speeds, keyboard LEDs, graphics modes.
2. Enable third-party apps to use the above with dbus methods
3. To make the above as easy as possible for new users
Point 3 means that the list of supported distros is very narrow - fedora is explicitly
supported, while Ubuntu and openSUSE are level-2 support. All other distros are *not*
supported (while asusd might still run fine on them). For best support use fedora 32+ Workstation.
**NOTICE:**
The following is *not* required for 5.11 kernel versions, as this version includes
all the required patches.
---
This program requires the kernel patch [here](https://www.spinics.net/lists/linux-input/msg68977.html) to be applied.
Alternatively you may use the dkms module for 'hid-asus-rog` from one of the
repositories [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
1. The following is *not* required for 5.11 kernel versions, as this version includes all the required patches.
2. 2021 hardware has a new keyboard prod_id and the patch is included in 5.12+
The patch enables the following in kernel:
'hid-asus-rog` DKMS module from [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
The module enables the following in kernel:
- Initialising the keyboard
- All hotkeys (FN+Key combos)
- 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` + `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.
## Discord
@@ -52,13 +49,14 @@ will probably suffer another rename once it becomes generic enough to do so.
- [X] User notifications daemon
- [X] Setting/modifying built-in LED modes
- [X] Per-key LED setting
- [X] Fancy LED modes (See examples)
- [X] Fancy LED modes (See examples) (currently being reworked)
- [X] Saving settings for reload
- [X] Logging - required for journalctl
- [X] AniMatrix display on G14 models that include it
- [X] AniMatrix display on G14 models that include it (currently being reworked)
- [X] Set battery charge limit (with kernel supporting this)
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
- [X] Fan curve control on G14 + G15 thanks to @Yarn1
- [X] Graphics mode switching between iGPU, dGPU, on-demand, and vfio (for VM pass-through)
+ [X] Requires only a logout/login
- [X] Toggle bios setting for boot/POST sound
- [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync)
@@ -66,13 +64,15 @@ will probably suffer another rename once it becomes generic enough to do so.
## Graphics switching
A new feature has been added to enable switching graphics modes. This can be disabled
in the config with `"manage_gfx": false,`. Additionally there is an extra setting
for laptops capable of g-sync dedicated gfx mode to enable the graphics switching
to switch on dedicated gfx for "nvidia" mode.
`asusd` can switch graphics modes between:
- `integrated`, uses the iGPU only and force-disables the dGPU
- `hybrid`, enables Nvidia prime-offload mode
- `nvidia`, uses the Nvidia gpu only
- `vfio`, binds the Nvidia gpu to vfio for VM pass-through
The CLI option for this does not require root until it asks for it, and provides
instructions.
This can be disabled in the config with `"manage_gfx": false,`. Additionally there
is an extra setting for laptops capable of g-sync dedicated gfx mode to enable the
graphics switching to switch on dedicated gfx for "nvidia" mode.
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`
@@ -81,6 +81,10 @@ stray configs blocking nvidia modules from loading in:
- `/etc/modprobe.d/`
- `/usr/lib/modprope.d/`
**VFIO NOTE:** The vfio modules *must not* be compiled into the kernel, they need
to be separate modules. If you don't plan to use vfio mode then you can ignore this
otherwise you may need a custom built kernel.
### Power management udev rule
If you have installed the Nvidia driver manually you will require the
@@ -89,8 +93,8 @@ If you have installed the Nvidia driver manually you will require the
### 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. This is espeically
true if you manually installed the nvidia drivers.
to stop dracut including the nvidia modules in the ramdisk if you manually
installed the nvidia drivers.
```
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
@@ -109,24 +113,21 @@ Models GA401, GA502, GU502 support LED brightness change only (no RGB).
If you model isn't getting the correct led modes, you can edit the file
`/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as follows:
```
0 STATIC
1 BREATHING
2 STROBE
3 RAINBOW
4 STAR
5 RAIN
6 HIGHLIGHT
7 LASER
8 RIPPLE
10 PULSE
11 COMET
12 FLASH
13 MULTISTATIC
255 PER_KEY
```
- Static
- Breathe
- Strobe
- Rainbow
- Star
- Rain
- Highlight
- Laser
- Ripple
- Pulse
- Comet
- Flash
use `cat /sys/class/dmi/id/product_name` to get details about your laptop.
use `cat /sys/class/dmi/id/product_name` to get details about your laptop. You
must restart the `asusd.service` after editing.
# Keybinds
@@ -156,8 +157,6 @@ Packaging and auto-builds are available [here](https://build.opensuse.org/packag
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
Alternatively check the releases page for f33 RPM.
---
Run `make` then `sudo make install` then reboot.
@@ -182,26 +181,8 @@ can be added on request). You will need to install the alternative service from
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
## Updating
If there has been a config file format change your config will be overwritten. This will
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
**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.
To see if the fan-mode changed cat either:
- `cat /sys/devices/platform/asus-nb-wmi/throttle_thermal_policy` or
- `cat /sys/devices/platform/asus-nb-wmi/fan_boost_mode`
The numbers are 0 = Normal/Balanced, 1 = Boost, 2 = Silent.
Running the program as a daemon manually will require root. Standard (non-daemon)
mode expects to be communicating with the daemon mode over dbus.
Commands are given by:
```
@@ -221,23 +202,6 @@ Some commands may have subcommands:
asusctl <command> <subcommand> --help
```
## Daemon mode
If the daemon service is enabled then on boot the following will be reloaded from save:
- LED brightness
- Last used built-in mode
- fan-boost/thermal mode
- battery charging limit
The daemon also saves the settings per mode as the keyboard does not do this
itself - this means cycling through modes with the Aura keys will use the
settings that were used via CLI.
Daemon mode creates a config file at `/etc/asusd/asusd.conf` which you can edit a
little of. Most parts will be byte arrays, but you can adjust things like
`mode_performance`.
## User NOTIFICATIONS via dbus
If you have a notifications handler set up, or are using KDE or Gnome then you
@@ -247,12 +211,9 @@ 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
## DBUS Input
See [README_DBUS.md](./README_DBUS.md).
## AniMe input
You will want to look at what MeuMeu has done with [https://github.com/Meumeu/ZephyrusBling/](https://github.com/Meumeu/ZephyrusBling/)
@@ -278,11 +239,3 @@ omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
# License
Mozilla Public License 2 (MPL-2.0)
# Credits
- [flukejones](https://github.com/flukejones/), project maintainer.
- [tuxuser](https://github.com/tuxuser/)
- [aspann](https://github.com/aspann)
- [meumeu](https://github.com/Meumeu)
- Anyone missed? Please contact me
-115
View File
@@ -1,115 +0,0 @@
# DBUS Guide
**WARNING: In progress updates**
Interface name = org.asuslinux.Daemon
Paths:
- `/org/asuslinux/Gfx`
+ `SetVendor` (string)
+ `NotifyVendor` (recv vendor label string)
- `/org/asuslinux/Led`
+ `LedMode` (AuraMode as json)
+ `LedModes` (array[AuraMode] as json)
+ `SetLedMode` (AuraMode -> json)
+ `NotifyLed` (recv json data)
- `/org/asuslinux/Anime`
+ `SetAnime` (byte array data)
- `/org/asuslinux/Charge`
+ `Limit` (u8)
+ `SetLimit` (u8)
+ `NotifyCharge` (recv i8)
- `/org/asuslinux/Profile`
+ `Profile` (recv current profile data as json string)
+ `Profiles` (recv profiles data as json string (map))
+ `SetProfile` (event -> json)
+ `NotifyProfile` (recv current profile name)
All `Notify*` methods are signals.
### SetLed
This method expects a string of JSON as input. The JSON is of format such:
```
{
"Static": {
"colour": [ 255, 0, 0]
}
}
```
The possible contents of a mode are:
- `"colour": [u8, u8, u8],`
- `"speed": <String>,` <Low, Med, High>
- `"direction": <String>,` <Up, Down, Left, Right>
Modes may or may not be available for a specific laptop (TODO: dbus getter for
supported modes). Modes are:
- `"Static": { "colour": <colour> },`
- `"Pulse": { "colour": <colour> },`
- `"Comet": { "colour": <colour> },`
- `"Flash": { "colour": <colour> },`
- `"Strobe": { "speed": <speed> },`
- `"Rain": { "speed": <speed> },`
- `"Laser": { "colour": <colour>, "speed": <speed> },`
- `"Ripple": { "colour": <colour>, "speed": <speed> },`
- `"Highlight": { "colour": <colour>, "speed": <speed> },`
- `"Rainbow": { "direction": <direction>, "speed": <speed> },`
- `"Breathe": { "colour": <colour>, "colour2": <colour>, "speed": <speed> },`
- `"Star": { "colour": <colour>, "colour2": <colour>, "speed": <speed> },`
- `"MultiStatic": { "colour1": <colour>, "colour2": <colour>, , "colour3": <colour>, "colour4": <colour> },`
Additionally to the above there is `"RGB": [[u8; 64]; 11]` which is for per-key
setting of LED's but this requires some refactoring to make it easily useable over
dbus.
Lastly, there is `"LedBrightness": <u8>` which accepts 0-3 for off, low, med, high.
### SetFanMode
Accepts an integer from the following:
- `0`: Normal
- `1`: Boost mode
- `2`: Silent mode
## dbus-send examples:
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Profile org.asuslinux.Daemon.NextProfile
```
## dbus-send examples OUTDATED
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"Static": {"colour": [ 80, 0, 40]}}'
```
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"Star":{"colour":[0,255,255],"colour2":[0,0,0],"speed":"Med"}}'
```
**Note:** setting colour2 to `[0,0,255]` activates random star colour. Colour2 has no effect on the
mode otherwise.
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"Star":{"colour":[0,255,255],"colour2":[0,0,255],"speed":"Med"}}'
```
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetKeyBacklight string:'{"LedBrightness":3}'
```
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.asuslinux.Daemon.SetFanMode byte:'2'
```
Monitoring dbus while sending commands via `rog-core` will give you the json structure if you are otherwise unsure, e.g: `dbus-monitor --system |grep -A2 asuslinux`.
## Getting an introspection .xml
```
dbus-send --system --print-reply --dest=org.asuslinux.Daemon /org/asuslinux/Charge org.freedesktop.DBus.Introspectable.Introspect > xml/asusd-charge.xml
```
-7
View File
@@ -1,7 +0,0 @@
# TODO
- There is lots of code duplication. This should be turned in to macros (dbus stuff etc)
- Add a little more information to profile notifications such as freq min/max, fan curves
- Finish splitting out controllers to own crates
- Finish move to zbus in client when zbus has client signal watch
- Consider a rename again because the project is getting a lot less ASUS centric
+1
View File
@@ -10,6 +10,7 @@ edition = "2018"
# serialisation
serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" }
rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" }
[dependencies.notify-rust]
+1 -1
View File
@@ -1,6 +1,6 @@
use daemon::config::Profile;
use notify_rust::{Hint, Notification, NotificationHandle};
use rog_dbus::{DbusProxies, Signals};
use rog_types::profile::Profile;
use std::error::Error;
use std::time::Duration;
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "asusctl"
version = "3.1.4"
version = "3.1.5"
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"
+3 -3
View File
@@ -7,14 +7,14 @@ use std::str::FromStr;
#[derive(Options)]
pub struct LedBrightness {
level: Option<u8>,
level: Option<u32>,
}
impl LedBrightness {
pub fn new(level: Option<u8>) -> Self {
pub fn new(level: Option<u32>) -> Self {
LedBrightness { level }
}
pub fn level(&self) -> Option<u8> {
pub fn level(&self) -> Option<u32> {
self.level
}
}
+36 -7
View File
@@ -9,7 +9,7 @@ use gumdrop::{Opt, Options};
use rog_dbus::AuraDbusClient;
use rog_types::{
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
aura_modes::{AuraEffect, AuraModeNum},
aura_modes::{self, AuraEffect, AuraModeNum},
cli_options::{AniMeActions, AniMeStatusValue},
gfx_vendors::GfxVendors,
profile::{FanLevel, ProfileCommand, ProfileEvent},
@@ -143,6 +143,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if parsed.help {
print_supported_help(&supported, &parsed);
println!("\nSee https://asus-linux.org/faq/ for additional help");
std::process::exit(1);
}
@@ -202,7 +203,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let level = dbus.proxies().led().get_led_brightness()?;
println!("Current keyboard led brightness: {}", level.to_string());
}
Some(level) => dbus.proxies().led().set_led_brightness(level)?,
Some(level) => dbus
.proxies()
.led()
.set_led_brightness(<aura_modes::LedBrightness>::from(level))?,
}
}
@@ -386,6 +390,9 @@ fn handle_profile(
if !cmd.next
&& !cmd.create
&& !cmd.list
&& !cmd.active_name
&& !cmd.active_data
&& !cmd.profiles_data
&& cmd.remove.is_none()
&& cmd.curve.is_none()
&& cmd.max_percentage.is_none()
@@ -416,12 +423,34 @@ fn handle_profile(
if cmd.next {
dbus.proxies().profile().next_fan()?;
} else if cmd.list {
let profile_names = dbus.proxies().profile().profile_names()?;
println!("Available profiles are {}", profile_names);
} else if let Some(profile) = &cmd.remove {
}
if let Some(profile) = &cmd.remove {
dbus.proxies().profile().remove(profile)?
} else {
}
if cmd.list {
let profile_names = dbus.proxies().profile().profile_names()?;
println!("Available profiles are {:?}", profile_names);
}
if cmd.active_name {
println!(
"Active profile: {:?}",
dbus.proxies().profile().active_profile_name()?
);
}
if cmd.active_data {
println!("Active profile:");
for s in dbus.proxies().profile().active_profile_data()?.lines() {
println!("{}", s);
}
}
if cmd.profiles_data {
println!("Profiles:");
for s in dbus.proxies().profile().all_profile_data()?.lines() {
println!("{}", s);
}
}
if cmd.profile.is_some() {
dbus.proxies()
.profile()
.write_command(&ProfileEvent::Cli(cmd.clone()))?
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "daemon"
version = "3.2.0"
version = "3.2.4"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
+1 -44
View File
@@ -1,6 +1,5 @@
use log::{error, info, warn};
use rog_fan_curve::Curve;
use rog_types::gfx_vendors::GfxVendors;
use rog_types::{gfx_vendors::GfxVendors, profile::Profile};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
@@ -136,45 +135,3 @@ impl Config {
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
}
#[derive(Deserialize, Serialize)]
pub struct Profile {
pub min_percentage: u8,
pub max_percentage: u8,
pub turbo: bool,
pub fan_preset: u8,
pub fan_curve: Option<Curve>,
}
#[deprecated]
pub type CPUSettings = Profile;
impl Default for Profile {
fn default() -> Self {
Profile {
min_percentage: 0,
max_percentage: 100,
turbo: false,
fan_preset: 0,
fan_curve: None,
}
}
}
impl Profile {
pub fn new(
min_percentage: u8,
max_percentage: u8,
turbo: bool,
fan_preset: u8,
fan_curve: Option<Curve>,
) -> Self {
Profile {
min_percentage,
max_percentage,
turbo,
fan_preset,
fan_curve,
}
}
}
+28 -4
View File
@@ -1,6 +1,6 @@
use crate::laptops::LaptopLedData;
use log::{error, warn};
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone};
use log::{error, info, warn};
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone, LedBrightness};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
@@ -8,9 +8,28 @@ use std::io::{Read, Write};
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
#[derive(Deserialize, Serialize)]
pub struct AuraConfigV320 {
pub brightness: u32,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
}
impl AuraConfigV320 {
pub(crate) fn into_current(self) -> AuraConfig {
AuraConfig {
brightness: <LedBrightness>::from(self.brightness),
current_mode: self.current_mode,
builtins: self.builtins,
multizone: self.multizone,
}
}
}
#[derive(Deserialize, Serialize)]
pub struct AuraConfig {
pub brightness: u8,
pub brightness: LedBrightness,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
@@ -19,7 +38,7 @@ pub struct AuraConfig {
impl Default for AuraConfig {
fn default() -> Self {
AuraConfig {
brightness: 1,
brightness: LedBrightness::Med,
current_mode: AuraModeNum::Static,
builtins: BTreeMap::new(),
multizone: None,
@@ -48,6 +67,11 @@ impl AuraConfig {
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
} else if let Ok(data) = serde_json::from_str::<AuraConfigV320>(&buf) {
let config = data.into_current();
config.write();
info!("Updated AuraConfig version");
return config;
}
warn!("Could not deserialise {}", AURA_CONFIG_PATH);
panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH);
+2 -2
View File
@@ -1,8 +1,8 @@
use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors};
use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors, profile::Profile};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::config::{Config, Profile};
use crate::config::Config;
/// for parsing old v2.1.2 config
#[allow(dead_code)]
+26 -28
View File
@@ -1,10 +1,7 @@
use crate::error::RogError;
use crate::{
config::{Config, Profile},
GetSupported,
};
use crate::{config::Config, GetSupported};
use log::{info, warn};
use rog_types::profile::{FanLevel, ProfileEvent};
use rog_types::profile::{FanLevel, Profile, ProfileEvent};
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Write;
@@ -90,60 +87,61 @@ impl DbusFanAndCpu {
}
/// Fetch the active profile name
fn active_profile_name(&mut self) -> String {
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
return cfg.active_profile.clone();
return Ok(cfg.active_profile.clone());
}
}
"Failed".to_string()
Err(Error::Failed(
"Failed to get active profile name".to_string(),
))
}
// TODO: Profile can't implement Type because of Curve
/// Fetch the active profile details
fn profile(&mut self) -> String {
fn profile(&mut self) -> zbus::fdo::Result<String> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
return json;
if let Ok(json) = serde_json::to_string_pretty(profile) {
return Ok(json);
}
}
}
}
"Failed".to_string()
Err(Error::Failed(
"Failed to get active profile details".to_string(),
))
}
fn profiles(&mut self) -> String {
/// Fetch all profile data
fn profiles(&mut self) -> zbus::fdo::Result<String> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
if let Ok(json) = serde_json::to_string(&cfg.power_profiles) {
return json;
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
return Ok(json);
}
}
}
"Failed".to_string()
Err(Error::Failed(
"Failed to get all profile details".to_string(),
))
}
fn profile_names(&self) -> String {
fn profile_names(&self) -> zbus::fdo::Result<Vec<String>> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
let profile_names: String = cfg
.power_profiles
.keys()
.cloned()
.collect::<Vec<String>>()
.join(", ");
return profile_names;
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
return Ok(profile_names);
}
}
"Failed".to_string()
Err(Error::Failed("Failed to get all profile names".to_string()))
}
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
@@ -172,7 +170,7 @@ impl DbusFanAndCpu {
}
}
return Err(Error::Failed("Failed to lock configuration".to_string()));
Err(Error::Failed("Failed to lock configuration".to_string()))
}
#[dbus_interface(signal)]
+11
View File
@@ -10,6 +10,10 @@ pub enum GfxError {
DisplayManagerAction(String, ExitStatus),
DisplayManagerTimeout(String),
GsyncModeActive,
VfioBuiltin,
MissingModule(String),
Modprobe(String),
Command(String, std::io::Error),
}
impl fmt::Display for GfxError {
@@ -28,6 +32,13 @@ impl fmt::Display for GfxError {
f,
"Can not switch gfx modes when dedicated/G-Sync mode is active"
),
GfxError::VfioBuiltin => write!(
f,
"Can not switch to vfio mode if the modules are built in to kernel"
),
GfxError::MissingModule(m) => write!(f, "The module {} is missing", m),
GfxError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
GfxError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
}
}
}
+41 -38
View File
@@ -3,7 +3,7 @@ use ctrl_gfx::*;
use ctrl_rog_bios::CtrlRogBios;
use log::{error, info, warn};
use logind_zbus::{
types::{SessionClass, SessionInfo, SessionType},
types::{SessionClass, SessionInfo, SessionState, SessionType},
ManagerProxy, SessionProxy,
};
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
@@ -95,10 +95,8 @@ impl Reloadable for CtrlGraphics {
impl CtrlGraphics {
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
let bus = PciBus::new()?;
info!("GFX: Rescanning PCI bus");
bus.rescan()?;
let devs = PciDevice::all()?;
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
@@ -169,7 +167,6 @@ impl CtrlGraphics {
config.gfx_mode = vendor;
config.write();
}
// TODO: Error here
}
/// Associated method to get which vendor mode is set
@@ -187,6 +184,7 @@ impl CtrlGraphics {
Ok(buf)
}
/// Some systems have a fallback service to load nouveau if nvidia fails
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
let action = if vendor == GfxVendors::Nvidia {
info!("GFX: Enabling nvidia-fallback.service");
@@ -213,6 +211,7 @@ impl CtrlGraphics {
Ok(())
}
/// Write the appropriate xorg config for the chosen mode
fn write_xorg_conf(vendor: GfxVendors) -> Result<(), RogError> {
let text = if vendor == GfxVendors::Nvidia {
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
@@ -239,6 +238,7 @@ impl CtrlGraphics {
Ok(())
}
/// Creates the full modprobe.conf required for vfio pass-through
fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec<u8> {
let mut vifo = MODPROBE_VFIO.to_vec();
for (d_count, dev) in devices.iter().enumerate() {
@@ -303,7 +303,7 @@ impl CtrlGraphics {
.map_err(|err| RogError::Command("device unbind error".into(), err))
}
fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> {
fn do_driver_action(driver: &str, action: &str) -> Result<(), GfxError> {
let mut cmd = Command::new(action);
cmd.arg(driver);
@@ -318,7 +318,7 @@ impl CtrlGraphics {
let output = cmd
.output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
.map_err(|err| GfxError::Command(format!("{:?}", cmd), err))?;
if !output.status.success() {
if output
.stderr
@@ -326,6 +326,9 @@ impl CtrlGraphics {
{
return Ok(());
}
if output.stderr.ends_with("is builtin.\n".as_bytes()) {
return Err(GfxError::VfioBuiltin);
}
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
warn!(
"{} {} failed: {:?}",
@@ -336,6 +339,11 @@ impl CtrlGraphics {
warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep {}` to confirm modules loaded", driver);
return Ok(());
}
if String::from_utf8_lossy(&output.stderr)
.contains(&format!("Module {} not found", driver))
{
return Err(GfxError::MissingModule(driver.into()));
}
if count >= MAX_TRIES {
let msg = format!(
"{} {} failed: {:?}",
@@ -343,14 +351,14 @@ impl CtrlGraphics {
driver,
String::from_utf8_lossy(&output.stderr)
);
return Err(RogError::Modprobe(msg));
return Err(GfxError::Modprobe(msg));
}
} else if output.status.success() {
return Ok(());
}
count += 1;
std::thread::sleep(std::time::Duration::from_millis(250));
std::thread::sleep(std::time::Duration::from_millis(50));
}
}
@@ -439,6 +447,7 @@ impl CtrlGraphics {
}
}
GfxVendors::Vfio => {
Self::do_driver_action("nouveau", "rmmod")?;
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
@@ -446,8 +455,15 @@ impl CtrlGraphics {
Self::do_driver_action("vfio-pci", "modprobe")?;
}
GfxVendors::Integrated => {
Self::do_driver_action("nouveau", "rmmod")?;
for driver in VFIO_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
Self::do_driver_action(driver, "rmmod").or_else(|err| {
if matches!(err, GfxError::VfioBuiltin) {
warn!("{}", err);
return Ok(());
}
Err(err)
})?;
}
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
@@ -455,11 +471,11 @@ impl CtrlGraphics {
Self::unbind_remove_nvidia(&devices)?;
}
}
Ok(())
}
fn graphical_session_alive(
/// Check if the user has any graphical uiser sessions that are active or online
fn graphical_user_sessions_exist(
connection: &Connection,
sessions: &[SessionInfo],
) -> Result<bool, RogError> {
@@ -468,9 +484,10 @@ impl CtrlGraphics {
if session_proxy.get_class()? == SessionClass::User {
match session_proxy.get_type()? {
SessionType::X11 | SessionType::Wayland | SessionType::MIR => {
//if session_proxy.get_active()? {
return Ok(true);
//}
match session_proxy.get_state()? {
SessionState::Online | SessionState::Active => return Ok(true),
SessionState::Closing | SessionState::Invalid => {}
}
}
_ => {}
}
@@ -499,12 +516,11 @@ impl CtrlGraphics {
loop {
let tmp = manager.list_sessions()?;
if !tmp.iter().eq(&sessions) {
warn!("GFX: Sessions list changed");
warn!("GFX: Old list:\n{:?}\nNew list:\n{:?}", &sessions, &tmp);
info!("GFX thread: Sessions list changed");
sessions = tmp;
}
if !Self::graphical_session_alive(&connection, &sessions)? {
if !Self::graphical_user_sessions_exist(&connection, &sessions)? {
break;
}
@@ -523,36 +539,22 @@ impl CtrlGraphics {
sleep(SLEEP_PERIOD);
}
info!("GFX: all graphical user sessions ended, continuing");
info!("GFX thread: 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::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")?;
}
Self::do_display_manager_action("restart")?;
// Save selected mode in case of reboot
Self::save_gfx_mode(vendor, config);
info!("GFX: display-manager started");
info!("GFX thread: display-manager started");
let v: &str = vendor.into();
info!("GFX: Graphics mode changed to {} successfully", v);
info!("GFX thread: Graphics mode changed to {} successfully", v);
Ok(format!("Graphics mode changed to {} successfully", v))
}
/// Before starting a new thread the old one *must* be cancelled
fn cancel_thread(&self) {
if let Ok(lock) = self.thread_kill.lock() {
if let Some(tx) = lock.as_ref() {
@@ -560,7 +562,7 @@ impl CtrlGraphics {
info!("GFX: Cancelling previous thread");
tx.send(true)
.map_err(|err| {
warn!("GFX: {}", err);
warn!("GFX thread: {}", err);
})
.ok();
}
@@ -619,6 +621,7 @@ impl CtrlGraphics {
let devices = self.nvidia.clone();
let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, &devices, &bus)?;
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
}
// TODO: undo if failed? Save last mode, catch errors...
Ok(action_required)
+48 -122
View File
@@ -7,11 +7,11 @@ static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
use crate::{
config_aura::AuraConfig,
error::RogError,
laptops::{match_laptop, LaptopLedData, HELP_ADDRESS},
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
};
use log::{error, info, warn};
use rog_types::{
aura_modes::{AuraEffect, AuraModeNum},
aura_modes::{AuraEffect, AuraModeNum, LedBrightness},
LED_MSG_LEN,
};
use std::fs::OpenOptions;
@@ -37,19 +37,17 @@ impl GetSupported for CtrlKbdBacklight {
fn get_supported() -> Self::A {
// let mode = <&str>::from(&<AuraModes>::from(*mode));
let mut stock_led_modes = None;
let multizone_led_mode = false;
let per_key_led_mode = false;
if let Some(laptop) = match_laptop() {
stock_led_modes = if laptop.supported_modes().standard.is_empty() {
None
} else {
Some(laptop.supported_modes().standard.clone())
};
}
let laptop = LaptopLedData::get_data();
let stock_led_modes = if laptop.standard.is_empty() {
None
} else {
Some(laptop.standard)
};
LedSupportedFunctions {
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(),
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_some(),
stock_led_modes,
multizone_led_mode,
per_key_led_mode,
@@ -59,8 +57,6 @@ impl GetSupported for CtrlKbdBacklight {
pub struct CtrlKbdBacklight {
led_node: Option<String>,
#[allow(dead_code)]
kbd_node: Option<String>,
pub bright_node: String,
supported_modes: LaptopLedData,
flip_effect_write: bool,
@@ -99,7 +95,7 @@ impl crate::ZbusAdd for DbusKbdBacklight {
/// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusKbdBacklight {
fn set_brightness(&mut self, brightness: u8) {
fn set_brightness(&mut self, brightness: LedBrightness) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_brightness(brightness)
.map_err(|err| warn!("{}", err))
@@ -245,9 +241,9 @@ impl crate::CtrlTask for CtrlKbdBacklight {
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
if let Some(num) = char::from(buf[0]).to_digit(10) {
if self.config.brightness != num as u8 {
if self.config.brightness != num.into() {
self.config.read();
self.config.brightness = num as u8;
self.config.brightness = num.into();
self.config.write();
}
return Ok(());
@@ -258,46 +254,37 @@ impl crate::CtrlTask for CtrlKbdBacklight {
impl CtrlKbdBacklight {
#[inline]
pub fn new(
id_product: &str,
condev_iface: Option<&String>,
supported_modes: LaptopLedData,
config: AuraConfig,
) -> Result<Self, RogError> {
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
// TODO: return error if *all* nodes are None
let led_node = Self::get_node_failover(id_product, None, Self::scan_led_node).map_or_else(
|err| {
warn!("led_node: {}", err);
None
},
Some,
);
let kbd_node = Self::get_node_failover(id_product, condev_iface, Self::scan_kbd_node)
.map_or_else(
|err| {
warn!("kbd_node: {}", err);
None
},
Some,
);
let mut led_node = None;
for prod in ASUS_KEYBOARD_DEVICES.iter() {
match Self::find_led_node(prod) {
Ok(node) => {
led_node = Some(node);
break;
}
Err(err) => warn!("led_node: {}", err),
}
}
let bright_node = Self::get_kbd_bright_path();
if led_node.is_none() && kbd_node.is_none() && Self::get_kbd_bright_path().is_err() {
if led_node.is_none() && bright_node.is_none() {
return Err(RogError::MissingFunction(
"All keyboard features missing, you may require a v5.11 series kernel or newer"
.into(),
));
}
if bright_node.is_none() {
return Err(RogError::MissingFunction(
"No brightness control, you may require a v5.11 series kernel or newer".into(),
));
}
let ctrl = CtrlKbdBacklight {
// Using `ok` here so we can continue without keyboard features but
// still get brightness control at least... maybe...
led_node,
kbd_node,
// TODO: Check for existance
bright_node: bright_node?.to_owned(),
bright_node: bright_node.unwrap(), // If was none then we already returned above
supported_modes,
flip_effect_write: false,
config,
@@ -305,14 +292,11 @@ impl CtrlKbdBacklight {
Ok(ctrl)
}
fn get_kbd_bright_path() -> Result<&'static str, RogError> {
fn get_kbd_bright_path() -> Option<String> {
if Path::new(KBD_BRIGHT_PATH).exists() {
Ok(KBD_BRIGHT_PATH)
} else {
Err(RogError::MissingFunction(
"Keyboard features missing, you may require a v5.11 series kernel or newer".into(),
))
return Some(KBD_BRIGHT_PATH.to_string());
}
None
}
pub fn get_brightness(&self) -> Result<u8, RogError> {
@@ -331,36 +315,24 @@ impl CtrlKbdBacklight {
Ok(buf[0])
}
pub fn set_brightness(&self, brightness: u8) -> Result<(), RogError> {
let mut file = OpenOptions::new()
.write(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
file.write_all(&[brightness])
pub fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
let path = Path::new(&self.bright_node);
let mut file =
OpenOptions::new()
.write(true)
.open(&path)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
file.write_all(&[brightness.as_char_code()])
.map_err(|err| RogError::Read("buffer".into(), err))?;
Ok(())
}
fn get_node_failover(
id_product: &str,
iface: Option<&String>,
fun: fn(&str, Option<&String>) -> Result<String, RogError>,
) -> Result<String, RogError> {
match fun(id_product, iface) {
Ok(o) => return Ok(o),
Err(e) => {
warn!("Looking for node: {}", e.to_string());
}
}
Err(RogError::NotFound(format!("{}, {:?}", id_product, iface)))
}
fn scan_led_node(id_product: &str, _: Option<&String>) -> Result<String, RogError> {
fn find_led_node(id_product: &str) -> Result<String, RogError> {
let mut enumerator = udev::Enumerator::new().map_err(|err| {
warn!("{}", err);
RogError::Udev("enumerator failed".into(), err)
@@ -393,57 +365,11 @@ impl CtrlKbdBacklight {
}
}
}
warn!("Did not find a hidraw node for LED control, your device may be unsupported or require a kernel patch, see: {}", HELP_ADDRESS);
Err(RogError::MissingFunction(
"ASUS LED device node not found".into(),
))
}
fn scan_kbd_node(id_product: &str, iface: Option<&String>) -> Result<String, RogError> {
let mut enumerator = udev::Enumerator::new().map_err(|err| {
warn!("{}", err);
RogError::Udev("enumerator failed".into(), err)
})?;
enumerator.match_subsystem("input").map_err(|err| {
warn!("{}", err);
RogError::Udev("match_subsystem failed".into(), err)
})?;
enumerator
.match_property("ID_MODEL_ID", id_product)
.map_err(|err| {
warn!("{}", err);
RogError::Udev("match_property failed".into(), err)
})?;
for device in enumerator
.scan_devices()
.map_err(|err| {
warn!("{}", err);
err
})
.map_err(|err| {
warn!("{}", err);
RogError::Udev("scan_devices failed".into(), err)
})?
{
if let Some(dev_node) = device.devnode() {
if let Some(inum) = device.property_value("ID_USB_INTERFACE_NUM") {
if let Some(iface) = iface {
if inum == iface.as_str() {
info!("Using device at: {:?} for keyboard polling", dev_node);
return Ok(dev_node.to_string_lossy().to_string());
}
}
}
}
}
warn!("Did not find keyboard consumer device node, if expected functions are missing please file an issue at {}", HELP_ADDRESS);
Err(RogError::MissingFunction(
"ASUS keyboard 'Consumer Device' node not found".into(),
))
}
pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> {
self.set_and_save(mode)
}
+13 -19
View File
@@ -1,11 +1,13 @@
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::laptops::match_laptop;
use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
};
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
use daemon::{
ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu},
laptops::LaptopLedData,
};
use daemon::{CtrlTask, Reloadable, ZbusAdd};
use log::LevelFilter;
@@ -136,23 +138,15 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
};
if let Some(laptop) = match_laptop() {
let aura_config = AuraConfig::load(laptop.supported_modes());
if let Ok(ctrl) = CtrlKbdBacklight::new(
laptop.usb_product(),
laptop.condev_iface(),
laptop.supported_modes().to_owned(),
aura_config,
)
.map_err(|err| {
error!("Keyboard control: {}", err);
err
}) {
let tmp = Arc::new(Mutex::new(ctrl));
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
tasks.push(tmp);
}
let laptop = LaptopLedData::get_data();
let aura_config = AuraConfig::load(&laptop);
if let Ok(ctrl) = CtrlKbdBacklight::new(laptop, aura_config).map_err(|err| {
error!("Keyboard control: {}", err);
err
}) {
let tmp = Arc::new(Mutex::new(ctrl));
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
tasks.push(tmp);
}
// TODO: implement messaging between threads to check fails
+30 -80
View File
@@ -4,80 +4,8 @@ use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Read;
pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
static LAPTOP_DEVICES: [u16; 4] = [0x1866, 0x1869, 0x1854, 0x19b6];
/// A helper of sorts specifically for functions tied to laptop models
#[derive(Debug)]
pub struct LaptopBase {
usb_product: String,
condev_iface: Option<String>, // required for finding the Consumer Device interface
led_support: LaptopLedData,
}
impl LaptopBase {
pub fn usb_product(&self) -> &str {
&self.usb_product
}
pub fn condev_iface(&self) -> Option<&String> {
self.condev_iface.as_ref()
}
pub fn supported_modes(&self) -> &LaptopLedData {
&self.led_support
}
}
pub fn match_laptop() -> Option<LaptopBase> {
for device in rusb::devices().expect("Couldn't get device").iter() {
let device_desc = device
.device_descriptor()
.expect("Couldn't get device descriptor");
if device_desc.vendor_id() == 0x0b05 && LAPTOP_DEVICES.contains(&device_desc.product_id()) {
let prod_str = format!("{:x?}", device_desc.product_id());
if device_desc.product_id() == 0x1854 {
let laptop = laptop(prod_str, None);
return Some(laptop);
}
let laptop = laptop(prod_str, Some("02".to_owned()));
return Some(laptop);
}
}
warn!(
"Unsupported laptop, please request support at {}",
HELP_ADDRESS
);
warn!("Continuing with minimal support");
None
}
fn laptop(prod: String, condev_iface: Option<String>) -> LaptopBase {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name().expect("Could not get board_name");
let prod_family = dmi.product_family().expect("Could not get product_family");
let mut laptop = LaptopBase {
usb_product: prod,
condev_iface,
led_support: LaptopLedData {
board_names: vec![],
prod_family: String::new(),
standard: vec![],
multizone: false,
per_key: false,
},
};
if let Some(modes) = LedSupportFile::load_from_config() {
if let Some(led_modes) = modes.matcher(&prod_family, &board_name) {
laptop.led_support = led_modes;
return laptop;
}
}
laptop
}
pub const ASUS_LED_MODE_CONF: &str = "/etc/asusd/asusd-ledmodes.toml";
pub const ASUS_KEYBOARD_DEVICES: [&str; 4] = ["1866", "1869", "1854", "19b6"];
pub fn print_board_info() {
let dmi = sysfs_class::DmiId::default();
@@ -98,8 +26,8 @@ pub fn print_modes(supported_modes: &[u8]) {
info!("- {}", mode);
}
info!(
"If these modes are incorrect or missing please request support at {}",
HELP_ADDRESS
"If these modes are incorrect you can edit {}",
ASUS_LED_MODE_CONF
);
} else {
info!("No RGB control available");
@@ -120,6 +48,28 @@ pub struct LaptopLedData {
pub per_key: bool,
}
impl LaptopLedData {
pub fn get_data() -> Self {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name().expect("Could not get board_name");
let prod_family = dmi.product_family().expect("Could not get product_family");
if let Some(modes) = LedSupportFile::load_from_config() {
if let Some(data) = modes.matcher(&prod_family, &board_name) {
return data;
}
}
info!("Using generic LED control for keyboard brightness only");
LaptopLedData {
prod_family,
board_names: vec![board_name],
standard: vec![],
multizone: false,
per_key: false,
}
}
}
impl LedSupportFile {
/// Consumes the LEDModes
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
@@ -137,19 +87,19 @@ impl LedSupportFile {
}
fn load_from_config() -> Option<Self> {
if let Ok(mut file) = OpenOptions::new().read(true).open(&LEDMODE_CONFIG_PATH) {
if let Ok(mut file) = OpenOptions::new().read(true).open(&ASUS_LED_MODE_CONF) {
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
warn!("{} is empty", LEDMODE_CONFIG_PATH);
warn!("{} is empty", ASUS_LED_MODE_CONF);
} else {
return Some(toml::from_str(&buf).unwrap_or_else(|_| {
panic!("Could not deserialise {}", LEDMODE_CONFIG_PATH)
panic!("Could not deserialise {}", ASUS_LED_MODE_CONF)
}));
}
}
}
warn!("Does {} exist?", LEDMODE_CONFIG_PATH);
warn!("Does {} exist?", ASUS_LED_MODE_CONF);
None
}
}
+1 -1
View File
@@ -42,7 +42,7 @@ per_key = true
[[led_data]]
prod_family = "ROG Strix"
board_names = ["GX531", "G512LV", "G712LV"]
board_names = ["GX531", "G512LV", "G712LV", "G712LW"]
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
multizone = true
per_key = false
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rog_dbus"
version = "3.0.0"
version = "3.1.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
+6 -3
View File
@@ -23,7 +23,10 @@ use std::sync::{Arc, Mutex};
use zbus::{dbus_proxy, Connection, Result};
use rog_types::{aura_modes::AuraEffect, aura_perkey::KeyColourArray};
use rog_types::{
aura_modes::{AuraEffect, LedBrightness},
aura_perkey::KeyColourArray,
};
const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS
@@ -39,7 +42,7 @@ trait Daemon {
fn prev_led_mode(&self) -> zbus::Result<()>;
/// SetBrightness method
fn set_brightness(&self, brightness: u8) -> zbus::Result<()>;
fn set_brightness(&self, brightness: LedBrightness) -> zbus::Result<()>;
/// SetLedMode method
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
@@ -80,7 +83,7 @@ impl<'a> LedProxy<'a> {
}
#[inline]
pub fn set_led_brightness(&self, level: u8) -> Result<()> {
pub fn set_led_brightness(&self, level: LedBrightness) -> Result<()> {
self.0.set_brightness(level)?;
Ok(())
}
+12 -2
View File
@@ -42,7 +42,7 @@ trait Daemon {
fn profiles(&self) -> zbus::Result<String>;
/// ProfileNames method
fn profile_names(&self) -> zbus::Result<String>;
fn profile_names(&self) -> zbus::Result<Vec<String>>;
/// Remove method
fn remove(&self, profile: &str) -> zbus::Result<()>;
@@ -72,6 +72,16 @@ impl<'a> ProfileProxy<'a> {
self.0.active_profile_name()
}
#[inline]
pub fn active_profile_data(&self) -> Result<String> {
self.0.profile()
}
#[inline]
pub fn all_profile_data(&self) -> Result<String> {
self.0.profiles()
}
#[inline]
pub fn next_fan(&self) -> Result<()> {
self.0.next_profile()
@@ -89,7 +99,7 @@ impl<'a> ProfileProxy<'a> {
}
#[inline]
pub fn profile_names(&self) -> Result<String> {
pub fn profile_names(&self) -> Result<Vec<String>> {
self.0.profile_names()
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rog_types"
version = "3.1.0"
version = "3.2.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
+26
View File
@@ -10,6 +10,32 @@ use serde_derive::{Deserialize, Serialize};
use std::str::FromStr;
use zvariant_derive::Type;
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
pub enum LedBrightness {
Off,
Low,
Med,
High,
}
impl LedBrightness {
pub fn as_char_code(&self) -> u8 {
std::char::from_digit(*self as u32, 10).unwrap() as u8
}
}
impl From<u32> for LedBrightness {
fn from(bright: u32) -> Self {
match bright {
0 => LedBrightness::Off,
1 => LedBrightness::Low,
2 => LedBrightness::Med,
3 => LedBrightness::High,
_ => LedBrightness::Med,
}
}
}
#[derive(Debug, Clone, PartialEq, Copy, Deserialize, Serialize, Type)]
pub struct Colour(pub u8, pub u8, pub u8);
+50 -2
View File
@@ -3,6 +3,48 @@ use rog_fan_curve::{Curve, Fan};
use serde_derive::{Deserialize, Serialize};
use std::str::FromStr;
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Profile {
pub min_percentage: u8,
pub max_percentage: u8,
pub turbo: bool,
pub fan_preset: u8,
pub fan_curve: Option<Curve>,
}
#[deprecated]
pub type CPUSettings = Profile;
impl Default for Profile {
fn default() -> Self {
Profile {
min_percentage: 0,
max_percentage: 100,
turbo: false,
fan_preset: 0,
fan_curve: None,
}
}
}
impl Profile {
pub fn new(
min_percentage: u8,
max_percentage: u8,
turbo: bool,
fan_preset: u8,
fan_curve: Option<Curve>,
) -> Self {
Profile {
min_percentage,
max_percentage,
turbo,
fan_preset,
fan_curve,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ProfileEvent {
Cli(ProfileCommand),
@@ -80,8 +122,16 @@ pub struct ProfileCommand {
pub next: bool,
#[options(help = "create the profile if it doesn't exist")]
pub create: bool,
#[options(meta = "", help = "remove a profile by name")]
pub remove: Option<String>,
#[options(help = "list available profiles")]
pub list: bool,
#[options(help = "get active profile name")]
pub active_name: bool,
#[options(help = "get active profile data")]
pub active_data: bool,
#[options(help = "get all profile data")]
pub profiles_data: bool,
#[options(meta = "", help = "enable or disable cpu turbo")]
pub turbo: Option<bool>,
@@ -100,6 +150,4 @@ pub struct ProfileCommand {
pub curve: Option<Curve>,
#[options(free)]
pub profile: Option<String>,
#[options(help = "remove a profile by name")]
pub remove: Option<String>,
}