Compare commits

..
11 Commits
10 changed files with 180 additions and 30 deletions
+1 -1
View File
@@ -90,7 +90,7 @@ pages:
- rm -rf public - rm -rf public
- mkdir public - mkdir public
- cp -R ci-target/doc/* 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: artifacts:
paths: paths:
- public - public
+6
View File
@@ -1,5 +1,11 @@
# Changelog # Changelog
## [6.3.1]
### Changes
- Removed a lighting mode that is unavailable in windows to G835L: thanks to @shevchenko0013 again!
## [6.3.0] ## [6.3.0]
### Changed ### Changed
+5 -3
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. 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). Support for TDP is tied to the new asus-armoury driver: available mainline since linux 6.19: everything older is not supported.
Z13 devices will need [these](https://lore.kernel.org/linux-input/20240416090402.31057-1-luke@ljones.dev/T/#t)
## X11 support ## 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. 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.
+71 -2
View File
@@ -25,6 +25,30 @@ pub struct Aura {
impl Aura { impl Aura {
/// Initialise the device if required. /// Initialise the device if required.
pub async fn do_initialization(&self) -> Result<(), RogError> { 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(()) 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 = [ 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)?; hid_raw.write_bytes(&msg)?;
} }
+23
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>
+19 -1
View File
@@ -570,7 +570,7 @@
device_name: "G835L", device_name: "G835L",
product_id: "", product_id: "",
layout_name: "g814ji-per-key", 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: [], basic_zones: [],
advanced_type: PerKey, advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo], power_zones: [Keyboard, Lightbar, Logo],
@@ -971,6 +971,24 @@
advanced_type: r#None, advanced_type: r#None,
power_zones: [Keyboard], 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", device_name: "RC71L",
product_id: "", product_id: "",
+20 -11
View File
@@ -123,7 +123,8 @@ impl AuraPowerState {
| ((self.shutdown as u32) << 7) | ((self.shutdown as u32) << 7)
} }
PowerZones::Lightbar => { 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.awake as u32) << (7 + 3))
| ((self.sleep as u32) << (7 + 4)) | ((self.sleep as u32) << (7 + 4))
| ((self.shutdown as u32) << (7 + 5)) | ((self.shutdown as u32) << (7 + 5))
@@ -133,12 +134,20 @@ impl AuraPowerState {
| ((self.awake as u32) << (15 + 2)) | ((self.awake as u32) << (15 + 2))
| ((self.sleep as u32) << (15 + 3)) | ((self.sleep as u32) << (15 + 3))
| ((self.shutdown as u32) << (15 + 4)) | ((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 => { PowerZones::RearGlow => {
((self.boot as u32) << (23 + 1)) ((self.boot as u32) << (23 + 1))
| ((self.awake as u32) << (23 + 2)) | ((self.awake as u32) << (23 + 2))
| ((self.sleep as u32) << (23 + 3)) | ((self.sleep as u32) << (23 + 3))
| ((self.shutdown as u32) << (23 + 4)) | ((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, PowerZones::None | PowerZones::KeyboardAndLightbar => 0,
} }
@@ -618,19 +627,19 @@ mod test {
assert_eq!(shut_keyb_, "10000000, 00000000, 00000000, 00000000"); assert_eq!(shut_keyb_, "10000000, 00000000, 00000000, 00000000");
// //
assert_eq!(boot_bar__, "00000000, 00000010, 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!(sleep_bar_, "00000000, 00001000, 00000000, 00000000");
assert_eq!(shut_bar__, "00000000, 00010000, 00000000, 00000000"); assert_eq!(shut_bar__, "00000000, 00010000, 00000000, 00000000");
// //
assert_eq!(boot_lid__, "00000000, 00000000, 00000001, 00000000"); assert_eq!(boot_lid__, "00000000, 00000000, 00010001, 00000000");
assert_eq!(awake_lid_, "00000000, 00000000, 00000010, 00000000"); assert_eq!(awake_lid_, "00000000, 00000000, 00100010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 00000100, 00000000"); assert_eq!(sleep_lid_, "00000000, 00000000, 01000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 00001000, 00000000"); assert_eq!(shut_lid__, "00000000, 00000000, 10001000, 00000000");
// //
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00000001"); assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00010001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00000010"); assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00100010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 00000100"); assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 01000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 00001000"); assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 10001000");
// All on // All on
let byte1 = to_binary_string_post2021(&LaptopAuraPower { 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");
} }
} }
+2 -2
View File
@@ -106,10 +106,10 @@ impl From<&str> for AuraDeviceType {
match s.to_lowercase().trim_start_matches("0x") { match s.to_lowercase().trim_start_matches("0x") {
"tuf" => AuraDeviceType::LaptopKeyboardTuf, "tuf" => AuraDeviceType::LaptopKeyboardTuf,
"1932" => AuraDeviceType::ScsiExtDisk, "1932" => AuraDeviceType::ScsiExtDisk,
"1866" | "18c6" | "1869" | "1854" => Self::LaptopKeyboardPre2021, "1866" | "1869" | "1854" => Self::LaptopKeyboardPre2021,
"1abe" | "1b4c" => Self::Ally, "1abe" | "1b4c" => Self::Ally,
"19b3" | "193b" => Self::AnimeOrSlash, "19b3" | "193b" => Self::AnimeOrSlash,
"19b6" => Self::LaptopKeyboard2021, "19b6" | "1a30" | "18c6" => Self::LaptopKeyboard2021,
_ => Self::Unknown, _ => Self::Unknown,
} }
} }
+13 -4
View File
@@ -162,7 +162,6 @@ impl CurveData {
/// Write this curve to the device fan specified by `self.fan` /// Write this curve to the device fan specified by `self.fan`
pub fn write_to_device(&self, device: &mut Device) -> std::io::Result<()> { pub fn write_to_device(&self, device: &mut Device) -> std::io::Result<()> {
let pwm_num: char = self.fan.into(); let pwm_num: char = self.fan.into();
let enable = if self.enabled { '1' } else { '2' };
for (index, out) in self.pwm.iter().enumerate() { for (index, out) in self.pwm.iter().enumerate() {
let pwm = pwm_str(pwm_num, index); let pwm = pwm_str(pwm_num, index);
@@ -176,10 +175,20 @@ impl CurveData {
device.set_attribute_value(&temp, out.to_string())?; 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 device
.set_attribute_value(format!("pwm{pwm_num}_enable"), enable.to_string()) .set_attribute_value(&enable_attr, enable.to_string())
.map_err(|e| error!("Failed to set pwm{pwm_num}_enable to {enable}: {e:?}")) .map_err(|e| error!("Failed to set {enable_attr} to {enable}: {e:?}"))
.ok(); .ok();
Ok(()) Ok(())
} }
+20 -6
View File
@@ -181,15 +181,29 @@ impl FanCurveProfiles {
PlatformProfile::Quiet | PlatformProfile::LowPower => &mut self.quiet, PlatformProfile::Quiet | PlatformProfile::LowPower => &mut self.quiet,
PlatformProfile::Custom => &mut self.custom, 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)?; 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) { for fan in fans.iter().filter(|f| f.enabled) {
debug!("write_profile_curve_to_platform: writing profile:{profile}, {fan:?}"); debug!(
fan.write_to_device(device)?; "write_profile_curve_to_platform: enabling fan for profile:{profile}, {:?}",
fan.fan
);
fan.set_enable(device)?;
} }
Ok(()) Ok(())
} }