]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Mar 2014 00:20:40 +0000 (17:20 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Mar 2014 00:20:40 +0000 (17:20 -0700)
Pull input updates from Dmitry Torokhov:
 "Some more updates for the input subsystem.

  You will get a fix for race in mousedev that has been causing quite a
  few oopses lately and a small fixup for force feedback support in
  evdev"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: mousedev - fix race when creating mixed device
  Input: don't modify the id of ioctl-provided ff effect on upload failure

drivers/input/evdev.c
drivers/input/mousedev.c

index a06e12552886fa57ffbe1731eb744762666cd787..ce953d895f5b2b92d3bbb0d1a19be8a86d563d6b 100644 (file)
@@ -954,11 +954,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                        return -EFAULT;
 
                error = input_ff_upload(dev, &effect, file);
+               if (error)
+                       return error;
 
                if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
                        return -EFAULT;
 
-               return error;
+               return 0;
        }
 
        /* Multi-number variable-length handlers */
index 4c842c320c2ede9f2bf42d507ee5c91f00eef7e3..b604564dec5c9a5d8d154ac18a61c02341f77e5d 100644 (file)
@@ -67,7 +67,6 @@ struct mousedev {
        struct device dev;
        struct cdev cdev;
        bool exist;
-       bool is_mixdev;
 
        struct list_head mixdev_node;
        bool opened_by_mixdev;
@@ -77,6 +76,9 @@ struct mousedev {
        int old_x[4], old_y[4];
        int frac_dx, frac_dy;
        unsigned long touch;
+
+       int (*open_device)(struct mousedev *mousedev);
+       void (*close_device)(struct mousedev *mousedev);
 };
 
 enum mousedev_emul {
@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 static struct mousedev *mousedev_mix;
 static LIST_HEAD(mousedev_mix_list);
 
-static void mixdev_open_devices(void);
-static void mixdev_close_devices(void);
-
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
 
@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
        if (retval)
                return retval;
 
-       if (mousedev->is_mixdev)
-               mixdev_open_devices();
-       else if (!mousedev->exist)
+       if (!mousedev->exist)
                retval = -ENODEV;
        else if (!mousedev->open++) {
                retval = input_open_device(&mousedev->handle);
@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
 {
        mutex_lock(&mousedev->mutex);
 
-       if (mousedev->is_mixdev)
-               mixdev_close_devices();
-       else if (mousedev->exist && !--mousedev->open)
+       if (mousedev->exist && !--mousedev->open)
                input_close_device(&mousedev->handle);
 
        mutex_unlock(&mousedev->mutex);
@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev)
  * stream. Note that this function is called with mousedev_mix->mutex
  * held.
  */
-static void mixdev_open_devices(void)
+static int mixdev_open_devices(struct mousedev *mixdev)
 {
-       struct mousedev *mousedev;
+       int error;
+
+       error = mutex_lock_interruptible(&mixdev->mutex);
+       if (error)
+               return error;
 
-       if (mousedev_mix->open++)
-               return;
+       if (!mixdev->open++) {
+               struct mousedev *mousedev;
 
-       list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
-               if (!mousedev->opened_by_mixdev) {
-                       if (mousedev_open_device(mousedev))
-                               continue;
+               list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+                       if (!mousedev->opened_by_mixdev) {
+                               if (mousedev_open_device(mousedev))
+                                       continue;
 
-                       mousedev->opened_by_mixdev = true;
+                               mousedev->opened_by_mixdev = true;
+                       }
                }
        }
+
+       mutex_unlock(&mixdev->mutex);
+       return 0;
 }
 
 /*
@@ -481,19 +484,22 @@ static void mixdev_open_devices(void)
  * device. Note that this function is called with mousedev_mix->mutex
  * held.
  */
-static void mixdev_close_devices(void)
+static void mixdev_close_devices(struct mousedev *mixdev)
 {
-       struct mousedev *mousedev;
+       mutex_lock(&mixdev->mutex);
 
-       if (--mousedev_mix->open)
-               return;
+       if (!--mixdev->open) {
+               struct mousedev *mousedev;
 
-       list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
-               if (mousedev->opened_by_mixdev) {
-                       mousedev->opened_by_mixdev = false;
-                       mousedev_close_device(mousedev);
+               list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+                       if (mousedev->opened_by_mixdev) {
+                               mousedev->opened_by_mixdev = false;
+                               mousedev_close_device(mousedev);
+                       }
                }
        }
+
+       mutex_unlock(&mixdev->mutex);
 }
 
 
@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)
        mousedev_detach_client(mousedev, client);
        kfree(client);
 
-       mousedev_close_device(mousedev);
+       mousedev->close_device(mousedev);
 
        return 0;
 }
@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file)
        client->mousedev = mousedev;
        mousedev_attach_client(mousedev, client);
 
-       error = mousedev_open_device(mousedev);
+       error = mousedev->open_device(mousedev);
        if (error)
                goto err_free_client;
 
@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
 
        if (mixdev) {
                dev_set_name(&mousedev->dev, "mice");
+
+               mousedev->open_device = mixdev_open_devices;
+               mousedev->close_device = mixdev_close_devices;
        } else {
                int dev_no = minor;
                /* Normalize device number if it falls into legacy range */
                if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
                        dev_no -= MOUSEDEV_MINOR_BASE;
                dev_set_name(&mousedev->dev, "mouse%d", dev_no);
+
+               mousedev->open_device = mousedev_open_device;
+               mousedev->close_device = mousedev_close_device;
        }
 
        mousedev->exist = true;
-       mousedev->is_mixdev = mixdev;
        mousedev->handle.dev = input_get_device(dev);
        mousedev->handle.name = dev_name(&mousedev->dev);
        mousedev->handle.handler = handler;
@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev)
        device_del(&mousedev->dev);
        mousedev_cleanup(mousedev);
        input_free_minor(MINOR(mousedev->dev.devt));
-       if (!mousedev->is_mixdev)
+       if (mousedev != mousedev_mix)
                input_unregister_handle(&mousedev->handle);
        put_device(&mousedev->dev);
 }