diff options
Diffstat (limited to 'drivers/input/evdev.c')
| -rw-r--r-- | drivers/input/evdev.c | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 6c58bfff01a3..118d0300f1fb 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -54,16 +54,9 @@ struct evdev_client { | |||
| 54 | static struct evdev *evdev_table[EVDEV_MINORS]; | 54 | static struct evdev *evdev_table[EVDEV_MINORS]; |
| 55 | static DEFINE_MUTEX(evdev_table_mutex); | 55 | static DEFINE_MUTEX(evdev_table_mutex); |
| 56 | 56 | ||
| 57 | static void evdev_pass_event(struct evdev_client *client, | 57 | static void __pass_event(struct evdev_client *client, |
| 58 | struct input_event *event, | 58 | const struct input_event *event) |
| 59 | ktime_t mono, ktime_t real) | ||
| 60 | { | 59 | { |
| 61 | event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | ||
| 62 | mono : real); | ||
| 63 | |||
| 64 | /* Interrupts are disabled, just acquire the lock. */ | ||
| 65 | spin_lock(&client->buffer_lock); | ||
| 66 | |||
| 67 | client->buffer[client->head++] = *event; | 60 | client->buffer[client->head++] = *event; |
| 68 | client->head &= client->bufsize - 1; | 61 | client->head &= client->bufsize - 1; |
| 69 | 62 | ||
| @@ -86,42 +79,74 @@ static void evdev_pass_event(struct evdev_client *client, | |||
| 86 | client->packet_head = client->head; | 79 | client->packet_head = client->head; |
| 87 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 80 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
| 88 | } | 81 | } |
| 82 | } | ||
| 83 | |||
| 84 | static void evdev_pass_values(struct evdev_client *client, | ||
| 85 | const struct input_value *vals, unsigned int count, | ||
| 86 | ktime_t mono, ktime_t real) | ||
| 87 | { | ||
| 88 | struct evdev *evdev = client->evdev; | ||
| 89 | const struct input_value *v; | ||
| 90 | struct input_event event; | ||
| 91 | bool wakeup = false; | ||
| 92 | |||
| 93 | event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? | ||
| 94 | mono : real); | ||
| 95 | |||
| 96 | /* Interrupts are disabled, just acquire the lock. */ | ||
| 97 | spin_lock(&client->buffer_lock); | ||
| 98 | |||
| 99 | for (v = vals; v != vals + count; v++) { | ||
| 100 | event.type = v->type; | ||
| 101 | event.code = v->code; | ||
| 102 | event.value = v->value; | ||
| 103 | __pass_event(client, &event); | ||
| 104 | if (v->type == EV_SYN && v->code == SYN_REPORT) | ||
| 105 | wakeup = true; | ||
| 106 | } | ||
| 89 | 107 | ||
| 90 | spin_unlock(&client->buffer_lock); | 108 | spin_unlock(&client->buffer_lock); |
| 109 | |||
| 110 | if (wakeup) | ||
| 111 | wake_up_interruptible(&evdev->wait); | ||
| 91 | } | 112 | } |
| 92 | 113 | ||
| 93 | /* | 114 | /* |
| 94 | * Pass incoming event to all connected clients. | 115 | * Pass incoming events to all connected clients. |
| 95 | */ | 116 | */ |
| 96 | static void evdev_event(struct input_handle *handle, | 117 | static void evdev_events(struct input_handle *handle, |
| 97 | unsigned int type, unsigned int code, int value) | 118 | const struct input_value *vals, unsigned int count) |
| 98 | { | 119 | { |
| 99 | struct evdev *evdev = handle->private; | 120 | struct evdev *evdev = handle->private; |
| 100 | struct evdev_client *client; | 121 | struct evdev_client *client; |
| 101 | struct input_event event; | ||
| 102 | ktime_t time_mono, time_real; | 122 | ktime_t time_mono, time_real; |
| 103 | 123 | ||
| 104 | time_mono = ktime_get(); | 124 | time_mono = ktime_get(); |
| 105 | time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); | 125 | time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); |
| 106 | 126 | ||
| 107 | event.type = type; | ||
| 108 | event.code = code; | ||
| 109 | event.value = value; | ||
| 110 | |||
| 111 | rcu_read_lock(); | 127 | rcu_read_lock(); |
| 112 | 128 | ||
| 113 | client = rcu_dereference(evdev->grab); | 129 | client = rcu_dereference(evdev->grab); |
| 114 | 130 | ||
| 115 | if (client) | 131 | if (client) |
| 116 | evdev_pass_event(client, &event, time_mono, time_real); | 132 | evdev_pass_values(client, vals, count, time_mono, time_real); |
| 117 | else | 133 | else |
| 118 | list_for_each_entry_rcu(client, &evdev->client_list, node) | 134 | list_for_each_entry_rcu(client, &evdev->client_list, node) |
| 119 | evdev_pass_event(client, &event, time_mono, time_real); | 135 | evdev_pass_values(client, vals, count, |
| 136 | time_mono, time_real); | ||
| 120 | 137 | ||
| 121 | rcu_read_unlock(); | 138 | rcu_read_unlock(); |
| 139 | } | ||
| 122 | 140 | ||
| 123 | if (type == EV_SYN && code == SYN_REPORT) | 141 | /* |
| 124 | wake_up_interruptible(&evdev->wait); | 142 | * Pass incoming event to all connected clients. |
| 143 | */ | ||
| 144 | static void evdev_event(struct input_handle *handle, | ||
| 145 | unsigned int type, unsigned int code, int value) | ||
| 146 | { | ||
| 147 | struct input_value vals[] = { { type, code, value } }; | ||
| 148 | |||
| 149 | evdev_events(handle, vals, 1); | ||
| 125 | } | 150 | } |
| 126 | 151 | ||
| 127 | static int evdev_fasync(int fd, struct file *file, int on) | 152 | static int evdev_fasync(int fd, struct file *file, int on) |
| @@ -653,20 +678,22 @@ static int evdev_handle_mt_request(struct input_dev *dev, | |||
| 653 | unsigned int size, | 678 | unsigned int size, |
| 654 | int __user *ip) | 679 | int __user *ip) |
| 655 | { | 680 | { |
| 656 | const struct input_mt_slot *mt = dev->mt; | 681 | const struct input_mt *mt = dev->mt; |
| 657 | unsigned int code; | 682 | unsigned int code; |
| 658 | int max_slots; | 683 | int max_slots; |
| 659 | int i; | 684 | int i; |
| 660 | 685 | ||
| 661 | if (get_user(code, &ip[0])) | 686 | if (get_user(code, &ip[0])) |
| 662 | return -EFAULT; | 687 | return -EFAULT; |
| 663 | if (!input_is_mt_value(code)) | 688 | if (!mt || !input_is_mt_value(code)) |
| 664 | return -EINVAL; | 689 | return -EINVAL; |
| 665 | 690 | ||
| 666 | max_slots = (size - sizeof(__u32)) / sizeof(__s32); | 691 | max_slots = (size - sizeof(__u32)) / sizeof(__s32); |
| 667 | for (i = 0; i < dev->mtsize && i < max_slots; i++) | 692 | for (i = 0; i < mt->num_slots && i < max_slots; i++) { |
| 668 | if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i])) | 693 | int value = input_mt_get_value(&mt->slots[i], code); |
| 694 | if (put_user(value, &ip[1 + i])) | ||
| 669 | return -EFAULT; | 695 | return -EFAULT; |
| 696 | } | ||
| 670 | 697 | ||
| 671 | return 0; | 698 | return 0; |
| 672 | } | 699 | } |
| @@ -1048,6 +1075,7 @@ MODULE_DEVICE_TABLE(input, evdev_ids); | |||
| 1048 | 1075 | ||
| 1049 | static struct input_handler evdev_handler = { | 1076 | static struct input_handler evdev_handler = { |
| 1050 | .event = evdev_event, | 1077 | .event = evdev_event, |
| 1078 | .events = evdev_events, | ||
| 1051 | .connect = evdev_connect, | 1079 | .connect = evdev_connect, |
| 1052 | .disconnect = evdev_disconnect, | 1080 | .disconnect = evdev_disconnect, |
| 1053 | .fops = &evdev_fops, | 1081 | .fops = &evdev_fops, |
