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:
Christoffer Sandberg 2020-12-02 17:25:43 +01:00
parent 6d76c68eb4
commit 6f14b22b33
No known key found for this signature in database
GPG key ID: BF563F71B6C7A96D
7 changed files with 331 additions and 95 deletions

18
src/ck.h Normal file
View 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

View file

@ -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);

View file

@ -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);

View file

@ -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);
TUXEDO_DEBUG("platform_driver_unregister()\n");
if (!IS_ERR_OR_NULL(current_driver))
platform_driver_unregister(current_driver->platform_driver);
platform_device_unregister(tuxedo_platform_device); TUXEDO_DEBUG("exit\n");
platform_driver_unregister(current_driver->platform_driver);
TUXEDO_DEBUG("exit");
} }
module_init(tuxdeo_keyboard_init); module_init(tuxdeo_keyboard_init);

21
src/tuxedo_keyboard.h Normal file
View 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

View file

@ -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

View file

@ -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