summaryrefslogtreecommitdiffstats
path: root/drivers/input/sparse-keymap.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2010-05-10 11:59:37 +0200
committerThomas Gleixner <tglx@linutronix.de>2010-05-10 14:20:42 +0200
commitdbb6be6d5e974c42bbecd183effaa0df69e1dd8b (patch)
tree5735cb47e70853d057a9881dd0ce44b83e88fa63 /drivers/input/sparse-keymap.c
parent6a867a395558a7f882d041783e4cdea6744ca2bf (diff)
parentb57f95a38233a2e73b679bea4a5453a1cc2a1cc9 (diff)
Merge branch 'linus' into timers/core
Reason: Further posix_cpu_timer patches depend on mainline changes Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/input/sparse-keymap.c')
-rw-r--r--drivers/input/sparse-keymap.c53
1 files changed, 34 insertions, 19 deletions
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index e6bde55e520..01424834476 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -15,6 +15,7 @@
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
+#include <linux/slab.h>
MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("Generic support for sparse keymaps");
@@ -67,12 +68,14 @@ static int sparse_keymap_getkeycode(struct input_dev *dev,
unsigned int scancode,
unsigned int *keycode)
{
- const struct key_entry *key =
- sparse_keymap_entry_from_scancode(dev, scancode);
+ const struct key_entry *key;
- if (key && key->type == KE_KEY) {
- *keycode = key->keycode;
- return 0;
+ if (dev->keycode) {
+ key = sparse_keymap_entry_from_scancode(dev, scancode);
+ if (key && key->type == KE_KEY) {
+ *keycode = key->keycode;
+ return 0;
+ }
}
return -EINVAL;
@@ -85,17 +88,16 @@ static int sparse_keymap_setkeycode(struct input_dev *dev,
struct key_entry *key;
int old_keycode;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
-
- key = sparse_keymap_entry_from_scancode(dev, scancode);
- if (key && key->type == KE_KEY) {
- old_keycode = key->keycode;
- key->keycode = keycode;
- set_bit(keycode, dev->keybit);
- if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
- clear_bit(old_keycode, dev->keybit);
- return 0;
+ if (dev->keycode) {
+ key = sparse_keymap_entry_from_scancode(dev, scancode);
+ if (key && key->type == KE_KEY) {
+ old_keycode = key->keycode;
+ key->keycode = keycode;
+ set_bit(keycode, dev->keybit);
+ if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
+ clear_bit(old_keycode, dev->keybit);
+ return 0;
+ }
}
return -EINVAL;
@@ -163,7 +165,7 @@ int sparse_keymap_setup(struct input_dev *dev,
return 0;
err_out:
- kfree(keymap);
+ kfree(map);
return error;
}
@@ -175,14 +177,27 @@ EXPORT_SYMBOL(sparse_keymap_setup);
*
* This function is used to free memory allocated by sparse keymap
* in an input device that was set up by sparse_keymap_setup().
+ * NOTE: It is safe to cal this function while input device is
+ * still registered (however the drivers should care not to try to
+ * use freed keymap and thus have to shut off interrups/polling
+ * before freeing the keymap).
*/
void sparse_keymap_free(struct input_dev *dev)
{
+ unsigned long flags;
+
+ /*
+ * Take event lock to prevent racing with input_get_keycode()
+ * and input_set_keycode() if we are called while input device
+ * is still registered.
+ */
+ spin_lock_irqsave(&dev->event_lock, flags);
+
kfree(dev->keycode);
dev->keycode = NULL;
dev->keycodemax = 0;
- dev->getkeycode = NULL;
- dev->setkeycode = NULL;
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
}
EXPORT_SYMBOL(sparse_keymap_free);