Skip to content

Commit 03d65ba

Browse files
authored
Merge pull request #14 from utajum/i2c-hid
Add I2C-HID keyboard RGB support and fix power limit controls
2 parents bb286fd + dae37a4 commit 03d65ba

File tree

11 files changed

+655
-14
lines changed

11 files changed

+655
-14
lines changed

.upstream-last-checked

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
f6614776dee111103b2ae8bf03677c17b6104e2f
1+
d9f4a60203d0bde376c10f0918687aea3ae831a3

install/90-ghelper.rules

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,15 @@ SUBSYSTEM=="hwmon", ATTR{name}=="asus_custom_fan_curve", \
105105
SUBSYSTEM=="input", ATTRS{name}=="Asus WMI hotkeys", TAG+="uaccess"
106106

107107
# ── ASUS HID devices (AURA RGB keyboard control) ──
108-
# Grant read/write access to ASUS HID raw devices for non-root AURA control
108+
# Grant read/write access to ASUS HID raw devices for non-root AURA control.
109+
# USB-HID: match via USB parent's idVendor attribute
109110
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0b05", MODE="0666"
110111
SUBSYSTEM=="usb", ATTRS{idVendor}=="0b05", MODE="0666"
112+
# I2C-HID: ASUS keyboards connected via I2C (e.g., FA608PP: ITE51368:00 0B05:19B6)
113+
# have no USB parent, so ATTRS{idVendor} won't match. Match via the HID device
114+
# uevent which contains the vendor ID in HID_ID field.
115+
SUBSYSTEM=="hidraw", ACTION=="add", \
116+
RUN+="/bin/sh -c 'grep -q 00000B05 /sys%p/device/uevent 2>/dev/null && chmod 0666 /dev/%k'"
111117

112118
# ── Backlight ──
113119
SUBSYSTEM=="backlight", ACTION=="add", \

src/Helpers/AppConfig.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ public static bool IsStrixLimitedRGB() =>
421421
ContainsModel("G513R") || ContainsModel("G713QM") || ContainsModel("G713PV") || ContainsModel("G513IE") ||
422422
ContainsModel("G713RC") || ContainsModel("G713IC") || ContainsModel("G713PU") || ContainsModel("G513QM") ||
423423
ContainsModel("G513QC") || ContainsModel("G531G") || ContainsModel("G615JMR") || ContainsModel("G615LM") ||
424-
ContainsModel("G615LR") || ContainsModel("G815LR");
424+
ContainsModel("G815LR");
425425
public static bool IsPossible4ZoneRGB() =>
426426
ContainsModel("G614JI_") || ContainsModel("G614JV_") || ContainsModel("G614JZ") ||
427427
ContainsModel("G614JU") || IsStrixLimitedRGB();

src/Helpers/Diagnostics.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ private static void AppendSysfsState(StringBuilder sb)
200200
// Keyboard
201201
"/sys/class/leds/asus::kbd_backlight/brightness",
202202
"/sys/class/leds/asus::kbd_backlight/multi_intensity",
203+
"/sys/class/leds/asus::kbd_backlight/kbd_rgb_mode",
204+
"/sys/class/leds/asus::kbd_backlight/kbd_rgb_state",
203205
// Platform profile
204206
"/sys/firmware/acpi/platform_profile",
205207
"/sys/firmware/acpi/platform_profile_choices",
@@ -228,6 +230,27 @@ private static void AppendSysfsState(StringBuilder sb)
228230
sb.AppendLine($" {shortPath}: {perms} = {value}");
229231
}
230232

