diff --git a/ap_led.c b/ap_led.c
index 769dd1c..80d9289 100644
--- a/ap_led.c
+++ b/ap_led.c
@@ -17,31 +17,90 @@
* along with this program. If not, see .
*/
+static enum led_brightness ap_led_brightness = 1;
+
+static bool ap_led_invert = TRUE;
+
static enum led_brightness ap_led_get(struct led_classdev *led_cdev) {
- u8 byte;
-
- ec_read(0xD9, &byte);
-
- return byte & 0x40 ? LED_OFF : LED_FULL;
+ return ap_led_brightness;
}
static int ap_led_set(struct led_classdev *led_cdev, enum led_brightness value) {
u8 byte;
ec_read(0xD9, &byte);
- ec_write(0xD9, value ? byte & ~0x40 : byte | 0x40);
+
+ if (value > 0) {
+ ap_led_brightness = 1;
+
+ if (ap_led_invert) {
+ byte &= ~0x40;
+ } else {
+ byte |= 0x40;
+ }
+ } else {
+ ap_led_brightness = 0;
+
+ if (ap_led_invert) {
+ byte |= 0x40;
+ } else {
+ byte &= ~0x40;
+ }
+ }
+
+ ec_write(0xD9, byte);
return 0;
}
static struct led_classdev ap_led = {
- .name = "system76::airplane",
- .brightness_get = ap_led_get,
- .brightness_set_blocking = ap_led_set,
- .max_brightness = 1,
- .default_trigger = "rfkill-any"
+ .name = "system76::airplane",
+ .brightness_get = ap_led_get,
+ .brightness_set_blocking = ap_led_set,
+ .max_brightness = 1,
+ .default_trigger = "rfkill-any"
};
+static ssize_t ap_led_invert_show(struct device *dev, struct device_attribute *attr, char *buf) {
+ return sprintf(buf, "%d\n", (int)ap_led_invert);
+}
+
+static ssize_t ap_led_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) {
+ unsigned int val;
+ int ret;
+ enum led_brightness brightness;
+
+ ret = kstrtouint(buf, 0, &val);
+ if (ret) {
+ return ret;
+ }
+
+ brightness = ap_led_get(&ap_led);
+
+ if (val) {
+ ap_led_invert = TRUE;
+ } else {
+ ap_led_invert = FALSE;
+ }
+
+ ap_led_set(&ap_led, brightness);
+
+ return size;
+}
+
+static struct device_attribute ap_led_invert_dev_attr = {
+ .attr = {
+ .name = "invert",
+ .mode = 0644,
+ },
+ .show = ap_led_invert_show,
+ .store = ap_led_invert_store,
+};
+
+static void ap_led_resume(void) {
+ ap_led_set(&ap_led, ap_led_brightness);
+}
+
static int __init ap_led_init(struct device *dev) {
int err;
@@ -49,11 +108,19 @@ static int __init ap_led_init(struct device *dev) {
if (unlikely(err)) {
return err;
}
+
+ if (device_create_file(ap_led.dev, &ap_led_invert_dev_attr) != 0) {
+ S76_ERROR("failed to create ap_led_invert\n");
+ }
+
+ ap_led_resume();
return 0;
}
static void __exit ap_led_exit(void) {
+ device_remove_file(ap_led.dev, &ap_led_invert_dev_attr);
+
if (!IS_ERR_OR_NULL(ap_led.dev)) {
led_classdev_unregister(&ap_led);
}
diff --git a/ec.c b/ec.c
deleted file mode 100644
index bbb2446..0000000
--- a/ec.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 EcKbRegion {
- EC_KB_LEFT,
- EC_KB_CENTER,
- EC_KB_RIGHT,
- EC_KB_EXTRA,
-};
-
-static void ec_kb_color_set(enum EcKbRegion region, u32 color) {
- u8 region_code;
- switch(region) {
- case EC_KB_LEFT:
- region_code = 0x3;
- break;
- case EC_KB_CENTER:
- region_code = 0x4;
- break;
- case EC_KB_RIGHT:
- region_code = 0x5;
- break;
- case EC_KB_EXTRA:
- region_code = 0x7;
- 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) {
- return 0;
-}
-
-static void ec_exit(void) {
-}
diff --git a/kb.c b/kb.c
deleted file mode 100644
index c9251a1..0000000
--- a/kb.c
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
- * kb.c
- *
- * Copyright (C) 2017 Jeremy Soller
- * Copyright (C) 2014-2016 Arnoud Willemsen
- * Copyright (C) 2013-2015 TUXEDO Computers GmbH
- *
- * 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 .
- */
-
-#define COLORS { \
- C(white, 0xFFFFFF), \
- C(blue, 0x0000FF), \
- C(red, 0xFF0000), \
- C(magenta, 0xFF00FF), \
- C(green, 0x00FF00), \
- C(cyan, 0x00FFFF), \
- C(yellow, 0xFFFF00), \
-}
-#undef C
-
-
-#define C(n, v) KB_COLOR_##n
-enum kb_color COLORS;
-#undef C
-
-union kb_rgb_color {
- u32 rgb;
- struct { u32 b:8, g:8, r:8, : 8; };
-};
-
-#define C(n, v) { .name = #n, .value = { .rgb = v, }, }
-struct {
- const char *const name;
- union kb_rgb_color value;
-} kb_colors[] = COLORS;
-#undef C
-
-#define KB_COLOR_DEFAULT KB_COLOR_white
-#define KB_BRIGHTNESS_MAX 5
-#define KB_BRIGHTNESS_DEFAULT 1
-
-static int param_set_kb_color(const char *val, const struct kernel_param *kp)
-{
- size_t i;
-
- if (!val)
- return -EINVAL;
-
- if (!val[0]) {
- *((enum kb_color *) kp->arg) = KB_COLOR_DEFAULT;
- return 0;
- }
-
- for (i = 0; i < ARRAY_SIZE(kb_colors); i++) {
- if (!strcmp(val, kb_colors[i].name)) {
- *((enum kb_color *) kp->arg) = i;
- return 0;
- }
- }
-
- return -EINVAL;
-}
-
-static int param_get_kb_color(char *buffer, const struct kernel_param *kp)
-{
- return sprintf(buffer, "%s",
- kb_colors[*((enum kb_color *) kp->arg)].name);
-}
-
-static const struct kernel_param_ops param_ops_kb_color = {
- .set = param_set_kb_color,
- .get = param_get_kb_color,
-};
-
-static enum kb_color param_kb_color[] = { [0 ... 3] = KB_COLOR_DEFAULT };
-static int param_kb_color_num;
-#define param_check_kb_color(name, p) __param_check(name, p, enum kb_color)
-module_param_array_named(kb_color, param_kb_color, kb_color,
- ¶m_kb_color_num, S_IRUSR);
-MODULE_PARM_DESC(kb_color, "Set the color(s) of the keyboard (sections)");
-
-static int param_set_kb_brightness(const char *val,
- const struct kernel_param *kp)
-{
- int ret;
-
- ret = param_set_byte(val, kp);
-
- if (!ret && *((unsigned char *) kp->arg) > KB_BRIGHTNESS_MAX)
- return -EINVAL;
-
- return ret;
-}
-
-static const struct kernel_param_ops param_ops_kb_brightness = {
- .set = param_set_kb_brightness,
- .get = param_get_byte,
-};
-
-static unsigned char param_kb_brightness = KB_BRIGHTNESS_DEFAULT;
-#define param_check_kb_brightness param_check_byte
-module_param_named(kb_brightness, param_kb_brightness, kb_brightness, S_IRUSR);
-MODULE_PARM_DESC(kb_brightness, "Set the brightness of the keyboard backlight");
-
-
-static bool param_kb_off = true;
-module_param_named(kb_off, param_kb_off, bool, S_IRUSR);
-MODULE_PARM_DESC(kb_off, "Switch keyboard backlight off");
-
-static bool param_kb_cycle_colors = true;
-module_param_named(kb_cycle_colors, param_kb_cycle_colors, bool, S_IRUSR);
-MODULE_PARM_DESC(kb_cycle_colors, "Cycle colors rather than modes");
-
-static struct {
- enum kb_extra {
- KB_HAS_EXTRA_TRUE,
- KB_HAS_EXTRA_FALSE,
- } extra;
-
- enum kb_state {
- KB_STATE_OFF,
- KB_STATE_ON,
- } state;
-
- struct {
- unsigned left;
- unsigned center;
- unsigned right;
- unsigned extra;
- } color;
-
- unsigned brightness;
-
- enum kb_mode {
- KB_MODE_RANDOM_COLOR,
- KB_MODE_CUSTOM,
- KB_MODE_BREATHE,
- KB_MODE_CYCLE,
- KB_MODE_WAVE,
- KB_MODE_DANCE,
- KB_MODE_TEMPO,
- KB_MODE_FLASH,
- } mode;
-
- struct kb_backlight_ops {
- void (*set_state)(enum kb_state state);
- void (*set_color)(unsigned left, unsigned center,
- unsigned right, unsigned extra);
- void (*set_brightness)(unsigned brightness);
- void (*set_mode)(enum kb_mode);
- void (*init)(void);
- } *ops;
-
-} kb_backlight = { .ops = NULL, };
-
-
-static void kb_dec_brightness(void)
-{
- if (kb_backlight.state == KB_STATE_OFF)
- return;
- if (kb_backlight.brightness == 0)
- return;
-
- S76_DEBUG();
-
- kb_backlight.ops->set_brightness(kb_backlight.brightness - 1);
-}
-
-static void kb_inc_brightness(void)
-{
- if (kb_backlight.state == KB_STATE_OFF)
- return;
-
- S76_DEBUG();
-
- kb_backlight.ops->set_brightness(kb_backlight.brightness + 1);
-}
-
-static void kb_toggle_state(void)
-{
- switch (kb_backlight.state) {
- case KB_STATE_OFF:
- kb_backlight.ops->set_state(KB_STATE_ON);
- break;
- case KB_STATE_ON:
- kb_backlight.ops->set_state(KB_STATE_OFF);
- break;
- default:
- BUG();
- }
-}
-
-static void kb_next_mode(void)
-{
- static enum kb_mode modes[] = {
- KB_MODE_RANDOM_COLOR,
- KB_MODE_DANCE,
- KB_MODE_TEMPO,
- KB_MODE_FLASH,
- KB_MODE_WAVE,
- KB_MODE_BREATHE,
- KB_MODE_CYCLE,
- KB_MODE_CUSTOM,
- };
-
- size_t i;
-
- if (kb_backlight.state == KB_STATE_OFF)
- return;
-
- for (i = 0; i < ARRAY_SIZE(modes); i++) {
- if (modes[i] == kb_backlight.mode)
- break;
- }
-
- BUG_ON(i == ARRAY_SIZE(modes));
-
- kb_backlight.ops->set_mode(modes[(i + 1) % ARRAY_SIZE(modes)]);
-}
-
-static void kb_next_color(void)
-{
- size_t i;
- unsigned int nc;
-
- if (kb_backlight.state == KB_STATE_OFF)
- return;
-
- for (i = 0; i < ARRAY_SIZE(kb_colors); i++) {
- if (i == kb_backlight.color.left)
- break;
- }
-
- if (i + 1 >= ARRAY_SIZE(kb_colors))
- nc = 0;
- else
- nc = i + 1;
-
- kb_backlight.ops->set_color(nc, nc, nc, nc);
-}
-
-/* full color backlight keyboard */
-
-static void kb_full_color__set_color(unsigned left, unsigned center,
- unsigned right, unsigned extra)
-{
- u32 cmd;
-
- S76_INFO(
- "Left: %s (%X), Center: %s (%X), Right: %s (%X), Extra: %s (%X)\n",
- kb_colors[left].name, (unsigned int)kb_colors[left].value.rgb,
- kb_colors[center].name, (unsigned int)kb_colors[center].value.rgb,
- kb_colors[right].name, (unsigned int)kb_colors[right].value.rgb,
- kb_colors[extra].name, (unsigned int)kb_colors[extra].value.rgb
- );
-
- ec_kb_color_set(EC_KB_LEFT, kb_colors[left].value.rgb);
- kb_backlight.color.left = left;
-
- ec_kb_color_set(EC_KB_CENTER, kb_colors[center].value.rgb);
- kb_backlight.color.center = center;
-
- ec_kb_color_set(EC_KB_RIGHT, kb_colors[right].value.rgb);
- kb_backlight.color.right = right;
-
- if (kb_backlight.extra == KB_HAS_EXTRA_TRUE) {
- ec_kb_color_set(EC_KB_EXTRA, kb_colors[extra].value.rgb);
- kb_backlight.color.extra = extra;
- }
-
- kb_backlight.mode = KB_MODE_CUSTOM;
-}
-
-static void kb_full_color__set_brightness(unsigned i)
-{
- u8 lvl;
- u8 lvl_to_raw[] = { 48, 72, 96, 144, 192, 255 };
-
- i = clamp_t(unsigned, i, 0, ARRAY_SIZE(lvl_to_raw) - 1);
-
- lvl = lvl_to_raw[i];
-
- kb_led_set(&kb_led, lvl);
- led_classdev_notify_brightness_hw_changed(&kb_led, lvl);
- kb_backlight.brightness = i;
-}
-
-static void kb_full_color__set_mode(unsigned mode)
-{
- static u32 cmds[] = {
- [KB_MODE_BREATHE] = 0x1002a000,
- [KB_MODE_CUSTOM] = 0,
- [KB_MODE_CYCLE] = 0x33010000,
- [KB_MODE_DANCE] = 0x80000000,
- [KB_MODE_FLASH] = 0xA0000000,
- [KB_MODE_RANDOM_COLOR] = 0x70000000,
- [KB_MODE_TEMPO] = 0x90000000,
- [KB_MODE_WAVE] = 0xB0000000,
- };
-
- BUG_ON(mode >= ARRAY_SIZE(cmds));
-
- s76_wmbb(SET_KB_LED, 0x10000000, NULL);
-
- if (mode == KB_MODE_CUSTOM) {
- kb_full_color__set_color(kb_backlight.color.left,
- kb_backlight.color.center,
- kb_backlight.color.right,
- kb_backlight.color.extra);
- kb_full_color__set_brightness(kb_backlight.brightness);
- return;
- }
-
- if (!s76_wmbb(SET_KB_LED, cmds[mode], NULL))
- kb_backlight.mode = mode;
-}
-
-static void kb_full_color__set_state(enum kb_state state)
-{
- u32 cmd = 0xE0000000;
-
- S76_DEBUG("State: %d\n", state);
-
- switch (state) {
- case KB_STATE_OFF:
- led_classdev_notify_brightness_hw_changed(&kb_led, 0);
-
- cmd |= 0x003001;
- break;
- case KB_STATE_ON:
- kb_full_color__set_brightness(kb_backlight.brightness);
-
- cmd |= 0x07F001;
- break;
- default:
- BUG();
- }
-
- if (!s76_wmbb(SET_KB_LED, cmd, NULL))
- kb_backlight.state = state;
-}
-
-static void kb_full_color__init(void)
-{
- S76_DEBUG();
-
- kb_backlight.extra = KB_HAS_EXTRA_FALSE;
-
- kb_full_color__set_state(param_kb_off ? KB_STATE_OFF : KB_STATE_ON);
- kb_full_color__set_color(param_kb_color[0], param_kb_color[1],
- param_kb_color[2], param_kb_color[3]);
- kb_full_color__set_brightness(param_kb_brightness);
-}
-
-static struct kb_backlight_ops kb_full_color_ops = {
- .set_state = kb_full_color__set_state,
- .set_color = kb_full_color__set_color,
- .set_brightness = kb_full_color__set_brightness,
- .set_mode = kb_full_color__set_mode,
- .init = kb_full_color__init,
-};
-
-static void kb_full_color__init_extra(void)
-{
- S76_DEBUG();
-
- kb_backlight.extra = KB_HAS_EXTRA_TRUE;
-
- kb_full_color__set_state(param_kb_off ? KB_STATE_OFF : KB_STATE_ON);
- kb_full_color__set_color(param_kb_color[0], param_kb_color[1],
- param_kb_color[2], param_kb_color[3]);
- kb_full_color__set_brightness(param_kb_brightness);
-}
-
-static struct kb_backlight_ops kb_full_color_with_extra_ops = {
- .set_state = kb_full_color__set_state,
- .set_color = kb_full_color__set_color,
- .set_brightness = kb_full_color__set_brightness,
- .set_mode = kb_full_color__set_mode,
- .init = kb_full_color__init_extra,
-};
-
-static void kb_wmi(u32 event) {
- if (!kb_backlight.ops)
- return;
-
- switch (event) {
- case 0x81:
- kb_dec_brightness();
- break;
- case 0x82:
- kb_inc_brightness();
- break;
- case 0x83:
- if (!param_kb_cycle_colors)
- kb_next_mode();
- else
- kb_next_color();
- break;
- case 0x9F:
- kb_toggle_state();
- break;
- }
-}
-
-/* Sysfs interface */
-
-static ssize_t s76_brightness_show(struct device *child,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", kb_backlight.brightness);
-}
-
-static ssize_t s76_brightness_store(struct device *child,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- unsigned int val;
- int ret;
-
- if (!kb_backlight.ops)
- return -EINVAL;
-
- ret = kstrtouint(buf, 0, &val);
- if (ret)
- return ret;
-
- kb_backlight.ops->set_brightness(val);
-
- return ret ? : size;
-}
-
-static DEVICE_ATTR(kb_brightness, 0644,
- s76_brightness_show, s76_brightness_store);
-
-static ssize_t s76_state_show(struct device *child,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", kb_backlight.state);
-}
-
-static ssize_t s76_state_store(struct device *child,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- unsigned int val;
- int ret;
-
- if (!kb_backlight.ops)
- return -EINVAL;
-
- ret = kstrtouint(buf, 0, &val);
- if (ret)
- return ret;
-
- val = clamp_t(unsigned, val, 0, 1);
- kb_backlight.ops->set_state(val);
-
- return ret ? : size;
-}
-
-static DEVICE_ATTR(kb_state, 0644,
- s76_state_show, s76_state_store);
-
-static ssize_t s76_mode_show(struct device *child,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", kb_backlight.mode);
-}
-
-static ssize_t s76_mode_store(struct device *child,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- static enum kb_mode modes[] = {
- KB_MODE_RANDOM_COLOR,
- KB_MODE_CUSTOM,
- KB_MODE_BREATHE,
- KB_MODE_CYCLE,
- KB_MODE_WAVE,
- KB_MODE_DANCE,
- KB_MODE_TEMPO,
- KB_MODE_FLASH,
- };
-
- unsigned int val;
- int ret;
-
- if (!kb_backlight.ops)
- return -EINVAL;
-
- ret = kstrtouint(buf, 0, &val);
- if (ret)
- return ret;
-
- val = clamp_t(unsigned, val, 0, 7);
- kb_backlight.ops->set_mode(modes[val]);
-
- return ret ? : size;
-}
-
-static DEVICE_ATTR(kb_mode, 0644,
- s76_mode_show, s76_mode_store);
-
-static ssize_t s76_color_show(struct device *child,
- struct device_attribute *attr, char *buf)
-{
- if (kb_backlight.extra == KB_HAS_EXTRA_TRUE)
- return sprintf(buf, "%s %s %s %s\n",
- kb_colors[kb_backlight.color.left].name,
- kb_colors[kb_backlight.color.center].name,
- kb_colors[kb_backlight.color.right].name,
- kb_colors[kb_backlight.color.extra].name);
- else
- return sprintf(buf, "%s %s %s\n",
- kb_colors[kb_backlight.color.left].name,
- kb_colors[kb_backlight.color.center].name,
- kb_colors[kb_backlight.color.right].name);
-}
-
-static ssize_t s76_color_store(struct device *child,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- unsigned int i, j;
- unsigned int val[4] = {0};
- char left[8];
- char right[8];
- char center[8];
- char extra[8];
-
- if (!kb_backlight.ops)
- return -EINVAL;
-
- i = sscanf(buf, "%7s %7s %7s %7s", left, center, right, extra);
-
- if (i == 1) {
- for (j = 0; j < ARRAY_SIZE(kb_colors); j++) {
- if (!strcmp(left, kb_colors[j].name))
- val[0] = j;
- }
- val[0] = clamp_t(unsigned, val[0], 0, ARRAY_SIZE(kb_colors));
- val[3] = val[2] = val[1] = val[0];
-
- } else if (i == 3 || i == 4) {
- for (j = 0; j < ARRAY_SIZE(kb_colors); j++) {
- if (!strcmp(left, kb_colors[j].name))
- val[0] = j;
- if (!strcmp(center, kb_colors[j].name))
- val[1] = j;
- if (!strcmp(right, kb_colors[j].name))
- val[2] = j;
- if (!strcmp(extra, kb_colors[j].name))
- val[3] = j;
- }
- val[0] = clamp_t(unsigned, val[0], 0, ARRAY_SIZE(kb_colors));
- val[1] = clamp_t(unsigned, val[1], 0, ARRAY_SIZE(kb_colors));
- val[2] = clamp_t(unsigned, val[2], 0, ARRAY_SIZE(kb_colors));
- val[3] = clamp_t(unsigned, val[3], 0, ARRAY_SIZE(kb_colors));
-
- } else
- return -EINVAL;
-
- kb_backlight.ops->set_color(val[0], val[1], val[2], val[3]);
-
- return size;
-}
-static DEVICE_ATTR(kb_color, 0644,
- s76_color_show, s76_color_store);
diff --git a/kb_led.c b/kb_led.c
index c3c9a3c..2cedc6d 100644
--- a/kb_led.c
+++ b/kb_led.c
@@ -19,13 +19,50 @@
#define SET_KB_LED 0x67
-static enum led_brightness kb_led_brightness = LED_OFF;
+union kb_led_color {
+ u32 rgb;
+ struct { u32 b:8, g:8, r:8, : 8; };
+};
+
+enum kb_led_region {
+ KB_LED_REGION_LEFT,
+ KB_LED_REGION_CENTER,
+ KB_LED_REGION_RIGHT,
+ KB_LED_REGION_EXTRA,
+};
+
+static enum led_brightness kb_led_brightness = 72;
+
+static enum led_brightness kb_led_toggle_brightness = 72;
+
+static enum led_brightness kb_led_levels[] = { 48, 72, 96, 144, 192, 255 };
+
+static union kb_led_color kb_led_regions[] = {
+ { .rgb = 0xFFFFFF },
+ { .rgb = 0xFFFFFF },
+ { .rgb = 0xFFFFFF },
+ { .rgb = 0xFFFFFF }
+};
+
+static int kb_led_colors_i = 0;
+
+static union kb_led_color kb_led_colors[] = {
+ { .rgb = 0xFFFFFF },
+ { .rgb = 0x0000FF },
+ { .rgb = 0xFF0000 },
+ { .rgb = 0xFF00FF },
+ { .rgb = 0x00FF00 },
+ { .rgb = 0x00FFFF },
+ { .rgb = 0xFFFF00 }
+};
static enum led_brightness kb_led_get(struct led_classdev *led_cdev) {
return kb_led_brightness;
}
static int kb_led_set(struct led_classdev *led_cdev, enum led_brightness value) {
+ S76_INFO("kb_led_set %d\n", (int)value);
+
if (!s76_wmbb(SET_KB_LED, 0xF4000000 | value, NULL)) {
kb_led_brightness = value;
}
@@ -33,14 +70,60 @@ 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) {
+ u32 cmd;
+
+ S76_INFO("kb_led_color_set %d %x\n", (int)region, (int)color.rgb);
+
+ switch (region) {
+ case KB_LED_REGION_LEFT:
+ cmd = 0xF0000000;
+ break;
+ case KB_LED_REGION_CENTER:
+ cmd = 0xF1000000;
+ break;
+ case KB_LED_REGION_RIGHT:
+ cmd = 0xF2000000;
+ break;
+ case KB_LED_REGION_EXTRA:
+ cmd = 0xF3000000;
+ break;
+ default:
+ return;
+ }
+
+ cmd |= color.b << 16;
+ cmd |= color.r << 8;
+ cmd |= color.g << 0;
+
+ if (!s76_wmbb(SET_KB_LED, cmd, NULL)) {
+ kb_led_regions[region] = color;
+ }
+}
+
static struct led_classdev kb_led = {
- .name = "system76::kbd_backlight",
+ .name = "system76::fun_backlight",
.flags = LED_BRIGHT_HW_CHANGED,
.brightness_get = kb_led_get,
.brightness_set_blocking = kb_led_set,
.max_brightness = 255,
};
+static void kb_led_resume(void) {
+ enum kb_led_region region;
+
+ // Enable keyboard backlight
+ s76_wmbb(SET_KB_LED, 0xE007F001, NULL);
+
+ // Reset current brightness
+ kb_led_set(&kb_led, kb_led_brightness);
+
+ // 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]);
+ }
+}
+
static int __init kb_led_init(struct device *dev) {
int err;
@@ -49,6 +132,8 @@ static int __init kb_led_init(struct device *dev) {
return err;
}
+ kb_led_resume();
+
return 0;
}
@@ -57,3 +142,62 @@ static void __exit kb_led_exit(void) {
led_classdev_unregister(&kb_led);
}
}
+
+static void kb_wmi_brightness(enum led_brightness value) {
+ S76_INFO("kb_wmi_brightness %d\n", (int)value);
+
+ kb_led_set(&kb_led, value);
+ led_classdev_notify_brightness_hw_changed(&kb_led, value);
+}
+
+static void kb_wmi_toggle(void) {
+ if (kb_led_brightness > 0) {
+ kb_led_toggle_brightness = kb_led_brightness;
+ kb_wmi_brightness(LED_OFF);
+ } else {
+ kb_wmi_brightness(kb_led_toggle_brightness);
+ }
+}
+
+static void kb_wmi_dec(void) {
+ int i;
+
+ if (kb_led_brightness > 0) {
+ for (i = sizeof(kb_led_levels)/sizeof(enum led_brightness); i > 0; i--) {
+ if (kb_led_levels[i - 1] < kb_led_brightness) {
+ kb_wmi_brightness(kb_led_levels[i - 1]);
+ break;
+ }
+ }
+ } else {
+ kb_wmi_toggle();
+ }
+}
+
+static void kb_wmi_inc(void) {
+ int i;
+
+ if (kb_led_brightness > 0) {
+ for (i = 0; i < sizeof(kb_led_levels)/sizeof(enum led_brightness); i++) {
+ if (kb_led_levels[i] > kb_led_brightness) {
+ kb_wmi_brightness(kb_led_levels[i]);
+ break;
+ }
+ }
+ } else {
+ kb_wmi_toggle();
+ }
+}
+
+static void kb_wmi_color(void) {
+ enum kb_led_region region;
+
+ kb_led_colors_i += 1;
+ if (kb_led_colors_i >= sizeof(kb_led_colors)/sizeof(union kb_led_color)) {
+ kb_led_colors_i = 0;
+ }
+
+ 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]);
+ }
+}
\ No newline at end of file
diff --git a/system76.c b/system76.c
index 1c0ede8..496030d 100644
--- a/system76.c
+++ b/system76.c
@@ -91,11 +91,11 @@ static int s76_wmbb(u32 method_id, u32 arg, u32 *retval) {
return 0;
}
-#include "ec.c"
+//#include "ec.c"
#include "ap_led.c"
#include "input.c"
#include "kb_led.c"
-#include "kb.c"
+//#include "kb.c"
#include "hwmon.c"
static void s76_debug_wmi(void) {
@@ -160,9 +160,21 @@ static void s76_wmi_notify(u32 value, void *context) {
S76_INFO("WMI event code (%x)\n", event);
switch (event) {
+ case 0x81:
+ kb_wmi_dec();
+ break;
+ case 0x82:
+ kb_wmi_inc();
+ break;
+ case 0x83:
+ kb_wmi_color();
+ break;
case 0x95:
s76_debug_wmi();
break;
+ case 0x9F:
+ kb_wmi_toggle();
+ break;
case 0xF4:
s76_input_airplane_wmi();
break;
@@ -173,7 +185,7 @@ static void s76_wmi_notify(u32 value, void *context) {
s76_input_touchpad_wmi(true);
break;
default:
- kb_wmi(event);
+ S76_INFO("Unknown WMI event code (%x)\n", event);
break;
}
}
@@ -181,11 +193,6 @@ static void s76_wmi_notify(u32 value, void *context) {
static int s76_probe(struct platform_device *dev) {
int err;
- err = ec_init();
- if (unlikely(err)) {
- S76_ERROR("Could not register EC device\n");
- }
-
err = ap_led_init(&dev->dev);
if (unlikely(err)) {
S76_ERROR("Could not register LED device\n");
@@ -201,26 +208,6 @@ static int s76_probe(struct platform_device *dev) {
S76_ERROR("Could not register input device\n");
}
- if (device_create_file(&dev->dev, &dev_attr_kb_brightness) != 0) {
- S76_ERROR("Sysfs attribute creation failed for brightness\n");
- }
-
- if (device_create_file(&dev->dev, &dev_attr_kb_state) != 0) {
- S76_ERROR("Sysfs attribute creation failed for state\n");
- }
-
- if (device_create_file(&dev->dev, &dev_attr_kb_mode) != 0) {
- S76_ERROR("Sysfs attribute creation failed for mode\n");
- }
-
- if (device_create_file(&dev->dev, &dev_attr_kb_color) != 0) {
- S76_ERROR("Sysfs attribute creation failed for color\n");
- }
-
- if (kb_backlight.ops) {
- kb_backlight.ops->init();
- }
-
#ifdef S76_HAS_HWMON
s76_hwmon_init(&dev->dev);
#endif
@@ -249,27 +236,19 @@ static int s76_remove(struct platform_device *dev) {
s76_hwmon_fini(&dev->dev);
#endif
- device_remove_file(&dev->dev, &dev_attr_kb_color);
- device_remove_file(&dev->dev, &dev_attr_kb_mode);
- device_remove_file(&dev->dev, &dev_attr_kb_state);
- device_remove_file(&dev->dev, &dev_attr_kb_brightness);
-
s76_input_exit();
kb_led_exit();
ap_led_exit();
- ec_exit();
-
return 0;
}
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);
- }
+
+ ap_led_resume();
+ kb_led_resume();
return 0;
}
@@ -285,23 +264,22 @@ static struct platform_driver s76_platform_driver = {
static int __init s76_dmi_matched(const struct dmi_system_id *id) {
S76_INFO("Model %s found\n", id->ident);
- kb_backlight.ops = id->driver_data;
return 1;
}
-#define DMI_TABLE(PRODUCT, DATA) { \
+#define DMI_TABLE(PRODUCT) { \
.ident = "System76 " PRODUCT, \
.matches = { \
DMI_MATCH(DMI_SYS_VENDOR, "System76"), \
DMI_MATCH(DMI_PRODUCT_VERSION, PRODUCT), \
}, \
.callback = s76_dmi_matched, \
- .driver_data = DATA, \
+ .driver_data = NULL, \
}
static struct dmi_system_id s76_dmi_table[] __initdata = {
- DMI_TABLE("oryp3-jeremy", &kb_full_color_ops),
+ DMI_TABLE("oryp3-jeremy"),
{}
};
@@ -310,14 +288,6 @@ MODULE_DEVICE_TABLE(dmi, s76_dmi_table);
static int __init s76_init(void) {
int err;
- switch (param_kb_color_num) {
- case 1:
- param_kb_color[1] = param_kb_color[2] = param_kb_color[0] = param_kb_color[3];
- break;
- case 2:
- return -EINVAL;
- }
-
dmi_check_system(s76_dmi_table);
if (!wmi_has_guid(S76_EVENT_GUID)) {