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

Commit 915ac4e2 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents aa4af831 e4dbedc7
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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 */
+42 −31
Original line number Diff line number Diff line
@@ -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,12 +454,16 @@ 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;

	if (mousedev_mix->open++)
		return;
	error = mutex_lock_interruptible(&mixdev->mutex);
	if (error)
		return error;

	if (!mixdev->open++) {
		struct mousedev *mousedev;

		list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
			if (!mousedev->opened_by_mixdev) {
@@ -476,17 +475,21 @@ static void mixdev_open_devices(void)
		}
	}

	mutex_unlock(&mixdev->mutex);
	return 0;
}

/*
 * Close all devices that were opened as part of multiplexed
 * 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) {
@@ -496,6 +499,9 @@ static void mixdev_close_devices(void)
		}
	}

	mutex_unlock(&mixdev->mutex);
}


static void mousedev_attach_client(struct mousedev *mousedev,
				   struct mousedev_client *client)
@@ -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);
}