--- /dev/null
+From 6addb1d6de1968b84852f54561cc9a999909b5a9 Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Thu, 30 Aug 2007 00:22:18 -0400
+Subject: Input: evdev - implement proper locking
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch 6addb1d6de1968b84852f54561cc9a999909b5a9 in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/evdev.c | 719 +++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 476 insertions(+), 243 deletions(-)
+
+--- a/drivers/input/evdev.c
++++ b/drivers/input/evdev.c
+@@ -30,6 +30,8 @@ struct evdev {
+ wait_queue_head_t wait;
+ struct evdev_client *grab;
+ struct list_head client_list;
++ spinlock_t client_lock; /* protects client_list */
++ struct mutex mutex;
+ struct device dev;
+ };
+
+@@ -37,39 +39,53 @@ struct evdev_client {
+ struct input_event buffer[EVDEV_BUFFER_SIZE];
+ int head;
+ int tail;
++ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+ struct fasync_struct *fasync;
+ struct evdev *evdev;
+ struct list_head node;
+ };
+
+ static struct evdev *evdev_table[EVDEV_MINORS];
++static DEFINE_MUTEX(evdev_table_mutex);
+
+-static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++static void evdev_pass_event(struct evdev_client *client,
++ struct input_event *event)
++{
++ /*
++ * Interrupts are disabled, just acquire the lock
++ */
++ spin_lock(&client->buffer_lock);
++ client->buffer[client->head++] = *event;
++ client->head &= EVDEV_BUFFER_SIZE - 1;
++ spin_unlock(&client->buffer_lock);
++
++ kill_fasync(&client->fasync, SIGIO, POLL_IN);
++}
++
++/*
++ * Pass incoming event to all connected clients. Note that we are
++ * caleld under a spinlock with interrupts off so we don't need
++ * to use rcu_read_lock() here. Writers will be using syncronize_sched()
++ * instead of synchrnoize_rcu().
++ */
++static void evdev_event(struct input_handle *handle,
++ unsigned int type, unsigned int code, int value)
+ {
+ struct evdev *evdev = handle->private;
+ struct evdev_client *client;
++ struct input_event event;
+
+- if (evdev->grab) {
+- client = evdev->grab;
+-
+- do_gettimeofday(&client->buffer[client->head].time);
+- client->buffer[client->head].type = type;
+- client->buffer[client->head].code = code;
+- client->buffer[client->head].value = value;
+- client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+-
+- kill_fasync(&client->fasync, SIGIO, POLL_IN);
+- } else
+- list_for_each_entry(client, &evdev->client_list, node) {
+-
+- do_gettimeofday(&client->buffer[client->head].time);
+- client->buffer[client->head].type = type;
+- client->buffer[client->head].code = code;
+- client->buffer[client->head].value = value;
+- client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+-
+- kill_fasync(&client->fasync, SIGIO, POLL_IN);
+- }
++ do_gettimeofday(&event.time);
++ event.type = type;
++ event.code = code;
++ event.value = value;
++
++ client = rcu_dereference(evdev->grab);
++ if (client)
++ evdev_pass_event(client, &event);
++ else
++ list_for_each_entry_rcu(client, &evdev->client_list, node)
++ evdev_pass_event(client, &event);
+
+ wake_up_interruptible(&evdev->wait);
+ }
+@@ -88,38 +104,142 @@ static int evdev_flush(struct file *file
+ {
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
++ int retval;
++
++ retval = mutex_lock_interruptible(&evdev->mutex);
++ if (retval)
++ return retval;
+
+ if (!evdev->exist)
+- return -ENODEV;
++ retval = -ENODEV;
++ else
++ retval = input_flush_device(&evdev->handle, file);
+
+- return input_flush_device(&evdev->handle, file);
++ mutex_unlock(&evdev->mutex);
++ return retval;
+ }
+
+ static void evdev_free(struct device *dev)
+ {
+ struct evdev *evdev = container_of(dev, struct evdev, dev);
+
+- evdev_table[evdev->minor] = NULL;
+ kfree(evdev);
+ }
+
++/*
++ * Grabs an event device (along with underlying input device).
++ * This function is called with evdev->mutex taken.
++ */
++static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
++{
++ int error;
++
++ if (evdev->grab)
++ return -EBUSY;
++
++ error = input_grab_device(&evdev->handle);
++ if (error)
++ return error;
++
++ rcu_assign_pointer(evdev->grab, client);
++ /*
++ * We don't use synchronize_rcu() here because read-side
++ * critical section is protected by a spinlock instead
++ * of rcu_read_lock().
++ */
++ synchronize_sched();
++
++ return 0;
++}
++
++static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
++{
++ if (evdev->grab != client)
++ return -EINVAL;
++
++ rcu_assign_pointer(evdev->grab, NULL);
++ synchronize_sched();
++ input_release_device(&evdev->handle);
++
++ return 0;
++}
++
++static void evdev_attach_client(struct evdev *evdev,
++ struct evdev_client *client)
++{
++ spin_lock(&evdev->client_lock);
++ list_add_tail_rcu(&client->node, &evdev->client_list);
++ spin_unlock(&evdev->client_lock);
++ synchronize_sched();
++}
++
++static void evdev_detach_client(struct evdev *evdev,
++ struct evdev_client *client)
++{
++ spin_lock(&evdev->client_lock);
++ list_del_rcu(&client->node);
++ spin_unlock(&evdev->client_lock);
++ synchronize_sched();
++}
++
++static int evdev_open_device(struct evdev *evdev)
++{
++ int retval;
++
++ retval = mutex_lock_interruptible(&evdev->mutex);
++ if (retval)
++ return retval;
++
++ if (!evdev->exist)
++ retval = -ENODEV;
++ else if (!evdev->open++)
++ retval = input_open_device(&evdev->handle);
++
++ mutex_unlock(&evdev->mutex);
++ return retval;
++}
++
++static void evdev_close_device(struct evdev *evdev)
++{
++ mutex_lock(&evdev->mutex);
++
++ if (evdev->exist && !--evdev->open)
++ input_close_device(&evdev->handle);
++
++ mutex_unlock(&evdev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void evdev_hangup(struct evdev *evdev)
++{
++ struct evdev_client *client;
++
++ spin_lock(&evdev->client_lock);
++ list_for_each_entry(client, &evdev->client_list, node)
++ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++ spin_unlock(&evdev->client_lock);
++
++ wake_up_interruptible(&evdev->wait);
++}
++
+ static int evdev_release(struct inode *inode, struct file *file)
+ {
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
+
+- if (evdev->grab == client) {
+- input_release_device(&evdev->handle);
+- evdev->grab = NULL;
+- }
++ mutex_lock(&evdev->mutex);
++ if (evdev->grab == client)
++ evdev_ungrab(evdev, client);
++ mutex_unlock(&evdev->mutex);
+
+ evdev_fasync(-1, file, 0);
+- list_del(&client->node);
++ evdev_detach_client(evdev, client);
+ kfree(client);
+
+- if (!--evdev->open && evdev->exist)
+- input_close_device(&evdev->handle);
+-
++ evdev_close_device(evdev);
+ put_device(&evdev->dev);
+
+ return 0;
+@@ -127,41 +247,44 @@ static int evdev_release(struct inode *i
+
+ static int evdev_open(struct inode *inode, struct file *file)
+ {
+- struct evdev_client *client;
+ struct evdev *evdev;
++ struct evdev_client *client;
+ int i = iminor(inode) - EVDEV_MINOR_BASE;
+ int error;
+
+ if (i >= EVDEV_MINORS)
+ return -ENODEV;
+
++ error = mutex_lock_interruptible(&evdev_table_mutex);
++ if (error)
++ return error;
+ evdev = evdev_table[i];
++ if (evdev)
++ get_device(&evdev->dev);
++ mutex_unlock(&evdev_table_mutex);
+
+- if (!evdev || !evdev->exist)
++ if (!evdev)
+ return -ENODEV;
+
+- get_device(&evdev->dev);
+-
+ client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+ if (!client) {
+ error = -ENOMEM;
+ goto err_put_evdev;
+ }
+
++ spin_lock_init(&client->buffer_lock);
+ client->evdev = evdev;
+- list_add_tail(&client->node, &evdev->client_list);
++ evdev_attach_client(evdev, client);
+
+- if (!evdev->open++ && evdev->exist) {
+- error = input_open_device(&evdev->handle);
+- if (error)
+- goto err_free_client;
+- }
++ error = evdev_open_device(evdev);
++ if (error)
++ goto err_free_client;
+
+ file->private_data = client;
+ return 0;
+
+ err_free_client:
+- list_del(&client->node);
++ evdev_detach_client(evdev, client);
+ kfree(client);
+ err_put_evdev:
+ put_device(&evdev->dev);
+@@ -197,12 +320,14 @@ static inline size_t evdev_event_size(vo
+ sizeof(struct input_event_compat) : sizeof(struct input_event);
+ }
+
+-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
++static int evdev_event_from_user(const char __user *buffer,
++ struct input_event *event)
+ {
+ if (COMPAT_TEST) {
+ struct input_event_compat compat_event;
+
+- if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat)))
++ if (copy_from_user(&compat_event, buffer,
++ sizeof(struct input_event_compat)))
+ return -EFAULT;
+
+ event->time.tv_sec = compat_event.time.tv_sec;
+@@ -219,7 +344,8 @@ static int evdev_event_from_user(const c
+ return 0;
+ }
+
+-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
++static int evdev_event_to_user(char __user *buffer,
++ const struct input_event *event)
+ {
+ if (COMPAT_TEST) {
+ struct input_event_compat compat_event;
+@@ -230,7 +356,8 @@ static int evdev_event_to_user(char __us
+ compat_event.code = event->code;
+ compat_event.value = event->value;
+
+- if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
++ if (copy_to_user(buffer, &compat_event,
++ sizeof(struct input_event_compat)))
+ return -EFAULT;
+
+ } else {
+@@ -248,7 +375,8 @@ static inline size_t evdev_event_size(vo
+ return sizeof(struct input_event);
+ }
+
+-static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
++static int evdev_event_from_user(const char __user *buffer,
++ struct input_event *event)
+ {
+ if (copy_from_user(event, buffer, sizeof(struct input_event)))
+ return -EFAULT;
+@@ -256,7 +384,8 @@ static int evdev_event_from_user(const c
+ return 0;
+ }
+
+-static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
++static int evdev_event_to_user(char __user *buffer,
++ const struct input_event *event)
+ {
+ if (copy_to_user(buffer, event, sizeof(struct input_event)))
+ return -EFAULT;
+@@ -266,37 +395,71 @@ static int evdev_event_to_user(char __us
+
+ #endif /* CONFIG_COMPAT */
+
+-static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
++static ssize_t evdev_write(struct file *file, const char __user *buffer,
++ size_t count, loff_t *ppos)
+ {
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
+ struct input_event event;
+- int retval = 0;
++ int retval;
+
+- if (!evdev->exist)
+- return -ENODEV;
++ retval = mutex_lock_interruptible(&evdev->mutex);
++ if (retval)
++ return retval;
++
++ if (!evdev->exist) {
++ retval = -ENODEV;
++ goto out;
++ }
+
+ while (retval < count) {
+
+- if (evdev_event_from_user(buffer + retval, &event))
+- return -EFAULT;
+- input_inject_event(&evdev->handle, event.type, event.code, event.value);
++ if (evdev_event_from_user(buffer + retval, &event)) {
++ retval = -EFAULT;
++ goto out;
++ }
++
++ input_inject_event(&evdev->handle,
++ event.type, event.code, event.value);
+ retval += evdev_event_size();
+ }
+
++ out:
++ mutex_unlock(&evdev->mutex);
+ return retval;
+ }
+
+-static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
++static int evdev_fetch_next_event(struct evdev_client *client,
++ struct input_event *event)
++{
++ int have_event;
++
++ spin_lock_irq(&client->buffer_lock);
++
++ have_event = client->head != client->tail;
++ if (have_event) {
++ *event = client->buffer[client->tail++];
++ client->tail &= EVDEV_BUFFER_SIZE - 1;
++ }
++
++ spin_unlock_irq(&client->buffer_lock);
++
++ return have_event;
++}
++
++static ssize_t evdev_read(struct file *file, char __user *buffer,
++ size_t count, loff_t *ppos)
+ {
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
++ struct input_event event;
+ int retval;
+
+ if (count < evdev_event_size())
+ return -EINVAL;
+
+- if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
++ if (client->head == client->tail && evdev->exist &&
++ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ retval = wait_event_interruptible(evdev->wait,
+@@ -307,14 +470,12 @@ static ssize_t evdev_read(struct file *f
+ if (!evdev->exist)
+ return -ENODEV;
+
+- while (client->head != client->tail && retval + evdev_event_size() <= count) {
+-
+- struct input_event *event = (struct input_event *) client->buffer + client->tail;
++ while (retval + evdev_event_size() <= count &&
++ evdev_fetch_next_event(client, &event)) {
+
+- if (evdev_event_to_user(buffer + retval, event))
++ if (evdev_event_to_user(buffer + retval, &event))
+ return -EFAULT;
+
+- client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+ retval += evdev_event_size();
+ }
+
+@@ -409,8 +570,8 @@ static int str_to_user(const char *str,
+ return copy_to_user(p, str, len) ? -EFAULT : len;
+ }
+
+-static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
+- void __user *p, int compat_mode)
++static long evdev_do_ioctl(struct file *file, unsigned int cmd,
++ void __user *p, int compat_mode)
+ {
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
+@@ -421,186 +582,208 @@ static long evdev_ioctl_handler(struct f
+ int i, t, u, v;
+ int error;
+
+- if (!evdev->exist)
+- return -ENODEV;
+-
+ switch (cmd) {
+
+- case EVIOCGVERSION:
+- return put_user(EV_VERSION, ip);
++ case EVIOCGVERSION:
++ return put_user(EV_VERSION, ip);
+
+- case EVIOCGID:
+- if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
+- return -EFAULT;
+- return 0;
++ case EVIOCGID:
++ if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
++ return -EFAULT;
++ return 0;
+
+- case EVIOCGREP:
+- if (!test_bit(EV_REP, dev->evbit))
+- return -ENOSYS;
+- if (put_user(dev->rep[REP_DELAY], ip))
+- return -EFAULT;
+- if (put_user(dev->rep[REP_PERIOD], ip + 1))
+- return -EFAULT;
+- return 0;
++ case EVIOCGREP:
++ if (!test_bit(EV_REP, dev->evbit))
++ return -ENOSYS;
++ if (put_user(dev->rep[REP_DELAY], ip))
++ return -EFAULT;
++ if (put_user(dev->rep[REP_PERIOD], ip + 1))
++ return -EFAULT;
++ return 0;
+
+- case EVIOCSREP:
+- if (!test_bit(EV_REP, dev->evbit))
+- return -ENOSYS;
+- if (get_user(u, ip))
+- return -EFAULT;
+- if (get_user(v, ip + 1))
+- return -EFAULT;
++ case EVIOCSREP:
++ if (!test_bit(EV_REP, dev->evbit))
++ return -ENOSYS;
++ if (get_user(u, ip))
++ return -EFAULT;
++ if (get_user(v, ip + 1))
++ return -EFAULT;
+
+- input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
+- input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
++ input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
++ input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
+
+- return 0;
++ return 0;
+
+- case EVIOCGKEYCODE:
+- if (get_user(t, ip))
+- return -EFAULT;
++ case EVIOCGKEYCODE:
++ if (get_user(t, ip))
++ return -EFAULT;
+
+- error = dev->getkeycode(dev, t, &v);
+- if (error)
+- return error;
++ error = dev->getkeycode(dev, t, &v);
++ if (error)
++ return error;
+
+- if (put_user(v, ip + 1))
+- return -EFAULT;
++ if (put_user(v, ip + 1))
++ return -EFAULT;
+
+- return 0;
++ return 0;
+
+- case EVIOCSKEYCODE:
+- if (get_user(t, ip) || get_user(v, ip + 1))
+- return -EFAULT;
++ case EVIOCSKEYCODE:
++ if (get_user(t, ip) || get_user(v, ip + 1))
++ return -EFAULT;
+
+- return dev->setkeycode(dev, t, v);
++ return dev->setkeycode(dev, t, v);
+
+- case EVIOCSFF:
+- if (copy_from_user(&effect, p, sizeof(effect)))
+- return -EFAULT;
++ case EVIOCSFF:
++ if (copy_from_user(&effect, p, sizeof(effect)))
++ return -EFAULT;
+
+- error = input_ff_upload(dev, &effect, file);
++ error = input_ff_upload(dev, &effect, file);
+
+- if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
+- return -EFAULT;
++ if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
++ return -EFAULT;
+
+- return error;
++ return error;
+
+- case EVIOCRMFF:
+- return input_ff_erase(dev, (int)(unsigned long) p, file);
++ case EVIOCRMFF:
++ return input_ff_erase(dev, (int)(unsigned long) p, file);
+
+- case EVIOCGEFFECTS:
+- i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
+- if (put_user(i, ip))
+- return -EFAULT;
+- return 0;
++ case EVIOCGEFFECTS:
++ i = test_bit(EV_FF, dev->evbit) ?
++ dev->ff->max_effects : 0;
++ if (put_user(i, ip))
++ return -EFAULT;
++ return 0;
+
+- case EVIOCGRAB:
+- if (p) {
+- if (evdev->grab)
+- return -EBUSY;
+- if (input_grab_device(&evdev->handle))
+- return -EBUSY;
+- evdev->grab = client;
+- return 0;
+- } else {
+- if (evdev->grab != client)
+- return -EINVAL;
+- input_release_device(&evdev->handle);
+- evdev->grab = NULL;
+- return 0;
++ case EVIOCGRAB:
++ if (p)
++ return evdev_grab(evdev, client);
++ else
++ return evdev_ungrab(evdev, client);
++
++ default:
++
++ if (_IOC_TYPE(cmd) != 'E')
++ return -EINVAL;
++
++ if (_IOC_DIR(cmd) == _IOC_READ) {
++
++ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) {
++
++ unsigned long *bits;
++ int len;
++
++ switch (_IOC_NR(cmd) & EV_MAX) {
++
++ case 0: bits = dev->evbit; len = EV_MAX; break;
++ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
++ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
++ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
++ case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
++ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
++ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
++ case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
++ case EV_SW: bits = dev->swbit; len = SW_MAX; break;
++ default: return -EINVAL;
++ }
++ return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
+ }
+
+- default:
++ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
++ return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
++ p, compat_mode);
+
+- if (_IOC_TYPE(cmd) != 'E')
+- return -EINVAL;
++ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
++ return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
++ p, compat_mode);
+
+- if (_IOC_DIR(cmd) == _IOC_READ) {
++ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
++ return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
++ p, compat_mode);
+
+- if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
++ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
++ return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
++ p, compat_mode);
+
+- unsigned long *bits;
+- int len;
++ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
++ return str_to_user(dev->name, _IOC_SIZE(cmd), p);
+
+- switch (_IOC_NR(cmd) & EV_MAX) {
+- case 0: bits = dev->evbit; len = EV_MAX; break;
+- case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+- case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+- case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+- case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+- case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+- case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+- case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
+- case EV_SW: bits = dev->swbit; len = SW_MAX; break;
+- default: return -EINVAL;
+- }
+- return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
+- }
++ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
++ return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
+
+- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+- return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
+- p, compat_mode);
++ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
++ return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
+
+- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+- return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
+- p, compat_mode);
++ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+- return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
+- p, compat_mode);
++ t = _IOC_NR(cmd) & ABS_MAX;
+
+- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
+- return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
+- p, compat_mode);
++ abs.value = dev->abs[t];
++ abs.minimum = dev->absmin[t];
++ abs.maximum = dev->absmax[t];
++ abs.fuzz = dev->absfuzz[t];
++ abs.flat = dev->absflat[t];
+
+- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
+- return str_to_user(dev->name, _IOC_SIZE(cmd), p);
++ if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
++ return -EFAULT;
+
+- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
+- return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
++ return 0;
++ }
+
+- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
+- return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
++ }
+
+- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
++ if (_IOC_DIR(cmd) == _IOC_WRITE) {
+
+- t = _IOC_NR(cmd) & ABS_MAX;
++ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+
+- abs.value = dev->abs[t];
+- abs.minimum = dev->absmin[t];
+- abs.maximum = dev->absmax[t];
+- abs.fuzz = dev->absfuzz[t];
+- abs.flat = dev->absflat[t];
++ t = _IOC_NR(cmd) & ABS_MAX;
+
+- if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+- return -EFAULT;
++ if (copy_from_user(&abs, p,
++ sizeof(struct input_absinfo)))
++ return -EFAULT;
++
++ /*
++ * Take event lock to ensure that we are not
++ * changing device parameters in the middle
++ * of event.
++ */
++ spin_lock_irq(&dev->event_lock);
++
++ dev->abs[t] = abs.value;
++ dev->absmin[t] = abs.minimum;
++ dev->absmax[t] = abs.maximum;
++ dev->absfuzz[t] = abs.fuzz;
++ dev->absflat[t] = abs.flat;
+
+- return 0;
+- }
++ spin_unlock_irq(&dev->event_lock);
+
++ return 0;
+ }
++ }
++ }
++ return -EINVAL;
++}
+
+- if (_IOC_DIR(cmd) == _IOC_WRITE) {
+-
+- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
++static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
++ void __user *p, int compat_mode)
++{
++ struct evdev_client *client = file->private_data;
++ struct evdev *evdev = client->evdev;
++ int retval;
+
+- t = _IOC_NR(cmd) & ABS_MAX;
++ retval = mutex_lock_interruptible(&evdev->mutex);
++ if (retval)
++ return retval;
+
+- if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+- return -EFAULT;
++ if (!evdev->exist) {
++ retval = -ENODEV;
++ goto out;
++ }
+
+- dev->abs[t] = abs.value;
+- dev->absmin[t] = abs.minimum;
+- dev->absmax[t] = abs.maximum;
+- dev->absfuzz[t] = abs.fuzz;
+- dev->absflat[t] = abs.flat;
++ retval = evdev_do_ioctl(file, cmd, p, compat_mode);
+
+- return 0;
+- }
+- }
+- }
+- return -EINVAL;
++ out:
++ mutex_unlock(&evdev->mutex);
++ return retval;
+ }
+
+ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+@@ -609,27 +792,79 @@ static long evdev_ioctl(struct file *fil
+ }
+
+ #ifdef CONFIG_COMPAT
+-static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
++static long evdev_ioctl_compat(struct file *file,
++ unsigned int cmd, unsigned long arg)
+ {
+ return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
+ }
+ #endif
+
+ static const struct file_operations evdev_fops = {
+- .owner = THIS_MODULE,
+- .read = evdev_read,
+- .write = evdev_write,
+- .poll = evdev_poll,
+- .open = evdev_open,
+- .release = evdev_release,
+- .unlocked_ioctl = evdev_ioctl,
++ .owner = THIS_MODULE,
++ .read = evdev_read,
++ .write = evdev_write,
++ .poll = evdev_poll,
++ .open = evdev_open,
++ .release = evdev_release,
++ .unlocked_ioctl = evdev_ioctl,
+ #ifdef CONFIG_COMPAT
+- .compat_ioctl = evdev_ioctl_compat,
++ .compat_ioctl = evdev_ioctl_compat,
+ #endif
+- .fasync = evdev_fasync,
+- .flush = evdev_flush
++ .fasync = evdev_fasync,
++ .flush = evdev_flush
+ };
+
++static int evdev_install_chrdev(struct evdev *evdev)
++{
++ /*
++ * No need to do any locking here as calls to connect and
++ * disconnect are serialized by the input core
++ */
++ evdev_table[evdev->minor] = evdev;
++ return 0;
++}
++
++static void evdev_remove_chrdev(struct evdev *evdev)
++{
++ /*
++ * Lock evdev table to prevent race with evdev_open()
++ */
++ mutex_lock(&evdev_table_mutex);
++ evdev_table[evdev->minor] = NULL;
++ mutex_unlock(&evdev_table_mutex);
++}
++
++/*
++ * 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.
++ */
++static void evdev_mark_dead(struct evdev *evdev)
++{
++ mutex_lock(&evdev->mutex);
++ evdev->exist = 0;
++ mutex_unlock(&evdev->mutex);
++}
++
++static void evdev_cleanup(struct evdev *evdev)
++{
++ struct input_handle *handle = &evdev->handle;
++
++ evdev_mark_dead(evdev);
++ evdev_hangup(evdev);
++ evdev_remove_chrdev(evdev);
++
++ /* evdev is marked dead so no one else accesses evdev->open */
++ if (evdev->open) {
++ input_flush_device(handle, NULL);
++ input_close_device(handle);
++ }
++}
++
++/*
++ * Create new evdev device. Note that input core serializes calls
++ * to connect and disconnect so we don't need to lock evdev_table here.
++ */
+ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+ {
+@@ -637,7 +872,10 @@ static int evdev_connect(struct input_ha
+ int minor;
+ int error;
+
+- for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
++ for (minor = 0; minor < EVDEV_MINORS; minor++)
++ if (!evdev_table[minor])
++ break;
++
+ if (minor == EVDEV_MINORS) {
+ printk(KERN_ERR "evdev: no more free evdev devices\n");
+ return -ENFILE;
+@@ -648,38 +886,44 @@ static int evdev_connect(struct input_ha
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&evdev->client_list);
++ spin_lock_init(&evdev->client_lock);
++ mutex_init(&evdev->mutex);
+ init_waitqueue_head(&evdev->wait);
+
++ snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
+ evdev->exist = 1;
+ evdev->minor = minor;
++
+ evdev->handle.dev = dev;
+ evdev->handle.name = evdev->name;
+ evdev->handle.handler = handler;
+ evdev->handle.private = evdev;
+- snprintf(evdev->name, sizeof(evdev->name), "event%d", minor);
+
+- snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id),
+- "event%d", minor);
++ strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id));
++ evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
+ evdev->dev.class = &input_class;
+ evdev->dev.parent = &dev->dev;
+- evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);
+ evdev->dev.release = evdev_free;
+ device_initialize(&evdev->dev);
+
+- evdev_table[minor] = evdev;
+-
+- error = device_add(&evdev->dev);
++ error = input_register_handle(&evdev->handle);
+ if (error)
+ goto err_free_evdev;
+
+- error = input_register_handle(&evdev->handle);
++ error = evdev_install_chrdev(evdev);
++ if (error)
++ goto err_unregister_handle;
++
++ error = device_add(&evdev->dev);
+ if (error)
+- goto err_delete_evdev;
++ goto err_cleanup_evdev;
+
+ return 0;
+
+- err_delete_evdev:
+- device_del(&evdev->dev);
++ err_cleanup_evdev:
++ evdev_cleanup(evdev);
++ err_unregister_handle:
++ input_unregister_handle(&evdev->handle);
+ err_free_evdev:
+ put_device(&evdev->dev);
+ return error;
+@@ -688,21 +932,10 @@ static int evdev_connect(struct input_ha
+ static void evdev_disconnect(struct input_handle *handle)
+ {
+ struct evdev *evdev = handle->private;
+- struct evdev_client *client;
+
+- input_unregister_handle(handle);
+ device_del(&evdev->dev);
+-
+- evdev->exist = 0;
+-
+- if (evdev->open) {
+- input_flush_device(handle, NULL);
+- input_close_device(handle);
+- list_for_each_entry(client, &evdev->client_list, node)
+- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+- wake_up_interruptible(&evdev->wait);
+- }
+-
++ evdev_cleanup(evdev);
++ input_unregister_handle(handle);
+ put_device(&evdev->dev);
+ }
+
+@@ -714,13 +947,13 @@ static const struct input_device_id evde
+ MODULE_DEVICE_TABLE(input, evdev_ids);
+
+ static struct input_handler evdev_handler = {
+- .event = evdev_event,
+- .connect = evdev_connect,
+- .disconnect = evdev_disconnect,
+- .fops = &evdev_fops,
+- .minor = EVDEV_MINOR_BASE,
+- .name = "evdev",
+- .id_table = evdev_ids,
++ .event = evdev_event,
++ .connect = evdev_connect,
++ .disconnect = evdev_disconnect,
++ .fops = &evdev_fops,
++ .minor = EVDEV_MINOR_BASE,
++ .name = "evdev",
++ .id_table = evdev_ids,
+ };
+
+ static int __init evdev_init(void)
--- /dev/null
+From 064450140f1eab959bd0eca0245f449993216074 Mon Sep 17 00:00:00 2001
+From: Oliver Neukum <oliver@neukum.org>
+Date: Fri, 12 Oct 2007 14:18:40 -0400
+Subject: [PATCH] Input: fix open count handling in input interfaces
+
+From: Oliver Neukum <oliver@neukum.org>
+
+patch 064450140f1eab959bd0eca0245f449993216074 in mainline.
+
+If input_open_device() fails we should not leave interfaces marked
+as opened.
+
+Signed-off-by: Oliver Neukum <oneukum@suse.de>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/evdev.c | 5 ++++-
+ drivers/input/joydev.c | 5 ++++-
+ drivers/input/mousedev.c | 5 ++++-
+ drivers/input/tsdev.c | 5 ++++-
+ 4 files changed, 16 insertions(+), 4 deletions(-)
+
+--- a/drivers/input/evdev.c
++++ b/drivers/input/evdev.c
+@@ -188,8 +188,11 @@ static int evdev_open_device(struct evde
+
+ if (!evdev->exist)
+ retval = -ENODEV;
+- else if (!evdev->open++)
++ else if (!evdev->open++) {
+ retval = input_open_device(&evdev->handle);
++ if (retval)
++ evdev->open--;
++ }
+
+ mutex_unlock(&evdev->mutex);
+ return retval;
+--- a/drivers/input/joydev.c
++++ b/drivers/input/joydev.c
+@@ -202,8 +202,11 @@ static int joydev_open_device(struct joy
+
+ if (!joydev->exist)
+ retval = -ENODEV;
+- else if (!joydev->open++)
++ else if (!joydev->open++) {
+ retval = input_open_device(&joydev->handle);
++ if (retval)
++ joydev->open--;
++ }
+
+ mutex_unlock(&joydev->mutex);
+ return retval;
+--- a/drivers/input/mousedev.c
++++ b/drivers/input/mousedev.c
+@@ -430,8 +430,11 @@ static int mousedev_open_device(struct m
+ mixdev_open_devices();
+ else if (!mousedev->exist)
+ retval = -ENODEV;
+- else if (!mousedev->open++)
++ else if (!mousedev->open++) {
+ retval = input_open_device(&mousedev->handle);
++ if (retval)
++ mousedev->open--;
++ }
+
+ mutex_unlock(&mousedev->mutex);
+ return retval;
+--- a/drivers/input/tsdev.c
++++ b/drivers/input/tsdev.c
+@@ -185,8 +185,11 @@ static int tsdev_open_device(struct tsde
+
+ if (!tsdev->exist)
+ retval = -ENODEV;
+- else if (!tsdev->open++)
++ else if (!tsdev->open++) {
+ retval = input_open_device(&tsdev->handle);
++ if (retval)
++ tsdev->open--;
++ }
+
+ mutex_unlock(&tsdev->mutex);
+ return retval;
--- /dev/null
+From 8006479c9b75fb6594a7b746af3d7f1fbb68f18f Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Thu, 30 Aug 2007 00:22:11 -0400
+Subject: Input: implement proper locking in input core
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch 8006479c9b75fb6594a7b746af3d7f1fbb68f18f in mainline.
+
+Also add some kerneldoc documentation to input.h
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/input.c | 666 ++++++++++++++++++++++++++++++++++++--------------
+ include/linux/input.h | 112 +++++++-
+ 2 files changed, 595 insertions(+), 183 deletions(-)
+
+--- a/drivers/input/input.c
++++ b/drivers/input/input.c
+@@ -17,10 +17,10 @@
+ #include <linux/major.h>
+ #include <linux/proc_fs.h>
+ #include <linux/seq_file.h>
+-#include <linux/interrupt.h>
+ #include <linux/poll.h>
+ #include <linux/device.h>
+ #include <linux/mutex.h>
++#include <linux/rcupdate.h>
+
+ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+ MODULE_DESCRIPTION("Input core");
+@@ -31,167 +31,244 @@ MODULE_LICENSE("GPL");
+ static LIST_HEAD(input_dev_list);
+ static LIST_HEAD(input_handler_list);
+
++/*
++ * input_mutex protects access to both input_dev_list and input_handler_list.
++ * This also causes input_[un]register_device and input_[un]register_handler
++ * be mutually exclusive which simplifies locking in drivers implementing
++ * input handlers.
++ */
++static DEFINE_MUTEX(input_mutex);
++
+ static struct input_handler *input_table[8];
+
+-/**
+- * input_event() - report new input event
+- * @dev: device that generated the event
+- * @type: type of the event
+- * @code: event code
+- * @value: value of the event
+- *
+- * This function should be used by drivers implementing various input devices
+- * See also input_inject_event()
+- */
+-void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
++static inline int is_event_supported(unsigned int code,
++ unsigned long *bm, unsigned int max)
+ {
+- struct input_handle *handle;
++ return code <= max && test_bit(code, bm);
++}
+
+- if (type > EV_MAX || !test_bit(type, dev->evbit))
+- return;
++static int input_defuzz_abs_event(int value, int old_val, int fuzz)
++{
++ if (fuzz) {
++ if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2)
++ return old_val;
+
+- add_input_randomness(type, code, value);
++ if (value > old_val - fuzz && value < old_val + fuzz)
++ return (old_val * 3 + value) / 4;
+
+- switch (type) {
++ if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2)
++ return (old_val + value) / 2;
++ }
+
+- case EV_SYN:
+- switch (code) {
+- case SYN_CONFIG:
+- if (dev->event)
+- dev->event(dev, type, code, value);
+- break;
+-
+- case SYN_REPORT:
+- if (dev->sync)
+- return;
+- dev->sync = 1;
+- break;
+- }
+- break;
++ return value;
++}
+
+- case EV_KEY:
++/*
++ * Pass event through all open handles. This function is called with
++ * dev->event_lock held and interrupts disabled. Because of that we
++ * do not need to use rcu_read_lock() here although we are using RCU
++ * to access handle list. Note that because of that write-side uses
++ * synchronize_sched() instead of synchronize_ru().
++ */
++static void input_pass_event(struct input_dev *dev,
++ unsigned int type, unsigned int code, int value)
++{
++ struct input_handle *handle = rcu_dereference(dev->grab);
+
+- if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
+- return;
++ if (handle)
++ handle->handler->event(handle, type, code, value);
++ else
++ list_for_each_entry_rcu(handle, &dev->h_list, d_node)
++ if (handle->open)
++ handle->handler->event(handle,
++ type, code, value);
++}
+
+- if (value == 2)
+- break;
++/*
++ * Generate software autorepeat event. Note that we take
++ * dev->event_lock here to avoid racing with input_event
++ * which may cause keys get "stuck".
++ */
++static void input_repeat_key(unsigned long data)
++{
++ struct input_dev *dev = (void *) data;
++ unsigned long flags;
+
+- change_bit(code, dev->key);
++ spin_lock_irqsave(&dev->event_lock, flags);
+
+- if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) {
+- dev->repeat_key = code;
+- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
+- }
++ if (test_bit(dev->repeat_key, dev->key) &&
++ is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) {
+
+- break;
++ input_pass_event(dev, EV_KEY, dev->repeat_key, 2);
+
+- case EV_SW:
++ if (dev->sync) {
++ /*
++ * Only send SYN_REPORT if we are not in a middle
++ * of driver parsing a new hardware packet.
++ * Otherwise assume that the driver will send
++ * SYN_REPORT once it's done.
++ */
++ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
++ }
+
+- if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value)
+- return;
++ if (dev->rep[REP_PERIOD])
++ mod_timer(&dev->timer, jiffies +
++ msecs_to_jiffies(dev->rep[REP_PERIOD]));
++ }
+
+- change_bit(code, dev->sw);
++ spin_unlock_irqrestore(&dev->event_lock, flags);
++}
+
+- break;
++static void input_start_autorepeat(struct input_dev *dev, int code)
++{
++ if (test_bit(EV_REP, dev->evbit) &&
++ dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
++ dev->timer.data) {
++ dev->repeat_key = code;
++ mod_timer(&dev->timer,
++ jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
++ }
++}
+
+- case EV_ABS:
++#define INPUT_IGNORE_EVENT 0
++#define INPUT_PASS_TO_HANDLERS 1
++#define INPUT_PASS_TO_DEVICE 2
++#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE)
+
+- if (code > ABS_MAX || !test_bit(code, dev->absbit))
+- return;
++static void input_handle_event(struct input_dev *dev,
++ unsigned int type, unsigned int code, int value)
++{
++ int disposition = INPUT_IGNORE_EVENT;
+
+- if (dev->absfuzz[code]) {
+- if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) &&
+- (value < dev->abs[code] + (dev->absfuzz[code] >> 1)))
+- return;
+-
+- if ((value > dev->abs[code] - dev->absfuzz[code]) &&
+- (value < dev->abs[code] + dev->absfuzz[code]))
+- value = (dev->abs[code] * 3 + value) >> 2;
+-
+- if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) &&
+- (value < dev->abs[code] + (dev->absfuzz[code] << 1)))
+- value = (dev->abs[code] + value) >> 1;
+- }
++ switch (type) {
+
+- if (dev->abs[code] == value)
+- return;
++ case EV_SYN:
++ switch (code) {
++ case SYN_CONFIG:
++ disposition = INPUT_PASS_TO_ALL;
++ break;
+
+- dev->abs[code] = value;
++ case SYN_REPORT:
++ if (!dev->sync) {
++ dev->sync = 1;
++ disposition = INPUT_PASS_TO_HANDLERS;
++ }
+ break;
++ }
++ break;
+
+- case EV_REL:
++ case EV_KEY:
++ if (is_event_supported(code, dev->keybit, KEY_MAX) &&
++ !!test_bit(code, dev->key) != value) {
+
+- if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0))
+- return;
++ if (value != 2) {
++ __change_bit(code, dev->key);
++ if (value)
++ input_start_autorepeat(dev, code);
++ }
+
+- break;
++ disposition = INPUT_PASS_TO_HANDLERS;
++ }
++ break;
+
+- case EV_MSC:
++ case EV_SW:
++ if (is_event_supported(code, dev->swbit, SW_MAX) &&
++ !!test_bit(code, dev->sw) != value) {
+
+- if (code > MSC_MAX || !test_bit(code, dev->mscbit))
+- return;
++ __change_bit(code, dev->sw);
++ disposition = INPUT_PASS_TO_HANDLERS;
++ }
++ break;
++
++ case EV_ABS:
++ if (is_event_supported(code, dev->absbit, ABS_MAX)) {
+
+- if (dev->event)
+- dev->event(dev, type, code, value);
++ value = input_defuzz_abs_event(value,
++ dev->abs[code], dev->absfuzz[code]);
+
+- break;
++ if (dev->abs[code] != value) {
++ dev->abs[code] = value;
++ disposition = INPUT_PASS_TO_HANDLERS;
++ }
++ }
++ break;
+
+- case EV_LED:
++ case EV_REL:
++ if (is_event_supported(code, dev->relbit, REL_MAX) && value)
++ disposition = INPUT_PASS_TO_HANDLERS;
+
+- if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
+- return;
++ break;
+
+- change_bit(code, dev->led);
++ case EV_MSC:
++ if (is_event_supported(code, dev->mscbit, MSC_MAX))
++ disposition = INPUT_PASS_TO_ALL;
+
+- if (dev->event)
+- dev->event(dev, type, code, value);
++ break;
+
+- break;
++ case EV_LED:
++ if (is_event_supported(code, dev->ledbit, LED_MAX) &&
++ !!test_bit(code, dev->led) != value) {
+
+- case EV_SND:
++ __change_bit(code, dev->led);
++ disposition = INPUT_PASS_TO_ALL;
++ }
++ break;
+
+- if (code > SND_MAX || !test_bit(code, dev->sndbit))
+- return;
++ case EV_SND:
++ if (is_event_supported(code, dev->sndbit, SND_MAX)) {
+
+ if (!!test_bit(code, dev->snd) != !!value)
+- change_bit(code, dev->snd);
++ __change_bit(code, dev->snd);
++ disposition = INPUT_PASS_TO_ALL;
++ }
++ break;
+
+- if (dev->event)
+- dev->event(dev, type, code, value);
++ case EV_REP:
++ if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) {
++ dev->rep[code] = value;
++ disposition = INPUT_PASS_TO_ALL;
++ }
++ break;
+
+- break;
++ case EV_FF:
++ if (value >= 0)
++ disposition = INPUT_PASS_TO_ALL;
++ break;
++ }
+
+- case EV_REP:
++ if (type != EV_SYN)
++ dev->sync = 0;
+
+- if (code > REP_MAX || value < 0 || dev->rep[code] == value)
+- return;
++ if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
++ dev->event(dev, type, code, value);
+
+- dev->rep[code] = value;
+- if (dev->event)
+- dev->event(dev, type, code, value);
++ if (disposition & INPUT_PASS_TO_HANDLERS)
++ input_pass_event(dev, type, code, value);
++}
+
+- break;
++/**
++ * input_event() - report new input event
++ * @dev: device that generated the event
++ * @type: type of the event
++ * @code: event code
++ * @value: value of the event
++ *
++ * This function should be used by drivers implementing various input
++ * devices. See also input_inject_event().
++ */
+
+- case EV_FF:
++void input_event(struct input_dev *dev,
++ unsigned int type, unsigned int code, int value)
++{
++ unsigned long flags;
+
+- if (value < 0)
+- return;
++ if (is_event_supported(type, dev->evbit, EV_MAX)) {
+
+- if (dev->event)
+- dev->event(dev, type, code, value);
+- break;
++ spin_lock_irqsave(&dev->event_lock, flags);
++ add_input_randomness(type, code, value);
++ input_handle_event(dev, type, code, value);
++ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+-
+- if (type != EV_SYN)
+- dev->sync = 0;
+-
+- if (dev->grab)
+- dev->grab->handler->event(dev->grab, type, code, value);
+- else
+- list_for_each_entry(handle, &dev->h_list, d_node)
+- if (handle->open)
+- handle->handler->event(handle, type, code, value);
+ }
+ EXPORT_SYMBOL(input_event);
+
+@@ -202,102 +279,230 @@ EXPORT_SYMBOL(input_event);
+ * @code: event code
+ * @value: value of the event
+ *
+- * Similar to input_event() but will ignore event if device is "grabbed" and handle
+- * injecting event is not the one that owns the device.
++ * Similar to input_event() but will ignore event if device is
++ * "grabbed" and handle injecting event is not the one that owns
++ * the device.
+ */
+-void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++void input_inject_event(struct input_handle *handle,
++ unsigned int type, unsigned int code, int value)
+ {
+- if (!handle->dev->grab || handle->dev->grab == handle)
+- input_event(handle->dev, type, code, value);
+-}
+-EXPORT_SYMBOL(input_inject_event);
+-
+-static void input_repeat_key(unsigned long data)
+-{
+- struct input_dev *dev = (void *) data;
++ struct input_dev *dev = handle->dev;
++ struct input_handle *grab;
++ unsigned long flags;
+
+- if (!test_bit(dev->repeat_key, dev->key))
+- return;
++ if (is_event_supported(type, dev->evbit, EV_MAX)) {
++ spin_lock_irqsave(&dev->event_lock, flags);
+
+- input_event(dev, EV_KEY, dev->repeat_key, 2);
+- input_sync(dev);
++ grab = rcu_dereference(dev->grab);
++ if (!grab || grab == handle)
++ input_handle_event(dev, type, code, value);
+
+- if (dev->rep[REP_PERIOD])
+- mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
++ spin_unlock_irqrestore(&dev->event_lock, flags);
++ }
+ }
++EXPORT_SYMBOL(input_inject_event);
+
++/**
++ * input_grab_device - grabs device for exclusive use
++ * @handle: input handle that wants to own the device
++ *
++ * When a device is grabbed by an input handle all events generated by
++ * the device are delivered only to this handle. Also events injected
++ * by other input handles are ignored while device is grabbed.
++ */
+ int input_grab_device(struct input_handle *handle)
+ {
+- if (handle->dev->grab)
+- return -EBUSY;
++ struct input_dev *dev = handle->dev;
++ int retval;
+
+- handle->dev->grab = handle;
+- return 0;
++ retval = mutex_lock_interruptible(&dev->mutex);
++ if (retval)
++ return retval;
++
++ if (dev->grab) {
++ retval = -EBUSY;
++ goto out;
++ }
++
++ rcu_assign_pointer(dev->grab, handle);
++ /*
++ * Not using synchronize_rcu() because read-side is protected
++ * by a spinlock with interrupts off instead of rcu_read_lock().
++ */
++ synchronize_sched();
++
++ out:
++ mutex_unlock(&dev->mutex);
++ return retval;
+ }
+ EXPORT_SYMBOL(input_grab_device);
+
+-void input_release_device(struct input_handle *handle)
++static void __input_release_device(struct input_handle *handle)
+ {
+ struct input_dev *dev = handle->dev;
+
+ if (dev->grab == handle) {
+- dev->grab = NULL;
++ rcu_assign_pointer(dev->grab, NULL);
++ /* Make sure input_pass_event() notices that grab is gone */
++ synchronize_sched();
+
+ list_for_each_entry(handle, &dev->h_list, d_node)
+- if (handle->handler->start)
++ if (handle->open && handle->handler->start)
+ handle->handler->start(handle);
+ }
+ }
++
++/**
++ * input_release_device - release previously grabbed device
++ * @handle: input handle that owns the device
++ *
++ * Releases previously grabbed device so that other input handles can
++ * start receiving input events. Upon release all handlers attached
++ * to the device have their start() method called so they have a change
++ * to synchronize device state with the rest of the system.
++ */
++void input_release_device(struct input_handle *handle)
++{
++ struct input_dev *dev = handle->dev;
++
++ mutex_lock(&dev->mutex);
++ __input_release_device(handle);
++ mutex_unlock(&dev->mutex);
++}
+ EXPORT_SYMBOL(input_release_device);
+
++/**
++ * input_open_device - open input device
++ * @handle: handle through which device is being accessed
++ *
++ * This function should be called by input handlers when they
++ * want to start receive events from given input device.
++ */
+ int input_open_device(struct input_handle *handle)
+ {
+ struct input_dev *dev = handle->dev;
+- int err;
++ int retval;
+
+- err = mutex_lock_interruptible(&dev->mutex);
+- if (err)
+- return err;
++ retval = mutex_lock_interruptible(&dev->mutex);
++ if (retval)
++ return retval;
++
++ if (dev->going_away) {
++ retval = -ENODEV;
++ goto out;
++ }
+
+ handle->open++;
+
+ if (!dev->users++ && dev->open)
+- err = dev->open(dev);
++ retval = dev->open(dev);
+
+- if (err)
+- handle->open--;
++ if (retval) {
++ dev->users--;
++ if (!--handle->open) {
++ /*
++ * Make sure we are not delivering any more events
++ * through this handle
++ */
++ synchronize_sched();
++ }
++ }
+
++ out:
+ mutex_unlock(&dev->mutex);
+-
+- return err;
++ return retval;
+ }
+ EXPORT_SYMBOL(input_open_device);
+
+-int input_flush_device(struct input_handle* handle, struct file* file)
++int input_flush_device(struct input_handle *handle, struct file *file)
+ {
+- if (handle->dev->flush)
+- return handle->dev->flush(handle->dev, file);
++ struct input_dev *dev = handle->dev;
++ int retval;
+
+- return 0;
++ retval = mutex_lock_interruptible(&dev->mutex);
++ if (retval)
++ return retval;
++
++ if (dev->flush)
++ retval = dev->flush(dev, file);
++
++ mutex_unlock(&dev->mutex);
++ return retval;
+ }
+ EXPORT_SYMBOL(input_flush_device);
+
++/**
++ * input_close_device - close input device
++ * @handle: handle through which device is being accessed
++ *
++ * This function should be called by input handlers when they
++ * want to stop receive events from given input device.
++ */
+ void input_close_device(struct input_handle *handle)
+ {
+ struct input_dev *dev = handle->dev;
+
+- input_release_device(handle);
+-
+ mutex_lock(&dev->mutex);
+
++ __input_release_device(handle);
++
+ if (!--dev->users && dev->close)
+ dev->close(dev);
+- handle->open--;
++
++ if (!--handle->open) {
++ /*
++ * synchronize_sched() makes sure that input_pass_event()
++ * completed and that no more input events are delivered
++ * through this handle
++ */
++ synchronize_sched();
++ }
+
+ mutex_unlock(&dev->mutex);
+ }
+ EXPORT_SYMBOL(input_close_device);
+
++/*
++ * Prepare device for unregistering
++ */
++static void input_disconnect_device(struct input_dev *dev)
++{
++ struct input_handle *handle;
++ int code;
++
++ /*
++ * Mark device as going away. Note that we take dev->mutex here
++ * not to protect access to dev->going_away but rather to ensure
++ * that there are no threads in the middle of input_open_device()
++ */
++ mutex_lock(&dev->mutex);
++ dev->going_away = 1;
++ mutex_unlock(&dev->mutex);
++
++ spin_lock_irq(&dev->event_lock);
++
++ /*
++ * Simulate keyup events for all pressed keys so that handlers
++ * are not left with "stuck" keys. The driver may continue
++ * generate events even after we done here but they will not
++ * reach any handlers.
++ */
++ if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
++ for (code = 0; code <= KEY_MAX; code++) {
++ if (is_event_supported(code, dev->keybit, KEY_MAX) &&
++ test_bit(code, dev->key)) {
++ input_pass_event(dev, EV_KEY, code, 0);
++ }
++ }
++ input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
++ }
++
++ list_for_each_entry(handle, &dev->h_list, d_node)
++ handle->open = 0;
++
++ spin_unlock_irq(&dev->event_lock);
++}
++
+ static int input_fetch_keycode(struct input_dev *dev, int scancode)
+ {
+ switch (dev->keycodesize) {
+@@ -473,7 +678,8 @@ static unsigned int input_proc_devices_p
+
+ static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+- /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
++ if (mutex_lock_interruptible(&input_mutex))
++ return NULL;
+
+ return seq_list_start(&input_dev_list, *pos);
+ }
+@@ -485,7 +691,7 @@ static void *input_devices_seq_next(stru
+
+ static void input_devices_seq_stop(struct seq_file *seq, void *v)
+ {
+- /* release lock here */
++ mutex_unlock(&input_mutex);
+ }
+
+ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
+@@ -569,7 +775,9 @@ static const struct file_operations inpu
+
+ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+- /* acquire lock here ... Yes, we do need locking, I knowi, I know... */
++ if (mutex_lock_interruptible(&input_mutex))
++ return NULL;
++
+ seq->private = (void *)(unsigned long)*pos;
+ return seq_list_start(&input_handler_list, *pos);
+ }
+@@ -582,7 +790,7 @@ static void *input_handlers_seq_next(str
+
+ static void input_handlers_seq_stop(struct seq_file *seq, void *v)
+ {
+- /* release lock here */
++ mutex_unlock(&input_mutex);
+ }
+
+ static int input_handlers_seq_show(struct seq_file *seq, void *v)
+@@ -1005,6 +1213,7 @@ struct input_dev *input_allocate_device(
+ dev->dev.class = &input_class;
+ device_initialize(&dev->dev);
+ mutex_init(&dev->mutex);
++ spin_lock_init(&dev->event_lock);
+ INIT_LIST_HEAD(&dev->h_list);
+ INIT_LIST_HEAD(&dev->node);
+
+@@ -1022,7 +1231,7 @@ EXPORT_SYMBOL(input_allocate_device);
+ * This function should only be used if input_register_device()
+ * was not called yet or if it failed. Once device was registered
+ * use input_unregister_device() and memory will be freed once last
+- * refrence to the device is dropped.
++ * reference to the device is dropped.
+ *
+ * Device should be allocated by input_allocate_device().
+ *
+@@ -1092,6 +1301,18 @@ void input_set_capability(struct input_d
+ }
+ EXPORT_SYMBOL(input_set_capability);
+
++/**
++ * input_register_device - register device with input core
++ * @dev: device to be registered
++ *
++ * This function registers device with input core. The device must be
++ * allocated with input_allocate_device() and all it's capabilities
++ * set up before registering.
++ * If function fails the device must be freed with input_free_device().
++ * Once device has been successfully registered it can be unregistered
++ * with input_unregister_device(); input_free_device() should not be
++ * called in this case.
++ */
+ int input_register_device(struct input_dev *dev)
+ {
+ static atomic_t input_no = ATOMIC_INIT(0);
+@@ -1099,7 +1320,7 @@ int input_register_device(struct input_d
+ const char *path;
+ int error;
+
+- set_bit(EV_SYN, dev->evbit);
++ __set_bit(EV_SYN, dev->evbit);
+
+ /*
+ * If delay and period are pre-set by the driver, then autorepeating
+@@ -1120,8 +1341,6 @@ int input_register_device(struct input_d
+ if (!dev->setkeycode)
+ dev->setkeycode = input_default_setkeycode;
+
+- list_add_tail(&dev->node, &input_dev_list);
+-
+ snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
+ "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
+
+@@ -1137,49 +1356,79 @@ int input_register_device(struct input_d
+ dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
+ kfree(path);
+
++ error = mutex_lock_interruptible(&input_mutex);
++ if (error) {
++ device_del(&dev->dev);
++ return error;
++ }
++
++ list_add_tail(&dev->node, &input_dev_list);
++
+ list_for_each_entry(handler, &input_handler_list, node)
+ input_attach_handler(dev, handler);
+
+ input_wakeup_procfs_readers();
+
++ mutex_unlock(&input_mutex);
++
+ return 0;
+ }
+ EXPORT_SYMBOL(input_register_device);
+
++/**
++ * input_unregister_device - unregister previously registered device
++ * @dev: device to be unregistered
++ *
++ * This function unregisters an input device. Once device is unregistered
++ * the caller should not try to access it as it may get freed at any moment.
++ */
+ void input_unregister_device(struct input_dev *dev)
+ {
+ struct input_handle *handle, *next;
+- int code;
+
+- for (code = 0; code <= KEY_MAX; code++)
+- if (test_bit(code, dev->key))
+- input_report_key(dev, code, 0);
+- input_sync(dev);
++ input_disconnect_device(dev);
+
+- del_timer_sync(&dev->timer);
++ mutex_lock(&input_mutex);
+
+ list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
+ handle->handler->disconnect(handle);
+ WARN_ON(!list_empty(&dev->h_list));
+
++ del_timer_sync(&dev->timer);
+ list_del_init(&dev->node);
+
+- device_unregister(&dev->dev);
+-
+ input_wakeup_procfs_readers();
++
++ mutex_unlock(&input_mutex);
++
++ device_unregister(&dev->dev);
+ }
+ EXPORT_SYMBOL(input_unregister_device);
+
++/**
++ * input_register_handler - register a new input handler
++ * @handler: handler to be registered
++ *
++ * This function registers a new input handler (interface) for input
++ * devices in the system and attaches it to all input devices that
++ * are compatible with the handler.
++ */
+ int input_register_handler(struct input_handler *handler)
+ {
+ struct input_dev *dev;
++ int retval;
++
++ retval = mutex_lock_interruptible(&input_mutex);
++ if (retval)
++ return retval;
+
+ INIT_LIST_HEAD(&handler->h_list);
+
+ if (handler->fops != NULL) {
+- if (input_table[handler->minor >> 5])
+- return -EBUSY;
+-
++ if (input_table[handler->minor >> 5]) {
++ retval = -EBUSY;
++ goto out;
++ }
+ input_table[handler->minor >> 5] = handler;
+ }
+
+@@ -1189,14 +1438,26 @@ int input_register_handler(struct input_
+ input_attach_handler(dev, handler);
+
+ input_wakeup_procfs_readers();
+- return 0;
++
++ out:
++ mutex_unlock(&input_mutex);
++ return retval;
+ }
+ EXPORT_SYMBOL(input_register_handler);
+
++/**
++ * input_unregister_handler - unregisters an input handler
++ * @handler: handler to be unregistered
++ *
++ * This function disconnects a handler from its input devices and
++ * removes it from lists of known handlers.
++ */
+ void input_unregister_handler(struct input_handler *handler)
+ {
+ struct input_handle *handle, *next;
+
++ mutex_lock(&input_mutex);
++
+ list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
+ handler->disconnect(handle);
+ WARN_ON(!list_empty(&handler->h_list));
+@@ -1207,14 +1468,50 @@ void input_unregister_handler(struct inp
+ input_table[handler->minor >> 5] = NULL;
+
+ input_wakeup_procfs_readers();
++
++ mutex_unlock(&input_mutex);
+ }
+ EXPORT_SYMBOL(input_unregister_handler);
+
++/**
++ * input_register_handle - register a new input handle
++ * @handle: handle to register
++ *
++ * This function puts a new input handle onto device's
++ * and handler's lists so that events can flow through
++ * it once it is opened using input_open_device().
++ *
++ * This function is supposed to be called from handler's
++ * connect() method.
++ */
+ int input_register_handle(struct input_handle *handle)
+ {
+ struct input_handler *handler = handle->handler;
++ struct input_dev *dev = handle->dev;
++ int error;
++
++ /*
++ * We take dev->mutex here to prevent race with
++ * input_release_device().
++ */
++ error = mutex_lock_interruptible(&dev->mutex);
++ if (error)
++ return error;
++ list_add_tail_rcu(&handle->d_node, &dev->h_list);
++ mutex_unlock(&dev->mutex);
++ /*
++ * We don't use synchronize_rcu() here because we rely
++ * on dev->event_lock to protect read-side critical
++ * section in input_pass_event().
++ */
++ synchronize_sched();
+
+- list_add_tail(&handle->d_node, &handle->dev->h_list);
++ /*
++ * Since we are supposed to be called from ->connect()
++ * which is mutually exclusive with ->disconnect()
++ * we can't be racing with input_unregister_handle()
++ * and so separate lock is not needed here.
++ */
+ list_add_tail(&handle->h_node, &handler->h_list);
+
+ if (handler->start)
+@@ -1224,10 +1521,29 @@ int input_register_handle(struct input_h
+ }
+ EXPORT_SYMBOL(input_register_handle);
+
++/**
++ * input_unregister_handle - unregister an input handle
++ * @handle: handle to unregister
++ *
++ * This function removes input handle from device's
++ * and handler's lists.
++ *
++ * This function is supposed to be called from handler's
++ * disconnect() method.
++ */
+ void input_unregister_handle(struct input_handle *handle)
+ {
++ struct input_dev *dev = handle->dev;
++
+ list_del_init(&handle->h_node);
+- list_del_init(&handle->d_node);
++
++ /*
++ * Take dev->mutex to prevent race with input_release_device().
++ */
++ mutex_lock(&dev->mutex);
++ list_del_rcu(&handle->d_node);
++ mutex_unlock(&dev->mutex);
++ synchronize_sched();
+ }
+ EXPORT_SYMBOL(input_unregister_handle);
+
+--- a/include/linux/input.h
++++ b/include/linux/input.h
+@@ -853,7 +853,7 @@ struct ff_rumble_effect {
+ * defining effect parameters
+ *
+ * This structure is sent through ioctl from the application to the driver.
+- * To create a new effect aplication should set its @id to -1; the kernel
++ * To create a new effect application should set its @id to -1; the kernel
+ * will return assigned @id which can later be used to update or delete
+ * this effect.
+ *
+@@ -933,9 +933,82 @@ struct ff_effect {
+ #define BIT(x) (1UL<<((x)%BITS_PER_LONG))
+ #define LONG(x) ((x)/BITS_PER_LONG)
+
++/**
++ * struct input_dev - represents an input device
++ * @name: name of the device
++ * @phys: physical path to the device in the system hierarchy
++ * @uniq: unique identification code for the device (if device has it)
++ * @id: id of the device (struct input_id)
++ * @evbit: bitmap of types of events supported by the device (EV_KEY,
++ * EV_REL, etc.)
++ * @keybit: bitmap of keys/buttons this device has
++ * @relbit: bitmap of relative axes for the device
++ * @absbit: bitmap of absolute axes for the device
++ * @mscbit: bitmap of miscellaneous events supported by the device
++ * @ledbit: bitmap of leds present on the device
++ * @sndbit: bitmap of sound effects supported by the device
++ * @ffbit: bitmap of force feedback effects supported by the device
++ * @swbit: bitmap of switches present on the device
++ * @keycodemax: size of keycode table
++ * @keycodesize: size of elements in keycode table
++ * @keycode: map of scancodes to keycodes for this device
++ * @setkeycode: optional method to alter current keymap, used to implement
++ * sparse keymaps. If not supplied default mechanism will be used
++ * @getkeycode: optional method to retrieve current keymap. If not supplied
++ * default mechanism will be used
++ * @ff: force feedback structure associated with the device if device
++ * supports force feedback effects
++ * @repeat_key: stores key code of the last key pressed; used to implement
++ * software autorepeat
++ * @timer: timer for software autorepeat
++ * @sync: set to 1 when there were no new events since last EV_SYNC
++ * @abs: current values for reports from absolute axes
++ * @rep: current values for autorepeat parameters (delay, rate)
++ * @key: reflects current state of device's keys/buttons
++ * @led: reflects current state of device's LEDs
++ * @snd: reflects current state of sound effects
++ * @sw: reflects current state of device's switches
++ * @absmax: maximum values for events coming from absolute axes
++ * @absmin: minimum values for events coming from absolute axes
++ * @absfuzz: describes noisiness for axes
++ * @absflat: size of the center flat position (used by joydev)
++ * @open: this method is called when the very first user calls
++ * input_open_device(). The driver must prepare the device
++ * to start generating events (start polling thread,
++ * request an IRQ, submit URB, etc.)
++ * @close: this method is called when the very last user calls
++ * input_close_device().
++ * @flush: purges the device. Most commonly used to get rid of force
++ * feedback effects loaded into the device when disconnecting
++ * from it
++ * @event: event handler for events sent _to_ the device, like EV_LED
++ * or EV_SND. The device is expected to carry out the requested
++ * action (turn on a LED, play sound, etc.) The call is protected
++ * by @event_lock and must not sleep
++ * @grab: input handle that currently has the device grabbed (via
++ * EVIOCGRAB ioctl). When a handle grabs a device it becomes sole
++ * recipient for all input events coming from the device
++ * @event_lock: this spinlock is is taken when input core receives
++ * and processes a new event for the device (in input_event()).
++ * Code that accesses and/or modifies parameters of a device
++ * (such as keymap or absmin, absmax, absfuzz, etc.) after device
++ * has been registered with input core must take this lock.
++ * @mutex: serializes calls to open(), close() and flush() methods
++ * @users: stores number of users (input handlers) that opened this
++ * device. It is used by input_open_device() and input_close_device()
++ * to make sure that dev->open() is only called when the first
++ * user opens device and dev->close() is called when the very
++ * last user closes the device
++ * @going_away: marks devices that are in a middle of unregistering and
++ * causes input_open_device*() fail with -ENODEV.
++ * @dev: driver model's view of this device
++ * @h_list: list of input handles associated with the device. When
++ * accessing the list dev->mutex must be held
++ * @node: used to place the device onto input_dev_list
++ */
+ struct input_dev {
+
+- void *private;
++ void *private; /* do not use */
+
+ const char *name;
+ const char *phys;
+@@ -963,8 +1036,6 @@ struct input_dev {
+ unsigned int repeat_key;
+ struct timer_list timer;
+
+- int state;
+-
+ int sync;
+
+ int abs[ABS_MAX + 1];
+@@ -987,8 +1058,11 @@ struct input_dev {
+
+ struct input_handle *grab;
+
+- struct mutex mutex; /* serializes open and close operations */
++ spinlock_t event_lock;
++ struct mutex mutex;
++
+ unsigned int users;
++ int going_away;
+
+ struct device dev;
+ union { /* temporarily so while we switching to struct device */
+@@ -1054,7 +1128,9 @@ struct input_handle;
+ /**
+ * struct input_handler - implements one of interfaces for input devices
+ * @private: driver-specific data
+- * @event: event handler
++ * @event: event handler. This method is being called by input core with
++ * interrupts disabled and dev->event_lock spinlock held and so
++ * it may not sleep
+ * @connect: called when attaching a handler to an input device
+ * @disconnect: disconnects a handler from input device
+ * @start: starts handler for given handle. This function is called by
+@@ -1066,10 +1142,18 @@ struct input_handle;
+ * @name: name of the handler, to be shown in /proc/bus/input/handlers
+ * @id_table: pointer to a table of input_device_ids this driver can
+ * handle
+- * @blacklist: prointer to a table of input_device_ids this driver should
++ * @blacklist: pointer to a table of input_device_ids this driver should
+ * ignore even if they match @id_table
+ * @h_list: list of input handles associated with the handler
+ * @node: for placing the driver onto input_handler_list
++ *
++ * Input handlers attach to input devices and create input handles. There
++ * are likely several handlers attached to any given input device at the
++ * same time. All of them will get their copy of input event generated by
++ * the device.
++ *
++ * Note that input core serializes calls to connect() and disconnect()
++ * methods.
+ */
+ struct input_handler {
+
+@@ -1091,6 +1175,18 @@ struct input_handler {
+ struct list_head node;
+ };
+
++/**
++ * struct input_handle - links input device with an input handler
++ * @private: handler-specific data
++ * @open: counter showing whether the handle is 'open', i.e. should deliver
++ * events from its device
++ * @name: name given to the handle by handler that created it
++ * @dev: input device the handle is attached to
++ * @handler: handler that works with the device through this handle
++ * @d_node: used to put the handle on device's list of attached handles
++ * @h_node: used to put the handle on handler's list of handles from which
++ * it gets events
++ */
+ struct input_handle {
+
+ void *private;
+@@ -1213,7 +1309,7 @@ extern struct class input_class;
+ * @max_effects: maximum number of effects supported by device
+ * @effects: pointer to an array of effects currently loaded into device
+ * @effect_owners: array of effect owners; when file handle owning
+- * an effect gets closed the effcet is automatically erased
++ * an effect gets closed the effect is automatically erased
+ *
+ * Every force-feedback device must implement upload() and playback()
+ * methods; erase() is optional. set_gain() and set_autocenter() need
--- /dev/null
+From b126207ccdfe492fbc339c18d4898b1b5353fc6b Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Thu, 30 Aug 2007 00:22:32 -0400
+Subject: [PATCH] Input: joydev - implement proper locking
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch b126207ccdfe492fbc339c18d4898b1b5353fc6b in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/joydev.c | 745 ++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 493 insertions(+), 252 deletions(-)
+
+--- a/drivers/input/joydev.c
++++ b/drivers/input/joydev.c
+@@ -43,6 +43,8 @@ struct joydev {
+ 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 js_corr corr[ABS_MAX + 1];
+@@ -61,31 +63,61 @@ struct joydev_client {
+ int head;
+ int tail;
+ int startup;
++ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+ struct fasync_struct *fasync;
+ struct joydev *joydev;
+ 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) {
+- case JS_CORR_NONE:
+- break;
+- case JS_CORR_BROKEN:
+- value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
+- ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
+- ((corr->coef[2] * (value - corr->coef[0])) >> 14);
+- break;
+- default:
+- return 0;
++
++ case JS_CORR_NONE:
++ break;
++
++ case JS_CORR_BROKEN:
++ value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
++ ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
++ ((corr->coef[2] * (value - corr->coef[0])) >> 14);
++ break;
++
++ default:
++ return 0;
+ }
+
+ return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
+ }
+
+-static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++static void joydev_pass_event(struct joydev_client *client,
++ struct js_event *event)
++{
++ struct joydev *joydev = client->joydev;
++
++ /*
++ * IRQs already disabled, just acquire the lock
++ */
++ spin_lock(&client->buffer_lock);
++
++ client->buffer[client->head] = *event;
++
++ if (client->startup == joydev->nabs + joydev->nkey) {
++ client->head++;
++ client->head &= JOYDEV_BUFFER_SIZE - 1;
++ if (client->tail == client->head)
++ client->startup = 0;
++ }
++
++ spin_unlock(&client->buffer_lock);
++
++ kill_fasync(&client->fasync, SIGIO, POLL_IN);
++}
++
++static void joydev_event(struct input_handle *handle,
++ unsigned int type, unsigned int code, int value)
+ {
+ struct joydev *joydev = handle->private;
+ struct joydev_client *client;
+@@ -93,39 +125,32 @@ static void joydev_event(struct input_ha
+
+ switch (type) {
+
+- case EV_KEY:
+- if (code < BTN_MISC || value == 2)
+- return;
+- event.type = JS_EVENT_BUTTON;
+- event.number = joydev->keymap[code - BTN_MISC];
+- event.value = value;
+- break;
+-
+- case EV_ABS:
+- event.type = JS_EVENT_AXIS;
+- event.number = joydev->absmap[code];
+- event.value = joydev_correct(value, joydev->corr + event.number);
+- if (event.value == joydev->abs[event.number])
+- return;
+- joydev->abs[event.number] = event.value;
+- break;
++ case EV_KEY:
++ if (code < BTN_MISC || value == 2)
++ return;
++ event.type = JS_EVENT_BUTTON;
++ event.number = joydev->keymap[code - BTN_MISC];
++ event.value = value;
++ break;
+
+- default:
++ case EV_ABS:
++ event.type = JS_EVENT_AXIS;
++ event.number = joydev->absmap[code];
++ event.value = joydev_correct(value,
++ &joydev->corr[event.number]);
++ if (event.value == joydev->abs[event.number])
+ return;
++ joydev->abs[event.number] = event.value;
++ break;
++
++ default:
++ return;
+ }
+
+ event.time = jiffies_to_msecs(jiffies);
+
+- list_for_each_entry(client, &joydev->client_list, node) {
+-
+- memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
+-
+- if (client->startup == joydev->nabs + joydev->nkey)
+- if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
+- client->startup = 0;
+-
+- kill_fasync(&client->fasync, SIGIO, POLL_IN);
+- }
++ list_for_each_entry_rcu(client, &joydev->client_list, node)
++ joydev_pass_event(client, &event);
+
+ wake_up_interruptible(&joydev->wait);
+ }
+@@ -144,23 +169,85 @@ static void joydev_free(struct device *d
+ {
+ struct joydev *joydev = container_of(dev, struct joydev, dev);
+
+- joydev_table[joydev->minor] = NULL;
+ kfree(joydev);
+ }
+
++static void joydev_attach_client(struct joydev *joydev,
++ struct joydev_client *client)
++{
++ spin_lock(&joydev->client_lock);
++ list_add_tail_rcu(&client->node, &joydev->client_list);
++ spin_unlock(&joydev->client_lock);
++ /*
++ * We don't use synchronize_rcu() here because read-side
++ * critical section is protected by a spinlock (dev->event_lock)
++ * instead of rcu_read_lock().
++ */
++ synchronize_sched();
++}
++
++static void joydev_detach_client(struct joydev *joydev,
++ struct joydev_client *client)
++{
++ spin_lock(&joydev->client_lock);
++ list_del_rcu(&client->node);
++ spin_unlock(&joydev->client_lock);
++ synchronize_sched();
++}
++
++static int joydev_open_device(struct joydev *joydev)
++{
++ int retval;
++
++ retval = mutex_lock_interruptible(&joydev->mutex);
++ if (retval)
++ return retval;
++
++ if (!joydev->exist)
++ retval = -ENODEV;
++ else if (!joydev->open++)
++ retval = input_open_device(&joydev->handle);
++
++ mutex_unlock(&joydev->mutex);
++ return retval;
++}
++
++static void joydev_close_device(struct joydev *joydev)
++{
++ mutex_lock(&joydev->mutex);
++
++ if (joydev->exist && !--joydev->open)
++ input_close_device(&joydev->handle);
++
++ mutex_unlock(&joydev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void joydev_hangup(struct joydev *joydev)
++{
++ struct joydev_client *client;
++
++ spin_lock(&joydev->client_lock);
++ list_for_each_entry(client, &joydev->client_list, node)
++ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++ spin_unlock(&joydev->client_lock);
++
++ wake_up_interruptible(&joydev->wait);
++}
++
+ static int joydev_release(struct inode *inode, struct file *file)
+ {
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
+
+ joydev_fasync(-1, file, 0);
+-
+- list_del(&client->node);
++ joydev_detach_client(joydev, client);
+ kfree(client);
+
+- if (!--joydev->open && joydev->exist)
+- input_close_device(&joydev->handle);
+-
++ joydev_close_device(joydev);
+ put_device(&joydev->dev);
+
+ return 0;
+@@ -176,11 +263,16 @@ static int joydev_open(struct inode *ino
+ if (i >= JOYDEV_MINORS)
+ return -ENODEV;
+
++ error = mutex_lock_interruptible(&joydev_table_mutex);
++ if (error)
++ return error;
+ joydev = joydev_table[i];
+- if (!joydev || !joydev->exist)
+- return -ENODEV;
++ if (joydev)
++ get_device(&joydev->dev);
++ mutex_unlock(&joydev_table_mutex);
+
+- get_device(&joydev->dev);
++ if (!joydev)
++ return -ENODEV;
+
+ client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
+ if (!client) {
+@@ -188,37 +280,129 @@ static int joydev_open(struct inode *ino
+ goto err_put_joydev;
+ }
+
++ spin_lock_init(&client->buffer_lock);
+ client->joydev = joydev;
+- list_add_tail(&client->node, &joydev->client_list);
++ joydev_attach_client(joydev, client);
+
+- if (!joydev->open++ && joydev->exist) {
+- error = input_open_device(&joydev->handle);
+- if (error)
+- goto err_free_client;
+- }
++ error = joydev_open_device(joydev);
++ if (error)
++ goto err_free_client;
+
+ file->private_data = client;
+ return 0;
+
+ err_free_client:
+- list_del(&client->node);
++ joydev_detach_client(joydev, client);
+ kfree(client);
+ err_put_joydev:
+ put_device(&joydev->dev);
+ return error;
+ }
+
+-static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
++static int joydev_generate_startup_event(struct joydev_client *client,
++ struct input_dev *input,
++ struct js_event *event)
+ {
+- return -EINVAL;
++ struct joydev *joydev = client->joydev;
++ int have_event;
++
++ spin_lock_irq(&client->buffer_lock);
++
++ have_event = client->startup < joydev->nabs + joydev->nkey;
++
++ if (have_event) {
++
++ event->time = jiffies_to_msecs(jiffies);
++ if (client->startup < joydev->nkey) {
++ event->type = JS_EVENT_BUTTON | JS_EVENT_INIT;
++ 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 = client->startup - joydev->nkey;
++ event->value = joydev->abs[event->number];
++ }
++ client->startup++;
++ }
++
++ spin_unlock_irq(&client->buffer_lock);
++
++ return have_event;
++}
++
++static int joydev_fetch_next_event(struct joydev_client *client,
++ struct js_event *event)
++{
++ int have_event;
++
++ spin_lock_irq(&client->buffer_lock);
++
++ have_event = client->head != client->tail;
++ if (have_event) {
++ *event = client->buffer[client->tail++];
++ client->tail &= JOYDEV_BUFFER_SIZE - 1;
++ }
++
++ spin_unlock_irq(&client->buffer_lock);
++
++ return have_event;
+ }
+
+-static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
++/*
++ * Old joystick interface
++ */
++static ssize_t joydev_0x_read(struct joydev_client *client,
++ struct input_dev *input,
++ char __user *buf)
++{
++ struct joydev *joydev = client->joydev;
++ struct JS_DATA_TYPE data;
++ int i;
++
++ spin_lock_irq(&input->event_lock);
++
++ /*
++ * Get device state
++ */
++ for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
++ data.buttons |=
++ test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
++ data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
++ data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
++
++ /*
++ * Reset reader's event queue
++ */
++ spin_lock(&client->buffer_lock);
++ client->startup = 0;
++ client->tail = client->head;
++ spin_unlock(&client->buffer_lock);
++
++ spin_unlock_irq(&input->event_lock);
++
++ if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
++ return -EFAULT;
++
++ return sizeof(struct JS_DATA_TYPE);
++}
++
++static inline int joydev_data_pending(struct joydev_client *client)
++{
++ struct joydev *joydev = client->joydev;
++
++ return client->startup < joydev->nabs + joydev->nkey ||
++ client->head != client->tail;
++}
++
++static ssize_t joydev_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
+ {
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
+ struct input_dev *input = joydev->handle.dev;
+- int retval = 0;
++ struct js_event event;
++ int retval;
+
+ if (!joydev->exist)
+ return -ENODEV;
+@@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *
+ if (count < sizeof(struct js_event))
+ return -EINVAL;
+
+- if (count == sizeof(struct JS_DATA_TYPE)) {
+-
+- struct JS_DATA_TYPE data;
+- int i;
+-
+- for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++)
+- data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0;
+- data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x;
+- data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y;
+-
+- if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
+- return -EFAULT;
+-
+- client->startup = 0;
+- client->tail = client->head;
+-
+- return sizeof(struct JS_DATA_TYPE);
+- }
++ if (count == sizeof(struct JS_DATA_TYPE))
++ return joydev_0x_read(client, input, buf);
+
+- if (client->startup == joydev->nabs + joydev->nkey &&
+- client->head == client->tail && (file->f_flags & O_NONBLOCK))
++ if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ retval = wait_event_interruptible(joydev->wait,
+- !joydev->exist ||
+- client->startup < joydev->nabs + joydev->nkey ||
+- client->head != client->tail);
++ !joydev->exist || joydev_data_pending(client));
+ if (retval)
+ return retval;
+
+ if (!joydev->exist)
+ return -ENODEV;
+
+- while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
+-
+- struct js_event event;
+-
+- event.time = jiffies_to_msecs(jiffies);
+-
+- if (client->startup < joydev->nkey) {
+- event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
+- 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 = client->startup - joydev->nkey;
+- event.value = joydev->abs[event.number];
+- }
++ while (retval + sizeof(struct js_event) <= count &&
++ joydev_generate_startup_event(client, input, &event)) {
+
+ if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
+ return -EFAULT;
+
+- client->startup++;
+ retval += sizeof(struct js_event);
+ }
+
+- while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
++ while (retval + sizeof(struct js_event) <= count &&
++ joydev_fetch_next_event(client, &event)) {
+
+- if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
++ if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
+ return -EFAULT;
+
+- client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
+ retval += sizeof(struct js_event);
+ }
+
+@@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct f
+ struct joydev *joydev = client->joydev;
+
+ 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));
++ return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) |
++ (joydev->exist ? 0 : (POLLHUP | POLLERR));
+ }
+
+-static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
++static int joydev_ioctl_common(struct joydev *joydev,
++ unsigned int cmd, void __user *argp)
+ {
+ struct input_dev *dev = joydev->handle.dev;
+ int i, j;
+
+ switch (cmd) {
+
+- case JS_SET_CAL:
+- return copy_from_user(&joydev->glue.JS_CORR, argp,
++ case JS_SET_CAL:
++ return copy_from_user(&joydev->glue.JS_CORR, argp,
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+
+- case JS_GET_CAL:
+- return copy_to_user(argp, &joydev->glue.JS_CORR,
++ case JS_GET_CAL:
++ return copy_to_user(argp, &joydev->glue.JS_CORR,
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+
+- case JS_SET_TIMEOUT:
+- return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
++ case JS_SET_TIMEOUT:
++ return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+
+- case JS_GET_TIMEOUT:
+- return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
++ case JS_GET_TIMEOUT:
++ return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+
+- case JSIOCGVERSION:
+- return put_user(JS_VERSION, (__u32 __user *) argp);
++ case JSIOCGVERSION:
++ return put_user(JS_VERSION, (__u32 __user *) argp);
+
+- case JSIOCGAXES:
+- return put_user(joydev->nabs, (__u8 __user *) argp);
+-
+- case JSIOCGBUTTONS:
+- return put_user(joydev->nkey, (__u8 __user *) argp);
+-
+- case JSIOCSCORR:
+- if (copy_from_user(joydev->corr, argp,
+- sizeof(joydev->corr[0]) * joydev->nabs))
+- return -EFAULT;
+- for (i = 0; i < joydev->nabs; i++) {
+- j = joydev->abspam[i];
+- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
+- }
+- return 0;
+-
+- case JSIOCGCORR:
+- return copy_to_user(argp, joydev->corr,
+- sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
++ case JSIOCGAXES:
++ return put_user(joydev->nabs, (__u8 __user *) argp);
++
++ case JSIOCGBUTTONS:
++ return put_user(joydev->nkey, (__u8 __user *) argp);
++
++ case JSIOCSCORR:
++ if (copy_from_user(joydev->corr, argp,
++ sizeof(joydev->corr[0]) * joydev->nabs))
++ return -EFAULT;
++
++ for (i = 0; i < joydev->nabs; i++) {
++ j = joydev->abspam[i];
++ joydev->abs[i] = joydev_correct(dev->abs[j],
++ &joydev->corr[i]);
++ }
++ return 0;
+
+- case JSIOCSAXMAP:
+- if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
+- return -EFAULT;
+- for (i = 0; i < joydev->nabs; i++) {
+- if (joydev->abspam[i] > ABS_MAX)
+- return -EINVAL;
+- joydev->absmap[joydev->abspam[i]] = i;
+- }
+- return 0;
+-
+- case JSIOCGAXMAP:
+- return copy_to_user(argp, joydev->abspam,
+- sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
++ case JSIOCGCORR:
++ return copy_to_user(argp, joydev->corr,
++ sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
++
++ case JSIOCSAXMAP:
++ if (copy_from_user(joydev->abspam, argp,
++ sizeof(__u8) * (ABS_MAX + 1)))
++ return -EFAULT;
++
++ for (i = 0; i < joydev->nabs; i++) {
++ if (joydev->abspam[i] > ABS_MAX)
++ return -EINVAL;
++ joydev->absmap[joydev->abspam[i]] = i;
++ }
++ return 0;
++
++ case JSIOCGAXMAP:
++ return copy_to_user(argp, joydev->abspam,
++ sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
++
++ case JSIOCSBTNMAP:
++ if (copy_from_user(joydev->keypam, argp,
++ sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
++ return -EFAULT;
++
++ for (i = 0; i < joydev->nkey; i++) {
++ if (joydev->keypam[i] > KEY_MAX ||
++ joydev->keypam[i] < BTN_MISC)
++ return -EINVAL;
++ joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
++ }
+
+- case JSIOCSBTNMAP:
+- if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
++ return 0;
++
++ case JSIOCGBTNMAP:
++ return copy_to_user(argp, joydev->keypam,
++ sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
++
++ default:
++ if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) {
++ int len;
++ if (!dev->name)
++ return 0;
++ len = strlen(dev->name) + 1;
++ if (len > _IOC_SIZE(cmd))
++ len = _IOC_SIZE(cmd);
++ if (copy_to_user(argp, dev->name, len))
+ return -EFAULT;
+- for (i = 0; i < joydev->nkey; i++) {
+- if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
+- return -EINVAL;
+- joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
+- }
+- return 0;
+-
+- case JSIOCGBTNMAP:
+- return copy_to_user(argp, joydev->keypam,
+- sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
+-
+- default:
+- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
+- int len;
+- if (!dev->name)
+- return 0;
+- len = strlen(dev->name) + 1;
+- if (len > _IOC_SIZE(cmd))
+- len = _IOC_SIZE(cmd);
+- if (copy_to_user(argp, dev->name, len))
+- return -EFAULT;
+- return len;
+- }
++ return len;
++ }
+ }
+ return -EINVAL;
+ }
+
+ #ifdef CONFIG_COMPAT
+-static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
++static long joydev_compat_ioctl(struct file *file,
++ unsigned int cmd, unsigned long arg)
+ {
+ 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;
+- int err;
++ int retval;
+
+- if (!joydev->exist)
+- return -ENODEV;
++ retval = mutex_lock_interruptible(&joydev->mutex);
++ if (retval)
++ return retval;
++
++ if (!joydev->exist) {
++ retval = -ENODEV;
++ goto out;
++ }
++
++ switch (cmd) {
+
+- switch(cmd) {
+ case JS_SET_TIMELIMIT:
+- err = get_user(tmp32, (s32 __user *) arg);
+- if (err == 0)
++ retval = get_user(tmp32, (s32 __user *) arg);
++ if (retval == 0)
+ joydev->glue.JS_TIMELIMIT = tmp32;
+ break;
++
+ case JS_GET_TIMELIMIT:
+ tmp32 = joydev->glue.JS_TIMELIMIT;
+- err = put_user(tmp32, (s32 __user *) arg);
++ retval = put_user(tmp32, (s32 __user *) arg);
+ break;
+
+ case JS_SET_ALL:
+- err = copy_from_user(&ds32, argp,
+- sizeof(ds32)) ? -EFAULT : 0;
+- if (err == 0) {
++ retval = copy_from_user(&ds32, argp,
++ sizeof(ds32)) ? -EFAULT : 0;
++ if (retval == 0) {
+ joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
+ joydev->glue.BUSY = ds32.BUSY;
+ joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+@@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct f
+ ds32.JS_SAVE = joydev->glue.JS_SAVE;
+ ds32.JS_CORR = joydev->glue.JS_CORR;
+
+- err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
++ retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
+ break;
+
+ default:
+- err = joydev_ioctl_common(joydev, cmd, argp);
++ retval = joydev_ioctl_common(joydev, cmd, argp);
++ break;
+ }
+- return err;
++
++ out:
++ mutex_unlock(&joydev->mutex);
++ return retval;
+ }
+ #endif /* CONFIG_COMPAT */
+
+-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++static long joydev_ioctl(struct file *file,
++ unsigned int cmd, unsigned long arg)
+ {
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
+ void __user *argp = (void __user *)arg;
++ int retval;
+
+- if (!joydev->exist)
+- return -ENODEV;
++ retval = mutex_lock_interruptible(&joydev->mutex);
++ if (retval)
++ return retval;
++
++ if (!joydev->exist) {
++ retval = -ENODEV;
++ goto out;
++ }
++
++ switch (cmd) {
++
++ case JS_SET_TIMELIMIT:
++ retval = get_user(joydev->glue.JS_TIMELIMIT,
++ (long __user *) arg);
++ break;
++
++ case JS_GET_TIMELIMIT:
++ retval = put_user(joydev->glue.JS_TIMELIMIT,
++ (long __user *) arg);
++ break;
++
++ case JS_SET_ALL:
++ retval = copy_from_user(&joydev->glue, argp,
++ sizeof(joydev->glue)) ? -EFAULT: 0;
++ break;
+
+- switch(cmd) {
+- case JS_SET_TIMELIMIT:
+- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+- case JS_GET_TIMELIMIT:
+- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+- case JS_SET_ALL:
+- return copy_from_user(&joydev->glue, argp,
+- sizeof(joydev->glue)) ? -EFAULT : 0;
+- case JS_GET_ALL:
+- return copy_to_user(argp, &joydev->glue,
+- sizeof(joydev->glue)) ? -EFAULT : 0;
+- default:
+- return joydev_ioctl_common(joydev, cmd, argp);
++ case JS_GET_ALL:
++ retval = copy_to_user(argp, &joydev->glue,
++ sizeof(joydev->glue)) ? -EFAULT : 0;
++ break;
++
++ default:
++ retval = joydev_ioctl_common(joydev, cmd, argp);
++ break;
+ }
++ out:
++ mutex_unlock(&joydev->mutex);
++ return retval;
+ }
+
+ static const struct file_operations joydev_fops = {
+- .owner = THIS_MODULE,
+- .read = joydev_read,
+- .write = joydev_write,
+- .poll = joydev_poll,
+- .open = joydev_open,
+- .release = joydev_release,
+- .ioctl = joydev_ioctl,
++ .owner = THIS_MODULE,
++ .read = joydev_read,
++ .poll = joydev_poll,
++ .open = joydev_open,
++ .release = joydev_release,
++ .unlocked_ioctl = joydev_ioctl,
+ #ifdef CONFIG_COMPAT
+- .compat_ioctl = joydev_compat_ioctl,
++ .compat_ioctl = joydev_compat_ioctl,
+ #endif
+- .fasync = joydev_fasync,
++ .fasync = joydev_fasync,
+ };
+
++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
++ * prevents new users from opening the device. Already posted
++ * blocking reads will stay, however new ones will fail.
++ */
++static void joydev_mark_dead(struct joydev *joydev)
++{
++ mutex_lock(&joydev->mutex);
++ joydev->exist = 0;
++ mutex_unlock(&joydev->mutex);
++}
++
++static void joydev_cleanup(struct joydev *joydev)
++{
++ struct input_handle *handle = &joydev->handle;
++
++ joydev_mark_dead(joydev);
++ joydev_hangup(joydev);
++ joydev_remove_chrdev(joydev);
++
++ /* joydev is marked dead so noone else accesses joydev->open */
++ if (joydev->open)
++ input_close_device(handle);
++}
++
+ static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+ {
+@@ -494,7 +727,10 @@ static int joydev_connect(struct input_h
+ int i, j, t, minor;
+ int error;
+
+- for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
++ 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;
+@@ -505,15 +741,19 @@ static int joydev_connect(struct input_h
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&joydev->client_list);
++ spin_lock_init(&joydev->client_lock);
++ mutex_init(&joydev->mutex);
+ init_waitqueue_head(&joydev->wait);
+
++ snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
++ joydev->exist = 1;
+ joydev->minor = minor;
++
+ joydev->exist = 1;
+ joydev->handle.dev = dev;
+ joydev->handle.name = joydev->name;
+ joydev->handle.handler = handler;
+ joydev->handle.private = joydev;
+- snprintf(joydev->name, sizeof(joydev->name), "js%d", minor);
+
+ for (i = 0; i < ABS_MAX + 1; i++)
+ if (test_bit(i, dev->absbit)) {
+@@ -545,67 +785,65 @@ static int joydev_connect(struct input_h
+ }
+ joydev->corr[i].type = JS_CORR_BROKEN;
+ joydev->corr[i].prec = dev->absfuzz[j];
+- joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
+- joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
+- if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j])))
+- continue;
+- joydev->corr[i].coef[2] = (1 << 29) / t;
+- joydev->corr[i].coef[3] = (1 << 29) / t;
++ joydev->corr[i].coef[0] =
++ (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j];
++ joydev->corr[i].coef[1] =
++ (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j];
++
++ t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j];
++ if (t) {
++ joydev->corr[i].coef[2] = (1 << 29) / t;
++ joydev->corr[i].coef[3] = (1 << 29) / t;
+
+- joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
++ joydev->abs[i] = joydev_correct(dev->abs[j],
++ joydev->corr + i);
++ }
+ }
+
+- snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id),
+- "js%d", minor);
++ strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id));
++ joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
+ joydev->dev.class = &input_class;
+ joydev->dev.parent = &dev->dev;
+- joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor);
+ joydev->dev.release = joydev_free;
+ device_initialize(&joydev->dev);
+
+- joydev_table[minor] = joydev;
+-
+- error = device_add(&joydev->dev);
++ error = input_register_handle(&joydev->handle);
+ if (error)
+ goto err_free_joydev;
+
+- error = input_register_handle(&joydev->handle);
++ error = joydev_install_chrdev(joydev);
+ if (error)
+- goto err_delete_joydev;
++ goto err_unregister_handle;
++
++ error = device_add(&joydev->dev);
++ if (error)
++ goto err_cleanup_joydev;
+
+ return 0;
+
+- err_delete_joydev:
+- device_del(&joydev->dev);
++ err_cleanup_joydev:
++ joydev_cleanup(joydev);
++ err_unregister_handle:
++ input_unregister_handle(&joydev->handle);
+ err_free_joydev:
+ put_device(&joydev->dev);
+ return error;
+ }
+
+-
+ static void joydev_disconnect(struct input_handle *handle)
+ {
+ struct joydev *joydev = handle->private;
+- struct joydev_client *client;
+
+- input_unregister_handle(handle);
+ device_del(&joydev->dev);
+-
+- joydev->exist = 0;
+-
+- if (joydev->open) {
+- input_close_device(handle);
+- list_for_each_entry(client, &joydev->client_list, node)
+- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+- wake_up_interruptible(&joydev->wait);
+- }
+-
++ joydev_cleanup(joydev);
++ input_unregister_handle(handle);
+ put_device(&joydev->dev);
+ }
+
+ static const struct input_device_id joydev_blacklist[] = {
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT(EV_KEY) },
+ .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+ }, /* Avoid itouchpads, touchscreens and tablets */
+@@ -614,17 +852,20 @@ static const struct input_device_id joyd
+
+ static const struct input_device_id joydev_ids[] = {
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT(EV_ABS) },
+ .absbit = { BIT(ABS_X) },
+ },
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT(EV_ABS) },
+ .absbit = { BIT(ABS_WHEEL) },
+ },
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT(EV_ABS) },
+ .absbit = { BIT(ABS_THROTTLE) },
+ },
+@@ -634,14 +875,14 @@ static const struct input_device_id joyd
+ MODULE_DEVICE_TABLE(input, joydev_ids);
+
+ static struct input_handler joydev_handler = {
+- .event = joydev_event,
+- .connect = joydev_connect,
+- .disconnect = joydev_disconnect,
+- .fops = &joydev_fops,
+- .minor = JOYDEV_MINOR_BASE,
+- .name = "joydev",
+- .id_table = joydev_ids,
+- .blacklist = joydev_blacklist,
++ .event = joydev_event,
++ .connect = joydev_connect,
++ .disconnect = joydev_disconnect,
++ .fops = &joydev_fops,
++ .minor = JOYDEV_MINOR_BASE,
++ .name = "joydev",
++ .id_table = joydev_ids,
++ .blacklist = joydev_blacklist,
+ };
+
+ static int __init joydev_init(void)
--- /dev/null
+From 464b241575f3700e14492e34f26bcd1794280f55 Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Thu, 30 Aug 2007 00:22:24 -0400
+Subject: [PATCH] Input: mousedev - implement proper locking
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch 464b241575f3700e14492e34f26bcd1794280f55 in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/mousedev.c | 742 +++++++++++++++++++++++++++++------------------
+ 1 file changed, 470 insertions(+), 272 deletions(-)
+
+--- a/drivers/input/mousedev.c
++++ b/drivers/input/mousedev.c
+@@ -61,9 +61,11 @@ struct mousedev {
+ int open;
+ int minor;
+ char name[16];
++ struct input_handle handle;
+ wait_queue_head_t wait;
+ struct list_head client_list;
+- struct input_handle handle;
++ spinlock_t client_lock; /* protects client_list */
++ struct mutex mutex;
+ struct device dev;
+
+ struct list_head mixdev_node;
+@@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[]
+ 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])
+
+-static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_touchpad_event(struct input_dev *dev,
++ struct mousedev *mousedev,
++ unsigned int code, int value)
+ {
+ int size, tmp;
+ enum { FRACTION_DENOM = 128 };
+
+ switch (code) {
+- case ABS_X:
+- fx(0) = value;
+- if (mousedev->touch && mousedev->pkt_count >= 2) {
+- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+- if (size == 0)
+- size = 256 * 2;
+- tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
+- tmp += mousedev->frac_dx;
+- mousedev->packet.dx = tmp / FRACTION_DENOM;
+- mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
+- }
+- break;
+
+- case ABS_Y:
+- fy(0) = value;
+- if (mousedev->touch && mousedev->pkt_count >= 2) {
+- /* use X size to keep the same scale */
+- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+- if (size == 0)
+- size = 256 * 2;
+- tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
+- tmp += mousedev->frac_dy;
+- mousedev->packet.dy = tmp / FRACTION_DENOM;
+- mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
+- }
+- break;
++ case ABS_X:
++ fx(0) = value;
++ if (mousedev->touch && mousedev->pkt_count >= 2) {
++ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
++ if (size == 0)
++ size = 256 * 2;
++ tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size;
++ tmp += mousedev->frac_dx;
++ mousedev->packet.dx = tmp / FRACTION_DENOM;
++ mousedev->frac_dx =
++ tmp - mousedev->packet.dx * FRACTION_DENOM;
++ }
++ break;
++
++ case ABS_Y:
++ fy(0) = value;
++ if (mousedev->touch && mousedev->pkt_count >= 2) {
++ /* use X size to keep the same scale */
++ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
++ if (size == 0)
++ size = 256 * 2;
++ tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size;
++ tmp += mousedev->frac_dy;
++ mousedev->packet.dy = tmp / FRACTION_DENOM;
++ mousedev->frac_dy = tmp -
++ mousedev->packet.dy * FRACTION_DENOM;
++ }
++ break;
+ }
+ }
+
+-static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
++ unsigned int code, int value)
+ {
+ int size;
+
+ switch (code) {
+- case ABS_X:
+- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+- if (size == 0)
+- size = xres ? : 1;
+- if (value > dev->absmax[ABS_X])
+- value = dev->absmax[ABS_X];
+- if (value < dev->absmin[ABS_X])
+- value = dev->absmin[ABS_X];
+- mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
+- mousedev->packet.abs_event = 1;
+- break;
+
+- case ABS_Y:
+- size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
+- if (size == 0)
+- size = yres ? : 1;
+- if (value > dev->absmax[ABS_Y])
+- value = dev->absmax[ABS_Y];
+- if (value < dev->absmin[ABS_Y])
+- value = dev->absmin[ABS_Y];
+- mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
+- mousedev->packet.abs_event = 1;
+- break;
++ case ABS_X:
++ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
++ if (size == 0)
++ size = xres ? : 1;
++ if (value > dev->absmax[ABS_X])
++ value = dev->absmax[ABS_X];
++ if (value < dev->absmin[ABS_X])
++ value = dev->absmin[ABS_X];
++ mousedev->packet.x =
++ ((value - dev->absmin[ABS_X]) * xres) / size;
++ mousedev->packet.abs_event = 1;
++ break;
++
++ case ABS_Y:
++ size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
++ if (size == 0)
++ size = yres ? : 1;
++ if (value > dev->absmax[ABS_Y])
++ value = dev->absmax[ABS_Y];
++ if (value < dev->absmin[ABS_Y])
++ value = dev->absmin[ABS_Y];
++ mousedev->packet.y = yres -
++ ((value - dev->absmin[ABS_Y]) * yres) / size;
++ mousedev->packet.abs_event = 1;
++ break;
+ }
+ }
+
+-static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_rel_event(struct mousedev *mousedev,
++ unsigned int code, int value)
+ {
+ switch (code) {
+- case REL_X: mousedev->packet.dx += value; break;
+- case REL_Y: mousedev->packet.dy -= value; break;
+- case REL_WHEEL: mousedev->packet.dz -= value; break;
++ case REL_X:
++ mousedev->packet.dx += value;
++ break;
++
++ case REL_Y:
++ mousedev->packet.dy -= value;
++ break;
++
++ case REL_WHEEL:
++ mousedev->packet.dz -= value;
++ break;
+ }
+ }
+
+-static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value)
++static void mousedev_key_event(struct mousedev *mousedev,
++ unsigned int code, int value)
+ {
+ int index;
+
+ switch (code) {
+- case BTN_TOUCH:
+- case BTN_0:
+- case BTN_LEFT: index = 0; break;
+- case BTN_STYLUS:
+- case BTN_1:
+- case BTN_RIGHT: index = 1; break;
+- case BTN_2:
+- case BTN_FORWARD:
+- case BTN_STYLUS2:
+- case BTN_MIDDLE: index = 2; break;
+- case BTN_3:
+- case BTN_BACK:
+- case BTN_SIDE: index = 3; break;
+- case BTN_4:
+- case BTN_EXTRA: index = 4; break;
+- default: return;
++
++ case BTN_TOUCH:
++ case BTN_0:
++ case BTN_LEFT: index = 0; break;
++
++ case BTN_STYLUS:
++ case BTN_1:
++ case BTN_RIGHT: index = 1; break;
++
++ case BTN_2:
++ case BTN_FORWARD:
++ case BTN_STYLUS2:
++ case BTN_MIDDLE: index = 2; break;
++
++ case BTN_3:
++ case BTN_BACK:
++ case BTN_SIDE: index = 3; break;
++
++ case BTN_4:
++ case BTN_EXTRA: index = 4; break;
++
++ default: return;
+ }
+
+ if (value) {
+@@ -226,19 +257,22 @@ static void mousedev_key_event(struct mo
+ }
+ }
+
+-static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
++static void mousedev_notify_readers(struct mousedev *mousedev,
++ struct mousedev_hw_data *packet)
+ {
+ struct mousedev_client *client;
+ struct mousedev_motion *p;
+- unsigned long flags;
++ unsigned int new_head;
+ int wake_readers = 0;
+
+- list_for_each_entry(client, &mousedev->client_list, node) {
+- spin_lock_irqsave(&client->packet_lock, flags);
++ list_for_each_entry_rcu(client, &mousedev->client_list, node) {
++
++ /* Just acquire the lock, interrupts already disabled */
++ spin_lock(&client->packet_lock);
+
+ p = &client->packets[client->head];
+ if (client->ready && p->buttons != mousedev->packet.buttons) {
+- unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
++ new_head = (client->head + 1) % PACKET_QUEUE_LEN;
+ if (new_head != client->tail) {
+ p = &client->packets[client->head = new_head];
+ memset(p, 0, sizeof(struct mousedev_motion));
+@@ -253,19 +287,22 @@ static void mousedev_notify_readers(stru
+ }
+
+ client->pos_x += packet->dx;
+- client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
++ client->pos_x = client->pos_x < 0 ?
++ 0 : (client->pos_x >= xres ? xres : client->pos_x);
+ client->pos_y += packet->dy;
+- client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
++ client->pos_y = client->pos_y < 0 ?
++ 0 : (client->pos_y >= yres ? yres : client->pos_y);
+
+ p->dx += packet->dx;
+ p->dy += packet->dy;
+ p->dz += packet->dz;
+ p->buttons = mousedev->packet.buttons;
+
+- if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
++ if (p->dx || p->dy || p->dz ||
++ p->buttons != client->last_buttons)
+ client->ready = 1;
+
+- spin_unlock_irqrestore(&client->packet_lock, flags);
++ spin_unlock(&client->packet_lock);
+
+ if (client->ready) {
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+@@ -281,7 +318,8 @@ static void mousedev_touchpad_touch(stru
+ {
+ if (!value) {
+ if (mousedev->touch &&
+- time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) {
++ time_before(jiffies,
++ mousedev->touch + msecs_to_jiffies(tap_time))) {
+ /*
+ * Toggle left button to emulate tap.
+ * We rely on the fact that mousedev_mix always has 0
+@@ -290,7 +328,8 @@ static void mousedev_touchpad_touch(stru
+ set_bit(0, &mousedev->packet.buttons);
+ set_bit(0, &mousedev_mix->packet.buttons);
+ mousedev_notify_readers(mousedev, &mousedev_mix->packet);
+- mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet);
++ mousedev_notify_readers(mousedev_mix,
++ &mousedev_mix->packet);
+ clear_bit(0, &mousedev->packet.buttons);
+ clear_bit(0, &mousedev_mix->packet.buttons);
+ }
+@@ -302,54 +341,61 @@ static void mousedev_touchpad_touch(stru
+ mousedev->touch = jiffies;
+ }
+
+-static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
++static void mousedev_event(struct input_handle *handle,
++ unsigned int type, unsigned int code, int value)
+ {
+ struct mousedev *mousedev = handle->private;
+
+ switch (type) {
+- case EV_ABS:
+- /* Ignore joysticks */
+- if (test_bit(BTN_TRIGGER, handle->dev->keybit))
+- return;
+
+- if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+- mousedev_touchpad_event(handle->dev, mousedev, code, value);
++ case EV_ABS:
++ /* Ignore joysticks */
++ if (test_bit(BTN_TRIGGER, handle->dev->keybit))
++ return;
++
++ if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
++ mousedev_touchpad_event(handle->dev,
++ mousedev, code, value);
++ else
++ mousedev_abs_event(handle->dev, mousedev, code, value);
++
++ break;
++
++ case EV_REL:
++ mousedev_rel_event(mousedev, code, value);
++ break;
++
++ case EV_KEY:
++ if (value != 2) {
++ if (code == BTN_TOUCH &&
++ test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
++ mousedev_touchpad_touch(mousedev, value);
+ else
+- mousedev_abs_event(handle->dev, mousedev, code, value);
+-
+- break;
+-
+- case EV_REL:
+- mousedev_rel_event(mousedev, code, value);
+- break;
++ mousedev_key_event(mousedev, code, value);
++ }
++ break;
+
+- case EV_KEY:
+- if (value != 2) {
+- if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit))
+- mousedev_touchpad_touch(mousedev, value);
+- else
+- mousedev_key_event(mousedev, code, value);
++ case EV_SYN:
++ if (code == SYN_REPORT) {
++ if (mousedev->touch) {
++ mousedev->pkt_count++;
++ /*
++ * Input system eats duplicate events,
++ * but we need all of them to do correct
++ * averaging so apply present one forward
++ */
++ fx(0) = fx(1);
++ fy(0) = fy(1);
+ }
+- break;
+-
+- case EV_SYN:
+- if (code == SYN_REPORT) {
+- if (mousedev->touch) {
+- mousedev->pkt_count++;
+- /* Input system eats duplicate events, but we need all of them
+- * to do correct averaging so apply present one forward
+- */
+- fx(0) = fx(1);
+- fy(0) = fy(1);
+- }
+
+- mousedev_notify_readers(mousedev, &mousedev->packet);
+- mousedev_notify_readers(mousedev_mix, &mousedev->packet);
++ mousedev_notify_readers(mousedev, &mousedev->packet);
++ mousedev_notify_readers(mousedev_mix, &mousedev->packet);
+
+- mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
+- mousedev->packet.abs_event = 0;
+- }
+- break;
++ mousedev->packet.dx = mousedev->packet.dy =
++ mousedev->packet.dz = 0;
++ mousedev->packet.abs_event = 0;
++ }
++ break;
+ }
+ }
+
+@@ -367,41 +413,45 @@ static void mousedev_free(struct device
+ {
+ struct mousedev *mousedev = container_of(dev, struct mousedev, dev);
+
+- mousedev_table[mousedev->minor] = NULL;
+ kfree(mousedev);
+ }
+
+-static int mixdev_add_device(struct mousedev *mousedev)
++static int mousedev_open_device(struct mousedev *mousedev)
+ {
+- int error;
+-
+- if (mousedev_mix->open) {
+- error = input_open_device(&mousedev->handle);
+- if (error)
+- return error;
++ int retval;
+
+- mousedev->open++;
+- mousedev->mixdev_open = 1;
+- }
++ retval = mutex_lock_interruptible(&mousedev->mutex);
++ if (retval)
++ return retval;
+
+- get_device(&mousedev->dev);
+- list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
++ if (mousedev->minor == MOUSEDEV_MIX)
++ mixdev_open_devices();
++ else if (!mousedev->exist)
++ retval = -ENODEV;
++ else if (!mousedev->open++)
++ retval = input_open_device(&mousedev->handle);
+
+- return 0;
++ mutex_unlock(&mousedev->mutex);
++ return retval;
+ }
+
+-static void mixdev_remove_device(struct mousedev *mousedev)
++static void mousedev_close_device(struct mousedev *mousedev)
+ {
+- if (mousedev->mixdev_open) {
+- mousedev->mixdev_open = 0;
+- if (!--mousedev->open && mousedev->exist)
+- input_close_device(&mousedev->handle);
+- }
++ mutex_lock(&mousedev->mutex);
+
+- list_del_init(&mousedev->mixdev_node);
+- put_device(&mousedev->dev);
++ if (mousedev->minor == MOUSEDEV_MIX)
++ mixdev_close_devices();
++ else if (mousedev->exist && !--mousedev->open)
++ input_close_device(&mousedev->handle);
++
++ mutex_unlock(&mousedev->mutex);
+ }
+
++/*
++ * Open all available devices so they can all be multiplexed in one.
++ * stream. Note that this function is called with mousedev_mix->mutex
++ * held.
++ */
+ static void mixdev_open_devices(void)
+ {
+ struct mousedev *mousedev;
+@@ -411,16 +461,19 @@ static void mixdev_open_devices(void)
+
+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+ if (!mousedev->mixdev_open) {
+- if (!mousedev->open && mousedev->exist)
+- if (input_open_device(&mousedev->handle))
+- continue;
++ if (mousedev_open_device(mousedev))
++ continue;
+
+- mousedev->open++;
+ mousedev->mixdev_open = 1;
+ }
+ }
+ }
+
++/*
++ * 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)
+ {
+ struct mousedev *mousedev;
+@@ -431,33 +484,50 @@ static void mixdev_close_devices(void)
+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+ if (mousedev->mixdev_open) {
+ mousedev->mixdev_open = 0;
+- if (!--mousedev->open && mousedev->exist)
+- input_close_device(&mousedev->handle);
++ mousedev_close_device(mousedev);
+ }
+ }
+ }
+
++
++static void mousedev_attach_client(struct mousedev *mousedev,
++ struct mousedev_client *client)
++{
++ spin_lock(&mousedev->client_lock);
++ list_add_tail_rcu(&client->node, &mousedev->client_list);
++ spin_unlock(&mousedev->client_lock);
++ /*
++ * We don't use synchronize_rcu() here because read-side
++ * critical section is protected by a spinlock (dev->event_lock)
++ * instead of rcu_read_lock().
++ */
++ synchronize_sched();
++}
++
++static void mousedev_detach_client(struct mousedev *mousedev,
++ struct mousedev_client *client)
++{
++ spin_lock(&mousedev->client_lock);
++ list_del_rcu(&client->node);
++ spin_unlock(&mousedev->client_lock);
++ synchronize_sched();
++}
++
+ static int mousedev_release(struct inode *inode, struct file *file)
+ {
+ struct mousedev_client *client = file->private_data;
+ struct mousedev *mousedev = client->mousedev;
+
+ mousedev_fasync(-1, file, 0);
+-
+- list_del(&client->node);
++ mousedev_detach_client(mousedev, client);
+ kfree(client);
+
+- if (mousedev->minor == MOUSEDEV_MIX)
+- mixdev_close_devices();
+- else if (!--mousedev->open && mousedev->exist)
+- input_close_device(&mousedev->handle);
+-
++ mousedev_close_device(mousedev);
+ put_device(&mousedev->dev);
+
+ return 0;
+ }
+
+-
+ static int mousedev_open(struct inode *inode, struct file *file)
+ {
+ struct mousedev_client *client;
+@@ -475,12 +545,17 @@ static int mousedev_open(struct inode *i
+ 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;
+
+- get_device(&mousedev->dev);
+-
+ client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
+ if (!client) {
+ error = -ENOMEM;
+@@ -491,21 +566,17 @@ static int mousedev_open(struct inode *i
+ client->pos_x = xres / 2;
+ client->pos_y = yres / 2;
+ client->mousedev = mousedev;
+- list_add_tail(&client->node, &mousedev->client_list);
++ mousedev_attach_client(mousedev, client);
+
+- if (mousedev->minor == MOUSEDEV_MIX)
+- mixdev_open_devices();
+- else if (!mousedev->open++ && mousedev->exist) {
+- error = input_open_device(&mousedev->handle);
+- if (error)
+- goto err_free_client;
+- }
++ error = mousedev_open_device(mousedev);
++ if (error)
++ goto err_free_client;
+
+ file->private_data = client;
+ return 0;
+
+ err_free_client:
+- list_del(&client->node);
++ mousedev_detach_client(mousedev, client);
+ kfree(client);
+ err_put_mousedev:
+ put_device(&mousedev->dev);
+@@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(i
+ return delta > limit ? limit : (delta < -limit ? -limit : delta);
+ }
+
+-static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
++static void mousedev_packet(struct mousedev_client *client,
++ signed char *ps2_data)
+ {
+- struct mousedev_motion *p;
+- unsigned long flags;
+-
+- spin_lock_irqsave(&client->packet_lock, flags);
+- p = &client->packets[client->tail];
++ struct mousedev_motion *p = &client->packets[client->tail];
+
+- ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
++ ps2_data[0] = 0x08 |
++ ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
+ ps2_data[1] = mousedev_limit_delta(p->dx, 127);
+ ps2_data[2] = mousedev_limit_delta(p->dy, 127);
+ p->dx -= ps2_data[1];
+ p->dy -= ps2_data[2];
+
+ switch (client->mode) {
+- case MOUSEDEV_EMUL_EXPS:
+- ps2_data[3] = mousedev_limit_delta(p->dz, 7);
+- p->dz -= ps2_data[3];
+- ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+- client->bufsiz = 4;
+- break;
+-
+- case MOUSEDEV_EMUL_IMPS:
+- ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+- ps2_data[3] = mousedev_limit_delta(p->dz, 127);
+- p->dz -= ps2_data[3];
+- client->bufsiz = 4;
+- break;
+-
+- case MOUSEDEV_EMUL_PS2:
+- default:
+- ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
+- p->dz = 0;
+- client->bufsiz = 3;
+- break;
++ case MOUSEDEV_EMUL_EXPS:
++ ps2_data[3] = mousedev_limit_delta(p->dz, 7);
++ p->dz -= ps2_data[3];
++ ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
++ client->bufsiz = 4;
++ break;
++
++ case MOUSEDEV_EMUL_IMPS:
++ ps2_data[0] |=
++ ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
++ ps2_data[3] = mousedev_limit_delta(p->dz, 127);
++ p->dz -= ps2_data[3];
++ client->bufsiz = 4;
++ break;
++
++ case MOUSEDEV_EMUL_PS2:
++ default:
++ ps2_data[0] |=
++ ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
++ p->dz = 0;
++ client->bufsiz = 3;
++ break;
+ }
+
+ if (!p->dx && !p->dy && !p->dz) {
+@@ -561,12 +632,56 @@ static void mousedev_packet(struct mouse
+ } else
+ client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
+ }
+-
+- spin_unlock_irqrestore(&client->packet_lock, flags);
+ }
+
++static void mousedev_generate_response(struct mousedev_client *client,
++ int command)
++{
++ client->ps2[0] = 0xfa; /* ACK */
++
++ switch (command) {
+
+-static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
++ case 0xeb: /* Poll */
++ mousedev_packet(client, &client->ps2[1]);
++ client->bufsiz++; /* account for leading ACK */
++ break;
++
++ case 0xf2: /* Get ID */
++ switch (client->mode) {
++ case MOUSEDEV_EMUL_PS2:
++ client->ps2[1] = 0;
++ break;
++ case MOUSEDEV_EMUL_IMPS:
++ client->ps2[1] = 3;
++ break;
++ case MOUSEDEV_EMUL_EXPS:
++ client->ps2[1] = 4;
++ break;
++ }
++ client->bufsiz = 2;
++ break;
++
++ case 0xe9: /* Get info */
++ client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
++ client->bufsiz = 4;
++ break;
++
++ case 0xff: /* Reset */
++ client->impsseq = client->imexseq = 0;
++ client->mode = MOUSEDEV_EMUL_PS2;
++ client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
++ client->bufsiz = 3;
++ break;
++
++ default:
++ client->bufsiz = 1;
++ break;
++ }
++ client->buffer = client->bufsiz;
++}
++
++static ssize_t mousedev_write(struct file *file, const char __user *buffer,
++ size_t count, loff_t *ppos)
+ {
+ struct mousedev_client *client = file->private_data;
+ unsigned char c;
+@@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct fil
+ if (get_user(c, buffer + i))
+ return -EFAULT;
+
++ spin_lock_irq(&client->packet_lock);
++
+ if (c == mousedev_imex_seq[client->imexseq]) {
+ if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
+ client->imexseq = 0;
+@@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct fil
+ } else
+ client->impsseq = 0;
+
+- client->ps2[0] = 0xfa;
+-
+- switch (c) {
+-
+- case 0xeb: /* Poll */
+- mousedev_packet(client, &client->ps2[1]);
+- client->bufsiz++; /* account for leading ACK */
+- break;
+-
+- case 0xf2: /* Get ID */
+- switch (client->mode) {
+- case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break;
+- case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
+- case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
+- }
+- client->bufsiz = 2;
+- break;
+-
+- case 0xe9: /* Get info */
+- client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
+- client->bufsiz = 4;
+- break;
+-
+- case 0xff: /* Reset */
+- client->impsseq = client->imexseq = 0;
+- client->mode = MOUSEDEV_EMUL_PS2;
+- client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
+- client->bufsiz = 3;
+- break;
+-
+- default:
+- client->bufsiz = 1;
+- break;
+- }
++ mousedev_generate_response(client, c);
+
+- client->buffer = client->bufsiz;
++ spin_unlock_irq(&client->packet_lock);
+ }
+
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
+-
+ wake_up_interruptible(&client->mousedev->wait);
+
+ return count;
+ }
+
+-static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
++static ssize_t mousedev_read(struct file *file, char __user *buffer,
++ size_t count, loff_t *ppos)
+ {
+ struct mousedev_client *client = file->private_data;
++ struct mousedev *mousedev = client->mousedev;
++ signed char data[sizeof(client->ps2)];
+ int retval = 0;
+
+- if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
++ if (!client->ready && !client->buffer && mousedev->exist &&
++ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+- retval = wait_event_interruptible(client->mousedev->wait,
+- !client->mousedev->exist || client->ready || client->buffer);
+-
++ retval = wait_event_interruptible(mousedev->wait,
++ !mousedev->exist || client->ready || client->buffer);
+ if (retval)
+ return retval;
+
+- if (!client->mousedev->exist)
++ if (!mousedev->exist)
+ return -ENODEV;
+
++ spin_lock_irq(&client->packet_lock);
++
+ if (!client->buffer && client->ready) {
+ mousedev_packet(client, client->ps2);
+ client->buffer = client->bufsiz;
+@@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file
+ if (count > client->buffer)
+ count = client->buffer;
+
++ memcpy(data, client->ps2 + client->bufsiz - client->buffer, count);
+ client->buffer -= count;
+
+- if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
++ spin_unlock_irq(&client->packet_lock);
++
++ if (copy_to_user(buffer, data, count))
+ return -EFAULT;
+
+ return count;
+@@ -692,6 +783,60 @@ static const struct file_operations mous
+ .fasync = mousedev_fasync,
+ };
+
++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
++ * blocking reads will stay, however new ones will fail.
++ */
++static void mousedev_mark_dead(struct mousedev *mousedev)
++{
++ mutex_lock(&mousedev->mutex);
++ mousedev->exist = 0;
++ mutex_unlock(&mousedev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void mousedev_hangup(struct mousedev *mousedev)
++{
++ struct mousedev_client *client;
++
++ spin_lock(&mousedev->client_lock);
++ list_for_each_entry(client, &mousedev->client_list, node)
++ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++ spin_unlock(&mousedev->client_lock);
++
++ wake_up_interruptible(&mousedev->wait);
++}
++
++static void mousedev_cleanup(struct mousedev *mousedev)
++{
++ struct input_handle *handle = &mousedev->handle;
++
++ mousedev_mark_dead(mousedev);
++ mousedev_hangup(mousedev);
++ mousedev_remove_chrdev(mousedev);
++
++ /* mousedev is marked dead so no one else accesses mousedev->open */
++ if (mousedev->open)
++ input_close_device(handle);
++}
++
+ static struct mousedev *mousedev_create(struct input_dev *dev,
+ struct input_handler *handler,
+ int minor)
+@@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(
+
+ INIT_LIST_HEAD(&mousedev->client_list);
+ INIT_LIST_HEAD(&mousedev->mixdev_node);
++ spin_lock_init(&mousedev->client_lock);
++ mutex_init(&mousedev->mutex);
++ lockdep_set_subclass(&mousedev->mutex,
++ minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0);
+ init_waitqueue_head(&mousedev->wait);
+
+ if (minor == MOUSEDEV_MIX)
+@@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(
+ mousedev->dev.release = mousedev_free;
+ device_initialize(&mousedev->dev);
+
+- mousedev_table[minor] = mousedev;
++ if (minor != MOUSEDEV_MIX) {
++ error = input_register_handle(&mousedev->handle);
++ if (error)
++ goto err_free_mousedev;
++ }
++
++ error = mousedev_install_chrdev(mousedev);
++ if (error)
++ goto err_unregister_handle;
+
+ error = device_add(&mousedev->dev);
+ if (error)
+- goto err_free_mousedev;
++ goto err_cleanup_mousedev;
+
+ return mousedev;
+
++ err_cleanup_mousedev:
++ mousedev_cleanup(mousedev);
++ err_unregister_handle:
++ if (minor != MOUSEDEV_MIX)
++ input_unregister_handle(&mousedev->handle);
+ err_free_mousedev:
+ put_device(&mousedev->dev);
+ err_out:
+@@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(
+
+ static void mousedev_destroy(struct mousedev *mousedev)
+ {
+- struct mousedev_client *client;
+-
+ device_del(&mousedev->dev);
+- mousedev->exist = 0;
++ mousedev_cleanup(mousedev);
++ if (mousedev->minor != MOUSEDEV_MIX)
++ input_unregister_handle(&mousedev->handle);
++ put_device(&mousedev->dev);
++}
+
+- if (mousedev->open) {
+- input_close_device(&mousedev->handle);
+- list_for_each_entry(client, &mousedev->client_list, node)
+- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+- wake_up_interruptible(&mousedev->wait);
++static int mixdev_add_device(struct mousedev *mousedev)
++{
++ int retval;
++
++ retval = mutex_lock_interruptible(&mousedev_mix->mutex);
++ if (retval)
++ return retval;
++
++ if (mousedev_mix->open) {
++ retval = mousedev_open_device(mousedev);
++ if (retval)
++ goto out;
++
++ mousedev->mixdev_open = 1;
+ }
+
++ get_device(&mousedev->dev);
++ list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
++
++ out:
++ mutex_unlock(&mousedev_mix->mutex);
++ return retval;
++}
++
++static void mixdev_remove_device(struct mousedev *mousedev)
++{
++ mutex_lock(&mousedev_mix->mutex);
++
++ if (mousedev->mixdev_open) {
++ mousedev->mixdev_open = 0;
++ mousedev_close_device(mousedev);
++ }
++
++ list_del_init(&mousedev->mixdev_node);
++ mutex_unlock(&mousedev_mix->mutex);
++
+ put_device(&mousedev->dev);
+ }
+
+-static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
++static int mousedev_connect(struct input_handler *handler,
++ struct input_dev *dev,
+ const struct input_device_id *id)
+ {
+ struct mousedev *mousedev;
+ int minor;
+ int error;
+
+- for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
++ 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;
+@@ -779,21 +976,13 @@ static int mousedev_connect(struct input
+ if (IS_ERR(mousedev))
+ return PTR_ERR(mousedev);
+
+- error = input_register_handle(&mousedev->handle);
+- if (error)
+- goto err_delete_mousedev;
+-
+ error = mixdev_add_device(mousedev);
+- if (error)
+- goto err_unregister_handle;
++ if (error) {
++ mousedev_destroy(mousedev);
++ return error;
++ }
+
+ return 0;
+-
+- err_unregister_handle:
+- input_unregister_handle(&mousedev->handle);
+- err_delete_mousedev:
+- device_unregister(&mousedev->dev);
+- return error;
+ }
+
+ static void mousedev_disconnect(struct input_handle *handle)
+@@ -801,33 +990,42 @@ static void mousedev_disconnect(struct i
+ struct mousedev *mousedev = handle->private;
+
+ mixdev_remove_device(mousedev);
+- input_unregister_handle(handle);
+ mousedev_destroy(mousedev);
+ }
+
+ static const struct input_device_id mousedev_ids[] = {
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_KEYBIT |
++ INPUT_DEVICE_ID_MATCH_RELBIT,
+ .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
+ .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
+ .relbit = { BIT(REL_X) | BIT(REL_Y) },
+- }, /* A mouse like device, at least one button, two relative axes */
++ }, /* A mouse like device, at least one button,
++ two relative axes */
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_RELBIT,
+ .evbit = { BIT(EV_KEY) | BIT(EV_REL) },
+ .relbit = { BIT(REL_WHEEL) },
+ }, /* A separate scrollwheel */
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_KEYBIT |
++ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
+ .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
+ .absbit = { BIT(ABS_X) | BIT(ABS_Y) },
+- }, /* A tablet like device, at least touch detection, two absolute axes */
++ }, /* A tablet like device, at least touch detection,
++ two absolute axes */
+ {
+- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
++ INPUT_DEVICE_ID_MATCH_KEYBIT |
++ INPUT_DEVICE_ID_MATCH_ABSBIT,
+ .evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
+ .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) },
+- .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
++ .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) |
++ BIT(ABS_TOOL_WIDTH) },
+ }, /* A touchpad */
+
+ { }, /* Terminating entry */
--- /dev/null
+From b9d2d110b10f7b4788d0fdd328cf57e34b767817 Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Thu, 30 Aug 2007 00:22:39 -0400
+Subject: [PATCH] Input: tsdev - implement proper locking
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch b9d2d110b10f7b4788d0fdd328cf57e34b767817 in mainline.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/tsdev.c | 392 +++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 278 insertions(+), 114 deletions(-)
+
+--- a/drivers/input/tsdev.c
++++ b/drivers/input/tsdev.c
+@@ -112,6 +112,8 @@ struct tsdev {
+ 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;
+
+ int x, y, pressure;
+@@ -122,8 +124,9 @@ struct tsdev_client {
+ struct fasync_struct *fasync;
+ struct list_head node;
+ struct tsdev *tsdev;
++ struct ts_event buffer[TSDEV_BUFFER_SIZE];
+ int head, tail;
+- struct ts_event event[TSDEV_BUFFER_SIZE];
++ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
+ int raw;
+ };
+
+@@ -137,6 +140,7 @@ struct tsdev_client {
+ #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
+
+ static struct tsdev *tsdev_table[TSDEV_MINORS/2];
++static DEFINE_MUTEX(tsdev_table_mutex);
+
+ static int tsdev_fasync(int fd, struct file *file, int on)
+ {
+@@ -144,9 +148,91 @@ static int tsdev_fasync(int fd, struct f
+ int retval;
+
+ retval = fasync_helper(fd, file, on, &client->fasync);
++
+ return retval < 0 ? retval : 0;
+ }
+
++static void tsdev_free(struct device *dev)
++{
++ struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
++
++ kfree(tsdev);
++}
++
++static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client)
++{
++ spin_lock(&tsdev->client_lock);
++ list_add_tail_rcu(&client->node, &tsdev->client_list);
++ spin_unlock(&tsdev->client_lock);
++ synchronize_sched();
++}
++
++static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client)
++{
++ spin_lock(&tsdev->client_lock);
++ list_del_rcu(&client->node);
++ spin_unlock(&tsdev->client_lock);
++ synchronize_sched();
++}
++
++static int tsdev_open_device(struct tsdev *tsdev)
++{
++ int retval;
++
++ retval = mutex_lock_interruptible(&tsdev->mutex);
++ if (retval)
++ return retval;
++
++ if (!tsdev->exist)
++ retval = -ENODEV;
++ else if (!tsdev->open++)
++ retval = input_open_device(&tsdev->handle);
++
++ mutex_unlock(&tsdev->mutex);
++ return retval;
++}
++
++static void tsdev_close_device(struct tsdev *tsdev)
++{
++ mutex_lock(&tsdev->mutex);
++
++ if (tsdev->exist && !--tsdev->open)
++ input_close_device(&tsdev->handle);
++
++ mutex_unlock(&tsdev->mutex);
++}
++
++/*
++ * Wake up users waiting for IO so they can disconnect from
++ * dead device.
++ */
++static void tsdev_hangup(struct tsdev *tsdev)
++{
++ struct tsdev_client *client;
++
++ spin_lock(&tsdev->client_lock);
++ list_for_each_entry(client, &tsdev->client_list, node)
++ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
++ spin_unlock(&tsdev->client_lock);
++
++ wake_up_interruptible(&tsdev->wait);
++}
++
++static int tsdev_release(struct inode *inode, struct file *file)
++{
++ struct tsdev_client *client = file->private_data;
++ struct tsdev *tsdev = client->tsdev;
++
++ tsdev_fasync(-1, file, 0);
++ tsdev_detach_client(tsdev, client);
++ kfree(client);
++
++ tsdev_close_device(tsdev);
++ put_device(&tsdev->dev);
++
++ return 0;
++}
++
+ static int tsdev_open(struct inode *inode, struct file *file)
+ {
+ int i = iminor(inode) - TSDEV_MINOR_BASE;
+@@ -161,11 +247,16 @@ static int tsdev_open(struct inode *inod
+ if (i >= TSDEV_MINORS)
+ return -ENODEV;
+
++ error = mutex_lock_interruptible(&tsdev_table_mutex);
++ if (error)
++ return error;
+ tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
+- if (!tsdev || !tsdev->exist)
+- return -ENODEV;
++ if (tsdev)
++ get_device(&tsdev->dev);
++ mutex_unlock(&tsdev_table_mutex);
+
+- get_device(&tsdev->dev);
++ if (!tsdev)
++ return -ENODEV;
+
+ client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
+ if (!client) {
+@@ -173,51 +264,42 @@ static int tsdev_open(struct inode *inod
+ goto err_put_tsdev;
+ }
+
++ spin_lock_init(&client->buffer_lock);
+ client->tsdev = tsdev;
+- client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
+- list_add_tail(&client->node, &tsdev->client_list);
++ client->raw = i >= TSDEV_MINORS / 2;
++ tsdev_attach_client(tsdev, client);
+
+- if (!tsdev->open++ && tsdev->exist) {
+- error = input_open_device(&tsdev->handle);
+- if (error)
+- goto err_free_client;
+- }
++ error = tsdev_open_device(tsdev);
++ if (error)
++ goto err_free_client;
+
+ file->private_data = client;
+ return 0;
+
+ err_free_client:
+- list_del(&client->node);
++ tsdev_detach_client(tsdev, client);
+ kfree(client);
+ err_put_tsdev:
+ put_device(&tsdev->dev);
+ return error;
+ }
+
+-static void tsdev_free(struct device *dev)
++static int tsdev_fetch_next_event(struct tsdev_client *client,
++ struct ts_event *event)
+ {
+- struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
++ int have_event;
+
+- tsdev_table[tsdev->minor] = NULL;
+- kfree(tsdev);
+-}
+-
+-static int tsdev_release(struct inode *inode, struct file *file)
+-{
+- struct tsdev_client *client = file->private_data;
+- struct tsdev *tsdev = client->tsdev;
+-
+- tsdev_fasync(-1, file, 0);
++ spin_lock_irq(&client->buffer_lock);
+
+- list_del(&client->node);
+- kfree(client);
+-
+- if (!--tsdev->open && tsdev->exist)
+- input_close_device(&tsdev->handle);
++ have_event = client->head != client->tail;
++ if (have_event) {
++ *event = client->buffer[client->tail++];
++ client->tail &= TSDEV_BUFFER_SIZE - 1;
++ }
+
+- put_device(&tsdev->dev);
++ spin_unlock_irq(&client->buffer_lock);
+
+- return 0;
++ return have_event;
+ }
+
+ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
+@@ -225,9 +307,11 @@ static ssize_t tsdev_read(struct file *f
+ {
+ struct tsdev_client *client = file->private_data;
+ struct tsdev *tsdev = client->tsdev;
+- int retval = 0;
++ struct ts_event event;
++ int retval;
+
+- if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
++ if (client->head == client->tail && tsdev->exist &&
++ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ retval = wait_event_interruptible(tsdev->wait,
+@@ -238,13 +322,14 @@ static ssize_t tsdev_read(struct file *f
+ if (!tsdev->exist)
+ return -ENODEV;
+
+- while (client->head != client->tail &&
+- retval + sizeof (struct ts_event) <= count) {
+- if (copy_to_user (buffer + retval, client->event + client->tail,
+- sizeof (struct ts_event)))
++ while (retval + sizeof(struct ts_event) <= count &&
++ tsdev_fetch_next_event(client, &event)) {
++
++ if (copy_to_user(buffer + retval, &event,
++ sizeof(struct ts_event)))
+ return -EFAULT;
+- client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
+- retval += sizeof (struct ts_event);
++
++ retval += sizeof(struct ts_event);
+ }
+
+ return retval;
+@@ -261,14 +346,23 @@ static unsigned int tsdev_poll(struct fi
+ (tsdev->exist ? 0 : (POLLHUP | POLLERR));
+ }
+
+-static int tsdev_ioctl(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
++static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ {
+ struct tsdev_client *client = file->private_data;
+ struct tsdev *tsdev = client->tsdev;
+ int retval = 0;
+
++ retval = mutex_lock_interruptible(&tsdev->mutex);
++ if (retval)
++ return retval;
++
++ if (!tsdev->exist) {
++ retval = -ENODEV;
++ goto out;
++ }
++
+ switch (cmd) {
++
+ case TS_GET_CAL:
+ if (copy_to_user((void __user *)arg, &tsdev->cal,
+ sizeof (struct ts_calibration)))
+@@ -277,7 +371,7 @@ static int tsdev_ioctl(struct inode *ino
+
+ case TS_SET_CAL:
+ if (copy_from_user(&tsdev->cal, (void __user *)arg,
+- sizeof (struct ts_calibration)))
++ sizeof(struct ts_calibration)))
+ retval = -EFAULT;
+ break;
+
+@@ -286,29 +380,79 @@ static int tsdev_ioctl(struct inode *ino
+ break;
+ }
+
++ out:
++ mutex_unlock(&tsdev->mutex);
+ return retval;
+ }
+
+ static const struct file_operations tsdev_fops = {
+- .owner = THIS_MODULE,
+- .open = tsdev_open,
+- .release = tsdev_release,
+- .read = tsdev_read,
+- .poll = tsdev_poll,
+- .fasync = tsdev_fasync,
+- .ioctl = tsdev_ioctl,
++ .owner = THIS_MODULE,
++ .open = tsdev_open,
++ .release = tsdev_release,
++ .read = tsdev_read,
++ .poll = tsdev_poll,
++ .fasync = tsdev_fasync,
++ .unlocked_ioctl = tsdev_ioctl,
+ };
+
++static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client,
++ int x, int y, int pressure, int millisecs)
++{
++ struct ts_event *event;
++ int tmp;
++
++ /* Interrupts are already disabled, just acquire the lock */
++ spin_lock(&client->buffer_lock);
++
++ event = &client->buffer[client->head++];
++ client->head &= TSDEV_BUFFER_SIZE - 1;
++
++ /* Calibration */
++ if (!client->raw) {
++ x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
++ y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
++ if (tsdev->cal.xyswap) {
++ tmp = x; x = y; y = tmp;
++ }
++ }
++
++ event->millisecs = millisecs;
++ event->x = x;
++ event->y = y;
++ event->pressure = pressure;
++
++ spin_unlock(&client->buffer_lock);
++
++ kill_fasync(&client->fasync, SIGIO, POLL_IN);
++}
++
++static void tsdev_distribute_event(struct tsdev *tsdev)
++{
++ struct tsdev_client *client;
++ struct timeval time;
++ int millisecs;
++
++ do_gettimeofday(&time);
++ millisecs = time.tv_usec / 1000;
++
++ list_for_each_entry_rcu(client, &tsdev->client_list, node)
++ tsdev_pass_event(tsdev, client,
++ tsdev->x, tsdev->y,
++ tsdev->pressure, millisecs);
++}
++
+ static void tsdev_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int value)
+ {
+ struct tsdev *tsdev = handle->private;
+- struct tsdev_client *client;
+- struct timeval time;
++ struct input_dev *dev = handle->dev;
++ int wake_up_readers = 0;
+
+ switch (type) {
++
+ case EV_ABS:
+ switch (code) {
++
+ case ABS_X:
+ tsdev->x = value;
+ break;
+@@ -318,9 +462,9 @@ static void tsdev_event(struct input_han
+ break;
+
+ case ABS_PRESSURE:
+- if (value > handle->dev->absmax[ABS_PRESSURE])
+- value = handle->dev->absmax[ABS_PRESSURE];
+- value -= handle->dev->absmin[ABS_PRESSURE];
++ if (value > dev->absmax[ABS_PRESSURE])
++ value = dev->absmax[ABS_PRESSURE];
++ value -= dev->absmin[ABS_PRESSURE];
+ if (value < 0)
+ value = 0;
+ tsdev->pressure = value;
+@@ -330,6 +474,7 @@ static void tsdev_event(struct input_han
+
+ case EV_REL:
+ switch (code) {
++
+ case REL_X:
+ tsdev->x += value;
+ if (tsdev->x < 0)
+@@ -351,6 +496,7 @@ static void tsdev_event(struct input_han
+ case EV_KEY:
+ if (code == BTN_TOUCH || code == BTN_MOUSE) {
+ switch (value) {
++
+ case 0:
+ tsdev->pressure = 0;
+ break;
+@@ -362,49 +508,71 @@ static void tsdev_event(struct input_han
+ }
+ }
+ break;
++
++ case EV_SYN:
++ if (code == SYN_REPORT) {
++ tsdev_distribute_event(tsdev);
++ wake_up_readers = 1;
++ }
++ break;
+ }
+
+- if (type != EV_SYN || code != SYN_REPORT)
+- return;
++ if (wake_up_readers)
++ wake_up_interruptible(&tsdev->wait);
++}
+
+- list_for_each_entry(client, &tsdev->client_list, node) {
+- int x, y, tmp;
++static int tsdev_install_chrdev(struct tsdev *tsdev)
++{
++ tsdev_table[tsdev->minor] = tsdev;
++ return 0;
++}
+
+- do_gettimeofday(&time);
+- client->event[client->head].millisecs = time.tv_usec / 1000;
+- client->event[client->head].pressure = tsdev->pressure;
+-
+- x = tsdev->x;
+- y = tsdev->y;
+-
+- /* Calibration */
+- if (!client->raw) {
+- x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
+- y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
+- if (tsdev->cal.xyswap) {
+- tmp = x; x = y; y = tmp;
+- }
+- }
++static void tsdev_remove_chrdev(struct tsdev *tsdev)
++{
++ mutex_lock(&tsdev_table_mutex);
++ tsdev_table[tsdev->minor] = NULL;
++ mutex_unlock(&tsdev_table_mutex);
++}
+
+- client->event[client->head].x = x;
+- client->event[client->head].y = y;
+- client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
+- kill_fasync(&client->fasync, SIGIO, POLL_IN);
+- }
+- wake_up_interruptible(&tsdev->wait);
++/*
++ * Mark device non-existant. This disables writes, ioctls and
++ * prevents new users from opening the device. Already posted
++ * blocking reads will stay, however new ones will fail.
++ */
++static void tsdev_mark_dead(struct tsdev *tsdev)
++{
++ mutex_lock(&tsdev->mutex);
++ tsdev->exist = 0;
++ mutex_unlock(&tsdev->mutex);
++}
++
++static void tsdev_cleanup(struct tsdev *tsdev)
++{
++ struct input_handle *handle = &tsdev->handle;
++
++ tsdev_mark_dead(tsdev);
++ tsdev_hangup(tsdev);
++ tsdev_remove_chrdev(tsdev);
++
++ /* tsdev is marked dead so noone else accesses tsdev->open */
++ if (tsdev->open)
++ input_close_device(handle);
+ }
+
+ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+ {
+ struct tsdev *tsdev;
+- int minor, delta;
++ int delta;
++ int minor;
+ int error;
+
+- for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
+- if (minor >= TSDEV_MINORS / 2) {
+- printk(KERN_ERR
+- "tsdev: You have way too many touchscreens\n");
++ for (minor = 0; minor < TSDEV_MINORS / 2; minor++)
++ if (!tsdev_table[minor])
++ break;
++
++ if (minor == TSDEV_MINORS) {
++ printk(KERN_ERR "tsdev: no more free tsdev devices\n");
+ return -ENFILE;
+ }
+
+@@ -413,15 +581,18 @@ static int tsdev_connect(struct input_ha
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&tsdev->client_list);
++ spin_lock_init(&tsdev->client_lock);
++ mutex_init(&tsdev->mutex);
+ init_waitqueue_head(&tsdev->wait);
+
++ snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
+ tsdev->exist = 1;
+ tsdev->minor = minor;
++
+ tsdev->handle.dev = dev;
+ tsdev->handle.name = tsdev->name;
+ tsdev->handle.handler = handler;
+ tsdev->handle.private = tsdev;
+- snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
+
+ /* Precompute the rough calibration matrix */
+ delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
+@@ -436,28 +607,31 @@ static int tsdev_connect(struct input_ha
+ tsdev->cal.yscale = (yres << 8) / delta;
+ tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
+
+- snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id),
+- "ts%d", minor);
++ strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id));
++ tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
+ tsdev->dev.class = &input_class;
+ tsdev->dev.parent = &dev->dev;
+- tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
+ tsdev->dev.release = tsdev_free;
+ device_initialize(&tsdev->dev);
+
+- tsdev_table[minor] = tsdev;
+-
+- error = device_add(&tsdev->dev);
++ error = input_register_handle(&tsdev->handle);
+ if (error)
+ goto err_free_tsdev;
+
+- error = input_register_handle(&tsdev->handle);
++ error = tsdev_install_chrdev(tsdev);
+ if (error)
+- goto err_delete_tsdev;
++ goto err_unregister_handle;
++
++ error = device_add(&tsdev->dev);
++ if (error)
++ goto err_cleanup_tsdev;
+
+ return 0;
+
+- err_delete_tsdev:
+- device_del(&tsdev->dev);
++ err_cleanup_tsdev:
++ tsdev_cleanup(tsdev);
++ err_unregister_handle:
++ input_unregister_handle(&tsdev->handle);
+ err_free_tsdev:
+ put_device(&tsdev->dev);
+ return error;
+@@ -466,20 +640,10 @@ static int tsdev_connect(struct input_ha
+ static void tsdev_disconnect(struct input_handle *handle)
+ {
+ struct tsdev *tsdev = handle->private;
+- struct tsdev_client *client;
+
+- input_unregister_handle(handle);
+ device_del(&tsdev->dev);
+-
+- tsdev->exist = 0;
+-
+- if (tsdev->open) {
+- input_close_device(handle);
+- list_for_each_entry(client, &tsdev->client_list, node)
+- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+- wake_up_interruptible(&tsdev->wait);
+- }
+-
++ tsdev_cleanup(tsdev);
++ input_unregister_handle(handle);
+ put_device(&tsdev->dev);
+ }
+
+@@ -510,13 +674,13 @@ static const struct input_device_id tsde
+ MODULE_DEVICE_TABLE(input, tsdev_ids);
+
+ static struct input_handler tsdev_handler = {
+- .event = tsdev_event,
+- .connect = tsdev_connect,
+- .disconnect = tsdev_disconnect,
+- .fops = &tsdev_fops,
+- .minor = TSDEV_MINOR_BASE,
+- .name = "tsdev",
+- .id_table = tsdev_ids,
++ .event = tsdev_event,
++ .connect = tsdev_connect,
++ .disconnect = tsdev_disconnect,
++ .fops = &tsdev_fops,
++ .minor = TSDEV_MINOR_BASE,
++ .name = "tsdev",
++ .id_table = tsdev_ids,
+ };
+
+ static int __init tsdev_init(void)
--- /dev/null
+From 82ba56c273911f7eda79849cfa0fc2d2e5a3b75b Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Sat, 13 Oct 2007 15:46:55 -0400
+Subject: [PATCH] Input: use full RCU API
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+patch 82ba56c273911f7eda79849cfa0fc2d2e5a3b75b in mainline.
+
+RT guys alerted me to the fact that in their tree spinlocks
+are preemptible and it is better to use full RCU API
+(rcu_read_lock()/rcu_read_unlock()) to be safe.
+
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Cc: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/input/evdev.c | 22 +++++++++-------------
+ drivers/input/input.c | 36 +++++++++++++++---------------------
+ drivers/input/joydev.c | 11 ++++-------
+ drivers/input/mousedev.c | 11 ++++-------
+ 4 files changed, 32 insertions(+), 48 deletions(-)
+
+--- a/drivers/input/evdev.c
++++ b/drivers/input/evdev.c
+@@ -63,10 +63,7 @@ static void evdev_pass_event(struct evde
+ }
+
+ /*
+- * Pass incoming event to all connected clients. Note that we are
+- * caleld under a spinlock with interrupts off so we don't need
+- * to use rcu_read_lock() here. Writers will be using syncronize_sched()
+- * instead of synchrnoize_rcu().
++ * Pass incoming event to all connected clients.
+ */
+ static void evdev_event(struct input_handle *handle,
+ unsigned int type, unsigned int code, int value)
+@@ -80,6 +77,8 @@ static void evdev_event(struct input_han
+ event.code = code;
+ event.value = value;
+
++ rcu_read_lock();
++
+ client = rcu_dereference(evdev->grab);
+ if (client)
+ evdev_pass_event(client, &event);
+@@ -87,6 +86,8 @@ static void evdev_event(struct input_han
+ list_for_each_entry_rcu(client, &evdev->client_list, node)
+ evdev_pass_event(client, &event);
+
++ rcu_read_unlock();
++
+ wake_up_interruptible(&evdev->wait);
+ }
+
+@@ -142,12 +143,7 @@ static int evdev_grab(struct evdev *evde
+ return error;
+
+ rcu_assign_pointer(evdev->grab, client);
+- /*
+- * We don't use synchronize_rcu() here because read-side
+- * critical section is protected by a spinlock instead
+- * of rcu_read_lock().
+- */
+- synchronize_sched();
++ synchronize_rcu();
+
+ return 0;
+ }
+@@ -158,7 +154,7 @@ static int evdev_ungrab(struct evdev *ev
+ return -EINVAL;
+
+ rcu_assign_pointer(evdev->grab, NULL);
+- synchronize_sched();
++ synchronize_rcu();
+ input_release_device(&evdev->handle);
+
+ return 0;
+@@ -170,7 +166,7 @@ static void evdev_attach_client(struct e
+ spin_lock(&evdev->client_lock);
+ list_add_tail_rcu(&client->node, &evdev->client_list);
+ spin_unlock(&evdev->client_lock);
+- synchronize_sched();
++ synchronize_rcu();
+ }
+
+ static void evdev_detach_client(struct evdev *evdev,
+@@ -179,7 +175,7 @@ static void evdev_detach_client(struct e
+ spin_lock(&evdev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&evdev->client_lock);
+- synchronize_sched();
++ synchronize_rcu();
+ }
+
+ static int evdev_open_device(struct evdev *evdev)
+--- a/drivers/input/input.c
++++ b/drivers/input/input.c
+@@ -65,16 +65,16 @@ static int input_defuzz_abs_event(int va
+
+ /*
+ * Pass event through all open handles. This function is called with
+- * dev->event_lock held and interrupts disabled. Because of that we
+- * do not need to use rcu_read_lock() here although we are using RCU
+- * to access handle list. Note that because of that write-side uses
+- * synchronize_sched() instead of synchronize_ru().
++ * dev->event_lock held and interrupts disabled.
+ */
+ static void input_pass_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
+ {
+- struct input_handle *handle = rcu_dereference(dev->grab);
++ struct input_handle *handle;
++
++ rcu_read_lock();
+
++ handle = rcu_dereference(dev->grab);
+ if (handle)
+ handle->handler->event(handle, type, code, value);
+ else
+@@ -82,6 +82,7 @@ static void input_pass_event(struct inpu
+ if (handle->open)
+ handle->handler->event(handle,
+ type, code, value);
++ rcu_read_unlock();
+ }
+
+ /*
+@@ -293,9 +294,11 @@ void input_inject_event(struct input_han
+ if (is_event_supported(type, dev->evbit, EV_MAX)) {
+ spin_lock_irqsave(&dev->event_lock, flags);
+
++ rcu_read_lock();
+ grab = rcu_dereference(dev->grab);
+ if (!grab || grab == handle)
+ input_handle_event(dev, type, code, value);
++ rcu_read_unlock();
+
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+@@ -325,11 +328,7 @@ int input_grab_device(struct input_handl
+ }
+
+ rcu_assign_pointer(dev->grab, handle);
+- /*
+- * Not using synchronize_rcu() because read-side is protected
+- * by a spinlock with interrupts off instead of rcu_read_lock().
+- */
+- synchronize_sched();
++ synchronize_rcu();
+
+ out:
+ mutex_unlock(&dev->mutex);
+@@ -344,7 +343,7 @@ static void __input_release_device(struc
+ if (dev->grab == handle) {
+ rcu_assign_pointer(dev->grab, NULL);
+ /* Make sure input_pass_event() notices that grab is gone */
+- synchronize_sched();
++ synchronize_rcu();
+
+ list_for_each_entry(handle, &dev->h_list, d_node)
+ if (handle->open && handle->handler->start)
+@@ -404,7 +403,7 @@ int input_open_device(struct input_handl
+ * Make sure we are not delivering any more events
+ * through this handle
+ */
+- synchronize_sched();
++ synchronize_rcu();
+ }
+ }
+
+@@ -451,11 +450,11 @@ void input_close_device(struct input_han
+
+ if (!--handle->open) {
+ /*
+- * synchronize_sched() makes sure that input_pass_event()
++ * synchronize_rcu() makes sure that input_pass_event()
+ * completed and that no more input events are delivered
+ * through this handle
+ */
+- synchronize_sched();
++ synchronize_rcu();
+ }
+
+ mutex_unlock(&dev->mutex);
+@@ -1499,12 +1498,7 @@ int input_register_handle(struct input_h
+ return error;
+ list_add_tail_rcu(&handle->d_node, &dev->h_list);
+ mutex_unlock(&dev->mutex);
+- /*
+- * We don't use synchronize_rcu() here because we rely
+- * on dev->event_lock to protect read-side critical
+- * section in input_pass_event().
+- */
+- synchronize_sched();
++ synchronize_rcu();
+
+ /*
+ * Since we are supposed to be called from ->connect()
+@@ -1543,7 +1537,7 @@ void input_unregister_handle(struct inpu
+ mutex_lock(&dev->mutex);
+ list_del_rcu(&handle->d_node);
+ mutex_unlock(&dev->mutex);
+- synchronize_sched();
++ synchronize_rcu();
+ }
+ EXPORT_SYMBOL(input_unregister_handle);
+
+--- a/drivers/input/joydev.c
++++ b/drivers/input/joydev.c
+@@ -149,8 +149,10 @@ static void joydev_event(struct input_ha
+
+ event.time = jiffies_to_msecs(jiffies);
+
++ rcu_read_lock();
+ list_for_each_entry_rcu(client, &joydev->client_list, node)
+ joydev_pass_event(client, &event);
++ rcu_read_unlock();
+
+ wake_up_interruptible(&joydev->wait);
+ }
+@@ -178,12 +180,7 @@ static void joydev_attach_client(struct
+ spin_lock(&joydev->client_lock);
+ list_add_tail_rcu(&client->node, &joydev->client_list);
+ spin_unlock(&joydev->client_lock);
+- /*
+- * We don't use synchronize_rcu() here because read-side
+- * critical section is protected by a spinlock (dev->event_lock)
+- * instead of rcu_read_lock().
+- */
+- synchronize_sched();
++ synchronize_rcu();
+ }
+
+ static void joydev_detach_client(struct joydev *joydev,
+@@ -192,7 +189,7 @@ static void joydev_detach_client(struct
+ spin_lock(&joydev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&joydev->client_lock);
+- synchronize_sched();
++ synchronize_rcu();
+ }
+
+ static int joydev_open_device(struct joydev *joydev)
+--- a/drivers/input/mousedev.c
++++ b/drivers/input/mousedev.c
+@@ -265,6 +265,7 @@ static void mousedev_notify_readers(stru
+ unsigned int new_head;
+ int wake_readers = 0;
+
++ rcu_read_lock();
+ list_for_each_entry_rcu(client, &mousedev->client_list, node) {
+
+ /* Just acquire the lock, interrupts already disabled */
+@@ -309,6 +310,7 @@ static void mousedev_notify_readers(stru
+ wake_readers = 1;
+ }
+ }
++ rcu_read_unlock();
+
+ if (wake_readers)
+ wake_up_interruptible(&mousedev->wait);
+@@ -496,12 +498,7 @@ static void mousedev_attach_client(struc
+ spin_lock(&mousedev->client_lock);
+ list_add_tail_rcu(&client->node, &mousedev->client_list);
+ spin_unlock(&mousedev->client_lock);
+- /*
+- * We don't use synchronize_rcu() here because read-side
+- * critical section is protected by a spinlock (dev->event_lock)
+- * instead of rcu_read_lock().
+- */
+- synchronize_sched();
++ synchronize_rcu();
+ }
+
+ static void mousedev_detach_client(struct mousedev *mousedev,
+@@ -510,7 +507,7 @@ static void mousedev_detach_client(struc
+ spin_lock(&mousedev->client_lock);
+ list_del_rcu(&client->node);
+ spin_unlock(&mousedev->client_lock);
+- synchronize_sched();
++ synchronize_rcu();
+ }
+
+ static int mousedev_release(struct inode *inode, struct file *file)
chelsio-fix-skb-dev-setting.patch
cxgb-fix-t2-gso.patch
cxgb-fix-stats.patch
+input-implement-proper-locking-in-input-core.patch
+input-evdev-implement-proper-locking.patch
+input-mousedev-implement-proper-locking.patch
+input-joydev-implement-proper-locking.patch
+input-tsdev-implement-proper-locking.patch
+input-use-full-rcu-api.patch
+input-fix-open-count-handling-in-input-interfaces.patch