|
@@ -48,6 +48,7 @@
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/rfkill.h>
|
|
|
#include <linux/input.h>
|
|
|
+#include <linux/input/sparse-keymap.h>
|
|
|
#include <linux/leds.h>
|
|
|
#include <linux/slab.h>
|
|
|
|
|
@@ -121,36 +122,28 @@ static const struct acpi_device_id toshiba_device_ids[] = {
|
|
|
};
|
|
|
MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
|
|
|
|
|
|
-struct key_entry {
|
|
|
- char type;
|
|
|
- u16 code;
|
|
|
- u16 keycode;
|
|
|
-};
|
|
|
-
|
|
|
-enum {KE_KEY, KE_END};
|
|
|
-
|
|
|
-static struct key_entry toshiba_acpi_keymap[] = {
|
|
|
- {KE_KEY, 0x101, KEY_MUTE},
|
|
|
- {KE_KEY, 0x102, KEY_ZOOMOUT},
|
|
|
- {KE_KEY, 0x103, KEY_ZOOMIN},
|
|
|
- {KE_KEY, 0x13b, KEY_COFFEE},
|
|
|
- {KE_KEY, 0x13c, KEY_BATTERY},
|
|
|
- {KE_KEY, 0x13d, KEY_SLEEP},
|
|
|
- {KE_KEY, 0x13e, KEY_SUSPEND},
|
|
|
- {KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
|
|
|
- {KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
|
|
|
- {KE_KEY, 0x141, KEY_BRIGHTNESSUP},
|
|
|
- {KE_KEY, 0x142, KEY_WLAN},
|
|
|
- {KE_KEY, 0x143, KEY_PROG1},
|
|
|
- {KE_KEY, 0xb05, KEY_PROG2},
|
|
|
- {KE_KEY, 0xb06, KEY_WWW},
|
|
|
- {KE_KEY, 0xb07, KEY_MAIL},
|
|
|
- {KE_KEY, 0xb30, KEY_STOP},
|
|
|
- {KE_KEY, 0xb31, KEY_PREVIOUSSONG},
|
|
|
- {KE_KEY, 0xb32, KEY_NEXTSONG},
|
|
|
- {KE_KEY, 0xb33, KEY_PLAYPAUSE},
|
|
|
- {KE_KEY, 0xb5a, KEY_MEDIA},
|
|
|
- {KE_END, 0, 0},
|
|
|
+static const struct key_entry toshiba_acpi_keymap[] __initconst = {
|
|
|
+ { KE_KEY, 0x101, { KEY_MUTE } },
|
|
|
+ { KE_KEY, 0x102, { KEY_ZOOMOUT } },
|
|
|
+ { KE_KEY, 0x103, { KEY_ZOOMIN } },
|
|
|
+ { KE_KEY, 0x13b, { KEY_COFFEE } },
|
|
|
+ { KE_KEY, 0x13c, { KEY_BATTERY } },
|
|
|
+ { KE_KEY, 0x13d, { KEY_SLEEP } },
|
|
|
+ { KE_KEY, 0x13e, { KEY_SUSPEND } },
|
|
|
+ { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
|
|
|
+ { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
|
|
|
+ { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
|
|
|
+ { KE_KEY, 0x142, { KEY_WLAN } },
|
|
|
+ { KE_KEY, 0x143, { KEY_PROG1 } },
|
|
|
+ { KE_KEY, 0xb05, { KEY_PROG2 } },
|
|
|
+ { KE_KEY, 0xb06, { KEY_WWW } },
|
|
|
+ { KE_KEY, 0xb07, { KEY_MAIL } },
|
|
|
+ { KE_KEY, 0xb30, { KEY_STOP } },
|
|
|
+ { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
|
|
|
+ { KE_KEY, 0xb32, { KEY_NEXTSONG } },
|
|
|
+ { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
|
|
|
+ { KE_KEY, 0xb5a, { KEY_MEDIA } },
|
|
|
+ { KE_END, 0 },
|
|
|
};
|
|
|
|
|
|
/* utility
|
|
@@ -852,64 +845,9 @@ static struct backlight_ops toshiba_backlight_data = {
|
|
|
.update_status = set_lcd_status,
|
|
|
};
|
|
|
|
|
|
-static struct key_entry *toshiba_acpi_get_entry_by_scancode(unsigned int code)
|
|
|
-{
|
|
|
- struct key_entry *key;
|
|
|
-
|
|
|
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
|
|
|
- if (code == key->code)
|
|
|
- return key;
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-static struct key_entry *toshiba_acpi_get_entry_by_keycode(unsigned int code)
|
|
|
-{
|
|
|
- struct key_entry *key;
|
|
|
-
|
|
|
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
|
|
|
- if (code == key->keycode && key->type == KE_KEY)
|
|
|
- return key;
|
|
|
-
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-static int toshiba_acpi_getkeycode(struct input_dev *dev,
|
|
|
- unsigned int scancode, unsigned int *keycode)
|
|
|
-{
|
|
|
- struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
|
|
|
-
|
|
|
- if (key && key->type == KE_KEY) {
|
|
|
- *keycode = key->keycode;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
-static int toshiba_acpi_setkeycode(struct input_dev *dev,
|
|
|
- unsigned int scancode, unsigned int keycode)
|
|
|
-{
|
|
|
- struct key_entry *key;
|
|
|
- unsigned int old_keycode;
|
|
|
-
|
|
|
- key = toshiba_acpi_get_entry_by_scancode(scancode);
|
|
|
- if (key && key->type == KE_KEY) {
|
|
|
- old_keycode = key->keycode;
|
|
|
- key->keycode = keycode;
|
|
|
- set_bit(keycode, dev->keybit);
|
|
|
- if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
|
|
|
- clear_bit(old_keycode, dev->keybit);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
|
|
|
{
|
|
|
u32 hci_result, value;
|
|
|
- struct key_entry *key;
|
|
|
|
|
|
if (event != 0x80)
|
|
|
return;
|
|
@@ -922,19 +860,11 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
|
|
|
if (value & 0x80)
|
|
|
continue;
|
|
|
|
|
|
- key = toshiba_acpi_get_entry_by_scancode
|
|
|
- (value);
|
|
|
- if (!key) {
|
|
|
+ if (!sparse_keymap_report_event(toshiba_acpi.hotkey_dev,
|
|
|
+ value, 1, true)) {
|
|
|
printk(MY_INFO "Unknown key %x\n",
|
|
|
value);
|
|
|
- continue;
|
|
|
}
|
|
|
- input_report_key(toshiba_acpi.hotkey_dev,
|
|
|
- key->keycode, 1);
|
|
|
- input_sync(toshiba_acpi.hotkey_dev);
|
|
|
- input_report_key(toshiba_acpi.hotkey_dev,
|
|
|
- key->keycode, 0);
|
|
|
- input_sync(toshiba_acpi.hotkey_dev);
|
|
|
} else if (hci_result == HCI_NOT_SUPPORTED) {
|
|
|
/* This is a workaround for an unresolved issue on
|
|
|
* some machines where system events sporadically
|
|
@@ -945,34 +875,17 @@ static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
|
|
|
} while (hci_result != HCI_EMPTY);
|
|
|
}
|
|
|
|
|
|
-static int toshiba_acpi_setup_keyboard(char *device)
|
|
|
+static int __init toshiba_acpi_setup_keyboard(char *device)
|
|
|
{
|
|
|
acpi_status status;
|
|
|
- acpi_handle handle;
|
|
|
- int result;
|
|
|
- const struct key_entry *key;
|
|
|
+ int error;
|
|
|
|
|
|
- status = acpi_get_handle(NULL, device, &handle);
|
|
|
+ status = acpi_get_handle(NULL, device, &toshiba_acpi.handle);
|
|
|
if (ACPI_FAILURE(status)) {
|
|
|
printk(MY_INFO "Unable to get notification device\n");
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
- toshiba_acpi.handle = handle;
|
|
|
-
|
|
|
- status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
|
|
|
- if (ACPI_FAILURE(status)) {
|
|
|
- printk(MY_INFO "Unable to enable hotkeys\n");
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
-
|
|
|
- status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
|
|
|
- toshiba_acpi_notify, NULL);
|
|
|
- if (ACPI_FAILURE(status)) {
|
|
|
- printk(MY_INFO "Unable to install hotkey notification\n");
|
|
|
- return -ENODEV;
|
|
|
- }
|
|
|
-
|
|
|
toshiba_acpi.hotkey_dev = input_allocate_device();
|
|
|
if (!toshiba_acpi.hotkey_dev) {
|
|
|
printk(MY_INFO "Unable to register input device\n");
|
|
@@ -982,27 +895,54 @@ static int toshiba_acpi_setup_keyboard(char *device)
|
|
|
toshiba_acpi.hotkey_dev->name = "Toshiba input device";
|
|
|
toshiba_acpi.hotkey_dev->phys = device;
|
|
|
toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
|
|
|
- toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
|
|
|
- toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
|
|
|
|
|
|
- for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
|
|
|
- set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
|
|
|
- set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
|
|
|
+ error = sparse_keymap_setup(toshiba_acpi.hotkey_dev,
|
|
|
+ toshiba_acpi_keymap, NULL);
|
|
|
+ if (error)
|
|
|
+ goto err_free_dev;
|
|
|
+
|
|
|
+ status = acpi_install_notify_handler(toshiba_acpi.handle,
|
|
|
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify, NULL);
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
+ printk(MY_INFO "Unable to install hotkey notification\n");
|
|
|
+ error = -ENODEV;
|
|
|
+ goto err_free_keymap;
|
|
|
+ }
|
|
|
+
|
|
|
+ status = acpi_evaluate_object(toshiba_acpi.handle, "ENAB", NULL, NULL);
|
|
|
+ if (ACPI_FAILURE(status)) {
|
|
|
+ printk(MY_INFO "Unable to enable hotkeys\n");
|
|
|
+ error = -ENODEV;
|
|
|
+ goto err_remove_notify;
|
|
|
}
|
|
|
|
|
|
- result = input_register_device(toshiba_acpi.hotkey_dev);
|
|
|
- if (result) {
|
|
|
+ error = input_register_device(toshiba_acpi.hotkey_dev);
|
|
|
+ if (error) {
|
|
|
printk(MY_INFO "Unable to register input device\n");
|
|
|
- return result;
|
|
|
+ goto err_remove_notify;
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+ err_remove_notify:
|
|
|
+ acpi_remove_notify_handler(toshiba_acpi.handle,
|
|
|
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
|
|
|
+ err_free_keymap:
|
|
|
+ sparse_keymap_free(toshiba_acpi.hotkey_dev);
|
|
|
+ err_free_dev:
|
|
|
+ input_free_device(toshiba_acpi.hotkey_dev);
|
|
|
+ toshiba_acpi.hotkey_dev = NULL;
|
|
|
+ return error;
|
|
|
}
|
|
|
|
|
|
static void toshiba_acpi_exit(void)
|
|
|
{
|
|
|
- if (toshiba_acpi.hotkey_dev)
|
|
|
+ if (toshiba_acpi.hotkey_dev) {
|
|
|
+ acpi_remove_notify_handler(toshiba_acpi.handle,
|
|
|
+ ACPI_DEVICE_NOTIFY, toshiba_acpi_notify);
|
|
|
+ sparse_keymap_free(toshiba_acpi.hotkey_dev);
|
|
|
input_unregister_device(toshiba_acpi.hotkey_dev);
|
|
|
+ }
|
|
|
|
|
|
if (toshiba_acpi.bt_rfk) {
|
|
|
rfkill_unregister(toshiba_acpi.bt_rfk);
|
|
@@ -1017,9 +957,6 @@ static void toshiba_acpi_exit(void)
|
|
|
if (toshiba_proc_dir)
|
|
|
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
|
|
|
|
|
|
- acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
|
|
|
- toshiba_acpi_notify);
|
|
|
-
|
|
|
if (toshiba_acpi.illumination_installed)
|
|
|
led_classdev_unregister(&toshiba_led);
|
|
|
|