Merge branch 'next' into for-linus
[~shefty/rdma-dev.git] / drivers / input / evdev.c
index 7df5bfef2624d5c1e49bd39208135c29aaed8653..4b2e10d5d641a9d90f41afdf43f6fb6ed64c5987 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/major.h>
 #include <linux/device.h>
 #include "input-compat.h"
@@ -46,6 +46,7 @@ struct evdev_client {
        struct fasync_struct *fasync;
        struct evdev *evdev;
        struct list_head node;
+       int clkid;
        unsigned int bufsize;
        struct input_event buffer[];
 };
@@ -54,8 +55,12 @@ static struct evdev *evdev_table[EVDEV_MINORS];
 static DEFINE_MUTEX(evdev_table_mutex);
 
 static void evdev_pass_event(struct evdev_client *client,
-                            struct input_event *event)
+                            struct input_event *event,
+                            ktime_t mono, ktime_t real)
 {
+       event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
+                                       mono : real);
+
        /* Interrupts are disabled, just acquire the lock. */
        spin_lock(&client->buffer_lock);
 
@@ -94,8 +99,11 @@ static void evdev_event(struct input_handle *handle,
        struct evdev *evdev = handle->private;
        struct evdev_client *client;
        struct input_event event;
+       ktime_t time_mono, time_real;
+
+       time_mono = ktime_get();
+       time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
 
-       do_gettimeofday(&event.time);
        event.type = type;
        event.code = code;
        event.value = value;
@@ -103,11 +111,12 @@ static void evdev_event(struct input_handle *handle,
        rcu_read_lock();
 
        client = rcu_dereference(evdev->grab);
+
        if (client)
-               evdev_pass_event(client, &event);
+               evdev_pass_event(client, &event, time_mono, time_real);
        else
                list_for_each_entry_rcu(client, &evdev->client_list, node)
-                       evdev_pass_event(client, &event);
+                       evdev_pass_event(client, &event, time_mono, time_real);
 
        rcu_read_unlock();
 
@@ -623,6 +632,28 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
        return input_set_keycode(dev, &ke);
 }
 
+static int evdev_handle_mt_request(struct input_dev *dev,
+                                  unsigned int size,
+                                  int __user *ip)
+{
+       const struct input_mt_slot *mt = dev->mt;
+       unsigned int code;
+       int max_slots;
+       int i;
+
+       if (get_user(code, &ip[0]))
+               return -EFAULT;
+       if (!input_is_mt_value(code))
+               return -EINVAL;
+
+       max_slots = (size - sizeof(__u32)) / sizeof(__s32);
+       for (i = 0; i < dev->mtsize && i < max_slots; i++)
+               if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))
+                       return -EFAULT;
+
+       return 0;
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                           void __user *p, int compat_mode)
 {
@@ -685,6 +716,14 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                else
                        return evdev_ungrab(evdev, client);
 
+       case EVIOCSCLOCKID:
+               if (copy_from_user(&i, p, sizeof(unsigned int)))
+                       return -EFAULT;
+               if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME)
+                       return -EINVAL;
+               client->clkid = i;
+               return 0;
+
        case EVIOCGKEYCODE:
                return evdev_handle_get_keycode(dev, p);
 
@@ -708,6 +747,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                return bits_to_user(dev->propbit, INPUT_PROP_MAX,
                                    size, p, compat_mode);
 
+       case EVIOCGMTSLOTS(0):
+               return evdev_handle_mt_request(dev, size, ip);
+
        case EVIOCGKEY(0):
                return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);