diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/misc/uinput.c | 78 |
1 files changed, 40 insertions, 38 deletions
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 1719554fe19..6099365102d 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
@@ -56,10 +56,11 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i | |||
56 | } | 56 | } |
57 | 57 | ||
58 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ | 58 | /* Atomically allocate an ID for the given request. Returns 0 on success. */ |
59 | static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) | 59 | static bool uinput_request_alloc_id(struct uinput_device *udev, |
60 | struct uinput_request *request) | ||
60 | { | 61 | { |
61 | int id; | 62 | int id; |
62 | int err = -1; | 63 | bool reserved = false; |
63 | 64 | ||
64 | spin_lock(&udev->requests_lock); | 65 | spin_lock(&udev->requests_lock); |
65 | 66 | ||
@@ -67,13 +68,13 @@ static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_req | |||
67 | if (!udev->requests[id]) { | 68 | if (!udev->requests[id]) { |
68 | request->id = id; | 69 | request->id = id; |
69 | udev->requests[id] = request; | 70 | udev->requests[id] = request; |
70 | err = 0; | 71 | reserved = true; |
71 | break; | 72 | break; |
72 | } | 73 | } |
73 | } | 74 | } |
74 | 75 | ||
75 | spin_unlock(&udev->requests_lock); | 76 | spin_unlock(&udev->requests_lock); |
76 | return err; | 77 | return reserved; |
77 | } | 78 | } |
78 | 79 | ||
79 | static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) | 80 | static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) |
@@ -85,11 +86,12 @@ static struct uinput_request *uinput_request_find(struct uinput_device *udev, in | |||
85 | return udev->requests[id]; | 86 | return udev->requests[id]; |
86 | } | 87 | } |
87 | 88 | ||
88 | static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request) | 89 | static int uinput_request_reserve_slot(struct uinput_device *udev, |
90 | struct uinput_request *request) | ||
89 | { | 91 | { |
90 | /* Allocate slot. If none are available right away, wait. */ | 92 | /* Allocate slot. If none are available right away, wait. */ |
91 | return wait_event_interruptible(udev->requests_waitq, | 93 | return wait_event_interruptible(udev->requests_waitq, |
92 | !uinput_request_alloc_id(udev, request)); | 94 | uinput_request_alloc_id(udev, request)); |
93 | } | 95 | } |
94 | 96 | ||
95 | static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) | 97 | static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request) |
@@ -101,14 +103,11 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques | |||
101 | complete(&request->done); | 103 | complete(&request->done); |
102 | } | 104 | } |
103 | 105 | ||
104 | static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) | 106 | static int uinput_request_send(struct uinput_device *udev, |
107 | struct uinput_request *request) | ||
105 | { | 108 | { |
106 | int retval; | 109 | int retval; |
107 | 110 | ||
108 | retval = uinput_request_reserve_slot(udev, request); | ||
109 | if (retval) | ||
110 | return retval; | ||
111 | |||
112 | retval = mutex_lock_interruptible(&udev->mutex); | 111 | retval = mutex_lock_interruptible(&udev->mutex); |
113 | if (retval) | 112 | if (retval) |
114 | return retval; | 113 | return retval; |
@@ -118,7 +117,12 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque | |||
118 | goto out; | 117 | goto out; |
119 | } | 118 | } |
120 | 119 | ||
121 | /* Tell our userspace app about this new request by queueing an input event */ | 120 | init_completion(&request->done); |
121 | |||
122 | /* | ||
123 | * Tell our userspace application about this new request | ||
124 | * by queueing an input event. | ||
125 | */ | ||
122 | uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); | 126 | uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); |
123 | 127 | ||
124 | out: | 128 | out: |
@@ -126,6 +130,25 @@ static int uinput_request_submit(struct uinput_device *udev, struct uinput_reque | |||
126 | return retval; | 130 | return retval; |
127 | } | 131 | } |
128 | 132 | ||
133 | static int uinput_request_submit(struct uinput_device *udev, | ||
134 | struct uinput_request *request) | ||
135 | { | ||
136 | int error; | ||
137 | |||
138 | error = uinput_request_reserve_slot(udev, request); | ||
139 | if (error) | ||
140 | return error; | ||
141 | |||
142 | error = uinput_request_send(udev, request); | ||
143 | if (error) { | ||
144 | uinput_request_done(udev, request); | ||
145 | return error; | ||
146 | } | ||
147 | |||
148 | wait_for_completion(&request->done); | ||
149 | return request->retval; | ||
150 | } | ||
151 | |||
129 | /* | 152 | /* |
130 | * Fail all ouitstanding requests so handlers don't wait for the userspace | 153 | * Fail all ouitstanding requests so handlers don't wait for the userspace |
131 | * to finish processing them. | 154 | * to finish processing them. |
@@ -167,7 +190,6 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff | |||
167 | { | 190 | { |
168 | struct uinput_device *udev = input_get_drvdata(dev); | 191 | struct uinput_device *udev = input_get_drvdata(dev); |
169 | struct uinput_request request; | 192 | struct uinput_request request; |
170 | int retval; | ||
171 | 193 | ||
172 | /* | 194 | /* |
173 | * uinput driver does not currently support periodic effects with | 195 | * uinput driver does not currently support periodic effects with |
@@ -180,42 +202,25 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff | |||
180 | effect->u.periodic.waveform == FF_CUSTOM) | 202 | effect->u.periodic.waveform == FF_CUSTOM) |
181 | return -EINVAL; | 203 | return -EINVAL; |
182 | 204 | ||
183 | request.id = -1; | ||
184 | init_completion(&request.done); | ||
185 | request.code = UI_FF_UPLOAD; | 205 | request.code = UI_FF_UPLOAD; |
186 | request.u.upload.effect = effect; | 206 | request.u.upload.effect = effect; |
187 | request.u.upload.old = old; | 207 | request.u.upload.old = old; |
188 | 208 | ||
189 | retval = uinput_request_submit(udev, &request); | 209 | return uinput_request_submit(udev, &request); |
190 | if (!retval) { | ||
191 | wait_for_completion(&request.done); | ||
192 | retval = request.retval; | ||
193 | } | ||
194 | |||
195 | return retval; | ||
196 | } | 210 | } |
197 | 211 | ||
198 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) | 212 | static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) |
199 | { | 213 | { |
200 | struct uinput_device *udev = input_get_drvdata(dev); | 214 | struct uinput_device *udev = input_get_drvdata(dev); |
201 | struct uinput_request request; | 215 | struct uinput_request request; |
202 | int retval; | ||
203 | 216 | ||
204 | if (!test_bit(EV_FF, dev->evbit)) | 217 | if (!test_bit(EV_FF, dev->evbit)) |
205 | return -ENOSYS; | 218 | return -ENOSYS; |
206 | 219 | ||
207 | request.id = -1; | ||
208 | init_completion(&request.done); | ||
209 | request.code = UI_FF_ERASE; | 220 | request.code = UI_FF_ERASE; |
210 | request.u.effect_id = effect_id; | 221 | request.u.effect_id = effect_id; |
211 | 222 | ||
212 | retval = uinput_request_submit(udev, &request); | 223 | return uinput_request_submit(udev, &request); |
213 | if (!retval) { | ||
214 | wait_for_completion(&request.done); | ||
215 | retval = request.retval; | ||
216 | } | ||
217 | |||
218 | return retval; | ||
219 | } | 224 | } |
220 | 225 | ||
221 | static void uinput_destroy_device(struct uinput_device *udev) | 226 | static void uinput_destroy_device(struct uinput_device *udev) |
@@ -478,20 +483,17 @@ static ssize_t uinput_events_to_user(struct uinput_device *udev, | |||
478 | { | 483 | { |
479 | struct input_event event; | 484 | struct input_event event; |
480 | size_t read = 0; | 485 | size_t read = 0; |
481 | int error = 0; | ||
482 | 486 | ||
483 | while (read + input_event_size() <= count && | 487 | while (read + input_event_size() <= count && |
484 | uinput_fetch_next_event(udev, &event)) { | 488 | uinput_fetch_next_event(udev, &event)) { |
485 | 489 | ||
486 | if (input_event_to_user(buffer + read, &event)) { | 490 | if (input_event_to_user(buffer + read, &event)) |
487 | error = -EFAULT; | 491 | return -EFAULT; |
488 | break; | ||
489 | } | ||
490 | 492 | ||
491 | read += input_event_size(); | 493 | read += input_event_size(); |
492 | } | 494 | } |
493 | 495 | ||
494 | return read ?: error; | 496 | return read; |
495 | } | 497 | } |
496 | 498 | ||
497 | static ssize_t uinput_read(struct file *file, char __user *buffer, | 499 | static ssize_t uinput_read(struct file *file, char __user *buffer, |