diff options
author | Atif Niyaz <atifniyaz@google.com> | 2019-07-24 15:26:31 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2019-07-25 04:12:20 -0400 |
commit | 3b51c44bd6936e86a7180abd9aebc4387a479253 (patch) | |
tree | 307baa973004837a30e57d0a3dccc54f89e06604 | |
parent | c2433827c1a149b72f1413f0151155f6fa4b3214 (diff) |
Input: allow drivers specify timestamp for input events
Currently, evdev stamps events with timestamps acquired in evdev_events()
However, this timestamping may not be accurate in terms of measuring
when the actual event happened.
Let's allow individual drivers specify timestamp in order to provide a more
accurate sense of time for the event. It is expected that drivers will set the
timestamp in their hard interrupt routine.
Signed-off-by: Atif Niyaz <atifniyaz@google.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | drivers/input/evdev.c | 35 | ||||
-rw-r--r-- | drivers/input/input.c | 40 | ||||
-rw-r--r-- | include/linux/input.h | 14 |
3 files changed, 62 insertions, 27 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 867c2cfd0038..d7dd6fcf2db0 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -25,13 +25,6 @@ | |||
25 | #include <linux/cdev.h> | 25 | #include <linux/cdev.h> |
26 | #include "input-compat.h" | 26 | #include "input-compat.h" |
27 | 27 | ||
28 | enum evdev_clock_type { | ||
29 | EV_CLK_REAL = 0, | ||
30 | EV_CLK_MONO, | ||
31 | EV_CLK_BOOT, | ||
32 | EV_CLK_MAX | ||
33 | }; | ||
34 | |||
35 | struct evdev { | 28 | struct evdev { |
36 | int open; | 29 | int open; |
37 | struct input_handle handle; | 30 | struct input_handle handle; |
@@ -53,7 +46,7 @@ struct evdev_client { | |||
53 | struct fasync_struct *fasync; | 46 | struct fasync_struct *fasync; |
54 | struct evdev *evdev; | 47 | struct evdev *evdev; |
55 | struct list_head node; | 48 | struct list_head node; |
56 | unsigned int clk_type; | 49 | enum input_clock_type clk_type; |
57 | bool revoked; | 50 | bool revoked; |
58 | unsigned long *evmasks[EV_CNT]; | 51 | unsigned long *evmasks[EV_CNT]; |
59 | unsigned int bufsize; | 52 | unsigned int bufsize; |
@@ -149,17 +142,10 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) | |||
149 | 142 | ||
150 | static void __evdev_queue_syn_dropped(struct evdev_client *client) | 143 | static void __evdev_queue_syn_dropped(struct evdev_client *client) |
151 | { | 144 | { |
145 | ktime_t *ev_time = input_get_timestamp(client->evdev->handle.dev); | ||
146 | struct timespec64 ts = ktime_to_timespec64(ev_time[client->clk_type]); | ||
152 | struct input_event ev; | 147 | struct input_event ev; |
153 | ktime_t time; | ||
154 | struct timespec64 ts; | ||
155 | 148 | ||
156 | time = client->clk_type == EV_CLK_REAL ? | ||
157 | ktime_get_real() : | ||
158 | client->clk_type == EV_CLK_MONO ? | ||
159 | ktime_get() : | ||
160 | ktime_get_boottime(); | ||
161 | |||
162 | ts = ktime_to_timespec64(time); | ||
163 | ev.input_event_sec = ts.tv_sec; | 149 | ev.input_event_sec = ts.tv_sec; |
164 | ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; | 150 | ev.input_event_usec = ts.tv_nsec / NSEC_PER_USEC; |
165 | ev.type = EV_SYN; | 151 | ev.type = EV_SYN; |
@@ -188,18 +174,18 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) | |||
188 | static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) | 174 | static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) |
189 | { | 175 | { |
190 | unsigned long flags; | 176 | unsigned long flags; |
191 | unsigned int clk_type; | 177 | enum input_clock_type clk_type; |
192 | 178 | ||
193 | switch (clkid) { | 179 | switch (clkid) { |
194 | 180 | ||
195 | case CLOCK_REALTIME: | 181 | case CLOCK_REALTIME: |
196 | clk_type = EV_CLK_REAL; | 182 | clk_type = INPUT_CLK_REAL; |
197 | break; | 183 | break; |
198 | case CLOCK_MONOTONIC: | 184 | case CLOCK_MONOTONIC: |
199 | clk_type = EV_CLK_MONO; | 185 | clk_type = INPUT_CLK_MONO; |
200 | break; | 186 | break; |
201 | case CLOCK_BOOTTIME: | 187 | case CLOCK_BOOTTIME: |
202 | clk_type = EV_CLK_BOOT; | 188 | clk_type = INPUT_CLK_BOOT; |
203 | break; | 189 | break; |
204 | default: | 190 | default: |
205 | return -EINVAL; | 191 | return -EINVAL; |
@@ -307,12 +293,7 @@ static void evdev_events(struct input_handle *handle, | |||
307 | { | 293 | { |
308 | struct evdev *evdev = handle->private; | 294 | struct evdev *evdev = handle->private; |
309 | struct evdev_client *client; | 295 | struct evdev_client *client; |
310 | ktime_t ev_time[EV_CLK_MAX]; | 296 | ktime_t *ev_time = input_get_timestamp(handle->dev); |
311 | |||
312 | ev_time[EV_CLK_MONO] = ktime_get(); | ||
313 | ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]); | ||
314 | ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO], | ||
315 | TK_OFFS_BOOT); | ||
316 | 297 | ||
317 | rcu_read_lock(); | 298 | rcu_read_lock(); |
318 | 299 | ||
diff --git a/drivers/input/input.c b/drivers/input/input.c index 7f3c5fcb9ed6..7494a0dede79 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -1895,6 +1895,46 @@ void input_free_device(struct input_dev *dev) | |||
1895 | EXPORT_SYMBOL(input_free_device); | 1895 | EXPORT_SYMBOL(input_free_device); |
1896 | 1896 | ||
1897 | /** | 1897 | /** |
1898 | * input_set_timestamp - set timestamp for input events | ||
1899 | * @dev: input device to set timestamp for | ||
1900 | * @timestamp: the time at which the event has occurred | ||
1901 | * in CLOCK_MONOTONIC | ||
1902 | * | ||
1903 | * This function is intended to provide to the input system a more | ||
1904 | * accurate time of when an event actually occurred. The driver should | ||
1905 | * call this function as soon as a timestamp is acquired ensuring | ||
1906 | * clock conversions in input_set_timestamp are done correctly. | ||
1907 | * | ||
1908 | * The system entering suspend state between timestamp acquisition and | ||
1909 | * calling input_set_timestamp can result in inaccurate conversions. | ||
1910 | */ | ||
1911 | void input_set_timestamp(struct input_dev *dev, ktime_t timestamp) | ||
1912 | { | ||
1913 | dev->timestamp[INPUT_CLK_MONO] = timestamp; | ||
1914 | dev->timestamp[INPUT_CLK_REAL] = ktime_mono_to_real(timestamp); | ||
1915 | dev->timestamp[INPUT_CLK_BOOT] = ktime_mono_to_any(timestamp, | ||
1916 | TK_OFFS_BOOT); | ||
1917 | } | ||
1918 | EXPORT_SYMBOL(input_set_timestamp); | ||
1919 | |||
1920 | /** | ||
1921 | * input_get_timestamp - get timestamp for input events | ||
1922 | * @dev: input device to get timestamp from | ||
1923 | * | ||
1924 | * A valid timestamp is a timestamp of non-zero value. | ||
1925 | */ | ||
1926 | ktime_t *input_get_timestamp(struct input_dev *dev) | ||
1927 | { | ||
1928 | const ktime_t invalid_timestamp = ktime_set(0, 0); | ||
1929 | |||
1930 | if (!ktime_compare(dev->timestamp[INPUT_CLK_MONO], invalid_timestamp)) | ||
1931 | input_set_timestamp(dev, ktime_get()); | ||
1932 | |||
1933 | return dev->timestamp; | ||
1934 | } | ||
1935 | EXPORT_SYMBOL(input_get_timestamp); | ||
1936 | |||
1937 | /** | ||
1898 | * input_set_capability - mark device as capable of a certain event | 1938 | * input_set_capability - mark device as capable of a certain event |
1899 | * @dev: device that is capable of emitting or accepting event | 1939 | * @dev: device that is capable of emitting or accepting event |
1900 | * @type: type of the event (EV_KEY, EV_REL, etc...) | 1940 | * @type: type of the event (EV_KEY, EV_REL, etc...) |
diff --git a/include/linux/input.h b/include/linux/input.h index 510e78558c10..e95a439d8bd5 100644 --- a/include/linux/input.h +++ b/include/linux/input.h | |||
@@ -33,6 +33,13 @@ struct input_value { | |||
33 | __s32 value; | 33 | __s32 value; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | enum input_clock_type { | ||
37 | INPUT_CLK_REAL = 0, | ||
38 | INPUT_CLK_MONO, | ||
39 | INPUT_CLK_BOOT, | ||
40 | INPUT_CLK_MAX | ||
41 | }; | ||
42 | |||
36 | /** | 43 | /** |
37 | * struct input_dev - represents an input device | 44 | * struct input_dev - represents an input device |
38 | * @name: name of the device | 45 | * @name: name of the device |
@@ -114,6 +121,8 @@ struct input_value { | |||
114 | * @vals: array of values queued in the current frame | 121 | * @vals: array of values queued in the current frame |
115 | * @devres_managed: indicates that devices is managed with devres framework | 122 | * @devres_managed: indicates that devices is managed with devres framework |
116 | * and needs not be explicitly unregistered or freed. | 123 | * and needs not be explicitly unregistered or freed. |
124 | * @timestamp: storage for a timestamp set by input_set_timestamp called | ||
125 | * by a driver | ||
117 | */ | 126 | */ |
118 | struct input_dev { | 127 | struct input_dev { |
119 | const char *name; | 128 | const char *name; |
@@ -184,6 +193,8 @@ struct input_dev { | |||
184 | struct input_value *vals; | 193 | struct input_value *vals; |
185 | 194 | ||
186 | bool devres_managed; | 195 | bool devres_managed; |
196 | |||
197 | ktime_t timestamp[INPUT_CLK_MAX]; | ||
187 | }; | 198 | }; |
188 | #define to_input_dev(d) container_of(d, struct input_dev, dev) | 199 | #define to_input_dev(d) container_of(d, struct input_dev, dev) |
189 | 200 | ||
@@ -382,6 +393,9 @@ void input_close_device(struct input_handle *); | |||
382 | 393 | ||
383 | int input_flush_device(struct input_handle *handle, struct file *file); | 394 | int input_flush_device(struct input_handle *handle, struct file *file); |
384 | 395 | ||
396 | void input_set_timestamp(struct input_dev *dev, ktime_t timestamp); | ||
397 | ktime_t *input_get_timestamp(struct input_dev *dev); | ||
398 | |||
385 | void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); | 399 | void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); |
386 | void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value); | 400 | void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value); |
387 | 401 | ||