Add serw14 with hack

The WMI interface is deprecated and does not work on serw14. Hack in a
call to the underlying ECMD to fix it for now.

Signed-off-by: Tim Crawford <tcrawford@system76.com>
This commit is contained in:
Tim Crawford 2025-06-05 13:35:13 -06:00
parent f886317ae8
commit af173d245a
No known key found for this signature in database
GPG Key ID: 68E558D2BBD856E3
2 changed files with 116 additions and 42 deletions

View File

@ -72,11 +72,11 @@ static int kb_led_set(struct led_classdev *led_cdev, enum led_brightness value)
return 0; return 0;
} }
static void kb_led_color_set(enum kb_led_region region, union kb_led_color color) static void kb_led_color_set_wmi(enum kb_led_region region, union kb_led_color color)
{ {
u32 cmd; u32 cmd;
pr_debug("kb_led_color_set %d %06X\n", (int)region, (int)color.rgb); pr_debug("%s %d %06X\n", __func__, (int)region, (int)color.rgb);
switch (region) { switch (region) {
case KB_LED_REGION_LEFT: case KB_LED_REGION_LEFT:
@ -104,6 +104,71 @@ static void kb_led_color_set(enum kb_led_region region, union kb_led_color color
} }
} }
// HACK: Directly call ECMD to fix serw14
static void kb_led_color_set(enum kb_led_region region, union kb_led_color color)
{
struct acpi_object_list input;
union acpi_object obj;
acpi_handle handle;
acpi_status status;
u8 *buf;
buf = (u8 *)kzalloc(8, GFP_KERNEL);
pr_debug("%s %d %06X\n", __func__, (int)region, (int)color.rgb);
buf[0] = 5;
buf[2] = 0xCA;
buf[4] = color.b;
buf[5] = color.r;
buf[6] = color.g;
switch (region) {
case KB_LED_REGION_LEFT:
buf[3] = 0x03;
break;
case KB_LED_REGION_CENTER:
buf[3] = 0x04;
break;
case KB_LED_REGION_RIGHT:
buf[3] = 0x05;
break;
case KB_LED_REGION_EXTRA:
buf[3] = 0x0B;
break;
}
obj.type = ACPI_TYPE_BUFFER;
obj.buffer.length = 8;
obj.buffer.pointer = buf;
input.count = 1;
input.pointer = &obj;
status = acpi_get_handle(NULL, (acpi_string)"\\_SB.PC00.LPCB.EC", &handle);
if (ACPI_FAILURE(status)) {
pr_err("%s failed to get handle: %x\n", __func__, status);
return;
}
status = acpi_evaluate_object(handle, "ECMD", &input, NULL);
if (ACPI_FAILURE(status)) {
pr_err("%s failed to call EC_CMD: %x\n", __func__, status);
return;
}
// Update lightbar to match keyboard color
buf[3] = 0x07;
status = acpi_evaluate_object(handle, "ECMD", &input, NULL);
if (ACPI_FAILURE(status)) {
pr_err("%s failed to call EC_CMD: %x\n", __func__, status);
return;
}
kfree(buf);
kb_led_regions[region] = color;
}
static struct led_classdev kb_led = { static struct led_classdev kb_led = {
.name = "system76::kbd_backlight", .name = "system76::kbd_backlight",
.flags = LED_BRIGHT_HW_CHANGED, .flags = LED_BRIGHT_HW_CHANGED,
@ -129,7 +194,10 @@ static ssize_t kb_led_color_store(enum kb_led_region region, const char *buf, si
} }
color.rgb = (u32)val; color.rgb = (u32)val;
kb_led_color_set(region, color); if (driver_flags & DRIVER_KB_LED_WMI)
kb_led_color_set_wmi(region, color);
else
kb_led_color_set(region, color);
return size; return size;
} }
@ -243,7 +311,10 @@ static void kb_led_resume(void)
// Reset current color // Reset current color
for (region = 0; region < sizeof(kb_led_regions)/sizeof(union kb_led_color); region++) { for (region = 0; region < sizeof(kb_led_regions)/sizeof(union kb_led_color); region++) {
kb_led_color_set(region, kb_led_regions[region]); if (driver_flags & DRIVER_KB_LED_WMI)
kb_led_color_set_wmi(region, kb_led_regions[region]);
else
kb_led_color_set(region, kb_led_regions[region]);
} }
// Reset current brightness // Reset current brightness
@ -355,7 +426,10 @@ static void kb_wmi_color(void)
} }
for (region = 0; region < sizeof(kb_led_regions)/sizeof(union kb_led_color); region++) { for (region = 0; region < sizeof(kb_led_regions)/sizeof(union kb_led_color); region++) {
kb_led_color_set(region, kb_led_colors[kb_led_colors_i]); if (driver_flags & DRIVER_KB_LED_WMI)
kb_led_color_set_wmi(region, kb_led_colors[kb_led_colors_i]);
else
kb_led_color_set(region, kb_led_colors[kb_led_colors_i]);
} }
led_classdev_notify_brightness_hw_changed(&kb_led, kb_led_brightness); led_classdev_notify_brightness_hw_changed(&kb_led, kb_led_brightness);

