Commit 66a71dd1 authored by Corentin Chary's avatar Corentin Chary

asus-laptop: switch to sparse keymap library

This patch is based on Dmitry Torokhov's patch with
some modifications and cleanups.
Signed-off-by: default avatarCorentin Chary <corentincj@iksaif.net>
parent d0930a2d
...@@ -59,6 +59,7 @@ config ASUS_LAPTOP ...@@ -59,6 +59,7 @@ config ASUS_LAPTOP
select NEW_LEDS select NEW_LEDS
select BACKLIGHT_CLASS_DEVICE select BACKLIGHT_CLASS_DEVICE
depends on INPUT depends on INPUT
select INPUT_SPARSEKMAP
---help--- ---help---
This is the new Linux driver for Asus laptops. It may also support some This is the new Linux driver for Asus laptops. It may also support some
MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#define ASUS_LAPTOP_VERSION "0.42" #define ASUS_LAPTOP_VERSION "0.42"
...@@ -243,52 +244,45 @@ struct asus_laptop { ...@@ -243,52 +244,45 @@ struct asus_laptop {
u16 *keycode_map; u16 *keycode_map;
}; };
struct key_entry {
char type;
u8 code;
u16 keycode;
};
enum { KE_KEY, KE_END };
static const struct key_entry asus_keymap[] = { static const struct key_entry asus_keymap[] = {
{KE_KEY, 0x02, KEY_SCREENLOCK}, {KE_KEY, 0x02, { KEY_SCREENLOCK } },
{KE_KEY, 0x05, KEY_WLAN}, {KE_KEY, 0x05, { KEY_WLAN } },
{KE_KEY, 0x08, KEY_F13}, {KE_KEY, 0x08, { KEY_F13 } },
{KE_KEY, 0x17, KEY_ZOOM}, {KE_KEY, 0x17, { KEY_ZOOM } },
{KE_KEY, 0x1f, KEY_BATTERY}, {KE_KEY, 0x1f, { KEY_BATTERY } },
{KE_KEY, 0x30, KEY_VOLUMEUP}, {KE_KEY, 0x30, { KEY_VOLUMEUP } },
{KE_KEY, 0x31, KEY_VOLUMEDOWN}, {KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
{KE_KEY, 0x32, KEY_MUTE}, {KE_KEY, 0x32, { KEY_MUTE } },
{KE_KEY, 0x33, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x33, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x34, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x34, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x40, KEY_PREVIOUSSONG}, {KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
{KE_KEY, 0x41, KEY_NEXTSONG}, {KE_KEY, 0x41, { KEY_NEXTSONG } },
{KE_KEY, 0x43, KEY_STOPCD}, {KE_KEY, 0x43, { KEY_STOPCD } },
{KE_KEY, 0x45, KEY_PLAYPAUSE}, {KE_KEY, 0x45, { KEY_PLAYPAUSE } },
{KE_KEY, 0x4c, KEY_MEDIA}, {KE_KEY, 0x4c, { KEY_MEDIA } },
{KE_KEY, 0x50, KEY_EMAIL}, {KE_KEY, 0x50, { KEY_EMAIL } },
{KE_KEY, 0x51, KEY_WWW}, {KE_KEY, 0x51, { KEY_WWW } },
{KE_KEY, 0x55, KEY_CALC}, {KE_KEY, 0x55, { KEY_CALC } },
{KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */ {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */
{KE_KEY, 0x5D, KEY_WLAN}, {KE_KEY, 0x5D, { KEY_WLAN } },
{KE_KEY, 0x5E, KEY_WLAN}, {KE_KEY, 0x5E, { KEY_WLAN } },
{KE_KEY, 0x5F, KEY_WLAN}, {KE_KEY, 0x5F, { KEY_WLAN } },
{KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
{KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */ {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
{KE_KEY, 0x82, KEY_CAMERA}, {KE_KEY, 0x82, { KEY_CAMERA } },
{KE_KEY, 0x88, KEY_WLAN }, {KE_KEY, 0x88, { KEY_WLAN } },
{KE_KEY, 0x8A, KEY_PROG1}, {KE_KEY, 0x8A, { KEY_PROG1 } },
{KE_KEY, 0x95, KEY_MEDIA}, {KE_KEY, 0x95, { KEY_MEDIA } },
{KE_KEY, 0x99, KEY_PHONE}, {KE_KEY, 0x99, { KEY_PHONE } },
{KE_KEY, 0xc4, KEY_KBDILLUMUP}, {KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
{KE_KEY, 0xc5, KEY_KBDILLUMDOWN}, {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
{KE_END, 0}, {KE_END, 0},
}; };
/* /*
* This function evaluates an ACPI method, given an int as parameter, the * This function evaluates an ACPI method, given an int as parameter, the
* method is searched within the scope of the handle, can be NULL. The output * method is searched within the scope of the handle, can be NULL. The output
...@@ -1050,123 +1044,55 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr, ...@@ -1050,123 +1044,55 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
/* /*
* Input device (i.e. hotkeys) * Input device (i.e. hotkeys)
*/ */
static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus,
int code)
{
struct key_entry *key;
for (key = asus->keymap; key->type != KE_END; key++)
if (code == key->code)
return key;
return NULL;
}
static struct key_entry *asus_get_entry_by_keycode(struct asus_laptop *asus,
int code)
{
struct key_entry *key;
for (key = asus->keymap; key->type != KE_END; key++)
if (code == key->keycode && key->type == KE_KEY)
return key;
return NULL;
}
static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
{
struct asus_laptop *asus = input_get_drvdata(dev);
struct key_entry *key = asus_get_entry_by_scancode(asus, scancode);
if (key && key->type == KE_KEY) {
*keycode = key->keycode;
return 0;
}
return -EINVAL;
}
static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
{
struct asus_laptop *asus = input_get_drvdata(dev);
struct key_entry *key;
int old_keycode;
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
key = asus_get_entry_by_scancode(asus, scancode);
if (key && key->type == KE_KEY) {
old_keycode = key->keycode;
key->keycode = keycode;
set_bit(keycode, dev->keybit);
if (!asus_get_entry_by_keycode(asus, old_keycode))
clear_bit(old_keycode, dev->keybit);
return 0;
}
return -EINVAL;
}
static void asus_input_notify(struct asus_laptop *asus, int event) static void asus_input_notify(struct asus_laptop *asus, int event)
{ {
struct key_entry *key; if (asus->inputdev)
sparse_keymap_report_event(asus->inputdev, event, 1, true);
key = asus_get_entry_by_scancode(asus, event);
if (!key)
return ;
switch (key->type) {
case KE_KEY:
input_report_key(asus->inputdev, key->keycode, 1);
input_sync(asus->inputdev);
input_report_key(asus->inputdev, key->keycode, 0);
input_sync(asus->inputdev);
break;
}
} }
static int asus_input_init(struct asus_laptop *asus) static int asus_input_init(struct asus_laptop *asus)
{ {
const struct key_entry *key; struct input_dev *input;
int result; int error;
asus->inputdev = input_allocate_device(); input = input_allocate_device();
if (!asus->inputdev) { if (!input) {
pr_info("Unable to allocate input device\n"); pr_info("Unable to allocate input device\n");
return 0; return 0;
} }
asus->inputdev->name = "Asus Laptop extra buttons"; input->name = "Asus Laptop extra buttons";
asus->inputdev->dev.parent = &asus->platform_device->dev; input->phys = ASUS_LAPTOP_FILE "/input0";
asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0"; input->id.bustype = BUS_HOST;
asus->inputdev->id.bustype = BUS_HOST; input->dev.parent = &asus->platform_device->dev;
asus->inputdev->getkeycode = asus_getkeycode; input_set_drvdata(input, asus);
asus->inputdev->setkeycode = asus_setkeycode;
input_set_drvdata(asus->inputdev, asus); error = sparse_keymap_setup(input, asus_keymap, NULL);
if (error) {
asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap), pr_err("Unable to setup input device keymap\n");
GFP_KERNEL); goto err_keymap;
for (key = asus->keymap; key->type != KE_END; key++) {
switch (key->type) {
case KE_KEY:
set_bit(EV_KEY, asus->inputdev->evbit);
set_bit(key->keycode, asus->inputdev->keybit);
break;
}
} }
result = input_register_device(asus->inputdev); error = input_register_device(input);
if (result) { if (error) {
pr_info("Unable to register input device\n"); pr_info("Unable to register input device\n");
input_free_device(asus->inputdev); goto err_device;
} }
return result;
asus->inputdev = input;
return 0;
err_keymap:
sparse_keymap_free(input);
err_device:
input_free_device(input);
return error;
} }
static void asus_input_exit(struct asus_laptop *asus) static void asus_input_exit(struct asus_laptop *asus)
{ {
if (asus->inputdev) if (asus->inputdev) {
sparse_keymap_free(asus->inputdev);
input_unregister_device(asus->inputdev); input_unregister_device(asus->inputdev);
}
} }
/* /*
......
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