Commit 4d291ed7 authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Matthew Garrett

Input: hp-wmi - switch to using sparse keymap library

Instead of implementing its own version of keymap hanlding switch over
to using sparse keymap library.

Also make sure that we install notify handler only after we allocated
input device and that we remove notify handler before unregistering
input device.
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
Signed-off-by: default avatarMatthew Garrett <mjg@redhat.com>
parent 890a7c8e
...@@ -141,6 +141,7 @@ config HP_WMI ...@@ -141,6 +141,7 @@ config HP_WMI
depends on ACPI_WMI depends on ACPI_WMI
depends on INPUT depends on INPUT
depends on RFKILL || RFKILL = n depends on RFKILL || RFKILL = n
select INPUT_SPARSEKMAP
help help
Say Y here if you want to support WMI-based hotkeys on HP laptops and Say Y here if you want to support WMI-based hotkeys on HP laptops and
to read data from WMI such as docking or ambient light sensor state. to read data from WMI such as docking or ambient light sensor state.
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/rfkill.h> #include <linux/rfkill.h>
...@@ -88,24 +89,16 @@ struct bios_return { ...@@ -88,24 +89,16 @@ struct bios_return {
u32 value; u32 value;
}; };
struct key_entry { static const struct key_entry hp_wmi_keymap[] = {
char type; /* See KE_* below */ { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
u16 code; { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
u16 keycode; { KE_KEY, 0x20e6, { KEY_PROG1 } },
}; { KE_KEY, 0x20e8, { KEY_MEDIA } },
{ KE_KEY, 0x2142, { KEY_MEDIA } },
enum { KE_KEY, KE_END }; { KE_KEY, 0x213b, { KEY_INFO } },
{ KE_KEY, 0x2169, { KEY_DIRECTION } },
static struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x231b, { KEY_HELP } },
{KE_KEY, 0x02, KEY_BRIGHTNESSUP}, { KE_END, 0 }
{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; static struct input_dev *hp_wmi_input_dev;
...@@ -347,64 +340,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); ...@@ -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(dock, S_IRUGO, show_dock, NULL);
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, 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) static void hp_wmi_notify(u32 value, void *context)
{ {
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
static struct key_entry *key;
union acpi_object *obj; union acpi_object *obj;
u32 event_id, event_data; u32 event_id, event_data;
int key_code = 0, ret; int key_code = 0, ret;
...@@ -465,19 +403,9 @@ static void hp_wmi_notify(u32 value, void *context) ...@@ -465,19 +403,9 @@ static void hp_wmi_notify(u32 value, void *context)
sizeof(key_code)); sizeof(key_code));
if (ret) if (ret)
break; break;
key = hp_wmi_get_entry_by_scancode(key_code);
if (key) { if (!sparse_keymap_report_event(hp_wmi_input_dev,
switch (key->type) { key_code, 1, true))
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
printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n", printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
key_code); key_code);
break; break;
...@@ -510,7 +438,7 @@ static void hp_wmi_notify(u32 value, void *context) ...@@ -510,7 +438,7 @@ static void hp_wmi_notify(u32 value, void *context)
static int __init hp_wmi_input_setup(void) static int __init hp_wmi_input_setup(void)
{ {
struct key_entry *key; acpi_status status;
int err; int err;
hp_wmi_input_dev = input_allocate_device(); hp_wmi_input_dev = input_allocate_device();
...@@ -520,21 +448,14 @@ static int __init hp_wmi_input_setup(void) ...@@ -520,21 +448,14 @@ static int __init hp_wmi_input_setup(void)
hp_wmi_input_dev->name = "HP WMI hotkeys"; hp_wmi_input_dev->name = "HP WMI hotkeys";
hp_wmi_input_dev->phys = "wmi/input0"; hp_wmi_input_dev->phys = "wmi/input0";
hp_wmi_input_dev->id.bustype = BUS_HOST; 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(EV_SW, hp_wmi_input_dev->evbit);
set_bit(SW_DOCK, hp_wmi_input_dev->swbit); __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
set_bit(SW_TABLET_MODE, 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 */ /* Set initial hardware state */
input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_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) ...@@ -542,14 +463,32 @@ static int __init hp_wmi_input_setup(void)
hp_wmi_tablet_state()); hp_wmi_tablet_state());
input_sync(hp_wmi_input_dev); input_sync(hp_wmi_input_dev);
err = input_register_device(hp_wmi_input_dev); status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
if (ACPI_FAILURE(status)) {
if (err) { err = -EIO;
input_free_device(hp_wmi_input_dev); goto err_free_keymap;
return err;
} }
err = input_register_device(hp_wmi_input_dev);
if (err)
goto err_uninstall_notifier;
return 0; 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) static void cleanup_sysfs(struct platform_device *device)
...@@ -704,15 +643,9 @@ static int __init hp_wmi_init(void) ...@@ -704,15 +643,9 @@ static int __init hp_wmi_init(void)
int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
if (event_capable) { 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(); err = hp_wmi_input_setup();
if (err) { if (err)
wmi_remove_notify_handler(HPWMI_EVENT_GUID);
return err; return err;
}
} }
if (bios_capable) { if (bios_capable) {
...@@ -739,20 +672,17 @@ static int __init hp_wmi_init(void) ...@@ -739,20 +672,17 @@ static int __init hp_wmi_init(void)
err_device_alloc: err_device_alloc:
platform_driver_unregister(&hp_wmi_driver); platform_driver_unregister(&hp_wmi_driver);
err_driver_reg: err_driver_reg:
if (wmi_has_guid(HPWMI_EVENT_GUID)) { if (event_capable)
input_unregister_device(hp_wmi_input_dev); hp_wmi_input_destroy();
wmi_remove_notify_handler(HPWMI_EVENT_GUID);
}
return err; return err;
} }
static void __exit hp_wmi_exit(void) static void __exit hp_wmi_exit(void)
{ {
if (wmi_has_guid(HPWMI_EVENT_GUID)) { if (wmi_has_guid(HPWMI_EVENT_GUID))
wmi_remove_notify_handler(HPWMI_EVENT_GUID); hp_wmi_input_destroy();
input_unregister_device(hp_wmi_input_dev);
}
if (hp_wmi_platform_dev) { if (hp_wmi_platform_dev) {
platform_device_unregister(hp_wmi_platform_dev); platform_device_unregister(hp_wmi_platform_dev);
platform_driver_unregister(&hp_wmi_driver); platform_driver_unregister(&hp_wmi_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment