mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fbc248177a | |||
| fc3d7653f5 | |||
| 2dc70ea6af | |||
| 01345b28a5 | |||
| 4eeacea832 | |||
| 6bf0fdd117 | |||
| 7fcde7df17 | |||
| 543b0b817f | |||
| 5a7d31fdf6 | |||
| 301c532b65 | |||
| df7ae4d014 | |||
| 96ceef1bdb | |||
| bc72b93625 | |||
| 03b338bdfa | |||
| 7a51cd1c70 | |||
| 0449a4b06b |
@@ -5,6 +5,34 @@ 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).
|
||||
|
||||
## [Unreleased]
|
||||
# [3.3.0] - 2021-04-3
|
||||
### Changed
|
||||
- Add ledmodes for G733QS
|
||||
- Add ledmodes for GA401Q
|
||||
- Default to vfio disabled in configuration. Will now hard-error if enabled and
|
||||
the kernel modules are builtin. To enable vfio switching `"gfx_vfio_enable": false,`
|
||||
must be changed to `true` in `/etc/asusd/asusd.conf`
|
||||
|
||||
# [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
|
||||
|
||||
Generated
+5
-4
@@ -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.3.0"
|
||||
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",
|
||||
|
||||
@@ -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,12 @@ 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.
|
||||
|
||||
To enable vfio switching you need to edit `/etc/asusd/asusd.conf` and change `"gfx_vfio_enable": false,` to true.
|
||||
|
||||
### Power management udev rule
|
||||
|
||||
If you have installed the Nvidia driver manually you will require the
|
||||
@@ -89,8 +95,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 +115,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 +159,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 +183,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 +204,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 +213,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 +241,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
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
@@ -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,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
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "asusctl"
|
||||
version = "3.1.4"
|
||||
version = "3.1.5"
|
||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||
edition = "2018"
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use rog_dbus::AuraDbusClient;
|
||||
use rog_types::anime_matrix::{AniMeImageBuffer, AniMePacketType, HEIGHT, WIDTH};
|
||||
use rog_types::anime_matrix::{AniMeImageBuffer, HEIGHT, WIDTH};
|
||||
use tinybmp::{Bmp, Pixel};
|
||||
|
||||
fn main() {
|
||||
let (client, _) = AuraDbusClient::new().unwrap();
|
||||
|
||||
let bmp =
|
||||
Bmp::from_slice(include_bytes!("non-skewed_r.bmp")).expect("Failed to parse BMP image");
|
||||
let bmp = Bmp::from_slice(include_bytes!("rust.bmp")).expect("Failed to parse BMP image");
|
||||
let pixels: Vec<Pixel> = bmp.into_iter().collect();
|
||||
//assert_eq!(pixels.len(), 56 * 56);
|
||||
|
||||
@@ -16,27 +15,30 @@ fn main() {
|
||||
// Aligned left
|
||||
for (i, px) in pixels.iter().enumerate() {
|
||||
if (px.x as usize / 2) < WIDTH && (px.y as usize) < HEIGHT && px.x % 2 == 0 {
|
||||
let mut c = px.color as u32;
|
||||
let c = px.color as u32;
|
||||
matrix.get_mut()[px.y as usize][px.x as usize / 2] = c as u8;
|
||||
}
|
||||
}
|
||||
|
||||
// Throw an alignment border up
|
||||
// {
|
||||
// let tmp = matrix.get_mut();
|
||||
// for x in tmp[0].iter_mut() {
|
||||
// *x = 0xff;
|
||||
// }
|
||||
// for row in tmp.iter_mut() {
|
||||
// row[row.len() - 1] = 0xff;
|
||||
// }
|
||||
// }
|
||||
{
|
||||
let tmp = matrix.get_mut();
|
||||
for x in tmp[0].iter_mut() {
|
||||
*x = 0xff;
|
||||
}
|
||||
for (i, row) in tmp.iter_mut().enumerate() {
|
||||
if i % 2 == 0 {
|
||||
let l = row.len();
|
||||
row[l - 1] = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix.debug_print();
|
||||
|
||||
let mut matrix: AniMePacketType = AniMePacketType::from(matrix);
|
||||
//let mut matrix: AniMePacketType = AniMePacketType::from(matrix);
|
||||
// println!("{:?}", matrix[0].to_vec());
|
||||
// println!("{:?}", matrix[1].to_vec());
|
||||
|
||||
//client.proxies().anime().set_brightness(&mut matrix).unwrap();
|
||||
client.proxies().anime().write_image(matrix).unwrap();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "daemon"
|
||||
version = "3.2.0"
|
||||
version = "3.3.0"
|
||||
license = "MPL-2.0"
|
||||
readme = "README.md"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
|
||||
+8
-44
@@ -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};
|
||||
@@ -16,6 +15,7 @@ pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
||||
pub struct Config {
|
||||
pub gfx_mode: GfxVendors,
|
||||
pub gfx_managed: bool,
|
||||
pub gfx_vfio_enable: bool,
|
||||
pub active_profile: String,
|
||||
pub toggle_profiles: Vec<String>,
|
||||
#[serde(skip)]
|
||||
@@ -34,6 +34,7 @@ impl Default for Config {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: true,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: "normal".into(),
|
||||
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
|
||||
curr_fan_mode: 0,
|
||||
@@ -64,6 +65,11 @@ impl Config {
|
||||
} else {
|
||||
if let Ok(data) = serde_json::from_str(&buf) {
|
||||
return data;
|
||||
} else if let Ok(data) = serde_json::from_str::<ConfigV324>(&buf) {
|
||||
let config = data.into_current();
|
||||
config.write();
|
||||
info!("Updated config version to: {}", VERSION);
|
||||
return config;
|
||||
} else if let Ok(data) = serde_json::from_str::<ConfigV317>(&buf) {
|
||||
let config = data.into_current();
|
||||
config.write();
|
||||
@@ -136,45 +142,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)]
|
||||
@@ -25,6 +25,7 @@ impl ConfigV212 {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
active_profile: self.active_profile,
|
||||
gfx_vfio_enable: false,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.power_profile,
|
||||
bat_charge_limit: self.bat_charge_limit,
|
||||
@@ -53,6 +54,7 @@ impl ConfigV222 {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.power_profile,
|
||||
@@ -84,6 +86,7 @@ impl ConfigV301 {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.curr_fan_mode,
|
||||
@@ -115,6 +118,34 @@ impl ConfigV317 {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.curr_fan_mode,
|
||||
bat_charge_limit: self.bat_charge_limit,
|
||||
power_profiles: self.power_profiles,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct ConfigV324 {
|
||||
pub gfx_mode: GfxVendors,
|
||||
pub gfx_managed: bool,
|
||||
pub active_profile: String,
|
||||
pub toggle_profiles: Vec<String>,
|
||||
#[serde(skip)]
|
||||
pub curr_fan_mode: u8,
|
||||
pub bat_charge_limit: u8,
|
||||
pub power_profiles: BTreeMap<String, Profile>,
|
||||
}
|
||||
|
||||
impl ConfigV324 {
|
||||
pub(crate) fn into_current(self) -> Config {
|
||||
Config {
|
||||
gfx_mode: GfxVendors::Hybrid,
|
||||
gfx_managed: self.gfx_managed,
|
||||
gfx_vfio_enable: false,
|
||||
active_profile: self.active_profile,
|
||||
toggle_profiles: self.toggle_profiles,
|
||||
curr_fan_mode: self.curr_fan_mode,
|
||||
|
||||
+26
-28
@@ -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)]
|
||||
|
||||
@@ -10,6 +10,11 @@ pub enum GfxError {
|
||||
DisplayManagerAction(String, ExitStatus),
|
||||
DisplayManagerTimeout(String),
|
||||
GsyncModeActive,
|
||||
VfioBuiltin,
|
||||
VfioDisabled,
|
||||
MissingModule(String),
|
||||
Modprobe(String),
|
||||
Command(String, std::io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for GfxError {
|
||||
@@ -28,6 +33,16 @@ 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::VfioDisabled => {
|
||||
write!(f, "Can not switch to vfio mode if disabled in config file")
|
||||
}
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+77
-47
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,6 +427,7 @@ impl CtrlGraphics {
|
||||
/// The daemon needs direct access to this function when it detects that the
|
||||
pub fn do_vendor_tasks(
|
||||
vendor: GfxVendors,
|
||||
vfio_enable: bool,
|
||||
devices: &[GraphicsDevice],
|
||||
bus: &PciBus,
|
||||
) -> Result<(), RogError> {
|
||||
@@ -431,23 +440,33 @@ impl CtrlGraphics {
|
||||
|
||||
match vendor {
|
||||
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
|
||||
for driver in VFIO_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
if vfio_enable {
|
||||
for driver in VFIO_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
}
|
||||
}
|
||||
for driver in NVIDIA_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "modprobe")?;
|
||||
}
|
||||
}
|
||||
GfxVendors::Vfio => {
|
||||
for driver in NVIDIA_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
if vfio_enable {
|
||||
Self::do_driver_action("nouveau", "rmmod")?;
|
||||
for driver in NVIDIA_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
}
|
||||
Self::unbind_only(&devices)?;
|
||||
Self::do_driver_action("vfio-pci", "modprobe")?;
|
||||
} else {
|
||||
return Err(GfxError::VfioDisabled.into());
|
||||
}
|
||||
Self::unbind_only(&devices)?;
|
||||
Self::do_driver_action("vfio-pci", "modprobe")?;
|
||||
}
|
||||
GfxVendors::Integrated => {
|
||||
for driver in VFIO_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
Self::do_driver_action("nouveau", "rmmod")?;
|
||||
if vfio_enable {
|
||||
for driver in VFIO_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
}
|
||||
}
|
||||
for driver in NVIDIA_DRIVERS.iter() {
|
||||
Self::do_driver_action(driver, "rmmod")?;
|
||||
@@ -455,11 +474,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 +487,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 +519,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 +542,28 @@ 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")?;
|
||||
Self::wait_display_manager_state("inactive")?;
|
||||
|
||||
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")?;
|
||||
}
|
||||
}
|
||||
let vfio_enable = if let Ok(config) = config.lock() {
|
||||
config.gfx_vfio_enable
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
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_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||
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 +571,7 @@ impl CtrlGraphics {
|
||||
info!("GFX: Cancelling previous thread");
|
||||
tx.send(true)
|
||||
.map_err(|err| {
|
||||
warn!("GFX: {}", err);
|
||||
warn!("GFX thread: {}", err);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
@@ -605,6 +616,17 @@ impl CtrlGraphics {
|
||||
return Err(GfxError::GsyncModeActive.into());
|
||||
}
|
||||
}
|
||||
|
||||
let vfio_enable = if let Ok(config) = self.config.lock() {
|
||||
config.gfx_vfio_enable
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if !vfio_enable && matches!(vendor, GfxVendors::Vfio) {
|
||||
return Err(GfxError::VfioDisabled.into());
|
||||
}
|
||||
|
||||
// Must always cancel any thread running
|
||||
self.cancel_thread();
|
||||
// determine which method we need here
|
||||
@@ -618,7 +640,8 @@ impl CtrlGraphics {
|
||||
info!("GFX: mode change does not require logout");
|
||||
let devices = self.nvidia.clone();
|
||||
let bus = self.bus.clone();
|
||||
Self::do_vendor_tasks(vendor, &devices, &bus)?;
|
||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
|
||||
}
|
||||
// TODO: undo if failed? Save last mode, catch errors...
|
||||
Ok(action_required)
|
||||
@@ -629,7 +652,14 @@ impl CtrlGraphics {
|
||||
let vendor = self.get_gfx_mode()?;
|
||||
let devices = self.nvidia.clone();
|
||||
let bus = self.bus.clone();
|
||||
Self::do_vendor_tasks(vendor, &devices, &bus)?;
|
||||
|
||||
let vfio_enable = if let Ok(config) = self.config.lock() {
|
||||
config.gfx_vfio_enable
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||
Self::toggle_fallback_service(vendor)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+48
-122
@@ -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)
|
||||
}
|
||||
|
||||
+19
-20
@@ -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;
|
||||
@@ -107,7 +109,12 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||
let devices = ctrl.devices();
|
||||
let bus = ctrl.bus();
|
||||
CtrlGraphics::do_vendor_tasks(GfxVendors::Nvidia, &devices, &bus)?;
|
||||
CtrlGraphics::do_vendor_tasks(
|
||||
GfxVendors::Nvidia,
|
||||
false,
|
||||
&devices,
|
||||
&bus,
|
||||
)?;
|
||||
} else if ded == 0 {
|
||||
info!("Dedicated GFX toggle is off");
|
||||
}
|
||||
@@ -136,23 +143,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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@ per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Strix"
|
||||
board_names = ["G531GW"]
|
||||
board_names = ["G531GW", "G733QS", "G733QR"]
|
||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||
multizone = false
|
||||
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
|
||||
@@ -80,4 +80,11 @@ prod_family = "ROG"
|
||||
board_names = ["GL553VE"]
|
||||
standard = ["Static", "Breathe", "Strobe"]
|
||||
multizone = true
|
||||
per_key = false
|
||||
|
||||
[[led_data]]
|
||||
prod_family = "ROG Zephyrus G14"
|
||||
board_names = ["GA401Q"]
|
||||
standard = ["Static", "Breathe", "Pulse"]
|
||||
multizone = false
|
||||
per_key = false
|
||||
+1
-1
@@ -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>"]
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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,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>"]
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user