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;
}
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;
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) {
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 = {
.name = "system76::kbd_backlight",
.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;
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;
}
@ -243,7 +311,10 @@ static void kb_led_resume(void)
// Reset current color
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
@ -355,7 +426,10 @@ static void kb_wmi_color(void)
}
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);

View File

@ -51,12 +51,13 @@
/* method IDs for S76_GET */
#define GET_EVENT 0x01 /* 1 */
#define DRIVER_AP_KEY (1 << 0)
#define DRIVER_AP_LED (1 << 1)
#define DRIVER_HWMON (1 << 2)
#define DRIVER_KB_LED (1 << 3)
#define DRIVER_OLED (1 << 4)
#define DRIVER_AP_WMI (1 << 5)
#define DRIVER_AP_KEY (1 << 0)
#define DRIVER_AP_LED (1 << 1)
#define DRIVER_HWMON (1 << 2)
#define DRIVER_KB_LED_WMI (1 << 3)
#define DRIVER_OLED (1 << 4)
#define DRIVER_AP_WMI (1 << 5)
#define DRIVER_KB_LED (1 << 6)
#define DRIVER_INPUT (DRIVER_AP_KEY | DRIVER_OLED)
@ -130,17 +131,17 @@ static void s76_wmi_notify(u32 value, void *context)
switch (event) {
case 0x81:
if (driver_flags & DRIVER_KB_LED) {
if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_dec();
}
break;
case 0x82:
if (driver_flags & DRIVER_KB_LED) {
if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_inc();
}
break;
case 0x83:
if (driver_flags & DRIVER_KB_LED) {
if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_color();
}
break;
@ -151,7 +152,7 @@ static void s76_wmi_notify(u32 value, void *context)
//TODO: Fn+ESC
break;
case 0x9F:
if (driver_flags & DRIVER_KB_LED) {
if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_wmi_toggle();
}
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);
if (unlikely(err)) {
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) {
s76_input_exit();
}
if (driver_flags & DRIVER_KB_LED) {
if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_led_exit();
}
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");
if (driver_flags & DRIVER_KB_LED) {
if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
kb_led_suspend();
}
@ -280,7 +281,7 @@ static int s76_resume(struct platform_device *dev)
if (driver_flags & DRIVER_AP_LED) {
ap_led_resume();
}
if (driver_flags & DRIVER_KB_LED) {
if (driver_flags & (DRIVER_KB_LED_WMI | DRIVER_KB_LED)) {
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 = {
DMI_TABLE_LEGACY("bonw13", DRIVER_HWMON | DRIVER_KB_LED),
DMI_TABLE("addw1", DRIVER_AP_LED | DRIVER_KB_LED | DRIVER_OLED),
DMI_TABLE("addw2", DRIVER_AP_LED | DRIVER_KB_LED | DRIVER_OLED),
DMI_TABLE("bonw15-b", DRIVER_HWMON | DRIVER_KB_LED),
DMI_TABLE("bonw16", DRIVER_HWMON | DRIVER_KB_LED),
DMI_TABLE("darp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED),
DMI_TABLE("darp6", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED),
DMI_TABLE_LEGACY("bonw13", DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("addw1", DRIVER_AP_LED | DRIVER_KB_LED_WMI | DRIVER_OLED),
DMI_TABLE("addw2", DRIVER_AP_LED | DRIVER_KB_LED_WMI | DRIVER_OLED),
DMI_TABLE("bonw15-b", DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("bonw16", DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("darp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("darp6", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("galp2", DRIVER_HWMON),
DMI_TABLE("galp3", 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("galp4", 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("gaze15", 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_WMI),
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("oryp3-jeremy", 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),
DMI_TABLE("oryp4-b", DRIVER_AP_KEY | DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED),
DMI_TABLE("oryp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED),
DMI_TABLE("oryp6", DRIVER_AP_LED | DRIVER_KB_LED),
DMI_TABLE("pang10", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED),
DMI_TABLE("pang11", DRIVER_AP_KEY | DRIVER_AP_WMI | DRIVER_KB_LED),
DMI_TABLE("serw11", 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),
DMI_TABLE("serw12", DRIVER_AP_KEY | DRIVER_AP_LED | 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_WMI),
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_WMI),
DMI_TABLE("oryp5", DRIVER_AP_LED | DRIVER_HWMON | DRIVER_KB_LED_WMI),
DMI_TABLE("oryp6", DRIVER_AP_LED | DRIVER_KB_LED_WMI),
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_WMI),
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_WMI),
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);
static int __init s76_init(void)
@ -397,14 +398,13 @@ static int __init s76_init(void)
return 0;
}
module_init(s76_init);
static void __exit s76_exit(void)
{
platform_device_unregister(s76_platform_device);
platform_driver_unregister(&s76_platform_driver);
}
module_init(s76_init);
module_exit(s76_exit);
MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>");