#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");
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);
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;
__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) {
/*
&input_dev_attr_group,
&input_dev_id_attr_group,
&input_dev_caps_attr_group,
+ &input_poller_attribute_group,
NULL
};
input_ff_destroy(dev);
input_mt_destroy_slots(dev);
+ kfree(dev->poller);
kfree(dev->absinfo);
kfree(dev->vals);
kfree(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
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;