Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aac8bcf1 authored by Aniroop Mathur's avatar Aniroop Mathur Committed by Dmitry Torokhov
Browse files

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: default avatarAniroop Mathur <a.mathur@samsung.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 2ba35320
Loading
Loading
Loading
Loading
+44 −16
Original line number Original line Diff line number Diff line
@@ -28,6 +28,13 @@
#include <linux/cdev.h>
#include <linux/cdev.h>
#include "input-compat.h"
#include "input-compat.h"


enum evdev_clock_type {
	EV_CLK_REAL = 0,
	EV_CLK_MONO,
	EV_CLK_BOOT,
	EV_CLK_MAX
};

struct evdev {
struct evdev {
	int open;
	int open;
	struct input_handle handle;
	struct input_handle handle;
@@ -49,12 +56,32 @@ struct evdev_client {
	struct fasync_struct *fasync;
	struct fasync_struct *fasync;
	struct evdev *evdev;
	struct evdev *evdev;
	struct list_head node;
	struct list_head node;
	int clkid;
	int clk_type;
	bool revoked;
	bool revoked;
	unsigned int bufsize;
	unsigned int bufsize;
	struct input_event buffer[];
	struct input_event buffer[];
};
};


static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
{
	switch (clkid) {

	case CLOCK_REALTIME:
		client->clk_type = EV_CLK_REAL;
		break;
	case CLOCK_MONOTONIC:
		client->clk_type = EV_CLK_MONO;
		break;
	case CLOCK_BOOTTIME:
		client->clk_type = EV_CLK_BOOT;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

/* flush queued events of type @type, caller must hold client->buffer_lock */
/* flush queued events of type @type, caller must hold client->buffer_lock */
static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
{
{
@@ -108,8 +135,11 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
	struct input_event ev;
	struct input_event ev;
	ktime_t time;
	ktime_t time;


	time = (client->clkid == CLOCK_MONOTONIC) ?
	time = client->clk_type == EV_CLK_REAL ?
		ktime_get() : ktime_get_real();
			ktime_get_real() :
			client->clk_type == EV_CLK_MONO ?
				ktime_get() :
				ktime_get_boottime();


	ev.time = ktime_to_timeval(time);
	ev.time = ktime_to_timeval(time);
	ev.type = EV_SYN;
	ev.type = EV_SYN;
@@ -159,7 +189,7 @@ static void __pass_event(struct evdev_client *client,


static void evdev_pass_values(struct evdev_client *client,
static void evdev_pass_values(struct evdev_client *client,
			const struct input_value *vals, unsigned int count,
			const struct input_value *vals, unsigned int count,
			ktime_t mono, ktime_t real)
			ktime_t *ev_time)
{
{
	struct evdev *evdev = client->evdev;
	struct evdev *evdev = client->evdev;
	const struct input_value *v;
	const struct input_value *v;
@@ -169,8 +199,7 @@ static void evdev_pass_values(struct evdev_client *client,
	if (client->revoked)
	if (client->revoked)
		return;
		return;


	event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
	event.time = ktime_to_timeval(ev_time[client->clk_type]);
				      mono : real);


	/* Interrupts are disabled, just acquire the lock. */
	/* Interrupts are disabled, just acquire the lock. */
	spin_lock(&client->buffer_lock);
	spin_lock(&client->buffer_lock);
@@ -198,21 +227,22 @@ static void evdev_events(struct input_handle *handle,
{
{
	struct evdev *evdev = handle->private;
	struct evdev *evdev = handle->private;
	struct evdev_client *client;
	struct evdev_client *client;
	ktime_t time_mono, time_real;
	ktime_t ev_time[EV_CLK_MAX];


	time_mono = ktime_get();
	ev_time[EV_CLK_MONO] = ktime_get();
	time_real = ktime_mono_to_real(time_mono);
	ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
	ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
						 TK_OFFS_BOOT);


	rcu_read_lock();
	rcu_read_lock();


	client = rcu_dereference(evdev->grab);
	client = rcu_dereference(evdev->grab);


	if (client)
	if (client)
		evdev_pass_values(client, vals, count, time_mono, time_real);
		evdev_pass_values(client, vals, count, ev_time);
	else
	else
		list_for_each_entry_rcu(client, &evdev->client_list, node)
		list_for_each_entry_rcu(client, &evdev->client_list, node)
			evdev_pass_values(client, vals, count,
			evdev_pass_values(client, vals, count, ev_time);
					  time_mono, time_real);


	rcu_read_unlock();
	rcu_read_unlock();
}
}
@@ -877,10 +907,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
	case EVIOCSCLOCKID:
	case EVIOCSCLOCKID:
		if (copy_from_user(&i, p, sizeof(unsigned int)))
		if (copy_from_user(&i, p, sizeof(unsigned int)))
			return -EFAULT;
			return -EFAULT;
		if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME)

			return -EINVAL;
		return evdev_set_clk_type(client, i);
		client->clkid = i;
		return 0;


	case EVIOCGKEYCODE:
	case EVIOCGKEYCODE:
		return evdev_handle_get_keycode(dev, p);
		return evdev_handle_get_keycode(dev, p);