mirror of
https://github.com/wessel-novacustom/clevo-keyboard.git
synced 2024-11-15 11:43:59 +01:00
clevo_keyboard: Basic modularization to allow for multiple interfaces
Basic working implementation, WIP - Modularize clevo_keyboard, allowing interfaces to "register" themselves - Add clevo_acpi interface to clevo_keyboard - Prefer acpi interface - Fixed some previously still coupled features on uniwill_keyboard side to allow for the structure change
This commit is contained in:
parent
6d76c68eb4
commit
6f14b22b33
18
src/ck.h
Normal file
18
src/ck.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
#ifndef TUXEDO_KEYBOARD_H
|
||||||
|
#define TUXEDO_KEYBOARD_H
|
||||||
|
|
||||||
|
int clevo_keyboard_init(void);
|
||||||
|
|
||||||
|
struct clevo_interface_t {
|
||||||
|
char *string_id;
|
||||||
|
void (*event_callb)(u32);
|
||||||
|
u32 (*method_call)(u8, u32, u32*);
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 clevo_keyboard_add_interface(struct clevo_interface_t *new_interface);
|
||||||
|
u32 clevo_keyboard_remove_interface(struct clevo_interface_t *new_interface);
|
||||||
|
|
||||||
|
#endif
|
|
@ -2,19 +2,22 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include "ck.h"
|
||||||
|
|
||||||
#define DRIVER_NAME "clevo_acpi"
|
#define DRIVER_NAME "clevo_acpi"
|
||||||
#define CLEVO_ACPI_RESOURCE_HID "CLV0001"
|
#define CLEVO_ACPI_RESOURCE_HID "CLV0001"
|
||||||
#define CLEVO_ACPI_DSM_UUID "93f224e4-fbdc-4bbf-add6-db71bdc0afad"
|
#define CLEVO_ACPI_DSM_UUID "93f224e4-fbdc-4bbf-add6-db71bdc0afad"
|
||||||
|
|
||||||
struct clevo_acpi_driver_data_t {
|
struct clevo_acpi_driver_data_t {
|
||||||
struct acpi_device *device;
|
struct acpi_device *adev;
|
||||||
|
struct clevo_interface_t *clevo_interface;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg)
|
static struct clevo_acpi_driver_data_t *active_driver_data = NULL;
|
||||||
|
|
||||||
|
static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg, u32 *result)
|
||||||
{
|
{
|
||||||
u32 status;
|
u32 status;
|
||||||
u32 result;
|
|
||||||
acpi_handle handle;
|
acpi_handle handle;
|
||||||
u64 dsm_rev_dummy = 0x00; // Dummy 0 value since not used
|
u64 dsm_rev_dummy = 0x00; // Dummy 0 value since not used
|
||||||
u64 dsm_func = cmd;
|
u64 dsm_func = cmd;
|
||||||
|
@ -45,24 +48,47 @@ static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg)
|
||||||
if (handle == NULL)
|
if (handle == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
pr_debug("evaluate _DSM cmd: %0#4x arg: %0#10x\n", cmd, arg);
|
||||||
out_obj = acpi_evaluate_dsm(handle, &clevo_acpi_dsm_uuid, dsm_rev_dummy, dsm_func, &dsm_argv4);
|
out_obj = acpi_evaluate_dsm(handle, &clevo_acpi_dsm_uuid, dsm_rev_dummy, dsm_func, &dsm_argv4);
|
||||||
if (!out_obj) {
|
if (!out_obj) {
|
||||||
pr_err("failed to evaluate _DSM\n");
|
pr_err("failed to evaluate _DSM\n");
|
||||||
result = 0;
|
status = -1;
|
||||||
} else {
|
} else {
|
||||||
if (out_obj->type == ACPI_TYPE_INTEGER) {
|
if (out_obj->type == ACPI_TYPE_INTEGER) {
|
||||||
result = (u32) out_obj->integer.value;
|
if (!IS_ERR_OR_NULL(result))
|
||||||
|
*result = (u32) out_obj->integer.value;
|
||||||
} else {
|
} else {
|
||||||
pr_err("unknown output from _DSM\n");
|
pr_err("unknown output from _DSM\n");
|
||||||
result = 0;
|
status = -ENODATA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ACPI_FREE(out_obj);
|
ACPI_FREE(out_obj);
|
||||||
|
|
||||||
return result;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 clevo_acpi_interface_method_call(u8 cmd, u32 arg, u32 *result_value)
|
||||||
|
{
|
||||||
|
u32 status = 0;
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(active_driver_data)) {
|
||||||
|
status = clevo_acpi_evaluate(active_driver_data->adev, cmd, arg, result_value);
|
||||||
|
} else {
|
||||||
|
pr_err("acpi method call exec, no driver data found\n");
|
||||||
|
pr_err("..for method_call: %0#4x arg: %0#10x\n", cmd, arg);
|
||||||
|
status = -ENODATA;
|
||||||
|
}
|
||||||
|
pr_debug("method_call: %0#4x arg: %0#10x result: %0#10x\n", cmd, arg, !IS_ERR_OR_NULL(result_value) ? *result_value : 0);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct clevo_interface_t clevo_acpi_interface = {
|
||||||
|
.string_id = "clevo_acpi",
|
||||||
|
.method_call = clevo_acpi_interface_method_call,
|
||||||
|
};
|
||||||
|
|
||||||
static int clevo_acpi_add(struct acpi_device *device)
|
static int clevo_acpi_add(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
struct clevo_acpi_driver_data_t *driver_data;
|
struct clevo_acpi_driver_data_t *driver_data;
|
||||||
|
@ -71,12 +97,18 @@ static int clevo_acpi_add(struct acpi_device *device)
|
||||||
if (!driver_data)
|
if (!driver_data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
driver_data->device = device;
|
driver_data->adev = device;
|
||||||
|
driver_data->clevo_interface = &clevo_acpi_interface;
|
||||||
|
|
||||||
|
active_driver_data = driver_data;
|
||||||
|
|
||||||
pr_debug("acpi add\n");
|
pr_debug("acpi add\n");
|
||||||
|
|
||||||
pr_debug("enable acpi events\n");
|
// Initiate clevo keyboard, if not already loaded by other interface driver
|
||||||
clevo_acpi_evaluate(device, 0x46, 0);
|
clevo_keyboard_init();
|
||||||
|
|
||||||
|
// Add this interface
|
||||||
|
clevo_keyboard_add_interface(&clevo_acpi_interface);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -84,12 +116,22 @@ static int clevo_acpi_add(struct acpi_device *device)
|
||||||
static int clevo_acpi_remove(struct acpi_device *device)
|
static int clevo_acpi_remove(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
pr_debug("acpi remove\n");
|
pr_debug("acpi remove\n");
|
||||||
|
clevo_keyboard_remove_interface(&clevo_acpi_interface);
|
||||||
|
active_driver_data = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clevo_acpi_notify(struct acpi_device *device, u32 event)
|
void clevo_acpi_notify(struct acpi_device *device, u32 event)
|
||||||
{
|
{
|
||||||
|
struct clevo_acpi_driver_data_t *clevo_acpi_driver_data;
|
||||||
pr_debug("event: %0#10x\n", event);
|
pr_debug("event: %0#10x\n", event);
|
||||||
|
|
||||||
|
// clevo_acpi_driver_data = container_of(&device, struct clevo_acpi_driver_data_t, adev);
|
||||||
|
if (!IS_ERR_OR_NULL(clevo_acpi_interface.event_callb)) {
|
||||||
|
// Execute registered callback
|
||||||
|
pr_debug("calling event addr\n");
|
||||||
|
clevo_acpi_interface.event_callb(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
@ -135,3 +177,5 @@ MODULE_AUTHOR("TUXEDO Computers GmbH <tux@tuxedocomputers.com>");
|
||||||
MODULE_DESCRIPTION("Driver for Clevo ACPI interface");
|
MODULE_DESCRIPTION("Driver for Clevo ACPI interface");
|
||||||
MODULE_VERSION("0.0.1");
|
MODULE_VERSION("0.0.1");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(acpi, clevo_acpi_device_ids);
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
#include "tuxedo_keyboard_common.h"
|
#include "tuxedo_keyboard_common.h"
|
||||||
|
#include "tuxedo_keyboard.h"
|
||||||
|
#include "ck.h"
|
||||||
|
|
||||||
#define CLEVO_EVENT_GUID "ABBC0F6B-8EA1-11D1-00A0-C90629100000"
|
#define CLEVO_EVENT_GUID "ABBC0F6B-8EA1-11D1-00A0-C90629100000"
|
||||||
#define CLEVO_EMAIL_GUID "ABBC0F6C-8EA1-11D1-00A0-C90629100000"
|
#define CLEVO_EMAIL_GUID "ABBC0F6C-8EA1-11D1-00A0-C90629100000"
|
||||||
|
@ -58,6 +60,66 @@
|
||||||
#define WMI_KEYEVENT_CODE_RFKILL1 0x85
|
#define WMI_KEYEVENT_CODE_RFKILL1 0x85
|
||||||
#define WMI_KEYEVENT_CODE_RFKILL2 0x86
|
#define WMI_KEYEVENT_CODE_RFKILL2 0x86
|
||||||
|
|
||||||
|
static struct clevo_interfaces_t {
|
||||||
|
struct clevo_interface_t *wmi;
|
||||||
|
struct clevo_interface_t *acpi;
|
||||||
|
} clevo_interfaces;
|
||||||
|
|
||||||
|
struct clevo_interface_t *active_clevo_interface;
|
||||||
|
|
||||||
|
void clevo_keyboard_write_state(void);
|
||||||
|
void clevo_keyboard_event_callb(u32 event);
|
||||||
|
|
||||||
|
u32 clevo_keyboard_add_interface(struct clevo_interface_t *new_interface)
|
||||||
|
{
|
||||||
|
if (strcmp(new_interface->string_id, "clevo_wmi") == 0) {
|
||||||
|
clevo_interfaces.wmi = new_interface;
|
||||||
|
clevo_interfaces.wmi->event_callb = clevo_keyboard_event_callb;
|
||||||
|
|
||||||
|
// Only use wmi if there is no other current interface
|
||||||
|
if (ZERO_OR_NULL_PTR(active_clevo_interface)) {
|
||||||
|
pr_debug("enable wmi events\n");
|
||||||
|
clevo_interfaces.wmi->method_call(0x46, 0, NULL);
|
||||||
|
|
||||||
|
active_clevo_interface = clevo_interfaces.wmi;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (strcmp(new_interface->string_id, "clevo_acpi") == 0) {
|
||||||
|
clevo_interfaces.acpi = new_interface;
|
||||||
|
clevo_interfaces.acpi->event_callb = clevo_keyboard_event_callb;
|
||||||
|
|
||||||
|
pr_debug("enable acpi events (takes priority)\n");
|
||||||
|
clevo_interfaces.acpi->method_call(0x46, 0, NULL);
|
||||||
|
active_clevo_interface = clevo_interfaces.acpi;
|
||||||
|
} else {
|
||||||
|
// Not recognized interface
|
||||||
|
pr_err("unrecognized interface\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
clevo_keyboard_write_state();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(clevo_keyboard_add_interface);
|
||||||
|
|
||||||
|
u32 clevo_keyboard_remove_interface(struct clevo_interface_t *interface)
|
||||||
|
{
|
||||||
|
if (strcmp(interface->string_id, "clevo_wmi") == 0) {
|
||||||
|
clevo_interfaces.wmi = NULL;
|
||||||
|
} else if (strcmp(interface->string_id, "clevo_acpi") == 0) {
|
||||||
|
clevo_interfaces.acpi = NULL;
|
||||||
|
} else {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (active_clevo_interface == interface)
|
||||||
|
active_clevo_interface = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(clevo_keyboard_remove_interface);
|
||||||
|
|
||||||
struct tuxedo_keyboard_driver clevo_keyboard_driver;
|
struct tuxedo_keyboard_driver clevo_keyboard_driver;
|
||||||
|
|
||||||
static struct key_entry clevo_wmi_keymap[] = {
|
static struct key_entry clevo_wmi_keymap[] = {
|
||||||
|
@ -229,6 +291,16 @@ static ssize_t show_hasextra_fs(struct device *child,
|
||||||
return sprintf(buffer, "%d\n", kbd_led_state.has_extra);
|
return sprintf(buffer, "%d\n", kbd_led_state.has_extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 clevo_evaluate_method(u8 cmd, u32 arg, u32 *result)
|
||||||
|
{
|
||||||
|
if (IS_ERR_OR_NULL(active_clevo_interface)) {
|
||||||
|
pr_err("clevo_keyboard: no active interface\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
TUXEDO_DEBUG("evaluate method\n");
|
||||||
|
return active_clevo_interface->method_call(cmd, arg, result);
|
||||||
|
}
|
||||||
|
|
||||||
static int evaluate_wmi_method_clevo(u32 submethod_id, u32 submethod_arg, u32 * retval)
|
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_input = { (acpi_size) sizeof(submethod_arg), &submethod_arg };
|
||||||
|
@ -265,10 +337,15 @@ static int evaluate_wmi_method_clevo(u32 submethod_id, u32 submethod_arg, u32 *
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 clevo_wmi_interface_method_call(u8 cmd, u32 arg, u32 *result_value)
|
||||||
|
{
|
||||||
|
return evaluate_wmi_method_clevo(cmd, arg, result_value);
|
||||||
|
}
|
||||||
|
|
||||||
static void set_brightness(u8 brightness)
|
static void set_brightness(u8 brightness)
|
||||||
{
|
{
|
||||||
TUXEDO_INFO("Set brightness on %d", brightness);
|
TUXEDO_INFO("Set brightness on %d", brightness);
|
||||||
if (!evaluate_wmi_method_clevo
|
if (!clevo_evaluate_method
|
||||||
(WMI_SUBMETHOD_ID_SET_KB_LEDS, 0xF4000000 | brightness, NULL)) {
|
(WMI_SUBMETHOD_ID_SET_KB_LEDS, 0xF4000000 | brightness, NULL)) {
|
||||||
kbd_led_state.brightness = brightness;
|
kbd_led_state.brightness = brightness;
|
||||||
}
|
}
|
||||||
|
@ -303,7 +380,7 @@ static int set_enabled_cmd(u8 state)
|
||||||
cmd |= 0x07F001;
|
cmd |= 0x07F001;
|
||||||
}
|
}
|
||||||
|
|
||||||
return evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_SET_KB_LEDS, cmd, NULL);
|
return clevo_evaluate_method(WMI_SUBMETHOD_ID_SET_KB_LEDS, cmd, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_enabled(u8 state)
|
static void set_enabled(u8 state)
|
||||||
|
@ -339,7 +416,7 @@ static int set_color(u32 region, u32 color)
|
||||||
|
|
||||||
TUXEDO_DEBUG("Set Color '%08x' for region '%08x'", color, region);
|
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);
|
return clevo_evaluate_method(WMI_SUBMETHOD_ID_SET_KB_LEDS, wmi_submethod_arg, NULL);
|
||||||
}
|
}
|
||||||
static int set_color_code_region(u32 region, u32 colorcode)
|
static int set_color_code_region(u32 region, u32 colorcode)
|
||||||
{
|
{
|
||||||
|
@ -455,7 +532,7 @@ static void set_blinking_pattern(u8 blinkling_pattern)
|
||||||
{
|
{
|
||||||
TUXEDO_INFO("set_mode on %s", blinking_patterns[blinkling_pattern].name);
|
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)) {
|
if (!clevo_evaluate_method(WMI_SUBMETHOD_ID_SET_KB_LEDS, blinking_patterns[blinkling_pattern].value, NULL)) {
|
||||||
// wmi method was succesfull so update ur internal state struct
|
// wmi method was succesfull so update ur internal state struct
|
||||||
kbd_led_state.blinking_pattern = blinkling_pattern;
|
kbd_led_state.blinking_pattern = blinkling_pattern;
|
||||||
}
|
}
|
||||||
|
@ -518,12 +595,13 @@ static int brightness_validator(const char *value,
|
||||||
return param_set_int(value, brightness_param);
|
return param_set_int(value, brightness_param);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clevo_wmi_notify(u32 value, void *context)
|
void clevo_keyboard_event_callb(u32 event)
|
||||||
{
|
{
|
||||||
u32 key_event;
|
u32 key_event;
|
||||||
|
TUXEDO_DEBUG("event callback: (%0#10x)\n", event);
|
||||||
|
|
||||||
evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_GET_EVENT, 0, &key_event);
|
clevo_evaluate_method(WMI_SUBMETHOD_ID_GET_EVENT, 0, &key_event);
|
||||||
TUXEDO_DEBUG("WMI event (%0#6x)\n", key_event);
|
TUXEDO_DEBUG("clevo event (%0#6x)\n", key_event);
|
||||||
|
|
||||||
switch (key_event) {
|
switch (key_event) {
|
||||||
case WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT:
|
case WMI_KEYEVENT_CODE_DECREASE_BACKLIGHT:
|
||||||
|
@ -563,16 +641,20 @@ static void clevo_wmi_notify(u32 value, void *context)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clevo_keyboard_driver.input_device != NULL) {
|
if (current_driver != NULL && current_driver->input_device != NULL) {
|
||||||
if (!sparse_keymap_report_known_event(
|
if (!sparse_keymap_report_known_event(
|
||||||
clevo_keyboard_driver.input_device, key_event, 1,
|
current_driver->input_device, key_event, 1, true)) {
|
||||||
true)) {
|
|
||||||
TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", key_event,
|
TUXEDO_DEBUG("Unknown key - %d (%0#6x)\n", key_event,
|
||||||
key_event);
|
key_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clevo_wmi_notify(u32 value, void *context)
|
||||||
|
{
|
||||||
|
clevo_keyboard_event_callb(value);
|
||||||
|
}
|
||||||
|
|
||||||
// Sysfs attribute file permissions and method linking
|
// Sysfs attribute file permissions and method linking
|
||||||
static DEVICE_ATTR(state, 0644, show_state_fs, set_state_fs);
|
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_left, 0644, show_color_left_fs, set_color_left_fs);
|
||||||
|
@ -584,44 +666,13 @@ 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(mode, 0644, show_blinking_patterns_fs, set_blinking_pattern_fs);
|
||||||
static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL);
|
static DEVICE_ATTR(extra, 0444, show_hasextra_fs, NULL);
|
||||||
|
|
||||||
static int clevo_keyboard_probe(struct platform_device *dev)
|
struct clevo_interface_t clevo_wmi_interface = {
|
||||||
|
.string_id = "clevo_wmi",
|
||||||
|
.method_call = clevo_wmi_interface_method_call
|
||||||
|
};
|
||||||
|
|
||||||
|
static void clevo_keyboard_init_device_interface(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
int status, ret;
|
|
||||||
|
|
||||||
if (!wmi_has_guid(CLEVO_EVENT_GUID)) {
|
|
||||||
TUXEDO_DEBUG("probe: Clevo event guid missing\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wmi_has_guid(CLEVO_GET_GUID)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = wmi_install_notify_handler(CLEVO_EVENT_GUID, clevo_wmi_notify,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (unlikely(ACPI_FAILURE(status))) {
|
|
||||||
TUXEDO_ERROR("Could not register WMI notify handler (%0#6x)\n",
|
|
||||||
status);
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable WMI events
|
|
||||||
evaluate_wmi_method_clevo(WMI_SUBMETHOD_ID_GET_AP, 0, NULL);
|
|
||||||
|
|
||||||
// Setup sysfs
|
// Setup sysfs
|
||||||
if (device_create_file(&dev->dev, &dev_attr_state) != 0) {
|
if (device_create_file(&dev->dev, &dev_attr_state) != 0) {
|
||||||
TUXEDO_ERROR("Sysfs attribute file creation failed for state\n");
|
TUXEDO_ERROR("Sysfs attribute file creation failed for state\n");
|
||||||
|
@ -682,7 +733,10 @@ static int clevo_keyboard_probe(struct platform_device *dev)
|
||||||
kbd_led_state.color.center = param_color_center;
|
kbd_led_state.color.center = param_color_center;
|
||||||
kbd_led_state.color.right = param_color_right;
|
kbd_led_state.color.right = param_color_right;
|
||||||
kbd_led_state.color.extra = param_color_extra;
|
kbd_led_state.color.extra = param_color_extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clevo_keyboard_write_state(void)
|
||||||
|
{
|
||||||
// Write state
|
// Write state
|
||||||
set_color(REGION_LEFT, param_color_left);
|
set_color(REGION_LEFT, param_color_left);
|
||||||
set_color(REGION_CENTER, param_color_center);
|
set_color(REGION_CENTER, param_color_center);
|
||||||
|
@ -692,14 +746,61 @@ static int clevo_keyboard_probe(struct platform_device *dev)
|
||||||
if (param_brightness > BRIGHTNESS_MAX) param_brightness = BRIGHTNESS_DEFAULT;
|
if (param_brightness > BRIGHTNESS_MAX) param_brightness = BRIGHTNESS_DEFAULT;
|
||||||
set_brightness(param_brightness);
|
set_brightness(param_brightness);
|
||||||
set_enabled(param_state);
|
set_enabled(param_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clevo_keyboard_probe(struct platform_device *dev)
|
||||||
|
{
|
||||||
|
int status, ret;
|
||||||
|
|
||||||
|
// *** Clevo ID part ***
|
||||||
|
if (!wmi_has_guid(CLEVO_EVENT_GUID)) {
|
||||||
|
TUXEDO_DEBUG("probe: Clevo event guid missing\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wmi_has_guid(CLEVO_GET_GUID)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
// *** Clevo ID part end ***
|
||||||
|
|
||||||
|
status = wmi_install_notify_handler(CLEVO_EVENT_GUID, clevo_wmi_notify,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (unlikely(ACPI_FAILURE(status))) {
|
||||||
|
TUXEDO_ERROR("Could not register WMI notify handler (%0#6x)\n",
|
||||||
|
status);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
clevo_keyboard_init_device_interface(dev);
|
||||||
|
|
||||||
|
// Add WMI interface (to be done in WMI driver)
|
||||||
|
clevo_keyboard_add_interface(&clevo_wmi_interface);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int clevo_keyboard_remove(struct platform_device *dev)
|
static int clevo_keyboard_probe_only_init(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
wmi_remove_notify_handler(CLEVO_EVENT_GUID);
|
clevo_keyboard_init_device_interface(dev);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clevo_keyboard_remove_device_interface(struct platform_device *dev)
|
||||||
|
{
|
||||||
device_remove_file(&dev->dev, &dev_attr_state);
|
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_left);
|
||||||
device_remove_file(&dev->dev, &dev_attr_color_center);
|
device_remove_file(&dev->dev, &dev_attr_color_center);
|
||||||
|
@ -711,6 +812,13 @@ static int clevo_keyboard_remove(struct platform_device *dev)
|
||||||
if (kbd_led_state.has_extra == 1) {
|
if (kbd_led_state.has_extra == 1) {
|
||||||
device_remove_file(&dev->dev, &dev_attr_color_extra);
|
device_remove_file(&dev->dev, &dev_attr_color_extra);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int clevo_keyboard_remove(struct platform_device *dev)
|
||||||
|
{
|
||||||
|
wmi_remove_notify_handler(CLEVO_EVENT_GUID);
|
||||||
|
|
||||||
|
clevo_keyboard_remove_device_interface(dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -724,7 +832,7 @@ static int clevo_keyboard_suspend(struct platform_device *dev, pm_message_t stat
|
||||||
|
|
||||||
static int clevo_keyboard_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);
|
clevo_evaluate_method(WMI_SUBMETHOD_ID_GET_AP, 0, NULL);
|
||||||
|
|
||||||
set_color(REGION_LEFT, kbd_led_state.color.left);
|
set_color(REGION_LEFT, kbd_led_state.color.left);
|
||||||
set_color(REGION_CENTER, kbd_led_state.color.center);
|
set_color(REGION_CENTER, kbd_led_state.color.center);
|
||||||
|
@ -755,3 +863,16 @@ struct tuxedo_keyboard_driver clevo_keyboard_driver = {
|
||||||
.probe = clevo_keyboard_probe,
|
.probe = clevo_keyboard_probe,
|
||||||
.key_map = clevo_wmi_keymap,
|
.key_map = clevo_wmi_keymap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tuxedo_keyboard_driver clevo_keyboard_driver_v2 = {
|
||||||
|
.platform_driver = &platform_driver_clevo,
|
||||||
|
.probe = clevo_keyboard_probe_only_init,
|
||||||
|
.key_map = clevo_wmi_keymap,
|
||||||
|
};
|
||||||
|
|
||||||
|
int clevo_keyboard_init(void)
|
||||||
|
{
|
||||||
|
tuxedo_keyboard_init_driver(&clevo_keyboard_driver_v2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(clevo_keyboard_init);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#define pr_fmt(fmt) "tuxedo_keyboard" ": " fmt
|
#define pr_fmt(fmt) "tuxedo_keyboard" ": " fmt
|
||||||
|
|
||||||
|
#include "tuxedo_keyboard.h"
|
||||||
#include "tuxedo_keyboard_common.h"
|
#include "tuxedo_keyboard_common.h"
|
||||||
#include "clevo_keyboard.h"
|
#include "clevo_keyboard.h"
|
||||||
#include "uniwill_keyboard.h"
|
#include "uniwill_keyboard.h"
|
||||||
|
@ -80,6 +81,44 @@ err_free_input_device:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct platform_device *tuxedo_keyboard_init_driver(struct tuxedo_keyboard_driver *tk_driver)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
TUXEDO_DEBUG("init driver start\n");
|
||||||
|
|
||||||
|
// If already initiated don't do anything further
|
||||||
|
if (!IS_ERR_OR_NULL(tuxedo_platform_device)) {
|
||||||
|
return tuxedo_platform_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
TUXEDO_DEBUG("create platform bundle\n");
|
||||||
|
|
||||||
|
tuxedo_platform_device = platform_create_bundle(
|
||||||
|
tk_driver->platform_driver, tk_driver->probe, NULL, 0, NULL, 0);
|
||||||
|
|
||||||
|
if (IS_ERR_OR_NULL(tuxedo_platform_device))
|
||||||
|
return tuxedo_platform_device;
|
||||||
|
|
||||||
|
TUXEDO_DEBUG("platform device created\n");
|
||||||
|
|
||||||
|
TUXEDO_DEBUG("initialize input device\n");
|
||||||
|
if (tk_driver->key_map != NULL) {
|
||||||
|
err = tuxedo_input_init(tk_driver->key_map);
|
||||||
|
if (unlikely(err)) {
|
||||||
|
TUXEDO_ERROR("Could not register input device\n");
|
||||||
|
tk_driver->input_device = NULL;
|
||||||
|
} else {
|
||||||
|
TUXEDO_DEBUG("input device registered\n");
|
||||||
|
tk_driver->input_device = tuxedo_input_device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_driver = tk_driver;
|
||||||
|
|
||||||
|
return tuxedo_platform_device;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(tuxedo_keyboard_init_driver);
|
||||||
|
|
||||||
static void __exit tuxedo_input_exit(void)
|
static void __exit tuxedo_input_exit(void)
|
||||||
{
|
{
|
||||||
if (unlikely(!tuxedo_input_device)) {
|
if (unlikely(!tuxedo_input_device)) {
|
||||||
|
@ -94,7 +133,7 @@ static void __exit tuxedo_input_exit(void)
|
||||||
|
|
||||||
static int __init tuxdeo_keyboard_init(void)
|
static int __init tuxdeo_keyboard_init(void)
|
||||||
{
|
{
|
||||||
int i, err;
|
int i;
|
||||||
int num_drivers = sizeof(driver_list) / sizeof(*driver_list);
|
int num_drivers = sizeof(driver_list) / sizeof(*driver_list);
|
||||||
TUXEDO_INFO("Model '%s' found\n",
|
TUXEDO_INFO("Model '%s' found\n",
|
||||||
dmi_get_system_info(DMI_PRODUCT_NAME));
|
dmi_get_system_info(DMI_PRODUCT_NAME));
|
||||||
|
@ -106,25 +145,13 @@ static int __init tuxdeo_keyboard_init(void)
|
||||||
i = 0;
|
i = 0;
|
||||||
while (IS_ERR_OR_NULL(tuxedo_platform_device) && i < num_drivers) {
|
while (IS_ERR_OR_NULL(tuxedo_platform_device) && i < num_drivers) {
|
||||||
current_driver = driver_list[i];
|
current_driver = driver_list[i];
|
||||||
tuxedo_platform_device = platform_create_bundle(
|
tuxedo_keyboard_init_driver(current_driver);
|
||||||
current_driver->platform_driver,
|
|
||||||
current_driver->probe, NULL, 0, NULL, 0);
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(tuxedo_platform_device)) {
|
if (IS_ERR_OR_NULL(tuxedo_platform_device)) {
|
||||||
TUXEDO_ERROR("No matching hardware found\n");
|
TUXEDO_DEBUG("No matching hardware found on init\n");
|
||||||
return -ENODEV;
|
current_driver = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
current_driver->input_device = NULL;
|
|
||||||
} else {
|
|
||||||
current_driver->input_device = tuxedo_input_device;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -132,13 +159,16 @@ static int __init tuxdeo_keyboard_init(void)
|
||||||
|
|
||||||
static void __exit tuxdeo_keyboard_exit(void)
|
static void __exit tuxdeo_keyboard_exit(void)
|
||||||
{
|
{
|
||||||
|
TUXEDO_DEBUG("tuxedo_input_exit()\n");
|
||||||
tuxedo_input_exit();
|
tuxedo_input_exit();
|
||||||
|
TUXEDO_DEBUG("platform_device_unregister()\n");
|
||||||
|
if (!IS_ERR_OR_NULL(tuxedo_platform_device))
|
||||||
platform_device_unregister(tuxedo_platform_device);
|
platform_device_unregister(tuxedo_platform_device);
|
||||||
|
TUXEDO_DEBUG("platform_driver_unregister()\n");
|
||||||
|
if (!IS_ERR_OR_NULL(current_driver))
|
||||||
platform_driver_unregister(current_driver->platform_driver);
|
platform_driver_unregister(current_driver->platform_driver);
|
||||||
|
|
||||||
TUXEDO_DEBUG("exit");
|
TUXEDO_DEBUG("exit\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(tuxdeo_keyboard_init);
|
module_init(tuxdeo_keyboard_init);
|
||||||
|
|
21
src/tuxedo_keyboard.h
Normal file
21
src/tuxedo_keyboard.h
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/dmi.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/input/sparse-keymap.h>
|
||||||
|
|
||||||
|
#ifndef TUXEDO_KEYBOARD_H
|
||||||
|
#define TUXEDO_KEYBOARD_H
|
||||||
|
|
||||||
|
struct clevo_interface_t {
|
||||||
|
char *string_id;
|
||||||
|
void (*event_callb)(u32);
|
||||||
|
u32 (*method_call)(u8, u32, u32*);
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 clevo_keyboard_add_interface(struct clevo_interface_t *new_interface);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -50,11 +50,13 @@ struct tuxedo_keyboard_driver {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global module devices
|
// Global module devices
|
||||||
static struct platform_device *tuxedo_platform_device;
|
static struct platform_device *tuxedo_platform_device = NULL;
|
||||||
static struct input_dev *tuxedo_input_device;
|
static struct input_dev *tuxedo_input_device = NULL;
|
||||||
|
|
||||||
// Currently chosen driver
|
// Currently chosen driver
|
||||||
static struct tuxedo_keyboard_driver *current_driver;
|
static struct tuxedo_keyboard_driver *current_driver = NULL;
|
||||||
|
|
||||||
|
struct platform_device *tuxedo_keyboard_init_driver(struct tuxedo_keyboard_driver *tk_driver);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basically a copy of the existing report event but doesn't report unknown events
|
* Basically a copy of the existing report event but doesn't report unknown events
|
||||||
|
|
|
@ -89,7 +89,7 @@ static struct key_entry uniwill_wmi_keymap[] = {
|
||||||
static void key_event_work(struct work_struct *work)
|
static void key_event_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
sparse_keymap_report_known_event(
|
sparse_keymap_report_known_event(
|
||||||
current_driver->input_device,
|
uniwill_keyboard_driver.input_device,
|
||||||
UNIWILL_OSD_TOUCHPADWORKAROUND,
|
UNIWILL_OSD_TOUCHPADWORKAROUND,
|
||||||
1,
|
1,
|
||||||
true
|
true
|
||||||
|
@ -244,20 +244,20 @@ static void uniwill_wmi_handle_event(u32 value, void *context, u32 guid_nr)
|
||||||
if (obj) {
|
if (obj) {
|
||||||
if (obj->type == ACPI_TYPE_INTEGER) {
|
if (obj->type == ACPI_TYPE_INTEGER) {
|
||||||
code = obj->integer.value;
|
code = obj->integer.value;
|
||||||
if (!sparse_keymap_report_known_event(current_driver->input_device, code, 1, true)) {
|
if (!sparse_keymap_report_known_event(uniwill_keyboard_driver.input_device, code, 1, true)) {
|
||||||
TUXEDO_DEBUG("[Ev %d] Unknown key - %d (%0#6x)\n", guid_nr, code, code);
|
TUXEDO_DEBUG("[Ev %d] Unknown key - %d (%0#6x)\n", guid_nr, code, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special key combination when mode change key is pressed
|
// Special key combination when mode change key is pressed
|
||||||
if (code == 0xb0) {
|
if (code == 0xb0) {
|
||||||
input_report_key(current_driver->input_device, KEY_LEFTMETA, 1);
|
input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 1);
|
||||||
input_report_key(current_driver->input_device, KEY_LEFTALT, 1);
|
input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTALT, 1);
|
||||||
input_report_key(current_driver->input_device, KEY_F6, 1);
|
input_report_key(uniwill_keyboard_driver.input_device, KEY_F6, 1);
|
||||||
input_sync(current_driver->input_device);
|
input_sync(uniwill_keyboard_driver.input_device);
|
||||||
input_report_key(current_driver->input_device, KEY_F6, 0);
|
input_report_key(uniwill_keyboard_driver.input_device, KEY_F6, 0);
|
||||||
input_report_key(current_driver->input_device, KEY_LEFTALT, 0);
|
input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTALT, 0);
|
||||||
input_report_key(current_driver->input_device, KEY_LEFTMETA, 0);
|
input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 0);
|
||||||
input_sync(current_driver->input_device);
|
input_sync(uniwill_keyboard_driver.input_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard backlight brightness toggle
|
// Keyboard backlight brightness toggle
|
||||||
|
|
Loading…
Reference in a new issue