Compare commits

...

11 Commits

Author SHA1 Message Date
rforced
5d52626e32 Merge branch 'fix-z13-2025-1' into 'main'
Draft: Fixes for Asus z13 2025

See merge request asus-linux/asusctl!245
2026-01-16 16:37:37 -05:00
Josh Dariano
f471f340d4 Fix fan controls on z13 2026-01-16 16:37:15 -05:00
Josh Dariano
8095ac34ed Fix formatting 2026-01-16 15:48:02 -05:00
Josh Dariano
9d629b62ca Fix aura backlight for z13 2026-01-16 15:33:30 -05:00
Josh Dariano
5282c56f59 Merge remote-tracking branch 'rforced/fix-z13-2025' 2026-01-16 14:13:45 -05:00
Josh Dariano
0d2cd4eb10 Fix keyboard light 2026-01-16 13:57:35 -05:00
Denis Benato
b20ecf5378 chore: README.md edits 2026-01-16 19:53:58 +01:00
Denis Benato
ade839e981 chore: Update README.md 2026-01-16 19:18:15 +01:00
Denis Benato
d625c279a6 fix: G835LW doesn't have pulse available in windows 2026-01-16 19:13:00 +01:00
Denis Benato
5ea14be3fa chore: add extra/index.html: docs landing redirect to asusctl docs 2026-01-14 14:25:13 +01:00
Denis Benato
64c2e55db4 chore: prepare for a new version 2026-01-14 02:27:39 +01:00
10 changed files with 180 additions and 30 deletions

View File

