Merge branch 'next' into for-linus-3.0
[pandora-kernel.git] / drivers / input / evdev.c
index 88d8e4c..4cf2534 100644 (file)
@@ -41,6 +41,7 @@ struct evdev {
 struct evdev_client {
        unsigned int head;
        unsigned int tail;
+       unsigned int packet_head; /* [future] position of the first element of next packet */
        spinlock_t buffer_lock; /* protects access to buffer, head and tail */
        struct fasync_struct *fasync;
        struct evdev *evdev;
@@ -72,12 +73,16 @@ static void evdev_pass_event(struct evdev_client *client,
                client->buffer[client->tail].type = EV_SYN;
                client->buffer[client->tail].code = SYN_DROPPED;
                client->buffer[client->tail].value = 0;
-       }
 
-       spin_unlock(&client->buffer_lock);
+               client->packet_head = client->tail;
+       }
 
-       if (event->type == EV_SYN)
+       if (event->type == EV_SYN && event->code == SYN_REPORT) {
+               client->packet_head = client->head;
                kill_fasync(&client->fasync, SIGIO, POLL_IN);
+       }
+
+       spin_unlock(&client->buffer_lock);
 }
 
 /*
@@ -106,7 +111,8 @@ static void evdev_event(struct input_handle *handle,
 
        rcu_read_unlock();
 
-       wake_up_interruptible(&evdev->wait);
+       if (type == EV_SYN && code == SYN_REPORT)
+               wake_up_interruptible(&evdev->wait);
 }
 
 static int evdev_fasync(int fd, struct file *file, int on)
@@ -159,7 +165,6 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
                return error;
 
        rcu_assign_pointer(evdev->grab, client);
-       synchronize_rcu();
 
        return 0;
 }
@@ -182,7 +187,6 @@ static void evdev_attach_client(struct evdev *evdev,
        spin_lock(&evdev->client_lock);
        list_add_tail_rcu(&client->node, &evdev->client_list);
        spin_unlock(&evdev->client_lock);
-       synchronize_rcu();
 }
 
 static void evdev_detach_client(struct evdev *evdev,
@@ -387,12 +391,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
        if (count < input_event_size())
                return -EINVAL;
 
-       if (client->head == client->tail && evdev->exist &&
+       if (client->packet_head == client->tail && evdev->exist &&
            (file->f_flags & O_NONBLOCK))
                return -EAGAIN;
 
        retval = wait_event_interruptible(evdev->wait,
-               client->head != client->tail || !evdev->exist);
+               client->packet_head != client->tail || !evdev->exist);
        if (retval)
                return retval;
 
@@ -421,7 +425,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
        poll_wait(file, &evdev->wait, wait);
 
        mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
-       if (client->head != client->tail)
+       if (client->packet_head != client->tail)
                mask |= POLLIN | POLLRDNORM;
 
        return mask;