diff options
Diffstat (limited to 'drivers/input/joydev.c')
| -rw-r--r-- | drivers/input/joydev.c | 99 | 
1 files changed, 37 insertions, 62 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 9d424cebfd2..f362883c94e 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -10,8 +10,9 @@   * (at your option) any later version.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <asm/io.h> -#include <asm/system.h>  #include <linux/delay.h>  #include <linux/errno.h>  #include <linux/joystick.h> @@ -26,6 +27,7 @@  #include <linux/poll.h>  #include <linux/init.h>  #include <linux/device.h> +#include <linux/cdev.h>  MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");  MODULE_DESCRIPTION("Joystick device interfaces"); @@ -38,13 +40,13 @@ MODULE_LICENSE("GPL");  struct joydev {  	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 js_corr corr[ABS_CNT]; @@ -69,9 +71,6 @@ struct joydev_client {  	struct list_head node;  }; -static struct joydev *joydev_table[JOYDEV_MINORS]; -static DEFINE_MUTEX(joydev_table_mutex); -  static int joydev_correct(int value, struct js_corr *corr)  {  	switch (corr->type) { @@ -178,7 +177,6 @@ static void joydev_attach_client(struct joydev *joydev,  	spin_lock(&joydev->client_lock);  	list_add_tail_rcu(&client->node, &joydev->client_list);  	spin_unlock(&joydev->client_lock); -	synchronize_rcu();  }  static void joydev_detach_client(struct joydev *joydev, @@ -245,37 +243,20 @@ static int joydev_release(struct inode *inode, struct file *file)  	kfree(client);  	joydev_close_device(joydev); -	put_device(&joydev->dev);  	return 0;  }  static int joydev_open(struct inode *inode, struct file *file)  { +	struct joydev *joydev = +			container_of(inode->i_cdev, struct joydev, cdev);  	struct joydev_client *client; -	struct joydev *joydev; -	int i = iminor(inode) - JOYDEV_MINOR_BASE;  	int error; -	if (i >= JOYDEV_MINORS) -		return -ENODEV; - -	error = mutex_lock_interruptible(&joydev_table_mutex); -	if (error) -		return error; -	joydev = joydev_table[i]; -	if (joydev) -		get_device(&joydev->dev); -	mutex_unlock(&joydev_table_mutex); - -	if (!joydev) -		return -ENODEV; -  	client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); -	if (!client) { -		error = -ENOMEM; -		goto err_put_joydev; -	} +	if (!client) +		return -ENOMEM;  	spin_lock_init(&client->buffer_lock);  	client->joydev = joydev; @@ -293,8 +274,6 @@ static int joydev_open(struct inode *inode, struct file *file)   err_free_client:  	joydev_detach_client(joydev, client);  	kfree(client); - err_put_joydev: -	put_device(&joydev->dev);  	return error;  } @@ -711,7 +690,7 @@ static long joydev_ioctl(struct file *file,  	case JS_SET_ALL:  		retval = copy_from_user(&joydev->glue, argp, -					sizeof(joydev->glue)) ? -EFAULT: 0; +					sizeof(joydev->glue)) ? -EFAULT : 0;  		break;  	case JS_GET_ALL: @@ -742,21 +721,8 @@ static const struct file_operations joydev_fops = {  	.llseek		= no_llseek,  }; -static int joydev_install_chrdev(struct joydev *joydev) -{ -	joydev_table[joydev->minor] = joydev; -	return 0; -} - -static void joydev_remove_chrdev(struct joydev *joydev) -{ -	mutex_lock(&joydev_table_mutex); -	joydev_table[joydev->minor] = NULL; -	mutex_unlock(&joydev_table_mutex); -} -  /* - * Mark device non-existant. This disables writes, ioctls and + * Mark device non-existent. This disables writes, ioctls and   * prevents new users from opening the device. Already posted   * blocking reads will stay, however new ones will fail.   */ @@ -773,9 +739,10 @@ static void joydev_cleanup(struct joydev *joydev)  	joydev_mark_dead(joydev);  	joydev_hangup(joydev); -	joydev_remove_chrdev(joydev); -	/* joydev is marked dead so noone else accesses joydev->open */ +	cdev_del(&joydev->cdev); + +	/* joydev is marked dead so no one else accesses joydev->open */  	if (joydev->open)  		input_close_device(handle);  } @@ -798,30 +765,33 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,  			  const struct input_device_id *id)  {  	struct joydev *joydev; -	int i, j, t, minor; +	int i, j, t, minor, dev_no;  	int error; -	for (minor = 0; minor < JOYDEV_MINORS; minor++) -		if (!joydev_table[minor]) -			break; - -	if (minor == JOYDEV_MINORS) { -		printk(KERN_ERR "joydev: no more free joydev devices\n"); -		return -ENFILE; +	minor = input_get_new_minor(JOYDEV_MINOR_BASE, JOYDEV_MINORS, true); +	if (minor < 0) { +		error = minor; +		pr_err("failed to reserve new minor: %d\n", error); +		return error;  	}  	joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); -	if (!joydev) -		return -ENOMEM; +	if (!joydev) { +		error = -ENOMEM; +		goto err_free_minor; +	}  	INIT_LIST_HEAD(&joydev->client_list);  	spin_lock_init(&joydev->client_lock);  	mutex_init(&joydev->mutex);  	init_waitqueue_head(&joydev->wait); - -	dev_set_name(&joydev->dev, "js%d", minor);  	joydev->exist = true; -	joydev->minor = minor; + +	dev_no = minor; +	/* Normalize device number if it falls into legacy range */ +	if (dev_no < JOYDEV_MINOR_BASE + JOYDEV_MINORS) +		dev_no -= JOYDEV_MINOR_BASE; +	dev_set_name(&joydev->dev, "js%d", dev_no);  	joydev->handle.dev = input_get_device(dev);  	joydev->handle.name = dev_name(&joydev->dev); @@ -875,7 +845,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,  		}  	} -	joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); +	joydev->dev.devt = MKDEV(INPUT_MAJOR, minor);  	joydev->dev.class = &input_class;  	joydev->dev.parent = &dev->dev;  	joydev->dev.release = joydev_free; @@ -885,7 +855,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,  	if (error)  		goto err_free_joydev; -	error = joydev_install_chrdev(joydev); +	cdev_init(&joydev->cdev, &joydev_fops); +	joydev->cdev.kobj.parent = &joydev->dev.kobj; +	error = cdev_add(&joydev->cdev, joydev->dev.devt, 1);  	if (error)  		goto err_unregister_handle; @@ -901,6 +873,8 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,  	input_unregister_handle(&joydev->handle);   err_free_joydev:  	put_device(&joydev->dev); + err_free_minor: +	input_free_minor(minor);  	return error;  } @@ -910,6 +884,7 @@ static void joydev_disconnect(struct input_handle *handle)  	device_del(&joydev->dev);  	joydev_cleanup(joydev); +	input_free_minor(MINOR(joydev->dev.devt));  	input_unregister_handle(handle);  	put_device(&joydev->dev);  } @@ -961,7 +936,7 @@ static struct input_handler joydev_handler = {  	.match		= joydev_match,  	.connect	= joydev_connect,  	.disconnect	= joydev_disconnect, -	.fops		= &joydev_fops, +	.legacy_minors	= true,  	.minor		= JOYDEV_MINOR_BASE,  	.name		= "joydev",  	.id_table	= joydev_ids,  | 