@@ -90,7 +90,7 @@ pages:
- rm -rf public
- mkdir public
- cp -R ci-target/doc/* public
- cp extra/index.html public
- if [ -f extra/index.html ]; then cp extra/index.html public; else echo "no extra/index.html to copy"; fi
artifacts:
paths:
- public

View File

@@ -1,5 +1,11 @@
# Changelog
## [6.3.1]
### Changes
- Removed a lighting mode that is unavailable in windows to G835L: thanks to @shevchenko0013 again!
## [6.3.0]
### Changed

View File

@@ -13,9 +13,7 @@ Now includes a GUI, `rog-control-center`.
Due to on-going driver work the minimum suggested kernel version is always **the latest*, as improvements and fixes are continuous.
Support for some new features is not avilable unless you run a patched kernel with the work I am doing [in this github repo](https://github.com/flukejones/linux/tree/wip/ally-6.13). Use the linked branch, or `wip/ally-6.12`. Everything that is done here is upstreamed eventually (a long process).
Z13 devices will need [these](https://lore.kernel.org/linux-input/20240416090402.31057-1-luke@ljones.dev/T/#t)
Support for TDP is tied to the new asus-armoury driver: available mainline since linux 6.19: everything older is not supported.
## X11 support
@@ -180,3 +178,7 @@ Reference to any ASUS products, services, processes, or other information and/or
The use of ROG and ASUS trademarks within this website and associated tools and libraries is only to provide a recognisable identifier to users to enable them to associate that these tools will work with ASUS ROG laptops.
---
## AI Disaclaimer
Portions of this code have been written by various AI tools and reviewed by the maintainer exaclty as with every other contribution.

View File

@@ -25,6 +25,30 @@ pub struct Aura {
impl Aura {
/// Initialise the device if required.
pub async fn do_initialization(&self) -> Result<(), RogError> {
if let Some(hid) = &self.hid {
let hid = hid.lock().await;
let init_1: [u8; 2] = [
0x5d, 0xb9,
];
let init_2 = b"]ASUS Tech.Inc.";
let init_3: [u8; 6] = [
0x5d, 0x05, 0x20, 0x31, 0, 0x1a,
];
hid.write_bytes(&init_1)?;
hid.write_bytes(init_2)?;
hid.write_bytes(&init_3)?;
let config = self.config.lock().await;
if config.support_data.device_name.contains("GZ30")
|| config.support_data.device_name.contains("Z13")
{
let z13_init: [u8; 4] = [
0x5d, 0xc0, 0x03, 0x01,
];
hid.write_bytes(&z13_init)?;
}
}
Ok(())
}
@@ -152,9 +176,54 @@ impl Aura {
}
}
let bytes = config.enabled.to_bytes(config.led_type);
let mut enabled = config.enabled.clone();
if config.support_data.device_name.contains("GZ30")
|| config.support_data.device_name.contains("Z13")
{
let logo_state = enabled
.states
.iter()
.find(|s| s.zone == PowerZones::Logo)
.cloned();
if let Some(logo) = logo_state {
let mut lid_found = false;
let mut bar_found = false;
for s in enabled.states.iter_mut() {
if s.zone == PowerZones::Lid {
s.boot = logo.boot;
s.awake = logo.awake;
s.sleep = logo.sleep;
s.shutdown = logo.shutdown;
lid_found = true;
}
if s.zone == PowerZones::Lightbar {
s.boot = logo.boot;
s.awake = logo.awake;
s.sleep = logo.sleep;
s.shutdown = logo.shutdown;
bar_found = true;
}
}
if !lid_found {
let mut new_state = logo;
new_state.zone = PowerZones::Lid;
enabled.states.push(new_state.clone());
new_state.zone = PowerZones::Lightbar;
enabled.states.push(new_state);
} else if !bar_found {
// Lid found but not bar?
let mut new_state = logo;
new_state.zone = PowerZones::Lightbar;
enabled.states.push(new_state);
}
}
}
let bytes = enabled.to_bytes(config.led_type);
let msg = [
0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3],
0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3], 0xff,
];
hid_raw.write_bytes(&msg)?;
}

23
extra/index.html Normal file
View File

@@ -0,0 +1,23 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>asusctl docs</title>
<!-- Redirect to the generated crate docs -->
<meta http-equiv="refresh" content="0;url=asusctl/index.html">
<link rel="canonical" href="asusctl/index.html">
<style>
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial; color:#222; display:flex; align-items:center; justify-content:center; height:100vh; margin:0 }
.box { text-align:center }
a { color: #0366d6 }
</style>
</head>
<body>
<div class="box">
<h1>asusctl documentation</h1>
<p>Redirecting to the generated docs — if your browser doesn't redirect automatically, <a href="asusctl/index.html">click here</a>.</p>
<p>If you expected a different landing page, update <code>extra/index.html</code> accordingly.</p>
</div>
</body>
</html>

View File

@@ -570,7 +570,7 @@
device_name: "G835L",
product_id: "",
layout_name: "g814ji-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
@@ -971,6 +971,24 @@
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "GZ302",
product_id: "18c6",
layout_name: "",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Logo],
),
(
device_name: "GZ302",
product_id: "1a30",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "RC71L",
product_id: "",

View File

@@ -123,7 +123,8 @@ impl AuraPowerState {
| ((self.shutdown as u32) << 7)
}
PowerZones::Lightbar => {
((self.boot as u32) << (7 + 2))
((self.awake as u32) << (7 + 1))
| ((self.boot as u32) << (7 + 2))
| ((self.awake as u32) << (7 + 3))
| ((self.sleep as u32) << (7 + 4))
| ((self.shutdown as u32) << (7 + 5))
@@ -133,12 +134,20 @@ impl AuraPowerState {
| ((self.awake as u32) << (15 + 2))
| ((self.sleep as u32) << (15 + 3))
| ((self.shutdown as u32) << (15 + 4))
| ((self.boot as u32) << (15 + 5))
| ((self.awake as u32) << (15 + 6))
| ((self.sleep as u32) << (15 + 7))
| ((self.shutdown as u32) << (15 + 8))
}
PowerZones::RearGlow => {
((self.boot as u32) << (23 + 1))
| ((self.awake as u32) << (23 + 2))
| ((self.sleep as u32) << (23 + 3))
| ((self.shutdown as u32) << (23 + 4))
| ((self.boot as u32) << (23 + 5))
| ((self.awake as u32) << (23 + 6))
| ((self.sleep as u32) << (23 + 7))
| ((self.shutdown as u32) << (23 + 8))
}
PowerZones::None | PowerZones::KeyboardAndLightbar => 0,
}
@@ -618,19 +627,19 @@ mod test {
assert_eq!(shut_keyb_, "10000000, 00000000, 00000000, 00000000");
//
assert_eq!(boot_bar__, "00000000, 00000010, 00000000, 00000000");
assert_eq!(awake_bar_, "00000000, 00000100, 00000000, 00000000");
assert_eq!(awake_bar_, "00000000, 00000101, 00000000, 00000000");
assert_eq!(sleep_bar_, "00000000, 00001000, 00000000, 00000000");
assert_eq!(shut_bar__, "00000000, 00010000, 00000000, 00000000");
//
assert_eq!(boot_lid__, "00000000, 00000000, 00000001, 00000000");
assert_eq!(awake_lid_, "00000000, 00000000, 00000010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 00000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 00001000, 00000000");
assert_eq!(boot_lid__, "00000000, 00000000, 00010001, 00000000");
assert_eq!(awake_lid_, "00000000, 00000000, 00100010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 01000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 10001000, 00000000");
//
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00000001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00000010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 00000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 00001000");
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00010001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00100010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 01000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 10001000");
// All on
let byte1 = to_binary_string_post2021(&LaptopAuraPower {
@@ -657,6 +666,6 @@ mod test {
},
],
});
assert_eq!(byte1, "11111111, 00011110, 00001111, 00001111");
assert_eq!(byte1, "11111111, 00011111, 11111111, 11111111");
}
}

View File

@@ -106,10 +106,10 @@ impl From<&str> for AuraDeviceType {
match s.to_lowercase().trim_start_matches("0x") {
"tuf" => AuraDeviceType::LaptopKeyboardTuf,
"1932" => AuraDeviceType::ScsiExtDisk,
"1866" | "18c6" | "1869" | "1854" => Self::LaptopKeyboardPre2021,
"1866" | "1869" | "1854" => Self::LaptopKeyboardPre2021,
"1abe" | "1b4c" => Self::Ally,
"19b3" | "193b" => Self::AnimeOrSlash,
"19b6" => Self::LaptopKeyboard2021,
"19b6" | "1a30" | "18c6" => Self::LaptopKeyboard2021,
_ => Self::Unknown,
}
}

View File

@@ -162,7 +162,6 @@ impl CurveData {
/// Write this curve to the device fan specified by `self.fan`
pub fn write_to_device(&self, device: &mut Device) -> std::io::Result<()> {
let pwm_num: char = self.fan.into();
let enable = if self.enabled { '1' } else { '2' };
for (index, out) in self.pwm.iter().enumerate() {
let pwm = pwm_str(pwm_num, index);
@@ -176,10 +175,20 @@ impl CurveData {
device.set_attribute_value(&temp, out.to_string())?;
}
// Enable must be done *after* all points are written pwm3_enable
// Note: pwm_enable is set by write_profile_curve_to_platform after all
// curves are written, because on some devices (e.g., ASUS Z13 2025)
// setting any pwm_enable to 2 resets ALL fan enables.
Ok(())
}
/// Set the enable state for this fan curve
pub fn set_enable(&self, device: &mut Device) -> std::io::Result<()> {
let pwm_num: char = self.fan.into();
let enable = if self.enabled { "1" } else { "2" };
let enable_attr = format!("pwm{pwm_num}_enable");
device
.set_attribute_value(format!("pwm{pwm_num}_enable"), enable.to_string())
.map_err(|e| error!("Failed to set pwm{pwm_num}_enable to {enable}: {e:?}"))
.set_attribute_value(&enable_attr, enable.to_string())
.map_err(|e| error!("Failed to set {enable_attr} to {enable}: {e:?}"))
.ok();
Ok(())
}

View File

@@ -181,15 +181,29 @@ impl FanCurveProfiles {
PlatformProfile::Quiet | PlatformProfile::LowPower => &mut self.quiet,
PlatformProfile::Custom => &mut self.custom,
};
for fan in fans.iter().filter(|f| !f.enabled) {
debug!("write_profile_curve_to_platform: writing profile:{profile}, {fan:?}");
// First write all curve data (pwm/temp values) for all fans
for fan in fans.iter() {
debug!("write_profile_curve_to_platform: writing curve data for profile:{profile}, {fan:?}");
fan.write_to_device(device)?;
}
// Write enabled fans last because the kernel currently resets *all* if one is
// disabled
// Then set enables: disabled fans first, then enabled fans last.
// This order is important because on some devices (e.g., ASUS Z13 2025)
// setting any pwm_enable to 2 (disabled) resets ALL fan enables.
for fan in fans.iter().filter(|f| !f.enabled) {
debug!(
"write_profile_curve_to_platform: disabling fan for profile:{profile}, {:?}",
fan.fan
);
fan.set_enable(device)?;
}
for fan in fans.iter().filter(|f| f.enabled) {
debug!("write_profile_curve_to_platform: writing profile:{profile}, {fan:?}");
fan.write_to_device(device)?;
debug!(
"write_profile_curve_to_platform: enabling fan for profile:{profile}, {:?}",
fan.fan
);
fan.set_enable(device)?;
}
Ok(())
}