diff options
Diffstat (limited to 'drivers/input/input.c')
-rw-r--r-- | drivers/input/input.c | 83 |
1 files changed, 76 insertions, 7 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index 7f3c5fcb9ed6..55086279d044 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -24,6 +24,7 @@ #include <linux/mutex.h> #include <linux/rcupdate.h> #include "input-compat.h" +#include "input-poller.h" MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); MODULE_DESCRIPTION("Input core"); @@ -396,6 +397,13 @@ static void input_handle_event(struct input_dev *dev, if (dev->num_vals >= 2) input_pass_values(dev, dev->vals, dev->num_vals); dev->num_vals = 0; + /* + * Reset the timestamp on flush so we won't end up + * with a stale one. Note we only need to reset the + * monolithic one as we use its presence when deciding + * whether to generate a synthetic timestamp. + */ + dev->timestamp[INPUT_CLK_MONO] = ktime_set(0, 0); } else if (dev->num_vals >= dev->max_vals - 2) { dev->vals[dev->num_vals++] = input_value_sync; input_pass_values(dev, dev->vals, dev->num_vals); @@ -603,20 +611,31 @@ int input_open_device(struct input_handle *handle) handle->open++; - if (!dev->users++ && dev->open) - retval = dev->open(dev); + if (dev->users++) { + /* + * Device is already opened, so we can exit immediately and + * report success. + */ + goto out; + } - if (retval) { - dev->users--; - if (!--handle->open) { + if (dev->open) { + retval = dev->open(dev); + if (retval) { + dev->users--; + handle->open--; /* * Make sure we are not delivering any more events * through this handle */ synchronize_rcu(); + goto out; } } + if (dev->poller) + input_dev_poller_start(dev->poller); + out: mutex_unlock(&dev->mutex); return retval; @@ -655,8 +674,13 @@ void input_close_device(struct input_handle *handle) __input_release_device(handle); - if (!--dev->users && dev->close) - dev->close(dev); + if (!--dev->users) { + if (dev->poller) + input_dev_poller_stop(dev->poller); + + if (dev->close) + dev->close(dev); + } if (!--handle->open) { /* @@ -1502,6 +1526,7 @@ static const struct attribute_group *input_dev_attr_groups[] = { &input_dev_attr_group, &input_dev_id_attr_group, &input_dev_caps_attr_group, + &input_poller_attribute_group, NULL }; @@ -1511,6 +1536,7 @@ static void input_dev_release(struct device *device) input_ff_destroy(dev); input_mt_destroy_slots(dev); + kfree(dev->poller); kfree(dev->absinfo); kfree(dev->vals); kfree(dev); @@ -1895,6 +1921,46 @@ void input_free_device(struct input_dev *dev) EXPORT_SYMBOL(input_free_device); /** + * input_set_timestamp - set timestamp for input events + * @dev: input device to set timestamp for + * @timestamp: the time at which the event has occurred + * in CLOCK_MONOTONIC + * + * This function is intended to provide to the input system a more + * accurate time of when an event actually occurred. The driver should + * call this function as soon as a timestamp is acquired ensuring + * clock conversions in input_set_timestamp are done correctly. + * + * The system entering suspend state between timestamp acquisition and + * calling input_set_timestamp can result in inaccurate conversions. + */ +void input_set_timestamp(struct input_dev *dev, ktime_t timestamp) +{ + dev->timestamp[INPUT_CLK_MONO] = timestamp; + dev->timestamp[INPUT_CLK_REAL] = ktime_mono_to_real(timestamp); + dev->timestamp[INPUT_CLK_BOOT] = ktime_mono_to_any(timestamp, + TK_OFFS_BOOT); +} +EXPORT_SYMBOL(input_set_timestamp); + +/** + * input_get_timestamp - get timestamp for input events + * @dev: input device to get timestamp from + * + * A valid timestamp is a timestamp of non-zero value. + */ +ktime_t *input_get_timestamp(struct input_dev *dev) +{ + const ktime_t invalid_timestamp = ktime_set(0, 0); + + if (!ktime_compare(dev->timestamp[INPUT_CLK_MONO], invalid_timestamp)) + input_set_timestamp(dev, ktime_get()); + + return dev->timestamp; +} +EXPORT_SYMBOL(input_get_timestamp); + +/** * input_set_capability - mark device as capable of a certain event * @dev: device that is capable of emitting or accepting event * @type: type of the event (EV_KEY, EV_REL, etc...) @@ -2135,6 +2201,9 @@ int input_register_device(struct input_dev *dev) if (!dev->setkeycode) dev->setkeycode = input_default_setkeycode; + if (dev->poller) + input_dev_poller_finalize(dev->poller); + error = device_add(&dev->dev); if (error) goto err_free_vals; |