diff options
Diffstat (limited to 'drivers/input/evdev.c')
-rw-r--r-- | drivers/input/evdev.c | 19 |
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 { | |||
41 | struct evdev_client { | 41 | struct 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 | ||
188 | static void evdev_detach_client(struct evdev *evdev, | 191 | static 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; |