|
@@ -29,6 +29,7 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/types.h>
|
|
|
#include <linux/input.h>
|
|
|
+#include <linux/input/sparse-keymap.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/acpi.h>
|
|
|
#include <linux/rfkill.h>
|
|
@@ -88,24 +89,16 @@ struct bios_return {
|
|
|
u32 value;
|
|
|
};
|
|
|
|
|
|
-struct key_entry {
|
|
|
- char type; /* See KE_* below */
|
|
|
- u16 code;
|
|
|
- u16 keycode;
|
|
|
-};
|
|
|
-
|
|
|
-enum { KE_KEY, KE_END };
|
|
|
-
|
|
|
-static struct key_entry hp_wmi_keymap[] = {
|
|
|
- {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
|
|
|
- {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
|
|
|
- {KE_KEY, 0x20e6, KEY_PROG1},
|
|
|
- {KE_KEY, 0x20e8, KEY_MEDIA},
|
|
|
- {KE_KEY, 0x2142, KEY_MEDIA},
|
|
|
- {KE_KEY, 0x213b, KEY_INFO},
|
|
|
- {KE_KEY, 0x2169, KEY_DIRECTION},
|
|
|
- {KE_KEY, 0x231b, KEY_HELP},
|
|
|
- {KE_END, 0}
|
|
|
+static const struct key_entry hp_wmi_keymap[] = {
|
|
|
+ { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
|
|
|
+ { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
|
|
|
+ { KE_KEY, 0x20e6, { KEY_PROG1 } },
|
|
|
+ { KE_KEY, 0x20e8, { KEY_MEDIA } },
|
|
|
+ { KE_KEY, 0x2142, { KEY_MEDIA } },
|
|
|
+ { KE_KEY, 0x213b, { KEY_INFO } },
|
|
|
+ { KE_KEY, 0x2169, { KEY_DIRECTION } },
|
|
|
+ { KE_KEY, 0x231b, { KEY_HELP } },
|
|
|
+ { KE_END, 0 }
|
|
|
};
|
|
|
|
|
|
static struct input_dev *hp_wmi_input_dev;
|
|
@@ -347,64 +340,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
|
|
|
static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
|
|
|
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
|
|
|
|
|
|
-static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
|
|
|
-{
|
|
|
- struct key_entry *key;
|
|
|
-
|
|
|
- for (key = hp_wmi_keymap; key->type != KE_END; key++)
|
|
|
- if (code == key->code)
|
|
|
- return key;
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
|
|
|
-{
|
|
|
- struct key_entry *key;
|
|
|
-
|
|
|
- for (key = hp_wmi_keymap; key->type != KE_END; key++)
|
|
|
- if (key->type == KE_KEY && keycode == key->keycode)
|
|
|
- return key;
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-static int hp_wmi_getkeycode(struct input_dev *dev,
|
|
|
- unsigned int scancode, unsigned int *keycode)
|
|
|
-{
|
|
|
- struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
|
|
|
-
|
|
|
- if (key && key->type == KE_KEY) {
|
|
|
- *keycode = key->keycode;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
-static int hp_wmi_setkeycode(struct input_dev *dev,
|
|
|
- unsigned int scancode, unsigned int keycode)
|
|
|
-{
|
|
|
- struct key_entry *key;
|
|
|
- unsigned int old_keycode;
|
|
|
-
|
|
|
- key = hp_wmi_get_entry_by_scancode(scancode);
|
|
|
- if (key && key->type == KE_KEY) {
|
|
|
- old_keycode = key->keycode;
|
|
|
- key->keycode = keycode;
|
|
|
- set_bit(keycode, dev->keybit);
|
|
|
- if (!hp_wmi_get_entry_by_keycode(old_keycode))
|
|
|
- clear_bit(old_keycode, dev->keybit);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
static void hp_wmi_notify(u32 value, void *context)
|
|
|
{
|
|
|
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
|
- static struct key_entry *key;
|
|
|
union acpi_object *obj;
|
|
|
u32 event_id, event_data;
|
|
|
int key_code = 0, ret;
|
|
@@ -465,19 +403,9 @@ static void hp_wmi_notify(u32 value, void *context)
|
|
|
sizeof(key_code));
|
|
|
if (ret)
|
|
|
break;
|
|
|
- key = hp_wmi_get_entry_by_scancode(key_code);
|
|
|
- if (key) {
|
|
|
- switch (key->type) {
|
|
|
- case KE_KEY:
|
|
|
- input_report_key(hp_wmi_input_dev,
|
|
|
- key->keycode, 1);
|
|
|
- input_sync(hp_wmi_input_dev);
|
|
|
- input_report_key(hp_wmi_input_dev,
|
|
|
- key->keycode, 0);
|
|
|
- input_sync(hp_wmi_input_dev);
|
|
|
- break;
|
|
|
- }
|
|
|
- } else
|
|
|
+
|
|
|
+ if (!sparse_keymap_report_event(hp_wmi_input_dev,
|
|
|
+ key_code, 1, true))
|
|
|
printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
|
|
|
key_code);
|
|
|
break;
|
|
@@ -510,7 +438,7 @@ static void hp_wmi_notify(u32 value, void *context)
|
|
|
|
|
|
static int __init hp_wmi_input_setup(void)
|
|
|
{
|
|
|
- struct key_entry *key;
|
|
|
+ acpi_status status;
|
|
|
int err;
|
|
|
|
|
|
hp_wmi_input_dev = input_allocate_device();
|
|
@@ -520,21 +448,14 @@ static int __init hp_wmi_input_setup(void)
|
|
|
hp_wmi_input_dev->name = "HP WMI hotkeys";
|
|
|
hp_wmi_input_dev->phys = "wmi/input0";
|
|
|
hp_wmi_input_dev->id.bustype = BUS_HOST;
|
|
|
- hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
|
|
|
- hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
|
|
|
-
|
|
|
- for (key = hp_wmi_keymap; key->type != KE_END; key++) {
|
|
|
- switch (key->type) {
|
|
|
- case KE_KEY:
|
|
|
- set_bit(EV_KEY, hp_wmi_input_dev->evbit);
|
|
|
- set_bit(key->keycode, hp_wmi_input_dev->keybit);
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
- set_bit(EV_SW, hp_wmi_input_dev->evbit);
|
|
|
- set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
|
|
|
- set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
|
|
|
+ __set_bit(EV_SW, hp_wmi_input_dev->evbit);
|
|
|
+ __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
|
|
|
+ __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
|
|
|
+
|
|
|
+ err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
|
|
|
+ if (err)
|
|
|
+ goto err_free_dev;
|
|
|
|
|
|
/* Set initial hardware state */
|
|
|
input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
|
|
@@ -542,14 +463,32 @@ static int __init hp_wmi_input_setup(void)
|
|
|
hp_wmi_tablet_state());
|
|
|
input_sync(hp_wmi_input_dev);
|
|
|
|
|
|
- err = input_register_device(hp_wmi_input_dev);
|
|
|
-
|
|
|
- if (err) {
|
|
|
- input_free_device(hp_wmi_input_dev);
|
|
|
- return err;
|
|
|
+ status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
+ err = -EIO;
|
|
|
+ goto err_free_keymap;
|
|
|
}
|
|
|
|
|
|
+ err = input_register_device(hp_wmi_input_dev);
|
|
|
+ if (err)
|
|
|
+ goto err_uninstall_notifier;
|
|
|
+
|
|
|
return 0;
|
|
|
+
|
|
|
+ err_uninstall_notifier:
|
|
|
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
|
|
|
+ err_free_keymap:
|
|
|
+ sparse_keymap_free(hp_wmi_input_dev);
|
|
|
+ err_free_dev:
|
|
|
+ input_free_device(hp_wmi_input_dev);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static void hp_wmi_input_destroy(void)
|
|
|
+{
|
|
|
+ wmi_remove_notify_handler(HPWMI_EVENT_GUID);
|
|
|
+ sparse_keymap_free(hp_wmi_input_dev);
|
|
|
+ input_unregister_device(hp_wmi_input_dev);
|
|
|
}
|
|
|
|
|
|
static void cleanup_sysfs(struct platform_device *device)
|
|
@@ -704,15 +643,9 @@ static int __init hp_wmi_init(void)
|
|
|
int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
|
|
|
|
|
|
if (event_capable) {
|
|
|
- err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
|
|
|
- hp_wmi_notify, NULL);
|
|
|
- if (ACPI_FAILURE(err))
|
|
|
- return -EINVAL;
|
|
|
err = hp_wmi_input_setup();
|
|
|
- if (err) {
|
|
|
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
|
|
|
+ if (err)
|
|
|
return err;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
if (bios_capable) {
|
|
@@ -739,20 +672,17 @@ err_device_add:
|
|
|
err_device_alloc:
|
|
|
platform_driver_unregister(&hp_wmi_driver);
|
|
|
err_driver_reg:
|
|
|
- if (wmi_has_guid(HPWMI_EVENT_GUID)) {
|
|
|
- input_unregister_device(hp_wmi_input_dev);
|
|
|
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
|
|
|
- }
|
|
|
+ if (event_capable)
|
|
|
+ hp_wmi_input_destroy();
|
|
|
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
static void __exit hp_wmi_exit(void)
|
|
|
{
|
|
|
- if (wmi_has_guid(HPWMI_EVENT_GUID)) {
|
|
|
- wmi_remove_notify_handler(HPWMI_EVENT_GUID);
|
|
|
- input_unregister_device(hp_wmi_input_dev);
|
|
|
- }
|
|
|
+ if (wmi_has_guid(HPWMI_EVENT_GUID))
|
|
|
+ hp_wmi_input_destroy();
|
|
|
+
|
|
|
if (hp_wmi_platform_dev) {
|
|
|
platform_device_unregister(hp_wmi_platform_dev);
|
|
|
platform_driver_unregister(&hp_wmi_driver);
|