aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/evdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r--drivers/input/evdev.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 88d8e4cb419a..4cf25347b015 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -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;