Input: uinput - support injecting multiple events in one write() call
authorRyan Mallon <rmallon@gmail.com>
Wed, 18 Sep 2013 19:40:47 +0000 (12:40 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Thu, 19 Sep 2013 15:57:56 +0000 (08:57 -0700)
Rework the code in uinput_inject_event so that it matches the code in
evdev_write and allows injecting more than one event, or zero events.

Signed-off-by: Ryan Mallon <rmallon@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/misc/uinput.c

index a0a4bbaef02c242a8ee16e54bdb9337e8f80407e..772835938a526ed2575f6bc187619fe962ac0e6c 100644 (file)
@@ -430,20 +430,30 @@ static int uinput_setup_device(struct uinput_device *udev,
        return retval;
 }
 
-static ssize_t uinput_inject_event(struct uinput_device *udev,
-                                  const char __user *buffer, size_t count)
+static ssize_t uinput_inject_events(struct uinput_device *udev,
+                                   const char __user *buffer, size_t count)
 {
        struct input_event ev;
+       size_t bytes = 0;
 
-       if (count < input_event_size())
+       if (count != 0 && count < input_event_size())
                return -EINVAL;
 
-       if (input_event_from_user(buffer, &ev))
-               return -EFAULT;
+       while (bytes + input_event_size() <= count) {
+               /*
+                * Note that even if some events were fetched successfully
+                * we are still going to return EFAULT instead of partial
+                * count to let userspace know that it got it's buffers
+                * all wrong.
+                */
+               if (input_event_from_user(buffer + bytes, &ev))
+                       return -EFAULT;
 
-       input_event(udev->dev, ev.type, ev.code, ev.value);
+               input_event(udev->dev, ev.type, ev.code, ev.value);
+               bytes += input_event_size();
+       }
 
-       return input_event_size();
+       return bytes;
 }
 
 static ssize_t uinput_write(struct file *file, const char __user *buffer,
@@ -460,7 +470,7 @@ static ssize_t uinput_write(struct file *file, const char __user *buffer,
                return retval;
 
        retval = udev->state == UIST_CREATED ?
-                       uinput_inject_event(udev, buffer, count) :
+                       uinput_inject_events(udev, buffer, count) :
                        uinput_setup_device(udev, buffer, count);
 
        mutex_unlock(&udev->mutex);