diff options
author | Aniroop Mathur <aniroop.mathur@gmail.com> | 2014-12-17 18:33:06 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2014-12-17 18:46:59 -0500 |
commit | aac8bcf1ed3e2e97da0ec7e859d20fe3fa76bd97 (patch) | |
tree | d9a9decdcaa1a008fdc4f75c20f3f1cb832e7854 /drivers/input | |
parent | 2ba353204779c81d09bb03051d8a7a4b842f9ad3 (diff) |
Input: evdev - add CLOCK_BOOTTIME support
This patch adds support for CLOCK_BOOTTIME for input event timestamp.
CLOCK_BOOTTIME includes suspend time, so it would allow aplications
to get correct time difference between two events even when system
resumes from suspend state.
Signed-off-by: Aniroop Mathur <a.mathur@samsung.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/evdev.c | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index bc203485716d..b1a52abc58df 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -28,6 +28,13 @@ | |||
28 | #include <linux/cdev.h> | 28 | #include <linux/cdev.h> |
29 | #include "input-compat.h" | 29 | #include "input-compat.h" |
30 | 30 | ||
31 | enum evdev_clock_type { | ||
32 | EV_CLK_REAL = 0, | ||
33 | EV_CLK_MONO, | ||
34 | EV_CLK_BOOT, | ||
35 | EV_CLK_MAX | ||
36 | }; | ||
37 | |||
31 | struct evdev { | 38 | struct evdev { |
32 | int open; | 39 | int open; |
33 | struct input_handle handle; | 40 | struct input_handle handle; |
@@ -49,12 +56,32 @@ struct evdev_client { | |||
49 | struct fasync_struct *fasync; | 56 | struct fasync_struct *fasync; |
50 | struct evdev *evdev; | 57 | struct evdev *evdev; |
51 | struct list_head node; | 58 | struct list_head node; |
52 | int clkid; | 59 | int clk_type; |
53 | bool revoked; | 60 | bool revoked; |
54 | unsigned int bufsize; | 61 | unsigned int bufsize; |
55 | struct input_event buffer[]; | 62 | struct input_event buffer[]; |
56 | }; | 63 | }; |
57 | 64 | ||
65 | static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid) | ||
66 | { | ||
67 | switch (clkid) { | ||
68 | |||
69 | case CLOCK_REALTIME: | ||
70 | client->clk_type = EV_CLK_REAL; | ||
71 | break; | ||
72 | case CLOCK_MONOTONIC: | ||
73 | client->clk_type = EV_CLK_MONO; | ||
74 | break; | ||
75 | case CLOCK_BOOTTIME: | ||
76 | client->clk_type = EV_CLK_BOOT; | ||
77 | break; | ||
78 | default: | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
58 | /* flush queued events of type @type, caller must hold client->buffer_lock */ | 85 | /* flush queued events of type @type, caller must hold client->buffer_lock */ |
59 | static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) | 86 | static void __evdev_flush_queue(struct evdev_client *client, unsigned int type) |
60 | { | 87 | { |
@@ -108,8 +135,11 @@ static void evdev_queue_syn_dropped(struct evdev_client *client) | |||
108 | struct input_event ev; | 135 | struct input_event ev; |
109 | ktime_t time; | 136 | ktime_t time; |
110 | 137 | ||
111 | time = (client->clkid == CLOCK_MONOTONIC) ? | 138 | time = client->clk_type == EV_CLK_REAL ? |
112 | ktime_get() : ktime_get_real(); | 139 | ktime_get_real() : |
140 | client->clk_type == EV_CLK_MONO ? | ||
141 | ktime_get() : | ||
142 | ktime_get_boottime(); | ||
113 | 143 | ||
114 | ev.time = ktime_to_timeval(time); | 144 | ev.time = ktime_to_timeval(time); |
115 | ev.type = EV_SYN; | 145 | ev.type = EV_SYN; |
@@ -159,7 +189,7 @@ static void __pass_event(struct evdev_client *client, | |||
159 | 189 | ||
160 | static void evdev_pass_values(struct evdev_client *client, | 190 | static void evdev_pass_values(struct evdev_client *client, |
161 | const struct input_value *vals, unsigned int count, | 191 | const struct input_value *vals, unsigned int count, |
162 | ktime_t mono, ktime_t real) | 192 | ktime_t *ev_time) |
163 | { | 193 | { |
164 | struct evdev *evdev = client->evdev; | 194 | struct evdev *evdev = client->evdev; |
165 | const struct input_value *v; | 195 | const struct input_value *v; |
@@ -169,8 +199,7 @@ static void evdev_pass_values(struct evdev_client *client, | |||
169 | if (client->revoked) | 199 | if (client->revoked) |
170 | return; | 200 | return; |
171 | 201 | ||
172 | event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | 202 | event.time = ktime_to_timeval(ev_time[client->clk_type]); |
173 | mono : real); | ||
174 | 203 | ||
175 | /* Interrupts are disabled, just acquire the lock. */ | 204 | /* Interrupts are disabled, just acquire the lock. */ |
176 | spin_lock(&client->buffer_lock); | 205 | spin_lock(&client->buffer_lock); |
@@ -198,21 +227,22 @@ static void evdev_events(struct input_handle *handle, | |||
198 | { | 227 | { |
199 | struct evdev *evdev = handle->private; | 228 | struct evdev *evdev = handle->private; |
200 | struct evdev_client *client; | 229 | struct evdev_client *client; |
201 | ktime_t time_mono, time_real; | 230 | ktime_t ev_time[EV_CLK_MAX]; |
202 | 231 | ||
203 | time_mono = ktime_get(); | 232 | ev_time[EV_CLK_MONO] = ktime_get(); |
204 | time_real = ktime_mono_to_real(time_mono); | 233 | ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]); |
234 | ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO], | ||
235 | TK_OFFS_BOOT); | ||
205 | 236 | ||
206 | rcu_read_lock(); | 237 | rcu_read_lock(); |
207 | 238 | ||
208 | client = rcu_dereference(evdev->grab); | 239 | client = rcu_dereference(evdev->grab); |
209 | 240 | ||
210 | if (client) | 241 | if (client) |
211 | evdev_pass_values(client, vals, count, time_mono, time_real); | 242 | evdev_pass_values(client, vals, count, ev_time); |
212 | else | 243 | else |
213 | list_for_each_entry_rcu(client, &evdev->client_list, node) | 244 | list_for_each_entry_rcu(client, &evdev->client_list, node) |
214 | evdev_pass_values(client, vals, count, | 245 | evdev_pass_values(client, vals, count, ev_time); |
215 | time_mono, time_real); | ||
216 | 246 | ||
217 | rcu_read_unlock(); | 247 | rcu_read_unlock(); |
218 | } | 248 | } |
@@ -877,10 +907,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, | |||
877 | case EVIOCSCLOCKID: | 907 | case EVIOCSCLOCKID: |
878 | if (copy_from_user(&i, p, sizeof(unsigned int))) | 908 | if (copy_from_user(&i, p, sizeof(unsigned int))) |
879 | return -EFAULT; | 909 | return -EFAULT; |
880 | if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME) | 910 | |
881 | return -EINVAL; | 911 | return evdev_set_clk_type(client, i); |
882 | client->clkid = i; | ||
883 | return 0; | ||
884 | 912 | ||
885 | case EVIOCGKEYCODE: | 913 | case EVIOCGKEYCODE: |
886 | return evdev_handle_get_keycode(dev, p); | 914 | return evdev_handle_get_keycode(dev, p); |