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 Original line Diff line number Diff line
@@ -954,11 +954,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
			return -EFAULT;
			return -EFAULT;


		error = input_ff_upload(dev, &effect, file);
		error = input_ff_upload(dev, &effect, file);
		if (error)
			return error;


		if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
		if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
			return -EFAULT;
			return -EFAULT;


		return error;
		return 0;
	}
	}


	/* Multi-number variable-length handlers */
	/* Multi-number variable-length handlers */
+42 −31
Original line number Original line Diff line number Diff line
@@ -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 {
	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 };
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)
	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)
{
{
	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,12 +454,16 @@ 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;


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

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


	mutex_unlock(&mixdev->mutex);
}



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


	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)
	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);
}
}