Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2e2e3b96 authored by Dmitry Torokhov's avatar Dmitry Torokhov
Browse files

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: default avatarYong Wang <yong.y.wang@intel.com>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 13bad37b
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -659,7 +659,14 @@ static int input_default_setkeycode(struct input_dev *dev,
int input_get_keycode(struct input_dev *dev,
		      unsigned int scancode, unsigned int *keycode)
{
	return dev->getkeycode(dev, scancode, keycode);
	unsigned long flags;
	int retval;

	spin_lock_irqsave(&dev->event_lock, flags);
	retval = dev->getkeycode(dev, scancode, keycode);
	spin_unlock_irqrestore(&dev->event_lock, flags);

	return retval;
}
EXPORT_SYMBOL(input_get_keycode);

+32 −18
Original line number Diff line number Diff line
@@ -67,13 +67,15 @@ 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 (dev->keycode) {
		key = sparse_keymap_entry_from_scancode(dev, scancode);
		if (key && key->type == KE_KEY) {
			*keycode = key->keycode;
			return 0;
		}
	}

	return -EINVAL;
}
@@ -85,9 +87,7 @@ static int sparse_keymap_setkeycode(struct input_dev *dev,
	struct key_entry *key;
	int old_keycode;

	if (keycode < 0 || keycode > KEY_MAX)
		return -EINVAL;

	if (dev->keycode) {
		key = sparse_keymap_entry_from_scancode(dev, scancode);
		if (key && key->type == KE_KEY) {
			old_keycode = key->keycode;
@@ -97,6 +97,7 @@ static int sparse_keymap_setkeycode(struct input_dev *dev,
				clear_bit(old_keycode, dev->keybit);
			return 0;
		}
	}

	return -EINVAL;
}
@@ -175,14 +176,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);