Merge branch 'fluke/gfx_ctrl_zbus' into 'next'
Fluke/gfx ctrl zbus See merge request asus-linux/asus-nb-ctrl!3
13
CHANGELOG.md
@@ -6,6 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
# [2.0.0] - 2020-09-21
|
||||||
|
### Changed
|
||||||
|
- Code refactor to spawn less tasks. Main loop will run only as fast as
|
||||||
|
it receives events
|
||||||
|
- No-longer using tokio or async, reducing resource use
|
||||||
|
### Added
|
||||||
|
- A basic user daemon has been added for user notifications over dbus (XDG spec)
|
||||||
|
- Added a user systemd service for notifications (asus-notify)
|
||||||
|
- Graphics mode handling <iGPU only, dGPU only, or hybrid>, see asusctl --help
|
||||||
|
### BREAKING CHANGES
|
||||||
|
- asusd.conf has changed slightly and will overwrite old configs
|
||||||
|
- All DBUS methods/signals/paths etc, are all updated and changed
|
||||||
|
|
||||||
# [1.1.2] - 2020-09-10
|
# [1.1.2] - 2020-09-10
|
||||||
### Changed
|
### Changed
|
||||||
- Bump rog-fan-curve to new versiont o support GA401IV
|
- Bump rog-fan-curve to new versiont o support GA401IV
|
||||||
|
|||||||
825
Cargo.lock
generated
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["asus-nb-ctrl", "asus-nb"]
|
members = ["asus-notify", "asus-nb-ctrl", "asus-nb", "ctrl-gfx"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
@@ -13,4 +13,4 @@ opt-level = 1
|
|||||||
|
|
||||||
[profile.bench]
|
[profile.bench]
|
||||||
debug = false
|
debug = false
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|||||||
19
Makefile
@@ -13,7 +13,10 @@ SRC = Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.r
|
|||||||
|
|
||||||
BIN_C=asusctl
|
BIN_C=asusctl
|
||||||
BIN_D=asusd
|
BIN_D=asusd
|
||||||
LEDCONFIG=asusd-ledmodes.toml
|
BIN_N=asus-notify
|
||||||
|
LEDCFG=asusd-ledmodes.toml
|
||||||
|
X11CFG=90-nvidia-screen-G05.conf
|
||||||
|
UDEVRULES=90-nvidia-pm.rules
|
||||||
VERSION:=$(shell grep -Pm1 'version = "(\d.\d.\d)"' asus-nb-ctrl/Cargo.toml | cut -d'"' -f2)
|
VERSION:=$(shell grep -Pm1 'version = "(\d.\d.\d)"' asus-nb-ctrl/Cargo.toml | cut -d'"' -f2)
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
@@ -38,17 +41,29 @@ distclean:
|
|||||||
install: all
|
install: all
|
||||||
install -D -m 0755 "target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
|
install -D -m 0755 "target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||||
install -D -m 0755 "target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
|
install -D -m 0755 "target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
|
||||||
|
install -D -m 0755 "target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
|
||||||
|
install -D -m 0644 "data/$(UDEVRULES)" "$(DESTDIR)/lib/udev/rules.d/$(UDEVRULES)"
|
||||||
install -D -m 0644 "data/$(BIN_D).rules" "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
|
install -D -m 0644 "data/$(BIN_D).rules" "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
|
||||||
install -D -m 0644 "data/$(LEDCONFIG)" "$(DESTDIR)$(sysconfdir)/asusd/$(LEDCONFIG)"
|
install -D -m 0644 "data/$(LEDCFG)" "$(DESTDIR)$(sysconfdir)/asusd/$(LEDCFG)"
|
||||||
install -D -m 0644 "data/$(BIN_D).conf" "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
|
install -D -m 0644 "data/$(BIN_D).conf" "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
|
||||||
|
install -D -m 0644 "data/$(X11CFG)" "$(DESTDIR)$(sysconfdir)/X11/xorg.conf.d/$(X11CFG)"
|
||||||
install -D -m 0644 "data/$(BIN_D).service" "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
|
install -D -m 0644 "data/$(BIN_D).service" "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
|
||||||
|
install -D -m 0644 "data/$(BIN_N).service" "$(DESTDIR)/lib/systemd/user/$(BIN_N).service"
|
||||||
|
install -D -m 0644 "data/icons/asus_notif_yellow.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_yellow.png"
|
||||||
|
install -D -m 0644 "data/icons/asus_notif_green.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_green.png"
|
||||||
|
install -D -m 0644 "data/icons/asus_notif_red.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_red.png"
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
|
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
|
||||||
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
|
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
|
||||||
|
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
|
||||||
|
rm -f "$(DESTDIR)/lib/udev/rules.d/$(UDEVRULES)"
|
||||||
rm -f "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
|
rm -f "$(DESTDIR)/lib/udev/rules.d/99-$(BIN_D).rules"
|
||||||
rm -f "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
|
rm -f "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN_D).conf"
|
||||||
|
rm -f "$(DESTDIR)$(sysconfdir)/X11/xorg.conf.d/$(X11CFG)"
|
||||||
rm -f "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
|
rm -f "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
|
||||||
|
rm -r "$(DESTDIR)/lib/systemd/user/$(BIN_N).service"
|
||||||
|
rm -r "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_*"
|
||||||
|
|
||||||
update:
|
update:
|
||||||
cargo update
|
cargo update
|
||||||
|
|||||||
207
README.md
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
**NOTICE:**
|
**NOTICE:**
|
||||||
|
|
||||||
This program requires the kernel patch in `./kernel-patch/` to be applied.
|
This program requires the kernel patch [here](https://www.spinics.net/lists/linux-input/msg68977.html) to be applied.
|
||||||
As of 04/08/2020 these have been submitted to lkml. Alternatively you may
|
Alternatively you may use the dkms module for 'hid-asus-rog` from one of the
|
||||||
use the dkms module for 'hid-asus-rog` from one of the repositories [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
|
repositories [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
|
||||||
|
|
||||||
The patch enables the following in kernel:
|
The patch enables the following in kernel:
|
||||||
|
|
||||||
@@ -29,56 +29,47 @@ asusd is a utility for Linux to control many aspects of various ASUS laptops.
|
|||||||
|
|
||||||
## SUPPORTED LAPTOPS
|
## SUPPORTED LAPTOPS
|
||||||
|
|
||||||
If your laptop is not in the following lists, it may still work with fan-mode switching and charge limit control.
|
Most ASUS gaming laptops that have a USB keyboard. If `lsusb` shows something similar
|
||||||
|
to this:
|
||||||
|
|
||||||
**Please help test or provide info for:**
|
```
|
||||||
|
Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
||||||
|
```
|
||||||
|
|
||||||
- GL703(0x1869)
|
then it may work without tweaks. Technically all other functions except the LED
|
||||||
- GL553/GL753 (device = 0x1854) (attempted support from researching 2nd-hand info, multizone may work)
|
and AniMe parts should work regardless of your latop make. Eventually this project
|
||||||
|
will probably suffer another rename once it becomes generic enough to do so.
|
||||||
|
|
||||||
**Laptop support is modified on a per-case basis** as the EC for the keyboard varies
|
## Implemented
|
||||||
a little between models, e.g, some RGB modes are missing, or it's a single colour.
|
|
||||||
As far as I can see, the EC does not give us a way to find what modes are supported.
|
|
||||||
|
|
||||||
### ANIME AND OTHER FUNCTIONS
|
- [X] System daemon
|
||||||
|
- [X] User notifications daemon
|
||||||
|
- [X] Setting/modifying built-in LED modes
|
||||||
|
- [X] Per-key LED setting
|
||||||
|
- [X] Fancy LED modes (See examples)
|
||||||
|
- [X] Saving settings for reload
|
||||||
|
- [X] Logging - required for journalctl
|
||||||
|
- [X] AniMatrix display on G14 models that include it
|
||||||
|
- [X] Set battery charge limit (with kernel supporting this)
|
||||||
|
- [X] Fancy fan control on G14 + G15 thanks to @Yarn1
|
||||||
|
- [X] Graphics mode switching between iGPU, dGPU, and On-Demand
|
||||||
|
|
||||||
**AniMe device check is performed on start, if your device has one it will be detected.**
|
## FUNCTIONS
|
||||||
|
|
||||||
**NOTE:** If charge limit or fan modes are not working, then you may require a kernel newer than 5.6.10.
|
### Graphics switching
|
||||||
|
|
||||||
- [X] AniMe Matrix display
|
A new feature has been added to enable switching graphics modes. This can be disabled
|
||||||
- [X] Power profile switching on fan-mode (FN+F5)
|
in the config with `"manage_gfx": false,`. Please be aware it is a work in progress.
|
||||||
- [X] Intel
|
|
||||||
- [X] Turbo enale/disable
|
|
||||||
- [X] Min frequency percentage
|
|
||||||
- [X] Max frequency percentage
|
|
||||||
- [X] AMD
|
|
||||||
- [X] Turbo enale/disable
|
|
||||||
- [X] Battery charge limit
|
|
||||||
|
|
||||||
**NOTE:** GA14/GA401 and GA15/GA502/GU502, You will need kernel [patches](https://lab.retarded.farm/zappel/asus-rog-zephyrus-g14/-/tree/master/kernel_patches).
|
The CLI option for this does not require root until it asks for it, and provides
|
||||||
|
instructions.
|
||||||
|
|
||||||
### KEYBOARD BACKLIGHT MODES
|
### KEYBOARD BACKLIGHT MODES
|
||||||
|
|
||||||
Models GA401, GA502, GU502 support LED brightness change only (no RGB).
|
Models GA401, GA502, GU502 support LED brightness change only (no RGB).
|
||||||
|
|
||||||
| MODEL | STATIC | BREATHING | STROBE | RAINBOW | STAR | RAIN | HIGHLIGHT | LASER | RIPPLE | PULSE | COMET | FLASH | ZONES | PER-KEY RGB |
|
If you model isn't getting the correct led modes, you can edit the file
|
||||||
|:------:|:------:|:---------:|:------:|:-------:|:----:|:----:|:---------:|:-----:|:------:|:-----:|:-----:|:-----:|:-----:|:-----------:|
|
`/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as follows:
|
||||||
| G512LI | X | X | X | X | | | | | | | | | | |
|
|
||||||
| G712LI | X | X | X | X | | | | | | | | | | |
|
|
||||||
| GM501 | X | X | X | X | | | | | | | | | X | |
|
|
||||||
| GX531 | X | X | X | X | | | | | | | | | X | |
|
|
||||||
| G512 | X | X | X | X | | | | | | | | | X | |
|
|
||||||
| G712 | X | X | X | X | | | | | | | | | X | |
|
|
||||||
| GX502 | X | X | X | X | X | X | X | X | X | X | X | X | | X |
|
|
||||||
| GX701 | X | X | X | X | X | X | X | X | X | X | X | X | | X |
|
|
||||||
| G531 | X | X | X | X | X | X | X | X | X | X | X | X | X | X |
|
|
||||||
| G731 | X | X | X | X | X | X | X | X | X | X | X | X | X | X |
|
|
||||||
| G532 | X | X | X | X | X | X | X | X | X | X | X | X | | X |
|
|
||||||
|
|
||||||
It is highly likely this doesn't cover all models.
|
|
||||||
|
|
||||||
For editing the `/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as follows:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
0 STATIC
|
0 STATIC
|
||||||
@@ -97,16 +88,7 @@ For editing the `/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as fo
|
|||||||
255 PER_KEY
|
255 PER_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
## Implemented
|
use `cat /sys/class/dmi/id/product_name` to get details about your laptop.
|
||||||
|
|
||||||
- [X] Daemon
|
|
||||||
- [X] Setting/modifying built-in LED modes
|
|
||||||
- [X] Per-key LED setting
|
|
||||||
- [X] Fancy LED modes (See examples)
|
|
||||||
- [X] Saving settings for reload
|
|
||||||
- [X] Logging - required for journalctl
|
|
||||||
- [X] AniMatrix display on G14 models that include it
|
|
||||||
- [X] Set battery charge limit (with kernel supporting this)
|
|
||||||
|
|
||||||
## Requirements for compiling
|
## Requirements for compiling
|
||||||
|
|
||||||
@@ -136,32 +118,31 @@ If you are upgrading from a previous installed version, you will need to restart
|
|||||||
$ systemctl daemon-reload && systemctl restart asusd
|
$ systemctl daemon-reload && systemctl restart asusd
|
||||||
```
|
```
|
||||||
|
|
||||||
You may also need to activate the service for debian install. If running Pop!_OS, I suggest disabling `system76-power`
|
You may also need to activate the service for debian install. If running Pop!_OS, I suggest disabling `system76-power` gnome-shell extension and systemd service.
|
||||||
gnome-shell extension, or at least limiting use of the power-management parts as `asusd` lets you set the same things
|
|
||||||
(one or the other will overwrite pstates). I will create a shell extension at some point similar to system76, but using
|
|
||||||
the asusd parts. It is safe to leave `system76-power.service` enabled and use for switching between graphics modes.
|
|
||||||
|
|
||||||
## Uninstalling
|
## Uninstalling
|
||||||
|
|
||||||
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd.conf`.
|
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
|
||||||
|
|
||||||
## Updating
|
## Updating
|
||||||
|
|
||||||
Occasionally you need to remove `/etc/asusd.conf` and restart the daemon to create a new one. You *can* back up the old
|
If there has been a config file format change your config will be overwritten. This will
|
||||||
one and copy settings back over (then restart daemon again).
|
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
|
**NOTE! Fan mode toggling requires a newer kernel**. I'm unsure when the patches
|
||||||
tested with the 5.6.6 kernel and above only. To see if the fan-mode changed cat either:
|
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/throttle_thermal_policy` or
|
||||||
- `cat /sys/devices/platform/asus-nb-wmi/fan_boost_mode`
|
- `cat /sys/devices/platform/asus-nb-wmi/fan_boost_mode`
|
||||||
|
|
||||||
The numbers are 0 = Normal/Balanced, 1 = Boost, 2 = Silent.
|
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
|
Running the program as a daemon manually will require root. Standard (non-daemon)
|
||||||
the daemon mode over dbus.
|
mode expects to be communicating with the daemon mode over dbus.
|
||||||
|
|
||||||
Commands are given by:
|
Commands are given by:
|
||||||
|
|
||||||
@@ -182,79 +163,6 @@ Some commands may have subcommands:
|
|||||||
asusctl <command> <subcommand> --help
|
asusctl <command> <subcommand> --help
|
||||||
```
|
```
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```
|
|
||||||
$ asusctl --help
|
|
||||||
Usage: asusctl [OPTIONS]
|
|
||||||
|
|
||||||
Optional arguments:
|
|
||||||
-h, --help print help message
|
|
||||||
-v, --version show program version number
|
|
||||||
-k, --kbd-bright VAL <off, low, med, high>
|
|
||||||
-p, --pwr-profile PWR <silent, normal, boost>
|
|
||||||
-c, --chg-limit CHRG <20-100>
|
|
||||||
|
|
||||||
Available commands:
|
|
||||||
led-mode Set the keyboard lighting from built-in modes
|
|
||||||
profile Create and configure profiles
|
|
||||||
|
|
||||||
$ asusctl profile --help
|
|
||||||
Usage: asusctl profile [OPTIONS]
|
|
||||||
|
|
||||||
Positional arguments:
|
|
||||||
profile
|
|
||||||
|
|
||||||
Optional arguments:
|
|
||||||
-h, --help print help message
|
|
||||||
-c, --create create the profile if it doesn't exist
|
|
||||||
-t, --turbo enable cpu turbo (AMD)
|
|
||||||
-n, --no-turbo disable cpu turbo (AMD)
|
|
||||||
-m, --min-percentage MIN-PERCENTAGE
|
|
||||||
set min cpu scaling (intel)
|
|
||||||
-M, --max-percentage MAX-PERCENTAGE
|
|
||||||
set max cpu scaling (intel)
|
|
||||||
-p, --preset PWR <silent, normal, boost>
|
|
||||||
-C, --curve CURVE set fan curve
|
|
||||||
|
|
||||||
$ asusctl led-mode --help
|
|
||||||
Usage: asusctl led-mode [OPTIONS]
|
|
||||||
|
|
||||||
Optional arguments:
|
|
||||||
-h, --help print help message
|
|
||||||
|
|
||||||
Available commands:
|
|
||||||
static set a single static colour
|
|
||||||
breathe pulse between one or two colours
|
|
||||||
strobe strobe through all colours
|
|
||||||
rainbow rainbow cycling in one of four directions
|
|
||||||
star rain pattern mimicking raindrops
|
|
||||||
rain rain pattern of three preset colours
|
|
||||||
highlight pressed keys are highlighted to fade
|
|
||||||
laser pressed keys generate horizontal laser
|
|
||||||
ripple pressed keys ripple outwards like a splash
|
|
||||||
pulse set a rapid pulse
|
|
||||||
comet set a vertical line zooming from left
|
|
||||||
flash set a wide vertical line zooming from left
|
|
||||||
multi-static 4-zone multi-colour
|
|
||||||
|
|
||||||
$ asusctl led-mode static --help
|
|
||||||
Usage: asusctl led-mode static [OPTIONS]
|
|
||||||
|
|
||||||
Optional arguments:
|
|
||||||
-h, --help print help message
|
|
||||||
-c HEX set the RGB value e.g, ff00ff
|
|
||||||
|
|
||||||
$ asusctl led-mode star --help
|
|
||||||
Usage: asusctl led-mode star [OPTIONS]
|
|
||||||
|
|
||||||
Optional arguments:
|
|
||||||
-h, --help print help message
|
|
||||||
-c HEX set the first RGB value e.g, ff00ff
|
|
||||||
-C HEX set the second RGB value e.g, ff00ff
|
|
||||||
-s SPEED set the speed: low, med, high
|
|
||||||
```
|
|
||||||
|
|
||||||
## Daemon mode
|
## Daemon mode
|
||||||
|
|
||||||
If the daemon service is enabled then on boot the following will be reloaded from save:
|
If the daemon service is enabled then on boot the following will be reloaded from save:
|
||||||
@@ -268,27 +176,40 @@ 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
|
itself - this means cycling through modes with the Aura keys will use the
|
||||||
settings that were used via CLI.
|
settings that were used via CLI.
|
||||||
|
|
||||||
Daemon mode creates a config file at `/etc/asusd.conf` which you can edit a
|
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
|
little of. Most parts will be byte arrays, but you can adjust things like
|
||||||
`mode_performance`.
|
`mode_performance`.
|
||||||
|
|
||||||
### DBUS Input
|
## User daemon for notification via dbus
|
||||||
|
|
||||||
|
If you have a notifications handler set up, or are using KDE or Gnome then you
|
||||||
|
can enable the user service to get basic notifications when something changes.
|
||||||
|
|
||||||
|
```
|
||||||
|
systemctl --user enable asus-notify.service
|
||||||
|
systemctl --user start asus-notify.service
|
||||||
|
```
|
||||||
|
# Other
|
||||||
|
|
||||||
|
## DBUS Input
|
||||||
|
|
||||||
See [README_DBUS.md](./README_DBUS.md).
|
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/)
|
||||||
|
|
||||||
### Wireshark captures
|
## Supporting more laptops
|
||||||
|
|
||||||
TODO: see `./wireshark_data/` for some captures.
|
|
||||||
|
|
||||||
### Supporting more laptops
|
|
||||||
|
|
||||||
Please file a support request.
|
Please file a support request.
|
||||||
|
|
||||||
## License
|
## Notes:
|
||||||
|
|
||||||
|
- If charge limit or fan modes are not working, then you may require a kernel newer than 5.6.10.
|
||||||
|
- AniMe device check is performed on start, if your device has one it will be detected.
|
||||||
|
- GA14/GA401 and GA15/GA502/GU502, You will need kernel [patches](https://lab.retarded.farm/zappel/asus-rog-zephyrus-g14/-/tree/master/kernel_patches), these are on their way to the kernel upstream.
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
Mozilla Public License 2 (MPL-2.0)
|
Mozilla Public License 2 (MPL-2.0)
|
||||||
|
|
||||||
|
|||||||
101
README_DBUS.md
@@ -1,31 +1,33 @@
|
|||||||
# DBUS Guide
|
# DBUS Guide
|
||||||
|
|
||||||
```rust
|
**WARNING: In progress updates**
|
||||||
pub static DBUS_NAME: &str = "org.asuslinux.Daemon";
|
|
||||||
pub static DBUS_PATH: &str = "/org/asuslinux/Daemon";
|
|
||||||
pub static DBUS_IFACE: &str = "org.asuslinux.Daemon";
|
|
||||||
```
|
|
||||||
|
|
||||||
## Methods
|
Interface name = org.asuslinux.Daemon
|
||||||
|
|
||||||
- `SetKeyBacklight`
|
Paths:
|
||||||
- `GetKeyBacklight`
|
- `/org/asuslinux/Gfx`
|
||||||
- `AnimatrixWrite`
|
+ `SetVendor` (string)
|
||||||
- `SetFanMode`
|
+ `NotifyVendor` (recv vendor label string)
|
||||||
- `GetFanMode`
|
- `/org/asuslinux/Led`
|
||||||
- `SetChargeLimit`
|
+ `LedMode` (AuraMode as json)
|
||||||
- `GetChargeLimit`
|
+ `LedModes` (array[AuraMode] as json)
|
||||||
- `GetKeyBacklightModes`
|
+ `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)
|
||||||
|
|
||||||
## Signals
|
All `Notify*` methods are signals.
|
||||||
|
|
||||||
- `KeyBacklightChanged`
|
### SetLed
|
||||||
- `FanModeChanged`
|
|
||||||
- `ChargeLimitChanged`
|
|
||||||
|
|
||||||
## Method Inputs
|
|
||||||
|
|
||||||
### SetKeyBacklight
|
|
||||||
|
|
||||||
This method expects a string of JSON as input. The JSON is of format such:
|
This method expects a string of JSON as input. The JSON is of format such:
|
||||||
|
|
||||||
@@ -66,23 +68,6 @@ dbus.
|
|||||||
|
|
||||||
Lastly, there is `"LedBrightness": <u8>` which accepts 0-3 for off, low, med, high.
|
Lastly, there is `"LedBrightness": <u8>` which accepts 0-3 for off, low, med, high.
|
||||||
|
|
||||||
### GetKeyBacklight
|
|
||||||
|
|
||||||
This method will return a JSON string in the same format as accepted by `SetKeyBacklight`.
|
|
||||||
|
|
||||||
### GetKeyBacklightModes
|
|
||||||
|
|
||||||
Will return a JSON string array of modes that this laptop accepts. The mode data
|
|
||||||
within this will be the current settings per mode. Good for:
|
|
||||||
|
|
||||||
- Getting supported modes
|
|
||||||
- Getting all mode settings
|
|
||||||
|
|
||||||
### AnimatrixWrite
|
|
||||||
|
|
||||||
Used to write data to the AniMe display if available. Currently is takes `[[u8; 640]; 2]`
|
|
||||||
which must be the byte data that will be written directly to the USB device.
|
|
||||||
|
|
||||||
### SetFanMode
|
### SetFanMode
|
||||||
|
|
||||||
Accepts an integer from the following:
|
Accepts an integer from the following:
|
||||||
@@ -91,41 +76,7 @@ Accepts an integer from the following:
|
|||||||
- `1`: Boost mode
|
- `1`: Boost mode
|
||||||
- `2`: Silent mode
|
- `2`: Silent mode
|
||||||
|
|
||||||
### GetFanMode
|
## dbus-send examples OUTDATED
|
||||||
|
|
||||||
Returns the integer set from above.
|
|
||||||
|
|
||||||
### SetChargeLimit
|
|
||||||
|
|
||||||
Accepts an integer in the range of 20-100.
|
|
||||||
|
|
||||||
### GetChargeLimit
|
|
||||||
|
|
||||||
Returns the integer set from above.
|
|
||||||
|
|
||||||
## Signal Outs
|
|
||||||
|
|
||||||
### KeyBacklightChanged
|
|
||||||
|
|
||||||
When emitted, it will emit the JSON data of the mode changed to, e.g:
|
|
||||||
|
|
||||||
```
|
|
||||||
{
|
|
||||||
"Static": {
|
|
||||||
"colour": [ 255, 0, 0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### FanModeChanged
|
|
||||||
|
|
||||||
When emitted, it will include the integer the fan mode was changed to.
|
|
||||||
|
|
||||||
### ChargeLimitChanged
|
|
||||||
|
|
||||||
When emitted, it will include the integer the charging limit was changed to.
|
|
||||||
|
|
||||||
## dbus-send examples
|
|
||||||
|
|
||||||
```
|
```
|
||||||
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:'{"Static": {"colour": [ 80, 0, 40]}}'
|
||||||
@@ -154,5 +105,5 @@ Monitoring dbus while sending commands via `rog-core` will give you the json str
|
|||||||
## Getting an introspection .xml
|
## Getting an introspection .xml
|
||||||
|
|
||||||
```
|
```
|
||||||
dbus-send --system --print-reply --dest=org.asuslinux.Daemon /org/asuslinux/Daemon org.freedesktop.DBus.Introspectable.Introspect > xml/dbus-0.14.4.xml
|
dbus-send --system --print-reply --dest=org.asuslinux.Daemon /org/asuslinux/Charge org.freedesktop.DBus.Introspectable.Introspect > xml/asusd-charge.xml
|
||||||
```
|
```
|
||||||
7
TODO.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# TODO
|
||||||
|
|
||||||
|
- There is lots of code duplication. This should be turned in to macros (dbus stuff etc)
|
||||||
|
- Add a little more information to profile notifications such as freq min/max, fan curves
|
||||||
|
- Finish splitting out controllers to own crates
|
||||||
|
- Finish move to zbus in client when zbus has client signal watch
|
||||||
|
- Consider a rename again because the project is getting a lot less ASUS centric
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asus-nb-ctrl"
|
name = "asus-nb-ctrl"
|
||||||
version = "1.1.2"
|
version = "2.0.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>"]
|
||||||
@@ -22,10 +22,10 @@ name = "asusd"
|
|||||||
path = "src/daemon.rs"
|
path = "src/daemon.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
ctrl-gfx = { path = "../ctrl-gfx" }
|
||||||
asus-nb = { path = "../asus-nb" }
|
asus-nb = { path = "../asus-nb" }
|
||||||
rusb = "^0.6.0"
|
rusb = "^0.6.0"
|
||||||
udev = "^0.4.0"
|
udev = "^0.4.0"
|
||||||
async-trait = "0.1.36"
|
|
||||||
|
|
||||||
# cli and logging
|
# cli and logging
|
||||||
gumdrop = "^0.8.0"
|
gumdrop = "^0.8.0"
|
||||||
@@ -33,9 +33,9 @@ log = "^0.4.8"
|
|||||||
env_logger = "^0.7.1"
|
env_logger = "^0.7.1"
|
||||||
|
|
||||||
# async
|
# async
|
||||||
dbus = { version = "^0.8.2", features = ["futures"] }
|
zbus = "1.1.1"
|
||||||
dbus-tokio = "^0.5.1"
|
zvariant = "2.2.0"
|
||||||
tokio = { version = "^0.2.4", features = ["rt-threaded", "sync"] }
|
#tokio = { version = "^0.2.4", features = ["rt-threaded", "sync"] }
|
||||||
|
|
||||||
# serialisation
|
# serialisation
|
||||||
serde = "^1.0"
|
serde = "^1.0"
|
||||||
@@ -48,3 +48,5 @@ sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
|||||||
rog_fan_curve = { version = "0.1.5", features = ["serde"] }
|
rog_fan_curve = { version = "0.1.5", features = ["serde"] }
|
||||||
# cpu power management
|
# cpu power management
|
||||||
intel-pstate = "^0.2.1"
|
intel-pstate = "^0.2.1"
|
||||||
|
|
||||||
|
yansi-term = "^0.1"
|
||||||
@@ -10,6 +10,7 @@ pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
|||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
pub gfx_managed: bool,
|
||||||
pub active_profile: String,
|
pub active_profile: String,
|
||||||
pub toggle_profiles: Vec<String>,
|
pub toggle_profiles: Vec<String>,
|
||||||
// TODO: remove power_profile
|
// TODO: remove power_profile
|
||||||
@@ -50,34 +51,38 @@ impl Config {
|
|||||||
|
|
||||||
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self {
|
fn create_default(file: &mut File, supported_led_modes: &[u8]) -> Self {
|
||||||
// create a default config here
|
// create a default config here
|
||||||
let mut c = Config::default();
|
let mut config = Config::default();
|
||||||
c.bat_charge_limit = 100;
|
config.gfx_managed = true;
|
||||||
c.kbd_backlight_mode = 0;
|
|
||||||
c.kbd_led_brightness = 1;
|
config.bat_charge_limit = 100;
|
||||||
|
config.kbd_backlight_mode = 0;
|
||||||
|
config.kbd_led_brightness = 1;
|
||||||
|
|
||||||
for n in supported_led_modes {
|
for n in supported_led_modes {
|
||||||
c.kbd_backlight_modes.push(AuraModes::from(*n))
|
config.kbd_backlight_modes.push(AuraModes::from(*n))
|
||||||
}
|
}
|
||||||
|
|
||||||
let profile = Profile::default();
|
let profile = Profile::default();
|
||||||
c.power_profiles.insert("normal".into(), profile);
|
config.power_profiles.insert("normal".into(), profile);
|
||||||
|
|
||||||
let mut profile = Profile::default();
|
let mut profile = Profile::default();
|
||||||
profile.fan_preset = 1;
|
profile.fan_preset = 1;
|
||||||
c.power_profiles.insert("boost".into(), profile);
|
config.power_profiles.insert("boost".into(), profile);
|
||||||
|
|
||||||
let mut profile = Profile::default();
|
let mut profile = Profile::default();
|
||||||
profile.fan_preset = 2;
|
profile.fan_preset = 2;
|
||||||
c.power_profiles.insert("silent".into(), profile);
|
config.power_profiles.insert("silent".into(), profile);
|
||||||
|
|
||||||
c.toggle_profiles.push("normal".into());
|
config.toggle_profiles.push("normal".into());
|
||||||
c.toggle_profiles.push("boost".into());
|
config.toggle_profiles.push("boost".into());
|
||||||
c.toggle_profiles.push("silent".into());
|
config.toggle_profiles.push("silent".into());
|
||||||
c.active_profile = "normal".into();
|
config.active_profile = "normal".into();
|
||||||
|
|
||||||
// Should be okay to unwrap this as is since it is a Default
|
// Should be okay to unwrap this as is since it is a Default
|
||||||
let json = serde_json::to_string_pretty(&c).unwrap();
|
let json = serde_json::to_string_pretty(&config).unwrap();
|
||||||
file.write_all(json.as_bytes())
|
file.write_all(json.as_bytes())
|
||||||
.unwrap_or_else(|_| panic!("Could not write {}", CONFIG_PATH));
|
.unwrap_or_else(|_| panic!("Could not write {}", CONFIG_PATH));
|
||||||
c
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&mut self) {
|
pub fn read(&mut self) {
|
||||||
@@ -97,6 +102,17 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_new() -> Result<Config, Box<dyn std::error::Error>> {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(&CONFIG_PATH)
|
||||||
|
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
|
||||||
|
let mut buf = String::new();
|
||||||
|
file.read_to_string(&mut buf)?;
|
||||||
|
let x: Config = serde_json::from_str(&buf)?;
|
||||||
|
Ok(x)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write(&self) {
|
pub fn write(&self) {
|
||||||
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
|
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
|
||||||
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
|
||||||
|
|||||||
@@ -9,16 +9,13 @@ const INIT: u8 = 0xc2;
|
|||||||
const APPLY: u8 = 0xc3;
|
const APPLY: u8 = 0xc3;
|
||||||
const SET: u8 = 0xc4;
|
const SET: u8 = 0xc4;
|
||||||
|
|
||||||
use crate::config::Config;
|
|
||||||
use asus_nb::error::AuraError;
|
use asus_nb::error::AuraError;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use rusb::{Device, DeviceHandle};
|
use rusb::{Device, DeviceHandle};
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use zbus::dbus_interface;
|
||||||
use tokio::sync::Mutex;
|
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -34,32 +31,24 @@ pub struct CtrlAnimeDisplay {
|
|||||||
initialised: bool,
|
initialised: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
use ::dbus::{nonblock::SyncConnection, tree::Signal};
|
//AnimatrixWrite
|
||||||
use async_trait::async_trait;
|
pub trait Dbus {
|
||||||
|
fn set_anime(&mut self, input: Vec<Vec<u8>>);
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl crate::ZbusAdd for CtrlAnimeDisplay {
|
||||||
impl crate::Controller for CtrlAnimeDisplay {
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
type A = Vec<Vec<u8>>;
|
server
|
||||||
|
.at(&"/org/asuslinux/Anime".try_into().unwrap(), self)
|
||||||
/// Spawns two tasks which continuously check for changes
|
.unwrap();
|
||||||
fn spawn_task_loop(
|
|
||||||
mut self,
|
|
||||||
_: Arc<Mutex<Config>>,
|
|
||||||
mut recv: Receiver<Self::A>,
|
|
||||||
_: Option<Arc<SyncConnection>>,
|
|
||||||
_: Option<Arc<Signal<()>>>,
|
|
||||||
) -> Vec<JoinHandle<()>> {
|
|
||||||
vec![tokio::spawn(async move {
|
|
||||||
while let Some(image) = recv.recv().await {
|
|
||||||
self.do_command(AnimatrixCommand::WriteImage(image))
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
|
||||||
}
|
|
||||||
})]
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, _: &mut Config) -> Result<(), Box<dyn Error>> {
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
Ok(())
|
impl Dbus for CtrlAnimeDisplay {
|
||||||
|
fn set_anime(&mut self, input: Vec<Vec<u8>>) {
|
||||||
|
self.do_command(AnimatrixCommand::WriteImage(input))
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,15 +89,15 @@ impl CtrlAnimeDisplay {
|
|||||||
Err(rusb::Error::NoDevice)
|
Err(rusb::Error::NoDevice)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn do_command(&mut self, command: AnimatrixCommand) -> Result<(), AuraError> {
|
pub fn do_command(&mut self, command: AnimatrixCommand) -> Result<(), AuraError> {
|
||||||
if !self.initialised {
|
if !self.initialised {
|
||||||
self.do_initialization().await?
|
self.do_initialization()?
|
||||||
}
|
}
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
AnimatrixCommand::WriteImage(effect) => self.write_image(effect).await?,
|
AnimatrixCommand::WriteImage(effect) => self.write_image(effect)?,
|
||||||
AnimatrixCommand::Set => self.do_set().await?,
|
AnimatrixCommand::Set => self.do_set()?,
|
||||||
AnimatrixCommand::Apply => self.do_apply().await?,
|
AnimatrixCommand::Apply => self.do_apply()?,
|
||||||
//AnimatrixCommand::ReloadLast => self.reload_last_builtin(&config).await?,
|
//AnimatrixCommand::ReloadLast => self.reload_last_builtin(&config).await?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -116,7 +105,7 @@ impl CtrlAnimeDisplay {
|
|||||||
|
|
||||||
/// Should only be used if the bytes you are writing are verified correct
|
/// Should only be used if the bytes you are writing are verified correct
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> {
|
fn write_bytes(&self, message: &[u8]) -> Result<(), AuraError> {
|
||||||
match self.handle.write_control(
|
match self.handle.write_control(
|
||||||
0x21, // request_type
|
0x21, // request_type
|
||||||
0x09, // request
|
0x09, // request
|
||||||
@@ -150,22 +139,22 @@ impl CtrlAnimeDisplay {
|
|||||||
///
|
///
|
||||||
/// Where led brightness is 0..255, low to high
|
/// Where led brightness is 0..255, low to high
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn write_image(&mut self, image: Vec<Vec<u8>>) -> Result<(), AuraError> {
|
fn write_image(&mut self, image: Vec<Vec<u8>>) -> Result<(), AuraError> {
|
||||||
for row in image.iter() {
|
for row in image.iter() {
|
||||||
self.write_bytes(row).await?;
|
self.write_bytes(row)?;
|
||||||
}
|
}
|
||||||
self.do_flush().await?;
|
self.do_flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn do_initialization(&mut self) -> Result<(), AuraError> {
|
fn do_initialization(&mut self) -> Result<(), AuraError> {
|
||||||
let mut init = [0; PACKET_SIZE];
|
let mut init = [0; PACKET_SIZE];
|
||||||
init[0] = DEV_PAGE; // This is the USB page we're using throughout
|
init[0] = DEV_PAGE; // This is the USB page we're using throughout
|
||||||
for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() {
|
for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() {
|
||||||
init[idx + 1] = *byte
|
init[idx + 1] = *byte
|
||||||
}
|
}
|
||||||
self.write_bytes(&init).await?;
|
self.write_bytes(&init)?;
|
||||||
|
|
||||||
// clear the init array and write other init message
|
// clear the init array and write other init message
|
||||||
for ch in init.iter_mut() {
|
for ch in init.iter_mut() {
|
||||||
@@ -174,43 +163,43 @@ impl CtrlAnimeDisplay {
|
|||||||
init[0] = DEV_PAGE; // write it to be sure?
|
init[0] = DEV_PAGE; // write it to be sure?
|
||||||
init[1] = INIT;
|
init[1] = INIT;
|
||||||
|
|
||||||
self.write_bytes(&init).await?;
|
self.write_bytes(&init)?;
|
||||||
self.initialised = true;
|
self.initialised = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn do_flush(&mut self) -> Result<(), AuraError> {
|
fn do_flush(&mut self) -> Result<(), AuraError> {
|
||||||
let mut flush = [0; PACKET_SIZE];
|
let mut flush = [0; PACKET_SIZE];
|
||||||
flush[0] = DEV_PAGE;
|
flush[0] = DEV_PAGE;
|
||||||
flush[1] = WRITE;
|
flush[1] = WRITE;
|
||||||
flush[2] = 0x03;
|
flush[2] = 0x03;
|
||||||
|
|
||||||
self.write_bytes(&flush).await?;
|
self.write_bytes(&flush)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn do_set(&mut self) -> Result<(), AuraError> {
|
fn do_set(&mut self) -> Result<(), AuraError> {
|
||||||
let mut flush = [0; PACKET_SIZE];
|
let mut flush = [0; PACKET_SIZE];
|
||||||
flush[0] = DEV_PAGE;
|
flush[0] = DEV_PAGE;
|
||||||
flush[1] = SET;
|
flush[1] = SET;
|
||||||
flush[2] = 0x01;
|
flush[2] = 0x01;
|
||||||
flush[3] = 0x80;
|
flush[3] = 0x80;
|
||||||
|
|
||||||
self.write_bytes(&flush).await?;
|
self.write_bytes(&flush)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn do_apply(&mut self) -> Result<(), AuraError> {
|
fn do_apply(&mut self) -> Result<(), AuraError> {
|
||||||
let mut flush = [0; PACKET_SIZE];
|
let mut flush = [0; PACKET_SIZE];
|
||||||
flush[0] = DEV_PAGE;
|
flush[0] = DEV_PAGE;
|
||||||
flush[1] = APPLY;
|
flush[1] = APPLY;
|
||||||
flush[2] = 0x01;
|
flush[2] = 0x01;
|
||||||
flush[3] = 0x80;
|
flush[3] = 0x80;
|
||||||
|
|
||||||
self.write_bytes(&flush).await?;
|
self.write_bytes(&flush)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +1,84 @@
|
|||||||
use crate::config::Config;
|
use crate::{config::Config, error::RogError};
|
||||||
use log::{error, info, warn};
|
//use crate::dbus::DbusEvents;
|
||||||
use std::error::Error;
|
use log::{info, warn};
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use std::sync::Mutex;
|
||||||
use tokio::sync::Mutex;
|
use zbus::dbus_interface;
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
|
|
||||||
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
|
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
|
||||||
|
|
||||||
pub struct CtrlCharge {
|
pub struct CtrlCharge {
|
||||||
path: &'static str,
|
path: &'static str,
|
||||||
|
config: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
use ::dbus::{nonblock::SyncConnection, tree::Signal};
|
trait Dbus {
|
||||||
use async_trait::async_trait;
|
fn set_limit(&mut self, charge: u8);
|
||||||
|
fn limit(&self) -> i8;
|
||||||
|
fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
impl crate::Controller for CtrlCharge {
|
impl Dbus for CtrlCharge {
|
||||||
type A = u8;
|
fn set_limit(&mut self, limit: u8) {
|
||||||
|
if let Ok(mut config) = self.config.try_lock() {
|
||||||
/// Spawns two tasks which continuously check for changes
|
self.set(limit, &mut config).unwrap();
|
||||||
fn spawn_task_loop(
|
self.notify_charge(limit).unwrap();
|
||||||
self,
|
}
|
||||||
config: Arc<Mutex<Config>>,
|
|
||||||
mut recv: Receiver<Self::A>,
|
|
||||||
_: Option<Arc<SyncConnection>>,
|
|
||||||
_: Option<Arc<Signal<()>>>,
|
|
||||||
) -> Vec<JoinHandle<()>> {
|
|
||||||
vec![tokio::spawn(async move {
|
|
||||||
while let Some(n) = recv.recv().await {
|
|
||||||
let mut config = config.lock().await;
|
|
||||||
self.set_charge_limit(n, &mut config)
|
|
||||||
.unwrap_or_else(|err| warn!("charge_limit: {}", err));
|
|
||||||
}
|
|
||||||
})]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
fn limit(&self) -> i8 {
|
||||||
config.read();
|
if let Ok(config) = self.config.try_lock() {
|
||||||
info!("Reloaded battery charge limit");
|
return config.bat_charge_limit as i8;
|
||||||
self.set_charge_limit(config.bat_charge_limit, config)
|
}
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
fn notify_charge(&self, limit: u8) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::ZbusAdd for CtrlCharge {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(&"/org/asuslinux/Charge".try_into().unwrap(), self)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlCharge {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
if let Ok(mut config) = self.config.try_lock() {
|
||||||
|
config.read();
|
||||||
|
info!("Reloaded battery charge limit");
|
||||||
|
self.set(config.bat_charge_limit, &mut config)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtrlCharge {
|
impl CtrlCharge {
|
||||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||||
let path = CtrlCharge::get_battery_path()?;
|
let path = CtrlCharge::get_battery_path()?;
|
||||||
info!("Device has battery charge threshold control");
|
info!("Device has battery charge threshold control");
|
||||||
Ok(CtrlCharge { path })
|
Ok(CtrlCharge { path, config })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_battery_path() -> Result<&'static str, std::io::Error> {
|
fn get_battery_path() -> Result<&'static str, RogError> {
|
||||||
if Path::new(BAT_CHARGE_PATH).exists() {
|
if Path::new(BAT_CHARGE_PATH).exists() {
|
||||||
Ok(BAT_CHARGE_PATH)
|
Ok(BAT_CHARGE_PATH)
|
||||||
} else {
|
} else {
|
||||||
Err(std::io::Error::new(
|
Err(RogError::MissingFunction(
|
||||||
std::io::ErrorKind::NotFound,
|
"Charge control not available".into(),
|
||||||
"Charge control not available",
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set_charge_limit(
|
pub(super) fn set(&self, limit: u8, config: &mut Config) -> Result<(), RogError> {
|
||||||
&self,
|
|
||||||
limit: u8,
|
|
||||||
config: &mut Config,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
if limit < 20 || limit > 100 {
|
if limit < 20 || limit > 100 {
|
||||||
warn!(
|
warn!(
|
||||||
"Unable to set battery charge limit, must be between 20-100: requested {}",
|
"Unable to set battery charge limit, must be between 20-100: requested {}",
|
||||||
@@ -79,12 +89,9 @@ impl CtrlCharge {
|
|||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(self.path)
|
.open(self.path)
|
||||||
.map_err(|err| {
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
warn!("Failed to open battery charge limit path: {}", err);
|
|
||||||
err
|
|
||||||
})?;
|
|
||||||
file.write_all(limit.to_string().as_bytes())
|
file.write_all(limit.to_string().as_bytes())
|
||||||
.unwrap_or_else(|err| error!("Could not write to {}, {}", BAT_CHARGE_PATH, err));
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
info!("Battery charge limit: {}", limit);
|
info!("Battery charge limit: {}", limit);
|
||||||
|
|
||||||
config.read();
|
config.read();
|
||||||
|
|||||||
@@ -1,149 +1,200 @@
|
|||||||
use crate::config::Config;
|
use crate::config::{Config, Profile};
|
||||||
use crate::config::Profile;
|
|
||||||
use asus_nb::profile::ProfileEvent;
|
use asus_nb::profile::ProfileEvent;
|
||||||
use log::{error, info, warn};
|
use log::{info, warn};
|
||||||
use std::error::Error;
|
use std::convert::TryInto;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use std::sync::Mutex;
|
||||||
use tokio::sync::Mutex;
|
use zbus::dbus_interface;
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
|
|
||||||
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
|
||||||
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
|
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
|
||||||
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
|
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
|
||||||
|
|
||||||
pub struct CtrlFanAndCPU {
|
pub struct CtrlFanAndCPU {
|
||||||
path: &'static str,
|
pub path: &'static str,
|
||||||
|
config: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
use ::dbus::{nonblock::SyncConnection, tree::Signal};
|
pub struct DbusFanAndCpu {
|
||||||
use async_trait::async_trait;
|
inner: Arc<Mutex<CtrlFanAndCPU>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl DbusFanAndCpu {
|
||||||
impl crate::Controller for CtrlFanAndCPU {
|
pub fn new(inner: Arc<Mutex<CtrlFanAndCPU>>) -> Self {
|
||||||
type A = ProfileEvent;
|
Self { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Spawns two tasks which continuously check for changes
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
fn spawn_task_loop(
|
impl DbusFanAndCpu {
|
||||||
self,
|
fn set_profile(&self, profile: String) {
|
||||||
config: Arc<Mutex<Config>>,
|
if let Ok(event) = serde_json::from_str(&profile) {
|
||||||
mut recv: Receiver<Self::A>,
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
_: Option<Arc<SyncConnection>>,
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
_: Option<Arc<Signal<()>>>,
|
cfg.read();
|
||||||
) -> Vec<JoinHandle<()>> {
|
ctrl.handle_profile_event(&event, &mut cfg)
|
||||||
let gate1 = Arc::new(Mutex::new(self));
|
|
||||||
let gate2 = gate1.clone();
|
|
||||||
let config1 = config.clone();
|
|
||||||
// spawn an endless loop
|
|
||||||
vec![
|
|
||||||
tokio::spawn(async move {
|
|
||||||
while let Some(event) = recv.recv().await {
|
|
||||||
let mut config = config1.lock().await;
|
|
||||||
let mut lock = gate1.lock().await;
|
|
||||||
|
|
||||||
config.read();
|
|
||||||
lock.handle_profile_event(&event, &mut config)
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
self.notify_profile(&cfg.active_profile)
|
||||||
|
.unwrap_or_else(|_| ());
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
// need to watch file path
|
}
|
||||||
tokio::spawn(async move {
|
|
||||||
loop {
|
|
||||||
tokio::time::delay_for(std::time::Duration::from_millis(100)).await;
|
|
||||||
let mut lock = gate2.lock().await;
|
|
||||||
let mut config = config.lock().await;
|
|
||||||
lock.fan_mode_check_change(&mut config)
|
|
||||||
.unwrap_or_else(|err| warn!("fan_ctrl: {}", err));
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
fn profile(&mut self) -> String {
|
||||||
let mut file = OpenOptions::new().write(true).open(self.path)?;
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
file.write_all(format!("{}\n", config.power_profile).as_bytes())
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
.unwrap_or_else(|err| error!("Could not write to {}, {}", self.path, err));
|
cfg.read();
|
||||||
let profile = config.active_profile.clone();
|
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||||
self.set_profile(&profile, config)?;
|
if let Ok(json) = serde_json::to_string(profile) {
|
||||||
info!(
|
return json;
|
||||||
"Reloaded fan mode: {:?}",
|
}
|
||||||
FanLevel::from(config.power_profile)
|
}
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
"Failed".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn profiles(&mut self) -> String {
|
||||||
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.try_lock() {
|
||||||
|
cfg.read();
|
||||||
|
if let Ok(json) = serde_json::to_string(&cfg.power_profiles) {
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"Failed".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
fn notify_profile(&self, profile: &str) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::ZbusAdd for DbusFanAndCpu {
|
||||||
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(&"/org/asuslinux/Profile".try_into().unwrap(), self)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlFanAndCPU {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(self.path)
|
||||||
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
|
file.write_all(format!("{}\n", config.power_profile).as_bytes())
|
||||||
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
|
let profile = config.active_profile.clone();
|
||||||
|
self.set(&profile, &mut config)?;
|
||||||
|
info!(
|
||||||
|
"Reloaded fan mode: {:?}",
|
||||||
|
FanLevel::from(config.power_profile)
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::CtrlTask for CtrlFanAndCPU {
|
||||||
|
fn do_task(&mut self) -> Result<(), RogError> {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(self.path)
|
||||||
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
|
file.read_exact(&mut buf)
|
||||||
|
.map_err(|err| RogError::Read(self.path.into(), err))?;
|
||||||
|
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
||||||
|
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||||
|
if config.power_profile != num as u8 {
|
||||||
|
config.read();
|
||||||
|
|
||||||
|
let mut i = config
|
||||||
|
.toggle_profiles
|
||||||
|
.iter()
|
||||||
|
.position(|x| x == &config.active_profile)
|
||||||
|
.map(|i| i + 1)
|
||||||
|
.unwrap_or(0);
|
||||||
|
if i >= config.toggle_profiles.len() {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_profile = config
|
||||||
|
.toggle_profiles
|
||||||
|
.get(i)
|
||||||
|
.unwrap_or(&config.active_profile)
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
self.set(&new_profile, &mut config)?;
|
||||||
|
|
||||||
|
info!("Profile was changed: {}", &new_profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(RogError::DoTask("Fan-level could not be parsed".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CtrlFanAndCPU {
|
impl CtrlFanAndCPU {
|
||||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
|
||||||
let path = CtrlFanAndCPU::get_fan_path()?;
|
let path = CtrlFanAndCPU::get_fan_path()?;
|
||||||
info!("Device has thermal throttle control");
|
info!("Device has thermal throttle control");
|
||||||
Ok(CtrlFanAndCPU { path })
|
Ok(CtrlFanAndCPU { path, config })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fan_path() -> Result<&'static str, std::io::Error> {
|
fn get_fan_path() -> Result<&'static str, RogError> {
|
||||||
if Path::new(FAN_TYPE_1_PATH).exists() {
|
if Path::new(FAN_TYPE_1_PATH).exists() {
|
||||||
Ok(FAN_TYPE_1_PATH)
|
Ok(FAN_TYPE_1_PATH)
|
||||||
} else if Path::new(FAN_TYPE_2_PATH).exists() {
|
} else if Path::new(FAN_TYPE_2_PATH).exists() {
|
||||||
Ok(FAN_TYPE_2_PATH)
|
Ok(FAN_TYPE_2_PATH)
|
||||||
} else {
|
} else {
|
||||||
Err(std::io::Error::new(
|
Err(RogError::MissingFunction(
|
||||||
std::io::ErrorKind::NotFound,
|
"Fan mode not available, you may require a v5.8 series kernel or newer".into(),
|
||||||
"Fan mode not available, you may require a v5.8 series kernel or newer",
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn fan_mode_check_change(
|
pub(super) fn do_update(&mut self, config: &mut Config) -> Result<(), RogError> {
|
||||||
&mut self,
|
config.read();
|
||||||
config: &mut Config,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mut file = OpenOptions::new().read(true).open(self.path)?;
|
|
||||||
let mut buf = [0u8; 1];
|
|
||||||
file.read_exact(&mut buf)?;
|
|
||||||
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
|
||||||
if config.power_profile != num as u8 {
|
|
||||||
config.read();
|
|
||||||
|
|
||||||
let mut i = config
|
let mut i = config
|
||||||
.toggle_profiles
|
.toggle_profiles
|
||||||
.iter()
|
.iter()
|
||||||
.position(|x| x == &config.active_profile)
|
.position(|x| x == &config.active_profile)
|
||||||
.map(|i| i + 1)
|
.map(|i| i + 1)
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
if i >= config.toggle_profiles.len() {
|
if i >= config.toggle_profiles.len() {
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
|
||||||
|
|
||||||
let new_profile = config
|
|
||||||
.toggle_profiles
|
|
||||||
.get(i)
|
|
||||||
.unwrap_or(&config.active_profile)
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
self.set_profile(&new_profile, config)?;
|
|
||||||
|
|
||||||
info!("Profile was changed: {}", &new_profile);
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
let err = std::io::Error::new(
|
|
||||||
std::io::ErrorKind::InvalidData,
|
let new_profile = config
|
||||||
"Fan-level could not be parsed",
|
.toggle_profiles
|
||||||
);
|
.get(i)
|
||||||
Err(Box::new(err))
|
.unwrap_or(&config.active_profile)
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
self.set(&new_profile, config)?;
|
||||||
|
|
||||||
|
info!("Profile was changed: {}", &new_profile);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set_fan_mode(
|
pub(super) fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
|
||||||
&mut self,
|
|
||||||
preset: u8,
|
|
||||||
config: &mut Config,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mode = config.active_profile.clone();
|
let mode = config.active_profile.clone();
|
||||||
let mut fan_ctrl = OpenOptions::new().write(true).open(self.path)?;
|
let mut fan_ctrl = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(self.path)
|
||||||
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
config.read();
|
config.read();
|
||||||
let mut mode_config = config
|
let mut mode_config = config
|
||||||
.power_profiles
|
.power_profiles
|
||||||
@@ -154,7 +205,7 @@ impl CtrlFanAndCPU {
|
|||||||
config.write();
|
config.write();
|
||||||
fan_ctrl
|
fan_ctrl
|
||||||
.write_all(format!("{}\n", preset).as_bytes())
|
.write_all(format!("{}\n", preset).as_bytes())
|
||||||
.unwrap_or_else(|err| error!("Could not write to {}, {}", self.path, err));
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
info!("Fan mode set to: {:?}", FanLevel::from(preset));
|
info!("Fan mode set to: {:?}", FanLevel::from(preset));
|
||||||
self.set_pstate_for_fan_mode(&mode, config)?;
|
self.set_pstate_for_fan_mode(&mode, config)?;
|
||||||
self.set_fan_curve_for_fan_mode(&mode, config)?;
|
self.set_fan_curve_for_fan_mode(&mode, config)?;
|
||||||
@@ -165,8 +216,9 @@ impl CtrlFanAndCPU {
|
|||||||
&mut self,
|
&mut self,
|
||||||
event: &ProfileEvent,
|
event: &ProfileEvent,
|
||||||
config: &mut Config,
|
config: &mut Config,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), RogError> {
|
||||||
match event {
|
match event {
|
||||||
|
ProfileEvent::Toggle => self.do_update(config)?,
|
||||||
ProfileEvent::ChangeMode(mode) => {
|
ProfileEvent::ChangeMode(mode) => {
|
||||||
self.set_fan_mode(*mode, config)?;
|
self.set_fan_mode(*mode, config)?;
|
||||||
}
|
}
|
||||||
@@ -204,21 +256,24 @@ impl CtrlFanAndCPU {
|
|||||||
profile.fan_curve = Some(curve.clone());
|
profile.fan_curve = Some(curve.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_profile(&profile_key, config)?;
|
self.set(&profile_key, config)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_profile(&mut self, profile: &str, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
|
||||||
let mode_config = config
|
let mode_config = config
|
||||||
.power_profiles
|
.power_profiles
|
||||||
.get(profile)
|
.get(profile)
|
||||||
.ok_or_else(|| RogError::MissingProfile(profile.into()))?;
|
.ok_or_else(|| RogError::MissingProfile(profile.into()))?;
|
||||||
let mut fan_ctrl = OpenOptions::new().write(true).open(self.path)?;
|
let mut fan_ctrl = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.open(self.path)
|
||||||
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
fan_ctrl
|
fan_ctrl
|
||||||
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
|
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
|
||||||
.unwrap_or_else(|err| error!("Could not write to {}, {}", self.path, err));
|
.map_err(|err| RogError::Write(self.path.into(), err))?;
|
||||||
config.power_profile = mode_config.fan_preset;
|
config.power_profile = mode_config.fan_preset;
|
||||||
|
|
||||||
self.set_pstate_for_fan_mode(profile, config)?;
|
self.set_pstate_for_fan_mode(profile, config)?;
|
||||||
@@ -230,12 +285,7 @@ impl CtrlFanAndCPU {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pstate_for_fan_mode(
|
fn set_pstate_for_fan_mode(&self, mode: &str, config: &mut Config) -> Result<(), RogError> {
|
||||||
&self,
|
|
||||||
// mode: FanLevel,
|
|
||||||
mode: &str,
|
|
||||||
config: &mut Config,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
info!("Setting pstate");
|
info!("Setting pstate");
|
||||||
let mode_config = config
|
let mode_config = config
|
||||||
.power_profiles
|
.power_profiles
|
||||||
@@ -257,25 +307,17 @@ impl CtrlFanAndCPU {
|
|||||||
let mut file = OpenOptions::new()
|
let mut file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
.open(AMD_BOOST_PATH)
|
.open(AMD_BOOST_PATH)
|
||||||
.map_err(|err| {
|
.map_err(|err| RogError::Path(self.path.into(), err))?;
|
||||||
warn!("Failed to open AMD boost: {}", err);
|
|
||||||
err
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let boost = if mode_config.turbo { "1" } else { "0" }; // opposite of Intel
|
let boost = if mode_config.turbo { "1" } else { "0" }; // opposite of Intel
|
||||||
file.write_all(boost.as_bytes())
|
file.write_all(boost.as_bytes())
|
||||||
.unwrap_or_else(|err| error!("Could not write to {}, {}", AMD_BOOST_PATH, err));
|
.map_err(|err| RogError::Write(AMD_BOOST_PATH.into(), err))?;
|
||||||
info!("AMD CPU Turbo: {}", boost);
|
info!("AMD CPU Turbo: {}", boost);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fan_curve_for_fan_mode(
|
fn set_fan_curve_for_fan_mode(&self, mode: &str, config: &Config) -> Result<(), RogError> {
|
||||||
&self,
|
|
||||||
// mode: FanLevel,
|
|
||||||
mode: &str,
|
|
||||||
config: &Config,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let mode_config = &config
|
let mode_config = &config
|
||||||
.power_profiles
|
.power_profiles
|
||||||
.get(mode)
|
.get(mode)
|
||||||
|
|||||||
@@ -3,135 +3,180 @@ static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|||||||
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
use crate::{config::Config, error::RogError, laptops::HELP_ADDRESS};
|
use crate::{config::Config, error::RogError, laptops::HELP_ADDRESS};
|
||||||
use asus_nb::{
|
use asus_nb::{aura_brightness_bytes, aura_modes::AuraModes, fancy::KeyColourArray, LED_MSG_LEN};
|
||||||
aura_brightness_bytes, aura_modes::AuraModes, fancy::KeyColourArray, DBUS_IFACE, DBUS_PATH,
|
|
||||||
LED_MSG_LEN,
|
|
||||||
};
|
|
||||||
use dbus::{channel::Sender, nonblock::SyncConnection, tree::Signal};
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use std::error::Error;
|
use std::convert::TryInto;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::mpsc::Receiver;
|
use std::sync::Mutex;
|
||||||
use tokio::sync::Mutex;
|
use zbus::dbus_interface;
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
|
|
||||||
pub struct CtrlKbdBacklight {
|
pub struct CtrlKbdBacklight {
|
||||||
led_node: Option<String>,
|
led_node: Option<String>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
kbd_node: Option<String>,
|
kbd_node: Option<String>,
|
||||||
bright_node: String,
|
pub bright_node: String,
|
||||||
supported_modes: Vec<u8>,
|
supported_modes: Vec<u8>,
|
||||||
flip_effect_write: bool,
|
flip_effect_write: bool,
|
||||||
|
config: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
use async_trait::async_trait;
|
pub struct DbusKbdBacklight {
|
||||||
|
inner: Arc<Mutex<CtrlKbdBacklight>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
impl DbusKbdBacklight {
|
||||||
impl crate::Controller for CtrlKbdBacklight {
|
pub fn new(inner: Arc<Mutex<CtrlKbdBacklight>>) -> Self {
|
||||||
type A = AuraModes;
|
Self { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Spawns two tasks which continuously check for changes
|
trait Dbus {
|
||||||
fn spawn_task_loop(
|
fn set_led(&mut self, data: String);
|
||||||
self,
|
fn ledmode(&self) -> String;
|
||||||
config: Arc<Mutex<Config>>,
|
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
||||||
mut recv: Receiver<Self::A>,
|
}
|
||||||
connection: Option<Arc<SyncConnection>>,
|
|
||||||
signal: Option<Arc<Signal<()>>>,
|
|
||||||
) -> Vec<JoinHandle<()>> {
|
|
||||||
let gate1 = Arc::new(Mutex::new(self));
|
|
||||||
let gate2 = gate1.clone();
|
|
||||||
|
|
||||||
let config1 = config.clone();
|
impl crate::ZbusAdd for DbusKbdBacklight {
|
||||||
vec![
|
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
tokio::spawn(async move {
|
server
|
||||||
while let Some(command) = recv.recv().await {
|
.at(&"/org/asuslinux/Led".try_into().unwrap(), self)
|
||||||
let mut config = config1.lock().await;
|
.unwrap();
|
||||||
let mut lock = gate1.lock().await;
|
}
|
||||||
match &command {
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl DbusKbdBacklight {
|
||||||
|
fn set_led_mode(&mut self, data: String) {
|
||||||
|
if let Ok(data) = serde_json::from_str(&data) {
|
||||||
|
if let Ok(mut ctrl) = self.inner.try_lock() {
|
||||||
|
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
|
||||||
|
match &data {
|
||||||
AuraModes::PerKey(_) => {
|
AuraModes::PerKey(_) => {
|
||||||
lock.do_command(command, &mut config)
|
ctrl.do_command(data, &mut cfg)
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let json = serde_json::to_string(&command).unwrap();
|
let json = serde_json::to_string(&data).unwrap();
|
||||||
lock.do_command(command, &mut config)
|
ctrl.do_command(data, &mut cfg)
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
connection
|
self.notify_led(&json).unwrap();
|
||||||
.as_ref()
|
|
||||||
.expect("LED Controller must have DBUS connection")
|
|
||||||
.send(
|
|
||||||
signal
|
|
||||||
.as_ref()
|
|
||||||
.expect("LED Controller must have DBUS signal")
|
|
||||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
|
||||||
.append1(json),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|_| 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
tokio::spawn(async move {
|
} else {
|
||||||
loop {
|
warn!("SetKeyBacklight could not deserialise");
|
||||||
tokio::time::delay_for(std::time::Duration::from_millis(100)).await;
|
}
|
||||||
let mut lock = gate2.lock().await;
|
|
||||||
let mut config = config.lock().await;
|
|
||||||
lock.let_bright_check_change(&mut config)
|
|
||||||
.unwrap_or_else(|err| warn!("led_ctrl: {}", err));
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
fn led_mode(&self) -> String {
|
||||||
// set current mode (if any)
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
if self.supported_modes.len() > 1 {
|
if let Ok(cfg) = ctrl.config.clone().try_lock() {
|
||||||
if self.supported_modes.contains(&config.kbd_backlight_mode) {
|
if let Some(mode) = cfg.get_led_mode_data(cfg.kbd_backlight_mode) {
|
||||||
let mode = config
|
if let Ok(json) = serde_json::to_string(&mode) {
|
||||||
.get_led_mode_data(config.kbd_backlight_mode)
|
return json;
|
||||||
.ok_or(RogError::NotSupported)?
|
|
||||||
.to_owned();
|
|
||||||
self.write_mode(&mode).await?;
|
|
||||||
info!("Reloaded last used mode");
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"An unsupported mode was set: {}, reset to first mode available",
|
|
||||||
<&str>::from(&<AuraModes>::from(config.kbd_backlight_mode))
|
|
||||||
);
|
|
||||||
for (idx, mode) in config.kbd_backlight_modes.iter_mut().enumerate() {
|
|
||||||
if !self.supported_modes.contains(&mode.into()) {
|
|
||||||
config.kbd_backlight_modes.remove(idx);
|
|
||||||
config.write();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.kbd_backlight_mode = self.supported_modes[0];
|
|
||||||
// TODO: do a recursive call with a boxed dyn future later
|
|
||||||
let mode = config
|
|
||||||
.get_led_mode_data(config.kbd_backlight_mode)
|
|
||||||
.ok_or(RogError::NotSupported)?
|
|
||||||
.to_owned();
|
|
||||||
self.write_mode(&mode).await?;
|
|
||||||
info!("Reloaded last used mode");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
warn!("SetKeyBacklight could not deserialise");
|
||||||
|
"SetKeyBacklight could not deserialise".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
// Reload brightness
|
fn led_modes(&self) -> String {
|
||||||
let bright = config.kbd_led_brightness;
|
if let Ok(ctrl) = self.inner.try_lock() {
|
||||||
let bytes = aura_brightness_bytes(bright);
|
if let Ok(cfg) = ctrl.config.clone().try_lock() {
|
||||||
self.write_bytes(&bytes).await?;
|
if let Ok(json) = serde_json::to_string(&cfg.kbd_backlight_modes) {
|
||||||
info!("Reloaded last used brightness");
|
return json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warn!("SetKeyBacklight could not deserialise");
|
||||||
|
"SetKeyBacklight could not deserialise".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
fn notify_led(&self, data: &str) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Reloadable for CtrlKbdBacklight {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError> {
|
||||||
|
// set current mode (if any)
|
||||||
|
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||||
|
if self.supported_modes.len() > 1 {
|
||||||
|
if self.supported_modes.contains(&config.kbd_backlight_mode) {
|
||||||
|
let mode = config
|
||||||
|
.get_led_mode_data(config.kbd_backlight_mode)
|
||||||
|
.ok_or(RogError::NotSupported)?
|
||||||
|
.to_owned();
|
||||||
|
self.write_mode(&mode)?;
|
||||||
|
info!("Reloaded last used mode");
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"An unsupported mode was set: {}, reset to first mode available",
|
||||||
|
<&str>::from(&<AuraModes>::from(config.kbd_backlight_mode))
|
||||||
|
);
|
||||||
|
for (idx, mode) in config.kbd_backlight_modes.iter_mut().enumerate() {
|
||||||
|
if !self.supported_modes.contains(&mode.into()) {
|
||||||
|
config.kbd_backlight_modes.remove(idx);
|
||||||
|
config.write();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.kbd_backlight_mode = self.supported_modes[0];
|
||||||
|
// TODO: do a recursive call with a boxed dyn future later
|
||||||
|
let mode = config
|
||||||
|
.get_led_mode_data(config.kbd_backlight_mode)
|
||||||
|
.ok_or(RogError::NotSupported)?
|
||||||
|
.to_owned();
|
||||||
|
self.write_mode(&mode)?;
|
||||||
|
info!("Reloaded last used mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload brightness
|
||||||
|
let bright = config.kbd_led_brightness;
|
||||||
|
let bytes = aura_brightness_bytes(bright);
|
||||||
|
self.write_bytes(&bytes)?;
|
||||||
|
info!("Reloaded last used brightness");
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::CtrlTask for CtrlKbdBacklight {
|
||||||
|
fn do_task(&mut self) -> Result<(), RogError> {
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(&self.bright_node)
|
||||||
|
.map_err(|err| RogError::Path((&self.bright_node).into(), err))?;
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
|
file.read_exact(&mut buf)
|
||||||
|
.map_err(|err| RogError::Read("buffer".into(), err))?;
|
||||||
|
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
||||||
|
if let Ok(mut config) = self.config.clone().try_lock() {
|
||||||
|
if config.kbd_led_brightness != num as u8 {
|
||||||
|
config.read();
|
||||||
|
config.kbd_led_brightness = num as u8;
|
||||||
|
config.write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err(RogError::ParseLED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CtrlKbdBacklight {
|
impl CtrlKbdBacklight {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(id_product: &str, condev_iface: Option<&String>, supported_modes: Vec<u8>) -> Self {
|
pub fn new(
|
||||||
|
id_product: &str,
|
||||||
|
condev_iface: Option<&String>,
|
||||||
|
supported_modes: Vec<u8>,
|
||||||
|
config: Arc<Mutex<Config>>,
|
||||||
|
) -> Self {
|
||||||
// TODO: return error if *all* nodes are None
|
// TODO: return error if *all* nodes are None
|
||||||
CtrlKbdBacklight {
|
CtrlKbdBacklight {
|
||||||
led_node: Self::get_node_failover(id_product, None, Self::scan_led_node).ok(),
|
led_node: Self::get_node_failover(id_product, None, Self::scan_led_node).ok(),
|
||||||
@@ -140,14 +185,15 @@ impl CtrlKbdBacklight {
|
|||||||
bright_node: "/sys/class/leds/asus::kbd_backlight/brightness".to_string(),
|
bright_node: "/sys/class/leds/asus::kbd_backlight/brightness".to_string(),
|
||||||
supported_modes,
|
supported_modes,
|
||||||
flip_effect_write: false,
|
flip_effect_write: false,
|
||||||
|
config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_node_failover(
|
fn get_node_failover(
|
||||||
id_product: &str,
|
id_product: &str,
|
||||||
iface: Option<&String>,
|
iface: Option<&String>,
|
||||||
fun: fn(&str, Option<&String>) -> Result<String, std::io::Error>,
|
fun: fn(&str, Option<&String>) -> Result<String, RogError>,
|
||||||
) -> Result<String, std::io::Error> {
|
) -> Result<String, RogError> {
|
||||||
for n in 0..=2 {
|
for n in 0..=2 {
|
||||||
// 0,1,2 inclusive
|
// 0,1,2 inclusive
|
||||||
match fun(id_product, iface) {
|
match fun(id_product, iface) {
|
||||||
@@ -157,32 +203,34 @@ impl CtrlKbdBacklight {
|
|||||||
warn!("Looking for node: {}", e.to_string());
|
warn!("Looking for node: {}", e.to_string());
|
||||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||||
} else {
|
} else {
|
||||||
return Err(e);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Shouldn't be possible to reach this...
|
// Shouldn't be possible to reach this...
|
||||||
let err = std::io::Error::new(std::io::ErrorKind::NotFound, "node not found");
|
Err(RogError::NotFound(format!("{}, {:?}", id_product, iface)))
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_led_node(id_product: &str, _: Option<&String>) -> Result<String, std::io::Error> {
|
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);
|
||||||
err
|
RogError::Udev("enumerator failed".into(), err)
|
||||||
})?;
|
})?;
|
||||||
enumerator.match_subsystem("hidraw").map_err(|err| {
|
enumerator.match_subsystem("hidraw").map_err(|err| {
|
||||||
warn!("{}", err);
|
warn!("{}", err);
|
||||||
err
|
RogError::Udev("match_subsystem failed".into(), err)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
for device in enumerator.scan_devices()? {
|
for device in enumerator.scan_devices().map_err(|err| {
|
||||||
|
warn!("{}", err);
|
||||||
|
RogError::Udev("scan_devices failed".into(), err)
|
||||||
|
})? {
|
||||||
if let Some(parent) = device
|
if let Some(parent) = device
|
||||||
.parent_with_subsystem_devtype("usb", "usb_device")
|
.parent_with_subsystem_devtype("usb", "usb_device")
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
warn!("{}", err);
|
warn!("{}", err);
|
||||||
err
|
RogError::Udev("parent_with_subsystem_devtype failed".into(), err)
|
||||||
})?
|
})?
|
||||||
{
|
{
|
||||||
if parent.attribute_value("idProduct").unwrap() == id_product {
|
if parent.attribute_value("idProduct").unwrap() == id_product {
|
||||||
@@ -194,30 +242,34 @@ impl CtrlKbdBacklight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let err = std::io::Error::new(
|
|
||||||
std::io::ErrorKind::NotFound,
|
|
||||||
"ASUS LED device node not found",
|
|
||||||
);
|
|
||||||
warn!("Did not find a hidraw node for LED control, your device may be unsupported or require a kernel patch, see: {}", HELP_ADDRESS);
|
warn!("Did not find a hidraw node for LED control, your device may be unsupported or require a kernel patch, see: {}", HELP_ADDRESS);
|
||||||
Err(err)
|
Err(RogError::MissingFunction(
|
||||||
|
"ASUS LED device node not found".into(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scan_kbd_node(id_product: &str, iface: Option<&String>) -> Result<String, std::io::Error> {
|
fn scan_kbd_node(id_product: &str, iface: Option<&String>) -> Result<String, RogError> {
|
||||||
let mut enumerator = udev::Enumerator::new()?;
|
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||||
|
warn!("{}", err);
|
||||||
|
RogError::Udev("enumerator failed".into(), err)
|
||||||
|
})?;
|
||||||
enumerator.match_subsystem("input").map_err(|err| {
|
enumerator.match_subsystem("input").map_err(|err| {
|
||||||
warn!("{}", err);
|
warn!("{}", err);
|
||||||
err
|
RogError::Udev("match_subsystem failed".into(), err)
|
||||||
})?;
|
})?;
|
||||||
enumerator
|
enumerator
|
||||||
.match_property("ID_MODEL_ID", id_product)
|
.match_property("ID_MODEL_ID", id_product)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
warn!("{}", err);
|
warn!("{}", err);
|
||||||
err
|
RogError::Udev("match_property failed".into(), err)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
for device in enumerator.scan_devices().map_err(|err| {
|
for device in enumerator.scan_devices().map_err(|err| {
|
||||||
warn!("{}", err);
|
warn!("{}", err);
|
||||||
err
|
err
|
||||||
|
}).map_err(|err| {
|
||||||
|
warn!("{}", err);
|
||||||
|
RogError::Udev("scan_devices failed".into(), err)
|
||||||
})? {
|
})? {
|
||||||
if let Some(dev_node) = device.devnode() {
|
if let Some(dev_node) = device.devnode() {
|
||||||
if let Some(inum) = device.property_value("ID_USB_INTERFACE_NUM") {
|
if let Some(inum) = device.property_value("ID_USB_INTERFACE_NUM") {
|
||||||
@@ -230,63 +282,39 @@ impl CtrlKbdBacklight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let err = std::io::Error::new(
|
|
||||||
std::io::ErrorKind::NotFound,
|
|
||||||
"ASUS keyboard 'Consumer Device' node not found",
|
|
||||||
);
|
|
||||||
warn!("Did not find keyboard consumer device node, if expected functions are missing please file an issue at {}", HELP_ADDRESS);
|
warn!("Did not find keyboard consumer device node, if expected functions are missing please file an issue at {}", HELP_ADDRESS);
|
||||||
Err(err)
|
Err(RogError::MissingFunction(
|
||||||
|
"ASUS keyboard 'Consumer Device' node not found".into(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn let_bright_check_change(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
pub fn do_command(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> {
|
||||||
let mut file = OpenOptions::new().read(true).open(&self.bright_node)?;
|
self.set_and_save(mode, config)
|
||||||
let mut buf = [0u8; 1];
|
|
||||||
file.read_exact(&mut buf)?;
|
|
||||||
if let Some(num) = char::from(buf[0]).to_digit(10) {
|
|
||||||
if config.kbd_led_brightness != num as u8 {
|
|
||||||
config.read();
|
|
||||||
config.kbd_led_brightness = num as u8;
|
|
||||||
config.write();
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let err = std::io::Error::new(
|
|
||||||
std::io::ErrorKind::InvalidData,
|
|
||||||
"LED brightness could not be parsed",
|
|
||||||
);
|
|
||||||
Err(Box::new(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn do_command(
|
|
||||||
&mut self,
|
|
||||||
mode: AuraModes,
|
|
||||||
config: &mut Config,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
self.set_and_save(mode, config).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should only be used if the bytes you are writing are verified correct
|
/// Should only be used if the bytes you are writing are verified correct
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn write_bytes(&self, message: &[u8]) -> Result<(), Box<dyn Error>> {
|
fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
|
||||||
if let Some(led_node) = &self.led_node {
|
if let Some(led_node) = &self.led_node {
|
||||||
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
|
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
|
||||||
file.write_all(message).unwrap();
|
file.write_all(message).unwrap();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Box::new(RogError::NotSupported))
|
Err(RogError::NotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write an effect block
|
/// Write an effect block
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn write_effect(&mut self, effect: &[Vec<u8>]) -> Result<(), Box<dyn Error>> {
|
fn write_effect(&mut self, effect: &[Vec<u8>]) -> Result<(), RogError> {
|
||||||
if self.flip_effect_write {
|
if self.flip_effect_write {
|
||||||
for row in effect.iter().rev() {
|
for row in effect.iter().rev() {
|
||||||
self.write_bytes(row).await?;
|
self.write_bytes(row)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for row in effect.iter() {
|
for row in effect.iter() {
|
||||||
self.write_bytes(row).await?;
|
self.write_bytes(row)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.flip_effect_write = !self.flip_effect_write;
|
self.flip_effect_write = !self.flip_effect_write;
|
||||||
@@ -297,15 +325,11 @@ impl CtrlKbdBacklight {
|
|||||||
///
|
///
|
||||||
/// This needs to be universal so that settings applied by dbus stick
|
/// This needs to be universal so that settings applied by dbus stick
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn set_and_save(
|
fn set_and_save(&mut self, mode: AuraModes, config: &mut Config) -> Result<(), RogError> {
|
||||||
&mut self,
|
|
||||||
mode: AuraModes,
|
|
||||||
config: &mut Config,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
match mode {
|
match mode {
|
||||||
AuraModes::LedBrightness(n) => {
|
AuraModes::LedBrightness(n) => {
|
||||||
let bytes: [u8; LED_MSG_LEN] = (&mode).into();
|
let bytes: [u8; LED_MSG_LEN] = (&mode).into();
|
||||||
self.write_bytes(&bytes).await?;
|
self.write_bytes(&bytes)?;
|
||||||
config.read();
|
config.read();
|
||||||
config.kbd_led_brightness = n;
|
config.kbd_led_brightness = n;
|
||||||
config.write();
|
config.write();
|
||||||
@@ -314,15 +338,15 @@ impl CtrlKbdBacklight {
|
|||||||
AuraModes::PerKey(v) => {
|
AuraModes::PerKey(v) => {
|
||||||
if v.is_empty() || v[0].is_empty() {
|
if v.is_empty() || v[0].is_empty() {
|
||||||
let bytes = KeyColourArray::get_init_msg();
|
let bytes = KeyColourArray::get_init_msg();
|
||||||
self.write_bytes(&bytes).await?;
|
self.write_bytes(&bytes)?;
|
||||||
} else {
|
} else {
|
||||||
self.write_effect(&v).await?;
|
self.write_effect(&v)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
config.read();
|
config.read();
|
||||||
let mode_num: u8 = u8::from(&mode);
|
let mode_num: u8 = u8::from(&mode);
|
||||||
self.write_mode(&mode).await?;
|
self.write_mode(&mode)?;
|
||||||
config.kbd_backlight_mode = mode_num;
|
config.kbd_backlight_mode = mode_num;
|
||||||
config.set_mode_data(mode);
|
config.set_mode_data(mode);
|
||||||
config.write();
|
config.write();
|
||||||
@@ -332,14 +356,14 @@ impl CtrlKbdBacklight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn write_mode(&mut self, mode: &AuraModes) -> Result<(), Box<dyn Error>> {
|
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
|
||||||
match mode {
|
match mode {
|
||||||
AuraModes::PerKey(v) => {
|
AuraModes::PerKey(v) => {
|
||||||
if v.is_empty() || v[0].is_empty() {
|
if v.is_empty() || v[0].is_empty() {
|
||||||
let bytes = KeyColourArray::get_init_msg();
|
let bytes = KeyColourArray::get_init_msg();
|
||||||
self.write_bytes(&bytes).await?;
|
self.write_bytes(&bytes)?;
|
||||||
} else {
|
} else {
|
||||||
self.write_effect(v).await?;
|
self.write_effect(v)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -349,20 +373,20 @@ impl CtrlKbdBacklight {
|
|||||||
if self.supported_modes.contains(&mode_num) {
|
if self.supported_modes.contains(&mode_num) {
|
||||||
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
|
let bytes: [[u8; LED_MSG_LEN]; 4] = mode.into();
|
||||||
for array in bytes.iter() {
|
for array in bytes.iter() {
|
||||||
self.write_bytes(array).await?;
|
self.write_bytes(array)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if self.supported_modes.contains(&mode_num) {
|
if self.supported_modes.contains(&mode_num) {
|
||||||
let bytes: [u8; LED_MSG_LEN] = mode.into();
|
let bytes: [u8; LED_MSG_LEN] = mode.into();
|
||||||
self.write_bytes(&bytes).await?;
|
self.write_bytes(&bytes)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.write_bytes(&LED_SET).await?;
|
self.write_bytes(&LED_SET)?;
|
||||||
// Changes won't persist unless apply is set
|
// Changes won't persist unless apply is set
|
||||||
self.write_bytes(&LED_APPLY).await?;
|
self.write_bytes(&LED_APPLY)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,27 +1,24 @@
|
|||||||
use daemon::{
|
use ctrl_gfx::ctrl_gfx::CtrlGraphics;
|
||||||
config::Config, ctrl_anime::CtrlAnimeDisplay, ctrl_charge::CtrlCharge,
|
use daemon::config::Config;
|
||||||
ctrl_fan_cpu::CtrlFanAndCPU, ctrl_leds::CtrlKbdBacklight, dbus::dbus_create_tree,
|
use daemon::ctrl_anime::CtrlAnimeDisplay;
|
||||||
laptops::match_laptop,
|
use daemon::ctrl_charge::CtrlCharge;
|
||||||
};
|
use daemon::ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu};
|
||||||
|
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
|
||||||
|
use daemon::laptops::match_laptop;
|
||||||
|
|
||||||
use dbus::{
|
use asus_nb::DBUS_NAME;
|
||||||
channel::Sender,
|
use daemon::{CtrlTask, Reloadable, ZbusAdd};
|
||||||
nonblock::{Process, SyncConnection},
|
|
||||||
tree::Signal,
|
|
||||||
};
|
|
||||||
use dbus_tokio::connection;
|
|
||||||
|
|
||||||
use asus_nb::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
|
||||||
use daemon::Controller;
|
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
#[tokio::main]
|
use zbus::fdo;
|
||||||
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
use zbus::Connection;
|
||||||
|
|
||||||
|
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut logger = env_logger::Builder::new();
|
let mut logger = env_logger::Builder::new();
|
||||||
logger
|
logger
|
||||||
.target(env_logger::Target::Stdout)
|
.target(env_logger::Target::Stdout)
|
||||||
@@ -30,7 +27,7 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
info!("Version: {}", daemon::VERSION);
|
info!("Version: {}", daemon::VERSION);
|
||||||
start_daemon().await?;
|
start_daemon()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,209 +40,100 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// as fast as 1ms per row of the matrix inside it. (10ms total time)
|
// as fast as 1ms per row of the matrix inside it. (10ms total time)
|
||||||
//
|
//
|
||||||
// DBUS processing takes 6ms if not tokiod
|
// DBUS processing takes 6ms if not tokiod
|
||||||
pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
let laptop = match_laptop();
|
let laptop = match_laptop();
|
||||||
let mut config = if let Some(laptop) = laptop.as_ref() {
|
let config = if let Some(laptop) = laptop.as_ref() {
|
||||||
Config::default().load(laptop.supported_modes())
|
Config::default().load(laptop.supported_modes())
|
||||||
} else {
|
} else {
|
||||||
Config::default().load(&[])
|
Config::default().load(&[])
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut led_control = if let Some(laptop) = laptop {
|
let connection = Connection::new_system()?;
|
||||||
Some(CtrlKbdBacklight::new(
|
fdo::DBusProxy::new(&connection)?
|
||||||
|
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
|
||||||
|
let mut object_server = zbus::ObjectServer::new(&connection);
|
||||||
|
|
||||||
|
let config = Arc::new(Mutex::new(config));
|
||||||
|
|
||||||
|
match CtrlCharge::new(config.clone()) {
|
||||||
|
Ok(mut ctrl) => {
|
||||||
|
// Do a reload of any settings
|
||||||
|
ctrl.reload()
|
||||||
|
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
|
||||||
|
// Then register to dbus server
|
||||||
|
ctrl.add_to_server(&mut object_server);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("charge_control: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match CtrlAnimeDisplay::new() {
|
||||||
|
Ok(ctrl) => {
|
||||||
|
ctrl.add_to_server(&mut object_server);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("AniMe control: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match CtrlGraphics::new() {
|
||||||
|
Ok(mut ctrl) => {
|
||||||
|
ctrl.reload()
|
||||||
|
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
|
||||||
|
ctrl.add_to_server(&mut object_server);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Gfx control: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect tasks for task thread
|
||||||
|
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
|
||||||
|
|
||||||
|
match CtrlFanAndCPU::new(config.clone()) {
|
||||||
|
Ok(mut ctrl) => {
|
||||||
|
ctrl.reload()
|
||||||
|
.unwrap_or_else(|err| warn!("Profile control: {}", err));
|
||||||
|
let tmp = Arc::new(Mutex::new(ctrl));
|
||||||
|
DbusFanAndCpu::new(tmp.clone()).add_to_server(&mut object_server);
|
||||||
|
tasks.push(tmp);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Profile control: {}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(laptop) = laptop {
|
||||||
|
let ctrl = CtrlKbdBacklight::new(
|
||||||
laptop.usb_product(),
|
laptop.usb_product(),
|
||||||
laptop.condev_iface(),
|
laptop.condev_iface(),
|
||||||
laptop.supported_modes().to_owned(),
|
laptop.supported_modes().to_owned(),
|
||||||
))
|
config,
|
||||||
} else {
|
);
|
||||||
None
|
let tmp = Arc::new(Mutex::new(ctrl));
|
||||||
};
|
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
|
||||||
|
tasks.push(tmp);
|
||||||
let mut charge_control = CtrlCharge::new().map_or_else(
|
|
||||||
|err| {
|
|
||||||
error!("{}", err);
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Some,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut fan_control = CtrlFanAndCPU::new().map_or_else(
|
|
||||||
|err| {
|
|
||||||
error!("{}", err);
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Some,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Reload settings
|
|
||||||
if let Some(ctrl) = fan_control.as_mut() {
|
|
||||||
ctrl.reload_from_config(&mut config)
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|err| warn!("Fan mode: {}", err));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ctrl) = charge_control.as_mut() {
|
// TODO: implement messaging between threads to check fails
|
||||||
ctrl.reload_from_config(&mut config)
|
// These tasks generally read a sys path or file to check for a
|
||||||
.await
|
// change
|
||||||
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
|
let _handle = std::thread::Builder::new()
|
||||||
}
|
.name("asusd watch".to_string())
|
||||||
|
.spawn(move || loop {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
|
||||||
if let Some(ctrl) = led_control.as_mut() {
|
for ctrl in tasks.iter() {
|
||||||
ctrl.reload_from_config(&mut config)
|
if let Ok(mut lock) = ctrl.try_lock() {
|
||||||
.await
|
lock.do_task().unwrap();
|
||||||
.unwrap_or_else(|err| warn!("Reload settings: {}", err));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let (resource, connection) = connection::new_system_sync()?;
|
|
||||||
tokio::spawn(async {
|
|
||||||
let err = resource.await;
|
|
||||||
panic!("Lost connection to D-Bus: {}", err);
|
|
||||||
});
|
|
||||||
|
|
||||||
connection
|
|
||||||
.request_name(DBUS_NAME, false, true, true)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let config = Arc::new(Mutex::new(config));
|
|
||||||
let (
|
|
||||||
tree,
|
|
||||||
aura_command_recv,
|
|
||||||
animatrix_recv,
|
|
||||||
_fan_mode_recv,
|
|
||||||
charge_limit_recv,
|
|
||||||
profile_recv,
|
|
||||||
led_changed_signal,
|
|
||||||
fanmode_signal,
|
|
||||||
charge_limit_signal,
|
|
||||||
) = dbus_create_tree(config.clone());
|
|
||||||
|
|
||||||
// We add the tree to the connection so that incoming method calls will be handled.
|
|
||||||
tree.start_receive_send(&*connection);
|
|
||||||
|
|
||||||
// Send boot signals
|
|
||||||
send_boot_signals(
|
|
||||||
connection.clone(),
|
|
||||||
config.clone(),
|
|
||||||
fanmode_signal.clone(),
|
|
||||||
charge_limit_signal.clone(),
|
|
||||||
led_changed_signal.clone(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// For helping with processing signals
|
|
||||||
start_signal_task(
|
|
||||||
connection.clone(),
|
|
||||||
config.clone(),
|
|
||||||
fanmode_signal,
|
|
||||||
charge_limit_signal,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Begin all tasks
|
|
||||||
let mut handles = Vec::new();
|
|
||||||
if let Ok(ctrl) = CtrlAnimeDisplay::new() {
|
|
||||||
handles.append(&mut ctrl.spawn_task_loop(config.clone(), animatrix_recv, None, None));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ctrl) = fan_control.take() {
|
|
||||||
handles.append(&mut ctrl.spawn_task_loop(config.clone(), profile_recv, None, None));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ctrl) = charge_control.take() {
|
|
||||||
handles.append(&mut ctrl.spawn_task_loop(config.clone(), charge_limit_recv, None, None));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ctrl) = led_control.take() {
|
|
||||||
handles.append(&mut ctrl.spawn_task_loop(
|
|
||||||
config.clone(),
|
|
||||||
aura_command_recv,
|
|
||||||
Some(connection.clone()),
|
|
||||||
Some(led_changed_signal),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
connection.process_all();
|
|
||||||
for handle in handles {
|
|
||||||
handle.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move these in to the controllers tasks
|
|
||||||
fn start_signal_task(
|
|
||||||
connection: Arc<SyncConnection>,
|
|
||||||
config: Arc<Mutex<Config>>,
|
|
||||||
fanmode_signal: Arc<Signal<()>>,
|
|
||||||
charge_limit_signal: Arc<Signal<()>>,
|
|
||||||
) {
|
|
||||||
tokio::spawn(async move {
|
|
||||||
// Some small things we need to track, without passing all sorts of stuff around
|
|
||||||
let mut last_fan_mode = config.lock().await.power_profile;
|
|
||||||
let mut last_charge_limit = config.lock().await.bat_charge_limit;
|
|
||||||
loop {
|
|
||||||
// Use tokio sleep to not hold up other threads
|
|
||||||
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
|
|
||||||
|
|
||||||
let config = config.lock().await;
|
|
||||||
if config.power_profile != last_fan_mode {
|
|
||||||
last_fan_mode = config.power_profile;
|
|
||||||
connection
|
|
||||||
.send(
|
|
||||||
fanmode_signal
|
|
||||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
|
||||||
.append1(last_fan_mode),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|_| 0);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if config.bat_charge_limit != last_charge_limit {
|
loop {
|
||||||
last_charge_limit = config.bat_charge_limit;
|
if let Err(err) = object_server.try_handle_next() {
|
||||||
connection
|
eprintln!("{}", err);
|
||||||
.send(
|
|
||||||
charge_limit_signal
|
|
||||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
|
||||||
.append1(last_charge_limit),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|_| 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn send_boot_signals(
|
|
||||||
connection: Arc<SyncConnection>,
|
|
||||||
config: Arc<Mutex<Config>>,
|
|
||||||
fanmode_signal: Arc<Signal<()>>,
|
|
||||||
charge_limit_signal: Arc<Signal<()>>,
|
|
||||||
led_changed_signal: Arc<Signal<()>>,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
let config = config.lock().await;
|
|
||||||
|
|
||||||
if let Some(data) = config.get_led_mode_data(config.kbd_backlight_mode) {
|
|
||||||
connection
|
|
||||||
.send(
|
|
||||||
led_changed_signal
|
|
||||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
|
||||||
.append1(serde_json::to_string(data)?),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|_| 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connection
|
|
||||||
.send(
|
|
||||||
fanmode_signal
|
|
||||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
|
||||||
.append1(config.power_profile),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|_| 0);
|
|
||||||
|
|
||||||
connection
|
|
||||||
.send(
|
|
||||||
charge_limit_signal
|
|
||||||
.msg(&DBUS_PATH.into(), &DBUS_IFACE.into())
|
|
||||||
.append1(config.bat_charge_limit),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|_| 0);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,259 +0,0 @@
|
|||||||
use crate::config::Config;
|
|
||||||
use asus_nb::profile::ProfileEvent;
|
|
||||||
use asus_nb::{aura_modes::AuraModes, DBUS_IFACE, DBUS_PATH};
|
|
||||||
use dbus::tree::{Factory, MTSync, Method, MethodErr, Signal, Tree};
|
|
||||||
use log::warn;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use tokio::sync::{
|
|
||||||
mpsc::{channel, Receiver, Sender},
|
|
||||||
Mutex,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn set_keyboard_backlight(sender: Mutex<Sender<AuraModes>>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
// method for ledmessage
|
|
||||||
.method("SetKeyBacklight", (), {
|
|
||||||
move |m| {
|
|
||||||
let json: &str = m.msg.read1()?;
|
|
||||||
if let Ok(mut lock) = sender.try_lock() {
|
|
||||||
if let Ok(data) = serde_json::from_str(json) {
|
|
||||||
lock.try_send(data).unwrap_or_else(|err| {
|
|
||||||
warn!("SetKeyBacklight over mpsc failed: {}", err)
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
warn!("SetKeyBacklight could not deserialise");
|
|
||||||
}
|
|
||||||
Ok(vec![])
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock daemon for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.inarg::<&str, _>("json")
|
|
||||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_keyboard_backlight(config: Arc<Mutex<Config>>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
.method("GetKeyBacklight", (), {
|
|
||||||
move |m| {
|
|
||||||
if let Ok(lock) = config.try_lock() {
|
|
||||||
for mode in &lock.kbd_backlight_modes {
|
|
||||||
if lock.kbd_backlight_mode == <u8>::from(mode) {
|
|
||||||
let mode = serde_json::to_string(&mode).unwrap();
|
|
||||||
let mret = m.msg.method_return().append1(mode);
|
|
||||||
return Ok(vec![mret]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(MethodErr::failed(
|
|
||||||
"Keyboard LED mode set to an invalid mode",
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock config for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.outarg::<&str, _>("json")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_keyboard_backlight_modes(config: Arc<Mutex<Config>>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
.method("GetKeyBacklightModes", (), {
|
|
||||||
move |m| {
|
|
||||||
if let Ok(lock) = config.try_lock() {
|
|
||||||
let mode = serde_json::to_string(&lock.kbd_backlight_modes).unwrap();
|
|
||||||
let mret = m.msg.method_return().append1(mode);
|
|
||||||
Ok(vec![mret])
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock config for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.outarg::<&str, _>("json")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_animatrix(
|
|
||||||
sender: Mutex<Sender<Vec<Vec<u8>>>>, // need mutex only to get interior mutability in MTSync
|
|
||||||
) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
// method for ledmessage
|
|
||||||
.method("AnimatrixWrite", (), {
|
|
||||||
move |m| {
|
|
||||||
let mut iter = m.msg.iter_init();
|
|
||||||
let byte_array: Vec<Vec<u8>> = vec![iter.read()?, iter.read()?];
|
|
||||||
if let Ok(mut lock) = sender.try_lock() {
|
|
||||||
// Ignore errors if the channel is already full
|
|
||||||
lock.try_send(byte_array).unwrap_or_else(|_err| {});
|
|
||||||
Ok(vec![])
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock daemon for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.inarg::<Vec<u8>, _>("bytearray1")
|
|
||||||
.inarg::<Vec<u8>, _>("bytearray2")
|
|
||||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_fan_mode(sender: Mutex<Sender<u8>>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
// method for ledmessage
|
|
||||||
.method("SetFanMode", (), {
|
|
||||||
move |m| {
|
|
||||||
if let Ok(mut lock) = sender.try_lock() {
|
|
||||||
let mut iter = m.msg.iter_init();
|
|
||||||
let byte: u8 = iter.read()?;
|
|
||||||
lock.try_send(byte).unwrap_or_else(|_err| {});
|
|
||||||
Ok(vec![])
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock daemon for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.inarg::<u8, _>("mode")
|
|
||||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_fan_mode(config: Arc<Mutex<Config>>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
.method("GetFanMode", (), {
|
|
||||||
move |m| {
|
|
||||||
if let Ok(lock) = config.try_lock() {
|
|
||||||
let mret = m.msg.method_return().append1(lock.power_profile);
|
|
||||||
Ok(vec![mret])
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock config for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.outarg::<u8, _>("mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_charge_limit(config: Arc<Mutex<Config>>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
.method("GetChargeLimit", (), {
|
|
||||||
move |m| {
|
|
||||||
if let Ok(lock) = config.try_lock() {
|
|
||||||
let mret = m.msg.method_return().append1(lock.bat_charge_limit);
|
|
||||||
Ok(vec![mret])
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock config for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.outarg::<u8, _>("limit")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_charge_limit(sender: Mutex<Sender<u8>>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
// method for ledmessage
|
|
||||||
.method("SetChargeLimit", (), {
|
|
||||||
move |m| {
|
|
||||||
if let Ok(mut lock) = sender.try_lock() {
|
|
||||||
let mut iter = m.msg.iter_init();
|
|
||||||
let byte: u8 = iter.read()?;
|
|
||||||
lock.try_send(byte).unwrap_or_else(|_err| {});
|
|
||||||
Ok(vec![])
|
|
||||||
} else {
|
|
||||||
Err(MethodErr::failed("Could not lock daemon for access"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.inarg::<u8, _>("limit")
|
|
||||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_profile(sender: Sender<ProfileEvent>) -> Method<MTSync, ()> {
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
factory
|
|
||||||
// method for profile
|
|
||||||
.method("ProfileCommand", (), {
|
|
||||||
move |m| {
|
|
||||||
let mut iter = m.msg.iter_init();
|
|
||||||
let byte: String = iter.read()?;
|
|
||||||
if let Ok(byte) = serde_json::from_str(&byte) {
|
|
||||||
sender.clone().try_send(byte).unwrap_or_else(|_err| {});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.inarg::<String, _>("limit")
|
|
||||||
.annotate("org.freedesktop.DBus.Method.NoReply", "true")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
pub fn dbus_create_tree(
|
|
||||||
config: Arc<Mutex<Config>>,
|
|
||||||
) -> (
|
|
||||||
Tree<MTSync, ()>,
|
|
||||||
Receiver<AuraModes>,
|
|
||||||
Receiver<Vec<Vec<u8>>>,
|
|
||||||
Receiver<u8>,
|
|
||||||
Receiver<u8>,
|
|
||||||
Receiver<ProfileEvent>,
|
|
||||||
Arc<Signal<()>>,
|
|
||||||
Arc<Signal<()>>,
|
|
||||||
Arc<Signal<()>>,
|
|
||||||
) {
|
|
||||||
let (aura_command_send, aura_command_recv) = channel::<AuraModes>(1);
|
|
||||||
let (animatrix_send, animatrix_recv) = channel::<Vec<Vec<u8>>>(1);
|
|
||||||
let (fan_mode_send, fan_mode_recv) = channel::<u8>(1);
|
|
||||||
let (profile_send, profile_recv) = channel::<ProfileEvent>(1);
|
|
||||||
let (charge_send, charge_recv) = channel::<u8>(1);
|
|
||||||
|
|
||||||
let factory = Factory::new_sync::<()>();
|
|
||||||
|
|
||||||
let key_backlight_changed = Arc::new(
|
|
||||||
factory
|
|
||||||
.signal("KeyBacklightChanged", ())
|
|
||||||
.sarg::<&str, _>("json"),
|
|
||||||
);
|
|
||||||
let chrg_limit_changed = Arc::new(
|
|
||||||
factory
|
|
||||||
.signal("ChargeLimitChanged", ())
|
|
||||||
.sarg::<u8, _>("limit"),
|
|
||||||
);
|
|
||||||
let fanmode_changed = Arc::new(factory.signal("FanModeChanged", ()).sarg::<u8, _>("mode"));
|
|
||||||
|
|
||||||
let tree = factory
|
|
||||||
.tree(())
|
|
||||||
.add(
|
|
||||||
factory.object_path(DBUS_PATH, ()).introspectable().add(
|
|
||||||
factory
|
|
||||||
.interface(DBUS_IFACE, ())
|
|
||||||
.add_m(set_keyboard_backlight(Mutex::new(aura_command_send)))
|
|
||||||
.add_m(set_animatrix(Mutex::new(animatrix_send)))
|
|
||||||
.add_m(set_fan_mode(Mutex::new(fan_mode_send)))
|
|
||||||
.add_m(set_profile(profile_send))
|
|
||||||
.add_m(set_charge_limit(Mutex::new(charge_send)))
|
|
||||||
.add_m(get_fan_mode(config.clone()))
|
|
||||||
.add_m(get_charge_limit(config.clone()))
|
|
||||||
.add_m(get_keyboard_backlight(config.clone()))
|
|
||||||
.add_m(get_keyboard_backlight_modes(config))
|
|
||||||
.add_s(key_backlight_changed.clone())
|
|
||||||
.add_s(fanmode_changed.clone())
|
|
||||||
.add_s(chrg_limit_changed.clone()),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.add(factory.object_path("/", ()).introspectable());
|
|
||||||
(
|
|
||||||
tree,
|
|
||||||
aura_command_recv,
|
|
||||||
animatrix_recv,
|
|
||||||
fan_mode_recv,
|
|
||||||
charge_recv,
|
|
||||||
profile_recv,
|
|
||||||
key_backlight_changed,
|
|
||||||
fanmode_changed,
|
|
||||||
chrg_limit_changed,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,58 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::convert::From;
|
||||||
|
use intel_pstate::PStateError;
|
||||||
|
use rog_fan_curve::CurveError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RogError {
|
pub enum RogError {
|
||||||
ParseFanLevel,
|
ParseFanLevel,
|
||||||
|
ParseVendor,
|
||||||
|
ParseLED,
|
||||||
MissingProfile(String),
|
MissingProfile(String),
|
||||||
|
Udev(String, std::io::Error),
|
||||||
|
Path(String, std::io::Error),
|
||||||
|
Read(String, std::io::Error),
|
||||||
|
Write(String, std::io::Error),
|
||||||
NotSupported,
|
NotSupported,
|
||||||
|
NotFound(String),
|
||||||
|
IntelPstate(PStateError),
|
||||||
|
FanCurve(CurveError),
|
||||||
|
DoTask(String),
|
||||||
|
MissingFunction(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for RogError {}
|
|
||||||
|
|
||||||
impl fmt::Display for RogError {
|
impl fmt::Display for RogError {
|
||||||
// This trait requires `fmt` with this exact signature.
|
// This trait requires `fmt` with this exact signature.
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
RogError::ParseFanLevel => write!(f, "Parse error"),
|
RogError::ParseFanLevel => write!(f, "Parse profile error"),
|
||||||
|
RogError::ParseVendor => write!(f, "Parse gfx vendor error"),
|
||||||
|
RogError::ParseLED => write!(f, "Parse LED error"),
|
||||||
RogError::MissingProfile(profile) => write!(f, "Profile does not exist {}", profile),
|
RogError::MissingProfile(profile) => write!(f, "Profile does not exist {}", profile),
|
||||||
|
RogError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error),
|
||||||
|
RogError::Path(path, error) => write!(f, "Path {}: {}", path, error),
|
||||||
|
RogError::Read(path, error) => write!(f, "Read {}: {}", path, error),
|
||||||
|
RogError::Write(path, error) => write!(f, "Write {}: {}", path, error),
|
||||||
RogError::NotSupported => write!(f, "Not supported"),
|
RogError::NotSupported => write!(f, "Not supported"),
|
||||||
|
RogError::NotFound(deets) => write!(f, "Not found: {}", deets),
|
||||||
|
RogError::IntelPstate(err) => write!(f, "Intel pstate error: {}", err),
|
||||||
|
RogError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err),
|
||||||
|
RogError::DoTask(deets) => write!(f, "Task error: {}", deets),
|
||||||
|
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for RogError {}
|
||||||
|
|
||||||
|
impl From<PStateError> for RogError {
|
||||||
|
fn from(err: PStateError) -> Self {
|
||||||
|
RogError::IntelPstate(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CurveError> for RogError {
|
||||||
|
fn from(err: CurveError) -> Self {
|
||||||
|
RogError::FanCurve(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,36 +10,31 @@ pub mod ctrl_fan_cpu;
|
|||||||
///
|
///
|
||||||
pub mod ctrl_leds;
|
pub mod ctrl_leds;
|
||||||
///
|
///
|
||||||
pub mod dbus;
|
|
||||||
/// Laptop matching to determine capabilities
|
/// Laptop matching to determine capabilities
|
||||||
pub mod laptops;
|
pub mod laptops;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use config::Config;
|
use config::Config;
|
||||||
use std::error::Error;
|
use crate::error::RogError;
|
||||||
use std::sync::Arc;
|
use zbus::ObjectServer;
|
||||||
use tokio::sync::{mpsc::Receiver, Mutex};
|
|
||||||
use tokio::task::JoinHandle;
|
|
||||||
|
|
||||||
pub static VERSION: &str = "1.1.2";
|
pub static VERSION: &str = "2.0.0";
|
||||||
|
|
||||||
use ::dbus::{nonblock::SyncConnection, tree::Signal};
|
pub trait Reloadable {
|
||||||
|
fn reload(&mut self) -> Result<(), RogError>;
|
||||||
|
}
|
||||||
|
|
||||||
#[async_trait]
|
pub trait ZbusAdd {
|
||||||
pub trait Controller {
|
fn add_to_server(self, server: &mut ObjectServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CtrlTask {
|
||||||
|
fn do_task(&mut self) -> Result<(), RogError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CtrlTaskComplex {
|
||||||
type A;
|
type A;
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>>;
|
fn do_task(&mut self, config: &mut Config, event: Self::A);
|
||||||
|
|
||||||
/// Spawn an infinitely running task (usually) which checks a Receiver for input,
|
|
||||||
/// and may send a signal over dbus
|
|
||||||
fn spawn_task_loop(
|
|
||||||
self,
|
|
||||||
config: Arc<Mutex<Config>>,
|
|
||||||
recv: Receiver<Self::A>,
|
|
||||||
connection: Option<Arc<SyncConnection>>,
|
|
||||||
signal: Option<Arc<Signal<()>>>,
|
|
||||||
) -> Vec<JoinHandle<()>>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ use asus_nb::{
|
|||||||
core_dbus::AuraDbusClient,
|
core_dbus::AuraDbusClient,
|
||||||
profile::{ProfileCommand, ProfileEvent},
|
profile::{ProfileCommand, ProfileEvent},
|
||||||
};
|
};
|
||||||
|
use ctrl_gfx::vendors::GfxVendors;
|
||||||
use daemon::ctrl_fan_cpu::FanLevel;
|
use daemon::ctrl_fan_cpu::FanLevel;
|
||||||
use gumdrop::Options;
|
use gumdrop::Options;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
use yansi_term::Colour::Green;
|
||||||
|
use yansi_term::Colour::Red;
|
||||||
|
|
||||||
#[derive(Options)]
|
#[derive(Options)]
|
||||||
struct CLIStart {
|
struct CLIStart {
|
||||||
@@ -20,6 +23,8 @@ struct CLIStart {
|
|||||||
pwr_profile: Option<FanLevel>,
|
pwr_profile: Option<FanLevel>,
|
||||||
#[options(meta = "CHRG", help = "<20-100>")]
|
#[options(meta = "CHRG", help = "<20-100>")]
|
||||||
chg_limit: Option<u8>,
|
chg_limit: Option<u8>,
|
||||||
|
#[options(help = "Set graphics mode: <nvidia, hybrid, compute, integrated>")]
|
||||||
|
graphics: Option<GfxVendors>,
|
||||||
#[options(command)]
|
#[options(command)]
|
||||||
command: Option<Command>,
|
command: Option<Command>,
|
||||||
}
|
}
|
||||||
@@ -40,8 +45,7 @@ struct LedModeCommand {
|
|||||||
command: Option<SetAuraBuiltin>,
|
command: Option<SetAuraBuiltin>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let mut logger = env_logger::Builder::new();
|
let mut logger = env_logger::Builder::new();
|
||||||
logger
|
logger
|
||||||
.target(env_logger::Target::Stdout)
|
.target(env_logger::Target::Stdout)
|
||||||
@@ -78,5 +82,52 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
if let Some(chg_limit) = parsed.chg_limit {
|
if let Some(chg_limit) = parsed.chg_limit {
|
||||||
writer.write_charge_limit(chg_limit)?;
|
writer.write_charge_limit(chg_limit)?;
|
||||||
}
|
}
|
||||||
|
if let Some(gfx) = parsed.graphics {
|
||||||
|
println!("Updating settings, please wait...");
|
||||||
|
println!("If this takes longer than 30s, ctrl+c then check journalctl");
|
||||||
|
|
||||||
|
writer.write_gfx_mode(gfx)?;
|
||||||
|
let res = writer.wait_gfx_changed()?;
|
||||||
|
match res.as_str() {
|
||||||
|
"reboot" => println!(
|
||||||
|
"{}\n{}",
|
||||||
|
Green.paint("\nGraphics vendor mode changed successfully\n"),
|
||||||
|
Red.paint("\nPlease reboot to complete switch to iGPU\n")
|
||||||
|
),
|
||||||
|
"restartx" => {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
Green.paint("\nGraphics vendor mode changed successfully\n")
|
||||||
|
);
|
||||||
|
restart_x()?;
|
||||||
|
std::process::exit(1)
|
||||||
|
}
|
||||||
|
_ => std::process::exit(-1),
|
||||||
|
}
|
||||||
|
std::process::exit(-1)
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restart_x() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!("Restart X server? y/n");
|
||||||
|
|
||||||
|
let mut buf = String::new();
|
||||||
|
std::io::stdin().read_line(&mut buf).expect("Input failed");
|
||||||
|
let input = buf.chars().next().unwrap() as char;
|
||||||
|
|
||||||
|
if input == 'Y' || input == 'y' {
|
||||||
|
println!("Restarting X server");
|
||||||
|
let status = std::process::Command::new("systemctl")
|
||||||
|
.arg("restart")
|
||||||
|
.arg("display-manager.service")
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
println!("systemctl: display-manager returned with {}", status);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("{}", Red.paint("Cancelled. Please restart X when ready"));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "asus-nb"
|
name = "asus-nb"
|
||||||
version = "1.1.0"
|
version = "2.0.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>"]
|
||||||
@@ -17,6 +17,9 @@ serde_derive = "^1.0"
|
|||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
yansi-term = "^0.1"
|
yansi-term = "^0.1"
|
||||||
rog_fan_curve = { version = "0.1", features = ["serde"] }
|
rog_fan_curve = { version = "0.1", features = ["serde"] }
|
||||||
|
zbus = "1.1.1"
|
||||||
|
zvariant = "2.2.0"
|
||||||
|
ctrl-gfx = { path = "../ctrl-gfx" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tinybmp = "^0.2.3"
|
tinybmp = "^0.2.3"
|
||||||
@@ -93,6 +93,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
writer.write_colour_block(&colours)?;
|
writer.write_colour_block(&colours)?;
|
||||||
|
|
||||||
// can change 100 times per second, so need to slow it down
|
// can change 100 times per second, so need to slow it down
|
||||||
//std::thread::sleep(std::time::Duration::from_millis(30));
|
std::thread::sleep(std::time::Duration::from_millis(30));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::anime_matrix::AniMePacketType;
|
use crate::anime_matrix::AniMePacketType;
|
||||||
use crate::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
use crate::{DBUS_IFACE, DBUS_NAME};
|
||||||
use dbus::channel::Sender;
|
use dbus::channel::Sender;
|
||||||
use dbus::{blocking::Connection, Message};
|
use dbus::{blocking::Connection, Message};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
@@ -65,8 +65,9 @@ impl AniMeDbusWriter {
|
|||||||
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
|
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "AnimatrixWrite")?
|
let mut msg =
|
||||||
.append2(image[0].to_vec(), image[1].to_vec());
|
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Anime", DBUS_IFACE, "SetAnime")?
|
||||||
|
.append2(image[0].to_vec(), image[1].to_vec());
|
||||||
msg.set_no_reply(true);
|
msg.set_no_reply(true);
|
||||||
self.connection.send(msg).unwrap();
|
self.connection.send(msg).unwrap();
|
||||||
thread::sleep(Duration::from_millis(self.block_time));
|
thread::sleep(Duration::from_millis(self.block_time));
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub const FLASH: u8 = 0x0c;
|
|||||||
pub const MULTISTATIC: u8 = 0x0d;
|
pub const MULTISTATIC: u8 = 0x0d;
|
||||||
pub const PER_KEY: u8 = 0xff;
|
pub const PER_KEY: u8 = 0xff;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub struct Colour(pub u8, pub u8, pub u8);
|
pub struct Colour(pub u8, pub u8, pub u8);
|
||||||
impl From<cli_options::Colour> for Colour {
|
impl From<cli_options::Colour> for Colour {
|
||||||
fn from(c: cli_options::Colour) -> Self {
|
fn from(c: cli_options::Colour) -> Self {
|
||||||
@@ -30,7 +30,7 @@ impl Default for Colour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||||
pub enum Speed {
|
pub enum Speed {
|
||||||
Low = 0xe1,
|
Low = 0xe1,
|
||||||
Med = 0xeb,
|
Med = 0xeb,
|
||||||
@@ -54,7 +54,7 @@ impl Default for Speed {
|
|||||||
/// Used for Rainbow mode.
|
/// Used for Rainbow mode.
|
||||||
///
|
///
|
||||||
/// Enum corresponds to the required integer value
|
/// Enum corresponds to the required integer value
|
||||||
#[derive(Copy, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Right,
|
Right,
|
||||||
Left,
|
Left,
|
||||||
@@ -77,7 +77,7 @@ impl Default for Direction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct TwoColourSpeed {
|
pub struct TwoColourSpeed {
|
||||||
pub colour: Colour,
|
pub colour: Colour,
|
||||||
pub colour2: Colour,
|
pub colour2: Colour,
|
||||||
@@ -93,7 +93,7 @@ impl From<cli_options::TwoColourSpeed> for TwoColourSpeed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct SingleSpeed {
|
pub struct SingleSpeed {
|
||||||
pub speed: Speed,
|
pub speed: Speed,
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ impl From<cli_options::SingleSpeed> for SingleSpeed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct SingleColour {
|
pub struct SingleColour {
|
||||||
pub colour: Colour,
|
pub colour: Colour,
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ impl From<cli_options::SingleColour> for SingleColour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct MultiColour {
|
pub struct MultiColour {
|
||||||
pub colour1: Colour,
|
pub colour1: Colour,
|
||||||
pub colour2: Colour,
|
pub colour2: Colour,
|
||||||
@@ -135,7 +135,7 @@ impl From<cli_options::MultiColour> for MultiColour {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct SingleSpeedDirection {
|
pub struct SingleSpeedDirection {
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
pub speed: Speed,
|
pub speed: Speed,
|
||||||
@@ -149,7 +149,7 @@ impl From<cli_options::SingleSpeedDirection> for SingleSpeedDirection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
pub struct SingleColourSpeed {
|
pub struct SingleColourSpeed {
|
||||||
pub colour: Colour,
|
pub colour: Colour,
|
||||||
pub speed: Speed,
|
pub speed: Speed,
|
||||||
@@ -163,7 +163,7 @@ impl From<cli_options::SingleColourSpeed> for SingleColourSpeed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub enum AuraModes {
|
pub enum AuraModes {
|
||||||
Static(SingleColour),
|
Static(SingleColour),
|
||||||
Breathe(TwoColourSpeed),
|
Breathe(TwoColourSpeed),
|
||||||
|
|||||||
@@ -1,53 +1,169 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::fancy::KeyColourArray;
|
use crate::fancy::KeyColourArray;
|
||||||
use crate::profile::ProfileEvent;
|
use crate::profile::ProfileEvent;
|
||||||
|
use ctrl_gfx::vendors::GfxVendors;
|
||||||
use dbus::channel::Sender;
|
use dbus::channel::Sender;
|
||||||
use dbus::{blocking::Connection, channel::Token, Message};
|
use dbus::{blocking::Connection, Message};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc,
|
Arc, Mutex,
|
||||||
};
|
};
|
||||||
use std::{thread, time::Duration};
|
use std::{thread, time::Duration};
|
||||||
|
|
||||||
|
use crate::dbus_gfx::OrgAsuslinuxDaemonNotifyGfx;
|
||||||
|
use crate::dbus_ledmode::OrgAsuslinuxDaemonNotifyLed;
|
||||||
|
use crate::dbus_profile::OrgAsuslinuxDaemonNotifyProfile;
|
||||||
|
use crate::dbus_charge::OrgAsuslinuxDaemonNotifyCharge;
|
||||||
|
|
||||||
|
// Signals separated out
|
||||||
|
pub struct CtrlSignals {
|
||||||
|
pub gfx_signal: Arc<Mutex<Option<String>>>,
|
||||||
|
pub profile_signal: Arc<Mutex<Option<String>>>,
|
||||||
|
pub ledmode_signal: Arc<Mutex<Option<AuraModes>>>,
|
||||||
|
pub charge_signal: Arc<Mutex<Option<u8>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlSignals {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(connection: &Connection) -> Result<Self, Box<dyn Error>> {
|
||||||
|
let proxy = connection.with_proxy(
|
||||||
|
"org.asuslinux.Daemon",
|
||||||
|
"/org/asuslinux/Gfx",
|
||||||
|
Duration::from_millis(5000),
|
||||||
|
);
|
||||||
|
|
||||||
|
let gfx_signal = Arc::new(Mutex::new(None));
|
||||||
|
let gfx_res1 = gfx_signal.clone();
|
||||||
|
|
||||||
|
let _x = proxy.match_signal(
|
||||||
|
move |sig: OrgAsuslinuxDaemonNotifyGfx, _: &Connection, _: &Message| {
|
||||||
|
if let Ok(mut lock) = gfx_res1.lock() {
|
||||||
|
*lock = Some(sig.vendor);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
//
|
||||||
|
let proxy = connection.with_proxy(
|
||||||
|
"org.asuslinux.Daemon",
|
||||||
|
"/org/asuslinux/Profile",
|
||||||
|
Duration::from_millis(5000),
|
||||||
|
);
|
||||||
|
|
||||||
|
let profile_signal = Arc::new(Mutex::new(None));
|
||||||
|
let prof_res1 = profile_signal.clone();
|
||||||
|
|
||||||
|
let _x = proxy.match_signal(
|
||||||
|
move |sig: OrgAsuslinuxDaemonNotifyProfile, _: &Connection, _: &Message| {
|
||||||
|
if let Ok(mut lock) = prof_res1.lock() {
|
||||||
|
*lock = Some(sig.profile);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
//
|
||||||
|
let proxy = connection.with_proxy(
|
||||||
|
"org.asuslinux.Daemon",
|
||||||
|
"/org/asuslinux/Led",
|
||||||
|
Duration::from_millis(5000),
|
||||||
|
);
|
||||||
|
|
||||||
|
let ledmode_signal = Arc::new(Mutex::new(None));
|
||||||
|
let led_res1 = ledmode_signal.clone();
|
||||||
|
|
||||||
|
let _x = proxy.match_signal(
|
||||||
|
move |sig: OrgAsuslinuxDaemonNotifyLed, _: &Connection, _: &Message| {
|
||||||
|
if let Ok(mut lock) = led_res1.lock() {
|
||||||
|
if let Ok(dat) = serde_json::from_str(&sig.data) {
|
||||||
|
*lock = Some(dat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
//
|
||||||
|
let proxy = connection.with_proxy(
|
||||||
|
"org.asuslinux.Daemon",
|
||||||
|
"/org/asuslinux/Charge",
|
||||||
|
Duration::from_millis(5000),
|
||||||
|
);
|
||||||
|
|
||||||
|
let charge_signal = Arc::new(Mutex::new(None));
|
||||||
|
let charge_res1 = charge_signal.clone();
|
||||||
|
|
||||||
|
let _x = proxy.match_signal(
|
||||||
|
move |sig: OrgAsuslinuxDaemonNotifyCharge, _: &Connection, _: &Message| {
|
||||||
|
if let Ok(mut lock) = charge_res1.lock() {
|
||||||
|
*lock = Some(sig.limit);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(CtrlSignals {
|
||||||
|
gfx_signal,
|
||||||
|
profile_signal,
|
||||||
|
ledmode_signal,
|
||||||
|
charge_signal,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Simplified way to write a effect block
|
/// Simplified way to write a effect block
|
||||||
pub struct AuraDbusClient {
|
pub struct AuraDbusClient {
|
||||||
connection: Box<Connection>,
|
connection: Box<Connection>,
|
||||||
block_time: u64,
|
block_time: u64,
|
||||||
stop: Arc<AtomicBool>,
|
stop: Arc<AtomicBool>,
|
||||||
stop_token: Token,
|
signals: CtrlSignals,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuraDbusClient {
|
impl AuraDbusClient {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
pub fn new() -> Result<Self, Box<dyn Error>> {
|
||||||
let connection = Connection::new_system()?;
|
let connection = Connection::new_system()?;
|
||||||
let stop = Arc::new(AtomicBool::new(false));
|
|
||||||
|
|
||||||
let stopper2 = stop.clone();
|
let stop = Arc::new(AtomicBool::new(false));
|
||||||
let match_rule = dbus::message::MatchRule::new_signal(DBUS_IFACE, "KeyBacklightChanged");
|
let match_rule = dbus::message::MatchRule::new_signal(DBUS_IFACE, "NotifyLed");
|
||||||
let stop_token = connection.add_match(match_rule, move |_: (), _, msg| {
|
let stop1 = stop.clone();
|
||||||
|
connection.add_match(match_rule, move |_: (), _, msg| {
|
||||||
if msg.read1::<&str>().is_ok() {
|
if msg.read1::<&str>().is_ok() {
|
||||||
stopper2.store(true, Ordering::Relaxed);
|
stop1.clone().store(true, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let signals = CtrlSignals::new(&connection)?;
|
||||||
|
|
||||||
Ok(AuraDbusClient {
|
Ok(AuraDbusClient {
|
||||||
connection: Box::new(connection),
|
connection: Box::new(connection),
|
||||||
block_time: 33333,
|
block_time: 33333,
|
||||||
stop,
|
stop,
|
||||||
stop_token,
|
signals,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn wait_gfx_changed(&self) -> Result<String, Box<dyn Error>> {
|
||||||
|
loop {
|
||||||
|
self.connection.process(Duration::from_micros(500))?;
|
||||||
|
if let Ok(lock) = self.signals.gfx_signal.lock() {
|
||||||
|
if let Some(stuff) = lock.as_ref() {
|
||||||
|
return Ok(stuff.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This method must always be called before the very first write to initialise
|
/// This method must always be called before the very first write to initialise
|
||||||
/// the keyboard LED EC in the correct mode
|
/// the keyboard LED EC in the correct mode
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn init_effect(&self) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn init_effect(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mode = AuraModes::PerKey(vec![vec![]]);
|
let mode = AuraModes::PerKey(vec![vec![]]);
|
||||||
let mut msg =
|
let mut msg =
|
||||||
Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetKeyBacklight")?
|
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
|
||||||
.append1(serde_json::to_string(&mode)?);
|
.append1(serde_json::to_string(&mode)?);
|
||||||
msg.set_no_reply(true);
|
msg.set_no_reply(true);
|
||||||
self.connection.send(msg).unwrap();
|
self.connection.send(msg).unwrap();
|
||||||
@@ -70,14 +186,13 @@ impl AuraDbusClient {
|
|||||||
}
|
}
|
||||||
let mode = AuraModes::PerKey(vecs);
|
let mode = AuraModes::PerKey(vecs);
|
||||||
let mut msg =
|
let mut msg =
|
||||||
Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetKeyBacklight")?
|
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
|
||||||
.append1(serde_json::to_string(&mode)?);
|
.append1(serde_json::to_string(&mode)?);
|
||||||
msg.set_no_reply(true);
|
msg.set_no_reply(true);
|
||||||
self.connection.send(msg).unwrap();
|
self.connection.send(msg).unwrap();
|
||||||
thread::sleep(Duration::from_micros(self.block_time));
|
thread::sleep(Duration::from_micros(self.block_time));
|
||||||
self.connection.process(Duration::from_micros(500))?;
|
self.connection.process(Duration::from_micros(500))?;
|
||||||
if self.stop.load(Ordering::Relaxed) {
|
if self.stop.load(Ordering::Relaxed) {
|
||||||
self.connection.remove_match(self.stop_token)?;
|
|
||||||
println!("Keyboard backlight was changed, exiting");
|
println!("Keyboard backlight was changed, exiting");
|
||||||
std::process::exit(1)
|
std::process::exit(1)
|
||||||
}
|
}
|
||||||
@@ -87,7 +202,7 @@ impl AuraDbusClient {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn write_keyboard_leds(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn write_keyboard_leds(&self, mode: &AuraModes) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut msg =
|
let mut msg =
|
||||||
Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetKeyBacklight")?
|
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Led", DBUS_IFACE, "SetLedMode")?
|
||||||
.append1(serde_json::to_string(mode)?);
|
.append1(serde_json::to_string(mode)?);
|
||||||
msg.set_no_reply(true);
|
msg.set_no_reply(true);
|
||||||
self.connection.send(msg).unwrap();
|
self.connection.send(msg).unwrap();
|
||||||
@@ -96,8 +211,23 @@ impl AuraDbusClient {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn write_fan_mode(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn write_fan_mode(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ProfileCommand")?
|
let mut msg = Message::new_method_call(
|
||||||
.append1(serde_json::to_string(&ProfileEvent::ChangeMode(level))?);
|
DBUS_NAME,
|
||||||
|
"/org/asuslinux/Profile",
|
||||||
|
DBUS_IFACE,
|
||||||
|
"SetProfile",
|
||||||
|
)?
|
||||||
|
.append1(serde_json::to_string(&ProfileEvent::ChangeMode(level))?);
|
||||||
|
msg.set_no_reply(true);
|
||||||
|
self.connection.send(msg).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn write_gfx_mode(&self, vendor: GfxVendors) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut msg =
|
||||||
|
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Gfx", DBUS_IFACE, "SetVendor")?
|
||||||
|
.append1(<&str>::from(&vendor));
|
||||||
msg.set_no_reply(true);
|
msg.set_no_reply(true);
|
||||||
self.connection.send(msg).unwrap();
|
self.connection.send(msg).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -108,8 +238,13 @@ impl AuraDbusClient {
|
|||||||
&self,
|
&self,
|
||||||
cmd: &ProfileEvent,
|
cmd: &ProfileEvent,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ProfileCommand")?
|
let mut msg = Message::new_method_call(
|
||||||
.append1(serde_json::to_string(cmd)?);
|
DBUS_NAME,
|
||||||
|
"/org/asuslinux/Profile",
|
||||||
|
DBUS_IFACE,
|
||||||
|
"SetProfile",
|
||||||
|
)?
|
||||||
|
.append1(serde_json::to_string(cmd)?);
|
||||||
msg.set_no_reply(true);
|
msg.set_no_reply(true);
|
||||||
self.connection.send(msg).unwrap();
|
self.connection.send(msg).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -117,8 +252,9 @@ impl AuraDbusClient {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn write_charge_limit(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn write_charge_limit(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "SetChargeLimit")?
|
let mut msg =
|
||||||
.append1(level);
|
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Charge", DBUS_IFACE, "SetLimit")?
|
||||||
|
.append1(level);
|
||||||
msg.set_no_reply(true);
|
msg.set_no_reply(true);
|
||||||
self.connection.send(msg).unwrap();
|
self.connection.send(msg).unwrap();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
46
asus-nb/src/dbus_charge.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Charge -m None`, see https://github.com/diwic/dbus-rs
|
||||||
|
use dbus as dbus;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use dbus::arg;
|
||||||
|
use dbus::blocking;
|
||||||
|
|
||||||
|
pub trait OrgAsuslinuxDaemon {
|
||||||
|
fn set_limit(&self, limit: u8) -> Result<(), dbus::Error>;
|
||||||
|
fn limit(&self) -> Result<i16, dbus::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
|
||||||
|
|
||||||
|
fn set_limit(&self, limit: u8) -> Result<(), dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "SetLimit", (limit, ))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn limit(&self) -> Result<i16, dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "Limit", ())
|
||||||
|
.and_then(|r: (i16, )| Ok(r.0, ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OrgAsuslinuxDaemonNotifyCharge {
|
||||||
|
pub limit: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyCharge {
|
||||||
|
fn append(&self, i: &mut arg::IterAppend) {
|
||||||
|
arg::RefArg::append(&self.limit, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyCharge {
|
||||||
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
|
Ok(OrgAsuslinuxDaemonNotifyCharge {
|
||||||
|
limit: i.read()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyCharge {
|
||||||
|
const NAME: &'static str = "NotifyCharge";
|
||||||
|
const INTERFACE: &'static str = "org.asuslinux.Daemon";
|
||||||
|
}
|
||||||
39
asus-nb/src/dbus_gfx.rs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Gfx -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
|
||||||
|
use dbus;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use dbus::arg;
|
||||||
|
use dbus::blocking;
|
||||||
|
|
||||||
|
pub trait OrgAsuslinuxDaemon {
|
||||||
|
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
|
||||||
|
for blocking::Proxy<'a, C>
|
||||||
|
{
|
||||||
|
fn set_vendor(&self, vendor: &str) -> Result<(), dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "SetVendor", (vendor,))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OrgAsuslinuxDaemonNotifyGfx {
|
||||||
|
pub vendor: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyGfx {
|
||||||
|
fn append(&self, i: &mut arg::IterAppend) {
|
||||||
|
arg::RefArg::append(&self.vendor, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyGfx {
|
||||||
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
|
Ok(OrgAsuslinuxDaemonNotifyGfx { vendor: i.read()? })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyGfx {
|
||||||
|
const NAME: &'static str = "NotifyGfx";
|
||||||
|
const INTERFACE: &'static str = "org.asuslinux.Daemon";
|
||||||
|
}
|
||||||
52
asus-nb/src/dbus_ledmode.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Led -m None`, see https://github.com/diwic/dbus-rs
|
||||||
|
use dbus as dbus;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use dbus::arg;
|
||||||
|
use dbus::blocking;
|
||||||
|
|
||||||
|
pub trait OrgAsuslinuxDaemon {
|
||||||
|
fn set_led_mode(&self, data: &str) -> Result<(), dbus::Error>;
|
||||||
|
fn led_mode(&self) -> Result<String, dbus::Error>;
|
||||||
|
fn led_modes(&self) -> Result<String, dbus::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
|
||||||
|
|
||||||
|
fn set_led_mode(&self, data: &str) -> Result<(), dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "SetLedMode", (data, ))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn led_mode(&self) -> Result<String, dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "LedMode", ())
|
||||||
|
.and_then(|r: (String, )| Ok(r.0, ))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn led_modes(&self) -> Result<String, dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "LedModes", ())
|
||||||
|
.and_then(|r: (String, )| Ok(r.0, ))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OrgAsuslinuxDaemonNotifyLed {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyLed {
|
||||||
|
fn append(&self, i: &mut arg::IterAppend) {
|
||||||
|
arg::RefArg::append(&self.data, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyLed {
|
||||||
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
|
Ok(OrgAsuslinuxDaemonNotifyLed {
|
||||||
|
data: i.read()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyLed {
|
||||||
|
const NAME: &'static str = "NotifyLed";
|
||||||
|
const INTERFACE: &'static str = "org.asuslinux.Daemon";
|
||||||
|
}
|
||||||
51
asus-nb/src/dbus_profile.rs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Profile -m None`, see https://github.com/diwic/dbus-rs
|
||||||
|
use dbus;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use dbus::arg;
|
||||||
|
use dbus::blocking;
|
||||||
|
|
||||||
|
pub trait OrgAsuslinuxDaemon {
|
||||||
|
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error>;
|
||||||
|
fn profile(&self) -> Result<String, dbus::Error>;
|
||||||
|
fn profiles(&self) -> Result<String, dbus::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
|
||||||
|
for blocking::Proxy<'a, C>
|
||||||
|
{
|
||||||
|
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "SetProfile", (profile,))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn profile(&self) -> Result<String, dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "Profile", ())
|
||||||
|
.and_then(|r: (String,)| Ok(r.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn profiles(&self) -> Result<String, dbus::Error> {
|
||||||
|
self.method_call("org.asuslinux.Daemon", "Profiles", ())
|
||||||
|
.and_then(|r: (String,)| Ok(r.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct OrgAsuslinuxDaemonNotifyProfile {
|
||||||
|
pub profile: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::AppendAll for OrgAsuslinuxDaemonNotifyProfile {
|
||||||
|
fn append(&self, i: &mut arg::IterAppend) {
|
||||||
|
arg::RefArg::append(&self.profile, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyProfile {
|
||||||
|
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
|
||||||
|
Ok(OrgAsuslinuxDaemonNotifyProfile { profile: i.read()? })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dbus::message::SignalArgs for OrgAsuslinuxDaemonNotifyProfile {
|
||||||
|
const NAME: &'static str = "NotifyProfile";
|
||||||
|
const INTERFACE: &'static str = "org.asuslinux.Daemon";
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum AuraError {
|
pub enum AuraError {
|
||||||
ParseColour,
|
ParseColour,
|
||||||
ParseSpeed,
|
ParseSpeed,
|
||||||
@@ -18,3 +20,21 @@ impl fmt::Display for AuraError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error for AuraError {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GraphicsError {
|
||||||
|
ParseVendor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GraphicsError {
|
||||||
|
// This trait requires `fmt` with this exact signature.
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
GraphicsError::ParseVendor => write!(f, "Could not parse vendor name"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for GraphicsError {}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ pub mod anime_dbus;
|
|||||||
/// Helper functions for the AniMe display
|
/// Helper functions for the AniMe display
|
||||||
pub mod anime_matrix;
|
pub mod anime_matrix;
|
||||||
|
|
||||||
|
pub mod dbus_gfx;
|
||||||
|
pub mod dbus_ledmode;
|
||||||
|
pub mod dbus_profile;
|
||||||
|
pub mod dbus_charge;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
// static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
// static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use std::str::FromStr;
|
|||||||
pub enum ProfileEvent {
|
pub enum ProfileEvent {
|
||||||
Cli(ProfileCommand),
|
Cli(ProfileCommand),
|
||||||
ChangeMode(u8),
|
ChangeMode(u8),
|
||||||
|
Toggle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
17
asus-notify/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "asus-notify"
|
||||||
|
version = "1.0.0"
|
||||||
|
authors = ["Luke D Jones <luke@ljones.dev>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# serialisation
|
||||||
|
serde = "^1.0"
|
||||||
|
serde_derive = "^1.0"
|
||||||
|
serde_json = "^1.0"
|
||||||
|
notify-rust = "^4.0.0"
|
||||||
|
dbus = { version = "^0.8" }
|
||||||
|
asus-nb = { path = "../asus-nb" }
|
||||||
|
asus-nb-ctrl = { path = "../asus-nb-ctrl" }
|
||||||
101
asus-notify/src/main.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
use asus_nb::core_dbus::CtrlSignals;
|
||||||
|
use daemon::config::{Config, Profile};
|
||||||
|
use dbus::blocking::Connection;
|
||||||
|
use notify_rust::{Hint, Notification, NotificationHandle};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut cfg = Config::read_new()?;
|
||||||
|
let mut last_profile = String::new();
|
||||||
|
|
||||||
|
let connection = Connection::new_system()?;
|
||||||
|
let signals = CtrlSignals::new(&connection)?;
|
||||||
|
|
||||||
|
let mut last_profile_notif: Option<NotificationHandle> = None;
|
||||||
|
let mut last_led_notif: Option<NotificationHandle> = None;
|
||||||
|
let mut last_gfx_notif: Option<NotificationHandle> = None;
|
||||||
|
let mut last_chrg_notif: Option<NotificationHandle> = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
std::thread::sleep(Duration::from_millis(100));
|
||||||
|
connection.process(std::time::Duration::from_millis(200))?;
|
||||||
|
|
||||||
|
if let Ok(mut lock) = signals.gfx_signal.lock() {
|
||||||
|
if let Some(vendor) = lock.take() {
|
||||||
|
if let Some(notif) = last_gfx_notif.take() {
|
||||||
|
notif.close();
|
||||||
|
}
|
||||||
|
let x = do_notif(&format!("Graphics mode changed to {}", vendor))?;
|
||||||
|
last_gfx_notif = Some(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(mut lock) = signals.charge_signal.lock() {
|
||||||
|
if let Some(limit) = lock.take() {
|
||||||
|
if let Some(notif) = last_chrg_notif.take() {
|
||||||
|
notif.close();
|
||||||
|
}
|
||||||
|
let x = do_notif(&format!("Battery charge limit changed to {}", limit))?;
|
||||||
|
last_led_notif = Some(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(mut lock) = signals.ledmode_signal.lock() {
|
||||||
|
if let Some(ledmode) = lock.take() {
|
||||||
|
if let Some(notif) = last_led_notif.take() {
|
||||||
|
notif.close();
|
||||||
|
}
|
||||||
|
let x = do_notif(&format!(
|
||||||
|
"Keyboard LED mode changed to {}",
|
||||||
|
<&str>::from(&ledmode)
|
||||||
|
))?;
|
||||||
|
last_led_notif = Some(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to do the config read because of a limitation preventing
|
||||||
|
// easy dbus notification from the profile controller
|
||||||
|
cfg.read();
|
||||||
|
if last_profile != cfg.active_profile {
|
||||||
|
if let Some(notif) = last_profile_notif.take() {
|
||||||
|
notif.close();
|
||||||
|
}
|
||||||
|
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
|
||||||
|
let x = do_thermal_notif(&profile, &cfg.active_profile)?;
|
||||||
|
last_profile_notif = Some(x);
|
||||||
|
last_profile = cfg.active_profile.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_thermal_notif(profile: &Profile, label: &str) -> Result<NotificationHandle, Box<dyn Error>> {
|
||||||
|
let fan = profile.fan_preset;
|
||||||
|
let turbo = if profile.turbo { "enabled" } else { "disabled" };
|
||||||
|
let icon = match fan {
|
||||||
|
0 => "asus_notif_yellow",
|
||||||
|
1 => "asus_notif_red",
|
||||||
|
2 => "asus_notif_green",
|
||||||
|
_ => "asus_notif_red",
|
||||||
|
};
|
||||||
|
let x = Notification::new()
|
||||||
|
.summary("ASUS ROG")
|
||||||
|
.body(&format!("Thermal profile changed to {}, turbo {}", label.to_uppercase(), turbo))
|
||||||
|
.hint(Hint::Resident(true))
|
||||||
|
.timeout(2000)
|
||||||
|
.hint(Hint::Category("device".into()))
|
||||||
|
//.hint(Hint::Transient(true))
|
||||||
|
.icon(icon)
|
||||||
|
.show()?;
|
||||||
|
Ok(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_notif(body: &str) -> Result<NotificationHandle, Box<dyn Error>> {
|
||||||
|
let x = Notification::new()
|
||||||
|
.summary("ASUS ROG")
|
||||||
|
.body(body)
|
||||||
|
.timeout(2000)
|
||||||
|
.show()?;
|
||||||
|
Ok(x)
|
||||||
|
}
|
||||||
19
ctrl-gfx/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "ctrl-gfx"
|
||||||
|
version = "2.0.0"
|
||||||
|
license = "MPL-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
authors = ["Luke <luke@ljones.dev>"]
|
||||||
|
description = "Fine control of laptop GPU"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sysfs-class = "^0.1.2"
|
||||||
|
log = "^0.4"
|
||||||
|
|
||||||
|
zbus = { version = "1.1.1", optional = true }
|
||||||
|
zvariant = { version = "2.2.0", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["use-zbus"]
|
||||||
|
use-zbus = ["zbus", "zvariant"]
|
||||||
335
ctrl-gfx/src/ctrl_gfx.rs
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
use log::{error, info, warn};
|
||||||
|
use std::error::Error;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::Command;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use sysfs_class::{PciDevice, SysClass};
|
||||||
|
use zbus::dbus_interface;
|
||||||
|
|
||||||
|
use crate::vendors::*;
|
||||||
|
use crate::*;
|
||||||
|
use crate::{error::GfxError, system::*};
|
||||||
|
|
||||||
|
pub struct CtrlGraphics {
|
||||||
|
bus: PciBus,
|
||||||
|
amd: Vec<GraphicsDevice>,
|
||||||
|
intel: Vec<GraphicsDevice>,
|
||||||
|
nvidia: Vec<GraphicsDevice>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
other: Vec<GraphicsDevice>,
|
||||||
|
initfs_cmd: Option<Command>,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Dbus {
|
||||||
|
fn set_vendor(&mut self, vendor: String);
|
||||||
|
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-zbus")]
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
#[cfg(feature = "use-zbus")]
|
||||||
|
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||||
|
impl Dbus for CtrlGraphics {
|
||||||
|
fn set_vendor(&mut self, vendor: String) {
|
||||||
|
if let Ok(tmp) = GfxVendors::from_str(&vendor) {
|
||||||
|
self.set(tmp).unwrap_or_else(|err| {
|
||||||
|
warn!("{}", err);
|
||||||
|
format!("Failed: {}", err.to_string())
|
||||||
|
});
|
||||||
|
self.notify_gfx(&vendor)
|
||||||
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[dbus_interface(signal)]
|
||||||
|
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CtrlGraphics {
|
||||||
|
pub fn new() -> std::io::Result<CtrlGraphics> {
|
||||||
|
let bus = PciBus::new()?;
|
||||||
|
|
||||||
|
info!("Rescanning PCI bus");
|
||||||
|
bus.rescan()?;
|
||||||
|
|
||||||
|
let devs = PciDevice::all()?;
|
||||||
|
|
||||||
|
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
|
||||||
|
let mut functions = Vec::new();
|
||||||
|
if let Some(parent_slot) = parent.id().split('.').next() {
|
||||||
|
for func in devs.iter() {
|
||||||
|
if let Some(func_slot) = func.id().split('.').next() {
|
||||||
|
if func_slot == parent_slot {
|
||||||
|
info!("{}: Function for {}", func.id(), parent.id());
|
||||||
|
functions.push(func.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
functions
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut amd = Vec::new();
|
||||||
|
let mut intel = Vec::new();
|
||||||
|
let mut nvidia = Vec::new();
|
||||||
|
let mut other = Vec::new();
|
||||||
|
for dev in devs.iter() {
|
||||||
|
let c = dev.class()?;
|
||||||
|
if 0x03 == (c >> 16) & 0xFF {
|
||||||
|
match dev.vendor()? {
|
||||||
|
0x1002 => {
|
||||||
|
info!("{}: AMD graphics", dev.id());
|
||||||
|
amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
|
}
|
||||||
|
0x10DE => {
|
||||||
|
info!("{}: NVIDIA graphics", dev.id());
|
||||||
|
nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
|
}
|
||||||
|
0x8086 => {
|
||||||
|
info!("{}: Intel graphics", dev.id());
|
||||||
|
intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
|
}
|
||||||
|
vendor => {
|
||||||
|
info!("{}: Other({:X}) graphics", dev.id(), vendor);
|
||||||
|
other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut initfs_cmd = None;
|
||||||
|
|
||||||
|
if Path::new(INITRAMFS_PATH).exists() {
|
||||||
|
let mut cmd = Command::new("update-initramfs");
|
||||||
|
cmd.arg("-u");
|
||||||
|
initfs_cmd = Some(cmd);
|
||||||
|
info!("Using initramfs update command 'update-initramfs'");
|
||||||
|
} else if Path::new(DRACUT_PATH).exists() {
|
||||||
|
let mut cmd = Command::new("dracut");
|
||||||
|
cmd.arg("-f");
|
||||||
|
initfs_cmd = Some(cmd);
|
||||||
|
info!("Using initramfs update command 'dracut'");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(CtrlGraphics {
|
||||||
|
bus,
|
||||||
|
amd,
|
||||||
|
intel,
|
||||||
|
nvidia,
|
||||||
|
other,
|
||||||
|
initfs_cmd,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "use-zbus")]
|
||||||
|
pub fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||||
|
server
|
||||||
|
.at(&"/org/asuslinux/Gfx".try_into().unwrap(), self)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reload(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
|
self.auto_power()?;
|
||||||
|
info!("Reloaded gfx mode: {:?}", CtrlGraphics::get_vendor()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_switch(&self) -> bool {
|
||||||
|
!self.nvidia.is_empty() && (!self.intel.is_empty() || !self.amd.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_prime_discrete() -> Result<String, GfxError> {
|
||||||
|
let s = std::fs::read_to_string(PRIME_DISCRETE_PATH)
|
||||||
|
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?
|
||||||
|
.trim()
|
||||||
|
.to_owned();
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_prime_discrete(mode: &str) -> Result<(), GfxError> {
|
||||||
|
std::fs::write(PRIME_DISCRETE_PATH, mode)
|
||||||
|
.map_err(|err| GfxError::Read(PRIME_DISCRETE_PATH.into(), err))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Associated method to get which vendor mode is set
|
||||||
|
pub fn get_vendor() -> Result<String, GfxError> {
|
||||||
|
let modules = Module::all().map_err(|err| GfxError::Read("get_vendor".into(), err))?;
|
||||||
|
let vendor = if modules
|
||||||
|
.iter()
|
||||||
|
.any(|module| module.name == "nouveau" || module.name == "nvidia")
|
||||||
|
{
|
||||||
|
let mode = match Self::get_prime_discrete() {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(_) => "nvidia".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if mode == "on-demand" {
|
||||||
|
"hybrid".to_string()
|
||||||
|
} else if mode == "off" {
|
||||||
|
"compute".to_string()
|
||||||
|
} else {
|
||||||
|
"nvidia".to_string()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"integrated".to_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(vendor)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_switching_prime_modes(vendor: &GfxVendors) -> Result<bool, GfxError> {
|
||||||
|
let prev_mode = GfxVendors::from_str(&Self::get_vendor()?)?;
|
||||||
|
let x = (prev_mode == GfxVendors::Hybrid || prev_mode == GfxVendors::Nvidia)
|
||||||
|
&& (*vendor == GfxVendors::Hybrid || *vendor == GfxVendors::Nvidia);
|
||||||
|
Ok(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write out config files if required, enable/disable relevant services, and update the ramdisk
|
||||||
|
pub fn set(&mut self, vendor: GfxVendors) -> Result<String, GfxError> {
|
||||||
|
//self.switchable_or_fail()?;
|
||||||
|
|
||||||
|
let mode = if vendor == GfxVendors::Hybrid {
|
||||||
|
"on-demand\n"
|
||||||
|
} else if vendor == GfxVendors::Nvidia {
|
||||||
|
"on\n"
|
||||||
|
} else {
|
||||||
|
// Integrated or Compute
|
||||||
|
"off\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("Setting {} to {}", PRIME_DISCRETE_PATH, mode);
|
||||||
|
Self::set_prime_discrete(mode)?;
|
||||||
|
|
||||||
|
// Switching from hybrid to/from nvidia shouldn't require a ramdisk update
|
||||||
|
// or a reboot.
|
||||||
|
let switching_prime_modes = Self::is_switching_prime_modes(&vendor)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
info!("Creating {}", MODPROBE_PATH);
|
||||||
|
|
||||||
|
let mut file = std::fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.write(true)
|
||||||
|
.open(MODPROBE_PATH)
|
||||||
|
.map_err(|err| GfxError::Path(MODPROBE_PATH.into(), err))?;
|
||||||
|
|
||||||
|
let text = if vendor == GfxVendors::Hybrid {
|
||||||
|
MODPROBE_HYBRID
|
||||||
|
} else if vendor == GfxVendors::Compute {
|
||||||
|
MODPROBE_COMPUTE
|
||||||
|
} else if vendor == GfxVendors::Nvidia {
|
||||||
|
MODPROBE_NVIDIA
|
||||||
|
} else {
|
||||||
|
MODPROBE_INTEGRATED
|
||||||
|
};
|
||||||
|
|
||||||
|
file.write_all(text)
|
||||||
|
.and_then(|_| file.sync_all())
|
||||||
|
.map_err(|err| GfxError::Write(MODPROBE_PATH.into(), err))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Creating {}", PRIMARY_GPU_XORG_PATH);
|
||||||
|
|
||||||
|
// begin section for non-separated Nvidia xorg modules
|
||||||
|
// eg, not put in their own directory
|
||||||
|
let mut file = std::fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.write(true)
|
||||||
|
.open(PRIMARY_GPU_XORG_PATH)
|
||||||
|
.map_err(|err| GfxError::Write(PRIMARY_GPU_XORG_PATH.into(), err))?;
|
||||||
|
|
||||||
|
let text = if vendor == GfxVendors::Nvidia {
|
||||||
|
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
|
||||||
|
} else {
|
||||||
|
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_END].concat()
|
||||||
|
};
|
||||||
|
|
||||||
|
file.write_all(&text)
|
||||||
|
.and_then(|_| file.sync_all())
|
||||||
|
.map_err(|err| GfxError::Write(MODPROBE_PATH.into(), err))?;
|
||||||
|
|
||||||
|
let action = if vendor == GfxVendors::Nvidia {
|
||||||
|
info!("Enabling nvidia-fallback.service");
|
||||||
|
"enable"
|
||||||
|
} else {
|
||||||
|
info!("Disabling nvidia-fallback.service");
|
||||||
|
"disable"
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = Command::new("systemctl")
|
||||||
|
.arg(action)
|
||||||
|
.arg("nvidia-fallback.service")
|
||||||
|
.status()
|
||||||
|
.map_err(|err| GfxError::Command("systemctl".into(), err))?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
// Error is ignored in case this service is removed
|
||||||
|
warn!(
|
||||||
|
"systemctl: {} (ignore warning if service does not exist!)",
|
||||||
|
status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut required_action = GfxCtrlAction::None;
|
||||||
|
if !switching_prime_modes {
|
||||||
|
info!("Updating initramfs");
|
||||||
|
if let Some(cmd) = self.initfs_cmd.as_mut() {
|
||||||
|
let status = cmd
|
||||||
|
.status()
|
||||||
|
.map_err(|err| GfxError::Write(format!("{:?}", cmd), err))?;
|
||||||
|
if !status.success() {
|
||||||
|
error!("Ram disk update failed");
|
||||||
|
} else {
|
||||||
|
info!("Successfully updated iniramfs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
required_action = GfxCtrlAction::Reboot;
|
||||||
|
} else if switching_prime_modes {
|
||||||
|
required_action = GfxCtrlAction::RestartX;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(required_action.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_power(&self) -> Option<bool> {
|
||||||
|
if self.can_switch() {
|
||||||
|
return Some(self.nvidia.iter().any(GraphicsDevice::exists));
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_power(&self, power: bool) -> Result<(), GfxError> {
|
||||||
|
// self.switchable_or_fail()?;
|
||||||
|
|
||||||
|
if power {
|
||||||
|
info!("Enabling graphics power");
|
||||||
|
self.bus
|
||||||
|
.rescan()
|
||||||
|
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?;
|
||||||
|
} else {
|
||||||
|
info!("Disabling graphics power");
|
||||||
|
|
||||||
|
// Unbind NVIDIA graphics devices and their functions
|
||||||
|
let unbinds = self.nvidia.iter().map(|dev| dev.unbind());
|
||||||
|
|
||||||
|
// Remove NVIDIA graphics devices and their functions
|
||||||
|
let removes = self.nvidia.iter().map(|dev| dev.remove());
|
||||||
|
|
||||||
|
Result::from_iter(unbinds.chain(removes))
|
||||||
|
.map_err(|err| GfxError::Command("device unbind error".into(), err))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn auto_power(&self) -> Result<(), GfxError> {
|
||||||
|
let vendor = CtrlGraphics::get_vendor()?;
|
||||||
|
self.set_power(vendor != "integrated")
|
||||||
|
}
|
||||||
|
}
|
||||||
30
ctrl-gfx/src/error.rs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
use std::error;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GfxError {
|
||||||
|
ParseVendor,
|
||||||
|
Path(String, std::io::Error),
|
||||||
|
Read(String, std::io::Error),
|
||||||
|
Write(String, std::io::Error),
|
||||||
|
Module(String, std::io::Error),
|
||||||
|
Bus(String, std::io::Error),
|
||||||
|
Command(String, std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GfxError {
|
||||||
|
// This trait requires `fmt` with this exact signature.
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
|
||||||
|
GfxError::Path(path, error) => write!(f, "Path {}: {}", path, error),
|
||||||
|
GfxError::Read(path, error) => write!(f, "Read {}: {}", path, error),
|
||||||
|
GfxError::Write(path, error) => write!(f, "Write {}: {}", path, error),
|
||||||
|
GfxError::Module(func, error) => write!(f, "Module error: {}: {}", func, error),
|
||||||
|
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
|
||||||
|
GfxError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for GfxError {}
|
||||||
58
ctrl-gfx/src/lib.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
pub mod vendors;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
|
||||||
|
pub mod ctrl_gfx;
|
||||||
|
|
||||||
|
pub mod system;
|
||||||
|
|
||||||
|
const PRIME_DISCRETE_PATH: &str = "/etc/prime-discrete";
|
||||||
|
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
|
||||||
|
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
|
||||||
|
const DRACUT_PATH: &str = "/usr/bin/dracut";
|
||||||
|
|
||||||
|
static MODPROBE_NVIDIA: &[u8] = MODPROBE_HYBRID;
|
||||||
|
|
||||||
|
static MODPROBE_HYBRID: &[u8] = br#"# Automatically generated by asusd
|
||||||
|
blacklist i2c_nvidia_gpu
|
||||||
|
alias i2c_nvidia_gpu off
|
||||||
|
options nvidia NVreg_DynamicPowerManagement=0x02
|
||||||
|
options nvidia-drm modeset=1
|
||||||
|
"#;
|
||||||
|
|
||||||
|
static MODPROBE_COMPUTE: &[u8] = br#"# Automatically generated by asusd
|
||||||
|
blacklist i2c_nvidia_gpu
|
||||||
|
alias i2c_nvidia_gpu off
|
||||||
|
options nvidia NVreg_DynamicPowerManagement=0x02
|
||||||
|
options nvidia-drm modeset=0
|
||||||
|
"#;
|
||||||
|
|
||||||
|
static MODPROBE_INTEGRATED: &[u8] = br#"# Automatically generated by asusd
|
||||||
|
blacklist i2c_nvidia_gpu
|
||||||
|
blacklist nouveau
|
||||||
|
blacklist nvidia
|
||||||
|
blacklist nvidia-drm
|
||||||
|
blacklist nvidia-modeset
|
||||||
|
alias i2c_nvidia_gpu off
|
||||||
|
alias nouveau off
|
||||||
|
alias nvidia off
|
||||||
|
alias nvidia-drm off
|
||||||
|
alias nvidia-modeset off
|
||||||
|
"#;
|
||||||
|
|
||||||
|
const PRIMARY_GPU_XORG_PATH: &str = "/etc/X11/xorg.conf.d/90-nvidia-primary.conf";
|
||||||
|
|
||||||
|
static PRIMARY_GPU_BEGIN: &[u8] = br#"# Automatically generated by asusd
|
||||||
|
Section "OutputClass"
|
||||||
|
Identifier "nvidia"
|
||||||
|
MatchDriver "nvidia-drm"
|
||||||
|
Driver "nvidia"
|
||||||
|
Option "TripleBuffer" "true"
|
||||||
|
Option "AllowEmptyInitialConfiguration"
|
||||||
|
Option "AllowExternalGpus""#;
|
||||||
|
|
||||||
|
static PRIMARY_GPU_NVIDIA: &[u8] = br#"
|
||||||
|
Option "PrimaryGPU" "true""#;
|
||||||
|
|
||||||
|
static PRIMARY_GPU_END: &[u8] = br#"
|
||||||
|
EndSection"#;
|
||||||
127
ctrl-gfx/src/system.rs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
use log::{error, info, warn};
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
use std::{fs::write, io, path::PathBuf};
|
||||||
|
use sysfs_class::{PciDevice, SysClass};
|
||||||
|
|
||||||
|
pub struct Module {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
fn parse(line: &str) -> io::Result<Module> {
|
||||||
|
let mut parts = line.split(' ');
|
||||||
|
|
||||||
|
let name = parts
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "module name not found"))?;
|
||||||
|
|
||||||
|
Ok(Module {
|
||||||
|
name: name.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn all() -> io::Result<Vec<Module>> {
|
||||||
|
let mut modules = Vec::new();
|
||||||
|
|
||||||
|
let data = read_to_string("/proc/modules")?;
|
||||||
|
for line in data.lines() {
|
||||||
|
let module = Module::parse(line)?;
|
||||||
|
modules.push(module);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(modules)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PciBus {
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PciBus {
|
||||||
|
pub fn new() -> io::Result<PciBus> {
|
||||||
|
let path = PathBuf::from("/sys/bus/pci");
|
||||||
|
if path.is_dir() {
|
||||||
|
Ok(PciBus { path })
|
||||||
|
} else {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::NotFound,
|
||||||
|
"pci directory not found",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rescan(&self) -> io::Result<()> {
|
||||||
|
write(self.path.join("rescan"), "1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GraphicsDevice {
|
||||||
|
id: String,
|
||||||
|
functions: Vec<PciDevice>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GraphicsDevice {
|
||||||
|
pub fn new(id: String, functions: Vec<PciDevice>) -> GraphicsDevice {
|
||||||
|
GraphicsDevice { id, functions }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exists(&self) -> bool {
|
||||||
|
self.functions.iter().any(|func| func.path().exists())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unbind(&self) -> Result<(), std::io::Error> {
|
||||||
|
for func in self.functions.iter() {
|
||||||
|
if func.path().exists() {
|
||||||
|
match func.driver() {
|
||||||
|
Ok(driver) => {
|
||||||
|
info!("{}: Unbinding {}", driver.id(), func.id());
|
||||||
|
unsafe {
|
||||||
|
driver.unbind(&func).map_err(|err| {
|
||||||
|
error!("gfx unbind: {}", err);
|
||||||
|
err
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => match err.kind() {
|
||||||
|
io::ErrorKind::NotFound => (),
|
||||||
|
_ => {
|
||||||
|
error!("gfx driver: {:?}, {}", func.path(), err);
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&self) -> Result<(), std::io::Error> {
|
||||||
|
for func in self.functions.iter() {
|
||||||
|
if func.path().exists() {
|
||||||
|
match func.driver() {
|
||||||
|
Ok(driver) => {
|
||||||
|
error!("{}: in use by {}", func.id(), driver.id());
|
||||||
|
}
|
||||||
|
Err(why) => match why.kind() {
|
||||||
|
std::io::ErrorKind::NotFound => {
|
||||||
|
info!("{}: Removing", func.id());
|
||||||
|
unsafe {
|
||||||
|
// ignore errors and carry on
|
||||||
|
if let Err(err) = func.remove() {
|
||||||
|
error!("gfx remove: {}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error!("Remove device failed");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!("{}: Already removed", func.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info!("Remmoved all gfx devices");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
85
ctrl-gfx/src/vendors.rs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum GfxVendors {
|
||||||
|
Nvidia,
|
||||||
|
Integrated,
|
||||||
|
Compute,
|
||||||
|
Hybrid,
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::error::GfxError;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
impl FromStr for GfxVendors {
|
||||||
|
type Err = GfxError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, GfxError> {
|
||||||
|
match s.to_lowercase().as_str() {
|
||||||
|
"nvidia" => Ok(GfxVendors::Nvidia),
|
||||||
|
"hybrid" => Ok(GfxVendors::Hybrid),
|
||||||
|
"compute" => Ok(GfxVendors::Compute),
|
||||||
|
"integrated" => Ok(GfxVendors::Integrated),
|
||||||
|
"nvidia\n" => Ok(GfxVendors::Nvidia),
|
||||||
|
"hybrid\n" => Ok(GfxVendors::Hybrid),
|
||||||
|
"compute\n" => Ok(GfxVendors::Compute),
|
||||||
|
"integrated\n" => Ok(GfxVendors::Integrated),
|
||||||
|
_ => Err(GfxError::ParseVendor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&GfxVendors> for &str {
|
||||||
|
fn from(mode: &GfxVendors) -> Self {
|
||||||
|
match mode {
|
||||||
|
GfxVendors::Nvidia => "nvidia",
|
||||||
|
GfxVendors::Hybrid => "hybrid",
|
||||||
|
GfxVendors::Compute => "compute",
|
||||||
|
GfxVendors::Integrated => "integrated",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum GfxCtrlAction {
|
||||||
|
Reboot,
|
||||||
|
RestartX,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for GfxCtrlAction {
|
||||||
|
type Err = GfxError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, GfxError> {
|
||||||
|
match s.to_lowercase().as_str() {
|
||||||
|
"reboot" => Ok(GfxCtrlAction::Reboot),
|
||||||
|
"restartx" => Ok(GfxCtrlAction::RestartX),
|
||||||
|
"none" => Ok(GfxCtrlAction::None),
|
||||||
|
_ => Err(GfxError::ParseVendor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&GfxCtrlAction> for &str {
|
||||||
|
fn from(mode: &GfxCtrlAction) -> Self {
|
||||||
|
match mode {
|
||||||
|
GfxCtrlAction::Reboot => "reboot",
|
||||||
|
GfxCtrlAction::RestartX => "restartx",
|
||||||
|
GfxCtrlAction::None => "none",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&GfxCtrlAction> for String {
|
||||||
|
fn from(mode: &GfxCtrlAction) -> Self {
|
||||||
|
match mode {
|
||||||
|
GfxCtrlAction::Reboot => "reboot".into(),
|
||||||
|
GfxCtrlAction::RestartX => "restartx".into(),
|
||||||
|
GfxCtrlAction::None => "none".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<GfxCtrlAction> for String {
|
||||||
|
fn from(mode: GfxCtrlAction) -> Self {
|
||||||
|
(&mode).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
7
data/90-nvidia-pm.rules
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
|
||||||
|
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
|
||||||
|
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
|
||||||
|
|
||||||
|
# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
|
||||||
|
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
|
||||||
|
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"
|
||||||
5
data/90-nvidia-screen-G05.conf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Section "ServerLayout"
|
||||||
|
Identifier "layout"
|
||||||
|
Option "AllowNVIDIAGPUScreens"
|
||||||
|
Option "metamodes" "nvidia-auto-select +0+0 {AllowGSYNC=On, AllowGSYNCCompatible=On}"
|
||||||
|
EndSection
|
||||||
14
data/asus-notify.service
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=ASUS Notifications
|
||||||
|
StartLimitInterval=200
|
||||||
|
StartLimitBurst=2
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/asus-notify
|
||||||
|
Restart=on-failure
|
||||||
|
Restart=always
|
||||||
|
RestartSec=1
|
||||||
|
Type=simple
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
BIN
data/icons/asus_notif_blue.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
BIN
data/icons/asus_notif_green.png
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
data/icons/asus_notif_orange.png
Normal file
|
After Width: | Height: | Size: 203 KiB |
BIN
data/icons/asus_notif_red.png
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
data/icons/asus_notif_white.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
data/icons/asus_notif_yellow.png
Normal file
|
After Width: | Height: | Size: 197 KiB |
@@ -1,338 +0,0 @@
|
|||||||
From 61e7ffe80b12db8ebb6033cfe2b70cccaefc07e1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Luke D Jones <luke@ljones.dev>
|
|
||||||
Date: Sat, 1 Aug 2020 20:33:28 +1200
|
|
||||||
Subject: [PATCH] HID: asus: add support for ASUS N-Key keyboard
|
|
||||||
|
|
||||||
Enable missing functionality of the keyboard found in many ASUS
|
|
||||||
Zephyrus laptops: Fn key combos and hotkeys, keyboard backlight
|
|
||||||
brightness control, and notify asus-wmi to toggle "fan-mode".
|
|
||||||
Two input event codes are added for keyboard LED mode switching
|
|
||||||
prev/next.
|
|
||||||
|
|
||||||
The keyboard has many of the same key outputs as the existing G752
|
|
||||||
keyboard including a few extras, and varies a little between laptop
|
|
||||||
models.
|
|
||||||
|
|
||||||
Additionally the keyboard requires the LED interface to be
|
|
||||||
intitialised before such things as keyboard backlight control work.
|
|
||||||
|
|
||||||
Misc changes in scope: update some hardcoded comparisons to use an
|
|
||||||
available define, change "Mic Toggle" to use a keycode that works.
|
|
||||||
|
|
||||||
Signed-off-by: Luke D Jones <luke@ljones.dev>
|
|
||||||
---
|
|
||||||
drivers/hid/hid-asus.c | 164 ++++++++++++++++++---
|
|
||||||
drivers/hid/hid-ids.h | 1 +
|
|
||||||
include/linux/platform_data/x86/asus-wmi.h | 2 +
|
|
||||||
include/uapi/linux/input-event-codes.h | 7 +
|
|
||||||
4 files changed, 152 insertions(+), 22 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
|
|
||||||
index e6e4c841fb06..fa9928672110 100644
|
|
||||||
--- a/drivers/hid/hid-asus.c
|
|
||||||
+++ b/drivers/hid/hid-asus.c
|
|
||||||
@@ -26,10 +26,12 @@
|
|
||||||
#include <linux/dmi.h>
|
|
||||||
#include <linux/hid.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
+#include <linux/acpi.h>
|
|
||||||
#include <linux/platform_data/x86/asus-wmi.h>
|
|
||||||
#include <linux/input/mt.h>
|
|
||||||
#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
|
|
||||||
#include <linux/power_supply.h>
|
|
||||||
+#include <../drivers/platform/x86/asus-wmi.h>
|
|
||||||
|
|
||||||
#include "hid-ids.h"
|
|
||||||
|
|
||||||
@@ -46,6 +48,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
|
||||||
#define INPUT_REPORT_ID 0x5d
|
|
||||||
#define FEATURE_KBD_REPORT_ID 0x5a
|
|
||||||
#define FEATURE_KBD_REPORT_SIZE 16
|
|
||||||
+#define FEATURE_KBD_LED_REPORT_ID1 0x5d
|
|
||||||
+#define FEATURE_KBD_LED_REPORT_ID2 0x5e
|
|
||||||
|
|
||||||
#define SUPPORT_KBD_BACKLIGHT BIT(0)
|
|
||||||
|
|
||||||
@@ -77,6 +81,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
|
||||||
#define QUIRK_G752_KEYBOARD BIT(8)
|
|
||||||
#define QUIRK_T101HA_DOCK BIT(9)
|
|
||||||
#define QUIRK_T90CHI BIT(10)
|
|
||||||
+#define QUIRK_ROG_NKEY_KEYBOARD BIT(12)
|
|
||||||
|
|
||||||
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
|
|
||||||
QUIRK_NO_INIT_REPORTS | \
|
|
||||||
@@ -257,10 +262,33 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * This enables triggering events in asus-wmi
|
|
||||||
+*/
|
|
||||||
+static int asus_wmi_send_event(struct asus_drvdata *drvdat, u8 code)
|
|
||||||
+{
|
|
||||||
+ int err;
|
|
||||||
+ u32 retval;
|
|
||||||
+
|
|
||||||
+ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS,
|
|
||||||
+ ASUS_WMI_METHODID_NOTIF, code, &retval);
|
|
||||||
+ if (err) {
|
|
||||||
+ pr_warn("Failed to notify asus-wmi: %d\n", err);
|
|
||||||
+ return err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (retval != 0) {
|
|
||||||
+ pr_warn("Failed to notify asus-wmi (retval): 0x%x\n", retval);
|
|
||||||
+ return -EIO;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int asus_event(struct hid_device *hdev, struct hid_field *field,
|
|
||||||
struct hid_usage *usage, __s32 value)
|
|
||||||
{
|
|
||||||
- if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
|
|
||||||
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR &&
|
|
||||||
(usage->hid & HID_USAGE) != 0x00 &&
|
|
||||||
(usage->hid & HID_USAGE) != 0xff && !usage->type) {
|
|
||||||
hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
|
|
||||||
@@ -281,6 +309,20 @@ static int asus_raw_event(struct hid_device *hdev,
|
|
||||||
if (drvdata->tp && data[0] == INPUT_REPORT_ID)
|
|
||||||
return asus_report_input(drvdata, data, size);
|
|
||||||
|
|
||||||
+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
|
||||||
+ /*
|
|
||||||
+ * Skip these report ID, the device emits a continuous stream associated
|
|
||||||
+ * with the AURA mode it is in
|
|
||||||
+ */
|
|
||||||
+ if (report->id == FEATURE_KBD_LED_REPORT_ID1 ||
|
|
||||||
+ report->id == FEATURE_KBD_LED_REPORT_ID2) {
|
|
||||||
+ return -1;
|
|
||||||
+ /* Fn+F5 "fan" symbol, trigger WMI event to toggle next mode */
|
|
||||||
+ } else if (report->id == FEATURE_KBD_REPORT_ID && data[1] == 0xae) {
|
|
||||||
+ return asus_wmi_send_event(drvdata, 0xae);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -293,7 +335,9 @@ static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size
|
|
||||||
if (!dmabuf)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
- ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf,
|
|
||||||
+ // The report ID should be set from the incoming buffer due to LED and key
|
|
||||||
+ // interfaces having different pages
|
|
||||||
+ ret = hid_hw_raw_request(hdev, buf[0], dmabuf,
|
|
||||||
buf_size, HID_FEATURE_REPORT,
|
|
||||||
HID_REQ_SET_REPORT);
|
|
||||||
kfree(dmabuf);
|
|
||||||
@@ -346,6 +390,44 @@ static int asus_kbd_get_functions(struct hid_device *hdev,
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int asus_kbd_led_init(struct hid_device *hdev)
|
|
||||||
+{
|
|
||||||
+ u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 };
|
|
||||||
+ u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20,
|
|
||||||
+ 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
|
|
||||||
+ u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1,
|
|
||||||
+ 0x05, 0x20, 0x31, 0x00, 0x08 };
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ hid_warn(hdev, "Asus initialise N-KEY Device");
|
|
||||||
+ /* The first message is an init start */
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init start command: %d\n", ret);
|
|
||||||
+ /* Followed by a string */
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 1.0: %d\n", ret);
|
|
||||||
+ /* Followed by a string */
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 1.1: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ /* begin second report ID with same data */
|
|
||||||
+ buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2;
|
|
||||||
+ buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2;
|
|
||||||
+
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 2.0: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 2.1: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
|
|
||||||
enum led_brightness brightness)
|
|
||||||
{
|
|
||||||
@@ -409,19 +491,28 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
|
|
||||||
unsigned char kbd_func;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
- /* Initialize keyboard */
|
|
||||||
- ret = asus_kbd_init(hdev);
|
|
||||||
- if (ret < 0)
|
|
||||||
- return ret;
|
|
||||||
+ if (drvdata->quirks & QUIRK_G752_KEYBOARD) {
|
|
||||||
+ /* Initialize keyboard */
|
|
||||||
+ ret = asus_kbd_init(hdev);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
|
|
||||||
- /* Get keyboard functions */
|
|
||||||
- ret = asus_kbd_get_functions(hdev, &kbd_func);
|
|
||||||
- if (ret < 0)
|
|
||||||
- return ret;
|
|
||||||
+ /* Get keyboard functions */
|
|
||||||
+ ret = asus_kbd_get_functions(hdev, &kbd_func);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
|
|
||||||
- /* Check for backlight support */
|
|
||||||
- if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
|
|
||||||
- return -ENODEV;
|
|
||||||
+ /* Check for backlight support */
|
|
||||||
+ if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
|
|
||||||
+ return -ENODEV;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
|
||||||
+ /* Initialize keyboard LED interface and Vendor keys on 0x1866 */
|
|
||||||
+ ret = asus_kbd_led_init(hdev);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
|
|
||||||
sizeof(struct asus_kbd_leds),
|
|
||||||
@@ -693,14 +784,14 @@ static int asus_input_mapping(struct hid_device *hdev,
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ASUS-specific keyboard hotkeys */
|
|
||||||
- if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
|
|
||||||
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) {
|
|
||||||
set_bit(EV_REP, hi->input->evbit);
|
|
||||||
switch (usage->hid & HID_USAGE) {
|
|
||||||
case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
|
|
||||||
case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
|
|
||||||
case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break;
|
|
||||||
case 0x6c: asus_map_key_clear(KEY_SLEEP); break;
|
|
||||||
- case 0x7c: asus_map_key_clear(KEY_MICMUTE); break;
|
|
||||||
+ case 0x7c: asus_map_key_clear(KEY_F20); break;
|
|
||||||
case 0x82: asus_map_key_clear(KEY_CAMERA); break;
|
|
||||||
case 0x88: asus_map_key_clear(KEY_RFKILL); break;
|
|
||||||
case 0xb5: asus_map_key_clear(KEY_CALC); break;
|
|
||||||
@@ -713,16 +804,42 @@ static int asus_input_mapping(struct hid_device *hdev,
|
|
||||||
/* ROG key */
|
|
||||||
case 0x38: asus_map_key_clear(KEY_PROG1); break;
|
|
||||||
|
|
||||||
- /* Fn+C ASUS Splendid */
|
|
||||||
- case 0xba: asus_map_key_clear(KEY_PROG2); break;
|
|
||||||
+ default:
|
|
||||||
+ if (drvdata->quirks & QUIRK_G752_KEYBOARD) {
|
|
||||||
+ switch (usage->hid & HID_USAGE) {
|
|
||||||
+ /* Fn+C ASUS Splendid */
|
|
||||||
+ case 0xba: asus_map_key_clear(KEY_PROG2); break;
|
|
||||||
|
|
||||||
- /* Fn+Space Power4Gear Hybrid */
|
|
||||||
- case 0x5c: asus_map_key_clear(KEY_PROG3); break;
|
|
||||||
+ /* Fn+Space Power4Gear Hybrid */
|
|
||||||
+ case 0x5c: asus_map_key_clear(KEY_PROG3); break;
|
|
||||||
|
|
||||||
- /* Fn+F5 "fan" symbol on FX503VD */
|
|
||||||
- case 0x99: asus_map_key_clear(KEY_PROG4); break;
|
|
||||||
+ /* Fn+F5 "fan" symbol on FX503VD */
|
|
||||||
+ case 0x99: asus_map_key_clear(KEY_PROG4); break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* device 0x1866, N-KEY Device specific */
|
|
||||||
+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
|
||||||
+ switch (usage->hid & HID_USAGE) {
|
|
||||||
+ /* Fn+Ret "Calc" symbol on device 0x1866, N-KEY Device */
|
|
||||||
+ case 0x92: asus_map_key_clear(KEY_CALC); break;
|
|
||||||
+
|
|
||||||
+ /* Fn+Left Aura mode previous */
|
|
||||||
+ case 0xb2: asus_map_key_clear(KEY_KBDILLUM_MODE_PREV); break;
|
|
||||||
+
|
|
||||||
+ /* Fn+Right Aura mode next */
|
|
||||||
+ case 0xb3: asus_map_key_clear(KEY_KBDILLUM_MODE_NEXT); break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- default:
|
|
||||||
/* ASUS lazily declares 256 usages, ignore the rest,
|
|
||||||
* as some make the keyboard appear as a pointer device. */
|
|
||||||
return -1;
|
|
||||||
@@ -1043,6 +1160,9 @@ static const struct hid_device_id asus_devices[] = {
|
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
|
||||||
USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD),
|
|
||||||
QUIRK_USE_KBD_BACKLIGHT },
|
|
||||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
|
||||||
+ USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD),
|
|
||||||
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
|
||||||
USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
|
|
||||||
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
|
|
||||||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
|
||||||
index 1c71a1aa76b2..42c2ca3832e0 100644
|
|
||||||
--- a/drivers/hid/hid-ids.h
|
|
||||||
+++ b/drivers/hid/hid-ids.h
|
|
||||||
@@ -193,6 +193,7 @@
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822
|
|
||||||
+#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
|
|
||||||
|
|
||||||
#define USB_VENDOR_ID_ATEN 0x0557
|
|
||||||
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
index d39fc658c320..10fca778ff9c 100644
|
|
||||||
--- a/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
+++ b/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
@@ -27,6 +27,8 @@
|
|
||||||
#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */
|
|
||||||
#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */
|
|
||||||
|
|
||||||
+#define ASUS_WMI_METHODID_NOTIF 0x00100021 /* Notify method ?? */
|
|
||||||
+
|
|
||||||
#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
|
|
||||||
|
|
||||||
/* Wireless */
|
|
||||||
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
|
|
||||||
index b6a835d37826..928abcf020d5 100644
|
|
||||||
--- a/include/uapi/linux/input-event-codes.h
|
|
||||||
+++ b/include/uapi/linux/input-event-codes.h
|
|
||||||
@@ -772,6 +772,13 @@
|
|
||||||
#define BTN_TRIGGER_HAPPY39 0x2e6
|
|
||||||
#define BTN_TRIGGER_HAPPY40 0x2e7
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Some keyboards have function keys associated with
|
|
||||||
+ * changing the keyboard backlight modes, e.g, RGB patterns
|
|
||||||
+ */
|
|
||||||
+#define KEY_KBDILLUM_MODE_PREV 0x2ea
|
|
||||||
+#define KEY_KBDILLUM_MODE_NEXT 0x2eb
|
|
||||||
+
|
|
||||||
/* We avoid low common keys in module aliases so they don't get huge. */
|
|
||||||
#define KEY_MIN_INTERESTING KEY_MUTE
|
|
||||||
#define KEY_MAX 0x2ff
|
|
||||||
--
|
|
||||||
2.26.2
|
|
||||||
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
From 2b70c3daf1bd92f9163efb726e37fb3e0bcc8989 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Luke D Jones <luke@ljones.dev>
|
|
||||||
Date: Thu, 30 Jul 2020 16:51:06 +1200
|
|
||||||
Subject: [PATCH] HID: asus: add support for ASUS N-Key keyboard
|
|
||||||
|
|
||||||
Enable missing functionality of the keyboard found in many ASUS
|
|
||||||
Zephyrus laptops: Fn key combos and hotkeys, keyboard backlight
|
|
||||||
brightness control, and notify asus-wmi to toggle "fan-mode".
|
|
||||||
Two input event codes are added for keyboard LED mode switching
|
|
||||||
prev/next.
|
|
||||||
|
|
||||||
The keyboard has many of the same key outputs as the existing G752
|
|
||||||
keyboard including a few extras, and varies a little between laptop
|
|
||||||
models.
|
|
||||||
|
|
||||||
Additionally the keyboard requires the LED interface to be
|
|
||||||
intitialised before such things as keyboard backlight control work.
|
|
||||||
|
|
||||||
Misc changes in scope: update some hardcoded comparisons to use an
|
|
||||||
available define, change "Mic Toggle" to use a keycode that works.
|
|
||||||
|
|
||||||
Signed-off-by: Luke D Jones <luke@ljones.dev>
|
|
||||||
---
|
|
||||||
drivers/hid/hid-asus.c | 166 ++++++++++++++++++---
|
|
||||||
drivers/hid/hid-ids.h | 1 +
|
|
||||||
include/linux/platform_data/x86/asus-wmi.h | 2 +
|
|
||||||
include/uapi/linux/input-event-codes.h | 7 +
|
|
||||||
4 files changed, 153 insertions(+), 23 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
|
|
||||||
index c183caf89d49..5dfca90cd616 100644
|
|
||||||
--- a/drivers/hid/hid-asus.c
|
|
||||||
+++ b/drivers/hid/hid-asus.c
|
|
||||||
@@ -26,10 +26,12 @@
|
|
||||||
#include <linux/dmi.h>
|
|
||||||
#include <linux/hid.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
+#include <linux/acpi.h>
|
|
||||||
#include <linux/platform_data/x86/asus-wmi.h>
|
|
||||||
#include <linux/input/mt.h>
|
|
||||||
#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
|
|
||||||
#include <linux/power_supply.h>
|
|
||||||
+#include <../drivers/platform/x86/asus-wmi.h>
|
|
||||||
|
|
||||||
#include "hid-ids.h"
|
|
||||||
|
|
||||||
@@ -48,6 +50,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
|
||||||
#define INPUT_REPORT_ID 0x5d
|
|
||||||
#define FEATURE_KBD_REPORT_ID 0x5a
|
|
||||||
#define FEATURE_KBD_REPORT_SIZE 16
|
|
||||||
+#define FEATURE_KBD_LED_REPORT_ID1 0x5d
|
|
||||||
+#define FEATURE_KBD_LED_REPORT_ID2 0x5e
|
|
||||||
|
|
||||||
#define SUPPORT_KBD_BACKLIGHT BIT(0)
|
|
||||||
|
|
||||||
@@ -80,6 +84,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
|
|
||||||
#define QUIRK_T101HA_DOCK BIT(9)
|
|
||||||
#define QUIRK_T90CHI BIT(10)
|
|
||||||
#define QUIRK_MEDION_E1239T BIT(11)
|
|
||||||
+#define QUIRK_ROG_NKEY_KEYBOARD BIT(12)
|
|
||||||
|
|
||||||
#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
|
|
||||||
QUIRK_NO_INIT_REPORTS | \
|
|
||||||
@@ -305,10 +310,33 @@ static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * This enables triggering events in asus-wmi
|
|
||||||
+ */
|
|
||||||
+static int asus_wmi_send_event(struct asus_drvdata *drvdat, u8 code)
|
|
||||||
+{
|
|
||||||
+ int err;
|
|
||||||
+ u32 retval;
|
|
||||||
+
|
|
||||||
+ err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS,
|
|
||||||
+ ASUS_WMI_METHODID_NOTIF, code, &retval);
|
|
||||||
+ if (err) {
|
|
||||||
+ pr_warn("Failed to notify asus-wmi: %d\n", err);
|
|
||||||
+ return err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (retval != 0) {
|
|
||||||
+ pr_warn("Failed to notify asus-wmi (retval): 0x%x\n", retval);
|
|
||||||
+ return -EIO;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int asus_event(struct hid_device *hdev, struct hid_field *field,
|
|
||||||
struct hid_usage *usage, __s32 value)
|
|
||||||
{
|
|
||||||
- if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
|
|
||||||
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR &&
|
|
||||||
(usage->hid & HID_USAGE) != 0x00 &&
|
|
||||||
(usage->hid & HID_USAGE) != 0xff && !usage->type) {
|
|
||||||
hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
|
|
||||||
@@ -332,6 +360,20 @@ static int asus_raw_event(struct hid_device *hdev,
|
|
||||||
if (drvdata->quirks & QUIRK_MEDION_E1239T)
|
|
||||||
return asus_e1239t_event(drvdata, data, size);
|
|
||||||
|
|
||||||
+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
|
||||||
+ /*
|
|
||||||
+ * Skip these report ID, the device emits a continuous stream associated
|
|
||||||
+ * with the AURA mode it is in
|
|
||||||
+ */
|
|
||||||
+ if (report->id == FEATURE_KBD_LED_REPORT_ID1 ||
|
|
||||||
+ report->id == FEATURE_KBD_LED_REPORT_ID2) {
|
|
||||||
+ return -1;
|
|
||||||
+ /* Fn+F5 "fan" symbol, trigger WMI event to toggle next mode */
|
|
||||||
+ } else if (report->id == FEATURE_KBD_REPORT_ID && data[1] == 0xae) {
|
|
||||||
+ return asus_wmi_send_event(drvdata, 0xae);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -344,7 +386,9 @@ static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size
|
|
||||||
if (!dmabuf)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
- ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf,
|
|
||||||
+ // The report ID should be set from the incoming buffer due to LED and key
|
|
||||||
+ // interfaces having different pages
|
|
||||||
+ ret = hid_hw_raw_request(hdev, buf[0], dmabuf,
|
|
||||||
buf_size, HID_FEATURE_REPORT,
|
|
||||||
HID_REQ_SET_REPORT);
|
|
||||||
kfree(dmabuf);
|
|
||||||
@@ -397,6 +441,44 @@ static int asus_kbd_get_functions(struct hid_device *hdev,
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int asus_kbd_led_init(struct hid_device *hdev)
|
|
||||||
+{
|
|
||||||
+ u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 };
|
|
||||||
+ u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20,
|
|
||||||
+ 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
|
|
||||||
+ u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1,
|
|
||||||
+ 0x05, 0x20, 0x31, 0x00, 0x08 };
|
|
||||||
+ int ret;
|
|
||||||
+
|
|
||||||
+ hid_warn(hdev, "Asus initialise N-KEY Device");
|
|
||||||
+ /* The first message is an init start */
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init start command: %d\n", ret);
|
|
||||||
+ /* Followed by a string */
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 1.0: %d\n", ret);
|
|
||||||
+ /* Followed by a string */
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 1.1: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ /* begin second report ID with same data */
|
|
||||||
+ buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2;
|
|
||||||
+ buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2;
|
|
||||||
+
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 2.0: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ hid_err(hdev, "Asus failed to send init command 2.1: %d\n", ret);
|
|
||||||
+
|
|
||||||
+ return ret;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
|
|
||||||
enum led_brightness brightness)
|
|
||||||
{
|
|
||||||
@@ -460,19 +542,28 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
|
|
||||||
unsigned char kbd_func;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
- /* Initialize keyboard */
|
|
||||||
- ret = asus_kbd_init(hdev);
|
|
||||||
- if (ret < 0)
|
|
||||||
- return ret;
|
|
||||||
+ if (drvdata->quirks & QUIRK_G752_KEYBOARD) {
|
|
||||||
+ /* Initialize keyboard */
|
|
||||||
+ ret = asus_kbd_init(hdev);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
|
|
||||||
- /* Get keyboard functions */
|
|
||||||
- ret = asus_kbd_get_functions(hdev, &kbd_func);
|
|
||||||
- if (ret < 0)
|
|
||||||
- return ret;
|
|
||||||
+ /* Get keyboard functions */
|
|
||||||
+ ret = asus_kbd_get_functions(hdev, &kbd_func);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
|
|
||||||
- /* Check for backlight support */
|
|
||||||
- if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
|
|
||||||
- return -ENODEV;
|
|
||||||
+ /* Check for backlight support */
|
|
||||||
+ if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
|
|
||||||
+ return -ENODEV;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
|
||||||
+ /* Initialize keyboard LED interface and Vendor keys on 0x1866 */
|
|
||||||
+ ret = asus_kbd_led_init(hdev);
|
|
||||||
+ if (ret < 0)
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
|
|
||||||
sizeof(struct asus_kbd_leds),
|
|
||||||
@@ -751,14 +842,14 @@ static int asus_input_mapping(struct hid_device *hdev,
|
|
||||||
usage->hid == (HID_UP_GENDEVCTRLS | 0x0026)))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
- /* ASUS-specific keyboard hotkeys */
|
|
||||||
- if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) {
|
|
||||||
+ /* ASUS-specific keyboard hotkeys and led backlight */
|
|
||||||
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) {
|
|
||||||
switch (usage->hid & HID_USAGE) {
|
|
||||||
case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
|
|
||||||
case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
|
|
||||||
case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break;
|
|
||||||
case 0x6c: asus_map_key_clear(KEY_SLEEP); break;
|
|
||||||
- case 0x7c: asus_map_key_clear(KEY_MICMUTE); break;
|
|
||||||
+ case 0x7c: asus_map_key_clear(KEY_F20); break;
|
|
||||||
case 0x82: asus_map_key_clear(KEY_CAMERA); break;
|
|
||||||
case 0x88: asus_map_key_clear(KEY_RFKILL); break;
|
|
||||||
case 0xb5: asus_map_key_clear(KEY_CALC); break;
|
|
||||||
@@ -771,16 +862,42 @@ static int asus_input_mapping(struct hid_device *hdev,
|
|
||||||
/* ROG key */
|
|
||||||
case 0x38: asus_map_key_clear(KEY_PROG1); break;
|
|
||||||
|
|
||||||
- /* Fn+C ASUS Splendid */
|
|
||||||
- case 0xba: asus_map_key_clear(KEY_PROG2); break;
|
|
||||||
+ default:
|
|
||||||
+ if (drvdata->quirks & QUIRK_G752_KEYBOARD) {
|
|
||||||
+ switch (usage->hid & HID_USAGE) {
|
|
||||||
+ /* Fn+C ASUS Splendid */
|
|
||||||
+ case 0xba: asus_map_key_clear(KEY_PROG2); break;
|
|
||||||
|
|
||||||
- /* Fn+Space Power4Gear Hybrid */
|
|
||||||
- case 0x5c: asus_map_key_clear(KEY_PROG3); break;
|
|
||||||
+ /* Fn+Space Power4Gear Hybrid */
|
|
||||||
+ case 0x5c: asus_map_key_clear(KEY_PROG3); break;
|
|
||||||
|
|
||||||
- /* Fn+F5 "fan" symbol on FX503VD */
|
|
||||||
- case 0x99: asus_map_key_clear(KEY_PROG4); break;
|
|
||||||
+ /* Fn+F5 "fan" symbol on FX503VD */
|
|
||||||
+ case 0x99: asus_map_key_clear(KEY_PROG4); break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* device 0x1866, N-KEY Device specific */
|
|
||||||
+ if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
|
|
||||||
+ switch (usage->hid & HID_USAGE) {
|
|
||||||
+ /* Fn+Ret "Calc" symbol on device 0x1866, N-KEY Device */
|
|
||||||
+ case 0x92: asus_map_key_clear(KEY_CALC); break;
|
|
||||||
+
|
|
||||||
+ /* Fn+Left Aura mode previous */
|
|
||||||
+ case 0xb2: asus_map_key_clear(KEY_KBDILLUM_MODE_PREV); break;
|
|
||||||
+
|
|
||||||
+ /* Fn+Right Aura mode next */
|
|
||||||
+ case 0xb3: asus_map_key_clear(KEY_KBDILLUM_MODE_NEXT); break;
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ return -1;
|
|
||||||
+ }
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
- default:
|
|
||||||
/* ASUS lazily declares 256 usages, ignore the rest,
|
|
||||||
* as some make the keyboard appear as a pointer device. */
|
|
||||||
return -1;
|
|
||||||
@@ -1126,6 +1243,9 @@ static const struct hid_device_id asus_devices[] = {
|
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
|
||||||
USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD),
|
|
||||||
QUIRK_USE_KBD_BACKLIGHT },
|
|
||||||
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
|
||||||
+ USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD),
|
|
||||||
+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
|
|
||||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
|
|
||||||
USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
|
|
||||||
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
|
|
||||||
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
|
|
||||||
index 6f370e020feb..c9f930ddcfd7 100644
|
|
||||||
--- a/drivers/hid/hid-ids.h
|
|
||||||
+++ b/drivers/hid/hid-ids.h
|
|
||||||
@@ -190,6 +190,7 @@
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822
|
|
||||||
+#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866
|
|
||||||
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
|
|
||||||
|
|
||||||
#define USB_VENDOR_ID_ATEN 0x0557
|
|
||||||
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
index 897b8332a39f..05253cfe786c 100644
|
|
||||||
--- a/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
+++ b/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
@@ -27,6 +27,8 @@
|
|
||||||
#define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */
|
|
||||||
#define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */
|
|
||||||
|
|
||||||
+#define ASUS_WMI_METHODID_NOTIF 0x00100021 /* Notify method ?? */
|
|
||||||
+
|
|
||||||
#define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
|
|
||||||
|
|
||||||
/* Wireless */
|
|
||||||
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
|
|
||||||
index 0c2e27d28e0a..ca59f7d7a25e 100644
|
|
||||||
--- a/include/uapi/linux/input-event-codes.h
|
|
||||||
+++ b/include/uapi/linux/input-event-codes.h
|
|
||||||
@@ -772,6 +772,13 @@
|
|
||||||
#define BTN_TRIGGER_HAPPY39 0x2e6
|
|
||||||
#define BTN_TRIGGER_HAPPY40 0x2e7
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Some keyboards have function keys associated with
|
|
||||||
+ * changing the keyboard backlight modes, e.g, RGB patterns
|
|
||||||
+ */
|
|
||||||
+#define KEY_KBDILLUM_MODE_PREV 0x2ea
|
|
||||||
+#define KEY_KBDILLUM_MODE_NEXT 0x2eb
|
|
||||||
+
|
|
||||||
/* We avoid low common keys in module aliases so they don't get huge. */
|
|
||||||
#define KEY_MIN_INTERESTING KEY_MUTE
|
|
||||||
#define KEY_MAX 0x2ff
|
|
||||||
--
|
|
||||||
2.26.2
|
|
||||||
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
---
|
|
||||||
.../ABI/testing/sysfs-platform-asus-wmi | 10 ++
|
|
||||||
drivers/platform/x86/asus-wmi.c | 113 ++++++++++++++++++
|
|
||||||
include/linux/platform_data/x86/asus-wmi.h | 1 +
|
|
||||||
3 files changed, 124 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
|
|
||||||
index 9e99f2909612..1efac0ddb417 100644
|
|
||||||
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
|
|
||||||
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
|
|
||||||
@@ -46,3 +46,13 @@ Description:
|
|
||||||
* 0 - normal,
|
|
||||||
* 1 - overboost,
|
|
||||||
* 2 - silent
|
|
||||||
+
|
|
||||||
+What: /sys/devices/platform/<platform>/throttle_thermal_policy
|
|
||||||
+Date: Dec 2019
|
|
||||||
+KernelVersion: 5.6
|
|
||||||
+Contact: "Leonid Maksymchuk" <leonmaxx@gmail.com>
|
|
||||||
+Description:
|
|
||||||
+ Throttle thermal policy mode:
|
|
||||||
+ * 0 - default,
|
|
||||||
+ * 1 - overboost,
|
|
||||||
+ * 2 - silent
|
|
||||||
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
|
|
||||||
index 821b08e01635..f10ec9d745e5 100644
|
|
||||||
--- a/drivers/platform/x86/asus-wmi.c
|
|
||||||
+++ b/drivers/platform/x86/asus-wmi.c
|
|
||||||
@@ -61,6 +61,7 @@ MODULE_LICENSE("GPL");
|
|
||||||
#define NOTIFY_KBD_BRTDWN 0xc5
|
|
||||||
#define NOTIFY_KBD_BRTTOGGLE 0xc7
|
|
||||||
#define NOTIFY_KBD_FBM 0x99
|
|
||||||
+#define NOTIFY_KBD_TTP 0xae
|
|
||||||
|
|
||||||
#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
|
|
||||||
|
|
||||||
@@ -81,6 +82,10 @@ MODULE_LICENSE("GPL");
|
|
||||||
#define ASUS_FAN_BOOST_MODE_SILENT_MASK 0x02
|
|
||||||
#define ASUS_FAN_BOOST_MODES_MASK 0x03
|
|
||||||
|
|
||||||
+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT 0
|
|
||||||
+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1
|
|
||||||
+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2
|
|
||||||
+
|
|
||||||
#define USB_INTEL_XUSB2PR 0xD0
|
|
||||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
|
|
||||||
|
|
||||||
@@ -198,6 +203,9 @@ struct asus_wmi {
|
|
||||||
u8 fan_boost_mode_mask;
|
|
||||||
u8 fan_boost_mode;
|
|
||||||
|
|
||||||
+ bool throttle_thermal_policy_available;
|
|
||||||
+ u8 throttle_thermal_policy_mode;
|
|
||||||
+
|
|
||||||
// The RSOC controls the maximum charging percentage.
|
|
||||||
bool battery_rsoc_available;
|
|
||||||
|
|
||||||
@@ -1724,6 +1732,98 @@ static ssize_t fan_boost_mode_store(struct device *dev,
|
|
||||||
// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent
|
|
||||||
static DEVICE_ATTR_RW(fan_boost_mode);
|
|
||||||
|
|
||||||
+/* Throttle thermal policy ****************************************************/
|
|
||||||
+
|
|
||||||
+static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
|
|
||||||
+{
|
|
||||||
+ u32 result;
|
|
||||||
+ int err;
|
|
||||||
+
|
|
||||||
+ asus->throttle_thermal_policy_available = false;
|
|
||||||
+
|
|
||||||
+ err = asus_wmi_get_devstate(asus,
|
|
||||||
+ ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
|
|
||||||
+ &result);
|
|
||||||
+ if (err) {
|
|
||||||
+ if (err == -ENODEV)
|
|
||||||
+ return 0;
|
|
||||||
+ return err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
|
|
||||||
+ asus->throttle_thermal_policy_available = true;
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int throttle_thermal_policy_write(struct asus_wmi *asus)
|
|
||||||
+{
|
|
||||||
+ int err;
|
|
||||||
+ u8 value;
|
|
||||||
+ u32 retval;
|
|
||||||
+
|
|
||||||
+ value = asus->throttle_thermal_policy_mode;
|
|
||||||
+
|
|
||||||
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
|
|
||||||
+ value, &retval);
|
|
||||||
+ if (err) {
|
|
||||||
+ pr_warn("Failed to set throttle thermal policy: %d\n", err);
|
|
||||||
+ return err;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (retval != 1) {
|
|
||||||
+ pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n",
|
|
||||||
+ retval);
|
|
||||||
+ return -EIO;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
|
|
||||||
+{
|
|
||||||
+ u8 new_mode = asus->throttle_thermal_policy_mode + 1;
|
|
||||||
+
|
|
||||||
+ if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
|
|
||||||
+ new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
|
|
||||||
+
|
|
||||||
+ asus->throttle_thermal_policy_mode = new_mode;
|
|
||||||
+ return throttle_thermal_policy_write(asus);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static ssize_t throttle_thermal_policy_show(struct device *dev,
|
|
||||||
+ struct device_attribute *attr, char *buf)
|
|
||||||
+{
|
|
||||||
+ struct asus_wmi *asus = dev_get_drvdata(dev);
|
|
||||||
+ u8 mode = asus->throttle_thermal_policy_mode;
|
|
||||||
+
|
|
||||||
+ return scnprintf(buf, PAGE_SIZE, "%d\n", mode);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static ssize_t throttle_thermal_policy_store(struct device *dev,
|
|
||||||
+ struct device_attribute *attr,
|
|
||||||
+ const char *buf, size_t count)
|
|
||||||
+{
|
|
||||||
+ int result;
|
|
||||||
+ u8 new_mode;
|
|
||||||
+ struct asus_wmi *asus = dev_get_drvdata(dev);
|
|
||||||
+
|
|
||||||
+ result = kstrtou8(buf, 10, &new_mode);
|
|
||||||
+ if (result < 0)
|
|
||||||
+ return result;
|
|
||||||
+
|
|
||||||
+ if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
|
|
||||||
+ return -EINVAL;
|
|
||||||
+
|
|
||||||
+ asus->throttle_thermal_policy_mode = new_mode;
|
|
||||||
+ throttle_thermal_policy_write(asus);
|
|
||||||
+
|
|
||||||
+ return count;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
|
|
||||||
+static DEVICE_ATTR_RW(throttle_thermal_policy);
|
|
||||||
+
|
|
||||||
/* Backlight ******************************************************************/
|
|
||||||
|
|
||||||
static int read_backlight_power(struct asus_wmi *asus)
|
|
||||||
@@ -2005,6 +2105,11 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) {
|
|
||||||
+ throttle_thermal_policy_switch_next(asus);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
@@ -2155,6 +2260,7 @@ static struct attribute *platform_attributes[] = {
|
|
||||||
&dev_attr_lid_resume.attr,
|
|
||||||
&dev_attr_als_enable.attr,
|
|
||||||
&dev_attr_fan_boost_mode.attr,
|
|
||||||
+ &dev_attr_throttle_thermal_policy.attr,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -2178,6 +2284,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
|
|
||||||
devid = ASUS_WMI_DEVID_ALS_ENABLE;
|
|
||||||
else if (attr == &dev_attr_fan_boost_mode.attr)
|
|
||||||
ok = asus->fan_boost_mode_available;
|
|
||||||
+ else if (attr == &dev_attr_throttle_thermal_policy.attr)
|
|
||||||
+ ok = asus->throttle_thermal_policy_available;
|
|
||||||
|
|
||||||
if (devid != -1)
|
|
||||||
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
|
|
||||||
@@ -2437,6 +2545,10 @@ static int asus_wmi_add(struct platform_device *pdev)
|
|
||||||
if (err)
|
|
||||||
goto fail_fan_boost_mode;
|
|
||||||
|
|
||||||
+ err = throttle_thermal_policy_check_present(asus);
|
|
||||||
+ if (err)
|
|
||||||
+ goto fail_throttle_thermal_policy;
|
|
||||||
+
|
|
||||||
err = asus_wmi_sysfs_init(asus->platform_device);
|
|
||||||
if (err)
|
|
||||||
goto fail_sysfs;
|
|
||||||
@@ -2521,6 +2633,7 @@ static int asus_wmi_add(struct platform_device *pdev)
|
|
||||||
fail_input:
|
|
||||||
asus_wmi_sysfs_exit(asus->platform_device);
|
|
||||||
fail_sysfs:
|
|
||||||
+fail_throttle_thermal_policy:
|
|
||||||
fail_fan_boost_mode:
|
|
||||||
fail_platform:
|
|
||||||
kfree(asus);
|
|
||||||
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
index 60249e22e844..d39fc658c320 100644
|
|
||||||
--- a/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
+++ b/include/linux/platform_data/x86/asus-wmi.h
|
|
||||||
@@ -58,6 +58,7 @@
|
|
||||||
#define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */
|
|
||||||
#define ASUS_WMI_DEVID_LIGHTBAR 0x00050025
|
|
||||||
#define ASUS_WMI_DEVID_FAN_BOOST_MODE 0x00110018
|
|
||||||
+#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
|
|
||||||
|
|
||||||
/* Misc */
|
|
||||||
#define ASUS_WMI_DEVID_CAMERA 0x00060013
|
|
||||||
--
|
|
||||||
2.24.0
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
---
|
|
||||||
drivers/platform/x86/asus-wmi.c | 11 +++++++++++
|
|
||||||
1 file changed, 11 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
|
|
||||||
index f10ec9d745e5..469f1a852719 100644
|
|
||||||
--- a/drivers/platform/x86/asus-wmi.c
|
|
||||||
+++ b/drivers/platform/x86/asus-wmi.c
|
|
||||||
@@ -1780,6 +1780,15 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
|
|
||||||
+{
|
|
||||||
+ if (!asus->throttle_thermal_policy_available)
|
|
||||||
+ return 0;
|
|
||||||
+
|
|
||||||
+ asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
|
|
||||||
+ return throttle_thermal_policy_write(asus);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
|
|
||||||
{
|
|
||||||
u8 new_mode = asus->throttle_thermal_policy_mode + 1;
|
|
||||||
@@ -2548,6 +2557,8 @@ static int asus_wmi_add(struct platform_device *pdev)
|
|
||||||
err = throttle_thermal_policy_check_present(asus);
|
|
||||||
if (err)
|
|
||||||
goto fail_throttle_thermal_policy;
|
|
||||||
+ else
|
|
||||||
+ throttle_thermal_policy_set_default(asus);
|
|
||||||
|
|
||||||
err = asus_wmi_sysfs_init(asus->platform_device);
|
|
||||||
if (err)
|
|
||||||
--
|
|
||||||
2.24.0
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
[root@rog tmp]# cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
|
|
||||||
[root@rog tmp]# iasl -d dsdt.dat
|
|
||||||
|
|
||||||
Intel ACPI Component Architecture
|
|
||||||
ASL+ Optimizing Compiler/Disassembler version 20200717
|
|
||||||
Copyright (c) 2000 - 2020 Intel Corporation
|
|
||||||
|
|
||||||
File appears to be binary: found 97272 non-ASCII characters, disassembling
|
|
||||||
Binary file appears to be a valid ACPI table, disassembling
|
|
||||||
Input file dsdt.dat, Length 0x45955 (285013) bytes
|
|
||||||
ACPI: DSDT 0x0000000000000000 045955 (v02 _ASUS_ Notebook 01072009 INTL 20160527)
|
|
||||||
Pass 1 parse of [DSDT]
|
|
||||||
ACPI Error: ^PCI0.LPCB.EC0_.ACNG: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^PCI0.LPCB.EC0.ACNG], AE_NOT_FOUND (20200717/dswload-495)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.NLIM: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.NLIM], AE_NOT_FOUND (20200717/dswload-495)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.TGPU: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.TGPU], AE_NOT_FOUND (20200717/dswload-495)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^^NPCF.PABS: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^^NPCF.PABS], AE_NOT_FOUND (20200717/dswload-495)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.CTGP: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.CTGP], AE_NOT_FOUND (20200717/dswload-495)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.TGPV: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.TGPV], AE_NOT_FOUND (20200717/dswload-495)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
Pass 2 parse of [DSDT]
|
|
||||||
ACPI Error: ^PCI0.LPCB.EC0_.ACNG: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^PCI0.LPCB.EC0.ACNG], AE_NOT_FOUND (20200717/dswload2-479)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.NLIM: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.NLIM], AE_NOT_FOUND (20200717/dswload2-479)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.TGPU: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.TGPU], AE_NOT_FOUND (20200717/dswload2-479)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^^NPCF.PABS: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^^NPCF.PABS], AE_NOT_FOUND (20200717/dswload2-479)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.CTGP: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.CTGP], AE_NOT_FOUND (20200717/dswload2-479)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
ACPI Error: ^^PEG0.PEGP.TGPV: Path has too many parent prefixes (^) (20200717/nsaccess-604)
|
|
||||||
Firmware Error (ACPI): Could not resolve symbol [^^PEG0.PEGP.TGPV], AE_NOT_FOUND (20200717/dswload2-479)
|
|
||||||
ACPI Error: AE_NOT_FOUND, During name lookup/catalog (20200717/psobject-372)
|
|
||||||
Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)
|
|
||||||
|
|
||||||
Parsing completed
|
|
||||||
Warning - Emitting ASL code "External (ESPC)"
|
|
||||||
This is a conflicting declaration with some other declaration within the ASL code.
|
|
||||||
This external declaration may need to be deleted in order to recompile the dsl file.
|
|
||||||
|
|
||||||
Warning - Emitting ASL code "External (PSON)"
|
|
||||||
This is a conflicting declaration with some other declaration within the ASL code.
|
|
||||||
This external declaration may need to be deleted in order to recompile the dsl file.
|
|
||||||
|
|
||||||
Disassembly completed
|
|
||||||
ASL Output: dsdt.dsl - 2006627 bytes
|
|
||||||
[root@rog tmp]#
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
cat /sys/class/dmi/id/product_name:ROG Strix G512LU_G512LU
|
|
||||||
cat /sys/class/dmi/id/product_family: ROG Strix
|
|
||||||
cat /sys/class/dmi/id/board_name:G512LU
|
|
||||||
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
001:002:002:DESCRIPTOR 1593779817.131018
|
|
||||||
06 31 FF 09 76 A1 01 85 5A 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 05 81 00 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 3F B1 00 C0 05 0C 09 01 A1 01
|
|
||||||
85 02 19 00 2A 3C 02 15 00 26 3C 02 75 10 95 02
|
|
||||||
81 00 C0 06 31 FF 09 79 A1 01 85 5D 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 1F 81 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F 91 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F B1 00 C0 06 31 FF
|
|
||||||
09 80 A1 01 85 5E 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 05 81 00 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 3F B1 00 C0
|
|
||||||
|
|
||||||
001:002:001:DESCRIPTOR 1593779817.133253
|
|
||||||
05 01 09 06 A1 01 85 09 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 08 75 01 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 F0 75 01 05 07 19 00 29 EF 15 00 25 01 81 02
|
|
||||||
C0
|
|
||||||
|
|
||||||
001:002:000:DESCRIPTOR 1593779817.134955
|
|
||||||
05 01 09 06 A1 01 85 01 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 01 75 08 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 06 75 08 15 00 26 FF 00 05 07 19 00 2A FF 00
|
|
||||||
81 00 95 C0 75 01 05 07 19 00 29 EF 15 00 25 01
|
|
||||||
81 02 C0
|
|
||||||
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
Product name: ROG Strix G531GT_G531GT
|
|
||||||
Product family: ROG Strix
|
|
||||||
Board name: G531GT
|
|
||||||
|
|
||||||
lsusb | grep 0b05: Bus 001 Device 004: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
1b00a00964188090ffff00000000090000020002000401400000005dbc00010101001000000000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000000 ROGKEY
|
|
||||||
1b006079b90e8090ffff00000000090000020002000401400000005dbc00010101601000ffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ENTER
|
|
||||||
1b00e014ee088090ffff00000000090000020002000401400000005dbc00010101701000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000000000000 RSHIFT
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
|
|
||||||
Bus 001 Device 004: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
Device Descriptor:
|
|
||||||
bLength 18
|
|
||||||
bDescriptorType 1
|
|
||||||
bcdUSB 2.00
|
|
||||||
bDeviceClass 0
|
|
||||||
bDeviceSubClass 0
|
|
||||||
bDeviceProtocol 0
|
|
||||||
bMaxPacketSize0 64
|
|
||||||
idVendor 0x0b05 ASUSTek Computer, Inc.
|
|
||||||
idProduct 0x1866
|
|
||||||
bcdDevice 0.02
|
|
||||||
iManufacturer 1 ASUSTeK Computer Inc.
|
|
||||||
iProduct 2 N-KEY Device
|
|
||||||
iSerial 0
|
|
||||||
bNumConfigurations 1
|
|
||||||
Configuration Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 2
|
|
||||||
wTotalLength 0x005b
|
|
||||||
bNumInterfaces 3
|
|
||||||
bConfigurationValue 1
|
|
||||||
iConfiguration 0
|
|
||||||
bmAttributes 0xe0
|
|
||||||
Self Powered
|
|
||||||
Remote Wakeup
|
|
||||||
MaxPower 100mA
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 0
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 3 (error)
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 67
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x81 EP 1 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 1
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 65
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x82 EP 2 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 2
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 2
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 167
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x83 EP 3 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x04 EP 4 OUT
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Device Status: 0x0001
|
|
||||||
Self Powered
|
|
||||||
|
Before Width: | Height: | Size: 188 KiB |
@@ -1,6 +0,0 @@
|
|||||||
1b00a0e94d068090ffff00000000090000020002000401400000005dbc00010400000000000000000000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000 LED6
|
|
||||||
1b0020d77e048090ffff00000000090000020002000401400000005dbc00010400000000000000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000000 LED5
|
|
||||||
1b008089e1048090ffff00000000090000020002000401400000005dbc00010400000000000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000000000000 LED4
|
|
||||||
1b0010103d088090ffff00000000090000020002000401400000005dbc00010400000000000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000 LED3
|
|
||||||
1b007079ce1f8090ffff00000000090000020002000401400000005dbc00010400000000000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000 LED2
|
|
||||||
1b00e0e4fe078090ffff00000000090000020002000401400000005dbc00010400000000000000000000ffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 LED1
|
|
||||||
|
Before Width: | Height: | Size: 3.2 MiB |
@@ -1,130 +0,0 @@
|
|||||||
|
|
||||||
Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
Device Descriptor:
|
|
||||||
bLength 18
|
|
||||||
bDescriptorType 1
|
|
||||||
bcdUSB 2.00
|
|
||||||
bDeviceClass 0
|
|
||||||
bDeviceSubClass 0
|
|
||||||
bDeviceProtocol 0
|
|
||||||
bMaxPacketSize0 64
|
|
||||||
idVendor 0x0b05 ASUSTek Computer, Inc.
|
|
||||||
idProduct 0x1866
|
|
||||||
bcdDevice 0.02
|
|
||||||
iManufacturer 1 ASUSTeK Computer Inc.
|
|
||||||
iProduct 2 N-KEY Device
|
|
||||||
iSerial 0
|
|
||||||
bNumConfigurations 1
|
|
||||||
Configuration Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 2
|
|
||||||
wTotalLength 0x005b
|
|
||||||
bNumInterfaces 3
|
|
||||||
bConfigurationValue 1
|
|
||||||
iConfiguration 0
|
|
||||||
bmAttributes 0xe0
|
|
||||||
Self Powered
|
|
||||||
Remote Wakeup
|
|
||||||
MaxPower 100mA
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 0
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 3 (error)
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 83
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x81 EP 1 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 1
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 65
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x82 EP 2 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 2
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 2
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 167
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x83 EP 3 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x04 EP 4 OUT
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Device Status: 0x0001
|
|
||||||
Self Powered
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
artem@art-kub:~$ cat /etc/*-release
|
|
||||||
DISTRIB_ID=Ubuntu
|
|
||||||
DISTRIB_RELEASE=20.04
|
|
||||||
DISTRIB_CODENAME=focal
|
|
||||||
DISTRIB_DESCRIPTION="Ubuntu 20.04 LTS"
|
|
||||||
NAME="Ubuntu"
|
|
||||||
VERSION="20.04 LTS (Focal Fossa)"
|
|
||||||
ID=ubuntu
|
|
||||||
ID_LIKE=debian
|
|
||||||
PRETTY_NAME="Ubuntu 20.04 LTS"
|
|
||||||
VERSION_ID="20.04"
|
|
||||||
HOME_URL="https://www.ubuntu.com/"
|
|
||||||
SUPPORT_URL="https://help.ubuntu.com/"
|
|
||||||
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
|
|
||||||
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
|
|
||||||
VERSION_CODENAME=focal
|
|
||||||
UBUNTU_CODENAME=focal
|
|
||||||
|
|
||||||
artem@art-kub:~$ hostnamectl
|
|
||||||
Static hostname: art-kub
|
|
||||||
Icon name: computer-laptop
|
|
||||||
Chassis: laptop
|
|
||||||
Machine ID: f3792a953d24486bb8881f4ab1b93e44
|
|
||||||
Boot ID: 5f064ae70f274461909bea1526a5b4e3
|
|
||||||
Operating System: Ubuntu 20.04 LTS
|
|
||||||
Kernel: Linux 5.4.0-39-generic
|
|
||||||
Architecture: x86-64
|
|
||||||
|
|
||||||
artem@art-kub:~$ cat /proc/version
|
|
||||||
Linux version 5.4.0-39-generic (buildd@lcy01-amd64-016) (gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu2)) #43-Ubuntu SMP Fri Jun 19 10:28:31 UTC 2020
|
|
||||||
|
|
||||||
artem@art-kub:~$ uname -a
|
|
||||||
Linux art-kub 5.4.0-39-generic #43-Ubuntu SMP Fri Jun 19 10:28:31 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
|
|
||||||
|
|
||||||
|
|
||||||
artem@art-kub:~$ cat /sys/class/dmi/id/product_name
|
|
||||||
ROG Strix G712LV_G712LV
|
|
||||||
|
|
||||||
artem@art-kub:~$ cat /sys/class/dmi/id/product_family
|
|
||||||
ROG Strix
|
|
||||||
|
|
||||||
artem@art-kub:~$ cat /sys/class/dmi/id/board_name
|
|
||||||
G712LV
|
|
||||||
|
|
||||||
artem@art-kub:~$ lsusb |grep 0b05
|
|
||||||
Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
001:002:002:DESCRIPTOR 1593321424.949103
|
|
||||||
06 31 FF 09 76 A1 01 85 5A 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 05 81 00 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 3F B1 00 C0 05 0C 09 01 A1 01
|
|
||||||
85 02 19 00 2A 3C 02 15 00 26 3C 02 75 10 95 02
|
|
||||||
81 00 C0 06 31 FF 09 79 A1 01 85 5D 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 1F 81 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F 91 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F B1 00 C0 06 31 FF
|
|
||||||
09 80 A1 01 85 5E 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 05 81 00 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 3F B1 00 C0
|
|
||||||
|
|
||||||
001:002:001:DESCRIPTOR 1593321424.951280
|
|
||||||
05 01 09 06 A1 01 85 09 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 08 75 01 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 F0 75 01 05 07 19 00 29 EF 15 00 25 01 81 02
|
|
||||||
C0
|
|
||||||
|
|
||||||
001:002:000:DESCRIPTOR 1593321424.952588
|
|
||||||
05 01 09 06 A1 01 85 01 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 01 75 08 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 06 75 08 15 00 26 FF 00 05 07 19 00 2A FF 00
|
|
||||||
81 00 95 C0 75 01 05 07 19 00 29 EF 15 00 25 01
|
|
||||||
81 02 C0
|
|
||||||
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
$ cat /sys/class/dmi/id/product_name
|
|
||||||
ROG Zephyrus G14 GA401IV_GA401IV
|
|
||||||
$ cat /sys/class/dmi/id/product_family
|
|
||||||
ROG Zephyrus G14
|
|
||||||
$ cat /sys/class/dmi/id/board_name
|
|
||||||
GA401IV
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
|
||||||
0x09, 0x06, // Usage (Keyboard)
|
|
||||||
0xA1, 0x01, // Collection (Application)
|
|
||||||
0x85, 0x09, // Report ID (9)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x95, 0x08, // Report Count (8)
|
|
||||||
0x05, 0x07, // Usage Page (Kbrd/Keypad)
|
|
||||||
0x19, 0xE0, // Usage Minimum (0xE0)
|
|
||||||
0x29, 0xE7, // Usage Maximum (0xE7)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x25, 0x01, // Logical Maximum (1)
|
|
||||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x95, 0x08, // Report Count (8)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x95, 0x05, // Report Count (5)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x05, 0x08, // Usage Page (LEDs)
|
|
||||||
0x19, 0x01, // Usage Minimum (Num Lock)
|
|
||||||
0x29, 0x05, // Usage Maximum (Kana)
|
|
||||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0x95, 0x01, // Report Count (1)
|
|
||||||
0x75, 0x03, // Report Size (3)
|
|
||||||
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0x95, 0xF0, // Report Count (-16)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x05, 0x07, // Usage Page (Kbrd/Keypad)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x29, 0xEF, // Usage Maximum (0xEF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x25, 0x01, // Logical Maximum (1)
|
|
||||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0xC0, // End Collection
|
|
||||||
|
|
||||||
// 65 bytes
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
0x06, 0x31, 0xFF, // Usage Page (Vendor Defined 0xFF31)
|
|
||||||
0x09, 0x76, // Usage (0x76)
|
|
||||||
0xA1, 0x01, // Collection (Application)
|
|
||||||
0x85, 0x5A, // Report ID (90)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x05, // Report Count (5)
|
|
||||||
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x3F, // Report Count (63)
|
|
||||||
0xB1, 0x00, // Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0x05, 0x0C, // Usage Page (Consumer)
|
|
||||||
0x09, 0x01, // Usage (Consumer Control)
|
|
||||||
0xA1, 0x01, // Collection (Application)
|
|
||||||
0x85, 0x02, // Report ID (2)
|
|
||||||
0x19, 0x00, // Usage Minimum (Unassigned)
|
|
||||||
0x2A, 0x3C, 0x02, // Usage Maximum (AC Format)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0x3C, 0x02, // Logical Maximum (572)
|
|
||||||
0x75, 0x10, // Report Size (16)
|
|
||||||
0x95, 0x02, // Report Count (2)
|
|
||||||
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0x06, 0x31, 0xFF, // Usage Page (Vendor Defined 0xFF31)
|
|
||||||
0x09, 0x79, // Usage (0x79)
|
|
||||||
0xA1, 0x01, // Collection (Application)
|
|
||||||
0x85, 0x5D, // Report ID (93)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x1F, // Report Count (31)
|
|
||||||
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x3F, // Report Count (63)
|
|
||||||
0x91, 0x00, // Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x3F, // Report Count (63)
|
|
||||||
0xB1, 0x00, // Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0xC0, // End Collection
|
|
||||||
0x06, 0x31, 0xFF, // Usage Page (Vendor Defined 0xFF31)
|
|
||||||
0x09, 0x80, // Usage (0x80)
|
|
||||||
0xA1, 0x01, // Collection (Application)
|
|
||||||
0x85, 0x5E, // Report ID (94)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x05, // Report Count (5)
|
|
||||||
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x3F, // Report Count (63)
|
|
||||||
0xB1, 0x00, // Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0xC0, // End Collection
|
|
||||||
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
|
||||||
0x09, 0x06, // Usage (Keyboard)
|
|
||||||
0xA1, 0x01, // Collection (Application)
|
|
||||||
0x85, 0x01, // Report ID (1)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x95, 0x08, // Report Count (8)
|
|
||||||
0x05, 0x07, // Usage Page (Kbrd/Keypad)
|
|
||||||
0x19, 0xE0, // Usage Minimum (0xE0)
|
|
||||||
0x29, 0xE7, // Usage Maximum (0xE7)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x25, 0x01, // Logical Maximum (1)
|
|
||||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x95, 0x01, // Report Count (1)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x95, 0x05, // Report Count (5)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x05, 0x08, // Usage Page (LEDs)
|
|
||||||
0x19, 0x01, // Usage Minimum (Num Lock)
|
|
||||||
0x29, 0x05, // Usage Maximum (Kana)
|
|
||||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0x95, 0x01, // Report Count (1)
|
|
||||||
0x75, 0x03, // Report Size (3)
|
|
||||||
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
|
||||||
0x95, 0x06, // Report Count (6)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
|
||||||
0x05, 0x07, // Usage Page (Kbrd/Keypad)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x2A, 0xFF, 0x00, // Usage Maximum (0xFF)
|
|
||||||
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x95, 0xC0, // Report Count (-64)
|
|
||||||
0x75, 0x01, // Report Size (1)
|
|
||||||
0x05, 0x07, // Usage Page (Kbrd/Keypad)
|
|
||||||
0x19, 0x00, // Usage Minimum (0x00)
|
|
||||||
0x29, 0xEF, // Usage Maximum (0xEF)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x25, 0x01, // Logical Maximum (1)
|
|
||||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0xC0, // End Collection
|
|
||||||
|
|
||||||
// 83 bytes
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
Bus 003 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
Device Descriptor:
|
|
||||||
bLength 18
|
|
||||||
bDescriptorType 1
|
|
||||||
bcdUSB 2.00
|
|
||||||
bDeviceClass 0
|
|
||||||
bDeviceSubClass 0
|
|
||||||
bDeviceProtocol 0
|
|
||||||
bMaxPacketSize0 64
|
|
||||||
idVendor 0x0b05 ASUSTek Computer, Inc.
|
|
||||||
idProduct 0x1866
|
|
||||||
bcdDevice 0.02
|
|
||||||
iManufacturer 1 ASUSTeK Computer Inc.
|
|
||||||
iProduct 2 N-KEY Device
|
|
||||||
iSerial 0
|
|
||||||
bNumConfigurations 1
|
|
||||||
Configuration Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 2
|
|
||||||
wTotalLength 0x005b
|
|
||||||
bNumInterfaces 3
|
|
||||||
bConfigurationValue 1
|
|
||||||
iConfiguration 0
|
|
||||||
bmAttributes 0xe0
|
|
||||||
Self Powered
|
|
||||||
Remote Wakeup
|
|
||||||
MaxPower 100mA
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 0
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 3 (error)
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 83
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x81 EP 1 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 1
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 65
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x82 EP 2 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 2
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 2
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 167
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x83 EP 3 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x04 EP 4 OUT
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Device Status: 0x0001
|
|
||||||
Self Powered
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
cat /sys/class/dmi/id/product_name
|
|
||||||
ROG Zephyrus G15 GA502IU_GA502IU
|
|
||||||
cat /sys/class/dmi/id/product_family
|
|
||||||
ROG Zephyrus G15
|
|
||||||
cat /sys/class/dmi/id/board_name
|
|
||||||
GA502IU
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
(base) will@zephyrusm:~$ lsusb | grep 0b05
|
|
||||||
Bus 001 Device 003: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
(base) will@zephyrusm:~$
|
|
||||||
|
|
||||||
(base) will@zephyrusm:~$ cat /sys/class/dmi/id/product_name
|
|
||||||
Zephyrus M GM501GM
|
|
||||||
(base) will@zephyrusm:~$ cat /sys/class/dmi/id/product_family
|
|
||||||
Zephyrus M
|
|
||||||
(base) will@zephyrusm:~$ cat /sys/class/dmi/id/board_name
|
|
||||||
GM501GM
|
|
||||||
(base) will@zephyrusm:~$
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
001:003:002:DESCRIPTOR 1588963579.696552
|
|
||||||
06 31 FF 09 76 A1 01 85 5A 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 05 81 00 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 3F B1 00 C0 05 0C 09 01 A1 01
|
|
||||||
85 02 19 00 2A 3C 02 15 00 26 3C 02 75 10 95 02
|
|
||||||
81 00 C0 06 31 FF 09 79 A1 01 85 5D 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 1F 81 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F 91 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F B1 00 C0 06 31 FF
|
|
||||||
09 80 A1 01 85 5E 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 05 81 00 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 3F B1 00 C0
|
|
||||||
|
|
||||||
001:003:001:DESCRIPTOR 1588963579.697560
|
|
||||||
05 01 09 06 A1 01 85 09 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 08 75 01 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 F0 75 01 05 07 19 00 29 EF 15 00 25 01 81 02
|
|
||||||
C0
|
|
||||||
|
|
||||||
001:003:000:DESCRIPTOR 1588963579.698493
|
|
||||||
05 01 09 06 A1 01 85 01 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 01 75 08 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 1E 75 08 15 00 26 FF 00 05 07 19 00 2A FF 00
|
|
||||||
81 00 C0
|
|
||||||
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
|
|
||||||
Bus 001 Device 003: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
Device Descriptor:
|
|
||||||
bLength 18
|
|
||||||
bDescriptorType 1
|
|
||||||
bcdUSB 2.00
|
|
||||||
bDeviceClass 0
|
|
||||||
bDeviceSubClass 0
|
|
||||||
bDeviceProtocol 0
|
|
||||||
bMaxPacketSize0 64
|
|
||||||
idVendor 0x0b05 ASUSTek Computer, Inc.
|
|
||||||
idProduct 0x1866
|
|
||||||
bcdDevice 0.02
|
|
||||||
iManufacturer 1 ASUSTeK Computer Inc.
|
|
||||||
iProduct 2 N-KEY Device
|
|
||||||
iSerial 0
|
|
||||||
bNumConfigurations 1
|
|
||||||
Configuration Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 2
|
|
||||||
wTotalLength 0x005b
|
|
||||||
bNumInterfaces 3
|
|
||||||
bConfigurationValue 1
|
|
||||||
iConfiguration 0
|
|
||||||
bmAttributes 0xe0
|
|
||||||
Self Powered
|
|
||||||
Remote Wakeup
|
|
||||||
MaxPower 100mA
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 0
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 3 (error)
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 67
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x81 EP 1 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 1
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 1
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 65
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x82 EP 2 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Interface Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 4
|
|
||||||
bInterfaceNumber 2
|
|
||||||
bAlternateSetting 0
|
|
||||||
bNumEndpoints 2
|
|
||||||
bInterfaceClass 3 Human Interface Device
|
|
||||||
bInterfaceSubClass 1 Boot Interface Subclass
|
|
||||||
bInterfaceProtocol 1 Keyboard
|
|
||||||
iInterface 1 ASUSTeK Computer Inc.
|
|
||||||
HID Device Descriptor:
|
|
||||||
bLength 9
|
|
||||||
bDescriptorType 33
|
|
||||||
bcdHID 1.10
|
|
||||||
bCountryCode 0 Not supported
|
|
||||||
bNumDescriptors 1
|
|
||||||
bDescriptorType 34 Report
|
|
||||||
wDescriptorLength 167
|
|
||||||
Report Descriptors:
|
|
||||||
** UNAVAILABLE **
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x83 EP 3 IN
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Endpoint Descriptor:
|
|
||||||
bLength 7
|
|
||||||
bDescriptorType 5
|
|
||||||
bEndpointAddress 0x04 EP 4 OUT
|
|
||||||
bmAttributes 3
|
|
||||||
Transfer Type Interrupt
|
|
||||||
Synch Type None
|
|
||||||
Usage Type Data
|
|
||||||
wMaxPacketSize 0x0040 1x 64 bytes
|
|
||||||
bInterval 1
|
|
||||||
Device Status: 0x0001
|
|
||||||
Self Powered
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
distro= Arch Linux
|
|
||||||
uname -r= 5.7.7-arch1-1
|
|
||||||
product_name= Zephyrus G GU502DU_GA502DU
|
|
||||||
product_family= Zephyrus G
|
|
||||||
board_name= GU502DU
|
|
||||||
lsusb= Bus 003 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
-- Logs begin at Thu 2020-07-02 17:11:02 CEST, end at Fri 2020-07-03 13:19:49 CEST. --
|
|
||||||
júl 03 13:19:13 Zephyrus systemd[1]: Started ROG Core Daemon.
|
|
||||||
júl 03 13:19:13 Zephyrus rog-core[933380]: INFO: Product name: Zephyrus G GU502DU_GA502DU
|
|
||||||
júl 03 13:19:13 Zephyrus rog-core[933380]: INFO: Board name: GU502DU
|
|
||||||
júl 03 13:19:13 Zephyrus rog-core[933380]: thread 'main' panicked at 'Unsupported laptop, please request support at
|
|
||||||
júl 03 13:19:13 Zephyrus rog-core[933380]: https://github.com/flukejones/rog-core', rog-core/src/laptops.rs:89:9
|
|
||||||
júl 03 13:19:13 Zephyrus rog-core[933380]: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
||||||
júl 03 13:19:13 Zephyrus systemd[1]: rog-core.service: Main process exited, code=dumped, status=6/ABRT
|
|
||||||
júl 03 13:19:13 Zephyrus systemd[1]: rog-core.service: Failed with result 'core-dump'.
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: rog-core.service: Scheduled restart job, restart counter is at 1.
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: Stopped ROG Core Daemon.
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: Started ROG Core Daemon.
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933401]: INFO: Product name: Zephyrus G GU502DU_GA502DU
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933401]: INFO: Board name: GU502DU
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933401]: thread 'main' panicked at 'Unsupported laptop, please request support at
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933401]: https://github.com/flukejones/rog-core', rog-core/src/laptops.rs:89:9
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933401]: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: rog-core.service: Main process exited, code=dumped, status=6/ABRT
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: rog-core.service: Failed with result 'core-dump'.
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: rog-core.service: Scheduled restart job, restart counter is at 2.
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: Stopped ROG Core Daemon.
|
|
||||||
júl 03 13:19:14 Zephyrus systemd[1]: Started ROG Core Daemon.
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933420]: INFO: Product name: Zephyrus G GU502DU_GA502DU
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933420]: INFO: Board name: GU502DU
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933420]: thread 'main' panicked at 'Unsupported laptop, please request support at
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933420]: https://github.com/flukejones/rog-core', rog-core/src/laptops.rs:89:9
|
|
||||||
júl 03 13:19:14 Zephyrus rog-core[933420]: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
||||||
júl 03 13:19:15 Zephyrus systemd[1]: rog-core.service: Main process exited, code=dumped, status=6/ABRT
|
|
||||||
júl 03 13:19:15 Zephyrus systemd[1]: rog-core.service: Failed with result 'core-dump'.
|
|
||||||
júl 03 13:19:15 Zephyrus systemd[1]: rog-core.service: Scheduled restart job, restart counter is at 3.
|
|
||||||
júl 03 13:19:15 Zephyrus systemd[1]: Stopped ROG Core Daemon.
|
|
||||||
júl 03 13:19:15 Zephyrus systemd[1]: Started ROG Core Daemon.
|
|
||||||
júl 03 13:19:15 Zephyrus rog-core[933440]: INFO: Product name: Zephyrus G GU502DU_GA502DU
|
|
||||||
júl 03 13:19:15 Zephyrus rog-core[933440]: INFO: Board name: GU502DU
|
|
||||||
júl 03 13:19:15 Zephyrus rog-core[933440]: thread 'main' panicked at 'Unsupported laptop, please request support at
|
|
||||||
júl 03 13:19:15 Zephyrus rog-core[933440]: https://github.com/flukejones/rog-core', rog-core/src/laptops.rs:89:9
|
|
||||||
júl 03 13:19:15 Zephyrus rog-core[933440]: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
||||||
júl 03 13:19:16 Zephyrus systemd[1]: rog-core.service: Main process exited, code=dumped, status=6/ABRT
|
|
||||||
júl 03 13:19:16 Zephyrus systemd[1]: rog-core.service: Failed with result 'core-dump'.
|
|
||||||
júl 03 13:19:16 Zephyrus systemd[1]: rog-core.service: Scheduled restart job, restart counter is at 4.
|
|
||||||
júl 03 13:19:16 Zephyrus systemd[1]: Stopped ROG Core Daemon.
|
|
||||||
júl 03 13:19:16 Zephyrus systemd[1]: Started ROG Core Daemon.
|
|
||||||
júl 03 13:19:16 Zephyrus rog-core[933457]: INFO: Product name: Zephyrus G GU502DU_GA502DU
|
|
||||||
júl 03 13:19:16 Zephyrus rog-core[933457]: INFO: Board name: GU502DU
|
|
||||||
júl 03 13:19:16 Zephyrus rog-core[933457]: thread 'main' panicked at 'Unsupported laptop, please request support at
|
|
||||||
júl 03 13:19:16 Zephyrus rog-core[933457]: https://github.com/flukejones/rog-core', rog-core/src/laptops.rs:89:9
|
|
||||||
júl 03 13:19:16 Zephyrus rog-core[933457]: note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|
||||||
júl 03 13:19:17 Zephyrus systemd[1]: rog-core.service: Main process exited, code=dumped, status=6/ABRT
|
|
||||||
júl 03 13:19:17 Zephyrus systemd[1]: rog-core.service: Failed with result 'core-dump'.
|
|
||||||
júl 03 13:19:17 Zephyrus systemd[1]: rog-core.service: Scheduled restart job, restart counter is at 5.
|
|
||||||
júl 03 13:19:17 Zephyrus systemd[1]: Stopped ROG Core Daemon.
|
|
||||||
júl 03 13:19:17 Zephyrus systemd[1]: rog-core.service: Start request repeated too quickly.
|
|
||||||
júl 03 13:19:17 Zephyrus systemd[1]: rog-core.service: Failed with result 'core-dump'.
|
|
||||||
júl 03 13:19:17 Zephyrus systemd[1]: Failed to start ROG Core Daemon.
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
003:003:001:DESCRIPTOR 1593775246.732819
|
|
||||||
05 01 09 02 A1 01 85 02 09 01 A1 00 05 09 19 01
|
|
||||||
29 10 15 00 25 01 95 10 75 01 81 02 05 01 16 01
|
|
||||||
F8 26 FF 07 75 0C 95 02 09 30 09 31 81 06 15 81
|
|
||||||
25 7F 75 08 95 01 09 38 81 06 05 0C 0A 38 02 95
|
|
||||||
01 81 06 C0 C0 05 0C 09 01 A1 01 85 03 75 10 95
|
|
||||||
02 15 01 26 8C 02 19 01 2A 8C 02 81 00 C0 05 01
|
|
||||||
09 80 A1 01 85 04 75 02 95 01 15 01 25 03 09 82
|
|
||||||
09 81 09 83 81 60 75 06 81 03 C0 06 00 FF 09 01
|
|
||||||
A1 01 85 10 75 08 95 06 15 00 26 FF 00 09 01 81
|
|
||||||
00 09 01 91 00 C0 06 00 FF 09 02 A1 01 85 11 75
|
|
||||||
08 95 13 15 00 26 FF 00 09 02 81 00 09 02 91 00
|
|
||||||
C0
|
|
||||||
|
|
||||||
003:003:000:DESCRIPTOR 1593775246.736060
|
|
||||||
05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
|
|
||||||
75 01 95 08 81 02 81 03 95 05 05 08 19 01 29 05
|
|
||||||
91 02 95 01 75 03 91 01 95 06 75 08 15 00 26 A4
|
|
||||||
00 05 07 19 00 2A A4 00 81 00 C0
|
|
||||||
|
|
||||||
003:002:002:DESCRIPTOR 1593775246.738826
|
|
||||||
06 31 FF 09 76 A1 01 85 5A 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 05 81 00 19 00 2A FF 00 15 00
|
|
||||||
26 FF 00 75 08 95 3F B1 00 C0 05 0C 09 01 A1 01
|
|
||||||
85 02 19 00 2A 3C 02 15 00 26 3C 02 75 10 95 02
|
|
||||||
81 00 C0 06 31 FF 09 79 A1 01 85 5D 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 1F 81 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F 91 00 19 00 2A FF
|
|
||||||
00 15 00 26 FF 00 75 08 95 3F B1 00 C0 06 31 FF
|
|
||||||
09 80 A1 01 85 5E 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 05 81 00 19 00 2A FF 00 15 00 26 FF 00
|
|
||||||
75 08 95 3F B1 00 C0
|
|
||||||
|
|
||||||
003:002:001:DESCRIPTOR 1593775246.741819
|
|
||||||
05 01 09 06 A1 01 85 09 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 08 75 01 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 F0 75 01 05 07 19 00 29 EF 15 00 25 01 81 02
|
|
||||||
C0
|
|
||||||
|
|
||||||
003:002:000:DESCRIPTOR 1593775246.744821
|
|
||||||
05 01 09 06 A1 01 85 01 75 01 95 08 05 07 19 E0
|
|
||||||
29 E7 15 00 25 01 81 02 95 01 75 08 81 03 95 05
|
|
||||||
75 01 05 08 19 01 29 05 91 02 95 01 75 03 91 03
|
|
||||||
95 1E 75 08 15 00 26 FF 00 05 07 19 00 2A FF 00
|
|
||||||
81 00 C0
|
|
||||||
|
|
||||||