diff options
Diffstat (limited to 'drivers/input/mousedev.c')
| -rw-r--r-- | drivers/input/mousedev.c | 294 | 
1 files changed, 155 insertions, 139 deletions
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 2a00ddf4f23..b604564dec5 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -9,9 +9,11 @@   * the Free Software Foundation.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #define MOUSEDEV_MINOR_BASE	32 -#define MOUSEDEV_MINORS		32 -#define MOUSEDEV_MIX		31 +#define MOUSEDEV_MINORS		31 +#define MOUSEDEV_MIX		63  #include <linux/sched.h>  #include <linux/slab.h> @@ -22,10 +24,8 @@  #include <linux/random.h>  #include <linux/major.h>  #include <linux/device.h> +#include <linux/cdev.h>  #include <linux/kernel.h> -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX -#include <linux/miscdevice.h> -#endif  MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");  MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); @@ -59,23 +59,26 @@ struct mousedev_hw_data {  struct mousedev {  	int open; -	int minor;  	struct input_handle handle;  	wait_queue_head_t wait;  	struct list_head client_list;  	spinlock_t client_lock; /* protects client_list */  	struct mutex mutex;  	struct device dev; +	struct cdev cdev;  	bool exist;  	struct list_head mixdev_node; -	int mixdev_open; +	bool opened_by_mixdev;  	struct mousedev_hw_data packet;  	unsigned int pkt_count;  	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 { @@ -112,16 +115,9 @@ struct mousedev_client {  static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };  static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; -static struct input_handler mousedev_handler; - -static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; -static DEFINE_MUTEX(mousedev_table_mutex);  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]) @@ -185,7 +181,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,  		if (size == 0)  			size = xres ? : 1; -		clamp(value, min, max); +		value = clamp(value, min, max);  		mousedev->packet.x = ((value - min) * xres) / size;  		mousedev->packet.abs_event = 1; @@ -199,7 +195,7 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,  		if (size == 0)  			size = yres ? : 1; -		clamp(value, min, max); +		value = clamp(value, min, max);  		mousedev->packet.y = yres - ((value - min) * yres) / size;  		mousedev->packet.abs_event = 1; @@ -431,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)  	if (retval)  		return retval; -	if (mousedev->minor == MOUSEDEV_MIX) -		mixdev_open_devices(); -	else if (!mousedev->exist) +	if (!mousedev->exist)  		retval = -ENODEV;  	else if (!mousedev->open++) {  		retval = input_open_device(&mousedev->handle); @@ -449,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)  {  	mutex_lock(&mousedev->mutex); -	if (mousedev->minor == MOUSEDEV_MIX) -		mixdev_close_devices(); -	else if (mousedev->exist && !--mousedev->open) +	if (mousedev->exist && !--mousedev->open)  		input_close_device(&mousedev->handle);  	mutex_unlock(&mousedev->mutex); @@ -462,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; -	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->mixdev_open) { -			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->mixdev_open = 1; +				mousedev->opened_by_mixdev = true; +			}  		}  	} + +	mutex_unlock(&mixdev->mutex); +	return 0;  }  /* @@ -484,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->mixdev_open) { -			mousedev->mixdev_open = 0; -			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);  } @@ -506,7 +509,6 @@ static void mousedev_attach_client(struct mousedev *mousedev,  	spin_lock(&mousedev->client_lock);  	list_add_tail_rcu(&client->node, &mousedev->client_list);  	spin_unlock(&mousedev->client_lock); -	synchronize_rcu();  }  static void mousedev_detach_client(struct mousedev *mousedev, @@ -526,8 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)  	mousedev_detach_client(mousedev, client);  	kfree(client); -	mousedev_close_device(mousedev); -	put_device(&mousedev->dev); +	mousedev->close_device(mousedev);  	return 0;  } @@ -537,36 +538,17 @@ static int mousedev_open(struct inode *inode, struct file *file)  	struct mousedev_client *client;  	struct mousedev *mousedev;  	int error; -	int i;  #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX  	if (imajor(inode) == MISC_MAJOR) -		i = MOUSEDEV_MIX; +		mousedev = mousedev_mix;  	else  #endif -		i = iminor(inode) - MOUSEDEV_MINOR_BASE; - -	if (i >= MOUSEDEV_MINORS) -		return -ENODEV; - -	error = mutex_lock_interruptible(&mousedev_table_mutex); -	if (error) { -		return error; -	} -	mousedev = mousedev_table[i]; -	if (mousedev) -		get_device(&mousedev->dev); -	mutex_unlock(&mousedev_table_mutex); - -	if (!mousedev) { -		return -ENODEV; -	} +		mousedev = container_of(inode->i_cdev, struct mousedev, cdev);  	client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); -	if (!client) { -		error = -ENOMEM; -		goto err_put_mousedev; -	} +	if (!client) +		return -ENOMEM;  	spin_lock_init(&client->packet_lock);  	client->pos_x = xres / 2; @@ -574,18 +556,18 @@ 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;  	file->private_data = client; +	nonseekable_open(inode, file); +  	return 0;   err_free_client:  	mousedev_detach_client(mousedev, client);  	kfree(client); - err_put_mousedev: -	put_device(&mousedev->dev);  	return error;  } @@ -785,29 +767,16 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)  }  static const struct file_operations mousedev_fops = { -	.owner =	THIS_MODULE, -	.read =		mousedev_read, -	.write =	mousedev_write, -	.poll =		mousedev_poll, -	.open =		mousedev_open, -	.release =	mousedev_release, -	.fasync =	mousedev_fasync, -	.llseek = noop_llseek, +	.owner		= THIS_MODULE, +	.read		= mousedev_read, +	.write		= mousedev_write, +	.poll		= mousedev_poll, +	.open		= mousedev_open, +	.release	= mousedev_release, +	.fasync		= mousedev_fasync, +	.llseek		= noop_llseek,  }; -static int mousedev_install_chrdev(struct mousedev *mousedev) -{ -	mousedev_table[mousedev->minor] = mousedev; -	return 0; -} - -static void mousedev_remove_chrdev(struct mousedev *mousedev) -{ -	mutex_lock(&mousedev_table_mutex); -	mousedev_table[mousedev->minor] = NULL; -	mutex_unlock(&mousedev_table_mutex); -} -  /*   * Mark device non-existent. This disables writes, ioctls and   * prevents new users from opening the device. Already posted @@ -842,24 +811,50 @@ static void mousedev_cleanup(struct mousedev *mousedev)  	mousedev_mark_dead(mousedev);  	mousedev_hangup(mousedev); -	mousedev_remove_chrdev(mousedev); + +	cdev_del(&mousedev->cdev);  	/* mousedev is marked dead so no one else accesses mousedev->open */  	if (mousedev->open)  		input_close_device(handle);  } +static int mousedev_reserve_minor(bool mixdev) +{ +	int minor; + +	if (mixdev) { +		minor = input_get_new_minor(MOUSEDEV_MIX, 1, false); +		if (minor < 0) +			pr_err("failed to reserve mixdev minor: %d\n", minor); +	} else { +		minor = input_get_new_minor(MOUSEDEV_MINOR_BASE, +					    MOUSEDEV_MINORS, true); +		if (minor < 0) +			pr_err("failed to reserve new minor: %d\n", minor); +	} + +	return minor; +} +  static struct mousedev *mousedev_create(struct input_dev *dev,  					struct input_handler *handler, -					int minor) +					bool mixdev)  {  	struct mousedev *mousedev; +	int minor;  	int error; +	minor = mousedev_reserve_minor(mixdev); +	if (minor < 0) { +		error = minor; +		goto err_out; +	} +  	mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);  	if (!mousedev) {  		error = -ENOMEM; -		goto err_out; +		goto err_free_minor;  	}  	INIT_LIST_HEAD(&mousedev->client_list); @@ -867,15 +862,25 @@ static struct mousedev *mousedev_create(struct input_dev *dev,  	spin_lock_init(&mousedev->client_lock);  	mutex_init(&mousedev->mutex);  	lockdep_set_subclass(&mousedev->mutex, -			     minor == MOUSEDEV_MIX ? SINGLE_DEPTH_NESTING : 0); +			     mixdev ? SINGLE_DEPTH_NESTING : 0);  	init_waitqueue_head(&mousedev->wait); -	if (minor == MOUSEDEV_MIX) +	if (mixdev) {  		dev_set_name(&mousedev->dev, "mice"); -	else -		dev_set_name(&mousedev->dev, "mouse%d", minor); -	mousedev->minor = minor; +		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->handle.dev = input_get_device(dev);  	mousedev->handle.name = dev_name(&mousedev->dev); @@ -885,17 +890,19 @@ static struct mousedev *mousedev_create(struct input_dev *dev,  	mousedev->dev.class = &input_class;  	if (dev)  		mousedev->dev.parent = &dev->dev; -	mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); +	mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor);  	mousedev->dev.release = mousedev_free;  	device_initialize(&mousedev->dev); -	if (minor != MOUSEDEV_MIX) { +	if (!mixdev) {  		error = input_register_handle(&mousedev->handle);  		if (error)  			goto err_free_mousedev;  	} -	error = mousedev_install_chrdev(mousedev); +	cdev_init(&mousedev->cdev, &mousedev_fops); +	mousedev->cdev.kobj.parent = &mousedev->dev.kobj; +	error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1);  	if (error)  		goto err_unregister_handle; @@ -908,10 +915,12 @@ static struct mousedev *mousedev_create(struct input_dev *dev,   err_cleanup_mousedev:  	mousedev_cleanup(mousedev);   err_unregister_handle: -	if (minor != MOUSEDEV_MIX) +	if (!mixdev)  		input_unregister_handle(&mousedev->handle);   err_free_mousedev:  	put_device(&mousedev->dev); + err_free_minor: +	input_free_minor(minor);   err_out:  	return ERR_PTR(error);  } @@ -920,7 +929,8 @@ static void mousedev_destroy(struct mousedev *mousedev)  {  	device_del(&mousedev->dev);  	mousedev_cleanup(mousedev); -	if (mousedev->minor != MOUSEDEV_MIX) +	input_free_minor(MINOR(mousedev->dev.devt)); +	if (mousedev != mousedev_mix)  		input_unregister_handle(&mousedev->handle);  	put_device(&mousedev->dev);  } @@ -938,7 +948,7 @@ static int mixdev_add_device(struct mousedev *mousedev)  		if (retval)  			goto out; -		mousedev->mixdev_open = 1; +		mousedev->opened_by_mixdev = true;  	}  	get_device(&mousedev->dev); @@ -953,8 +963,8 @@ static void mixdev_remove_device(struct mousedev *mousedev)  {  	mutex_lock(&mousedev_mix->mutex); -	if (mousedev->mixdev_open) { -		mousedev->mixdev_open = 0; +	if (mousedev->opened_by_mixdev) { +		mousedev->opened_by_mixdev = false;  		mousedev_close_device(mousedev);  	} @@ -969,19 +979,9 @@ static int mousedev_connect(struct input_handler *handler,  			    const struct input_device_id *id)  {  	struct mousedev *mousedev; -	int minor;  	int error; -	for (minor = 0; minor < MOUSEDEV_MINORS; minor++) -		if (!mousedev_table[minor]) -			break; - -	if (minor == MOUSEDEV_MINORS) { -		printk(KERN_ERR "mousedev: no more free mousedev devices\n"); -		return -ENFILE; -	} - -	mousedev = mousedev_create(dev, handler, minor); +	mousedev = mousedev_create(dev, handler, false);  	if (IS_ERR(mousedev))  		return PTR_ERR(mousedev); @@ -1054,27 +1054,53 @@ static const struct input_device_id mousedev_ids[] = {  MODULE_DEVICE_TABLE(input, mousedev_ids);  static struct input_handler mousedev_handler = { -	.event =	mousedev_event, -	.connect =	mousedev_connect, -	.disconnect =	mousedev_disconnect, -	.fops =		&mousedev_fops, -	.minor =	MOUSEDEV_MINOR_BASE, -	.name =		"mousedev", -	.id_table =	mousedev_ids, +	.event		= mousedev_event, +	.connect	= mousedev_connect, +	.disconnect	= mousedev_disconnect, +	.legacy_minors	= true, +	.minor		= MOUSEDEV_MINOR_BASE, +	.name		= "mousedev", +	.id_table	= mousedev_ids,  };  #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX +#include <linux/miscdevice.h> +  static struct miscdevice psaux_mouse = { -	PSMOUSE_MINOR, "psaux", &mousedev_fops +	.minor	= PSMOUSE_MINOR, +	.name	= "psaux", +	.fops	= &mousedev_fops,  }; -static int psaux_registered; + +static bool psaux_registered; + +static void __init mousedev_psaux_register(void) +{ +	int error; + +	error = misc_register(&psaux_mouse); +	if (error) +		pr_warn("could not register psaux device, error: %d\n", +			   error); +	else +		psaux_registered = true; +} + +static void __exit mousedev_psaux_unregister(void) +{ +	if (psaux_registered) +		misc_deregister(&psaux_mouse); +} +#else +static inline void mousedev_psaux_register(void) { } +static inline void mousedev_psaux_unregister(void) { }  #endif  static int __init mousedev_init(void)  {  	int error; -	mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); +	mousedev_mix = mousedev_create(NULL, &mousedev_handler, true);  	if (IS_ERR(mousedev_mix))  		return PTR_ERR(mousedev_mix); @@ -1084,26 +1110,16 @@ static int __init mousedev_init(void)  		return error;  	} -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX -	error = misc_register(&psaux_mouse); -	if (error) -		printk(KERN_WARNING "mice: could not register psaux device, " -			"error: %d\n", error); -	else -		psaux_registered = 1; -#endif +	mousedev_psaux_register(); -	printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); +	pr_info("PS/2 mouse device common for all mice\n");  	return 0;  }  static void __exit mousedev_exit(void)  { -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX -	if (psaux_registered) -		misc_deregister(&psaux_mouse); -#endif +	mousedev_psaux_unregister();  	input_unregister_handler(&mousedev_handler);  	mousedev_destroy(mousedev_mix);  }  | 