View File

@ -51,12 +51,13 @@
/* method IDs for S76_GET */ /* method IDs for S76_GET */
#define GET_EVENT 0x01 /* 1 */ #define GET_EVENT 0x01 /* 1 */
#define DRIVER_AP_KEY (1 << 0) #define DRIVER_AP_KEY (1 << 0)
#define DRIVER_AP_LED (1 << 1) #define DRIVER_AP_LED (1 << 1)
#define DRIVER_HWMON (1 << 2) #define DRIVER_HWMON (1 << 2)
#define DRIVER_KB_LED (1 << 3) #define DRIVER_KB_LED_WMI (1 << 3)
#define DRIVER_OLED (1 << 4) #define DRIVER_OLED (1 << 4)
#define DRIVER_AP_WMI (1 << 5) #define DRIVER_AP_WMI (1 << 5)
#define DRIVER_KB_LED (1 << 6)
#define DRIVER_INPUT (DRIVER_AP_KEY | DRIVER_OLED) #define DRIVER_INPUT (DRIVER_AP_KEY | DRIVER_OLED)
@ -130,17 +131,17 @@ static void s76_wmi_notify(u32 value, void *context)
switch (event) { switch (event) {
case 0x81: case 0x81:
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_dec(); kb_wmi_dec();
} }
break; break;
case 0x82: case 0x82:
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_inc(); kb_wmi_inc();
} }
break; break;
case 0x83: case 0x83:
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_color(); kb_wmi_color();
} }
break; break;
@ -151,7 +152,7 @@ static void s76_wmi_notify(u32 value, void *context)
//TODO: Fn+ESC //TODO: Fn+ESC
break; break;
case 0x9F: case 0x9F:
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_toggle(); kb_wmi_toggle();
} }
break; break;
@ -189,7 +190,7 @@ static int __init s76_probe(struct platform_device *dev)
} }
} }
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
err = kb_led_init(&dev->dev); err = kb_led_init(&dev->dev);
if (unlikely(err)) { if (unlikely(err)) {
pr_err("Could not register LED device\n"); pr_err("Could not register LED device\n");
@ -248,7 +249,7 @@ static int s76_remove(struct platform_device *dev)
if (driver_flags & DRIVER_INPUT) { if (driver_flags & DRIVER_INPUT) {
s76_input_exit(); s76_input_exit();
} }
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_led_exit(); kb_led_exit();
} }
if (driver_flags & DRIVER_AP_LED) { if (driver_flags & DRIVER_AP_LED) {
@ -264,7 +265,7 @@ static int s76_suspend(struct platform_device *dev, pm_message_t status)
{ {
pr_debug("s76_suspend\n"); pr_debug("s76_suspend\n");
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_led_suspend(); kb_led_suspend();
} }
@ -280,7 +281,7 @@ static int s76_resume(struct platform_device *dev)
if (driver_flags & DRIVER_AP_LED) { if (driver_flags & DRIVER_AP_LED) {
ap_led_resume(); ap_led_resume();
} }
if (driver_flags & DRIVER_KB_LED) { if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_led_resume(); kb_led_resume();
} }
@ -334,36 +335,36 @@ static int __init s76_dmi_matched(const struct dmi_system_id *id)
} }
static struct dmi_system_id s76_dmi_table[] __initdata = { static struct dmi_system_id s76_dmi_table[] __initdata = {
DMI_TABLE_LEGACY("bonw13", DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE_LEGACY("bonw13", DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("addw1", DRIVER_AP_LED | DRIVER_KB_LED | DRIVER_OLED), DMI_TABLE("addw1", DRIVER_AP_LED | DRIVER_KB_LED_WMI | DRIVER_OLED),
DMI_TABLE("addw2", DRIVER_AP_LED | DRIVER_KB_LED | DRIVER_OLED), DMI_TABLE("addw2", DRIVER_AP_LED | DRIVER_KB_LED_WMI | DRIVER_OLED),
DMI_TABLE("bonw15-b", DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("bonw15-b", DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("bonw16", DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("bonw16", DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("darp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("darp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("darp6", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("darp6", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("galp2", DRIVER_HWMON), DMI_TABLE("galp2", DRIVER_HWMON),
DMI_TABLE("galp3", DRIVER_HWMON), DMI_TABLE("galp3", DRIVER_HWMON),
DMI_TABLE("galp3-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("galp3-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON),
DMI_TABLE("galp3-c", DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("galp3-c", DRIVER_AP_LED | DRIVER_HWMON),
DMI_TABLE("galp4", DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("galp4", DRIVER_AP_LED | DRIVER_HWMON),
DMI_TABLE("gaze13", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("gaze13", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON),
DMI_TABLE("gaze14", DRIVER_AP_LED | DRIVER_KB_LED), DMI_TABLE("gaze14", DRIVER_AP_LED | DRIVER_KB_LED_WMI),
DMI_TABLE("gaze15", DRIVER_AP_LED | DRIVER_KB_LED), DMI_TABLE("gaze15", DRIVER_AP_LED | DRIVER_KB_LED_WMI),
DMI_TABLE("kudu5", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON), DMI_TABLE("kudu5", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON),
DMI_TABLE("kudu6", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED), DMI_TABLE("kudu6", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED_WMI),
DMI_TABLE("oryp3-jeremy", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("oryp3-jeremy", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("oryp4", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("oryp4", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("oryp4-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("oryp4-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("oryp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("oryp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("oryp6", DRIVER_AP_LED | DRIVER_KB_LED), DMI_TABLE("oryp6", DRIVER_AP_LED | DRIVER_KB_LED_WMI),
DMI_TABLE("pang10", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED), DMI_TABLE("pang10", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED_WMI),
DMI_TABLE("pang11", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED), DMI_TABLE("pang11", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED_WMI),
DMI_TABLE("serw11", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("serw11", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("serw11-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED), DMI_TABLE("serw11-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("serw12", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_AP_WMI | DRIVER_KB_LED), DMI_TABLE("serw12", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_AP_WMI | DRIVER_KB_LED_WMI),
DMI_TABLE("serw14", DRIVER_HWMON | DRIVER_KB_LED),
{} {}
}; };
MODULE_DEVICE_TABLE(dmi, s76_dmi_table); MODULE_DEVICE_TABLE(dmi, s76_dmi_table);
static int __init s76_init(void) static int __init s76_init(void)
@ -397,14 +398,13 @@ static int __init s76_init(void)
return 0; return 0;
} }
module_init(s76_init);
static void __exit s76_exit(void) static void __exit s76_exit(void)
{ {
platform_device_unregister(s76_platform_device); platform_device_unregister(s76_platform_device);
platform_driver_unregister(&s76_platform_driver); platform_driver_unregister(&s76_platform_driver);
} }
module_init(s76_init);
module_exit(s76_exit); module_exit(s76_exit);
MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>"); MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>");