diff --git a/src/clevo_acpi.c b/src/clevo_acpi.c index e1abd8f..f8f5442 100644 --- a/src/clevo_acpi.c +++ b/src/clevo_acpi.c @@ -32,9 +32,9 @@ struct clevo_acpi_driver_data_t { static struct clevo_acpi_driver_data_t *active_driver_data = NULL; -static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg, union acpi_object **result) +static int clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg, union acpi_object **result) { - u32 status; + int status; acpi_handle handle; u64 dsm_rev_dummy = 0x00; // Dummy 0 value since not used u64 dsm_func = cmd; @@ -79,9 +79,9 @@ static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg, unio return status; } -u32 clevo_acpi_interface_method_call(u8 cmd, u32 arg, union acpi_object **result_value) +int clevo_acpi_interface_method_call(u8 cmd, u32 arg, union acpi_object **result_value) { - u32 status = 0; + int status = 0; if (!IS_ERR_OR_NULL(active_driver_data)) { status = clevo_acpi_evaluate(active_driver_data->adev, cmd, arg, result_value); @@ -141,7 +141,7 @@ void clevo_acpi_notify(struct acpi_device *device, u32 event) { u32 event_value; union acpi_object *out_obj; - u32 status; + int status; // struct clevo_acpi_driver_data_t *clevo_acpi_driver_data; status = clevo_acpi_evaluate(device, 0x01, 0, &out_obj); diff --git a/src/clevo_interfaces.h b/src/clevo_interfaces.h index fabeff5..d734295 100644 --- a/src/clevo_interfaces.h +++ b/src/clevo_interfaces.h @@ -48,6 +48,8 @@ #define CLEVO_CMD_GET_BIOS_FEATURES_2 0x7A #define CLEVO_CMD_GET_BIOS_FEATURES_2_SUB_WHITE_ONLY_KB_MAX_5 0x4000 +#define CLEVO_CMD_GET_KB_WHITE_LEDS 0x3D // Get brightness of white only keyboard backlights + // The clevo set commands expect a parameter #define CLEVO_CMD_SET_FANSPEED_VALUE 0x68 #define CLEVO_CMD_SET_FANSPEED_AUTO 0x69 @@ -58,7 +60,7 @@ #define CLEVO_CMD_SET_EVENTS_ENABLED 0x46 -#define CLEVO_CMD_SET_KB_WHITE_LEDS 0x27 // Set brightness of single color keyboard backlights +#define CLEVO_CMD_SET_KB_WHITE_LEDS 0x27 // Set brightness of white only keyboard backlights #define CLEVO_CMD_SET_KB_RGB_LEDS 0x67 // Used to set color, brightness, blinking pattern, etc. #define CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_0 0xF0000000 // 1-zone RGB and 3-zone RGB left #define CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_1 0xF1000000 // 3-zone RGB center @@ -72,14 +74,14 @@ struct clevo_interface_t { char *string_id; void (*event_callb)(u32); - u32 (*method_call)(u8, u32, union acpi_object **); + int (*method_call)(u8, u32, union acpi_object **); }; -u32 clevo_keyboard_add_interface(struct clevo_interface_t *new_interface); -u32 clevo_keyboard_remove_interface(struct clevo_interface_t *interface); -u32 clevo_evaluate_method(u8 cmd, u32 arg, u32 *result); -u32 clevo_evaluate_method2(u8 cmd, u32 arg, union acpi_object **result); -u32 clevo_get_active_interface_id(char **id_str); +int clevo_keyboard_add_interface(struct clevo_interface_t *new_interface); +int clevo_keyboard_remove_interface(struct clevo_interface_t *interface); +int clevo_evaluate_method(u8 cmd, u32 arg, u32 *result); +int clevo_evaluate_method2(u8 cmd, u32 arg, union acpi_object **result); +int clevo_get_active_interface_id(char **id_str); #define MODULE_ALIAS_CLEVO_WMI() \ MODULE_ALIAS("wmi:" CLEVO_WMI_EVENT_GUID); \ diff --git a/src/clevo_keyboard.h b/src/clevo_keyboard.h index d069fe2..8aea994 100644 --- a/src/clevo_keyboard.h +++ b/src/clevo_keyboard.h @@ -54,8 +54,8 @@ static struct key_entry clevo_keymap[] = { { KE_KEY, CLEVO_EVENT_KB_LEDS_INCREASE, { KEY_KBDILLUMUP } }, { KE_KEY, CLEVO_EVENT_KB_LEDS_TOGGLE, { KEY_KBDILLUMTOGGLE } }, { KE_KEY, CLEVO_EVENT_KB_LEDS_CYCLE_MODE, { KEY_LIGHTS_TOGGLE } }, - // Single cycle key (white only versions) - { KE_KEY, CLEVO_EVENT_KB_LEDS_CYCLE_BRIGHTNESS, { KEY_KBDILLUMTOGGLE } }, + // Single cycle key (white only versions) (currently handled in driver) + // { KE_KEY, CLEVO_EVENT_KB_LEDS_CYCLE_BRIGHTNESS, { KEY_KBDILLUMTOGGLE } }, // Touchpad // The weirdly named touchpad toggle key that is implemented as KEY_F21 "everywhere" @@ -106,7 +106,7 @@ static struct kbd_backlight_mode_t { { .key = 7, .value = 0xB0000000, .name = "WAVE"} }; -u32 clevo_evaluate_method2(u8 cmd, u32 arg, union acpi_object **result) +int clevo_evaluate_method2(u8 cmd, u32 arg, union acpi_object **result) { if (IS_ERR_OR_NULL(active_clevo_interface)) { pr_err("clevo_keyboard: no active interface while attempting cmd %02x arg %08x\n", cmd, arg); @@ -116,9 +116,9 @@ u32 clevo_evaluate_method2(u8 cmd, u32 arg, union acpi_object **result) } EXPORT_SYMBOL(clevo_evaluate_method2); -u32 clevo_evaluate_method(u8 cmd, u32 arg, u32 *result) +int clevo_evaluate_method(u8 cmd, u32 arg, u32 *result) { - u32 status = 0; + int status = 0; union acpi_object *out_obj; status = clevo_evaluate_method2(cmd, arg, &out_obj); @@ -140,7 +140,7 @@ u32 clevo_evaluate_method(u8 cmd, u32 arg, u32 *result) } EXPORT_SYMBOL(clevo_evaluate_method); -u32 clevo_get_active_interface_id(char **id_str) +int clevo_get_active_interface_id(char **id_str) { if (IS_ERR_OR_NULL(active_clevo_interface)) return -ENODEV; @@ -256,6 +256,9 @@ static void clevo_keyboard_event_callb(u32 event) case CLEVO_EVENT_KB_LEDS_CYCLE_MODE: set_next_color_whole_kb(); break; + case CLEVO_EVENT_KB_LEDS_CYCLE_BRIGHTNESS: + clevo_leds_notify_brightness_change_extern(); + break; default: break; } @@ -382,7 +385,7 @@ static struct tuxedo_keyboard_driver clevo_keyboard_driver = { .key_map = clevo_keymap, }; -u32 clevo_keyboard_add_interface(struct clevo_interface_t *new_interface) +int clevo_keyboard_add_interface(struct clevo_interface_t *new_interface) { mutex_lock(&clevo_keyboard_interface_modification_lock); @@ -420,7 +423,7 @@ u32 clevo_keyboard_add_interface(struct clevo_interface_t *new_interface) } EXPORT_SYMBOL(clevo_keyboard_add_interface); -u32 clevo_keyboard_remove_interface(struct clevo_interface_t *interface) +int clevo_keyboard_remove_interface(struct clevo_interface_t *interface) { mutex_lock(&clevo_keyboard_interface_modification_lock); diff --git a/src/clevo_leds.h b/src/clevo_leds.h index ddb2c4a..275f3f2 100644 --- a/src/clevo_leds.h +++ b/src/clevo_leds.h @@ -36,6 +36,7 @@ int clevo_leds_init(struct platform_device *dev); int clevo_leds_remove(struct platform_device *dev); enum clevo_kb_backlight_types clevo_leds_get_backlight_type(void); void clevo_leds_restore_state_extern(void); +void clevo_leds_notify_brightness_change_extern(void); void clevo_leds_set_brightness_extern(enum led_brightness brightness); void clevo_leds_set_color_extern(u32 color); @@ -180,7 +181,8 @@ static struct led_classdev clevo_led_cdev = { .name = "white:" LED_FUNCTION_KBD_BACKLIGHT, .max_brightness = CLEVO_KBD_BRIGHTNESS_WHITE_MAX, .brightness_set = &clevo_leds_set_brightness, - .brightness = CLEVO_KBD_BRIGHTNESS_WHITE_DEFAULT + .brightness = CLEVO_KBD_BRIGHTNESS_WHITE_DEFAULT, + .flags = LED_BRIGHT_HW_CHANGED }; static struct mc_subled clevo_mcled_cdevs_subleds[3][3] = { @@ -276,7 +278,7 @@ static struct led_classdev_mc clevo_mcled_cdevs[3] = { int clevo_leds_init(struct platform_device *dev) { int ret, i; - u32 status; + int status; union acpi_object *result; u32 result_fallback; @@ -408,6 +410,8 @@ enum clevo_kb_backlight_types clevo_leds_get_backlight_type(void) { } EXPORT_SYMBOL(clevo_leds_get_backlight_type); +// TODO Don't reuse brightness_set as it is writing back the same brightness which could lead to race conditions. +// Reimplement brightness_set instead without writing back brightness value like in uniwill_leds.h. void clevo_leds_restore_state_extern(void) { if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR) { clevo_led_cdev.brightness_set(&clevo_led_cdev, clevo_led_cdev.brightness); @@ -423,6 +427,21 @@ void clevo_leds_restore_state_extern(void) { } EXPORT_SYMBOL(clevo_leds_restore_state_extern); +void clevo_leds_notify_brightness_change_extern(void) { + int status; + u32 result; + + if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR) { + status = clevo_evaluate_method(CLEVO_CMD_GET_KB_WHITE_LEDS, 0, &result); + pr_debug("Firmware set brightness: %u\n", result); + clevo_led_cdev.brightness = result; + led_classdev_notify_brightness_hw_changed(&clevo_led_cdev, result); + } +} +EXPORT_SYMBOL(clevo_leds_notify_brightness_change_extern); + +// TODO Not used externaly, but only on init. Should not be exposed because it would require a correct +// led_classdev_notify_brightness_hw_changed implementation when used outside of init. void clevo_leds_set_brightness_extern(enum led_brightness brightness) { if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR) { clevo_led_cdev.brightness_set(&clevo_led_cdev, brightness); @@ -438,6 +457,8 @@ void clevo_leds_set_brightness_extern(enum led_brightness brightness) { } EXPORT_SYMBOL(clevo_leds_set_brightness_extern); +// TODO Not used externaly, but only on init. Should not be exposed because it would require a correct +// led_classdev_notify_brightness_hw_changed equivalent for color implementation when used outside of init. void clevo_leds_set_color_extern(u32 color) { if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_1_ZONE_RGB) { clevo_mcled_cdevs[0].subled_info[0].intensity = (color >> 16) & 0xff; diff --git a/src/clevo_wmi.c b/src/clevo_wmi.c index f7e0186..51adaaa 100644 --- a/src/clevo_wmi.c +++ b/src/clevo_wmi.c @@ -30,7 +30,7 @@ static int clevo_wmi_evaluate(u32 wmi_method_id, u32 wmi_arg, union acpi_object struct acpi_buffer acpi_buffer_out = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *acpi_result; acpi_status status_acpi; - u32 return_status = 0; + int return_status = 0; status_acpi = wmi_evaluate_method(CLEVO_WMI_METHOD_GUID, 0x00, wmi_method_id, @@ -55,7 +55,7 @@ static int clevo_wmi_evaluate(u32 wmi_method_id, u32 wmi_arg, union acpi_object return return_status; } -u32 clevo_wmi_interface_method_call(u8 cmd, u32 arg, union acpi_object **result_value) +int clevo_wmi_interface_method_call(u8 cmd, u32 arg, union acpi_object **result_value) { return clevo_wmi_evaluate(cmd, arg, result_value); } @@ -71,7 +71,7 @@ static int clevo_wmi_probe(struct wmi_device *wdev) static int clevo_wmi_probe(struct wmi_device *wdev, const void *dummy_context) #endif { - u32 status; + int status; union acpi_object *out_obj; pr_debug("clevo_wmi driver probe\n"); @@ -126,7 +126,7 @@ static void clevo_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy) { u32 event_value; union acpi_object *out_obj; - u32 status; + int status; status = clevo_wmi_evaluate(0x01, 0, &out_obj); if (!status) { diff --git a/src/tuxedo_io/tuxedo_io.c b/src/tuxedo_io/tuxedo_io.c index f420819..5a863b1 100644 --- a/src/tuxedo_io/tuxedo_io.c +++ b/src/tuxedo_io/tuxedo_io.c @@ -52,7 +52,7 @@ static struct uniwill_device_features_t *uw_feats; /** * strstr version of dmi_match */ -static bool dmi_string_in(enum dmi_field f, const char *str) +static bool __attribute__ ((unused)) dmi_string_in(enum dmi_field f, const char *str) { const char *info = dmi_get_system_info(f); diff --git a/src/uniwill_keyboard.h b/src/uniwill_keyboard.h index 20dcc02..fb62732 100644 --- a/src/uniwill_keyboard.h +++ b/src/uniwill_keyboard.h @@ -237,13 +237,12 @@ static int keyboard_notifier_callb(struct notifier_block *nb, unsigned long code int ret = NOTIFY_OK; if (!param->down) { - if (code == KBD_KEYCODE) { switch (param->value) { - case 125: + case KEY_LEFTMETA: // If the last keys up were 85 -> 29 -> 125 // manually report KEY_F21 - if (prevprev_key == 85 && prev_key == 29) { + if (prevprev_key == KEY_ZENKAKUHANKAKU && prev_key == KEY_LEFTCTRL) { TUXEDO_DEBUG("Touchpad Toggle\n"); schedule_work(&uniwill_key_event_work); ret = NOTIFY_OK; @@ -275,29 +274,41 @@ static void uniwill_write_kbd_bl_enable(u8 enable) void uniwill_event_callb(u32 code) { - if (uniwill_keyboard_driver.input_device != NULL) - if (!sparse_keymap_report_known_event(uniwill_keyboard_driver.input_device, code, 1, true)) { - TUXEDO_DEBUG("Unknown code - %d (%0#6x)\n", code, code); - } - - // Special key combination when mode change key is pressed - if (code == UNIWILL_OSD_MODE_CHANGE_KEY_EVENT) { - input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 1); - input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTALT, 1); - input_report_key(uniwill_keyboard_driver.input_device, KEY_F6, 1); - input_sync(uniwill_keyboard_driver.input_device); - input_report_key(uniwill_keyboard_driver.input_device, KEY_F6, 0); - input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTALT, 0); - input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 0); - input_sync(uniwill_keyboard_driver.input_device); - } - - // Refresh keyboard state and charging prio on cable switch event - if (code == UNIWILL_OSD_DC_ADAPTER_CHANGE) { - uniwill_leds_restore_state_extern(); - - msleep(50); - uw_charging_priority_write_state(); + switch (code) { + case UNIWILL_OSD_MODE_CHANGE_KEY_EVENT: + // Special key combination when mode change key is pressed (the one next to + // the power key). Opens TCC by default when installed. + input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 1); + input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTALT, 1); + input_report_key(uniwill_keyboard_driver.input_device, KEY_F6, 1); + input_sync(uniwill_keyboard_driver.input_device); + input_report_key(uniwill_keyboard_driver.input_device, KEY_F6, 0); + input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTALT, 0); + input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 0); + input_sync(uniwill_keyboard_driver.input_device); + break; + case UNIWILL_OSD_DC_ADAPTER_CHANGE: + // Refresh keyboard state and charging prio on cable switch event + uniwill_leds_restore_state_extern(); + msleep(50); + uw_charging_priority_write_state(); + break; + case UNIWILL_KEY_KBDILLUMTOGGLE: + case UNIWILL_OSD_KB_LED_LEVEL0: + case UNIWILL_OSD_KB_LED_LEVEL1: + case UNIWILL_OSD_KB_LED_LEVEL2: + case UNIWILL_OSD_KB_LED_LEVEL3: + case UNIWILL_OSD_KB_LED_LEVEL4: + // Notify userspace/UPower that the firmware changed the keyboard backlight + // brightness on white only keyboards. Fallthrough on other keyboards to + // emit KEY_KBDILLUMTOGGLE. + if (uniwill_leds_notify_brightness_change_extern()) + return; + fallthrough; + default: + if (uniwill_keyboard_driver.input_device != NULL) + if (!sparse_keymap_report_known_event(uniwill_keyboard_driver.input_device, code, 1, true)) + TUXEDO_DEBUG("Unknown code - %d (%0#6x)\n", code, code); } } @@ -786,7 +797,7 @@ static int uw_has_charging_profile(bool *status) return 0; } -static void uw_charging_profile_write_state(void) +static void __attribute__ ((unused)) uw_charging_profile_write_state(void) { if (uw_charging_profile_loaded) uw_set_charging_profile(uw_charging_profile_last_written_value); @@ -1140,10 +1151,11 @@ static int uniwill_keyboard_probe(struct platform_device *dev) u32 i; u8 data; int status; + struct uniwill_device_features_t *uw_feats; set_rom_id(); - struct uniwill_device_features_t *uw_feats = uniwill_get_device_features(); + uw_feats = uniwill_get_device_features(); // FIXME Hard set balanced profile until we have implemented a way to // switch it while tuxedo_io is loaded diff --git a/src/uniwill_leds.h b/src/uniwill_leds.h index 1f14ee7..4fdbc29 100644 --- a/src/uniwill_leds.h +++ b/src/uniwill_leds.h @@ -47,6 +47,7 @@ int uniwill_leds_init_early(struct platform_device *dev); int uniwill_leds_init_late(struct platform_device *dev); int uniwill_leds_remove(struct platform_device *dev); enum uniwill_kb_backlight_types uniwill_leds_get_backlight_type(void); +int uniwill_leds_notify_brightness_change_extern(void); void uniwill_leds_restore_state_extern(void); void uniwill_leds_set_brightness_extern(enum led_brightness brightness); void uniwill_leds_set_color_extern(u32 color); @@ -135,7 +136,8 @@ static struct led_classdev uniwill_led_cdev = { .name = "white:" LED_FUNCTION_KBD_BACKLIGHT, .max_brightness = UNIWILL_KBD_BRIGHTNESS_WHITE_MAX, .brightness_set = &uniwill_leds_set_brightness, - .brightness = UNIWILL_KBD_BRIGHTNESS_WHITE_DEFAULT + .brightness = UNIWILL_KBD_BRIGHTNESS_WHITE_DEFAULT, + .flags = LED_BRIGHT_HW_CHANGED }; static struct mc_subled uw_mcled_cdev_subleds[3] = { @@ -164,6 +166,7 @@ static struct led_classdev_mc uniwill_mcled_cdev = { .led_cdev.max_brightness = UNIWILL_KBD_BRIGHTNESS_MAX, .led_cdev.brightness_set = &uniwill_leds_set_brightness_mc, .led_cdev.brightness = UNIWILL_KBD_BRIGHTNESS_DEFAULT, + .led_cdev.flags = LED_BRIGHT_HW_CHANGED, .num_colors = 3, .subled_info = uw_mcled_cdev_subleds }; @@ -282,12 +285,29 @@ enum uniwill_kb_backlight_types uniwill_leds_get_backlight_type(void) { } EXPORT_SYMBOL(uniwill_leds_get_backlight_type); +int uniwill_leds_notify_brightness_change_extern(void) { + u8 data = 0; + + if (uw_leds_initialized) { + if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) { + uniwill_read_ec_ram(UW_EC_REG_KBD_BL_STATUS, &data); + data = (data >> 5) & 0x3; + uniwill_led_cdev.brightness = data; + led_classdev_notify_brightness_hw_changed(&uniwill_led_cdev, data); + return true; + } + } + return false; +} + void uniwill_leds_restore_state_extern(void) { u8 data; if (uw_leds_initialized) { if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) { - uniwill_led_cdev.brightness_set(&uniwill_led_cdev, uniwill_led_cdev.brightness); + if (uniwill_write_kbd_bl_white(uniwill_led_cdev.brightness)) { + pr_debug("uniwill_leds_restore_state_extern(): uniwill_write_kbd_bl_white() failed\n"); + } } else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) { // reset @@ -296,7 +316,11 @@ void uniwill_leds_restore_state_extern(void) { uniwill_write_ec_ram(UW_EC_REG_KBD_BL_STATUS, data); // write - uniwill_mcled_cdev.led_cdev.brightness_set(&uniwill_mcled_cdev.led_cdev, uniwill_mcled_cdev.led_cdev.brightness); + if (uniwill_write_kbd_bl_rgb(uniwill_mcled_cdev.subled_info[0].brightness, + uniwill_mcled_cdev.subled_info[1].brightness, + uniwill_mcled_cdev.subled_info[2].brightness)) { + pr_debug("uniwill_leds_restore_state_extern(): uniwill_write_kbd_bl_rgb() failed\n"); + } } } }