diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
| commit | 5c34202b8bf942da411b6599668a76b07449bbfd (patch) | |
| tree | 5719c361321eaddc8e4f1b0c8a7994f0e9a6fdd3 /drivers/input/joydev.c | |
| parent | 0d4804b31f91cfbcff6d62af0bc09a893a1c8ae0 (diff) | |
| parent | 1f8a6b658a943b4f04a1fc7b3a420360202c86cd (diff) | |
Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/input/joydev.c')
| -rw-r--r-- | drivers/input/joydev.c | 188 | 
1 files changed, 113 insertions, 75 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 9f3529ad3fd..06f0541b24d 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -24,7 +24,6 @@  #include <linux/module.h>  #include <linux/poll.h>  #include <linux/init.h> -#include <linux/smp_lock.h>  #include <linux/device.h>  MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); @@ -43,7 +42,7 @@ struct joydev {  	char name[16];  	struct input_handle handle;  	wait_queue_head_t wait; -	struct list_head list; +	struct list_head client_list;  	struct js_corr corr[ABS_MAX + 1];  	struct JS_DATA_SAVE_TYPE glue;  	int nabs; @@ -55,7 +54,7 @@ struct joydev {  	__s16 abs[ABS_MAX + 1];  }; -struct joydev_list { +struct joydev_client {  	struct js_event buffer[JOYDEV_BUFFER_SIZE];  	int head;  	int tail; @@ -87,7 +86,7 @@ static int joydev_correct(int value, struct js_corr *corr)  static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)  {  	struct joydev *joydev = handle->private; -	struct joydev_list *list; +	struct joydev_client *client;  	struct js_event event;  	switch (type) { @@ -115,15 +114,15 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne  	event.time = jiffies_to_msecs(jiffies); -	list_for_each_entry(list, &joydev->list, node) { +	list_for_each_entry(client, &joydev->client_list, node) { -		memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); +		memcpy(client->buffer + client->head, &event, sizeof(struct js_event)); -		if (list->startup == joydev->nabs + joydev->nkey) -			if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) -				list->startup = 0; +		if (client->startup == joydev->nabs + joydev->nkey) +			if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) +				client->startup = 0; -		kill_fasync(&list->fasync, SIGIO, POLL_IN); +		kill_fasync(&client->fasync, SIGIO, POLL_IN);  	}  	wake_up_interruptible(&joydev->wait); @@ -132,9 +131,9 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne  static int joydev_fasync(int fd, struct file *file, int on)  {  	int retval; -	struct joydev_list *list = file->private_data; +	struct joydev_client *client = file->private_data; -	retval = fasync_helper(fd, file, on, &list->fasync); +	retval = fasync_helper(fd, file, on, &client->fasync);  	return retval < 0 ? retval : 0;  } @@ -145,60 +144,73 @@ static void joydev_free(struct joydev *joydev)  	kfree(joydev);  } -static int joydev_release(struct inode * inode, struct file * file) +static int joydev_release(struct inode *inode, struct file *file)  { -	struct joydev_list *list = file->private_data; +	struct joydev_client *client = file->private_data; +	struct joydev *joydev = client->joydev;  	joydev_fasync(-1, file, 0); -	list_del(&list->node); +	list_del(&client->node); +	kfree(client); -	if (!--list->joydev->open) { -		if (list->joydev->exist) -			input_close_device(&list->joydev->handle); +	if (!--joydev->open) { +		if (joydev->exist) +			input_close_device(&joydev->handle);  		else -			joydev_free(list->joydev); +			joydev_free(joydev);  	} -	kfree(list);  	return 0;  }  static int joydev_open(struct inode *inode, struct file *file)  { -	struct joydev_list *list; +	struct joydev_client *client; +	struct joydev *joydev;  	int i = iminor(inode) - JOYDEV_MINOR_BASE; +	int error; + +	if (i >= JOYDEV_MINORS) +		return -ENODEV; -	if (i >= JOYDEV_MINORS || !joydev_table[i]) +	joydev = joydev_table[i]; +	if (!joydev || !joydev->exist)  		return -ENODEV; -	if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL))) +	client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); +	if (!client)  		return -ENOMEM; -	list->joydev = joydev_table[i]; -	list_add_tail(&list->node, &joydev_table[i]->list); -	file->private_data = list; +	client->joydev = joydev; +	list_add_tail(&client->node, &joydev->client_list); -	if (!list->joydev->open++) -		if (list->joydev->exist) -			input_open_device(&list->joydev->handle); +	if (!joydev->open++ && joydev->exist) { +		error = input_open_device(&joydev->handle); +		if (error) { +			list_del(&client->node); +			kfree(client); +			return error; +		} +	} +	file->private_data = client;  	return 0;  } -static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) +static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)  {  	return -EINVAL;  }  static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  { -	struct joydev_list *list = file->private_data; -	struct joydev *joydev = list->joydev; +	struct joydev_client *client = file->private_data; +	struct joydev *joydev = client->joydev;  	struct input_dev *input = joydev->handle.dev;  	int retval = 0; -	if (!list->joydev->exist) +	if (!joydev->exist)  		return -ENODEV;  	if (count < sizeof(struct js_event)) @@ -217,56 +229,55 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo  		if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))  			return -EFAULT; -		list->startup = 0; -		list->tail = list->head; +		client->startup = 0; +		client->tail = client->head;  		return sizeof(struct JS_DATA_TYPE);  	} -	if (list->startup == joydev->nabs + joydev->nkey && -	    list->head == list->tail && (file->f_flags & O_NONBLOCK)) +	if (client->startup == joydev->nabs + joydev->nkey && +	    client->head == client->tail && (file->f_flags & O_NONBLOCK))  		return -EAGAIN; -	retval = wait_event_interruptible(list->joydev->wait, -					  !list->joydev->exist || -					  list->startup < joydev->nabs + joydev->nkey || -					  list->head != list->tail); - +	retval = wait_event_interruptible(joydev->wait, +					  !joydev->exist || +					  client->startup < joydev->nabs + joydev->nkey || +					  client->head != client->tail);  	if (retval)  		return retval; -	if (!list->joydev->exist) +	if (!joydev->exist)  		return -ENODEV; -	while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { +	while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {  		struct js_event event;  		event.time = jiffies_to_msecs(jiffies); -		if (list->startup < joydev->nkey) { +		if (client->startup < joydev->nkey) {  			event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; -			event.number = list->startup; +			event.number = client->startup;  			event.value = !!test_bit(joydev->keypam[event.number], input->key);  		} else {  			event.type = JS_EVENT_AXIS | JS_EVENT_INIT; -			event.number = list->startup - joydev->nkey; +			event.number = client->startup - joydev->nkey;  			event.value = joydev->abs[event.number];  		}  		if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))  			return -EFAULT; -		list->startup++; +		client->startup++;  		retval += sizeof(struct js_event);  	} -	while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { +	while (client->head != client->tail && retval + sizeof(struct js_event) <= count) { -		if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) +		if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))  			return -EFAULT; -		list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); +		client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);  		retval += sizeof(struct js_event);  	} @@ -276,11 +287,12 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo  /* No kernel lock - fine */  static unsigned int joydev_poll(struct file *file, poll_table *wait)  { -	struct joydev_list *list = file->private_data; +	struct joydev_client *client = file->private_data; +	struct joydev *joydev = client->joydev; -	poll_wait(file, &list->joydev->wait, wait); -	return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? -		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); +	poll_wait(file, &joydev->wait, wait); +	return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ? +		(POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));  }  static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) @@ -374,8 +386,8 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u  #ifdef CONFIG_COMPAT  static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  { -	struct joydev_list *list = file->private_data; -	struct joydev *joydev = list->joydev; +	struct joydev_client *client = file->private_data; +	struct joydev *joydev = client->joydev;  	void __user *argp = (void __user *)arg;  	s32 tmp32;  	struct JS_DATA_SAVE_TYPE_32 ds32; @@ -428,8 +440,8 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo  static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  { -	struct joydev_list *list = file->private_data; -	struct joydev *joydev = list->joydev; +	struct joydev_client *client = file->private_data; +	struct joydev *joydev = client->joydev;  	void __user *argp = (void __user *)arg;  	if (!joydev->exist) @@ -465,23 +477,26 @@ static const struct file_operations joydev_fops = {  	.fasync =	joydev_fasync,  }; -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, -					   const struct input_device_id *id) +static int joydev_connect(struct input_handler *handler, struct input_dev *dev, +			  const struct input_device_id *id)  {  	struct joydev *joydev;  	struct class_device *cdev; +	dev_t devt;  	int i, j, t, minor; +	int error;  	for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);  	if (minor == JOYDEV_MINORS) {  		printk(KERN_ERR "joydev: no more free joydev devices\n"); -		return NULL; +		return -ENFILE;  	} -	if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL))) -		return NULL; +	joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); +	if (!joydev) +		return -ENOMEM; -	INIT_LIST_HEAD(&joydev->list); +	INIT_LIST_HEAD(&joydev->client_list);  	init_waitqueue_head(&joydev->wait);  	joydev->minor = minor; @@ -534,31 +549,54 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct  	joydev_table[minor] = joydev; -	cdev = class_device_create(&input_class, &dev->cdev, -			MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), -			dev->cdev.dev, joydev->name); +	devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor), + +	cdev = class_device_create(&input_class, &dev->cdev, devt, +				   dev->cdev.dev, joydev->name); +	if (IS_ERR(cdev)) { +		error = PTR_ERR(cdev); +		goto err_free_joydev; +	}  	/* temporary symlink to keep userspace happy */ -	sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj, -			  joydev->name); +	error = sysfs_create_link(&input_class.subsys.kobj, +				  &cdev->kobj, joydev->name); +	if (error) +		goto err_cdev_destroy; + +	error = input_register_handle(&joydev->handle); +	if (error) +		goto err_remove_link; + +	return 0; -	return &joydev->handle; + err_remove_link: +	sysfs_remove_link(&input_class.subsys.kobj, joydev->name); + err_cdev_destroy: +	class_device_destroy(&input_class, devt); + err_free_joydev: +	joydev_table[minor] = NULL; +	kfree(joydev); +	return error;  } +  static void joydev_disconnect(struct input_handle *handle)  {  	struct joydev *joydev = handle->private; -	struct joydev_list *list; +	struct joydev_client *client; + +	input_unregister_handle(handle); -	sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name); +	sysfs_remove_link(&input_class.subsys.kobj, joydev->name);  	class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));  	joydev->exist = 0;  	if (joydev->open) {  		input_close_device(handle);  		wake_up_interruptible(&joydev->wait); -		list_for_each_entry(list, &joydev->list, node) -			kill_fasync(&list->fasync, SIGIO, POLL_HUP); +		list_for_each_entry(client, &joydev->client_list, node) +			kill_fasync(&client->fasync, SIGIO, POLL_HUP);  	} else  		joydev_free(joydev);  }  | 
