mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Better laptop LED mode handling
This commit is contained in:
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -46,6 +46,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"sysfs-class",
|
"sysfs-class",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"toml",
|
||||||
"udev",
|
"udev",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -892,6 +893,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.4.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "udev"
|
name = "udev"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -13,6 +13,7 @@ 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
|
||||||
|
|
||||||
DEBUG ?= 0
|
DEBUG ?= 0
|
||||||
ifeq ($(DEBUG),0)
|
ifeq ($(DEBUG),0)
|
||||||
@@ -37,6 +38,7 @@ 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 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/$(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/$(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"
|
||||||
|
|
||||||
@@ -46,6 +48,7 @@ uninstall:
|
|||||||
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)/lib/systemd/system/$(BIN_D).service"
|
rm -f "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
|
||||||
|
rm -rf "$(DESTDIR)$(sysconfdir)/asusd/"
|
||||||
|
|
||||||
update:
|
update:
|
||||||
cargo update
|
cargo update
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ tokio = { version = "^0.2.4", features = ["rt-threaded", "sync"] }
|
|||||||
serde = "^1.0"
|
serde = "^1.0"
|
||||||
serde_derive = "^1.0"
|
serde_derive = "^1.0"
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
|
toml = "0.4.6"
|
||||||
|
|
||||||
# Device control
|
# Device control
|
||||||
sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
sysfs-class = "^0.1.2" # used for backlight control and baord ID
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use serde_derive::{Deserialize, Serialize};
|
|||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
|
|
||||||
pub static CONFIG_PATH: &str = "/etc/asusd.conf";
|
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Serialize)]
|
#[derive(Default, Deserialize, Serialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
|||||||
@@ -42,20 +42,20 @@ impl crate::Controller for CtrlAnimeDisplay {
|
|||||||
type A = Vec<Vec<u8>>;
|
type A = Vec<Vec<u8>>;
|
||||||
|
|
||||||
/// Spawns two tasks which continuously check for changes
|
/// Spawns two tasks which continuously check for changes
|
||||||
fn spawn_task(
|
fn spawn_task_loop(
|
||||||
mut self,
|
mut self,
|
||||||
_: Arc<Mutex<Config>>,
|
_: Arc<Mutex<Config>>,
|
||||||
mut recv: Receiver<Self::A>,
|
mut recv: Receiver<Self::A>,
|
||||||
_: Option<Arc<SyncConnection>>,
|
_: Option<Arc<SyncConnection>>,
|
||||||
_: Option<Arc<Signal<()>>>,
|
_: Option<Arc<Signal<()>>>,
|
||||||
) -> JoinHandle<()> {
|
) -> Vec<JoinHandle<()>> {
|
||||||
tokio::spawn(async move {
|
vec![tokio::spawn(async move {
|
||||||
while let Some(image) = recv.recv().await {
|
while let Some(image) = recv.recv().await {
|
||||||
self.do_command(AnimatrixCommand::WriteImage(image))
|
self.do_command(AnimatrixCommand::WriteImage(image))
|
||||||
.await
|
.await
|
||||||
.unwrap_or_else(|err| warn!("{}", err));
|
.unwrap_or_else(|err| warn!("{}", err));
|
||||||
}
|
}
|
||||||
})
|
})]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, _: &mut Config) -> Result<(), Box<dyn Error>> {
|
async fn reload_from_config(&mut self, _: &mut Config) -> Result<(), Box<dyn Error>> {
|
||||||
|
|||||||
@@ -23,20 +23,20 @@ impl crate::Controller for CtrlCharge {
|
|||||||
type A = u8;
|
type A = u8;
|
||||||
|
|
||||||
/// Spawns two tasks which continuously check for changes
|
/// Spawns two tasks which continuously check for changes
|
||||||
fn spawn_task(
|
fn spawn_task_loop(
|
||||||
self,
|
self,
|
||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
mut recv: Receiver<Self::A>,
|
mut recv: Receiver<Self::A>,
|
||||||
_: Option<Arc<SyncConnection>>,
|
_: Option<Arc<SyncConnection>>,
|
||||||
_: Option<Arc<Signal<()>>>,
|
_: Option<Arc<Signal<()>>>,
|
||||||
) -> JoinHandle<()> {
|
) -> Vec<JoinHandle<()>> {
|
||||||
tokio::spawn(async move {
|
vec![tokio::spawn(async move {
|
||||||
while let Some(n) = recv.recv().await {
|
while let Some(n) = recv.recv().await {
|
||||||
let mut config = config.lock().await;
|
let mut config = config.lock().await;
|
||||||
self.set_charge_limit(n, &mut config)
|
self.set_charge_limit(n, &mut config)
|
||||||
.unwrap_or_else(|err| warn!("{:?}", err));
|
.unwrap_or_else(|err| warn!("{:?}", err));
|
||||||
}
|
}
|
||||||
})
|
})]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
||||||
|
|||||||
@@ -26,39 +26,40 @@ impl crate::Controller for CtrlFanAndCPU {
|
|||||||
type A = u8;
|
type A = u8;
|
||||||
|
|
||||||
/// Spawns two tasks which continuously check for changes
|
/// Spawns two tasks which continuously check for changes
|
||||||
fn spawn_task(
|
fn spawn_task_loop(
|
||||||
self,
|
self,
|
||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
mut recv: Receiver<Self::A>,
|
mut recv: Receiver<Self::A>,
|
||||||
_: Option<Arc<SyncConnection>>,
|
_: Option<Arc<SyncConnection>>,
|
||||||
_: Option<Arc<Signal<()>>>,
|
_: Option<Arc<Signal<()>>>,
|
||||||
) -> JoinHandle<()> {
|
) -> Vec<JoinHandle<()>> {
|
||||||
let gate1 = Arc::new(Mutex::new(self));
|
let gate1 = Arc::new(Mutex::new(self));
|
||||||
let gate2 = gate1.clone();
|
let gate2 = gate1.clone();
|
||||||
let config1 = config.clone();
|
let config1 = config.clone();
|
||||||
// spawn an endless loop
|
// spawn an endless loop
|
||||||
tokio::spawn(async move {
|
vec![
|
||||||
while let Some(mode) = recv.recv().await {
|
tokio::spawn(async move {
|
||||||
let mut config = config1.lock().await;
|
while let Some(mode) = recv.recv().await {
|
||||||
if let Ok(mut lock) = gate1.try_lock() {
|
let mut config = config1.lock().await;
|
||||||
lock.set_fan_mode(mode, &mut config)
|
if let Ok(mut lock) = gate1.try_lock() {
|
||||||
.unwrap_or_else(|err| warn!("{:?}", err));
|
lock.set_fan_mode(mode, &mut config)
|
||||||
}
|
.unwrap_or_else(|err| warn!("{:?}", err));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
// need to watch file path
|
|
||||||
// TODO: split this out to a struct CtrlFanAndCPUWatcher or similar
|
|
||||||
tokio::spawn(async move {
|
|
||||||
loop {
|
|
||||||
if let Ok(mut lock) = gate2.try_lock() {
|
|
||||||
let mut config = config.lock().await;
|
|
||||||
lock.fan_mode_check_change(&mut config)
|
|
||||||
.unwrap_or_else(|err| warn!("{:?}", err));
|
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
// need to watch file path
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
if let Ok(mut lock) = gate2.try_lock() {
|
||||||
|
let mut config = config.lock().await;
|
||||||
|
lock.fan_mode_check_change(&mut config)
|
||||||
|
.unwrap_or_else(|err| warn!("{:?}", err));
|
||||||
|
}
|
||||||
|
|
||||||
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
|
tokio::time::delay_for(std::time::Duration::from_millis(500)).await;
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
||||||
|
|||||||
@@ -30,14 +30,14 @@ impl crate::Controller for CtrlKbdBacklight {
|
|||||||
type A = AuraModes;
|
type A = AuraModes;
|
||||||
|
|
||||||
/// Spawns two tasks which continuously check for changes
|
/// Spawns two tasks which continuously check for changes
|
||||||
fn spawn_task(
|
fn spawn_task_loop(
|
||||||
mut self,
|
mut self,
|
||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
mut recv: Receiver<Self::A>,
|
mut recv: Receiver<Self::A>,
|
||||||
connection: Option<Arc<SyncConnection>>,
|
connection: Option<Arc<SyncConnection>>,
|
||||||
signal: Option<Arc<Signal<()>>>,
|
signal: Option<Arc<Signal<()>>>,
|
||||||
) -> JoinHandle<()> {
|
) -> Vec<JoinHandle<()>> {
|
||||||
tokio::spawn(async move {
|
vec![tokio::spawn(async move {
|
||||||
while let Some(command) = recv.recv().await {
|
while let Some(command) = recv.recv().await {
|
||||||
let mut config = config.lock().await;
|
let mut config = config.lock().await;
|
||||||
match &command {
|
match &command {
|
||||||
@@ -65,7 +65,7 @@ impl crate::Controller for CtrlKbdBacklight {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})]
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
async fn reload_from_config(&mut self, config: &mut Config) -> Result<(), Box<dyn Error>> {
|
||||||
|
|||||||
@@ -41,9 +41,13 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// DBUS processing takes 6ms if not tokiod
|
// DBUS processing takes 6ms if not tokiod
|
||||||
pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
||||||
let laptop = match_laptop();
|
let laptop = match_laptop();
|
||||||
let mut config = Config::default().load(laptop.supported_modes());
|
let mut config = if let Some(laptop) = laptop.as_ref() {
|
||||||
|
Config::default().load(laptop.supported_modes())
|
||||||
|
} else {
|
||||||
|
Config::default().load(&[])
|
||||||
|
};
|
||||||
|
|
||||||
let mut led_control =
|
let mut led_control = if let Some(laptop) = laptop {
|
||||||
CtrlKbdBacklight::new(laptop.usb_product(), laptop.supported_modes().to_owned())
|
CtrlKbdBacklight::new(laptop.usb_product(), laptop.supported_modes().to_owned())
|
||||||
.map_or_else(
|
.map_or_else(
|
||||||
|err| {
|
|err| {
|
||||||
@@ -51,7 +55,10 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
Some,
|
Some,
|
||||||
);
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut charge_control = CtrlCharge::new().map_or_else(
|
let mut charge_control = CtrlCharge::new().map_or_else(
|
||||||
|err| {
|
|err| {
|
||||||
@@ -134,19 +141,19 @@ pub async fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
// Begin all tasks
|
// Begin all tasks
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
if let Ok(ctrl) = CtrlAnimeDisplay::new() {
|
if let Ok(ctrl) = CtrlAnimeDisplay::new() {
|
||||||
handles.push(ctrl.spawn_task(config.clone(), animatrix_recv, None, None));
|
handles.append(&mut ctrl.spawn_task_loop(config.clone(), animatrix_recv, None, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ctrl) = fan_control.take() {
|
if let Some(ctrl) = fan_control.take() {
|
||||||
handles.push(ctrl.spawn_task(config.clone(), fan_mode_recv, None, None));
|
handles.append(&mut ctrl.spawn_task_loop(config.clone(), fan_mode_recv, None, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ctrl) = charge_control.take() {
|
if let Some(ctrl) = charge_control.take() {
|
||||||
handles.push(ctrl.spawn_task(config.clone(), charge_limit_recv, None, None));
|
handles.append(&mut ctrl.spawn_task_loop(config.clone(), charge_limit_recv, None, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ctrl) = led_control.take() {
|
if let Some(ctrl) = led_control.take() {
|
||||||
handles.push(ctrl.spawn_task(
|
handles.append(&mut ctrl.spawn_task_loop(
|
||||||
config.clone(),
|
config.clone(),
|
||||||
aura_command_recv,
|
aura_command_recv,
|
||||||
Some(connection.clone()),
|
Some(connection.clone()),
|
||||||
|
|||||||
@@ -1,112 +1,13 @@
|
|||||||
use asus_nb::aura_modes::{
|
use asus_nb::aura_modes::{AuraModes, BREATHING, STATIC, STROBE};
|
||||||
AuraModes, BREATHING, COMET, FLASH, HIGHLIGHT, LASER, MULTISTATIC, PULSE, RAIN, RAINBOW, RGB,
|
|
||||||
RIPPLE, STAR, STATIC, STROBE,
|
|
||||||
};
|
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
pub static LEDMODE_CONFIG_PATH: &str = "/etc/asusd/asusd-ledmodes.toml";
|
||||||
|
|
||||||
static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
|
static HELP_ADDRESS: &str = "https://gitlab.com/asus-linux/asus-nb-ctrl";
|
||||||
|
|
||||||
pub fn match_laptop() -> LaptopBase {
|
|
||||||
for device in rusb::devices().unwrap().iter() {
|
|
||||||
let device_desc = device.device_descriptor().unwrap();
|
|
||||||
if device_desc.vendor_id() == 0x0b05 {
|
|
||||||
match device_desc.product_id() {
|
|
||||||
0x1866 => return select_1866_device("1866".to_owned()),
|
|
||||||
0x1869 => return select_1866_device("1869".to_owned()),
|
|
||||||
0x1854 => {
|
|
||||||
info!("Found GL753 or similar");
|
|
||||||
return LaptopBase {
|
|
||||||
usb_product: "1854".to_string(),
|
|
||||||
supported_modes: vec![STATIC, BREATHING, STROBE],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic!("could not match laptop");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn select_1866_device(prod: String) -> LaptopBase {
|
|
||||||
let dmi = sysfs_class::DmiId::default();
|
|
||||||
let board_name = dmi.board_name().expect("Could not get board_name");
|
|
||||||
let prod_name = dmi.product_name().expect("Could not get board_name");
|
|
||||||
|
|
||||||
info!("Product name: {}", prod_name.trim());
|
|
||||||
info!("Board name: {}", board_name.trim());
|
|
||||||
|
|
||||||
let mut laptop = LaptopBase {
|
|
||||||
usb_product: prod,
|
|
||||||
supported_modes: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
// AniMe, no RGB
|
|
||||||
if board_name.starts_with("GA401")
|
|
||||||
|| board_name.starts_with("GA502")
|
|
||||||
|| board_name.starts_with("GU502")
|
|
||||||
{
|
|
||||||
info!("No RGB control available");
|
|
||||||
// RGB, per-key settings, no zones
|
|
||||||
} else if board_name.starts_with("GX502")
|
|
||||||
|| board_name.starts_with("GX701")
|
|
||||||
|| board_name.starts_with("G531")
|
|
||||||
|| board_name.starts_with("GL531")
|
|
||||||
|| board_name.starts_with("G532")
|
|
||||||
{
|
|
||||||
laptop.supported_modes = vec![
|
|
||||||
STATIC, BREATHING, STROBE, RAINBOW, STAR, RAIN, HIGHLIGHT, LASER, RIPPLE, PULSE, COMET,
|
|
||||||
FLASH, RGB,
|
|
||||||
];
|
|
||||||
} else if board_name.starts_with("G531") || board_name.starts_with("G731") {
|
|
||||||
laptop.supported_modes = vec![
|
|
||||||
STATIC,
|
|
||||||
BREATHING,
|
|
||||||
STROBE,
|
|
||||||
RAINBOW,
|
|
||||||
STAR,
|
|
||||||
RAIN,
|
|
||||||
HIGHLIGHT,
|
|
||||||
LASER,
|
|
||||||
RIPPLE,
|
|
||||||
PULSE,
|
|
||||||
COMET,
|
|
||||||
FLASH,
|
|
||||||
MULTISTATIC,
|
|
||||||
RGB,
|
|
||||||
];
|
|
||||||
// RGB, limited effects, no zones
|
|
||||||
} else if board_name.starts_with("G512LI") || board_name.starts_with("G712LI") {
|
|
||||||
laptop.supported_modes = vec![STATIC, BREATHING, STROBE, RAINBOW, PULSE];
|
|
||||||
// RGB, limited effects, 4-zone RGB
|
|
||||||
} else if board_name.starts_with("GM501")
|
|
||||||
|| board_name.starts_with("GX531")
|
|
||||||
|| board_name.starts_with("G512")
|
|
||||||
|| board_name.starts_with("G712")
|
|
||||||
{
|
|
||||||
laptop.supported_modes = vec![STATIC, BREATHING, STROBE, RAINBOW, PULSE, MULTISTATIC];
|
|
||||||
} else {
|
|
||||||
warn!(
|
|
||||||
"Unsupported laptop, please request support at {}",
|
|
||||||
HELP_ADDRESS
|
|
||||||
);
|
|
||||||
warn!("Continuing with minimal support")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !laptop.supported_modes.is_empty() {
|
|
||||||
info!("Supported Keyboard LED modes are:");
|
|
||||||
for mode in &laptop.supported_modes {
|
|
||||||
let mode = <&str>::from(&<AuraModes>::from(*mode));
|
|
||||||
info!("- {}", mode);
|
|
||||||
}
|
|
||||||
info!(
|
|
||||||
"If these modes are incorrect or missing please request support at {}",
|
|
||||||
HELP_ADDRESS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
laptop
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LaptopBase {
|
pub struct LaptopBase {
|
||||||
usb_product: String,
|
usb_product: String,
|
||||||
supported_modes: Vec<u8>,
|
supported_modes: Vec<u8>,
|
||||||
@@ -120,3 +21,120 @@ impl LaptopBase {
|
|||||||
&self.supported_modes
|
&self.supported_modes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn match_laptop() -> Option<LaptopBase> {
|
||||||
|
for device in rusb::devices().unwrap().iter() {
|
||||||
|
let device_desc = device.device_descriptor().unwrap();
|
||||||
|
if device_desc.vendor_id() == 0x0b05 {
|
||||||
|
match device_desc.product_id() {
|
||||||
|
0x1866 => {
|
||||||
|
let laptop = select_1866_device("1866".to_owned());
|
||||||
|
print_modes(&laptop.supported_modes);
|
||||||
|
return Some(laptop);
|
||||||
|
}
|
||||||
|
0x1869 => return Some(select_1866_device("1869".to_owned())),
|
||||||
|
0x1854 => {
|
||||||
|
info!("Found GL753 or similar");
|
||||||
|
return Some(LaptopBase {
|
||||||
|
usb_product: "1854".to_string(),
|
||||||
|
supported_modes: vec![STATIC, BREATHING, STROBE],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_1866_device(prod: String) -> LaptopBase {
|
||||||
|
let dmi = sysfs_class::DmiId::default();
|
||||||
|
let board_name = dmi.board_name().expect("Could not get board_name");
|
||||||
|
let prod_family = dmi.product_family().expect("Could not get product_family");
|
||||||
|
let prod_name = dmi.product_name().expect("Could not get product_name");
|
||||||
|
|
||||||
|
info!("Product name: {}", prod_name.trim());
|
||||||
|
info!("Board name: {}", board_name.trim());
|
||||||
|
|
||||||
|
let mut laptop = LaptopBase {
|
||||||
|
usb_product: prod,
|
||||||
|
supported_modes: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(modes) = LEDModeGroup::load_from_config() {
|
||||||
|
if let Some(led_modes) = modes.matcher(&prod_family, &board_name) {
|
||||||
|
laptop.supported_modes = led_modes;
|
||||||
|
return laptop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!(
|
||||||
|
"Unsupported laptop, please request support at {}",
|
||||||
|
HELP_ADDRESS
|
||||||
|
);
|
||||||
|
warn!("Continuing with minimal support");
|
||||||
|
|
||||||
|
laptop
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_modes(supported_modes: &[u8]) {
|
||||||
|
if !supported_modes.is_empty() {
|
||||||
|
info!("Supported Keyboard LED modes are:");
|
||||||
|
for mode in supported_modes {
|
||||||
|
let mode = <&str>::from(&<AuraModes>::from(*mode));
|
||||||
|
info!("- {}", mode);
|
||||||
|
}
|
||||||
|
info!(
|
||||||
|
"If these modes are incorrect or missing please request support at {}",
|
||||||
|
HELP_ADDRESS
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!("No RGB control available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
struct LEDModeGroup {
|
||||||
|
led_modes: Vec<LEDModes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LEDModeGroup {
|
||||||
|
/// Consumes the LEDModes
|
||||||
|
fn matcher(self, prod_family: &str, board_name: &str) -> Option<Vec<u8>> {
|
||||||
|
for led_modes in self.led_modes {
|
||||||
|
if prod_family.contains(&led_modes.prod_family) {
|
||||||
|
for board in led_modes.board_names {
|
||||||
|
if board_name.contains(&board) {
|
||||||
|
info!("Matched to {} {}", led_modes.prod_family, board);
|
||||||
|
return Some(led_modes.led_modes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_from_config() -> Option<Self> {
|
||||||
|
if let Ok(mut file) = OpenOptions::new().read(true).open(&LEDMODE_CONFIG_PATH) {
|
||||||
|
let mut buf = String::new();
|
||||||
|
if let Ok(l) = file.read_to_string(&mut buf) {
|
||||||
|
if l == 0 {
|
||||||
|
warn!("{} is empty", LEDMODE_CONFIG_PATH);
|
||||||
|
} else {
|
||||||
|
return Some(toml::from_str(&buf).unwrap_or_else(|_| {
|
||||||
|
panic!("Could not deserialise {}", LEDMODE_CONFIG_PATH)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
warn!("Does {} exist?", LEDMODE_CONFIG_PATH);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
struct LEDModes {
|
||||||
|
prod_family: String,
|
||||||
|
board_names: Vec<String>,
|
||||||
|
led_modes: Vec<u8>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,11 +35,11 @@ pub trait Controller {
|
|||||||
|
|
||||||
/// Spawn an infinitely running task (usually) which checks a Receiver for input,
|
/// Spawn an infinitely running task (usually) which checks a Receiver for input,
|
||||||
/// and may send a signal over dbus
|
/// and may send a signal over dbus
|
||||||
fn spawn_task(
|
fn spawn_task_loop(
|
||||||
self,
|
self,
|
||||||
config: Arc<Mutex<Config>>,
|
config: Arc<Mutex<Config>>,
|
||||||
recv: Receiver<Self::A>,
|
recv: Receiver<Self::A>,
|
||||||
connection: Option<Arc<SyncConnection>>,
|
connection: Option<Arc<SyncConnection>>,
|
||||||
signal: Option<Arc<Signal<()>>>,
|
signal: Option<Arc<Signal<()>>>,
|
||||||
) -> JoinHandle<()>;
|
) -> Vec<JoinHandle<()>>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub const PULSE: u8 = 0x0a;
|
|||||||
pub const COMET: u8 = 0x0b;
|
pub const COMET: u8 = 0x0b;
|
||||||
pub const FLASH: u8 = 0x0c;
|
pub const FLASH: u8 = 0x0c;
|
||||||
pub const MULTISTATIC: u8 = 0x0d;
|
pub const MULTISTATIC: u8 = 0x0d;
|
||||||
pub const RGB: u8 = 0xf0;
|
pub const RGB: u8 = 0xff;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
pub struct Colour(pub u8, pub u8, pub u8);
|
pub struct Colour(pub u8, pub u8, pub u8);
|
||||||
|
|||||||
34
data/asusd-ledmodes.toml
Normal file
34
data/asusd-ledmodes.toml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
[[led_modes]]
|
||||||
|
prod_family = "Zephyrus S"
|
||||||
|
board_names = ["GX502", "GX701", "G531", "GL531", "G532"]
|
||||||
|
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 255]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "ROG Strix"
|
||||||
|
board_names = ["GX531", "G512LV", "G712LV"]
|
||||||
|
led_modes = [0, 1, 2, 3, 10, 13]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "Zephyrus"
|
||||||
|
board_names = ["GM501GM", "GX531"]
|
||||||
|
led_modes = [0, 1, 2, 3, 10, 13]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "ROG Strix"
|
||||||
|
board_names = ["G512LI", "G712LI"]
|
||||||
|
led_modes = [0, 1, 2, 3, 10]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "Strix"
|
||||||
|
board_names = ["G731GV", "G731GW", "G531GV", "G531GW"]
|
||||||
|
led_modes = [0, 1, 2, 3, 13]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "Strix"
|
||||||
|
board_names = ["G731GT", "G731GU", "G531GT", "G531GU"]
|
||||||
|
led_modes = [0, 1, 2, 3]
|
||||||
|
|
||||||
|
[[led_modes]]
|
||||||
|
prod_family = "Strix Scar"
|
||||||
|
board_names = ["G531", "G731"]
|
||||||
|
led_modes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 255]
|
||||||
59237
reverse_eng/dsl/G531GT.dsl
Normal file
59237
reverse_eng/dsl/G531GT.dsl
Normal file
File diff suppressed because it is too large
Load Diff
6
reverse_eng/g531/board_details
Normal file
6
reverse_eng/g531/board_details
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
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
|
||||||
|
|
||||||
130
reverse_eng/g531/laptop_info.txt
Normal file
130
reverse_eng/g531/laptop_info.txt
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
|
||||||
|
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
|
||||||
Reference in New Issue
Block a user