From 27841a685d5202dbdb3cce746cd26dc9ee852e18 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Wed, 27 May 2020 17:08:40 +0200 Subject: [PATCH 01/12] Split code for modularizing --- src/clevo_keyboard.h | 685 ++++++++++++++++++++++++++++++++++ src/tuxedo_keyboard.c | 699 +---------------------------------- src/tuxedo_keyboard_common.h | 51 +++ 3 files changed, 740 insertions(+), 695 deletions(-) create mode 100644 src/clevo_keyboard.h create mode 100644 src/tuxedo_keyboard_common.h diff --git a/src/clevo_keyboard.h b/src/clevo_keyboard.h new file mode 100644 index 0000000..6845649 --- /dev/null +++ b/src/clevo_keyboard.h @@ -0,0 +1,685 @@ +/* +* clevo_keyboard.h +* +* Copyright (C) 2018-2020 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, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "tuxedo_keyboard_common.h" + +#define CLEVO_EVENT_GUID "ABBC0F6B-8EA1-11D1-00A0-C90629100000" +#define CLEVO_EMAIL_GUID "ABBC0F6C-8EA1-11D1-00A0-C90629100000" +#define CLEVO_GET_GUID "ABBC0F6D-8EA1-11D1-00A0-C90629100000" + +#define BRIGHTNESS_MIN 0 +#define BRIGHTNESS_MAX 255 +#define BRIGHTNESS_DEFAULT BRIGHTNESS_MAX + +#define REGION_LEFT 0xF0000000 +#define REGION_CENTER 0xF1000000 +#define REGION_RIGHT 0xF2000000 +#define REGION_EXTRA 0xF3000000 + +#define KEYBOARD_BRIGHTNESS 0xF4000000 + +/* All these COLOR_* macros are never used in the code, don't know why they are + here, maybe for documentation purposes. So won't delete for now */ +#define COLOR_BLACK 0x000000 +#define COLOR_RED 0xFF0000 +#define COLOR_GREEN 0x00FF00 +#define COLOR_BLUE 0x0000FF +#define COLOR_YELLOW 0xFFFF00 +#define COLOR_MAGENTA 0xFF00FF +#define COLOR_CYAN 0x00FFFF +#define COLOR_WHITE 0xFFFFFF + + +#define KB_COLOR_DEFAULT COLOR_WHITE // Default Color: White +#define DEFAULT_BLINKING_PATTERN 0 + +// Submethod IDs for the CLEVO_GET WMI method +#define WMI_SUBMETHOD_ID_GET_EVENT 0x01 +#define WMI_SUBMETHOD_ID_GET_AP 0x46 +#define WMI_SUBMETHOD_ID_SET_KB_LEDS 0x67 /* used to set color, brightness, + blinking pattern, etc. */ + + +// WMI Event Codes +#define WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT 0x81 +#define WMI_KEYEVENT_CODE_INCREASE_BACKLIGHT 0x82 +#define WMI_KEYEVENT_CODE_NEXT_BLINKING_PATTERN 0x83 +#define WMI_KEYEVENT_CODE_TOGGLE_STATE 0x9F + +#define WMI_KEYEVENT_CODE_CYCLE_BRIGHTNESS 0x8A +#define WMI_KEYEVENT_CODE_TOUCHPAD_TOGGLE 0x5D +#define WMI_KEYEVENT_CODE_TOUCHPAD_OFF 0xFC +#define WMI_KEYEVENT_CODE_TOUCHPAD_ON 0xFD + +#define WMI_KEYEVENT_CODE_RFKILL1 0x85 +#define WMI_KEYEVENT_CODE_RFKILL2 0x86 + +static const struct key_entry clevo_wmi_keymap[] = { + // Keyboard backlight (RGB versions) + { KE_KEY, WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT, { KEY_KBDILLUMDOWN } }, + { KE_KEY, WMI_KEYEVENT_CODE_INCREASE_BACKLIGHT, { KEY_KBDILLUMUP } }, + { KE_KEY, WMI_KEYEVENT_CODE_TOGGLE_STATE, { KEY_KBDILLUMTOGGLE } }, + { KE_KEY, WMI_KEYEVENT_CODE_NEXT_BLINKING_PATTERN, { KEY_LIGHTS_TOGGLE } }, + // Single cycle key (white only versions) + { KE_KEY, WMI_KEYEVENT_CODE_CYCLE_BRIGHTNESS, { KEY_KBDILLUMUP } }, + + // Touchpad + // The weirdly named touchpad toggle key that is implemented as KEY_F21 "everywhere" + // (instead of KEY_TOUCHPAD_TOGGLE or on/off) + // Most "new" devices just provide one toggle event + { KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_TOGGLE, { KEY_F21 } }, + // Some "old" devices produces on/off events + { KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_OFF, { KEY_F21 } }, + { KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_ON, { KEY_F21 } }, + // The alternative key events (currently not used) + //{ KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_OFF, { KEY_TOUCHPAD_OFF } }, + //{ KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_ON, { KEY_TOUCHPAD_ON } }, + //{ KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } }, + + { KE_KEY, WMI_KEYEVENT_CODE_RFKILL1, { KEY_RFKILL } }, // Still needed by some devices + { KE_IGNORE, WMI_KEYEVENT_CODE_RFKILL2, { KEY_RFKILL } }, // Older rfkill event + // Note: Volume events need to be ignored as to not interfere with built-in functionality + { KE_IGNORE, 0xfa, { KEY_UNKNOWN } }, // Appears by volume up/down + { KE_IGNORE, 0xfb, { KEY_UNKNOWN } }, // Appears by mute toggle + + { KE_END, 0 } +}; + +#define BRIGHTNESS_STEP 25 + +struct color_t { + u32 code; + char* name; +}; + +struct color_list_t { + uint size; + struct color_t colors[]; +}; + +// Keyboard struct +struct kbd_led_state_t { + u8 has_extra; + u8 enabled; + + struct { + u32 left; + u32 center; + u32 right; + u32 extra; + } color; + + u8 brightness; + u8 blinking_pattern; + u8 whole_kbd_color; +}; + +struct blinking_pattern_t { + u8 key; + u32 value; + const char *const name; +}; + +// Param Validators +static int blinking_pattern_id_validator(const char *value, + const struct kernel_param *blinking_pattern_param); +static const struct kernel_param_ops param_ops_mode_ops = { + .set = blinking_pattern_id_validator, + .get = param_get_int, +}; + +static int brightness_validator(const char *val, + const struct kernel_param *brightness_param); +static const struct kernel_param_ops param_ops_brightness_ops = { + .set = brightness_validator, + .get = param_get_int, +}; + +// Module Parameters +static uint param_color_left = KB_COLOR_DEFAULT; +module_param_named(color_left, param_color_left, uint, S_IRUSR); +MODULE_PARM_DESC(color_left, "Color for the Left Region"); + +static uint param_color_center = KB_COLOR_DEFAULT; +module_param_named(color_center, param_color_center, uint, S_IRUSR); +MODULE_PARM_DESC(color_center, "Color for the Center Region"); + +static uint param_color_right = KB_COLOR_DEFAULT; +module_param_named(color_right, param_color_right, uint, S_IRUSR); +MODULE_PARM_DESC(color_right, "Color for the Right Region"); + +static uint param_color_extra = KB_COLOR_DEFAULT; +module_param_named(color_extra, param_color_extra, uint, S_IRUSR); +MODULE_PARM_DESC(color_extra, "Color for the Extra Region"); + +static ushort param_blinking_pattern = DEFAULT_BLINKING_PATTERN; +module_param_cb(mode, ¶m_ops_mode_ops, ¶m_blinking_pattern, S_IRUSR); +MODULE_PARM_DESC(mode, "Set the keyboard backlight blinking pattern"); + +static ushort param_brightness = BRIGHTNESS_DEFAULT; +module_param_cb(brightness, ¶m_ops_brightness_ops, ¶m_brightness, + S_IRUSR); +MODULE_PARM_DESC(brightness, "Set the Keyboard Brightness"); + +static bool param_state = true; +module_param_named(state, param_state, bool, S_IRUSR); +MODULE_PARM_DESC(state, + "Set the State of the Keyboard TRUE = ON | FALSE = OFF"); + +static struct kbd_led_state_t kbd_led_state = { + .has_extra = 0, + .enabled = 1, + .color = { + .left = KB_COLOR_DEFAULT, .center = KB_COLOR_DEFAULT, + .right = KB_COLOR_DEFAULT, .extra = KB_COLOR_DEFAULT + }, + .brightness = BRIGHTNESS_DEFAULT, + .blinking_pattern = DEFAULT_BLINKING_PATTERN, + .whole_kbd_color = 7 +}; + +static struct color_list_t color_list = { + .size = 8, + .colors = { + { .name = "BLACK", .code = 0x000000 }, // 0 + { .name = "RED", .code = 0xFF0000 }, // 1 + { .name = "GREEN", .code = 0x00FF00 }, // 2 + { .name = "BLUE", .code = 0x0000FF }, // 3 + { .name = "YELLOW", .code = 0xFFFF00 }, // 4 + { .name = "MAGENTA", .code = 0xFF00FF }, // 5 + { .name = "CYAN", .code = 0x00FFFF }, // 6 + { .name = "WHITE", .code = 0xFFFFFF }, // 7 + } +}; + +static struct blinking_pattern_t blinking_patterns[] = { + { .key = 0,.value = 0,.name = "CUSTOM"}, + { .key = 1,.value = 0x1002a000,.name = "BREATHE"}, + { .key = 2,.value = 0x33010000,.name = "CYCLE"}, + { .key = 3,.value = 0x80000000,.name = "DANCE"}, + { .key = 4,.value = 0xA0000000,.name = "FLASH"}, + { .key = 5,.value = 0x70000000,.name = "RANDOM_COLOR"}, + { .key = 6,.value = 0x90000000,.name = "TEMPO"}, + { .key = 7,.value = 0xB0000000,.name = "WAVE"} +}; + +// Sysfs Interface Methods +// Sysfs Interface for the keyboard state (ON / OFF) +static ssize_t show_state_fs(struct device *child, + struct device_attribute *attr, char *buffer) +{ + return sprintf(buffer, "%d\n", kbd_led_state.enabled); +} + +// Sysfs Interface for the color of the left side (Color as hexvalue) +static ssize_t show_color_left_fs(struct device *child, + struct device_attribute *attr, char *buffer) +{ + return sprintf(buffer, "%06x\n", kbd_led_state.color.left); +} + +// Sysfs Interface for the color of the center (Color as hexvalue) +static ssize_t show_color_center_fs(struct device *child, + struct device_attribute *attr, char *buffer) +{ + return sprintf(buffer, "%06x\n", kbd_led_state.color.center); +} + +// Sysfs Interface for the color of the right side (Color as hexvalue) +static ssize_t show_color_right_fs(struct device *child, + struct device_attribute *attr, char *buffer) +{ + return sprintf(buffer, "%06x\n", kbd_led_state.color.right); +} + +// Sysfs Interface for the color of the extra region (Color as hexvalue) +static ssize_t show_color_extra_fs(struct device *child, + struct device_attribute *attr, char *buffer) +{ + return sprintf(buffer, "%06x\n", kbd_led_state.color.extra); +} + +// Sysfs Interface for the keyboard brightness (unsigned int) +static ssize_t show_brightness_fs(struct device *child, + struct device_attribute *attr, char *buffer) +{ + return sprintf(buffer, "%d\n", kbd_led_state.brightness); +} + +// Sysfs Interface for the backlight blinking pattern +static ssize_t show_blinking_patterns_fs(struct device *child, struct device_attribute *attr, + char *buffer) +{ + return sprintf(buffer, "%d\n", kbd_led_state.blinking_pattern); +} + +// Sysfs Interface for if the keyboard has extra region +static ssize_t show_hasextra_fs(struct device *child, + struct device_attribute *attr, char *buffer) +{ + return sprintf(buffer, "%d\n", kbd_led_state.has_extra); +} + +static int evaluate_wmi_method_clevo(u32 submethod_id, u32 submethod_arg, u32 * retval) +{ + struct acpi_buffer acpi_input = { (acpi_size) sizeof(submethod_arg), &submethod_arg }; + struct acpi_buffer acpi_output = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + acpi_status status; + u32 wmi_output; + + TUXEDO_DEBUG("evaluate wmi method: %0#4x IN : %0#6x\n", submethod_id, submethod_arg); + + status = wmi_evaluate_method(CLEVO_GET_GUID, 0x00, submethod_id, + &acpi_input, &acpi_output); + + if (unlikely(ACPI_FAILURE(status))) { + TUXEDO_ERROR("evaluate_wmi_method error"); + return -EIO; + } + + obj = (union acpi_object *)acpi_output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) { + wmi_output = (u32) obj->integer.value; + } else { + wmi_output = 0; + } + + TUXEDO_DEBUG("WMI submethod %0#4x output: %0#6x (input: %0#6x)\n", + submethod_id, wmi_output, submethod_arg); + + if (likely(retval)) { /* if no NULL pointer */ + *retval = wmi_output; + } + + kfree(obj); + return 0; +} + +static void set_brightness(u8 brightness) +{ + TUXEDO_INFO("Set brightness on %d", brightness); + if (!evaluate_wmi_method_clevo + (WMI_SUBMETHOD_ID_SET_KB_LEDS, 0xF4000000 | brightness, NULL)) { + kbd_led_state.brightness = brightness; + } +} + +static ssize_t set_brightness_fs(struct device *child, + struct device_attribute *attr, + const char *buffer, size_t size) +{ + unsigned int val; + // hier unsigned? + + int err = kstrtouint(buffer, 0, &val); + if (err) { + return err; + } + + val = clamp_t(u8, val, BRIGHTNESS_MIN, BRIGHTNESS_MAX); + set_brightness(val); + + return size; +} + +static int set_enabled_cmd(u8 state) +{ + u32 cmd = 0xE0000000; + TUXEDO_INFO("Set keyboard enabled to: %d\n", state); + + if (state == 0) { + cmd |= 0x003001; + } else { + cmd |= 0x07F001; + } + + return evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_SET_KB_LEDS, cmd, NULL); +} + +static void set_enabled(u8 state) +{ + if (!set_enabled_cmd(state)) { + kbd_led_state.enabled = state; + } +} + +static ssize_t set_state_fs(struct device *child, struct device_attribute *attr, + const char *buffer, size_t size) +{ + unsigned int state; + + int err = kstrtouint(buffer, 0, &state); + if (err) { + return err; + } + + state = clamp_t(u8, state, 0, 1); + + set_enabled(state); + + return size; +} + +static int set_color(u32 region, u32 color) +{ + u32 cset = + ((color & 0x0000FF) << 16) | ((color & 0xFF0000) >> 8) | + ((color & 0x00FF00) >> 8); + u32 wmi_submethod_arg = region | cset; + + TUXEDO_DEBUG("Set Color '%08x' for region '%08x'", color, region); + + return evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_SET_KB_LEDS, wmi_submethod_arg, NULL); +} +static int set_color_code_region(u32 region, u32 colorcode) +{ + int err; + if (0 == (err = set_color(region, colorcode))) { + // after succesfully setting color, update our state struct + // depending on which region was changed + switch (region) { + case REGION_LEFT: + kbd_led_state.color.left = colorcode; + break; + case REGION_CENTER: + kbd_led_state.color.center = colorcode; + break; + case REGION_RIGHT: + kbd_led_state.color.right = colorcode; + break; + case REGION_EXTRA: + kbd_led_state.color.extra = colorcode; + break; + } + } + + return err; +} + +static int set_color_string_region(const char *color_string, size_t size, u32 region) +{ + u32 colorcode; + int err = kstrtouint(color_string, 0, &colorcode); + + if (err) { + return err; + } + + if (!set_color(region, colorcode)) { + // after succesfully setting color, update our state struct + // depending on which region was changed + switch (region) { + case REGION_LEFT: + kbd_led_state.color.left = colorcode; + break; + case REGION_CENTER: + kbd_led_state.color.center = colorcode; + break; + case REGION_RIGHT: + kbd_led_state.color.right = colorcode; + break; + case REGION_EXTRA: + kbd_led_state.color.extra = colorcode; + break; + } + } + + return size; +} + +static ssize_t set_color_left_fs(struct device *child, + struct device_attribute *attr, + const char *color_string, size_t size) +{ + return set_color_string_region(color_string, size, REGION_LEFT); +} + +static ssize_t set_color_center_fs(struct device *child, + struct device_attribute *attr, + const char *color_string, size_t size) +{ + return set_color_string_region(color_string, size, REGION_CENTER); +} + +static ssize_t set_color_right_fs(struct device *child, + struct device_attribute *attr, + const char *color_string, size_t size) +{ + return set_color_string_region(color_string, size, REGION_RIGHT); +} + +static ssize_t set_color_extra_fs(struct device *child, + struct device_attribute *attr, + const char *color_string, size_t size) +{ + return set_color_string_region(color_string, size, REGION_EXTRA); +} + +static int set_next_color_whole_kb(void) +{ + /* "Calculate" new to-be color */ + u32 new_color_id; + u32 new_color_code; + + new_color_id = kbd_led_state.whole_kbd_color + 1; + if (new_color_id >= color_list.size) { + new_color_id = 0; + } + new_color_code = color_list.colors[new_color_id].code; + + TUXEDO_INFO("set_next_color_whole_kb(): new_color_id: %i, new_color_code %X", + new_color_id, new_color_code); + + /* Set color on all four regions*/ + set_color_code_region(REGION_LEFT, new_color_code); + set_color_code_region(REGION_CENTER, new_color_code); + set_color_code_region(REGION_RIGHT, new_color_code); + set_color_code_region(REGION_EXTRA, new_color_code); + + kbd_led_state.whole_kbd_color = new_color_id; + + return 0; +} + +static void set_blinking_pattern(u8 blinkling_pattern) +{ + TUXEDO_INFO("set_mode on %s", blinking_patterns[blinkling_pattern].name); + + if (!evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_SET_KB_LEDS, blinking_patterns[blinkling_pattern].value, NULL)) { + // wmi method was succesfull so update ur internal state struct + kbd_led_state.blinking_pattern = blinkling_pattern; + } + + if (blinkling_pattern == 0) { // 0 is the "custom" blinking pattern + + // so just set all regions to the stored colors + set_color(REGION_LEFT, kbd_led_state.color.left); + set_color(REGION_CENTER, kbd_led_state.color.center); + set_color(REGION_RIGHT, kbd_led_state.color.right); + + if (kbd_led_state.has_extra == 1) { + set_color(REGION_EXTRA, kbd_led_state.color.extra); + } + } +} + +static ssize_t set_blinking_pattern_fs(struct device *child, + struct device_attribute *attr, + const char *buffer, size_t size) +{ + unsigned int blinking_pattern; + + int err = kstrtouint(buffer, 0, &blinking_pattern); + if (err) { + return err; + } + + blinking_pattern = clamp_t(u8, blinking_pattern, 0, ARRAY_SIZE(blinking_patterns) - 1); + set_blinking_pattern(blinking_pattern); + + return size; +} + +static int blinking_pattern_id_validator(const char *value, + const struct kernel_param *blinking_pattern_param) +{ + int blinking_pattern = 0; + + if (kstrtoint(value, 10, &blinking_pattern) != 0 + || blinking_pattern < 0 + || blinking_pattern > (ARRAY_SIZE(blinking_patterns) - 1)) { + return -EINVAL; + } + + return param_set_int(value, blinking_pattern_param); +} + +static int brightness_validator(const char *value, + const struct kernel_param *brightness_param) +{ + int brightness = 0; + + if (kstrtoint(value, 10, &brightness) != 0 + || brightness < BRIGHTNESS_MIN + || brightness > BRIGHTNESS_MAX) { + return -EINVAL; + } + + return param_set_int(value, brightness_param); +} + +static void tuxedo_wmi_notify(u32 value, void *context) +{ + u32 key_event; + + evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_GET_EVENT, 0, &key_event); + TUXEDO_DEBUG("WMI event (%0#6x)\n", key_event); + + switch (key_event) { + case WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT: + if (kbd_led_state.brightness == BRIGHTNESS_MIN + || (kbd_led_state.brightness - 25) < BRIGHTNESS_MIN) { + set_brightness(BRIGHTNESS_MIN); + } else { + set_brightness(kbd_led_state.brightness - 25); + } + + break; + + case WMI_KEYEVENT_CODE_INCREASE_BACKLIGHT: + if (kbd_led_state.brightness == BRIGHTNESS_MAX + || (kbd_led_state.brightness + 25) > BRIGHTNESS_MAX) { + set_brightness(BRIGHTNESS_MAX); + } else { + set_brightness(kbd_led_state.brightness + 25); + } + + break; + +// case WMI_CODE_NEXT_BLINKING_PATTERN: +// set_blinking_pattern((kbd_led_state.blinking_pattern + 1) > +// (ARRAY_SIZE(blinking_patterns) - 1) ? 0 : (kbd_led_state.blinking_pattern + 1)); +// break; + + case WMI_KEYEVENT_CODE_NEXT_BLINKING_PATTERN: + set_next_color_whole_kb(); + break; + + case WMI_KEYEVENT_CODE_TOGGLE_STATE: + set_enabled(kbd_led_state.enabled == 0 ? 1 : 0); + break; + + default: + break; + } + + if (!sparse_keymap_report_known_event(tuxedo_input_device, key_event, 1, true)) { + TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", key_event, key_event); + } +} + +static int tuxedo_wmi_probe(struct platform_device *dev) +{ + int status = wmi_install_notify_handler(CLEVO_EVENT_GUID, + tuxedo_wmi_notify, NULL); + + TUXEDO_DEBUG("tuxedo_wmi_probe status: (%0#6x)", status); + + if (unlikely(ACPI_FAILURE(status))) { + TUXEDO_ERROR("Could not register WMI notify handler (%0#6x)\n", + status); + return -EIO; + } + + evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_GET_AP, 0, NULL); + + return 0; +} + +static int tuxedo_wmi_remove(struct platform_device *dev) +{ + wmi_remove_notify_handler(CLEVO_EVENT_GUID); + return 0; +} + +static int tuxedo_wmi_suspend(struct platform_device *dev, pm_message_t state) +{ + // turning the keyboard off prevents default colours showing on resume + set_enabled_cmd(0); + return 0; +} + +static int tuxedo_wmi_resume(struct platform_device *dev) +{ + evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_GET_AP, 0, NULL); + + set_color(REGION_LEFT, kbd_led_state.color.left); + set_color(REGION_CENTER, kbd_led_state.color.center); + set_color(REGION_RIGHT, kbd_led_state.color.right); + if (kbd_led_state.has_extra) + set_color(REGION_EXTRA, kbd_led_state.color.extra); + + set_blinking_pattern(kbd_led_state.blinking_pattern); + set_brightness(kbd_led_state.brightness); + set_enabled(kbd_led_state.enabled); + + return 0; +} + +static struct platform_driver platform_driver_clevo = { + .remove = tuxedo_wmi_remove, + .suspend = tuxedo_wmi_suspend, + .resume = tuxedo_wmi_resume, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +// Sysfs attribute file permissions and method linking +static DEVICE_ATTR(state, 0644, show_state_fs, set_state_fs); +static DEVICE_ATTR(color_left, 0644, show_color_left_fs, set_color_left_fs); +static DEVICE_ATTR(color_center, 0644, show_color_center_fs, + set_color_center_fs); +static DEVICE_ATTR(color_right, 0644, show_color_right_fs, set_color_right_fs); +static DEVICE_ATTR(color_extra, 0644, show_color_extra_fs, set_color_extra_fs); +static DEVICE_ATTR(brightness, 0644, show_brightness_fs, set_brightness_fs); +static DEVICE_ATTR(mode, 0644, show_blinking_patterns_fs, set_blinking_pattern_fs); +static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL); diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index e958a50..841ba7b 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -28,10 +28,8 @@ #include #include #include - -#define CLEVO_EVENT_GUID "ABBC0F6B-8EA1-11D1-00A0-C90629100000" -#define CLEVO_EMAIL_GUID "ABBC0F6C-8EA1-11D1-00A0-C90629100000" -#define CLEVO_GET_GUID "ABBC0F6D-8EA1-11D1-00A0-C90629100000" +#include "tuxedo_keyboard_common.h" +#include "clevo_keyboard.h" MODULE_AUTHOR("TUXEDO Computers GmbH "); MODULE_DESCRIPTION("TUXEDO Computers keyboard & keyboard backlight Driver"); @@ -41,695 +39,6 @@ MODULE_VERSION("2.0.4"); MODULE_ALIAS("wmi:" CLEVO_EVENT_GUID); MODULE_ALIAS("wmi:" CLEVO_GET_GUID); -/* :::: Module specific Constants and simple Macros :::: */ - -#define __TUXEDO_PR(lvl, fmt, ...) do { pr_##lvl(fmt, ##__VA_ARGS__); } while (0) -#define TUXEDO_INFO(fmt, ...) __TUXEDO_PR(info, fmt, ##__VA_ARGS__) -#define TUXEDO_ERROR(fmt, ...) __TUXEDO_PR(err, fmt, ##__VA_ARGS__) -#define TUXEDO_DEBUG(fmt, ...) __TUXEDO_PR(debug, "[%s:%u] " fmt, __func__, __LINE__, ##__VA_ARGS__) - -#define BRIGHTNESS_MIN 0 -#define BRIGHTNESS_MAX 255 -#define BRIGHTNESS_DEFAULT BRIGHTNESS_MAX - -#define REGION_LEFT 0xF0000000 -#define REGION_CENTER 0xF1000000 -#define REGION_RIGHT 0xF2000000 -#define REGION_EXTRA 0xF3000000 - -#define KEYBOARD_BRIGHTNESS 0xF4000000 - -/* All these COLOR_* macros are never used in the code, don't know why they are - here, maybe for documentation purposes. So won't delete for now */ -#define COLOR_BLACK 0x000000 -#define COLOR_RED 0xFF0000 -#define COLOR_GREEN 0x00FF00 -#define COLOR_BLUE 0x0000FF -#define COLOR_YELLOW 0xFFFF00 -#define COLOR_MAGENTA 0xFF00FF -#define COLOR_CYAN 0x00FFFF -#define COLOR_WHITE 0xFFFFFF - - -#define KB_COLOR_DEFAULT COLOR_WHITE // Default Color: White -#define DEFAULT_BLINKING_PATTERN 0 - -// Submethod IDs for the CLEVO_GET WMI method -#define WMI_SUBMETHOD_ID_GET_EVENT 0x01 -#define WMI_SUBMETHOD_ID_GET_AP 0x46 -#define WMI_SUBMETHOD_ID_SET_KB_LEDS 0x67 /* used to set color, brightness, - blinking pattern, etc. */ - - -// WMI Event Codes -#define WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT 0x81 -#define WMI_KEYEVENT_CODE_INCREASE_BACKLIGHT 0x82 -#define WMI_KEYEVENT_CODE_NEXT_BLINKING_PATTERN 0x83 -#define WMI_KEYEVENT_CODE_TOGGLE_STATE 0x9F - -#define WMI_KEYEVENT_CODE_CYCLE_BRIGHTNESS 0x8A -#define WMI_KEYEVENT_CODE_TOUCHPAD_TOGGLE 0x5D -#define WMI_KEYEVENT_CODE_TOUCHPAD_OFF 0xFC -#define WMI_KEYEVENT_CODE_TOUCHPAD_ON 0xFD - -#define WMI_KEYEVENT_CODE_RFKILL1 0x85 -#define WMI_KEYEVENT_CODE_RFKILL2 0x86 - -static const struct key_entry clevo_wmi_keymap[] = { - // Keyboard backlight (RGB versions) - { KE_KEY, WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT, { KEY_KBDILLUMDOWN } }, - { KE_KEY, WMI_KEYEVENT_CODE_INCREASE_BACKLIGHT, { KEY_KBDILLUMUP } }, - { KE_KEY, WMI_KEYEVENT_CODE_TOGGLE_STATE, { KEY_KBDILLUMTOGGLE } }, - { KE_KEY, WMI_KEYEVENT_CODE_NEXT_BLINKING_PATTERN, { KEY_LIGHTS_TOGGLE } }, - // Single cycle key (white only versions) - { KE_KEY, WMI_KEYEVENT_CODE_CYCLE_BRIGHTNESS, { KEY_KBDILLUMUP } }, - - // Touchpad - // The weirdly named touchpad toggle key that is implemented as KEY_F21 "everywhere" - // (instead of KEY_TOUCHPAD_TOGGLE or on/off) - // Most "new" devices just provide one toggle event - { KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_TOGGLE, { KEY_F21 } }, - // Some "old" devices produces on/off events - { KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_OFF, { KEY_F21 } }, - { KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_ON, { KEY_F21 } }, - // The alternative key events (currently not used) - //{ KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_OFF, { KEY_TOUCHPAD_OFF } }, - //{ KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_ON, { KEY_TOUCHPAD_ON } }, - //{ KE_KEY, WMI_KEYEVENT_CODE_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } }, - - { KE_KEY, WMI_KEYEVENT_CODE_RFKILL1, { KEY_RFKILL } }, // Still needed by some devices - { KE_IGNORE, WMI_KEYEVENT_CODE_RFKILL2, { KEY_RFKILL } }, // Older rfkill event - // Note: Volume events need to be ignored as to not interfere with built-in functionality - { KE_IGNORE, 0xfa, { KEY_UNKNOWN } }, // Appears by volume up/down - { KE_IGNORE, 0xfb, { KEY_UNKNOWN } }, // Appears by mute toggle - - { KE_END, 0 } -}; - -#define BRIGHTNESS_STEP 25 - -struct color_t { - u32 code; - char* name; -}; - -struct color_list_t { - uint size; - struct color_t colors[]; -}; - -// Keyboard struct -struct kbd_led_state_t { - u8 has_extra; - u8 enabled; - - struct { - u32 left; - u32 center; - u32 right; - u32 extra; - } color; - - u8 brightness; - u8 blinking_pattern; - u8 whole_kbd_color; -}; - -struct blinking_pattern_t { - u8 key; - u32 value; - const char *const name; -}; - -struct platform_device *tuxedo_platform_device; -static struct input_dev *tuxedo_input_device; - -// Param Validators -static int blinking_pattern_id_validator(const char *value, - const struct kernel_param *blinking_pattern_param); -static const struct kernel_param_ops param_ops_mode_ops = { - .set = blinking_pattern_id_validator, - .get = param_get_int, -}; - -static int brightness_validator(const char *val, - const struct kernel_param *brightness_param); -static const struct kernel_param_ops param_ops_brightness_ops = { - .set = brightness_validator, - .get = param_get_int, -}; - -// Module Parameters -static uint param_color_left = KB_COLOR_DEFAULT; -module_param_named(color_left, param_color_left, uint, S_IRUSR); -MODULE_PARM_DESC(color_left, "Color for the Left Region"); - -static uint param_color_center = KB_COLOR_DEFAULT; -module_param_named(color_center, param_color_center, uint, S_IRUSR); -MODULE_PARM_DESC(color_center, "Color for the Center Region"); - -static uint param_color_right = KB_COLOR_DEFAULT; -module_param_named(color_right, param_color_right, uint, S_IRUSR); -MODULE_PARM_DESC(color_right, "Color for the Right Region"); - -static uint param_color_extra = KB_COLOR_DEFAULT; -module_param_named(color_extra, param_color_extra, uint, S_IRUSR); -MODULE_PARM_DESC(color_extra, "Color for the Extra Region"); - -static ushort param_blinking_pattern = DEFAULT_BLINKING_PATTERN; -module_param_cb(mode, ¶m_ops_mode_ops, ¶m_blinking_pattern, S_IRUSR); -MODULE_PARM_DESC(mode, "Set the keyboard backlight blinking pattern"); - -static ushort param_brightness = BRIGHTNESS_DEFAULT; -module_param_cb(brightness, ¶m_ops_brightness_ops, ¶m_brightness, - S_IRUSR); -MODULE_PARM_DESC(brightness, "Set the Keyboard Brightness"); - -static bool param_state = true; -module_param_named(state, param_state, bool, S_IRUSR); -MODULE_PARM_DESC(state, - "Set the State of the Keyboard TRUE = ON | FALSE = OFF"); - -static struct kbd_led_state_t kbd_led_state = { - .has_extra = 0, - .enabled = 1, - .color = { - .left = KB_COLOR_DEFAULT, .center = KB_COLOR_DEFAULT, - .right = KB_COLOR_DEFAULT, .extra = KB_COLOR_DEFAULT - }, - .brightness = BRIGHTNESS_DEFAULT, - .blinking_pattern = DEFAULT_BLINKING_PATTERN, - .whole_kbd_color = 7 -}; - -static struct color_list_t color_list = { - .size = 8, - .colors = { - { .name = "BLACK", .code = 0x000000 }, // 0 - { .name = "RED", .code = 0xFF0000 }, // 1 - { .name = "GREEN", .code = 0x00FF00 }, // 2 - { .name = "BLUE", .code = 0x0000FF }, // 3 - { .name = "YELLOW", .code = 0xFFFF00 }, // 4 - { .name = "MAGENTA", .code = 0xFF00FF }, // 5 - { .name = "CYAN", .code = 0x00FFFF }, // 6 - { .name = "WHITE", .code = 0xFFFFFF }, // 7 - } -}; - -static struct blinking_pattern_t blinking_patterns[] = { - { .key = 0,.value = 0,.name = "CUSTOM"}, - { .key = 1,.value = 0x1002a000,.name = "BREATHE"}, - { .key = 2,.value = 0x33010000,.name = "CYCLE"}, - { .key = 3,.value = 0x80000000,.name = "DANCE"}, - { .key = 4,.value = 0xA0000000,.name = "FLASH"}, - { .key = 5,.value = 0x70000000,.name = "RANDOM_COLOR"}, - { .key = 6,.value = 0x90000000,.name = "TEMPO"}, - { .key = 7,.value = 0xB0000000,.name = "WAVE"} -}; - -// Sysfs Interface Methods -// Sysfs Interface for the keyboard state (ON / OFF) -static ssize_t show_state_fs(struct device *child, - struct device_attribute *attr, char *buffer) -{ - return sprintf(buffer, "%d\n", kbd_led_state.enabled); -} - -// Sysfs Interface for the color of the left side (Color as hexvalue) -static ssize_t show_color_left_fs(struct device *child, - struct device_attribute *attr, char *buffer) -{ - return sprintf(buffer, "%06x\n", kbd_led_state.color.left); -} - -// Sysfs Interface for the color of the center (Color as hexvalue) -static ssize_t show_color_center_fs(struct device *child, - struct device_attribute *attr, char *buffer) -{ - return sprintf(buffer, "%06x\n", kbd_led_state.color.center); -} - -// Sysfs Interface for the color of the right side (Color as hexvalue) -static ssize_t show_color_right_fs(struct device *child, - struct device_attribute *attr, char *buffer) -{ - return sprintf(buffer, "%06x\n", kbd_led_state.color.right); -} - -// Sysfs Interface for the color of the extra region (Color as hexvalue) -static ssize_t show_color_extra_fs(struct device *child, - struct device_attribute *attr, char *buffer) -{ - return sprintf(buffer, "%06x\n", kbd_led_state.color.extra); -} - -// Sysfs Interface for the keyboard brightness (unsigned int) -static ssize_t show_brightness_fs(struct device *child, - struct device_attribute *attr, char *buffer) -{ - return sprintf(buffer, "%d\n", kbd_led_state.brightness); -} - -// Sysfs Interface for the backlight blinking pattern -static ssize_t show_blinking_patterns_fs(struct device *child, struct device_attribute *attr, - char *buffer) -{ - return sprintf(buffer, "%d\n", kbd_led_state.blinking_pattern); -} - -// Sysfs Interface for if the keyboard has extra region -static ssize_t show_hasextra_fs(struct device *child, - struct device_attribute *attr, char *buffer) -{ - return sprintf(buffer, "%d\n", kbd_led_state.has_extra); -} - -static int tuxedo_evaluate_wmi_method(u32 submethod_id, u32 submethod_arg, u32 * retval) -{ - struct acpi_buffer acpi_input = { (acpi_size) sizeof(submethod_arg), &submethod_arg }; - struct acpi_buffer acpi_output = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; - acpi_status status; - u32 wmi_output; - - TUXEDO_DEBUG("evaluate wmi method: %0#4x IN : %0#6x\n", submethod_id, submethod_arg); - - status = wmi_evaluate_method(CLEVO_GET_GUID, 0x00, submethod_id, - &acpi_input, &acpi_output); - - if (unlikely(ACPI_FAILURE(status))) { - TUXEDO_ERROR("evaluate_wmi_method error"); - return -EIO; - } - - obj = (union acpi_object *)acpi_output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) { - wmi_output = (u32) obj->integer.value; - } else { - wmi_output = 0; - } - - TUXEDO_DEBUG("WMI submethod %0#4x output: %0#6x (input: %0#6x)\n", - submethod_id, wmi_output, submethod_arg); - - if (likely(retval)) { /* if no NULL pointer */ - *retval = wmi_output; - } - - kfree(obj); - return 0; -} - -static void set_brightness(u8 brightness) -{ - TUXEDO_INFO("Set brightness on %d", brightness); - if (!tuxedo_evaluate_wmi_method - (WMI_SUBMETHOD_ID_SET_KB_LEDS, 0xF4000000 | brightness, NULL)) { - kbd_led_state.brightness = brightness; - } -} - -static ssize_t set_brightness_fs(struct device *child, - struct device_attribute *attr, - const char *buffer, size_t size) -{ - unsigned int val; - // hier unsigned? - - int err = kstrtouint(buffer, 0, &val); - if (err) { - return err; - } - - val = clamp_t(u8, val, BRIGHTNESS_MIN, BRIGHTNESS_MAX); - set_brightness(val); - - return size; -} - -static int set_enabled_cmd(u8 state) -{ - u32 cmd = 0xE0000000; - TUXEDO_INFO("Set keyboard enabled to: %d\n", state); - - if (state == 0) { - cmd |= 0x003001; - } else { - cmd |= 0x07F001; - } - - return tuxedo_evaluate_wmi_method(WMI_SUBMETHOD_ID_SET_KB_LEDS, cmd, NULL); -} - -static void set_enabled(u8 state) -{ - if (!set_enabled_cmd(state)) { - kbd_led_state.enabled = state; - } -} - -static ssize_t set_state_fs(struct device *child, struct device_attribute *attr, - const char *buffer, size_t size) -{ - unsigned int state; - - int err = kstrtouint(buffer, 0, &state); - if (err) { - return err; - } - - state = clamp_t(u8, state, 0, 1); - - set_enabled(state); - - return size; -} - -static int set_color(u32 region, u32 color) -{ - u32 cset = - ((color & 0x0000FF) << 16) | ((color & 0xFF0000) >> 8) | - ((color & 0x00FF00) >> 8); - u32 wmi_submethod_arg = region | cset; - - TUXEDO_DEBUG("Set Color '%08x' for region '%08x'", color, region); - - return tuxedo_evaluate_wmi_method(WMI_SUBMETHOD_ID_SET_KB_LEDS, wmi_submethod_arg, NULL); -} -static int set_color_code_region(u32 region, u32 colorcode) -{ - int err; - if (0 == (err = set_color(region, colorcode))) { - // after succesfully setting color, update our state struct - // depending on which region was changed - switch (region) { - case REGION_LEFT: - kbd_led_state.color.left = colorcode; - break; - case REGION_CENTER: - kbd_led_state.color.center = colorcode; - break; - case REGION_RIGHT: - kbd_led_state.color.right = colorcode; - break; - case REGION_EXTRA: - kbd_led_state.color.extra = colorcode; - break; - } - } - - return err; -} - -static int set_color_string_region(const char *color_string, size_t size, u32 region) -{ - u32 colorcode; - int err = kstrtouint(color_string, 0, &colorcode); - - if (err) { - return err; - } - - if (!set_color(region, colorcode)) { - // after succesfully setting color, update our state struct - // depending on which region was changed - switch (region) { - case REGION_LEFT: - kbd_led_state.color.left = colorcode; - break; - case REGION_CENTER: - kbd_led_state.color.center = colorcode; - break; - case REGION_RIGHT: - kbd_led_state.color.right = colorcode; - break; - case REGION_EXTRA: - kbd_led_state.color.extra = colorcode; - break; - } - } - - return size; -} - -static ssize_t set_color_left_fs(struct device *child, - struct device_attribute *attr, - const char *color_string, size_t size) -{ - return set_color_string_region(color_string, size, REGION_LEFT); -} - -static ssize_t set_color_center_fs(struct device *child, - struct device_attribute *attr, - const char *color_string, size_t size) -{ - return set_color_string_region(color_string, size, REGION_CENTER); -} - -static ssize_t set_color_right_fs(struct device *child, - struct device_attribute *attr, - const char *color_string, size_t size) -{ - return set_color_string_region(color_string, size, REGION_RIGHT); -} - -static ssize_t set_color_extra_fs(struct device *child, - struct device_attribute *attr, - const char *color_string, size_t size) -{ - return set_color_string_region(color_string, size, REGION_EXTRA); -} - -static int set_next_color_whole_kb(void) -{ - /* "Calculate" new to-be color */ - u32 new_color_id; - u32 new_color_code; - - new_color_id = kbd_led_state.whole_kbd_color + 1; - if (new_color_id >= color_list.size) { - new_color_id = 0; - } - new_color_code = color_list.colors[new_color_id].code; - - TUXEDO_INFO("set_next_color_whole_kb(): new_color_id: %i, new_color_code %X", - new_color_id, new_color_code); - - /* Set color on all four regions*/ - // TODO: perhaps use set_color_region here, because of better struct state - // handling (or implement something like it myself) - set_color_code_region(REGION_LEFT, new_color_code); - set_color_code_region(REGION_CENTER, new_color_code); - set_color_code_region(REGION_RIGHT, new_color_code); - set_color_code_region(REGION_EXTRA, new_color_code); - - kbd_led_state.whole_kbd_color = new_color_id; - - return 0; -} - -static void set_blinking_pattern(u8 blinkling_pattern) -{ - TUXEDO_INFO("set_mode on %s", blinking_patterns[blinkling_pattern].name); - - if (!tuxedo_evaluate_wmi_method(WMI_SUBMETHOD_ID_SET_KB_LEDS, blinking_patterns[blinkling_pattern].value, NULL)) { - // wmi method was succesfull so update ur internal state struct - kbd_led_state.blinking_pattern = blinkling_pattern; - } - - if (blinkling_pattern == 0) { // 0 is the "custom" blinking pattern - - // so just set all regions to the stored colors - set_color(REGION_LEFT, kbd_led_state.color.left); - set_color(REGION_CENTER, kbd_led_state.color.center); - set_color(REGION_RIGHT, kbd_led_state.color.right); - - if (kbd_led_state.has_extra == 1) { - set_color(REGION_EXTRA, kbd_led_state.color.extra); - } - } -} - -static ssize_t set_blinking_pattern_fs(struct device *child, - struct device_attribute *attr, - const char *buffer, size_t size) -{ - unsigned int blinking_pattern; - - int err = kstrtouint(buffer, 0, &blinking_pattern); - if (err) { - return err; - } - - blinking_pattern = clamp_t(u8, blinking_pattern, 0, ARRAY_SIZE(blinking_patterns) - 1); - set_blinking_pattern(blinking_pattern); - - return size; -} - -static int blinking_pattern_id_validator(const char *value, - const struct kernel_param *blinking_pattern_param) -{ - int blinking_pattern = 0; - - if (kstrtoint(value, 10, &blinking_pattern) != 0 - || blinking_pattern < 0 - || blinking_pattern > (ARRAY_SIZE(blinking_patterns) - 1)) { - return -EINVAL; - } - - return param_set_int(value, blinking_pattern_param); -} - -static int brightness_validator(const char *value, - const struct kernel_param *brightness_param) -{ - int brightness = 0; - - if (kstrtoint(value, 10, &brightness) != 0 - || brightness < BRIGHTNESS_MIN - || brightness > BRIGHTNESS_MAX) { - return -EINVAL; - } - - return param_set_int(value, brightness_param); -} - -/** - * Basically a copy of the existing report event but doesn't report unknown events - */ -static bool sparse_keymap_report_known_event(struct input_dev *dev, unsigned int code, - unsigned int value, bool autorelease) -{ - const struct key_entry *ke = - sparse_keymap_entry_from_scancode(dev, code); - - if (ke) { - sparse_keymap_report_entry(dev, ke, value, autorelease); - return true; - } - - return false; -} - -static void tuxedo_wmi_notify(u32 value, void *context) -{ - u32 key_event; - - tuxedo_evaluate_wmi_method(WMI_SUBMETHOD_ID_GET_EVENT, 0, &key_event); - TUXEDO_DEBUG("WMI event (%0#6x)\n", key_event); - - switch (key_event) { - case WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT: - if (kbd_led_state.brightness == BRIGHTNESS_MIN - || (kbd_led_state.brightness - 25) < BRIGHTNESS_MIN) { - set_brightness(BRIGHTNESS_MIN); - } else { - set_brightness(kbd_led_state.brightness - 25); - } - - break; - - case WMI_KEYEVENT_CODE_INCREASE_BACKLIGHT: - if (kbd_led_state.brightness == BRIGHTNESS_MAX - || (kbd_led_state.brightness + 25) > BRIGHTNESS_MAX) { - set_brightness(BRIGHTNESS_MAX); - } else { - set_brightness(kbd_led_state.brightness + 25); - } - - break; - -// case WMI_CODE_NEXT_BLINKING_PATTERN: -// set_blinking_pattern((kbd_led_state.blinking_pattern + 1) > -// (ARRAY_SIZE(blinking_patterns) - 1) ? 0 : (kbd_led_state.blinking_pattern + 1)); -// break; - - case WMI_KEYEVENT_CODE_NEXT_BLINKING_PATTERN: - set_next_color_whole_kb(); - break; - - case WMI_KEYEVENT_CODE_TOGGLE_STATE: - set_enabled(kbd_led_state.enabled == 0 ? 1 : 0); - break; - - default: - break; - } - - if (!sparse_keymap_report_known_event(tuxedo_input_device, key_event, 1, true)) { - TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", key_event, key_event); - } -} - -static int tuxedo_wmi_probe(struct platform_device *dev) -{ - int status = wmi_install_notify_handler(CLEVO_EVENT_GUID, tuxedo_wmi_notify, NULL); - - // neuer name? - TUXEDO_DEBUG("clevo_xsm_wmi_probe status: (%0#6x)", status); - - if (unlikely(ACPI_FAILURE(status))) { - TUXEDO_ERROR("Could not register WMI notify handler (%0#6x)\n", status); - return -EIO; - } - - tuxedo_evaluate_wmi_method(WMI_SUBMETHOD_ID_GET_AP, 0, NULL); - - return 0; -} - -static int tuxedo_wmi_remove(struct platform_device *dev) -{ - wmi_remove_notify_handler(CLEVO_EVENT_GUID); - return 0; -} - -static int tuxedo_wmi_suspend(struct platform_device *dev, pm_message_t state) -{ - // turning the keyboard off prevents default colours showing on resume - set_enabled_cmd(0); - return 0; -} - -static int tuxedo_wmi_resume(struct platform_device *dev) -{ - tuxedo_evaluate_wmi_method(WMI_SUBMETHOD_ID_GET_AP, 0, NULL); - - set_color(REGION_LEFT, kbd_led_state.color.left); - set_color(REGION_CENTER, kbd_led_state.color.center); - set_color(REGION_RIGHT, kbd_led_state.color.right); - if (kbd_led_state.has_extra) - set_color(REGION_EXTRA, kbd_led_state.color.extra); - - set_blinking_pattern(kbd_led_state.blinking_pattern); - set_brightness(kbd_led_state.brightness); - set_enabled(kbd_led_state.enabled); - - return 0; -} - -static struct platform_driver tuxedo_platform_driver = { - .remove = tuxedo_wmi_remove, - .suspend = tuxedo_wmi_suspend, - .resume = tuxedo_wmi_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -// Sysfs attribute file permissions and method linking -static DEVICE_ATTR(state, 0644, show_state_fs, set_state_fs); -static DEVICE_ATTR(color_left, 0644, show_color_left_fs, set_color_left_fs); -static DEVICE_ATTR(color_center, 0644, show_color_center_fs, - set_color_center_fs); -static DEVICE_ATTR(color_right, 0644, show_color_right_fs, set_color_right_fs); -static DEVICE_ATTR(color_extra, 0644, show_color_extra_fs, set_color_extra_fs); -static DEVICE_ATTR(brightness, 0644, show_brightness_fs, set_brightness_fs); -static DEVICE_ATTR(mode, 0644, show_blinking_patterns_fs, set_blinking_pattern_fs); -static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL); - static int __init tuxedo_input_init(void) { int err; @@ -795,7 +104,7 @@ static int __init tuxdeo_keyboard_init(void) dmi_get_system_info(DMI_PRODUCT_NAME)); tuxedo_platform_device = - platform_create_bundle(&tuxedo_platform_driver, tuxedo_wmi_probe, + platform_create_bundle(&platform_driver_clevo, tuxedo_wmi_probe, NULL, 0, NULL, 0); if (unlikely(IS_ERR(tuxedo_platform_device))) { @@ -898,7 +207,7 @@ static void __exit tuxdeo_keyboard_exit(void) platform_device_unregister(tuxedo_platform_device); - platform_driver_unregister(&tuxedo_platform_driver); + platform_driver_unregister(&platform_driver_clevo); TUXEDO_DEBUG("exit"); } diff --git a/src/tuxedo_keyboard_common.h b/src/tuxedo_keyboard_common.h new file mode 100644 index 0000000..2b2e3e3 --- /dev/null +++ b/src/tuxedo_keyboard_common.h @@ -0,0 +1,51 @@ +/* +* tuxedo_keyboard_common.h +* +* Copyright (C) 2018-2020 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, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#ifndef TUXEDO_KEYBOARD_COMMON_H +#define TUXEDO_KEYBOARD_COMMON_H + +#include + +/* :::: Module specific Constants and simple Macros :::: */ +#define __TUXEDO_PR(lvl, fmt, ...) do { pr_##lvl(fmt, ##__VA_ARGS__); } while (0) +#define TUXEDO_INFO(fmt, ...) __TUXEDO_PR(info, fmt, ##__VA_ARGS__) +#define TUXEDO_ERROR(fmt, ...) __TUXEDO_PR(err, fmt, ##__VA_ARGS__) +#define TUXEDO_DEBUG(fmt, ...) __TUXEDO_PR(debug, "[%s:%u] " fmt, __func__, __LINE__, ##__VA_ARGS__) + +static struct platform_device *tuxedo_platform_device; +static struct input_dev *tuxedo_input_device; + +/** + * Basically a copy of the existing report event but doesn't report unknown events + */ +bool sparse_keymap_report_known_event(struct input_dev *dev, unsigned int code, + unsigned int value, bool autorelease) +{ + const struct key_entry *ke = + sparse_keymap_entry_from_scancode(dev, code); + + if (ke) { + sparse_keymap_report_entry(dev, ke, value, autorelease); + return true; + } + + return false; +} + +#endif \ No newline at end of file From bc9a14328c18a97f4681af6801d383ccd999aeac Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Wed, 27 May 2020 18:04:08 +0200 Subject: [PATCH 02/12] Parameterize keymap --- src/tuxedo_keyboard.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index 841ba7b..ebb761d 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -39,7 +39,7 @@ MODULE_VERSION("2.0.4"); MODULE_ALIAS("wmi:" CLEVO_EVENT_GUID); MODULE_ALIAS("wmi:" CLEVO_GET_GUID); -static int __init tuxedo_input_init(void) +static int __init tuxedo_input_init(const struct key_entry key_map[]) { int err; @@ -54,10 +54,12 @@ static int __init tuxedo_input_init(void) tuxedo_input_device->id.bustype = BUS_HOST; tuxedo_input_device->dev.parent = &tuxedo_platform_device->dev; - err = sparse_keymap_setup(tuxedo_input_device, clevo_wmi_keymap, NULL); - if (err) { - TUXEDO_ERROR("Failed to setup sparse keymap\n"); - goto err_free_input_device; + if (key_map != NULL) { + err = sparse_keymap_setup(tuxedo_input_device, key_map, NULL); + if (err) { + TUXEDO_ERROR("Failed to setup sparse keymap\n"); + goto err_free_input_device; + } } err = input_register_device(tuxedo_input_device); @@ -112,7 +114,7 @@ static int __init tuxdeo_keyboard_init(void) return PTR_ERR(tuxedo_platform_device); } - err = tuxedo_input_init(); + err = tuxedo_input_init(clevo_wmi_keymap); if (unlikely(err)) { TUXEDO_ERROR("Could not register input device\n"); } From 955c683971090ad6afd869e3d17f6f470dff6243 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Thu, 28 May 2020 18:35:46 +0200 Subject: [PATCH 03/12] Further modularize drivers incl. probe/remove --- src/clevo_keyboard.h | 128 +++++++++++++++++++++++++++++++---- src/tuxedo_keyboard.c | 119 +++++--------------------------- src/tuxedo_keyboard_common.h | 10 +++ 3 files changed, 142 insertions(+), 115 deletions(-) diff --git a/src/clevo_keyboard.h b/src/clevo_keyboard.h index 6845649..192957c 100644 --- a/src/clevo_keyboard.h +++ b/src/clevo_keyboard.h @@ -70,7 +70,7 @@ #define WMI_KEYEVENT_CODE_RFKILL1 0x85 #define WMI_KEYEVENT_CODE_RFKILL2 0x86 -static const struct key_entry clevo_wmi_keymap[] = { +static struct key_entry clevo_wmi_keymap[] = { // Keyboard backlight (RGB versions) { KE_KEY, WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT, { KEY_KBDILLUMDOWN } }, { KE_KEY, WMI_KEYEVENT_CODE_INCREASE_BACKLIGHT, { KEY_KBDILLUMUP } }, @@ -615,12 +615,33 @@ static void tuxedo_wmi_notify(u32 value, void *context) } } +// Sysfs attribute file permissions and method linking +static DEVICE_ATTR(state, 0644, show_state_fs, set_state_fs); +static DEVICE_ATTR(color_left, 0644, show_color_left_fs, set_color_left_fs); +static DEVICE_ATTR(color_center, 0644, show_color_center_fs, + set_color_center_fs); +static DEVICE_ATTR(color_right, 0644, show_color_right_fs, set_color_right_fs); +static DEVICE_ATTR(color_extra, 0644, show_color_extra_fs, set_color_extra_fs); +static DEVICE_ATTR(brightness, 0644, show_brightness_fs, set_brightness_fs); +static DEVICE_ATTR(mode, 0644, show_blinking_patterns_fs, set_blinking_pattern_fs); +static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL); + static int tuxedo_wmi_probe(struct platform_device *dev) { - int status = wmi_install_notify_handler(CLEVO_EVENT_GUID, - tuxedo_wmi_notify, NULL); + int status, err; - TUXEDO_DEBUG("tuxedo_wmi_probe status: (%0#6x)", status); + if (!wmi_has_guid(CLEVO_EVENT_GUID)) { + TUXEDO_ERROR("No known WMI event notification GUID found\n"); + return -ENODEV; + } + + if (!wmi_has_guid(CLEVO_GET_GUID)) { + TUXEDO_ERROR("No known WMI control method GUID found\n"); + return -ENODEV; + } + + status = wmi_install_notify_handler(CLEVO_EVENT_GUID, tuxedo_wmi_notify, + NULL); if (unlikely(ACPI_FAILURE(status))) { TUXEDO_ERROR("Could not register WMI notify handler (%0#6x)\n", @@ -628,14 +649,98 @@ static int tuxedo_wmi_probe(struct platform_device *dev) return -EIO; } + // Enable WMI events evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_GET_AP, 0, NULL); + // Setup sysfs + if (device_create_file(&dev->dev, &dev_attr_state) != 0) { + TUXEDO_ERROR("Sysfs attribute file creation failed for state\n"); + } + + if (device_create_file + (&dev->dev, &dev_attr_color_left) != 0) { + TUXEDO_ERROR + ("Sysfs attribute file creation failed for color left\n"); + } + + if (device_create_file + (&dev->dev, &dev_attr_color_center) != 0) { + TUXEDO_ERROR + ("Sysfs attribute file creation failed for color center\n"); + } + + if (device_create_file + (&dev->dev, &dev_attr_color_right) != 0) { + TUXEDO_ERROR + ("Sysfs attribute file creation failed for color right\n"); + } + + if (set_color(REGION_EXTRA, KB_COLOR_DEFAULT) != 0) { + TUXEDO_DEBUG("Keyboard does not support EXTRA Color"); + kbd_led_state.has_extra = 0; + } else { + kbd_led_state.has_extra = 1; + if (device_create_file + (&dev->dev, + &dev_attr_color_extra) != 0) { + TUXEDO_ERROR + ("Sysfs attribute file creation failed for color extra\n"); + } + + set_color(REGION_EXTRA, param_color_extra); + } + + if (device_create_file(&dev->dev, &dev_attr_extra) != + 0) { + TUXEDO_ERROR + ("Sysfs attribute file creation failed for extra information flag\n"); + } + + if (device_create_file(&dev->dev, &dev_attr_mode) != + 0) { + TUXEDO_ERROR("Sysfs attribute file creation failed for blinking pattern\n"); + } + + if (device_create_file + (&dev->dev, &dev_attr_brightness) != 0) { + TUXEDO_ERROR + ("Sysfs attribute file creation failed for brightness\n"); + } + + // Set state variables + kbd_led_state.color.left = param_color_left; + kbd_led_state.color.center = param_color_center; + kbd_led_state.color.right = param_color_right; + kbd_led_state.color.extra = param_color_extra; + + // Write state + set_color(REGION_LEFT, param_color_left); + set_color(REGION_CENTER, param_color_center); + set_color(REGION_RIGHT, param_color_right); + + set_blinking_pattern(param_blinking_pattern); + set_brightness(param_brightness); + set_enabled(param_state); + return 0; } static int tuxedo_wmi_remove(struct platform_device *dev) { wmi_remove_notify_handler(CLEVO_EVENT_GUID); + + device_remove_file(&dev->dev, &dev_attr_state); + device_remove_file(&dev->dev, &dev_attr_color_left); + device_remove_file(&dev->dev, &dev_attr_color_center); + device_remove_file(&dev->dev, &dev_attr_color_right); + device_remove_file(&dev->dev, &dev_attr_extra); + device_remove_file(&dev->dev, &dev_attr_mode); + device_remove_file(&dev->dev, &dev_attr_brightness); + + if (kbd_led_state.has_extra == 1) { + device_remove_file(&dev->dev, &dev_attr_color_extra); + } + return 0; } @@ -673,13 +778,8 @@ static struct platform_driver platform_driver_clevo = { }, }; -// Sysfs attribute file permissions and method linking -static DEVICE_ATTR(state, 0644, show_state_fs, set_state_fs); -static DEVICE_ATTR(color_left, 0644, show_color_left_fs, set_color_left_fs); -static DEVICE_ATTR(color_center, 0644, show_color_center_fs, - set_color_center_fs); -static DEVICE_ATTR(color_right, 0644, show_color_right_fs, set_color_right_fs); -static DEVICE_ATTR(color_extra, 0644, show_color_extra_fs, set_color_extra_fs); -static DEVICE_ATTR(brightness, 0644, show_brightness_fs, set_brightness_fs); -static DEVICE_ATTR(mode, 0644, show_blinking_patterns_fs, set_blinking_pattern_fs); -static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL); +struct tuxedo_keyboard_driver clevo_keyboard_driver = { + .platform_driver = &platform_driver_clevo, + .probe = tuxedo_wmi_probe, + .key_map = clevo_wmi_keymap, +}; diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index ebb761d..780778f 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -39,7 +39,7 @@ MODULE_VERSION("2.0.4"); MODULE_ALIAS("wmi:" CLEVO_EVENT_GUID); MODULE_ALIAS("wmi:" CLEVO_GET_GUID); -static int __init tuxedo_input_init(const struct key_entry key_map[]) +static int tuxedo_input_init(const struct key_entry key_map[]) { int err; @@ -92,100 +92,31 @@ static int __init tuxdeo_keyboard_init(void) { int err; - if (!wmi_has_guid(CLEVO_EVENT_GUID)) { - TUXEDO_ERROR("No known WMI event notification GUID found\n"); - return -ENODEV; - } - - if (!wmi_has_guid(CLEVO_GET_GUID)) { - TUXEDO_ERROR("No known WMI control method GUID found\n"); - return -ENODEV; - } - TUXEDO_INFO("Model '%s' found\n", dmi_get_system_info(DMI_PRODUCT_NAME)); + // Attempt to load each available driver + // Associated probe decides if it fits + // Driver from first successful probe is used tuxedo_platform_device = - platform_create_bundle(&platform_driver_clevo, tuxedo_wmi_probe, - NULL, 0, NULL, 0); + platform_create_bundle(clevo_keyboard_driver.platform_driver, + clevo_keyboard_driver.probe, NULL, 0, + NULL, 0); - if (unlikely(IS_ERR(tuxedo_platform_device))) { - TUXEDO_ERROR("Can not init Platform driver"); - return PTR_ERR(tuxedo_platform_device); - } - - err = tuxedo_input_init(clevo_wmi_keymap); - if (unlikely(err)) { - TUXEDO_ERROR("Could not register input device\n"); - } - - if (device_create_file(&tuxedo_platform_device->dev, &dev_attr_state) != 0) { - TUXEDO_ERROR("Sysfs attribute file creation failed for state\n"); - } - - if (device_create_file - (&tuxedo_platform_device->dev, &dev_attr_color_left) != 0) { - TUXEDO_ERROR - ("Sysfs attribute file creation failed for color left\n"); - } - - if (device_create_file - (&tuxedo_platform_device->dev, &dev_attr_color_center) != 0) { - TUXEDO_ERROR - ("Sysfs attribute file creation failed for color center\n"); - } - - if (device_create_file - (&tuxedo_platform_device->dev, &dev_attr_color_right) != 0) { - TUXEDO_ERROR - ("Sysfs attribute file creation failed for color right\n"); - } - - if (set_color(REGION_EXTRA, KB_COLOR_DEFAULT) != 0) { - TUXEDO_DEBUG("Keyboard does not support EXTRA Color"); - kbd_led_state.has_extra = 0; + if (IS_ERR(tuxedo_platform_device)) { + TUXEDO_ERROR("No matching hardware found\n"); + return -ENODEV; } else { - kbd_led_state.has_extra = 1; - if (device_create_file - (&tuxedo_platform_device->dev, - &dev_attr_color_extra) != 0) { - TUXEDO_ERROR - ("Sysfs attribute file creation failed for color extra\n"); + current_driver = &clevo_keyboard_driver; + } + + if (current_driver->key_map != NULL) { + err = tuxedo_input_init(current_driver->key_map); + if (unlikely(err)) { + TUXEDO_ERROR("Could not register input device\n"); } - - set_color(REGION_EXTRA, param_color_extra); } - if (device_create_file(&tuxedo_platform_device->dev, &dev_attr_extra) != - 0) { - TUXEDO_ERROR - ("Sysfs attribute file creation failed for extra information flag\n"); - } - - if (device_create_file(&tuxedo_platform_device->dev, &dev_attr_mode) != - 0) { - TUXEDO_ERROR("Sysfs attribute file creation failed for blinking pattern\n"); - } - - if (device_create_file - (&tuxedo_platform_device->dev, &dev_attr_brightness) != 0) { - TUXEDO_ERROR - ("Sysfs attribute file creation failed for brightness\n"); - } - - kbd_led_state.color.left = param_color_left; - kbd_led_state.color.center = param_color_center; - kbd_led_state.color.right = param_color_right; - kbd_led_state.color.extra = param_color_extra; - - set_color(REGION_LEFT, param_color_left); - set_color(REGION_CENTER, param_color_center); - set_color(REGION_RIGHT, param_color_right); - - set_blinking_pattern(param_blinking_pattern); - set_brightness(param_brightness); - set_enabled(param_state); - return 0; } @@ -193,23 +124,9 @@ static void __exit tuxdeo_keyboard_exit(void) { tuxedo_input_exit(); - device_remove_file(&tuxedo_platform_device->dev, &dev_attr_state); - device_remove_file(&tuxedo_platform_device->dev, &dev_attr_color_left); - device_remove_file(&tuxedo_platform_device->dev, - &dev_attr_color_center); - device_remove_file(&tuxedo_platform_device->dev, &dev_attr_color_right); - device_remove_file(&tuxedo_platform_device->dev, &dev_attr_extra); - device_remove_file(&tuxedo_platform_device->dev, &dev_attr_mode); - device_remove_file(&tuxedo_platform_device->dev, &dev_attr_brightness); - - if (kbd_led_state.has_extra == 1) { - device_remove_file(&tuxedo_platform_device->dev, - &dev_attr_color_extra); - } - platform_device_unregister(tuxedo_platform_device); - platform_driver_unregister(&platform_driver_clevo); + platform_driver_unregister(current_driver->platform_driver); TUXEDO_DEBUG("exit"); } diff --git a/src/tuxedo_keyboard_common.h b/src/tuxedo_keyboard_common.h index 2b2e3e3..ed6718b 100644 --- a/src/tuxedo_keyboard_common.h +++ b/src/tuxedo_keyboard_common.h @@ -28,9 +28,19 @@ #define TUXEDO_ERROR(fmt, ...) __TUXEDO_PR(err, fmt, ##__VA_ARGS__) #define TUXEDO_DEBUG(fmt, ...) __TUXEDO_PR(debug, "[%s:%u] " fmt, __func__, __LINE__, ##__VA_ARGS__) +struct tuxedo_keyboard_driver { + struct platform_driver *platform_driver; + int (*probe)(struct platform_device *); + struct key_entry *key_map; +}; + +// Global module devices static struct platform_device *tuxedo_platform_device; static struct input_dev *tuxedo_input_device; +// Currently chosen driver +static struct tuxedo_keyboard_driver *current_driver; + /** * Basically a copy of the existing report event but doesn't report unknown events */ From da7534772a6fa28eb1a41b401e8612dd70ea9b1d Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Fri, 29 May 2020 11:41:05 +0200 Subject: [PATCH 04/12] Additional decoupling --- src/clevo_keyboard.h | 50 +++++++++++++++++++++--------------- src/tuxedo_keyboard.c | 3 +++ src/tuxedo_keyboard_common.h | 5 ++++ 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/src/clevo_keyboard.h b/src/clevo_keyboard.h index 192957c..63ebd72 100644 --- a/src/clevo_keyboard.h +++ b/src/clevo_keyboard.h @@ -70,6 +70,8 @@ #define WMI_KEYEVENT_CODE_RFKILL1 0x85 #define WMI_KEYEVENT_CODE_RFKILL2 0x86 +struct tuxedo_keyboard_driver clevo_keyboard_driver; + static struct key_entry clevo_wmi_keymap[] = { // Keyboard backlight (RGB versions) { KE_KEY, WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT, { KEY_KBDILLUMDOWN } }, @@ -446,28 +448,28 @@ static int set_color_string_region(const char *color_string, size_t size, u32 re static ssize_t set_color_left_fs(struct device *child, struct device_attribute *attr, - const char *color_string, size_t size) + const char *color_string, size_t size) { return set_color_string_region(color_string, size, REGION_LEFT); } static ssize_t set_color_center_fs(struct device *child, struct device_attribute *attr, - const char *color_string, size_t size) + const char *color_string, size_t size) { return set_color_string_region(color_string, size, REGION_CENTER); } static ssize_t set_color_right_fs(struct device *child, struct device_attribute *attr, - const char *color_string, size_t size) + const char *color_string, size_t size) { return set_color_string_region(color_string, size, REGION_RIGHT); } static ssize_t set_color_extra_fs(struct device *child, struct device_attribute *attr, - const char *color_string, size_t size) + const char *color_string, size_t size) { return set_color_string_region(color_string, size, REGION_EXTRA); } @@ -565,7 +567,7 @@ static int brightness_validator(const char *value, return param_set_int(value, brightness_param); } -static void tuxedo_wmi_notify(u32 value, void *context) +static void clevo_wmi_notify(u32 value, void *context) { u32 key_event; @@ -610,8 +612,13 @@ static void tuxedo_wmi_notify(u32 value, void *context) break; } - if (!sparse_keymap_report_known_event(tuxedo_input_device, key_event, 1, true)) { - TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", key_event, key_event); + if (clevo_keyboard_driver.input_device != NULL) { + if (!sparse_keymap_report_known_event( + clevo_keyboard_driver.input_device, key_event, 1, + true)) { + TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", key_event, + key_event); + } } } @@ -626,9 +633,9 @@ static DEVICE_ATTR(brightness, 0644, show_brightness_fs, set_brightness_fs); static DEVICE_ATTR(mode, 0644, show_blinking_patterns_fs, set_blinking_pattern_fs); static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL); -static int tuxedo_wmi_probe(struct platform_device *dev) +static int clevo_keyboard_probe(struct platform_device *dev) { - int status, err; + int status; if (!wmi_has_guid(CLEVO_EVENT_GUID)) { TUXEDO_ERROR("No known WMI event notification GUID found\n"); @@ -640,7 +647,7 @@ static int tuxedo_wmi_probe(struct platform_device *dev) return -ENODEV; } - status = wmi_install_notify_handler(CLEVO_EVENT_GUID, tuxedo_wmi_notify, + status = wmi_install_notify_handler(CLEVO_EVENT_GUID, clevo_wmi_notify, NULL); if (unlikely(ACPI_FAILURE(status))) { @@ -725,7 +732,7 @@ static int tuxedo_wmi_probe(struct platform_device *dev) return 0; } -static int tuxedo_wmi_remove(struct platform_device *dev) +static int clevo_keyboard_remove(struct platform_device *dev) { wmi_remove_notify_handler(CLEVO_EVENT_GUID); @@ -744,14 +751,14 @@ static int tuxedo_wmi_remove(struct platform_device *dev) return 0; } -static int tuxedo_wmi_suspend(struct platform_device *dev, pm_message_t state) +static int clevo_keyboard_suspend(struct platform_device *dev, pm_message_t state) { // turning the keyboard off prevents default colours showing on resume set_enabled_cmd(0); return 0; } -static int tuxedo_wmi_resume(struct platform_device *dev) +static int clevo_keyboard_resume(struct platform_device *dev) { evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_GET_AP, 0, NULL); @@ -769,17 +776,18 @@ static int tuxedo_wmi_resume(struct platform_device *dev) } static struct platform_driver platform_driver_clevo = { - .remove = tuxedo_wmi_remove, - .suspend = tuxedo_wmi_suspend, - .resume = tuxedo_wmi_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, + .remove = clevo_keyboard_remove, + .suspend = clevo_keyboard_suspend, + .resume = clevo_keyboard_resume, + .driver = + { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, }; struct tuxedo_keyboard_driver clevo_keyboard_driver = { .platform_driver = &platform_driver_clevo, - .probe = tuxedo_wmi_probe, + .probe = clevo_keyboard_probe, .key_map = clevo_wmi_keymap, }; diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index 780778f..eec7d8f 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -114,6 +114,9 @@ static int __init tuxdeo_keyboard_init(void) err = tuxedo_input_init(current_driver->key_map); if (unlikely(err)) { TUXEDO_ERROR("Could not register input device\n"); + current_driver->input_device = NULL; + } else { + current_driver->input_device = tuxedo_input_device; } } diff --git a/src/tuxedo_keyboard_common.h b/src/tuxedo_keyboard_common.h index ed6718b..cb75d0b 100644 --- a/src/tuxedo_keyboard_common.h +++ b/src/tuxedo_keyboard_common.h @@ -29,9 +29,14 @@ #define TUXEDO_DEBUG(fmt, ...) __TUXEDO_PR(debug, "[%s:%u] " fmt, __func__, __LINE__, ##__VA_ARGS__) struct tuxedo_keyboard_driver { + // Platform driver provided by driver struct platform_driver *platform_driver; + // Probe method provided by driver int (*probe)(struct platform_device *); + // Keymap provided by driver struct key_entry *key_map; + // Input device reference filled in on module init after probe success + struct input_dev *input_device; }; // Global module devices From e74a3404a74982e3409ece908eb9e5f016566726 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Fri, 29 May 2020 13:19:28 +0200 Subject: [PATCH 05/12] Add additional id check to existing driver --- src/clevo_keyboard.h | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/clevo_keyboard.h b/src/clevo_keyboard.h index 63ebd72..7793ba2 100644 --- a/src/clevo_keyboard.h +++ b/src/clevo_keyboard.h @@ -635,15 +635,27 @@ static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL); static int clevo_keyboard_probe(struct platform_device *dev) { - int status; + int status, ret; if (!wmi_has_guid(CLEVO_EVENT_GUID)) { - TUXEDO_ERROR("No known WMI event notification GUID found\n"); + TUXEDO_DEBUG("probe: Clevo event guid missing\n"); return -ENODEV; } if (!wmi_has_guid(CLEVO_GET_GUID)) { - TUXEDO_ERROR("No known WMI control method GUID found\n"); + TUXEDO_DEBUG("probe: Clevo method guid missing\n"); + return -ENODEV; + } + + // Since the WMI GUIDs aren't unique let's (at least) + // check the return of some "known existing general" method + status = evaluate_wmi_method_clevo(0x52, 0, &ret); + if (status < 0) { + TUXEDO_DEBUG("probe: Clevo GUIDs present but method call failed\n"); + return -ENODEV; + } + if (ret == 0xffffffff) { + TUXEDO_DEBUG("probe: Clevo GUIDs present but method returned unexpected value\n"); return -ENODEV; } From 3bb71064ae6a1e52f0568c930117f87a6d7ce79e Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Fri, 29 May 2020 16:20:02 +0200 Subject: [PATCH 06/12] Add empty new driver --- src/tuxedo_keyboard.c | 30 ++++++++++------- src/tuxedo_keyboard_common.h | 5 +++ src/uniwill_keyboard.h | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 11 deletions(-) create mode 100644 src/uniwill_keyboard.h diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index eec7d8f..e780cba 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -18,8 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#define DRIVER_NAME "tuxedo_keyboard" -#define pr_fmt(fmt) DRIVER_NAME ": " fmt +#define pr_fmt(fmt) "tuxedo_keyboard" ": " fmt #include #include @@ -30,6 +29,7 @@ #include #include "tuxedo_keyboard_common.h" #include "clevo_keyboard.h" +#include "uniwill_keyboard.h" MODULE_AUTHOR("TUXEDO Computers GmbH "); MODULE_DESCRIPTION("TUXEDO Computers keyboard & keyboard backlight Driver"); @@ -39,6 +39,11 @@ MODULE_VERSION("2.0.4"); MODULE_ALIAS("wmi:" CLEVO_EVENT_GUID); MODULE_ALIAS("wmi:" CLEVO_GET_GUID); +static struct tuxedo_keyboard_driver *driver_list[] = { + &clevo_keyboard_driver, + &uniwill_keyboard_driver +}; + static int tuxedo_input_init(const struct key_entry key_map[]) { int err; @@ -90,24 +95,27 @@ static void __exit tuxedo_input_exit(void) static int __init tuxdeo_keyboard_init(void) { - int err; - + int i, err; + int num_drivers = sizeof(driver_list) / sizeof(*driver_list); TUXEDO_INFO("Model '%s' found\n", dmi_get_system_info(DMI_PRODUCT_NAME)); // Attempt to load each available driver // Associated probe decides if it fits // Driver from first successful probe is used - tuxedo_platform_device = - platform_create_bundle(clevo_keyboard_driver.platform_driver, - clevo_keyboard_driver.probe, NULL, 0, - NULL, 0); - if (IS_ERR(tuxedo_platform_device)) { + i = 0; + while (IS_ERR_OR_NULL(tuxedo_platform_device) && i < num_drivers) { + current_driver = driver_list[i]; + tuxedo_platform_device = platform_create_bundle( + current_driver->platform_driver, + current_driver->probe, NULL, 0, NULL, 0); + ++i; + } + + if (IS_ERR_OR_NULL(tuxedo_platform_device)) { TUXEDO_ERROR("No matching hardware found\n"); return -ENODEV; - } else { - current_driver = &clevo_keyboard_driver; } if (current_driver->key_map != NULL) { diff --git a/src/tuxedo_keyboard_common.h b/src/tuxedo_keyboard_common.h index cb75d0b..950db5f 100644 --- a/src/tuxedo_keyboard_common.h +++ b/src/tuxedo_keyboard_common.h @@ -20,6 +20,7 @@ #ifndef TUXEDO_KEYBOARD_COMMON_H #define TUXEDO_KEYBOARD_COMMON_H +#include #include /* :::: Module specific Constants and simple Macros :::: */ @@ -28,6 +29,10 @@ #define TUXEDO_ERROR(fmt, ...) __TUXEDO_PR(err, fmt, ##__VA_ARGS__) #define TUXEDO_DEBUG(fmt, ...) __TUXEDO_PR(debug, "[%s:%u] " fmt, __func__, __LINE__, ##__VA_ARGS__) +#ifndef DRIVER_NAME +#define DRIVER_NAME "tuxedo_keyboard" +#endif + struct tuxedo_keyboard_driver { // Platform driver provided by driver struct platform_driver *platform_driver; diff --git a/src/uniwill_keyboard.h b/src/uniwill_keyboard.h new file mode 100644 index 0000000..0b77252 --- /dev/null +++ b/src/uniwill_keyboard.h @@ -0,0 +1,63 @@ +/* +* uniwill_keyboard.h +* +* Copyright (C) 2018-2020 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, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "tuxedo_keyboard_common.h" + +struct tuxedo_keyboard_driver uniwill_keyboard_driver; + +static struct key_entry uniwill_wmi_keymap[] = { + { KE_END, 0 } +}; + +static int uniwill_keyboard_probe(struct platform_device *dev) +{ + return -ENODEV; +} + +static int uniwill_keyboard_remove(struct platform_device *dev) +{ + return 0; +} + +static int uniwill_keyboard_suspend(struct platform_device *dev, pm_message_t state) +{ + return 0; +} + +static int uniwill_keyboard_resume(struct platform_device *dev) +{ + return 0; +} + +static struct platform_driver platform_driver_uniwill = { + .remove = uniwill_keyboard_remove, + .suspend = uniwill_keyboard_suspend, + .resume = uniwill_keyboard_resume, + .driver = + { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, +}; + +struct tuxedo_keyboard_driver uniwill_keyboard_driver = { + .platform_driver = &platform_driver_uniwill, + .probe = uniwill_keyboard_probe, + .key_map = uniwill_wmi_keymap, +}; From f7d79e6bbcf5993f334eb9a7fb9ae294a5b760f1 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Fri, 29 May 2020 17:47:18 +0200 Subject: [PATCH 07/12] Add basic probe and wmi notifiers --- src/uniwill_keyboard.h | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/uniwill_keyboard.h b/src/uniwill_keyboard.h index 0b77252..1c924a5 100644 --- a/src/uniwill_keyboard.h +++ b/src/uniwill_keyboard.h @@ -18,20 +18,113 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "tuxedo_keyboard_common.h" +#include +#include + +#define UNIWILL_WMI_MGMT_GUID_BA "ABBC0F6D-8EA1-11D1-00A0-C90629100000" +#define UNIWILL_WMI_MGMT_GUID_BB "ABBC0F6E-8EA1-11D1-00A0-C90629100000" +#define UNIWILL_WMI_MGMT_GUID_BC "ABBC0F6F-8EA1-11D1-00A0-C90629100000" + +#define UNIWILL_WMI_EVENT_GUID_0 "ABBC0F70-8EA1-11D1-00A0-C90629100000" +#define UNIWILL_WMI_EVENT_GUID_1 "ABBC0F71-8EA1-11D1-00A0-C90629100000" +#define UNIWILL_WMI_EVENT_GUID_2 "ABBC0F72-8EA1-11D1-00A0-C90629100000" + +#define UNIWILL_OSD_RADIOON 0x01A +#define UNIWILL_OSD_RADIOOFF 0x01B struct tuxedo_keyboard_driver uniwill_keyboard_driver; static struct key_entry uniwill_wmi_keymap[] = { + { KE_KEY, UNIWILL_OSD_RADIOON, { KEY_RFKILL } }, + { KE_KEY, UNIWILL_OSD_RADIOOFF, { KEY_RFKILL } }, { KE_END, 0 } }; +static void uniwill_wmi_handle_event(u32 value, void *context, u32 guid_nr) +{ + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *obj; + + acpi_status status; + int code; + + status = wmi_get_event_data(value, &response); + if (status != AE_OK) { + TUXEDO_ERROR("uniwill handle event -> bad event status\n"); + return; + } + + obj = (union acpi_object *) response.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) { + code = obj->integer.value; + if (!sparse_keymap_report_known_event(current_driver->input_device, code, 1, true)) { + TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", code, code); + } + } + + kfree(obj); +} + +static void uniwill_wmi_notify0(u32 value, void *context) +{ + uniwill_wmi_handle_event(value, context, 0); +} + +static void uniwill_wmi_notify1(u32 value, void *context) +{ + uniwill_wmi_handle_event(value, context, 1); +} + +static void uniwill_wmi_notify2(u32 value, void *context) +{ + uniwill_wmi_handle_event(value, context, 2); +} + static int uniwill_keyboard_probe(struct platform_device *dev) { + int status; + + // Look for for GUIDs used on uniwill devices + status = + wmi_has_guid(UNIWILL_WMI_EVENT_GUID_0) && + wmi_has_guid(UNIWILL_WMI_EVENT_GUID_1) && + wmi_has_guid(UNIWILL_WMI_EVENT_GUID_2) && + wmi_has_guid(UNIWILL_WMI_MGMT_GUID_BA) && + wmi_has_guid(UNIWILL_WMI_MGMT_GUID_BB) && + wmi_has_guid(UNIWILL_WMI_MGMT_GUID_BC); + + if (!status) { + TUXEDO_DEBUG("probe: At least one Uniwill GUID missing\n"); + return -ENODEV; + } + + // Attempt to add event handlers + status = + wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_0, uniwill_wmi_notify0, NULL) && + wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_1, uniwill_wmi_notify1, NULL) && + wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_2, uniwill_wmi_notify2, NULL); + + if (!status) { + TUXEDO_ERROR("probe: Failed to install at least one uniwill notify handler\n"); + goto err_remove_notifiers; + } + + return 0; + +err_remove_notifiers: + wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_0); + wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_1); + wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_2); + return -ENODEV; } static int uniwill_keyboard_remove(struct platform_device *dev) { + wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_0); + wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_1); + wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_2); + return 0; } From 8a7052dbda88cf7b0144de25c7a8c6b769e4cae6 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Tue, 2 Jun 2020 10:11:45 +0200 Subject: [PATCH 08/12] Add event sending structure for touchpad toggle workaround --- src/tuxedo_keyboard.c | 4 +++ src/uniwill_keyboard.h | 78 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 71 insertions(+), 11 deletions(-) diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index e780cba..553a800 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -67,6 +67,10 @@ static int tuxedo_input_init(const struct key_entry key_map[]) } } + // Add touchpad key event bits for manual report workaround + tuxedo_input_device->evbit[0] = BIT_MASK(EV_KEY); + tuxedo_input_device->keybit[BIT_WORD(KEY_F21)] = BIT_MASK(KEY_F21); + err = input_register_device(tuxedo_input_device); if (unlikely(err)) { TUXEDO_ERROR("Error registering input device\n"); diff --git a/src/uniwill_keyboard.h b/src/uniwill_keyboard.h index 1c924a5..5f48eb1 100644 --- a/src/uniwill_keyboard.h +++ b/src/uniwill_keyboard.h @@ -20,6 +20,8 @@ #include "tuxedo_keyboard_common.h" #include #include +#include +#include #define UNIWILL_WMI_MGMT_GUID_BA "ABBC0F6D-8EA1-11D1-00A0-C90629100000" #define UNIWILL_WMI_MGMT_GUID_BB "ABBC0F6E-8EA1-11D1-00A0-C90629100000" @@ -29,17 +31,60 @@ #define UNIWILL_WMI_EVENT_GUID_1 "ABBC0F71-8EA1-11D1-00A0-C90629100000" #define UNIWILL_WMI_EVENT_GUID_2 "ABBC0F72-8EA1-11D1-00A0-C90629100000" -#define UNIWILL_OSD_RADIOON 0x01A +#define UNIWILL_OSD_RADIOON 0x01A #define UNIWILL_OSD_RADIOOFF 0x01B struct tuxedo_keyboard_driver uniwill_keyboard_driver; static struct key_entry uniwill_wmi_keymap[] = { - { KE_KEY, UNIWILL_OSD_RADIOON, { KEY_RFKILL } }, - { KE_KEY, UNIWILL_OSD_RADIOOFF, { KEY_RFKILL } }, + // { KE_KEY, UNIWILL_OSD_RADIOON, { KEY_RFKILL } }, + // { KE_KEY, UNIWILL_OSD_RADIOOFF, { KEY_RFKILL } }, { KE_END, 0 } }; +static void key_event_work(struct work_struct *work) +{ + input_report_key(uniwill_keyboard_driver.input_device, KEY_F21, 1); + input_report_key(uniwill_keyboard_driver.input_device, KEY_F21, 0); + input_sync(uniwill_keyboard_driver.input_device); +} + +// Previous key codes for detecting longer combination +static u32 prev_key = 0, prevprev_key = 0; +static DECLARE_WORK(uniwill_key_event_work, key_event_work); + +static int keyboard_notifier_callb(struct notifier_block *nb, unsigned long code, void *_param) +{ + struct keyboard_notifier_param *param = _param; + int ret = NOTIFY_OK; + + if (!param->down) { + + if (code == KBD_KEYCODE) { + TUXEDO_DEBUG("[%d, %d, %d]\n", prevprev_key, prev_key, param->value); + switch (param->value) { + case 125: + // If the last keys up were 85 -> 29 -> 125 + // manually report KEY_F21 + if (prevprev_key == 85 && prev_key == 29) { + TUXEDO_DEBUG("Touchpad Toggle\n"); + schedule_work(&uniwill_key_event_work); + ret = NOTIFY_STOP; + } + break; + } + prevprev_key = prev_key; + prev_key = param->value; + } + } + + return ret; +} + +static struct notifier_block keyboard_notifier_block = { + .notifier_call = keyboard_notifier_callb +}; + static void uniwill_wmi_handle_event(u32 value, void *context, u32 guid_nr) { struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -58,7 +103,7 @@ static void uniwill_wmi_handle_event(u32 value, void *context, u32 guid_nr) if (obj && obj->type == ACPI_TYPE_INTEGER) { code = obj->integer.value; if (!sparse_keymap_report_known_event(current_driver->input_device, code, 1, true)) { - TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", code, code); + TUXEDO_DEBUG("[Ev %d] Unknown key - %d (%0#6x)\n", guid_nr, code, code); } } @@ -99,15 +144,25 @@ static int uniwill_keyboard_probe(struct platform_device *dev) } // Attempt to add event handlers - status = - wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_0, uniwill_wmi_notify0, NULL) && - wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_1, uniwill_wmi_notify1, NULL) && - wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_2, uniwill_wmi_notify2, NULL); - - if (!status) { - TUXEDO_ERROR("probe: Failed to install at least one uniwill notify handler\n"); + status = wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_0, uniwill_wmi_notify0, NULL); + if (ACPI_FAILURE(status)) { + TUXEDO_ERROR("probe: Failed to install uniwill notify handler 0\n"); goto err_remove_notifiers; } + + status = wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_1, uniwill_wmi_notify1, NULL); + if (ACPI_FAILURE(status)) { + TUXEDO_ERROR("probe: Failed to install uniwill notify handler 1\n"); + goto err_remove_notifiers; + } + + status = wmi_install_notify_handler(UNIWILL_WMI_EVENT_GUID_2, uniwill_wmi_notify2, NULL); + if (ACPI_FAILURE(status)) { + TUXEDO_ERROR("probe: Failed to install uniwill notify handler 2\n"); + goto err_remove_notifiers; + } + + status = register_keyboard_notifier(&keyboard_notifier_block); return 0; @@ -121,6 +176,7 @@ err_remove_notifiers: static int uniwill_keyboard_remove(struct platform_device *dev) { + unregister_keyboard_notifier(&keyboard_notifier_block); wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_0); wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_1); wmi_remove_notify_handler(UNIWILL_WMI_EVENT_GUID_2); From 13d9b8bbf8e0049c9492fc4978e743b27b637b62 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Tue, 16 Jun 2020 14:40:54 +0200 Subject: [PATCH 09/12] Add special key-combo when gauge key is pressed --- src/tuxedo_keyboard.c | 4 ---- src/uniwill_keyboard.h | 30 ++++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index 553a800..e780cba 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -67,10 +67,6 @@ static int tuxedo_input_init(const struct key_entry key_map[]) } } - // Add touchpad key event bits for manual report workaround - tuxedo_input_device->evbit[0] = BIT_MASK(EV_KEY); - tuxedo_input_device->keybit[BIT_WORD(KEY_F21)] = BIT_MASK(KEY_F21); - err = input_register_device(tuxedo_input_device); if (unlikely(err)) { TUXEDO_ERROR("Error registering input device\n"); diff --git a/src/uniwill_keyboard.h b/src/uniwill_keyboard.h index 5f48eb1..1b195a8 100644 --- a/src/uniwill_keyboard.h +++ b/src/uniwill_keyboard.h @@ -34,19 +34,30 @@ #define UNIWILL_OSD_RADIOON 0x01A #define UNIWILL_OSD_RADIOOFF 0x01B +#define UNIWILL_OSD_TOUCHPADWORKAROUND 0xFFF + struct tuxedo_keyboard_driver uniwill_keyboard_driver; static struct key_entry uniwill_wmi_keymap[] = { // { KE_KEY, UNIWILL_OSD_RADIOON, { KEY_RFKILL } }, // { KE_KEY, UNIWILL_OSD_RADIOOFF, { KEY_RFKILL } }, + // { KE_KEY, 0xb0, { KEY_F13 } }, + { KE_KEY, UNIWILL_OSD_TOUCHPADWORKAROUND, { KEY_F21 } }, + // Only used to put ev bits + { KE_KEY, 0xffff, { KEY_F6 } }, + { KE_KEY, 0xffff, { KEY_LEFTALT } }, + { KE_KEY, 0xffff, { KEY_LEFTMETA } }, { KE_END, 0 } }; static void key_event_work(struct work_struct *work) { - input_report_key(uniwill_keyboard_driver.input_device, KEY_F21, 1); - input_report_key(uniwill_keyboard_driver.input_device, KEY_F21, 0); - input_sync(uniwill_keyboard_driver.input_device); + sparse_keymap_report_known_event( + current_driver->input_device, + UNIWILL_OSD_TOUCHPADWORKAROUND, + 1, + true + ); } // Previous key codes for detecting longer combination @@ -61,7 +72,6 @@ static int keyboard_notifier_callb(struct notifier_block *nb, unsigned long code if (!param->down) { if (code == KBD_KEYCODE) { - TUXEDO_DEBUG("[%d, %d, %d]\n", prevprev_key, prev_key, param->value); switch (param->value) { case 125: // If the last keys up were 85 -> 29 -> 125 @@ -107,6 +117,18 @@ static void uniwill_wmi_handle_event(u32 value, void *context, u32 guid_nr) } } + // Special key combination when mode change key is pressed + if (code == 0xb0) { + input_report_key(current_driver->input_device, KEY_LEFTMETA, 1); + input_report_key(current_driver->input_device, KEY_LEFTALT, 1); + input_report_key(current_driver->input_device, KEY_F6, 1); + input_sync(current_driver->input_device); + input_report_key(current_driver->input_device, KEY_F6, 0); + input_report_key(current_driver->input_device, KEY_LEFTALT, 0); + input_report_key(current_driver->input_device, KEY_LEFTMETA, 0); + input_sync(current_driver->input_device); + } + kfree(obj); } From 2d3f22a579df37b9ff6832af866355e82465c690 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Thu, 18 Jun 2020 10:42:10 +0200 Subject: [PATCH 10/12] Move special code handling to where it is actually defined --- src/uniwill_keyboard.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/uniwill_keyboard.h b/src/uniwill_keyboard.h index 1b195a8..d3b8be6 100644 --- a/src/uniwill_keyboard.h +++ b/src/uniwill_keyboard.h @@ -115,18 +115,18 @@ static void uniwill_wmi_handle_event(u32 value, void *context, u32 guid_nr) if (!sparse_keymap_report_known_event(current_driver->input_device, code, 1, true)) { TUXEDO_DEBUG("[Ev %d] Unknown key - %d (%0#6x)\n", guid_nr, code, code); } - } - // Special key combination when mode change key is pressed - if (code == 0xb0) { - input_report_key(current_driver->input_device, KEY_LEFTMETA, 1); - input_report_key(current_driver->input_device, KEY_LEFTALT, 1); - input_report_key(current_driver->input_device, KEY_F6, 1); - input_sync(current_driver->input_device); - input_report_key(current_driver->input_device, KEY_F6, 0); - input_report_key(current_driver->input_device, KEY_LEFTALT, 0); - input_report_key(current_driver->input_device, KEY_LEFTMETA, 0); - input_sync(current_driver->input_device); + // Special key combination when mode change key is pressed + if (code == 0xb0) { + input_report_key(current_driver->input_device, KEY_LEFTMETA, 1); + input_report_key(current_driver->input_device, KEY_LEFTALT, 1); + input_report_key(current_driver->input_device, KEY_F6, 1); + input_sync(current_driver->input_device); + input_report_key(current_driver->input_device, KEY_F6, 0); + input_report_key(current_driver->input_device, KEY_LEFTALT, 0); + input_report_key(current_driver->input_device, KEY_LEFTMETA, 0); + input_sync(current_driver->input_device); + } } kfree(obj); From 1ac2a55e6845583946602d9ed4d3dfaf60f0e958 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Thu, 18 Jun 2020 10:50:13 +0200 Subject: [PATCH 11/12] Update changelogs --- .../usr/share/doc/module-name/changelog.gz | Bin 351 -> 421 bytes src_pkg/rpm_pkg.spec | 4 ++++ 2 files changed, 4 insertions(+) diff --git a/deb/module-name/usr/share/doc/module-name/changelog.gz b/deb/module-name/usr/share/doc/module-name/changelog.gz index 54bb69620b74e78d0644aae62a1d769944985f62..7783e38d66732fd83a401dde05dfda3081e4a473 100644 GIT binary patch literal 421 zcmV;W0b2eaiwFoUD(hYX17m1mZf9j|Z)X6NlFM$}Fc3xe`ii?uTic*yD-ZR721Oen zK)YzN4=8dh6P8GU8anphhf?Im1!5T95i>*ZoIB*OCGDnb+Lcavjf-q1X88w{##y62 zBlwD}+I_9va{_$CU+UNg#laKULDsQ>rSoW9tZ3R8McpuYt2ODdf-bbJ^L)_oL7Rpw zOTXI>X<||wA5IcXr}%*fX?01y!WRzP?>wL?*R+Ajce8l<20X691nD*IgGDAXfm9TW zt3n8T5~&bL!tWU_jvJ16%eAR%#9N?E#2i|`%oZD0hlWrFW@le}-2|qx(f=&&Koew_ z_$_xMcUH`^Q{408+;?Qj%L8OIvTcp6{tN%-01P=u_IoR(TGyspF(PzaX;7a$JK zn*)=)$n#Ss*>RITX6qO}{x#i$LL z?9x|-?G;{yNylc~>Q literal 351 zcmV-l0igaLiwFoq@XTHU17m1mZf9j|Z)X6Nk;!htFcd}i`HH*j0LTf1igZv>)ppfx z+I{83k6;n}BFAR<`Hh(sVxvVM{Yfm;y^5k>A8cmFi^I~lU_02y;x z*V>e5d|k8MD!jJ9kgeo|Epl1RDqT(;0yG@^Vp>aeu}M5SFiEpCJ!g`fHrd2%*uhfc z*tP~vIzq@hltTJ{Q*&0nB1rGJVyU2;##6ID<7UmM&5s3}i7v4P`PqZ?Hszp 2.0.5-1 +- Restructure to allow for more devices +- Added device support +- Added rudimentary device detection * Tue May 26 2020 C Sandberg 2.0.4-1 - Added rfkill key event - Fix volume button events, ignore From 1464197ef76852edf73a66a4bb2651c6d1146bb3 Mon Sep 17 00:00:00 2001 From: Christoffer Sandberg Date: Mon, 22 Jun 2020 13:33:41 +0200 Subject: [PATCH 12/12] Add new WMI module aliases --- src/tuxedo_keyboard.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tuxedo_keyboard.c b/src/tuxedo_keyboard.c index e780cba..485f4e3 100644 --- a/src/tuxedo_keyboard.c +++ b/src/tuxedo_keyboard.c @@ -39,6 +39,10 @@ MODULE_VERSION("2.0.4"); MODULE_ALIAS("wmi:" CLEVO_EVENT_GUID); MODULE_ALIAS("wmi:" CLEVO_GET_GUID); +MODULE_ALIAS("wmi:" UNIWILL_WMI_EVENT_GUID_0); +MODULE_ALIAS("wmi:" UNIWILL_WMI_EVENT_GUID_1); +MODULE_ALIAS("wmi:" UNIWILL_WMI_EVENT_GUID_2); + static struct tuxedo_keyboard_driver *driver_list[] = { &clevo_keyboard_driver, &uniwill_keyboard_driver