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.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 88d8e4cb419a..be0921ef6b52 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -41,6 +41,7 @@ struct evdev {
41struct evdev_client { 41struct evdev_client {
42 unsigned int head; 42 unsigned int head;
43 unsigned int tail; 43 unsigned int tail;
44 unsigned int packet_head; /* [future] position of the first element of next packet */
44 spinlock_t buffer_lock; /* protects access to buffer, head and tail */ 45 spinlock_t buffer_lock; /* protects access to buffer, head and tail */
45 struct fasync_struct *fasync; 46 struct fasync_struct *fasync;
46 struct evdev *evdev; 47 struct evdev *evdev;
@@ -72,12 +73,16 @@ static void evdev_pass_event(struct evdev_client *client,
72 client->buffer[client->tail].type = EV_SYN; 73 client->buffer[client->tail].type = EV_SYN;
73 client->buffer[client->tail].code = SYN_DROPPED; 74 client->buffer[client->tail].code = SYN_DROPPED;
74 client->buffer[client->tail].value = 0; 75 client->buffer[client->tail].value = 0;
75 }
76 76
77 spin_unlock(&client->buffer_lock); 77 client->packet_head = client->tail;
78 }
78 79
79 if (event->type == EV_SYN) 80 if (event->type == EV_SYN && event->code == SYN_REPORT) {
81 client->packet_head = client->head;
80 kill_fasync(&client->fasync, SIGIO, POLL_IN); 82 kill_fasync(&client->fasync, SIGIO, POLL_IN);
83 }
84
85 spin_unlock(&client->buffer_lock);
81} 86}
82 87
83/* 88/*
@@ -159,7 +164,6 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
159 return error; 164 return error;
160 165
161 rcu_assign_pointer(evdev->grab, client); 166 rcu_assign_pointer(evdev->grab, client);
162 synchronize_rcu();
163 167
164 return 0; 168 return 0;
165} 169}
@@ -182,7 +186,6 @@ static void evdev_attach_client(struct evdev *evdev,
182 spin_lock(&evdev->client_lock); 186 spin_lock(&evdev->client_lock);
183 list_add_tail_rcu(&client->node, &evdev->client_list); 187 list_add_tail_rcu(&client->node, &evdev->client_list);
184 spin_unlock(&evdev->client_lock); 188 spin_unlock(&evdev->client_lock);
185 synchronize_rcu();
186} 189}
187 190
188static void evdev_detach_client(struct evdev *evdev, 191static void evdev_detach_client(struct evdev *evdev,
@@ -387,12 +390,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
387 if (count < input_event_size()) 390 if (count < input_event_size())
388 return -EINVAL; 391 return -EINVAL;
389 392
390 if (client->head == client->tail && evdev->exist && 393 if (client->packet_head == client->tail && evdev->exist &&
391 (file->f_flags & O_NONBLOCK)) 394 (file->f_flags & O_NONBLOCK))
392 return -EAGAIN; 395 return -EAGAIN;
393 396
394 retval = wait_event_interruptible(evdev->wait, 397 retval = wait_event_interruptible(evdev->wait,
395 client->head != client->tail || !evdev->exist); 398 client->packet_head != client->tail || !evdev->exist);
396 if (retval) 399 if (retval)
397 return retval; 400 return retval;
398 401
@@ -421,7 +424,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
421 poll_wait(file, &evdev->wait, wait); 424 poll_wait(file, &evdev->wait, wait);
422 425
423 mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR; 426 mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
424 if (client->head != client->tail) 427 if (client->packet_head != client->tail)
425 mask |= POLLIN | POLLRDNORM; 428 mask |= POLLIN | POLLRDNORM;
426 429
427 return mask; 430 return mask;