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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [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
|
# [3.2.0] - 2021-03-21
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
Generated
+5
-4
@@ -28,12 +28,13 @@ dependencies = [
|
|||||||
"daemon",
|
"daemon",
|
||||||
"notify-rust",
|
"notify-rust",
|
||||||
"rog_dbus",
|
"rog_dbus",
|
||||||
|
"rog_types",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "asusctl"
|
name = "asusctl"
|
||||||
version = "3.1.4"
|
version = "3.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"daemon",
|
"daemon",
|
||||||
"gumdrop",
|
"gumdrop",
|
||||||
@@ -196,7 +197,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daemon"
|
name = "daemon"
|
||||||
version = "3.2.0"
|
version = "3.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"intel-pstate",
|
"intel-pstate",
|
||||||
@@ -887,7 +888,7 @@ checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rog_dbus"
|
name = "rog_dbus"
|
||||||
version = "3.0.0"
|
version = "3.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rog_fan_curve",
|
"rog_fan_curve",
|
||||||
"rog_types",
|
"rog_types",
|
||||||
@@ -908,7 +909,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rog_types"
|
name = "rog_types"
|
||||||
version = "3.1.0"
|
version = "3.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gumdrop",
|
"gumdrop",
|
||||||
"rog_fan_curve",
|
"rog_fan_curve",
|
||||||
|
|||||||
@@ -5,29 +5,26 @@
|
|||||||
`asusd` is a utility for Linux to control many aspects of various ASUS laptops
|
`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.
|
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:**
|
**NOTICE:**
|
||||||
The following is *not* required for 5.11 kernel versions, as this version includes
|
1. The following is *not* required for 5.11 kernel versions, as this version includes all the required patches.
|
||||||
all the required patches.
|
2. 2021 hardware has a new keyboard prod_id and the patch is included in 5.12+
|
||||||
---
|
|
||||||
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/).
|
|
||||||
|
|
||||||
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)
|
- 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
|
## Discord
|
||||||
|
|
||||||
@@ -52,13 +49,14 @@ will probably suffer another rename once it becomes generic enough to do so.
|
|||||||
- [X] User notifications daemon
|
- [X] User notifications daemon
|
||||||
- [X] Setting/modifying built-in LED modes
|
- [X] Setting/modifying built-in LED modes
|
||||||
- [X] Per-key LED setting
|
- [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] Saving settings for reload
|
||||||
- [X] Logging - required for journalctl
|
- [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] Set battery charge limit (with kernel supporting this)
|
||||||
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
|
- [X] Fan curve control on G14 + G15 thanks to @Yarn1
|
||||||
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
|
- [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 boot/POST sound
|
||||||
- [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync)
|
- [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
|
## Graphics switching
|
||||||
|
|
||||||
A new feature has been added to enable switching graphics modes. This can be disabled
|
`asusd` can switch graphics modes between:
|
||||||
in the config with `"manage_gfx": false,`. Additionally there is an extra setting
|
- `integrated`, uses the iGPU only and force-disables the dGPU
|
||||||
for laptops capable of g-sync dedicated gfx mode to enable the graphics switching
|
- `hybrid`, enables Nvidia prime-offload mode
|
||||||
to switch on dedicated gfx for "nvidia" 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
|
This can be disabled in the config with `"manage_gfx": false,`. Additionally there
|
||||||
instructions.
|
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
|
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`
|
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/`
|
- `/etc/modprobe.d/`
|
||||||
- `/usr/lib/modprope.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
|
### Power management udev rule
|
||||||
|
|
||||||
If you have installed the Nvidia driver manually you will require the
|
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
|
### fedora and openSUSE
|
||||||
|
|
||||||
You *may* need a file `/etc/dracut.conf.d/90-nvidia-dracut-G05.conf` installed
|
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
|
to stop dracut including the nvidia modules in the ramdisk if you manually
|
||||||
true if you manually installed the nvidia drivers.
|
installed the nvidia drivers.
|
||||||
|
|
||||||
```
|
```
|
||||||
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
|
# 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
|
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:
|
`/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as follows:
|
||||||
|
|
||||||
```
|
- Static
|
||||||
0 STATIC
|
- Breathe
|
||||||
1 BREATHING
|
- Strobe
|
||||||
2 STROBE
|
- Rainbow
|
||||||
3 RAINBOW
|
- Star
|
||||||
4 STAR
|
- Rain
|
||||||
5 RAIN
|
- Highlight
|
||||||
6 HIGHLIGHT
|
- Laser
|
||||||
7 LASER
|
- Ripple
|
||||||
8 RIPPLE
|
- Pulse
|
||||||
10 PULSE
|
- Comet
|
||||||
11 COMET
|
- Flash
|
||||||
12 FLASH
|
|
||||||
13 MULTISTATIC
|
|
||||||
255 PER_KEY
|
|
||||||
```
|
|
||||||
|
|
||||||
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
|
# 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/)
|
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.
|
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/`.
|
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
|
# 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:
|
Commands are given by:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -221,23 +204,6 @@ Some commands may have subcommands:
|
|||||||
asusctl <command> <subcommand> --help
|
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
|
## User NOTIFICATIONS via dbus
|
||||||
|
|
||||||
If you have a notifications handler set up, or are using KDE or Gnome then you
|
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 enable asus-notify.service
|
||||||
systemctl --user start asus-notify.service
|
systemctl --user start asus-notify.service
|
||||||
```
|
```
|
||||||
|
|
||||||
# OTHER
|
# OTHER
|
||||||
|
|
||||||
## DBUS Input
|
|
||||||
|
|
||||||
See [README_DBUS.md](./README_DBUS.md).
|
|
||||||
|
|
||||||
## AniMe input
|
## AniMe input
|
||||||
|
|
||||||
You will want to look at what MeuMeu has done with [https://github.com/Meumeu/ZephyrusBling/](https://github.com/Meumeu/ZephyrusBling/)
|
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
|
# License
|
||||||
|
|
||||||
Mozilla Public License 2 (MPL-2.0)
|
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
|
# serialisation
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
rog_dbus = { path = "../rog-dbus" }
|
rog_dbus = { path = "../rog-dbus" }
|
||||||
|
rog_types = { path = "../rog-types" }
|
||||||
daemon = { path = "../daemon" }
|
daemon = { path = "../daemon" }
|
||||||
|
|
||||||
[dependencies.notify-rust]
|
[dependencies.notify-rust]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use daemon::config::Profile;
|
|
||||||
use notify_rust::{Hint, Notification, NotificationHandle};
|
use notify_rust::{Hint, Notification, NotificationHandle};
|
||||||
use rog_dbus::{DbusProxies, Signals};
|
use rog_dbus::{DbusProxies, Signals};
|
||||||
|
use rog_types::profile::Profile;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asusctl"
|
name = "asusctl"
|
||||||
version = "3.1.4"
|
version = "3.1.5"
|
||||||
authors = ["Luke D Jones <luke@ljones.dev>"]
|
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
use rog_dbus::AuraDbusClient;
|
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};
|
use tinybmp::{Bmp, Pixel};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (client, _) = AuraDbusClient::new().unwrap();
|
let (client, _) = AuraDbusClient::new().unwrap();
|
||||||
|
|
||||||
let bmp =
|
let bmp = Bmp::from_slice(include_bytes!("rust.bmp")).expect("Failed to parse BMP image");
|
||||||
Bmp::from_slice(include_bytes!("non-skewed_r.bmp")).expect("Failed to parse BMP image");
|
|
||||||
let pixels: Vec<Pixel> = bmp.into_iter().collect();
|
let pixels: Vec<Pixel> = bmp.into_iter().collect();
|
||||||
//assert_eq!(pixels.len(), 56 * 56);
|
//assert_eq!(pixels.len(), 56 * 56);
|
||||||
|
|
||||||
@@ -16,27 +15,30 @@ fn main() {
|
|||||||
// Aligned left
|
// Aligned left
|
||||||
for (i, px) in pixels.iter().enumerate() {
|
for (i, px) in pixels.iter().enumerate() {
|
||||||
if (px.x as usize / 2) < WIDTH && (px.y as usize) < HEIGHT && px.x % 2 == 0 {
|
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;
|
matrix.get_mut()[px.y as usize][px.x as usize / 2] = c as u8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Throw an alignment border up
|
// Throw an alignment border up
|
||||||
// {
|
{
|
||||||
// let tmp = matrix.get_mut();
|
let tmp = matrix.get_mut();
|
||||||
// for x in tmp[0].iter_mut() {
|
for x in tmp[0].iter_mut() {
|
||||||
// *x = 0xff;
|
*x = 0xff;
|
||||||
// }
|
}
|
||||||
// for row in tmp.iter_mut() {
|
for (i, row) in tmp.iter_mut().enumerate() {
|
||||||
// row[row.len() - 1] = 0xff;
|
if i % 2 == 0 {
|
||||||
// }
|
let l = row.len();
|
||||||
// }
|
row[l - 1] = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
matrix.debug_print();
|
matrix.debug_print();
|
||||||
|
|
||||||
let mut matrix: AniMePacketType = AniMePacketType::from(matrix);
|
//let mut matrix: AniMePacketType = AniMePacketType::from(matrix);
|
||||||
// println!("{:?}", matrix[0].to_vec());
|
// println!("{:?}", matrix[0].to_vec());
|
||||||
// println!("{:?}", matrix[1].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)]
|
#[derive(Options)]
|
||||||
pub struct LedBrightness {
|
pub struct LedBrightness {
|
||||||
level: Option<u8>,
|
level: Option<u32>,
|
||||||
}
|
}
|
||||||
impl LedBrightness {
|
impl LedBrightness {
|
||||||
pub fn new(level: Option<u8>) -> Self {
|
pub fn new(level: Option<u32>) -> Self {
|
||||||
LedBrightness { level }
|
LedBrightness { level }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn level(&self) -> Option<u8> {
|
pub fn level(&self) -> Option<u32> {
|
||||||
self.level
|
self.level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-7
@@ -9,7 +9,7 @@ use gumdrop::{Opt, Options};
|
|||||||
use rog_dbus::AuraDbusClient;
|
use rog_dbus::AuraDbusClient;
|
||||||
use rog_types::{
|
use rog_types::{
|
||||||
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
|
anime_matrix::{AniMeDataBuffer, FULL_PANE_LEN},
|
||||||
aura_modes::{AuraEffect, AuraModeNum},
|
aura_modes::{self, AuraEffect, AuraModeNum},
|
||||||
cli_options::{AniMeActions, AniMeStatusValue},
|
cli_options::{AniMeActions, AniMeStatusValue},
|
||||||
gfx_vendors::GfxVendors,
|
gfx_vendors::GfxVendors,
|
||||||
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
profile::{FanLevel, ProfileCommand, ProfileEvent},
|
||||||
@@ -143,6 +143,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
|
|
||||||
if parsed.help {
|
if parsed.help {
|
||||||
print_supported_help(&supported, &parsed);
|
print_supported_help(&supported, &parsed);
|
||||||
|
println!("\nSee https://asus-linux.org/faq/ for additional help");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +203,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let level = dbus.proxies().led().get_led_brightness()?;
|
let level = dbus.proxies().led().get_led_brightness()?;
|
||||||
println!("Current keyboard led brightness: {}", level.to_string());
|
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
|
if !cmd.next
|
||||||
&& !cmd.create
|
&& !cmd.create
|
||||||
&& !cmd.list
|
&& !cmd.list
|
||||||
|
&& !cmd.active_name
|
||||||
|
&& !cmd.active_data
|
||||||
|
&& !cmd.profiles_data
|
||||||
&& cmd.remove.is_none()
|
&& cmd.remove.is_none()
|
||||||
&& cmd.curve.is_none()
|
&& cmd.curve.is_none()
|
||||||
&& cmd.max_percentage.is_none()
|
&& cmd.max_percentage.is_none()
|
||||||
@@ -416,12 +423,34 @@ fn handle_profile(
|
|||||||
|
|
||||||
if cmd.next {
|
if cmd.next {
|
||||||
dbus.proxies().profile().next_fan()?;
|
dbus.proxies().profile().next_fan()?;
|
||||||
} else if cmd.list {
|
}
|
||||||
let profile_names = dbus.proxies().profile().profile_names()?;
|
if let Some(profile) = &cmd.remove {
|
||||||
println!("Available profiles are {}", profile_names);
|
|
||||||
} else if let Some(profile) = &cmd.remove {
|
|
||||||
dbus.proxies().profile().remove(profile)?
|
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()
|
dbus.proxies()
|
||||||
.profile()
|
.profile()
|
||||||
.write_command(&ProfileEvent::Cli(cmd.clone()))?
|
.write_command(&ProfileEvent::Cli(cmd.clone()))?
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "daemon"
|
name = "daemon"
|
||||||
version = "3.2.0"
|
version = "3.3.0"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["Luke <luke@ljones.dev>"]
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
|||||||
+8
-44
@@ -1,6 +1,5 @@
|
|||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_fan_curve::Curve;
|
use rog_types::{gfx_vendors::GfxVendors, profile::Profile};
|
||||||
use rog_types::gfx_vendors::GfxVendors;
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
@@ -16,6 +15,7 @@ pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
|||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub gfx_mode: GfxVendors,
|
pub gfx_mode: GfxVendors,
|
||||||
pub gfx_managed: bool,
|
pub gfx_managed: bool,
|
||||||
|
pub gfx_vfio_enable: bool,
|
||||||
pub active_profile: String,
|
pub active_profile: String,
|
||||||
pub toggle_profiles: Vec<String>,
|
pub toggle_profiles: Vec<String>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
@@ -34,6 +34,7 @@ impl Default for Config {
|
|||||||
Config {
|
Config {
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: true,
|
gfx_managed: true,
|
||||||
|
gfx_vfio_enable: false,
|
||||||
active_profile: "normal".into(),
|
active_profile: "normal".into(),
|
||||||
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
|
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
|
||||||
curr_fan_mode: 0,
|
curr_fan_mode: 0,
|
||||||
@@ -64,6 +65,11 @@ impl Config {
|
|||||||
} else {
|
} else {
|
||||||
if let Ok(data) = serde_json::from_str(&buf) {
|
if let Ok(data) = serde_json::from_str(&buf) {
|
||||||
return data;
|
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) {
|
} else if let Ok(data) = serde_json::from_str::<ConfigV317>(&buf) {
|
||||||
let config = data.into_current();
|
let config = data.into_current();
|
||||||
config.write();
|
config.write();
|
||||||
@@ -136,45 +142,3 @@ impl Config {
|
|||||||
.unwrap_or_else(|err| error!("Could not write config: {}", err));
|
.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 crate::laptops::LaptopLedData;
|
||||||
use log::{error, warn};
|
use log::{error, info, warn};
|
||||||
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone};
|
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone, LedBrightness};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
@@ -8,9 +8,28 @@ use std::io::{Read, Write};
|
|||||||
|
|
||||||
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
|
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)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct AuraConfig {
|
pub struct AuraConfig {
|
||||||
pub brightness: u8,
|
pub brightness: LedBrightness,
|
||||||
pub current_mode: AuraModeNum,
|
pub current_mode: AuraModeNum,
|
||||||
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
|
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
|
||||||
pub multizone: Option<AuraMultiZone>,
|
pub multizone: Option<AuraMultiZone>,
|
||||||
@@ -19,7 +38,7 @@ pub struct AuraConfig {
|
|||||||
impl Default for AuraConfig {
|
impl Default for AuraConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
AuraConfig {
|
AuraConfig {
|
||||||
brightness: 1,
|
brightness: LedBrightness::Med,
|
||||||
current_mode: AuraModeNum::Static,
|
current_mode: AuraModeNum::Static,
|
||||||
builtins: BTreeMap::new(),
|
builtins: BTreeMap::new(),
|
||||||
multizone: None,
|
multizone: None,
|
||||||
@@ -48,6 +67,11 @@ impl AuraConfig {
|
|||||||
} else {
|
} else {
|
||||||
if let Ok(data) = serde_json::from_str(&buf) {
|
if let Ok(data) = serde_json::from_str(&buf) {
|
||||||
return data;
|
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);
|
warn!("Could not deserialise {}", AURA_CONFIG_PATH);
|
||||||
panic!("Please remove {} then restart asusd", 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 serde_derive::{Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::config::{Config, Profile};
|
use crate::config::Config;
|
||||||
|
|
||||||
/// for parsing old v2.1.2 config
|
/// for parsing old v2.1.2 config
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -25,6 +25,7 @@ impl ConfigV212 {
|
|||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: self.gfx_managed,
|
gfx_managed: self.gfx_managed,
|
||||||
active_profile: self.active_profile,
|
active_profile: self.active_profile,
|
||||||
|
gfx_vfio_enable: false,
|
||||||
toggle_profiles: self.toggle_profiles,
|
toggle_profiles: self.toggle_profiles,
|
||||||
curr_fan_mode: self.power_profile,
|
curr_fan_mode: self.power_profile,
|
||||||
bat_charge_limit: self.bat_charge_limit,
|
bat_charge_limit: self.bat_charge_limit,
|
||||||
@@ -53,6 +54,7 @@ impl ConfigV222 {
|
|||||||
Config {
|
Config {
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: self.gfx_managed,
|
gfx_managed: self.gfx_managed,
|
||||||
|
gfx_vfio_enable: false,
|
||||||
active_profile: self.active_profile,
|
active_profile: self.active_profile,
|
||||||
toggle_profiles: self.toggle_profiles,
|
toggle_profiles: self.toggle_profiles,
|
||||||
curr_fan_mode: self.power_profile,
|
curr_fan_mode: self.power_profile,
|
||||||
@@ -84,6 +86,7 @@ impl ConfigV301 {
|
|||||||
Config {
|
Config {
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: self.gfx_managed,
|
gfx_managed: self.gfx_managed,
|
||||||
|
gfx_vfio_enable: false,
|
||||||
active_profile: self.active_profile,
|
active_profile: self.active_profile,
|
||||||
toggle_profiles: self.toggle_profiles,
|
toggle_profiles: self.toggle_profiles,
|
||||||
curr_fan_mode: self.curr_fan_mode,
|
curr_fan_mode: self.curr_fan_mode,
|
||||||
@@ -115,6 +118,34 @@ impl ConfigV317 {
|
|||||||
Config {
|
Config {
|
||||||
gfx_mode: GfxVendors::Hybrid,
|
gfx_mode: GfxVendors::Hybrid,
|
||||||
gfx_managed: self.gfx_managed,
|
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,
|
active_profile: self.active_profile,
|
||||||
toggle_profiles: self.toggle_profiles,
|
toggle_profiles: self.toggle_profiles,
|
||||||
curr_fan_mode: self.curr_fan_mode,
|
curr_fan_mode: self.curr_fan_mode,
|
||||||
|
|||||||
+26
-28
@@ -1,10 +1,7 @@
|
|||||||
use crate::error::RogError;
|
use crate::error::RogError;
|
||||||
use crate::{
|
use crate::{config::Config, GetSupported};
|
||||||
config::{Config, Profile},
|
|
||||||
GetSupported,
|
|
||||||
};
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use rog_types::profile::{FanLevel, ProfileEvent};
|
use rog_types::profile::{FanLevel, Profile, ProfileEvent};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@@ -90,60 +87,61 @@ impl DbusFanAndCpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the active profile name
|
/// 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(ctrl) = self.inner.try_lock() {
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
cfg.read();
|
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
|
/// 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(ctrl) = self.inner.try_lock() {
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
cfg.read();
|
cfg.read();
|
||||||
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||||
if let Ok(json) = serde_json::to_string(profile) {
|
if let Ok(json) = serde_json::to_string_pretty(profile) {
|
||||||
return json;
|
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(ctrl) = self.inner.try_lock() {
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
cfg.read();
|
cfg.read();
|
||||||
if let Ok(json) = serde_json::to_string(&cfg.power_profiles) {
|
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
|
||||||
return json;
|
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(ctrl) = self.inner.try_lock() {
|
||||||
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
cfg.read();
|
cfg.read();
|
||||||
|
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
|
||||||
let profile_names: String = cfg
|
return Ok(profile_names);
|
||||||
.power_profiles
|
|
||||||
.keys()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
return profile_names;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"Failed".to_string()
|
Err(Error::Failed("Failed to get all profile names".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
|
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)]
|
#[dbus_interface(signal)]
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ pub enum GfxError {
|
|||||||
DisplayManagerAction(String, ExitStatus),
|
DisplayManagerAction(String, ExitStatus),
|
||||||
DisplayManagerTimeout(String),
|
DisplayManagerTimeout(String),
|
||||||
GsyncModeActive,
|
GsyncModeActive,
|
||||||
|
VfioBuiltin,
|
||||||
|
VfioDisabled,
|
||||||
|
MissingModule(String),
|
||||||
|
Modprobe(String),
|
||||||
|
Command(String, std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for GfxError {
|
impl fmt::Display for GfxError {
|
||||||
@@ -28,6 +33,16 @@ impl fmt::Display for GfxError {
|
|||||||
f,
|
f,
|
||||||
"Can not switch gfx modes when dedicated/G-Sync mode is active"
|
"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 ctrl_rog_bios::CtrlRogBios;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use logind_zbus::{
|
use logind_zbus::{
|
||||||
types::{SessionClass, SessionInfo, SessionType},
|
types::{SessionClass, SessionInfo, SessionState, SessionType},
|
||||||
ManagerProxy, SessionProxy,
|
ManagerProxy, SessionProxy,
|
||||||
};
|
};
|
||||||
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
|
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
|
||||||
@@ -95,10 +95,8 @@ impl Reloadable for CtrlGraphics {
|
|||||||
impl CtrlGraphics {
|
impl CtrlGraphics {
|
||||||
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
|
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
|
||||||
let bus = PciBus::new()?;
|
let bus = PciBus::new()?;
|
||||||
|
|
||||||
info!("GFX: Rescanning PCI bus");
|
info!("GFX: Rescanning PCI bus");
|
||||||
bus.rescan()?;
|
bus.rescan()?;
|
||||||
|
|
||||||
let devs = PciDevice::all()?;
|
let devs = PciDevice::all()?;
|
||||||
|
|
||||||
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
|
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
|
||||||
@@ -169,7 +167,6 @@ impl CtrlGraphics {
|
|||||||
config.gfx_mode = vendor;
|
config.gfx_mode = vendor;
|
||||||
config.write();
|
config.write();
|
||||||
}
|
}
|
||||||
// TODO: Error here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Associated method to get which vendor mode is set
|
/// Associated method to get which vendor mode is set
|
||||||
@@ -187,6 +184,7 @@ impl CtrlGraphics {
|
|||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Some systems have a fallback service to load nouveau if nvidia fails
|
||||||
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
|
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
|
||||||
let action = if vendor == GfxVendors::Nvidia {
|
let action = if vendor == GfxVendors::Nvidia {
|
||||||
info!("GFX: Enabling nvidia-fallback.service");
|
info!("GFX: Enabling nvidia-fallback.service");
|
||||||
@@ -213,6 +211,7 @@ impl CtrlGraphics {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the appropriate xorg config for the chosen mode
|
||||||
fn write_xorg_conf(vendor: GfxVendors) -> Result<(), RogError> {
|
fn write_xorg_conf(vendor: GfxVendors) -> Result<(), RogError> {
|
||||||
let text = if vendor == GfxVendors::Nvidia {
|
let text = if vendor == GfxVendors::Nvidia {
|
||||||
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
|
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
|
||||||
@@ -239,6 +238,7 @@ impl CtrlGraphics {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates the full modprobe.conf required for vfio pass-through
|
||||||
fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec<u8> {
|
fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec<u8> {
|
||||||
let mut vifo = MODPROBE_VFIO.to_vec();
|
let mut vifo = MODPROBE_VFIO.to_vec();
|
||||||
for (d_count, dev) in devices.iter().enumerate() {
|
for (d_count, dev) in devices.iter().enumerate() {
|
||||||
@@ -303,7 +303,7 @@ impl CtrlGraphics {
|
|||||||
.map_err(|err| RogError::Command("device unbind error".into(), err))
|
.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);
|
let mut cmd = Command::new(action);
|
||||||
cmd.arg(driver);
|
cmd.arg(driver);
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ impl CtrlGraphics {
|
|||||||
|
|
||||||
let output = cmd
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
.map_err(|err| GfxError::Command(format!("{:?}", cmd), err))?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
if output
|
if output
|
||||||
.stderr
|
.stderr
|
||||||
@@ -326,6 +326,9 @@ impl CtrlGraphics {
|
|||||||
{
|
{
|
||||||
return Ok(());
|
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()) {
|
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
|
||||||
warn!(
|
warn!(
|
||||||
"{} {} failed: {:?}",
|
"{} {} 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);
|
warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep {}` to confirm modules loaded", driver);
|
||||||
return Ok(());
|
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 {
|
if count >= MAX_TRIES {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"{} {} failed: {:?}",
|
"{} {} failed: {:?}",
|
||||||
@@ -343,14 +351,14 @@ impl CtrlGraphics {
|
|||||||
driver,
|
driver,
|
||||||
String::from_utf8_lossy(&output.stderr)
|
String::from_utf8_lossy(&output.stderr)
|
||||||
);
|
);
|
||||||
return Err(RogError::Modprobe(msg));
|
return Err(GfxError::Modprobe(msg));
|
||||||
}
|
}
|
||||||
} else if output.status.success() {
|
} else if output.status.success() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
count += 1;
|
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
|
/// The daemon needs direct access to this function when it detects that the
|
||||||
pub fn do_vendor_tasks(
|
pub fn do_vendor_tasks(
|
||||||
vendor: GfxVendors,
|
vendor: GfxVendors,
|
||||||
|
vfio_enable: bool,
|
||||||
devices: &[GraphicsDevice],
|
devices: &[GraphicsDevice],
|
||||||
bus: &PciBus,
|
bus: &PciBus,
|
||||||
) -> Result<(), RogError> {
|
) -> Result<(), RogError> {
|
||||||
@@ -431,23 +440,33 @@ impl CtrlGraphics {
|
|||||||
|
|
||||||
match vendor {
|
match vendor {
|
||||||
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
|
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
|
||||||
for driver in VFIO_DRIVERS.iter() {
|
if vfio_enable {
|
||||||
Self::do_driver_action(driver, "rmmod")?;
|
for driver in VFIO_DRIVERS.iter() {
|
||||||
|
Self::do_driver_action(driver, "rmmod")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for driver in NVIDIA_DRIVERS.iter() {
|
for driver in NVIDIA_DRIVERS.iter() {
|
||||||
Self::do_driver_action(driver, "modprobe")?;
|
Self::do_driver_action(driver, "modprobe")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GfxVendors::Vfio => {
|
GfxVendors::Vfio => {
|
||||||
for driver in NVIDIA_DRIVERS.iter() {
|
if vfio_enable {
|
||||||
Self::do_driver_action(driver, "rmmod")?;
|
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 => {
|
GfxVendors::Integrated => {
|
||||||
for driver in VFIO_DRIVERS.iter() {
|
Self::do_driver_action("nouveau", "rmmod")?;
|
||||||
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() {
|
for driver in NVIDIA_DRIVERS.iter() {
|
||||||
Self::do_driver_action(driver, "rmmod")?;
|
Self::do_driver_action(driver, "rmmod")?;
|
||||||
@@ -455,11 +474,11 @@ impl CtrlGraphics {
|
|||||||
Self::unbind_remove_nvidia(&devices)?;
|
Self::unbind_remove_nvidia(&devices)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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,
|
connection: &Connection,
|
||||||
sessions: &[SessionInfo],
|
sessions: &[SessionInfo],
|
||||||
) -> Result<bool, RogError> {
|
) -> Result<bool, RogError> {
|
||||||
@@ -468,9 +487,10 @@ impl CtrlGraphics {
|
|||||||
if session_proxy.get_class()? == SessionClass::User {
|
if session_proxy.get_class()? == SessionClass::User {
|
||||||
match session_proxy.get_type()? {
|
match session_proxy.get_type()? {
|
||||||
SessionType::X11 | SessionType::Wayland | SessionType::MIR => {
|
SessionType::X11 | SessionType::Wayland | SessionType::MIR => {
|
||||||
//if session_proxy.get_active()? {
|
match session_proxy.get_state()? {
|
||||||
return Ok(true);
|
SessionState::Online | SessionState::Active => return Ok(true),
|
||||||
//}
|
SessionState::Closing | SessionState::Invalid => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -499,12 +519,11 @@ impl CtrlGraphics {
|
|||||||
loop {
|
loop {
|
||||||
let tmp = manager.list_sessions()?;
|
let tmp = manager.list_sessions()?;
|
||||||
if !tmp.iter().eq(&sessions) {
|
if !tmp.iter().eq(&sessions) {
|
||||||
warn!("GFX: Sessions list changed");
|
info!("GFX thread: Sessions list changed");
|
||||||
warn!("GFX: Old list:\n{:?}\nNew list:\n{:?}", &sessions, &tmp);
|
|
||||||
sessions = tmp;
|
sessions = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !Self::graphical_session_alive(&connection, &sessions)? {
|
if !Self::graphical_user_sessions_exist(&connection, &sessions)? {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,36 +542,28 @@ impl CtrlGraphics {
|
|||||||
sleep(SLEEP_PERIOD);
|
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::do_display_manager_action("stop")?;
|
||||||
|
Self::wait_display_manager_state("inactive")?;
|
||||||
|
|
||||||
match Self::wait_display_manager_state("inactive") {
|
let vfio_enable = if let Ok(config) = config.lock() {
|
||||||
Ok(_) => info!("GFX: display-manager stopped"),
|
config.gfx_vfio_enable
|
||||||
Err(err) => {
|
} else {
|
||||||
warn!("GFX: {}", err);
|
false
|
||||||
warn!("GFX: Retry stop display manager");
|
};
|
||||||
Self::do_display_manager_action("stop")?;
|
|
||||||
Self::wait_display_manager_state("inactive")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::do_vendor_tasks(vendor, &devices, &bus)?;
|
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||||
Self::do_display_manager_action("start")?;
|
Self::do_display_manager_action("restart")?;
|
||||||
|
|
||||||
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")?;
|
|
||||||
}
|
|
||||||
// Save selected mode in case of reboot
|
// Save selected mode in case of reboot
|
||||||
Self::save_gfx_mode(vendor, config);
|
Self::save_gfx_mode(vendor, config);
|
||||||
info!("GFX: display-manager started");
|
info!("GFX thread: display-manager started");
|
||||||
|
|
||||||
let v: &str = vendor.into();
|
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))
|
Ok(format!("Graphics mode changed to {} successfully", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Before starting a new thread the old one *must* be cancelled
|
||||||
fn cancel_thread(&self) {
|
fn cancel_thread(&self) {
|
||||||
if let Ok(lock) = self.thread_kill.lock() {
|
if let Ok(lock) = self.thread_kill.lock() {
|
||||||
if let Some(tx) = lock.as_ref() {
|
if let Some(tx) = lock.as_ref() {
|
||||||
@@ -560,7 +571,7 @@ impl CtrlGraphics {
|
|||||||
info!("GFX: Cancelling previous thread");
|
info!("GFX: Cancelling previous thread");
|
||||||
tx.send(true)
|
tx.send(true)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
warn!("GFX: {}", err);
|
warn!("GFX thread: {}", err);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
@@ -605,6 +616,17 @@ impl CtrlGraphics {
|
|||||||
return Err(GfxError::GsyncModeActive.into());
|
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
|
// Must always cancel any thread running
|
||||||
self.cancel_thread();
|
self.cancel_thread();
|
||||||
// determine which method we need here
|
// determine which method we need here
|
||||||
@@ -618,7 +640,8 @@ impl CtrlGraphics {
|
|||||||
info!("GFX: mode change does not require logout");
|
info!("GFX: mode change does not require logout");
|
||||||
let devices = self.nvidia.clone();
|
let devices = self.nvidia.clone();
|
||||||
let bus = self.bus.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...
|
// TODO: undo if failed? Save last mode, catch errors...
|
||||||
Ok(action_required)
|
Ok(action_required)
|
||||||
@@ -629,7 +652,14 @@ impl CtrlGraphics {
|
|||||||
let vendor = self.get_gfx_mode()?;
|
let vendor = self.get_gfx_mode()?;
|
||||||
let devices = self.nvidia.clone();
|
let devices = self.nvidia.clone();
|
||||||
let bus = self.bus.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)?;
|
Self::toggle_fallback_service(vendor)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-122
@@ -7,11 +7,11 @@ static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
|
|||||||
use crate::{
|
use crate::{
|
||||||
config_aura::AuraConfig,
|
config_aura::AuraConfig,
|
||||||
error::RogError,
|
error::RogError,
|
||||||
laptops::{match_laptop, LaptopLedData, HELP_ADDRESS},
|
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
|
||||||
};
|
};
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rog_types::{
|
use rog_types::{
|
||||||
aura_modes::{AuraEffect, AuraModeNum},
|
aura_modes::{AuraEffect, AuraModeNum, LedBrightness},
|
||||||
LED_MSG_LEN,
|
LED_MSG_LEN,
|
||||||
};
|
};
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
@@ -37,19 +37,17 @@ impl GetSupported for CtrlKbdBacklight {
|
|||||||
|
|
||||||
fn get_supported() -> Self::A {
|
fn get_supported() -> Self::A {
|
||||||
// let mode = <&str>::from(&<AuraModes>::from(*mode));
|
// let mode = <&str>::from(&<AuraModes>::from(*mode));
|
||||||
let mut stock_led_modes = None;
|
|
||||||
let multizone_led_mode = false;
|
let multizone_led_mode = false;
|
||||||
let per_key_led_mode = false;
|
let per_key_led_mode = false;
|
||||||
if let Some(laptop) = match_laptop() {
|
let laptop = LaptopLedData::get_data();
|
||||||
stock_led_modes = if laptop.supported_modes().standard.is_empty() {
|
let stock_led_modes = if laptop.standard.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(laptop.supported_modes().standard.clone())
|
Some(laptop.standard)
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
LedSupportedFunctions {
|
LedSupportedFunctions {
|
||||||
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_ok(),
|
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_some(),
|
||||||
stock_led_modes,
|
stock_led_modes,
|
||||||
multizone_led_mode,
|
multizone_led_mode,
|
||||||
per_key_led_mode,
|
per_key_led_mode,
|
||||||
@@ -59,8 +57,6 @@ impl GetSupported for CtrlKbdBacklight {
|
|||||||
|
|
||||||
pub struct CtrlKbdBacklight {
|
pub struct CtrlKbdBacklight {
|
||||||
led_node: Option<String>,
|
led_node: Option<String>,
|
||||||
#[allow(dead_code)]
|
|
||||||
kbd_node: Option<String>,
|
|
||||||
pub bright_node: String,
|
pub bright_node: String,
|
||||||
supported_modes: LaptopLedData,
|
supported_modes: LaptopLedData,
|
||||||
flip_effect_write: bool,
|
flip_effect_write: bool,
|
||||||
@@ -99,7 +95,7 @@ impl crate::ZbusAdd for DbusKbdBacklight {
|
|||||||
/// LED commands are split between Brightness, Modes, Per-Key
|
/// LED commands are split between Brightness, Modes, Per-Key
|
||||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
impl DbusKbdBacklight {
|
impl DbusKbdBacklight {
|
||||||
fn set_brightness(&mut self, brightness: u8) {
|
fn set_brightness(&mut self, brightness: LedBrightness) {
|
||||||
if let Ok(ctrl) = self.inner.try_lock() {
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
ctrl.set_brightness(brightness)
|
ctrl.set_brightness(brightness)
|
||||||
.map_err(|err| warn!("{}", err))
|
.map_err(|err| warn!("{}", err))
|
||||||
@@ -245,9 +241,9 @@ impl crate::CtrlTask for CtrlKbdBacklight {
|
|||||||
file.read_exact(&mut buf)
|
file.read_exact(&mut buf)
|
||||||
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
||||||
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
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.read();
|
||||||
self.config.brightness = num as u8;
|
self.config.brightness = num.into();
|
||||||
self.config.write();
|
self.config.write();
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -258,46 +254,37 @@ impl crate::CtrlTask for CtrlKbdBacklight {
|
|||||||
|
|
||||||
impl CtrlKbdBacklight {
|
impl CtrlKbdBacklight {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
|
||||||
id_product: &str,
|
|
||||||
condev_iface: Option<&String>,
|
|
||||||
supported_modes: LaptopLedData,
|
|
||||||
config: AuraConfig,
|
|
||||||
) -> Result<Self, RogError> {
|
|
||||||
// TODO: return error if *all* nodes are None
|
// 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(
|
let mut led_node = None;
|
||||||
|err| {
|
for prod in ASUS_KEYBOARD_DEVICES.iter() {
|
||||||
warn!("led_node: {}", err);
|
match Self::find_led_node(prod) {
|
||||||
None
|
Ok(node) => {
|
||||||
},
|
led_node = Some(node);
|
||||||
Some,
|
break;
|
||||||
);
|
}
|
||||||
|
Err(err) => warn!("led_node: {}", err),
|
||||||
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 bright_node = Self::get_kbd_bright_path();
|
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(
|
return Err(RogError::MissingFunction(
|
||||||
"All keyboard features missing, you may require a v5.11 series kernel or newer"
|
"All keyboard features missing, you may require a v5.11 series kernel or newer"
|
||||||
.into(),
|
.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 {
|
let ctrl = CtrlKbdBacklight {
|
||||||
// Using `ok` here so we can continue without keyboard features but
|
|
||||||
// still get brightness control at least... maybe...
|
|
||||||
led_node,
|
led_node,
|
||||||
kbd_node,
|
bright_node: bright_node.unwrap(), // If was none then we already returned above
|
||||||
// TODO: Check for existance
|
|
||||||
bright_node: bright_node?.to_owned(),
|
|
||||||
supported_modes,
|
supported_modes,
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
config,
|
config,
|
||||||
@@ -305,14 +292,11 @@ impl CtrlKbdBacklight {
|
|||||||
Ok(ctrl)
|
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() {
|
if Path::new(KBD_BRIGHT_PATH).exists() {
|
||||||
Ok(KBD_BRIGHT_PATH)
|
return Some(KBD_BRIGHT_PATH.to_string());
|
||||||
} else {
|
|
||||||
Err(RogError::MissingFunction(
|
|
||||||
"Keyboard features missing, you may require a v5.11 series kernel or newer".into(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brightness(&self) -> Result<u8, RogError> {
|
pub fn get_brightness(&self) -> Result<u8, RogError> {
|
||||||
@@ -331,36 +315,24 @@ impl CtrlKbdBacklight {
|
|||||||
Ok(buf[0])
|
Ok(buf[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_brightness(&self, brightness: u8) -> Result<(), RogError> {
|
pub fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
|
||||||
let mut file = OpenOptions::new()
|
let path = Path::new(&self.bright_node);
|
||||||
.write(true)
|
let mut file =
|
||||||
.open(&self.bright_node)
|
OpenOptions::new()
|
||||||
.map_err(|err| match err.kind() {
|
.write(true)
|
||||||
std::io::ErrorKind::NotFound => {
|
.open(&path)
|
||||||
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
|
.map_err(|err| match err.kind() {
|
||||||
}
|
std::io::ErrorKind::NotFound => {
|
||||||
_ => RogError::Path((&self.bright_node).into(), err),
|
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
|
||||||
})?;
|
}
|
||||||
file.write_all(&[brightness])
|
_ => RogError::Path((&self.bright_node).into(), err),
|
||||||
|
})?;
|
||||||
|
file.write_all(&[brightness.as_char_code()])
|
||||||
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_node_failover(
|
fn find_led_node(id_product: &str) -> Result<String, RogError> {
|
||||||
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> {
|
|
||||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||||
warn!("{}", err);
|
warn!("{}", err);
|
||||||
RogError::Udev("enumerator failed".into(), 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(
|
Err(RogError::MissingFunction(
|
||||||
"ASUS LED device node not found".into(),
|
"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> {
|
pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> {
|
||||||
self.set_and_save(mode)
|
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::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
|
||||||
use daemon::laptops::match_laptop;
|
|
||||||
use daemon::{
|
use daemon::{
|
||||||
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
|
||||||
};
|
};
|
||||||
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
|
||||||
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
|
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
|
||||||
|
use daemon::{
|
||||||
|
ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu},
|
||||||
|
laptops::LaptopLedData,
|
||||||
|
};
|
||||||
|
|
||||||
use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
||||||
use log::LevelFilter;
|
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");
|
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||||
let devices = ctrl.devices();
|
let devices = ctrl.devices();
|
||||||
let bus = ctrl.bus();
|
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 {
|
} else if ded == 0 {
|
||||||
info!("Dedicated GFX toggle is off");
|
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);
|
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(laptop) = match_laptop() {
|
let laptop = LaptopLedData::get_data();
|
||||||
let aura_config = AuraConfig::load(laptop.supported_modes());
|
let aura_config = AuraConfig::load(&laptop);
|
||||||
|
if let Ok(ctrl) = CtrlKbdBacklight::new(laptop, aura_config).map_err(|err| {
|
||||||
if let Ok(ctrl) = CtrlKbdBacklight::new(
|
error!("Keyboard control: {}", err);
|
||||||
laptop.usb_product(),
|
err
|
||||||
laptop.condev_iface(),
|
}) {
|
||||||
laptop.supported_modes().to_owned(),
|
let tmp = Arc::new(Mutex::new(ctrl));
|
||||||
aura_config,
|
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
|
||||||
)
|
tasks.push(tmp);
|
||||||
.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
|
// 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::fs::OpenOptions;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
|
pub const ASUS_LED_MODE_CONF: &str = "/etc/asusd/asusd-ledmodes.toml";
|
||||||
pub static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
|
pub const ASUS_KEYBOARD_DEVICES: [&str; 4] = ["1866", "1869", "1854", "19b6"];
|
||||||
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 fn print_board_info() {
|
pub fn print_board_info() {
|
||||||
let dmi = sysfs_class::DmiId::default();
|
let dmi = sysfs_class::DmiId::default();
|
||||||
@@ -98,8 +26,8 @@ pub fn print_modes(supported_modes: &[u8]) {
|
|||||||
info!("- {}", mode);
|
info!("- {}", mode);
|
||||||
}
|
}
|
||||||
info!(
|
info!(
|
||||||
"If these modes are incorrect or missing please request support at {}",
|
"If these modes are incorrect you can edit {}",
|
||||||
HELP_ADDRESS
|
ASUS_LED_MODE_CONF
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
info!("No RGB control available");
|
info!("No RGB control available");
|
||||||
@@ -120,6 +48,28 @@ pub struct LaptopLedData {
|
|||||||
pub per_key: bool,
|
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 {
|
impl LedSupportFile {
|
||||||
/// Consumes the LEDModes
|
/// Consumes the LEDModes
|
||||||
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
|
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
|
||||||
@@ -137,19 +87,19 @@ impl LedSupportFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_from_config() -> Option<Self> {
|
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();
|
let mut buf = String::new();
|
||||||
if let Ok(l) = file.read_to_string(&mut buf) {
|
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
warn!("{} is empty", LEDMODE_CONFIG_PATH);
|
warn!("{} is empty", ASUS_LED_MODE_CONF);
|
||||||
} else {
|
} else {
|
||||||
return Some(toml::from_str(&buf).unwrap_or_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
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,14 +35,14 @@ per_key = false
|
|||||||
|
|
||||||
[[led_data]]
|
[[led_data]]
|
||||||
prod_family = "ROG Strix"
|
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"]
|
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"]
|
||||||
multizone = false
|
multizone = false
|
||||||
per_key = true
|
per_key = true
|
||||||
|
|
||||||
[[led_data]]
|
[[led_data]]
|
||||||
prod_family = "ROG Strix"
|
prod_family = "ROG Strix"
|
||||||
board_names = ["GX531", "G512LV", "G712LV"]
|
board_names = ["GX531", "G512LV", "G712LV", "G712LW"]
|
||||||
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"]
|
||||||
multizone = true
|
multizone = true
|
||||||
per_key = false
|
per_key = false
|
||||||
@@ -80,4 +80,11 @@ prod_family = "ROG"
|
|||||||
board_names = ["GL553VE"]
|
board_names = ["GL553VE"]
|
||||||
standard = ["Static", "Breathe", "Strobe"]
|
standard = ["Static", "Breathe", "Strobe"]
|
||||||
multizone = true
|
multizone = true
|
||||||
|
per_key = false
|
||||||
|
|
||||||
|
[[led_data]]
|
||||||
|
prod_family = "ROG Zephyrus G14"
|
||||||
|
board_names = ["GA401Q"]
|
||||||
|
standard = ["Static", "Breathe", "Pulse"]
|
||||||
|
multizone = false
|
||||||
per_key = false
|
per_key = false
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rog_dbus"
|
name = "rog_dbus"
|
||||||
version = "3.0.0"
|
version = "3.1.0"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["Luke <luke@ljones.dev>"]
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ use std::sync::{Arc, Mutex};
|
|||||||
|
|
||||||
use zbus::{dbus_proxy, Connection, Result};
|
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
|
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<()>;
|
fn prev_led_mode(&self) -> zbus::Result<()>;
|
||||||
|
|
||||||
/// SetBrightness method
|
/// SetBrightness method
|
||||||
fn set_brightness(&self, brightness: u8) -> zbus::Result<()>;
|
fn set_brightness(&self, brightness: LedBrightness) -> zbus::Result<()>;
|
||||||
|
|
||||||
/// SetLedMode method
|
/// SetLedMode method
|
||||||
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
|
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
|
||||||
@@ -80,7 +83,7 @@ impl<'a> LedProxy<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_led_brightness(&self, level: u8) -> Result<()> {
|
pub fn set_led_brightness(&self, level: LedBrightness) -> Result<()> {
|
||||||
self.0.set_brightness(level)?;
|
self.0.set_brightness(level)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ trait Daemon {
|
|||||||
fn profiles(&self) -> zbus::Result<String>;
|
fn profiles(&self) -> zbus::Result<String>;
|
||||||
|
|
||||||
/// ProfileNames method
|
/// ProfileNames method
|
||||||
fn profile_names(&self) -> zbus::Result<String>;
|
fn profile_names(&self) -> zbus::Result<Vec<String>>;
|
||||||
|
|
||||||
/// Remove method
|
/// Remove method
|
||||||
fn remove(&self, profile: &str) -> zbus::Result<()>;
|
fn remove(&self, profile: &str) -> zbus::Result<()>;
|
||||||
@@ -72,6 +72,16 @@ impl<'a> ProfileProxy<'a> {
|
|||||||
self.0.active_profile_name()
|
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]
|
#[inline]
|
||||||
pub fn next_fan(&self) -> Result<()> {
|
pub fn next_fan(&self) -> Result<()> {
|
||||||
self.0.next_profile()
|
self.0.next_profile()
|
||||||
@@ -89,7 +99,7 @@ impl<'a> ProfileProxy<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn profile_names(&self) -> Result<String> {
|
pub fn profile_names(&self) -> Result<Vec<String>> {
|
||||||
self.0.profile_names()
|
self.0.profile_names()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rog_types"
|
name = "rog_types"
|
||||||
version = "3.1.0"
|
version = "3.2.0"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = ["Luke <luke@ljones.dev>"]
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
|||||||
@@ -10,6 +10,32 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use zvariant_derive::Type;
|
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)]
|
#[derive(Debug, Clone, PartialEq, Copy, Deserialize, Serialize, Type)]
|
||||||
pub struct Colour(pub u8, pub u8, pub u8);
|
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 serde_derive::{Deserialize, Serialize};
|
||||||
use std::str::FromStr;
|
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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum ProfileEvent {
|
pub enum ProfileEvent {
|
||||||
Cli(ProfileCommand),
|
Cli(ProfileCommand),
|
||||||
@@ -80,8 +122,16 @@ pub struct ProfileCommand {
|
|||||||
pub next: bool,
|
pub next: bool,
|
||||||
#[options(help = "create the profile if it doesn't exist")]
|
#[options(help = "create the profile if it doesn't exist")]
|
||||||
pub create: bool,
|
pub create: bool,
|
||||||
|
#[options(meta = "", help = "remove a profile by name")]
|
||||||
|
pub remove: Option<String>,
|
||||||
#[options(help = "list available profiles")]
|
#[options(help = "list available profiles")]
|
||||||
pub list: bool,
|
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")]
|
#[options(meta = "", help = "enable or disable cpu turbo")]
|
||||||
pub turbo: Option<bool>,
|
pub turbo: Option<bool>,
|
||||||
@@ -100,6 +150,4 @@ pub struct ProfileCommand {
|
|||||||
pub curve: Option<Curve>,
|
pub curve: Option<Curve>,
|
||||||
#[options(free)]
|
#[options(free)]
|
||||||
pub profile: Option<String>,
|
pub profile: Option<String>,
|
||||||
#[options(help = "remove a profile by name")]
|
|
||||||
pub remove: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user