aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/sparse-keymap.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-03-22 01:56:15 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-03-22 02:00:51 -0400
commit2e2e3b96d98d5c17e9c09bc6088df3e182a71814 (patch)
tree0ed49ca3ee60a9deb465d8aa4894365bd8d3030d /drivers/input/sparse-keymap.c
parent13bad37b04c779d98983307a27f97e9caa36f9b1 (diff)
Input: sparse-keymap - implement safer freeing of the keymap
Allow calling sparse_keymap_free() before unregistering input device whithout risk of racing with EVIOCGETKEYCODE and EVIOCSETKEYCODE. This makes life of drivers writers easier. Acked-by: Yong Wang <yong.y.wang@intel.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/sparse-keymap.c')
-rw-r--r--drivers/input/sparse-keymap.c50
1 files changed, 32 insertions, 18 deletions
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index f64e004935a9..2434ac5d43fe 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -67,12 +67,14 @@ static int sparse_keymap_getkeycode(struct input_dev *dev,
67 unsigned int scancode, 67 unsigned int scancode,
68 unsigned int *keycode) 68 unsigned int *keycode)
69{ 69{
70 const struct key_entry *key = 70 const struct key_entry *key;
71 sparse_keymap_entry_from_scancode(dev, scancode);
72 71
73 if (key && key->type == KE_KEY) { 72 if (dev->keycode) {
74 *keycode = key->keycode; 73 key = sparse_keymap_entry_from_scancode(dev, scancode);
75 return 0; 74 if (key && key->type == KE_KEY) {
75 *keycode = key->keycode;
76 return 0;
77 }
76 } 78 }
77 79
78 return -EINVAL; 80 return -EINVAL;
@@ -85,17 +87,16 @@ static int sparse_keymap_setkeycode(struct input_dev *dev,
85 struct key_entry *key; 87 struct key_entry *key;
86 int old_keycode; 88 int old_keycode;
87 89
88 if (keycode < 0 || keycode > KEY_MAX) 90 if (dev->keycode) {
89 return -EINVAL; 91 key = sparse_keymap_entry_from_scancode(dev, scancode);
90 92 if (key && key->type == KE_KEY) {
91 key = sparse_keymap_entry_from_scancode(dev, scancode); 93 old_keycode = key->keycode;
92 if (key && key->type == KE_KEY) { 94 key->keycode = keycode;
93 old_keycode = key->keycode; 95 set_bit(keycode, dev->keybit);
94 key->keycode = keycode; 96 if (!sparse_keymap_entry_from_keycode(dev, old_keycode))
95 set_bit(keycode, dev->keybit); 97 clear_bit(old_keycode, dev->keybit);
96 if (!sparse_keymap_entry_from_keycode(dev, old_keycode)) 98 return 0;
97 clear_bit(old_keycode, dev->keybit); 99 }
98 return 0;
99 } 100 }
100 101
101 return -EINVAL; 102 return -EINVAL;
@@ -175,14 +176,27 @@ EXPORT_SYMBOL(sparse_keymap_setup);
175 * 176 *
176 * This function is used to free memory allocated by sparse keymap 177 * This function is used to free memory allocated by sparse keymap
177 * in an input device that was set up by sparse_keymap_setup(). 178 * in an input device that was set up by sparse_keymap_setup().
179 * NOTE: It is safe to cal this function while input device is
180 * still registered (however the drivers should care not to try to
181 * use freed keymap and thus have to shut off interrups/polling
182 * before freeing the keymap).
178 */ 183 */
179void sparse_keymap_free(struct input_dev *dev) 184void sparse_keymap_free(struct input_dev *dev)
180{ 185{
186 unsigned long flags;
187
188 /*
189 * Take event lock to prevent racing with input_get_keycode()
190 * and input_set_keycode() if we are called while input device
191 * is still registered.
192 */
193 spin_lock_irqsave(&dev->event_lock, flags);
194
181 kfree(dev->keycode); 195 kfree(dev->keycode);
182 dev->keycode = NULL; 196 dev->keycode = NULL;
183 dev->keycodemax = 0; 197 dev->keycodemax = 0;
184 dev->getkeycode = NULL; 198
185 dev->setkeycode = NULL; 199 spin_unlock_irqrestore(&dev->event_lock, flags);
186} 200}
187EXPORT_SYMBOL(sparse_keymap_free); 201EXPORT_SYMBOL(sparse_keymap_free);
188 202