summaryrefslogtreecommitdiff
path: root/drivers/input/input.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/input.c')
-rw-r--r--drivers/input/input.c725
1 files changed, 409 insertions, 316 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 711485437567..ec4346f20efd 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -96,48 +96,16 @@ static void input_start_autorepeat(struct input_dev *dev, int code)
static void input_stop_autorepeat(struct input_dev *dev)
{
- del_timer(&dev->timer);
-}
-
-/*
- * Pass event first through all filters and then, if event has not been
- * filtered out, through all open handles. This function is called with
- * dev->event_lock held and interrupts disabled.
- */
-static unsigned int input_to_handler(struct input_handle *handle,
- struct input_value *vals, unsigned int count)
-{
- struct input_handler *handler = handle->handler;
- struct input_value *end = vals;
- struct input_value *v;
-
- if (handler->filter) {
- for (v = vals; v != vals + count; v++) {
- if (handler->filter(handle, v->type, v->code, v->value))
- continue;
- if (end != v)
- *end = *v;
- end++;
- }
- count = end - vals;
- }
-
- if (!count)
- return 0;
-
- if (handler->events)
- handler->events(handle, vals, count);
- else if (handler->event)
- for (v = vals; v != vals + count; v++)
- handler->event(handle, v->type, v->code, v->value);
-
- return count;
+ timer_delete(&dev->timer);
}
/*
* Pass values first through all filters and then, if event has not been
- * filtered out, through all open handles. This function is called with
- * dev->event_lock held and interrupts disabled.
+ * filtered out, through all open handles. This order is achieved by placing
+ * filters at the head of the list of handles attached to the device, and
+ * placing regular handles at the tail of the list.
+ *
+ * This function is called with dev->event_lock held and interrupts disabled.
*/
static void input_pass_values(struct input_dev *dev,
struct input_value *vals, unsigned int count)
@@ -147,25 +115,23 @@ static void input_pass_values(struct input_dev *dev,
lockdep_assert_held(&dev->event_lock);
- if (!count)
- return;
-
- rcu_read_lock();
+ scoped_guard(rcu) {
+ handle = rcu_dereference(dev->grab);
+ if (handle) {
+ count = handle->handle_events(handle, vals, count);
+ break;
+ }
- handle = rcu_dereference(dev->grab);
- if (handle) {
- count = input_to_handler(handle, vals, count);
- } else {
- list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+ list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
if (handle->open) {
- count = input_to_handler(handle, vals, count);
+ count = handle->handle_events(handle, vals,
+ count);
if (!count)
break;
}
+ }
}
- rcu_read_unlock();
-
/* trigger auto repeat for key events */
if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
for (v = vals; v != vals + count; v++) {
@@ -354,9 +320,6 @@ static void input_event_dispose(struct input_dev *dev, int disposition,
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
- if (!dev->vals)
- return;
-
if (disposition & INPUT_PASS_TO_HANDLERS) {
struct input_value *v;
@@ -427,13 +390,9 @@ void input_handle_event(struct input_dev *dev,
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
- unsigned long flags;
-
if (is_event_supported(type, dev->evbit, EV_MAX)) {
-
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
input_handle_event(dev, type, code, value);
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_event);
@@ -454,18 +413,15 @@ void input_inject_event(struct input_handle *handle,
{
struct input_dev *dev = handle->dev;
struct input_handle *grab;
- unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX)) {
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
+ guard(rcu)();
- rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
input_handle_event(dev, type, code, value);
- rcu_read_unlock();
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_inject_event);
@@ -563,22 +519,15 @@ EXPORT_SYMBOL(input_copy_abs);
int input_grab_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- int retval;
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ if (dev->grab)
+ return -EBUSY;
- if (dev->grab) {
- retval = -EBUSY;
- goto out;
+ rcu_assign_pointer(dev->grab, handle);
}
- rcu_assign_pointer(dev->grab, handle);
-
- out:
- mutex_unlock(&dev->mutex);
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_grab_device);
@@ -613,9 +562,8 @@ void input_release_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
__input_release_device(handle);
- mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_release_device);
@@ -629,64 +577,57 @@ EXPORT_SYMBOL(input_release_device);
int input_open_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- int retval;
-
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
+ int error;
- if (dev->going_away) {
- retval = -ENODEV;
- goto out;
- }
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ if (dev->going_away)
+ return -ENODEV;
- handle->open++;
+ handle->open++;
- if (dev->users++ || dev->inhibited) {
- /*
- * Device is already opened and/or inhibited,
- * so we can exit immediately and report success.
- */
- goto out;
- }
+ if (handle->handler->passive_observer)
+ return 0;
- if (dev->open) {
- retval = dev->open(dev);
- if (retval) {
- dev->users--;
- handle->open--;
+ if (dev->users++ || dev->inhibited) {
/*
- * Make sure we are not delivering any more events
- * through this handle
+ * Device is already opened and/or inhibited,
+ * so we can exit immediately and report success.
*/
- synchronize_rcu();
- goto out;
+ return 0;
}
- }
- if (dev->poller)
- input_dev_poller_start(dev->poller);
+ if (dev->open) {
+ error = dev->open(dev);
+ if (error) {
+ dev->users--;
+ handle->open--;
+ /*
+ * Make sure we are not delivering any more
+ * events through this handle.
+ */
+ synchronize_rcu();
+ return error;
+ }
+ }
- out:
- mutex_unlock(&dev->mutex);
- return retval;
+ if (dev->poller)
+ input_dev_poller_start(dev->poller);
+ }
+
+ return 0;
}
EXPORT_SYMBOL(input_open_device);
int input_flush_device(struct input_handle *handle, struct file *file)
{
struct input_dev *dev = handle->dev;
- int retval;
-
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
- if (dev->flush)
- retval = dev->flush(dev, file);
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ if (dev->flush)
+ return dev->flush(dev, file);
+ }
- mutex_unlock(&dev->mutex);
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_flush_device);
@@ -701,15 +642,17 @@ void input_close_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
__input_release_device(handle);
- if (!--dev->users && !dev->inhibited) {
- if (dev->poller)
- input_dev_poller_stop(dev->poller);
- if (dev->close)
- dev->close(dev);
+ if (!handle->handler->passive_observer) {
+ if (!--dev->users && !dev->inhibited) {
+ if (dev->poller)
+ input_dev_poller_stop(dev->poller);
+ if (dev->close)
+ dev->close(dev);
+ }
}
if (!--handle->open) {
@@ -720,8 +663,6 @@ void input_close_device(struct input_handle *handle)
*/
synchronize_rcu();
}
-
- mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_close_device);
@@ -758,11 +699,10 @@ static void input_disconnect_device(struct input_dev *dev)
* not to protect access to dev->going_away but rather to ensure
* that there are no threads in the middle of input_open_device()
*/
- mutex_lock(&dev->mutex);
- dev->going_away = true;
- mutex_unlock(&dev->mutex);
+ scoped_guard(mutex, &dev->mutex)
+ dev->going_away = true;
- spin_lock_irq(&dev->event_lock);
+ guard(spinlock_irq)(&dev->event_lock);
/*
* Simulate keyup events for all pressed keys so that handlers
@@ -775,8 +715,6 @@ static void input_disconnect_device(struct input_dev *dev)
list_for_each_entry(handle, &dev->h_list, d_node)
handle->open = 0;
-
- spin_unlock_irq(&dev->event_lock);
}
/**
@@ -933,14 +871,9 @@ static int input_default_setkeycode(struct input_dev *dev,
*/
int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
{
- unsigned long flags;
- int retval;
-
- spin_lock_irqsave(&dev->event_lock, flags);
- retval = dev->getkeycode(dev, ke);
- spin_unlock_irqrestore(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
- return retval;
+ return dev->getkeycode(dev, ke);
}
EXPORT_SYMBOL(input_get_keycode);
@@ -955,18 +888,17 @@ EXPORT_SYMBOL(input_get_keycode);
int input_set_keycode(struct input_dev *dev,
const struct input_keymap_entry *ke)
{
- unsigned long flags;
unsigned int old_keycode;
- int retval;
+ int error;
if (ke->keycode > KEY_MAX)
return -EINVAL;
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
- retval = dev->setkeycode(dev, ke, &old_keycode);
- if (retval)
- goto out;
+ error = dev->setkeycode(dev, ke, &old_keycode);
+ if (error)
+ return error;
/* Make sure KEY_RESERVED did not get enabled. */
__clear_bit(KEY_RESERVED, dev->keybit);
@@ -994,10 +926,7 @@ int input_set_keycode(struct input_dev *dev,
EV_SYN, SYN_REPORT, 1);
}
- out:
- spin_unlock_irqrestore(&dev->event_lock, flags);
-
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_set_keycode);
@@ -1116,33 +1045,31 @@ static inline void input_wakeup_procfs_readers(void)
wake_up(&input_devices_poll_wait);
}
+struct input_seq_state {
+ unsigned short pos;
+ bool mutex_acquired;
+ int input_devices_state;
+};
+
static __poll_t input_proc_devices_poll(struct file *file, poll_table *wait)
{
+ struct seq_file *seq = file->private_data;
+ struct input_seq_state *state = seq->private;
+
poll_wait(file, &input_devices_poll_wait, wait);
- if (file->f_version != input_devices_state) {
- file->f_version = input_devices_state;
+ if (state->input_devices_state != input_devices_state) {
+ state->input_devices_state = input_devices_state;
return EPOLLIN | EPOLLRDNORM;
}
return 0;
}
-union input_seq_state {
- struct {
- unsigned short pos;
- bool mutex_acquired;
- };
- void *p;
-};
-
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
int error;
- /* We need to fit into seq->private pointer */
- BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
-
error = mutex_lock_interruptible(&input_mutex);
if (error) {
state->mutex_acquired = false;
@@ -1161,7 +1088,7 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void input_seq_stop(struct seq_file *seq, void *v)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
if (state->mutex_acquired)
mutex_unlock(&input_mutex);
@@ -1247,7 +1174,8 @@ static const struct seq_operations input_devices_seq_ops = {
static int input_proc_devices_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &input_devices_seq_ops);
+ return seq_open_private(file, &input_devices_seq_ops,
+ sizeof(struct input_seq_state));
}
static const struct proc_ops input_devices_proc_ops = {
@@ -1255,17 +1183,14 @@ static const struct proc_ops input_devices_proc_ops = {
.proc_poll = input_proc_devices_poll,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
- .proc_release = seq_release,
+ .proc_release = seq_release_private,
};
static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
int error;
- /* We need to fit into seq->private pointer */
- BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
-
error = mutex_lock_interruptible(&input_mutex);
if (error) {
state->mutex_acquired = false;
@@ -1280,7 +1205,7 @@ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
state->pos = *pos + 1;
return seq_list_next(v, &input_handler_list, pos);
@@ -1289,7 +1214,7 @@ static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static int input_handlers_seq_show(struct seq_file *seq, void *v)
{
struct input_handler *handler = container_of(v, struct input_handler, node);
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
if (handler->filter)
@@ -1310,14 +1235,15 @@ static const struct seq_operations input_handlers_seq_ops = {
static int input_proc_handlers_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &input_handlers_seq_ops);
+ return seq_open_private(file, &input_handlers_seq_ops,
+ sizeof(struct input_seq_state));
}
static const struct proc_ops input_handlers_proc_ops = {
.proc_open = input_proc_handlers_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
- .proc_release = seq_release,
+ .proc_release = seq_release_private,
};
static int __init input_proc_init(void)
@@ -1378,19 +1304,19 @@ static int input_print_modalias_bits(char *buf, int size,
char name, const unsigned long *bm,
unsigned int min_bit, unsigned int max_bit)
{
- int len = 0, i;
+ int bit = min_bit;
+ int len = 0;
len += snprintf(buf, max(size, 0), "%c", name);
- for (i = min_bit; i < max_bit; i++)
- if (bm[BIT_WORD(i)] & BIT_MASK(i))
- len += snprintf(buf + len, max(size - len, 0), "%X,", i);
+ for_each_set_bit_from(bit, bm, max_bit)
+ len += snprintf(buf + len, max(size - len, 0), "%X,", bit);
return len;
}
-static int input_print_modalias(char *buf, int size, const struct input_dev *id,
- int add_cr)
+static int input_print_modalias_parts(char *buf, int size, int full_len,
+ const struct input_dev *id)
{
- int len;
+ int len, klen, remainder, space;
len = snprintf(buf, max(size, 0),
"input:b%04Xv%04Xp%04Xe%04X-",
@@ -1399,8 +1325,48 @@ static int input_print_modalias(char *buf, int size, const struct input_dev *id,
len += input_print_modalias_bits(buf + len, size - len,
'e', id->evbit, 0, EV_MAX);
- len += input_print_modalias_bits(buf + len, size - len,
+
+ /*
+ * Calculate the remaining space in the buffer making sure we
+ * have place for the terminating 0.
+ */
+ space = max(size - (len + 1), 0);
+
+ klen = input_print_modalias_bits(buf + len, size - len,
'k', id->keybit, KEY_MIN_INTERESTING, KEY_MAX);
+ len += klen;
+
+ /*
+ * If we have more data than we can fit in the buffer, check
+ * if we can trim key data to fit in the rest. We will indicate
+ * that key data is incomplete by adding "+" sign at the end, like
+ * this: * "k1,2,3,45,+,".
+ *
+ * Note that we shortest key info (if present) is "k+," so we
+ * can only try to trim if key data is longer than that.
+ */
+ if (full_len && size < full_len + 1 && klen > 3) {
+ remainder = full_len - len;
+ /*
+ * We can only trim if we have space for the remainder
+ * and also for at least "k+," which is 3 more characters.
+ */
+ if (remainder <= space - 3) {
+ /*
+ * We are guaranteed to have 'k' in the buffer, so
+ * we need at least 3 additional bytes for storing
+ * "+," in addition to the remainder.
+ */
+ for (int i = size - 1 - remainder - 3; i >= 0; i--) {
+ if (buf[i] == 'k' || buf[i] == ',') {
+ strcpy(buf + i + 1, "+,");
+ len = i + 3; /* Not counting '\0' */
+ break;
+ }
+ }
+ }
+ }
+
len += input_print_modalias_bits(buf + len, size - len,
'r', id->relbit, 0, REL_MAX);
len += input_print_modalias_bits(buf + len, size - len,
@@ -1416,12 +1382,25 @@ static int input_print_modalias(char *buf, int size, const struct input_dev *id,
len += input_print_modalias_bits(buf + len, size - len,
'w', id->swbit, 0, SW_MAX);
- if (add_cr)
- len += snprintf(buf + len, max(size - len, 0), "\n");
-
return len;
}
+static int input_print_modalias(char *buf, int size, const struct input_dev *id)
+{
+ int full_len;
+
+ /*
+ * Printing is done in 2 passes: first one figures out total length
+ * needed for the modalias string, second one will try to trim key
+ * data in case when buffer is too small for the entire modalias.
+ * If the buffer is too small regardless, it will fill as much as it
+ * can (without trimming key data) into the buffer and leave it to
+ * the caller to figure out what to do with the result.
+ */
+ full_len = input_print_modalias_parts(NULL, 0, 0, id);
+ return input_print_modalias_parts(buf, size, full_len, id);
+}
+
static ssize_t input_dev_show_modalias(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1429,7 +1408,9 @@ static ssize_t input_dev_show_modalias(struct device *dev,
struct input_dev *id = to_input_dev(dev);
ssize_t len;
- len = input_print_modalias(buf, PAGE_SIZE, id, 1);
+ len = input_print_modalias(buf, PAGE_SIZE, id);
+ if (len < PAGE_SIZE - 2)
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
return min_t(int, len, PAGE_SIZE);
}
@@ -1641,6 +1622,23 @@ static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
return 0;
}
+/*
+ * This is a pretty gross hack. When building uevent data the driver core
+ * may try adding more environment variables to kobj_uevent_env without
+ * telling us, so we have no idea how much of the buffer we can use to
+ * avoid overflows/-ENOMEM elsewhere. To work around this let's artificially
+ * reduce amount of memory we will use for the modalias environment variable.
+ *
+ * The potential additions are:
+ *
+ * SEQNUM=18446744073709551615 - (%llu - 28 bytes)
+ * HOME=/ (6 bytes)
+ * PATH=/sbin:/bin:/usr/sbin:/usr/bin (34 bytes)
+ *
+ * 68 bytes total. Allow extra buffer - 96 bytes
+ */
+#define UEVENT_ENV_EXTRA_LEN 96
+
static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
const struct input_dev *dev)
{
@@ -1650,9 +1648,11 @@ static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
return -ENOMEM;
len = input_print_modalias(&env->buf[env->buflen - 1],
- sizeof(env->buf) - env->buflen,
- dev, 0);
- if (len >= (sizeof(env->buf) - env->buflen))
+ (int)sizeof(env->buf) - env->buflen -
+ UEVENT_ENV_EXTRA_LEN,
+ dev);
+ if (len >= ((int)sizeof(env->buf) - env->buflen -
+ UEVENT_ENV_EXTRA_LEN))
return -ENOMEM;
env->buflen += len;
@@ -1760,26 +1760,21 @@ static void input_dev_toggle(struct input_dev *dev, bool activate)
*/
void input_reset_device(struct input_dev *dev)
{
- unsigned long flags;
-
- mutex_lock(&dev->mutex);
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(mutex)(&dev->mutex);
+ guard(spinlock_irqsave)(&dev->event_lock);
input_dev_toggle(dev, true);
if (input_dev_release_keys(dev))
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
- mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_reset_device);
static int input_inhibit_device(struct input_dev *dev)
{
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
if (dev->inhibited)
- goto out;
+ return 0;
if (dev->users) {
if (dev->close)
@@ -1788,54 +1783,50 @@ static int input_inhibit_device(struct input_dev *dev)
input_dev_poller_stop(dev->poller);
}
- spin_lock_irq(&dev->event_lock);
- input_mt_release_slots(dev);
- input_dev_release_keys(dev);
- input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
- input_dev_toggle(dev, false);
- spin_unlock_irq(&dev->event_lock);
+ scoped_guard(spinlock_irq, &dev->event_lock) {
+ input_mt_release_slots(dev);
+ input_dev_release_keys(dev);
+ input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
+ input_dev_toggle(dev, false);
+ }
dev->inhibited = true;
-out:
- mutex_unlock(&dev->mutex);
return 0;
}
static int input_uninhibit_device(struct input_dev *dev)
{
- int ret = 0;
+ int error;
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
if (!dev->inhibited)
- goto out;
+ return 0;
if (dev->users) {
if (dev->open) {
- ret = dev->open(dev);
- if (ret)
- goto out;
+ error = dev->open(dev);
+ if (error)
+ return error;
}
if (dev->poller)
input_dev_poller_start(dev->poller);
}
dev->inhibited = false;
- spin_lock_irq(&dev->event_lock);
- input_dev_toggle(dev, true);
- spin_unlock_irq(&dev->event_lock);
-out:
- mutex_unlock(&dev->mutex);
- return ret;
+ scoped_guard(spinlock_irq, &dev->event_lock)
+ input_dev_toggle(dev, true);
+
+ return 0;
}
static int input_dev_suspend(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/*
* Keys that are pressed now are unlikely to be
@@ -1847,8 +1838,6 @@ static int input_dev_suspend(struct device *dev)
/* Turn off LEDs and sounds, if any are active. */
input_dev_toggle(input_dev, false);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -1856,13 +1845,11 @@ static int input_dev_resume(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/* Restore state of LEDs and sounds, if any were active. */
input_dev_toggle(input_dev, true);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -1870,7 +1857,7 @@ static int input_dev_freeze(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/*
* Keys that are pressed now are unlikely to be
@@ -1879,8 +1866,6 @@ static int input_dev_freeze(struct device *dev)
if (input_dev_release_keys(input_dev))
input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -1888,13 +1873,11 @@ static int input_dev_poweroff(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/* Turn off LEDs and sounds, if any are active. */
input_dev_toggle(input_dev, false);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -1939,22 +1922,41 @@ struct input_dev *input_allocate_device(void)
struct input_dev *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev) {
- dev->dev.type = &input_dev_type;
- dev->dev.class = &input_class;
- device_initialize(&dev->dev);
- mutex_init(&dev->mutex);
- spin_lock_init(&dev->event_lock);
- timer_setup(&dev->timer, NULL, 0);
- INIT_LIST_HEAD(&dev->h_list);
- INIT_LIST_HEAD(&dev->node);
-
- dev_set_name(&dev->dev, "input%lu",
- (unsigned long)atomic_inc_return(&input_no));
+ if (!dev)
+ return NULL;
- __module_get(THIS_MODULE);
+ /*
+ * Start with space for SYN_REPORT + 7 EV_KEY/EV_MSC events + 2 spare,
+ * see input_estimate_events_per_packet(). We will tune the number
+ * when we register the device.
+ */
+ dev->max_vals = 10;
+ dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
+ if (!dev->vals) {
+ kfree(dev);
+ return NULL;
}
+ mutex_init(&dev->mutex);
+ spin_lock_init(&dev->event_lock);
+ timer_setup(&dev->timer, NULL, 0);
+ INIT_LIST_HEAD(&dev->h_list);
+ INIT_LIST_HEAD(&dev->node);
+
+ dev->dev.type = &input_dev_type;
+ dev->dev.class = &input_class;
+ device_initialize(&dev->dev);
+ /*
+ * From this point on we can no longer simply "kfree(dev)", we need
+ * to use input_free_device() so that device core properly frees its
+ * resources associated with the input device.
+ */
+
+ dev_set_name(&dev->dev, "input%lu",
+ (unsigned long)atomic_inc_return(&input_no));
+
+ __module_get(THIS_MODULE);
+
return dev;
}
EXPORT_SYMBOL(input_allocate_device);
@@ -2168,7 +2170,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
mt_slots = dev->mt->num_slots;
} else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
- dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
+ dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1;
mt_slots = clamp(mt_slots, 2, 32);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
mt_slots = 2;
@@ -2216,18 +2218,16 @@ static void __input_unregister_device(struct input_dev *dev)
input_disconnect_device(dev);
- mutex_lock(&input_mutex);
+ scoped_guard(mutex, &input_mutex) {
+ list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
+ handle->handler->disconnect(handle);
+ WARN_ON(!list_empty(&dev->h_list));
- list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
- handle->handler->disconnect(handle);
- WARN_ON(!list_empty(&dev->h_list));
+ timer_delete_sync(&dev->timer);
+ list_del_init(&dev->node);
- del_timer_sync(&dev->timer);
- list_del_init(&dev->node);
-
- input_wakeup_procfs_readers();
-
- mutex_unlock(&input_mutex);
+ input_wakeup_procfs_readers();
+ }
device_del(&dev->dev);
}
@@ -2250,9 +2250,8 @@ static void devm_input_device_unregister(struct device *dev, void *res)
static void input_repeat_key(struct timer_list *t)
{
struct input_dev *dev = from_timer(dev, t, timer);
- unsigned long flags;
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
if (!dev->inhibited &&
test_bit(dev->repeat_key, dev->key) &&
@@ -2266,8 +2265,6 @@ static void input_repeat_key(struct timer_list *t)
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
/**
@@ -2294,6 +2291,35 @@ bool input_device_enabled(struct input_dev *dev)
}
EXPORT_SYMBOL_GPL(input_device_enabled);
+static int input_device_tune_vals(struct input_dev *dev)
+{
+ struct input_value *vals;
+ unsigned int packet_size;
+ unsigned int max_vals;
+
+ packet_size = input_estimate_events_per_packet(dev);
+ if (dev->hint_events_per_packet < packet_size)
+ dev->hint_events_per_packet = packet_size;
+
+ max_vals = dev->hint_events_per_packet + 2;
+ if (dev->max_vals >= max_vals)
+ return 0;
+
+ vals = kcalloc(max_vals, sizeof(*vals), GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ scoped_guard(spinlock_irq, &dev->event_lock) {
+ dev->max_vals = max_vals;
+ swap(dev->vals, vals);
+ }
+
+ /* Because of swap() above, this frees the old vals memory */
+ kfree(vals);
+
+ return 0;
+}
+
/**
* input_register_device - register device with input core
* @dev: device to be registered
@@ -2321,7 +2347,6 @@ int input_register_device(struct input_dev *dev)
{
struct input_devres *devres = NULL;
struct input_handler *handler;
- unsigned int packet_size;
const char *path;
int error;
@@ -2349,16 +2374,9 @@ int input_register_device(struct input_dev *dev)
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);
- packet_size = input_estimate_events_per_packet(dev);
- if (dev->hint_events_per_packet < packet_size)
- dev->hint_events_per_packet = packet_size;
-
- dev->max_vals = dev->hint_events_per_packet + 2;
- dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
- if (!dev->vals) {
- error = -ENOMEM;
+ error = input_device_tune_vals(dev);
+ if (error)
goto err_devres_free;
- }
/*
* If delay and period are pre-set by the driver, then autorepeating
@@ -2378,7 +2396,7 @@ int input_register_device(struct input_dev *dev)
error = device_add(&dev->dev);
if (error)
- goto err_free_vals;
+ goto err_devres_free;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%s as %s\n",
@@ -2386,18 +2404,15 @@ int input_register_device(struct input_dev *dev)
path ? path : "N/A");
kfree(path);
- error = mutex_lock_interruptible(&input_mutex);
- if (error)
- goto err_device_del;
-
- list_add_tail(&dev->node, &input_dev_list);
+ error = -EINTR;
+ scoped_cond_guard(mutex_intr, goto err_device_del, &input_mutex) {
+ list_add_tail(&dev->node, &input_dev_list);
- list_for_each_entry(handler, &input_handler_list, node)
- input_attach_handler(dev, handler);
+ list_for_each_entry(handler, &input_handler_list, node)
+ input_attach_handler(dev, handler);
- input_wakeup_procfs_readers();
-
- mutex_unlock(&input_mutex);
+ input_wakeup_procfs_readers();
+ }
if (dev->devres_managed) {
dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
@@ -2408,9 +2423,6 @@ int input_register_device(struct input_dev *dev)
err_device_del:
device_del(&dev->dev);
-err_free_vals:
- kfree(dev->vals);
- dev->vals = NULL;
err_devres_free:
devres_free(devres);
return error;
@@ -2443,6 +2455,26 @@ void input_unregister_device(struct input_dev *dev)
}
EXPORT_SYMBOL(input_unregister_device);
+static int input_handler_check_methods(const struct input_handler *handler)
+{
+ int count = 0;
+
+ if (handler->filter)
+ count++;
+ if (handler->events)
+ count++;
+ if (handler->event)
+ count++;
+
+ if (count > 1) {
+ pr_err("%s: only one event processing method can be defined (%s)\n",
+ __func__, handler->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* input_register_handler - register a new input handler
* @handler: handler to be registered
@@ -2456,20 +2488,21 @@ int input_register_handler(struct input_handler *handler)
struct input_dev *dev;
int error;
- error = mutex_lock_interruptible(&input_mutex);
+ error = input_handler_check_methods(handler);
if (error)
return error;
- INIT_LIST_HEAD(&handler->h_list);
+ scoped_cond_guard(mutex_intr, return -EINTR, &input_mutex) {
+ INIT_LIST_HEAD(&handler->h_list);
- list_add_tail(&handler->node, &input_handler_list);
+ list_add_tail(&handler->node, &input_handler_list);
- list_for_each_entry(dev, &input_dev_list, node)
- input_attach_handler(dev, handler);
+ list_for_each_entry(dev, &input_dev_list, node)
+ input_attach_handler(dev, handler);
- input_wakeup_procfs_readers();
+ input_wakeup_procfs_readers();
+ }
- mutex_unlock(&input_mutex);
return 0;
}
EXPORT_SYMBOL(input_register_handler);
@@ -2485,7 +2518,7 @@ void input_unregister_handler(struct input_handler *handler)
{
struct input_handle *handle, *next;
- mutex_lock(&input_mutex);
+ guard(mutex)(&input_mutex);
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
handler->disconnect(handle);
@@ -2494,8 +2527,6 @@ void input_unregister_handler(struct input_handler *handler)
list_del_init(&handler->node);
input_wakeup_procfs_readers();
-
- mutex_unlock(&input_mutex);
}
EXPORT_SYMBOL(input_unregister_handler);
@@ -2515,22 +2546,89 @@ int input_handler_for_each_handle(struct input_handler *handler, void *data,
int (*fn)(struct input_handle *, void *))
{
struct input_handle *handle;
- int retval = 0;
+ int retval;
- rcu_read_lock();
+ guard(rcu)();
list_for_each_entry_rcu(handle, &handler->h_list, h_node) {
retval = fn(handle, data);
if (retval)
- break;
+ return retval;
}
- rcu_read_unlock();
-
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_handler_for_each_handle);
+/*
+ * An implementation of input_handle's handle_events() method that simply
+ * invokes handler->event() method for each event one by one.
+ */
+static unsigned int input_handle_events_default(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ struct input_handler *handler = handle->handler;
+ struct input_value *v;
+
+ for (v = vals; v != vals + count; v++)
+ handler->event(handle, v->type, v->code, v->value);
+
+ return count;
+}
+
+/*
+ * An implementation of input_handle's handle_events() method that invokes
+ * handler->filter() method for each event one by one and removes events
+ * that were filtered out from the "vals" array.
+ */
+static unsigned int input_handle_events_filter(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ struct input_handler *handler = handle->handler;
+ struct input_value *end = vals;
+ struct input_value *v;
+
+ for (v = vals; v != vals + count; v++) {
+ if (handler->filter(handle, v->type, v->code, v->value))
+ continue;
+ if (end != v)
+ *end = *v;
+ end++;
+ }
+
+ return end - vals;
+}
+
+/*
+ * An implementation of input_handle's handle_events() method that does nothing.
+ */
+static unsigned int input_handle_events_null(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ return count;
+}
+
+/*
+ * Sets up appropriate handle->event_handler based on the input_handler
+ * associated with the handle.
+ */
+static void input_handle_setup_event_handler(struct input_handle *handle)
+{
+ struct input_handler *handler = handle->handler;
+
+ if (handler->filter)
+ handle->handle_events = input_handle_events_filter;
+ else if (handler->event)
+ handle->handle_events = input_handle_events_default;
+ else if (handler->events)
+ handle->handle_events = handler->events;
+ else
+ handle->handle_events = input_handle_events_null;
+}
+
/**
* input_register_handle - register a new input handle
* @handle: handle to register
@@ -2546,26 +2644,22 @@ int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
- int error;
+ input_handle_setup_event_handler(handle);
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
- error = mutex_lock_interruptible(&dev->mutex);
- if (error)
- return error;
-
- /*
- * Filters go to the head of the list, normal handlers
- * to the tail.
- */
- if (handler->filter)
- list_add_rcu(&handle->d_node, &dev->h_list);
- else
- list_add_tail_rcu(&handle->d_node, &dev->h_list);
-
- mutex_unlock(&dev->mutex);
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ /*
+ * Filters go to the head of the list, normal handlers
+ * to the tail.
+ */
+ if (handler->filter)
+ list_add_rcu(&handle->d_node, &dev->h_list);
+ else
+ list_add_tail_rcu(&handle->d_node, &dev->h_list);
+ }
/*
* Since we are supposed to be called from ->connect()
@@ -2601,9 +2695,8 @@ void input_unregister_handle(struct input_handle *handle)
/*
* Take dev->mutex to prevent race with input_release_device().
*/
- mutex_lock(&dev->mutex);
- list_del_rcu(&handle->d_node);
- mutex_unlock(&dev->mutex);
+ scoped_guard(mutex, &dev->mutex)
+ list_del_rcu(&handle->d_node);
synchronize_rcu();
}