From 5f631c3b2f44904e12aec6ba8dbb44a9bccde883 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 2 Jan 2018 16:17:06 -0700 Subject: [PATCH] Add code to rewrite WMI methods using EC --- ec.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ led.c | 26 ++++++++------------- system76.c | 18 +++++++++++++-- 3 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 ec.c diff --git a/ec.c b/ec.c new file mode 100644 index 0000000..73618a9 --- /dev/null +++ b/ec.c @@ -0,0 +1,67 @@ +/* + * ec.c - EC rewrite of WMI functions + * + * Copyright (C) 2017 Jeremy Soller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + // EC Registers + + #define FCMD 0xF8 + #define FDAT 0xF9 + #define FBUF 0xFA + #define FBF1 0xFB + #define FBF2 0xFC + #define FBF3 0xFD + +enum KbRegion { + KB_LEFT, + KB_CENTER, + KB_RIGHT, +}; + +static void ec_kb_color_set(enum KbRegion region, u32 color) { + u8 region_code; + switch(region) { + case KB_LEFT: + region_code = 0x3; + break; + case KB_CENTER: + region_code = 0x4; + break; + case KB_RIGHT: + region_code = 0x5; + break; + default: + return; + } + + ec_write(FDAT, region_code); + ec_write(FBUF, (color & 0xFF)); + ec_write(FBF1, ((color >> 16) & 0xFF)); + ec_write(FBF2, ((color >> 8) & 0xFF)); + ec_write(FCMD, 0xCA); +} + +static int ec_init(void) { + ec_kb_color_set(KB_LEFT, 0xFF0000); + ec_kb_color_set(KB_CENTER, 0xFF00); + ec_kb_color_set(KB_RIGHT, 0xFF); + + return 0; +} + +static void ec_exit(void) { +} diff --git a/led.c b/led.c index 794fab2..1caccab 100644 --- a/led.c +++ b/led.c @@ -26,8 +26,7 @@ static struct _led_work { int wk; } led_work; -static void airplane_led_update(struct work_struct *work) -{ +static void airplane_led_update(struct work_struct *work) { u8 byte; struct _led_work *w; @@ -40,8 +39,7 @@ static void airplane_led_update(struct work_struct *work) /* wmbb 0x6C 1 (?) */ } -static enum led_brightness airplane_led_get(struct led_classdev *led_cdev) -{ +static enum led_brightness airplane_led_get(struct led_classdev *led_cdev) { u8 byte; ec_read(0xD9, &byte); @@ -50,10 +48,7 @@ static enum led_brightness airplane_led_get(struct led_classdev *led_cdev) } /* must not sleep */ -static void airplane_led_set(struct led_classdev *led_cdev, - enum led_brightness value) -{ - S76_INFO("Set airplane LED to %X", value); +static void airplane_led_set(struct led_classdev *led_cdev, enum led_brightness value) { led_work.wk = value; queue_work(led_workqueue, &led_work.work); } @@ -66,20 +61,20 @@ static struct led_classdev airplane_led = { .default_trigger = "rfkill-any" }; -static int __init s76_led_init(void) -{ +static int __init s76_led_init(void) { int err; led_workqueue = create_singlethread_workqueue("led_workqueue"); - if (unlikely(!led_workqueue)) + if (unlikely(!led_workqueue)) { return -ENOMEM; + } INIT_WORK(&led_work.work, airplane_led_update); - err = led_classdev_register(&s76_platform_device->dev, - &airplane_led); - if (unlikely(err)) + err = led_classdev_register(&s76_platform_device->dev, &airplane_led); + if (unlikely(err)) { goto err_destroy_workqueue; + } return 0; @@ -90,8 +85,7 @@ err_destroy_workqueue: return err; } -static void __exit s76_led_exit(void) -{ +static void __exit s76_led_exit(void) { if (!IS_ERR_OR_NULL(airplane_led.dev)) led_classdev_unregister(&airplane_led); if (led_workqueue) diff --git a/system76.c b/system76.c index 6affc8d..acb11e2 100644 --- a/system76.c +++ b/system76.c @@ -89,6 +89,7 @@ static int s76_wmbb(u32 method_id, u32 arg, u32 *retval) { return 0; } +#include "ec.c" #include "led.c" #include "input.c" #include "kb.c" @@ -124,6 +125,9 @@ static int s76_probe(struct platform_device *dev) { S76_ERROR("Could not register WMI notify handler (%0#6x)\n", status); return -EIO; } + + // Enable hotkey support + s76_wmbb(0x46, 0, NULL); if (kb_backlight.ops) { kb_backlight.ops->init(); @@ -139,6 +143,9 @@ static int s76_remove(struct platform_device *dev) { } static int s76_resume(struct platform_device *dev) { + // Enable hotkey support + s76_wmbb(0x46, 0, NULL); + if (kb_backlight.ops && kb_backlight.state == KB_STATE_ON) { kb_backlight.ops->set_mode(kb_backlight.mode); } @@ -173,8 +180,8 @@ static int __init s76_dmi_matched(const struct dmi_system_id *id) { } static struct dmi_system_id s76_dmi_table[] __initdata = { - DMI_TABLE("bonw13", NULL), - DMI_TABLE("oryp3-b", NULL), + DMI_TABLE("bonw13", &kb_full_color_with_extra_ops), + DMI_TABLE("oryp3-b", &kb_full_color_ops), {} }; @@ -240,10 +247,17 @@ static int __init s76_init(void) { s76_hwmon_init(&s76_platform_device->dev); #endif + err = ec_init(); + if (unlikely(err)) { + S76_ERROR("Could not register EC device\n"); + } + return 0; } static void __exit s76_exit(void) { + ec_exit(); + #ifdef S76_HAS_HWMON s76_hwmon_fini(&s76_platform_device->dev); #endif