233+
// Keyboard backlight directory listing (TUF kbd_rgb_mode/state diagnostics)
234+
const string kbdDir = "/sys/class/leds/asus::kbd_backlight";
235+
if (Directory.Exists(kbdDir))
236+
{
237+
sb.AppendLine();
238+
sb.AppendLine(" kbd_backlight attributes:");
239+
try
240+
{
241+
foreach (var file in Directory.GetFiles(kbdDir).OrderBy(f => f))
242+
{
243+
var name = Path.GetFileName(file);
244+
var perms = GetFilePermissions(file);
245+
sb.AppendLine($" {name}: {perms}");
246+
}
247+
}
248+
catch (Exception ex)
249+
{
250+
sb.AppendLine($" (error: {ex.Message})");
251+
}
252+
}
253+
231254
// Resolved WMI attributes (may be legacy sysfs or firmware-attributes)
232255
sb.AppendLine();
233256
sb.AppendLine(" WMI attributes (resolved via ResolveAttrPath):");
@@ -318,6 +341,32 @@ private static void AppendUsbDevices(StringBuilder sb)
318341
"-c \"lsusb 2>/dev/null | grep -i '0b05' || echo '(none found)'\"");
319342
sb.AppendLine(lsusb ?? "(lsusb failed)");
320343
sb.AppendLine();
344+
345+
// Also scan native hidraw devices (catches I2C-HID that lsusb misses)
346+
sb.AppendLine("--- HID Raw Devices (ASUS, incl. I2C-HID) ---");
347+
try
348+
{
349+
var devices = USB.HidrawHelper.EnumerateAsusDevices();
350+
if (devices.Count == 0)
351+
{
352+
sb.AppendLine("(none found)");
353+
}
354+
else
355+
{
356+
foreach (var dev in devices)
357+
{
358+
sb.AppendLine($" {dev.Path}: VID=0x{dev.Vendor:X4} PID=0x{dev.Product:X4} Bus={dev.BusName} Aura={dev.HasAuraReport}");
359+
}
360+
}
361+
}
362+
catch (Exception ex)
363+
{
364+
sb.AppendLine($" (error: {ex.Message})");
365+
}
366+
367+
sb.AppendLine($"AsusHid.IsAvailable: {USB.AsusHid.IsAvailable()}");
368+
sb.AppendLine($"AsusHid.UsingI2cHidraw: {USB.AsusHid.UsingI2cHidraw}");
369+
sb.AppendLine();
321370
}
322371

323372
private static void AppendFirmwareAttributes(StringBuilder sb)

src/Mode/ModeControl.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,16 @@ private void AutoPower(int mode)
233233
Helpers.Logger.WriteLine($"AutoPower: PL2 = {pl2}W (max={maxTotal}W)");
234234
}
235235

236+
// fPPT (fast boost)
237+
int fppt = Helpers.AppConfig.GetMode("limit_fppt");
238+
if (fppt > maxTotal || fppt < MinTotal) fppt = -1;
239+
if (fppt > 0 && wmi.IsFeatureSupported("ppt_fppt"))
240+
{
241+
wmi.SetPptLimit("ppt_fppt", fppt);
242+
if (fppt > _customPower) _customPower = fppt;
243+
Helpers.Logger.WriteLine($"AutoPower: fPPT = {fppt}W (max={maxTotal}W)");
244+
}
245+
236246
// NVIDIA dynamic boost
237247
int nvBoost = Helpers.AppConfig.GetMode("gpu_boost");
238248
if (nvBoost > maxGpuBoost) nvBoost = maxGpuBoost;

src/UI/Views/FansWindow.axaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,19 @@
8383
VerticalAlignment="Center" />
8484
</Grid>
8585

86+
<!-- PPT fPPT (fast boost) -->
87+
<Grid x:Name="gridFppt" ColumnDefinitions="120,*,50" Margin="0,4" IsVisible="False">
88+
<TextBlock Grid.Column="0" Text="CPU fPPT (Fast)"
89+
Classes="label-dim" VerticalAlignment="Center" />
90+
<Slider Grid.Column="1" x:Name="sliderFppt"
91+
Minimum="5" Maximum="150" Value="65"
92+
TickFrequency="5"
93+
ValueChanged="SliderFppt_ValueChanged" />
94+
<TextBlock Grid.Column="2" x:Name="labelFppt" Classes="value"
95+
Text="65W" HorizontalAlignment="Center"
96+
VerticalAlignment="Center" />
97+
</Grid>
98+
8699
<!-- CPU Boost -->
87100
<Grid ColumnDefinitions="120,*" Margin="0,8,0,0">
88101
<TextBlock Grid.Column="0" Text="CPU Boost"
@@ -95,6 +108,12 @@
95108
</StackPanel>
96109
</Grid>
97110

111+
<!-- Auto-apply power -->
112+
<CheckBox x:Name="checkApplyPower"
113+
Content="Auto-apply power limits on mode change" Margin="0,8,0,0"
114+
Checked="CheckApplyPower_Changed"
115+
Unchecked="CheckApplyPower_Changed" />
116+
98117
<!-- Sensor readings -->
99118
<TextBlock x:Name="labelSensors" Classes="label-dim"
100119
Text="" Margin="0,8,0,0" />

src/UI/Views/FansWindow.axaml.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,25 @@ private void CheckApplyFans_Changed(object? sender, RoutedEventArgs e)
130130
Helpers.AppConfig.SetMode("auto_apply_fans", enabled ? 1 : 0);
131131
}
132132

