Commit e4dbedc7 authored by Dmitry Torokhov's avatar Dmitry Torokhov

Input: mousedev - fix race when creating mixed device

We should not be using static variable mousedev_mix in methods that can be
called before that singleton gets assigned. While at it let's add open and
close methods to mousedev structure so that we do not need to test if we
are dealing with multiplexor or normal device and simply call appropriate
method directly.

This fixes: https://bugzilla.kernel.org/show_bug.cgi?id=71551Reported-by: default avatarGiulioDP <depasquale.giulio@gmail.com>
Tested-by: default avatarGiulioDP <depasquale.giulio@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent fc7392aa
...@@ -67,7 +67,6 @@ struct mousedev { ...@@ -67,7 +67,6 @@ struct mousedev {
struct device dev; struct device dev;
struct cdev cdev; struct cdev cdev;
bool exist; bool exist;
bool is_mixdev;
struct list_head mixdev_node; struct list_head mixdev_node;
bool opened_by_mixdev; bool opened_by_mixdev;
...@@ -77,6 +76,9 @@ struct mousedev { ...@@ -77,6 +76,9 @@ struct mousedev {
int old_x[4], old_y[4]; int old_x[4], old_y[4];
int frac_dx, frac_dy; int frac_dx, frac_dy;
unsigned long touch; unsigned long touch;
int (*open_device)(struct mousedev *mousedev);
void (*close_device)(struct mousedev *mousedev);
}; };
enum mousedev_emul { enum mousedev_emul {
...@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; ...@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
static struct mousedev *mousedev_mix; static struct mousedev *mousedev_mix;
static LIST_HEAD(mousedev_mix_list); 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 fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(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) ...@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
if (retval) if (retval)
return retval; return retval;
if (mousedev->is_mixdev) if (!mousedev->exist)
mixdev_open_devices();
else if (!mousedev->exist)
retval = -ENODEV; retval = -ENODEV;
else if (!mousedev->open++) { else if (!mousedev->open++) {
retval = input_open_device(&mousedev->handle); retval = input_open_device(&mousedev->handle);
...@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev) ...@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
{ {
mutex_lock(&mousedev->mutex); mutex_lock(&mousedev->mutex);
if (mousedev->is_mixdev) if (mousedev->exist && !--mousedev->open)
mixdev_close_devices();
else if (mousedev->exist && !--mousedev->open)
input_close_device(&mousedev->handle); input_close_device(&mousedev->handle);
mutex_unlock(&mousedev->mutex); mutex_unlock(&mousedev->mutex);
...@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev) ...@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev)
* stream. Note that this function is called with mousedev_mix->mutex * stream. Note that this function is called with mousedev_mix->mutex
* held. * 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++) if (!mixdev->open++) {
return; struct mousedev *mousedev;
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (!mousedev->opened_by_mixdev) { if (!mousedev->opened_by_mixdev) {
if (mousedev_open_device(mousedev)) if (mousedev_open_device(mousedev))
continue; 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) ...@@ -481,19 +484,22 @@ static void mixdev_open_devices(void)
* device. Note that this function is called with mousedev_mix->mutex * device. Note that this function is called with mousedev_mix->mutex
* held. * 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) if (!--mixdev->open) {
return; struct mousedev *mousedev;
list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
if (mousedev->opened_by_mixdev) { if (mousedev->opened_by_mixdev) {
mousedev->opened_by_mixdev = false; mousedev->opened_by_mixdev = false;
mousedev_close_device(mousedev); mousedev_close_device(mousedev);
}
} }
} }
mutex_unlock(&mixdev->mutex);
} }
...@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file) ...@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)
mousedev_detach_client(mousedev, client); mousedev_detach_client(mousedev, client);
kfree(client); kfree(client);
mousedev_close_device(mousedev); mousedev->close_device(mousedev);
return 0; return 0;
} }
...@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file) ...@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file)
client->mousedev = mousedev; client->mousedev = mousedev;
mousedev_attach_client(mousedev, client); mousedev_attach_client(mousedev, client);
error = mousedev_open_device(mousedev); error = mousedev->open_device(mousedev);
if (error) if (error)
goto err_free_client; goto err_free_client;
...@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev, ...@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
if (mixdev) { if (mixdev) {
dev_set_name(&mousedev->dev, "mice"); dev_set_name(&mousedev->dev, "mice");
mousedev->open_device = mixdev_open_devices;
mousedev->close_device = mixdev_close_devices;
} else { } else {
int dev_no = minor; int dev_no = minor;
/* Normalize device number if it falls into legacy range */ /* Normalize device number if it falls into legacy range */
if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS) if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
dev_no -= MOUSEDEV_MINOR_BASE; dev_no -= MOUSEDEV_MINOR_BASE;
dev_set_name(&mousedev->dev, "mouse%d", dev_no); 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->exist = true;
mousedev->is_mixdev = mixdev;
mousedev->handle.dev = input_get_device(dev); mousedev->handle.dev = input_get_device(dev);
mousedev->handle.name = dev_name(&mousedev->dev); mousedev->handle.name = dev_name(&mousedev->dev);
mousedev->handle.handler = handler; mousedev->handle.handler = handler;
...@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev) ...@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev)
device_del(&mousedev->dev); device_del(&mousedev->dev);
mousedev_cleanup(mousedev); mousedev_cleanup(mousedev);
input_free_minor(MINOR(mousedev->dev.devt)); input_free_minor(MINOR(mousedev->dev.devt));
if (!mousedev->is_mixdev) if (mousedev != mousedev_mix)
input_unregister_handle(&mousedev->handle); input_unregister_handle(&mousedev->handle);
put_device(&mousedev->dev); put_device(&mousedev->dev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment