panasonic-laptop - switch to using sparse keymap library
nstead of implementing its own version of keymap hanlding switch over to using sparse keymap library. Cc: Harald Welte <laforge@gnumonks.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Matthew Garrett <mjg@redhat.com>
This commit is contained in:
Родитель
97490f1cf8
Коммит
1a765cac9a
|
@ -171,6 +171,7 @@ config PANASONIC_LAPTOP
|
|||
tristate "Panasonic Laptop Extras"
|
||||
depends on INPUT && ACPI
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select INPUT_SPARSEKMAP
|
||||
---help---
|
||||
This driver adds support for access to backlight control and hotkeys
|
||||
on Panasonic Let's Note laptops.
|
||||
|
|
|
@ -128,6 +128,7 @@
|
|||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
|
||||
|
||||
#ifndef ACPI_HOTKEY_COMPONENT
|
||||
|
@ -200,30 +201,29 @@ static struct acpi_driver acpi_pcc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
#define KEYMAP_SIZE 11
|
||||
static const unsigned int initial_keymap[KEYMAP_SIZE] = {
|
||||
/* 0 */ KEY_RESERVED,
|
||||
/* 1 */ KEY_BRIGHTNESSDOWN,
|
||||
/* 2 */ KEY_BRIGHTNESSUP,
|
||||
/* 3 */ KEY_DISPLAYTOGGLE,
|
||||
/* 4 */ KEY_MUTE,
|
||||
/* 5 */ KEY_VOLUMEDOWN,
|
||||
/* 6 */ KEY_VOLUMEUP,
|
||||
/* 7 */ KEY_SLEEP,
|
||||
/* 8 */ KEY_PROG1, /* Change CPU boost */
|
||||
/* 9 */ KEY_BATTERY,
|
||||
/* 10 */ KEY_SUSPEND,
|
||||
static const struct key_entry panasonic_keymap[] = {
|
||||
{ KE_KEY, 0, { KEY_RESERVED } },
|
||||
{ KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
|
||||
{ KE_KEY, 2, { KEY_BRIGHTNESSUP } },
|
||||
{ KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
|
||||
{ KE_KEY, 4, { KEY_MUTE } },
|
||||
{ KE_KEY, 5, { KEY_VOLUMEDOWN } },
|
||||
{ KE_KEY, 6, { KEY_VOLUMEUP } },
|
||||
{ KE_KEY, 7, { KEY_SLEEP } },
|
||||
{ KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
|
||||
{ KE_KEY, 9, { KEY_BATTERY } },
|
||||
{ KE_KEY, 10, { KEY_SUSPEND } },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
struct pcc_acpi {
|
||||
acpi_handle handle;
|
||||
unsigned long num_sifr;
|
||||
int sticky_mode;
|
||||
u32 *sinf;
|
||||
u32 *sinf;
|
||||
struct acpi_device *device;
|
||||
struct input_dev *input_dev;
|
||||
struct backlight_device *backlight;
|
||||
unsigned int keymap[KEYMAP_SIZE];
|
||||
};
|
||||
|
||||
struct pcc_keyinput {
|
||||
|
@ -446,56 +446,10 @@ static struct attribute_group pcc_attr_group = {
|
|||
|
||||
/* hotkey input device driver */
|
||||
|
||||
static int pcc_getkeycode(struct input_dev *dev,
|
||||
unsigned int scancode, unsigned int *keycode)
|
||||
{
|
||||
struct pcc_acpi *pcc = input_get_drvdata(dev);
|
||||
|
||||
if (scancode >= ARRAY_SIZE(pcc->keymap))
|
||||
return -EINVAL;
|
||||
|
||||
*keycode = pcc->keymap[scancode];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int keymap_get_by_keycode(struct pcc_acpi *pcc, unsigned int keycode)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++) {
|
||||
if (pcc->keymap[i] == keycode)
|
||||
return i+1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcc_setkeycode(struct input_dev *dev,
|
||||
unsigned int scancode, unsigned int keycode)
|
||||
{
|
||||
struct pcc_acpi *pcc = input_get_drvdata(dev);
|
||||
int oldkeycode;
|
||||
|
||||
if (scancode >= ARRAY_SIZE(pcc->keymap))
|
||||
return -EINVAL;
|
||||
|
||||
oldkeycode = pcc->keymap[scancode];
|
||||
pcc->keymap[scancode] = keycode;
|
||||
|
||||
set_bit(keycode, dev->keybit);
|
||||
|
||||
if (!keymap_get_by_keycode(pcc, oldkeycode))
|
||||
clear_bit(oldkeycode, dev->keybit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
|
||||
{
|
||||
struct input_dev *hotk_input_dev = pcc->input_dev;
|
||||
int rc;
|
||||
int key_code, hkey_num;
|
||||
unsigned long long result;
|
||||
|
||||
rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
|
||||
|
@ -508,25 +462,10 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
|
|||
|
||||
acpi_bus_generate_proc_event(pcc->device, HKEY_NOTIFY, result);
|
||||
|
||||
hkey_num = result & 0xf;
|
||||
|
||||
if (hkey_num < 0 || hkey_num >= ARRAY_SIZE(pcc->keymap)) {
|
||||
if (!sparse_keymap_report_event(hotk_input_dev,
|
||||
result & 0xf, result & 0x80, false))
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"hotkey number out of range: %d\n",
|
||||
hkey_num));
|
||||
return;
|
||||
}
|
||||
|
||||
key_code = pcc->keymap[hkey_num];
|
||||
|
||||
if (key_code != KEY_RESERVED) {
|
||||
int pushed = (result & 0x80) ? TRUE : FALSE;
|
||||
|
||||
input_report_key(hotk_input_dev, key_code, pushed);
|
||||
input_sync(hotk_input_dev);
|
||||
}
|
||||
|
||||
return;
|
||||
"Unknown hotkey event: %d\n", result));
|
||||
}
|
||||
|
||||
static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
|
||||
|
@ -545,40 +484,55 @@ static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event)
|
|||
|
||||
static int acpi_pcc_init_input(struct pcc_acpi *pcc)
|
||||
{
|
||||
int i, rc;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
pcc->input_dev = input_allocate_device();
|
||||
if (!pcc->input_dev) {
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Couldn't allocate input device for hotkey"));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pcc->input_dev->evbit[0] = BIT(EV_KEY);
|
||||
input_dev->name = ACPI_PCC_DRIVER_NAME;
|
||||
input_dev->phys = ACPI_PCC_INPUT_PHYS;
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->id.vendor = 0x0001;
|
||||
input_dev->id.product = 0x0001;
|
||||
input_dev->id.version = 0x0100;
|
||||
|
||||
pcc->input_dev->name = ACPI_PCC_DRIVER_NAME;
|
||||
pcc->input_dev->phys = ACPI_PCC_INPUT_PHYS;
|
||||
pcc->input_dev->id.bustype = BUS_HOST;
|
||||
pcc->input_dev->id.vendor = 0x0001;
|
||||
pcc->input_dev->id.product = 0x0001;
|
||||
pcc->input_dev->id.version = 0x0100;
|
||||
pcc->input_dev->getkeycode = pcc_getkeycode;
|
||||
pcc->input_dev->setkeycode = pcc_setkeycode;
|
||||
error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
|
||||
if (error) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Unable to setup input device keymap\n"));
|
||||
goto err_free_dev;
|
||||
}
|
||||
|
||||
/* load initial keymap */
|
||||
memcpy(pcc->keymap, initial_keymap, sizeof(pcc->keymap));
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Unable to register input device\n"));
|
||||
goto err_free_keymap;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pcc->keymap); i++)
|
||||
__set_bit(pcc->keymap[i], pcc->input_dev->keybit);
|
||||
__clear_bit(KEY_RESERVED, pcc->input_dev->keybit);
|
||||
pcc->input_dev = input_dev;
|
||||
return 0;
|
||||
|
||||
input_set_drvdata(pcc->input_dev, pcc);
|
||||
err_free_keymap:
|
||||
sparse_keymap_free(input_dev);
|
||||
err_free_dev:
|
||||
input_free_device(input_dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
rc = input_register_device(pcc->input_dev);
|
||||
if (rc < 0)
|
||||
input_free_device(pcc->input_dev);
|
||||
|
||||
return rc;
|
||||
static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
|
||||
{
|
||||
sparse_keymap_free(pcc->input_dev);
|
||||
input_unregister_device(pcc->input_dev);
|
||||
/*
|
||||
* No need to input_free_device() since core input API refcounts
|
||||
* and free()s the device.
|
||||
*/
|
||||
}
|
||||
|
||||
/* kernel module interface */
|
||||
|
@ -636,7 +590,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
|||
if (result) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error installing keyinput handler\n"));
|
||||
goto out_hotkey;
|
||||
goto out_sinf;
|
||||
}
|
||||
|
||||
if (!acpi_pcc_retrieve_biosdata(pcc, pcc->sinf)) {
|
||||
|
@ -651,7 +605,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
|||
&pcc_backlight_ops, &props);
|
||||
if (IS_ERR(pcc->backlight)) {
|
||||
result = PTR_ERR(pcc->backlight);
|
||||
goto out_sinf;
|
||||
goto out_input;
|
||||
}
|
||||
|
||||
/* read the initial brightness setting from the hardware */
|
||||
|
@ -669,12 +623,10 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
|
|||
|
||||
out_backlight:
|
||||
backlight_device_unregister(pcc->backlight);
|
||||
out_input:
|
||||
acpi_pcc_destroy_input(pcc);
|
||||
out_sinf:
|
||||
kfree(pcc->sinf);
|
||||
out_input:
|
||||
input_unregister_device(pcc->input_dev);
|
||||
/* no need to input_free_device() since core input API refcount and
|
||||
* free()s the device */
|
||||
out_hotkey:
|
||||
kfree(pcc);
|
||||
|
||||
|
@ -709,9 +661,7 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type)
|
|||
|
||||
backlight_device_unregister(pcc->backlight);
|
||||
|
||||
input_unregister_device(pcc->input_dev);
|
||||
/* no need to input_free_device() since core input API refcount and
|
||||
* free()s the device */
|
||||
acpi_pcc_destroy_input(pcc);
|
||||
|
||||
kfree(pcc->sinf);
|
||||
kfree(pcc);
|
||||
|
|
Загрузка…
Ссылка в новой задаче