133+
private void CheckApplyPower_Changed(object? sender, RoutedEventArgs e)
134+
{
135+
bool enabled = checkApplyPower.IsChecked ?? false;
136+
Helpers.AppConfig.SetMode("auto_apply_power", enabled ? 1 : 0);
137+
}
138+
133139
// ── Power Limits ──
134140

135141
private void LoadPowerLimits()
136142
{
137143
var wmi = App.Wmi;
138144
if (wmi == null) return;
139145

146+
// Read from hardware, fall back to saved config
140147
int pl1 = wmi.GetPptLimit("ppt_pl1_spl");
148+
if (pl1 <= 0) pl1 = Helpers.AppConfig.GetMode("limit_slow");
149+
141150
int pl2 = wmi.GetPptLimit("ppt_pl2_sppt");
151+
if (pl2 <= 0) pl2 = Helpers.AppConfig.GetMode("limit_fast");
142152

143153
if (pl1 > 0)
144154
{
@@ -151,6 +161,22 @@ private void LoadPowerLimits()
151161
sliderPL2.Value = pl2;
152162
labelPL2.Text = $"{pl2}W";
153163
}
164+
165+
// fPPT (fast boost) — only show if supported
166+
bool hasFppt = wmi.IsFeatureSupported("ppt_fppt");
167+
gridFppt.IsVisible = hasFppt;
168+
if (hasFppt)
169+
{
170+
int fppt = wmi.GetPptLimit("ppt_fppt");
171+
if (fppt <= 0) fppt = Helpers.AppConfig.GetMode("limit_fppt");
172+
if (fppt > 0)
173+
{
174+
sliderFppt.Value = fppt;
175+
labelFppt.Text = $"{fppt}W";
176+
}
177+
}
178+
179+
checkApplyPower.IsChecked = Helpers.AppConfig.IsMode("auto_apply_power");
154180
}
155181

156182
private void SliderPL1_ValueChanged(object? sender,
@@ -159,6 +185,7 @@ private void SliderPL1_ValueChanged(object? sender,
159185
int watts = (int)e.NewValue;
160186
labelPL1.Text = $"{watts}W";
161187
App.Wmi?.SetPptLimit("ppt_pl1_spl", watts);
188+
Helpers.AppConfig.SetMode("limit_slow", watts);
162189
}
163190

164191
private void SliderPL2_ValueChanged(object? sender,
@@ -167,6 +194,16 @@ private void SliderPL2_ValueChanged(object? sender,
167194
int watts = (int)e.NewValue;
168195
labelPL2.Text = $"{watts}W";
169196
App.Wmi?.SetPptLimit("ppt_pl2_sppt", watts);
197+
Helpers.AppConfig.SetMode("limit_fast", watts);
198+
}
199+
200+
private void SliderFppt_ValueChanged(object? sender,
201+
Avalonia.Controls.Primitives.RangeBaseValueChangedEventArgs e)
202+
{
203+
int watts = (int)e.NewValue;
204+
labelFppt.Text = $"{watts}W";
205+
App.Wmi?.SetPptLimit("ppt_fppt", watts);
206+
Helpers.AppConfig.SetMode("limit_fppt", watts);
170207
}
171208

172209
// ── CPU Boost ──

src/UI/Views/MainWindow.axaml.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -700,12 +700,26 @@ private void InitAura()
700700

701701
Helpers.Logger.WriteLine("AURA HID device found — initializing RGB controls");
702702

703-
// Load saved values
703+
// Send AURA HID init handshake (wake up the LED controller).
704+
// This is critical for I2C-HID keyboards (e.g., FA608PP) that need
705+
// the handshake before they respond to any RGB commands.
706+
// On Windows, G-Helper's Aura.Init() does this in InputDispatcher.AutoKeyboard().
707+
Aura.Init();
708+
709+
// Load saved values into static fields BEFORE applying to hardware
704710
Aura.Mode = (AuraMode)Helpers.AppConfig.Get("aura_mode");
705711
Aura.Speed = (AuraSpeed)Helpers.AppConfig.Get("aura_speed");
706712
Aura.SetColor(Helpers.AppConfig.Get("aura_color", unchecked((int)0xFFFFFFFF)));
707713
Aura.SetColor2(Helpers.AppConfig.Get("aura_color2", 0));
708714

715+
// Apply saved power state + mode so the keyboard lights up on startup
716+
// (runs on background thread after config values are loaded above)
717+
Task.Run(() =>
718+
{
719+
Aura.ApplyPower();
720+
Aura.ApplyAura();
721+
});
722+
709723
_suppressAuraEvents = true;
710724

711725
// Populate mode combo

0 commit comments

Comments
 (0)