Commit 3a51f7c40437077ac4a463307e9a4ae6b78755a8
1 parent
e4f5c82a92
Input: evdev - consolidate compat and regular code
Compat and normal code mirror each other and are hard to maintain. When EV_SW was added compat_ioctl case was missed. Here is my attempt at consolidating the code. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 1 changed file with 213 additions and 280 deletions Side-by-side Diff
drivers/input/evdev.c
... | ... | @@ -146,6 +146,7 @@ |
146 | 146 | } |
147 | 147 | |
148 | 148 | #ifdef CONFIG_COMPAT |
149 | + | |
149 | 150 | struct input_event_compat { |
150 | 151 | struct compat_timeval time; |
151 | 152 | __u16 type; |
152 | 153 | |
153 | 154 | |
154 | 155 | |
155 | 156 | |
156 | 157 | |
157 | 158 | |
158 | 159 | |
159 | 160 | |
160 | 161 | |
161 | 162 | |
162 | 163 | |
163 | 164 | |
164 | 165 | |
165 | 166 | |
166 | 167 | |
167 | 168 | |
168 | 169 | |
169 | 170 | |
170 | 171 | |
171 | 172 | |
172 | 173 | |
173 | 174 | |
174 | 175 | |
... | ... | @@ -165,98 +166,107 @@ |
165 | 166 | # define COMPAT_TEST test_thread_flag(TIF_32BIT) |
166 | 167 | #endif |
167 | 168 | |
168 | -static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | |
169 | +static inline size_t evdev_event_size(void) | |
169 | 170 | { |
170 | - struct evdev_list *list = file->private_data; | |
171 | - struct input_event_compat event; | |
172 | - int retval = 0; | |
171 | + return COMPAT_TEST ? | |
172 | + sizeof(struct input_event_compat) : sizeof(struct input_event); | |
173 | +} | |
173 | 174 | |
174 | - while (retval < count) { | |
175 | - if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat))) | |
175 | +static int evdev_event_from_user(const char __user *buffer, struct input_event *event) | |
176 | +{ | |
177 | + if (COMPAT_TEST) { | |
178 | + struct input_event_compat compat_event; | |
179 | + | |
180 | + if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat))) | |
176 | 181 | return -EFAULT; |
177 | - input_event(list->evdev->handle.dev, event.type, event.code, event.value); | |
178 | - retval += sizeof(struct input_event_compat); | |
182 | + | |
183 | + event->time.tv_sec = compat_event.time.tv_sec; | |
184 | + event->time.tv_usec = compat_event.time.tv_usec; | |
185 | + event->type = compat_event.type; | |
186 | + event->code = compat_event.code; | |
187 | + event->value = compat_event.value; | |
188 | + | |
189 | + } else { | |
190 | + if (copy_from_user(event, buffer, sizeof(struct input_event))) | |
191 | + return -EFAULT; | |
179 | 192 | } |
180 | 193 | |
181 | - return retval; | |
194 | + return 0; | |
182 | 195 | } |
183 | -#endif | |
184 | 196 | |
185 | -static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | |
197 | +static int evdev_event_to_user(char __user *buffer, const struct input_event *event) | |
186 | 198 | { |
187 | - struct evdev_list *list = file->private_data; | |
188 | - struct input_event event; | |
189 | - int retval = 0; | |
199 | + if (COMPAT_TEST) { | |
200 | + struct input_event_compat compat_event; | |
190 | 201 | |
191 | - if (!list->evdev->exist) return -ENODEV; | |
202 | + compat_event.time.tv_sec = event->time.tv_sec; | |
203 | + compat_event.time.tv_usec = event->time.tv_usec; | |
204 | + compat_event.type = event->type; | |
205 | + compat_event.code = event->code; | |
206 | + compat_event.value = event->value; | |
192 | 207 | |
193 | -#ifdef CONFIG_COMPAT | |
194 | - if (COMPAT_TEST) | |
195 | - return evdev_write_compat(file, buffer, count, ppos); | |
196 | -#endif | |
208 | + if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat))) | |
209 | + return -EFAULT; | |
197 | 210 | |
198 | - while (retval < count) { | |
199 | - | |
200 | - if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) | |
211 | + } else { | |
212 | + if (copy_to_user(buffer, event, sizeof(struct input_event))) | |
201 | 213 | return -EFAULT; |
202 | - input_event(list->evdev->handle.dev, event.type, event.code, event.value); | |
203 | - retval += sizeof(struct input_event); | |
204 | 214 | } |
205 | 215 | |
206 | - return retval; | |
216 | + return 0; | |
207 | 217 | } |
208 | 218 | |
209 | -#ifdef CONFIG_COMPAT | |
210 | -static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos) | |
219 | +#else | |
220 | + | |
221 | +static inline size_t evdev_event_size(void) | |
211 | 222 | { |
212 | - struct evdev_list *list = file->private_data; | |
213 | - int retval; | |
223 | + return sizeof(struct input_event); | |
224 | +} | |
214 | 225 | |
215 | - if (count < sizeof(struct input_event_compat)) | |
216 | - return -EINVAL; | |
226 | +static int evdev_event_from_user(const char __user *buffer, struct input_event *event) | |
227 | +{ | |
228 | + if (copy_from_user(event, buffer, sizeof(struct input_event))) | |
229 | + return -EFAULT; | |
217 | 230 | |
218 | - if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) | |
219 | - return -EAGAIN; | |
231 | + return 0; | |
232 | +} | |
220 | 233 | |
221 | - retval = wait_event_interruptible(list->evdev->wait, | |
222 | - list->head != list->tail || (!list->evdev->exist)); | |
234 | +static int evdev_event_to_user(char __user *buffer, const struct input_event *event) | |
235 | +{ | |
236 | + if (copy_to_user(buffer, event, sizeof(struct input_event))) | |
237 | + return -EFAULT; | |
223 | 238 | |
224 | - if (retval) | |
225 | - return retval; | |
239 | + return 0; | |
240 | +} | |
226 | 241 | |
242 | +#endif /* CONFIG_COMPAT */ | |
243 | + | |
244 | +static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | |
245 | +{ | |
246 | + struct evdev_list *list = file->private_data; | |
247 | + struct input_event event; | |
248 | + int retval = 0; | |
249 | + | |
227 | 250 | if (!list->evdev->exist) |
228 | 251 | return -ENODEV; |
229 | 252 | |
230 | - while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) { | |
231 | - struct input_event *event = (struct input_event *) list->buffer + list->tail; | |
232 | - struct input_event_compat event_compat; | |
233 | - event_compat.time.tv_sec = event->time.tv_sec; | |
234 | - event_compat.time.tv_usec = event->time.tv_usec; | |
235 | - event_compat.type = event->type; | |
236 | - event_compat.code = event->code; | |
237 | - event_compat.value = event->value; | |
253 | + while (retval < count) { | |
238 | 254 | |
239 | - if (copy_to_user(buffer + retval, &event_compat, | |
240 | - sizeof(struct input_event_compat))) return -EFAULT; | |
241 | - list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); | |
242 | - retval += sizeof(struct input_event_compat); | |
255 | + if (evdev_event_from_user(buffer + retval, &event)) | |
256 | + return -EFAULT; | |
257 | + input_event(list->evdev->handle.dev, event.type, event.code, event.value); | |
258 | + retval += evdev_event_size(); | |
243 | 259 | } |
244 | 260 | |
245 | 261 | return retval; |
246 | 262 | } |
247 | -#endif | |
248 | 263 | |
249 | 264 | static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) |
250 | 265 | { |
251 | 266 | struct evdev_list *list = file->private_data; |
252 | 267 | int retval; |
253 | 268 | |
254 | -#ifdef CONFIG_COMPAT | |
255 | - if (COMPAT_TEST) | |
256 | - return evdev_read_compat(file, buffer, count, ppos); | |
257 | -#endif | |
258 | - | |
259 | - if (count < sizeof(struct input_event)) | |
269 | + if (count < evdev_event_size()) | |
260 | 270 | return -EINVAL; |
261 | 271 | |
262 | 272 | if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) |
263 | 273 | |
... | ... | @@ -271,11 +281,15 @@ |
271 | 281 | if (!list->evdev->exist) |
272 | 282 | return -ENODEV; |
273 | 283 | |
274 | - while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { | |
275 | - if (copy_to_user(buffer + retval, list->buffer + list->tail, | |
276 | - sizeof(struct input_event))) return -EFAULT; | |
284 | + while (list->head != list->tail && retval + evdev_event_size() <= count) { | |
285 | + | |
286 | + struct input_event *event = (struct input_event *) list->buffer + list->tail; | |
287 | + | |
288 | + if (evdev_event_to_user(buffer + retval, event)) | |
289 | + return -EFAULT; | |
290 | + | |
277 | 291 | list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); |
278 | - retval += sizeof(struct input_event); | |
292 | + retval += evdev_event_size(); | |
279 | 293 | } |
280 | 294 | |
281 | 295 | return retval; |
282 | 296 | |
283 | 297 | |
284 | 298 | |
... | ... | @@ -290,17 +304,95 @@ |
290 | 304 | (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); |
291 | 305 | } |
292 | 306 | |
293 | -static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
307 | +#ifdef CONFIG_COMPAT | |
308 | + | |
309 | +#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) | |
310 | +#define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) | |
311 | + | |
312 | +#ifdef __BIG_ENDIAN | |
313 | +static int bits_to_user(unsigned long *bits, unsigned int maxbit, | |
314 | + unsigned int maxlen, void __user *p, int compat) | |
294 | 315 | { |
316 | + int len, i; | |
317 | + | |
318 | + if (compat) { | |
319 | + len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t); | |
320 | + if (len < maxlen) | |
321 | + len = maxlen; | |
322 | + | |
323 | + for (i = 0; i < len / sizeof(compat_long_t); i++) | |
324 | + if (copy_to_user((compat_long_t __user *) p + i, | |
325 | + (compat_long_t *) bits + | |
326 | + i + 1 - ((i % 2) << 1), | |
327 | + sizeof(compat_long_t))) | |
328 | + return -EFAULT; | |
329 | + } else { | |
330 | + len = NBITS(maxbit) * sizeof(long); | |
331 | + if (len > maxlen) | |
332 | + len = maxlen; | |
333 | + | |
334 | + if (copy_to_user(p, bits, len)) | |
335 | + return -EFAULT; | |
336 | + } | |
337 | + | |
338 | + return len; | |
339 | +} | |
340 | +#else | |
341 | +static int bits_to_user(unsigned long *bits, unsigned int maxbit, | |
342 | + unsigned int maxlen, void __user *p, int compat) | |
343 | +{ | |
344 | + int len = compat ? | |
345 | + NBITS_COMPAT(maxbit) * sizeof(compat_long_t) : | |
346 | + NBITS(maxbit) * sizeof(long); | |
347 | + | |
348 | + if (len > maxlen) | |
349 | + len = maxlen; | |
350 | + | |
351 | + return copy_to_user(p, bits, len) ? -EFAULT : len; | |
352 | +} | |
353 | +#endif /* __BIG_ENDIAN */ | |
354 | + | |
355 | +#else | |
356 | + | |
357 | +static int bits_to_user(unsigned long *bits, unsigned int maxbit, | |
358 | + unsigned int maxlen, void __user *p, int compat) | |
359 | +{ | |
360 | + int len = NBITS(maxbit) * sizeof(long); | |
361 | + | |
362 | + if (len > maxlen) | |
363 | + len = maxlen; | |
364 | + | |
365 | + return copy_to_user(p, bits, len) ? -EFAULT : len; | |
366 | +} | |
367 | + | |
368 | +#endif /* CONFIG_COMPAT */ | |
369 | + | |
370 | +static int str_to_user(const char *str, unsigned int maxlen, void __user *p) | |
371 | +{ | |
372 | + int len; | |
373 | + | |
374 | + if (!str) | |
375 | + return -ENOENT; | |
376 | + | |
377 | + len = strlen(str) + 1; | |
378 | + if (len > maxlen) | |
379 | + len = maxlen; | |
380 | + | |
381 | + return copy_to_user(p, str, len) ? -EFAULT : len; | |
382 | +} | |
383 | + | |
384 | +static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |
385 | + void __user *p, int compat_mode) | |
386 | +{ | |
295 | 387 | struct evdev_list *list = file->private_data; |
296 | 388 | struct evdev *evdev = list->evdev; |
297 | 389 | struct input_dev *dev = evdev->handle.dev; |
298 | 390 | struct input_absinfo abs; |
299 | - void __user *p = (void __user *)arg; | |
300 | - int __user *ip = (int __user *)arg; | |
391 | + int __user *ip = (int __user *)p; | |
301 | 392 | int i, t, u, v; |
302 | 393 | |
303 | - if (!evdev->exist) return -ENODEV; | |
394 | + if (!evdev->exist) | |
395 | + return -ENODEV; | |
304 | 396 | |
305 | 397 | switch (cmd) { |
306 | 398 | |
307 | 399 | |
308 | 400 | |
309 | 401 | |
310 | 402 | |
311 | 403 | |
... | ... | @@ -308,26 +400,39 @@ |
308 | 400 | return put_user(EV_VERSION, ip); |
309 | 401 | |
310 | 402 | case EVIOCGID: |
311 | - return copy_to_user(p, &dev->id, sizeof(struct input_id)) ? -EFAULT : 0; | |
403 | + if (copy_to_user(p, &dev->id, sizeof(struct input_id))) | |
404 | + return -EFAULT; | |
312 | 405 | |
406 | + return 0; | |
407 | + | |
313 | 408 | case EVIOCGKEYCODE: |
314 | - if (get_user(t, ip)) return -EFAULT; | |
315 | - if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; | |
316 | - if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) return -EFAULT; | |
409 | + if (get_user(t, ip)) | |
410 | + return -EFAULT; | |
411 | + if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) | |
412 | + return -EINVAL; | |
413 | + if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) | |
414 | + return -EFAULT; | |
317 | 415 | return 0; |
318 | 416 | |
319 | 417 | case EVIOCSKEYCODE: |
320 | - if (get_user(t, ip)) return -EFAULT; | |
321 | - if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; | |
322 | - if (get_user(v, ip + 1)) return -EFAULT; | |
323 | - if (v < 0 || v > KEY_MAX) return -EINVAL; | |
324 | - if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) return -EINVAL; | |
418 | + if (get_user(t, ip)) | |
419 | + return -EFAULT; | |
420 | + if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) | |
421 | + return -EINVAL; | |
422 | + if (get_user(v, ip + 1)) | |
423 | + return -EFAULT; | |
424 | + if (v < 0 || v > KEY_MAX) | |
425 | + return -EINVAL; | |
426 | + if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) | |
427 | + return -EINVAL; | |
428 | + | |
325 | 429 | u = SET_INPUT_KEYCODE(dev, t, v); |
326 | 430 | clear_bit(u, dev->keybit); |
327 | 431 | set_bit(v, dev->keybit); |
328 | 432 | for (i = 0; i < dev->keycodemax; i++) |
329 | - if (INPUT_KEYCODE(dev,i) == u) | |
433 | + if (INPUT_KEYCODE(dev, i) == u) | |
330 | 434 | set_bit(u, dev->keybit); |
435 | + | |
331 | 436 | return 0; |
332 | 437 | |
333 | 438 | case EVIOCSFF: |
334 | 439 | |
335 | 440 | |
336 | 441 | |
337 | 442 | |
... | ... | @@ -338,25 +443,25 @@ |
338 | 443 | if (copy_from_user(&effect, p, sizeof(effect))) |
339 | 444 | return -EFAULT; |
340 | 445 | err = dev->upload_effect(dev, &effect); |
341 | - if (put_user(effect.id, &(((struct ff_effect __user *)arg)->id))) | |
446 | + if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) | |
342 | 447 | return -EFAULT; |
343 | 448 | return err; |
344 | - } | |
345 | - else return -ENOSYS; | |
449 | + } else | |
450 | + return -ENOSYS; | |
346 | 451 | |
347 | 452 | case EVIOCRMFF: |
348 | - if (dev->erase_effect) { | |
349 | - return dev->erase_effect(dev, (int)arg); | |
350 | - } | |
351 | - else return -ENOSYS; | |
453 | + if (!dev->erase_effect) | |
454 | + return -ENOSYS; | |
352 | 455 | |
456 | + return dev->erase_effect(dev, (int)(unsigned long) p); | |
457 | + | |
353 | 458 | case EVIOCGEFFECTS: |
354 | 459 | if (put_user(dev->ff_effects_max, ip)) |
355 | 460 | return -EFAULT; |
356 | 461 | return 0; |
357 | 462 | |
358 | 463 | case EVIOCGRAB: |
359 | - if (arg) { | |
464 | + if (p) { | |
360 | 465 | if (evdev->grab) |
361 | 466 | return -EBUSY; |
362 | 467 | if (input_grab_device(&evdev->handle)) |
363 | 468 | |
364 | 469 | |
365 | 470 | |
366 | 471 | |
367 | 472 | |
368 | 473 | |
369 | 474 | |
... | ... | @@ -395,62 +500,33 @@ |
395 | 500 | case EV_SW: bits = dev->swbit; len = SW_MAX; break; |
396 | 501 | default: return -EINVAL; |
397 | 502 | } |
398 | - len = NBITS(len) * sizeof(long); | |
399 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
400 | - return copy_to_user(p, bits, len) ? -EFAULT : len; | |
503 | + return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); | |
401 | 504 | } |
402 | 505 | |
403 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { | |
404 | - int len; | |
405 | - len = NBITS(KEY_MAX) * sizeof(long); | |
406 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
407 | - return copy_to_user(p, dev->key, len) ? -EFAULT : len; | |
408 | - } | |
506 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) | |
507 | + return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), | |
508 | + p, compat_mode); | |
409 | 509 | |
410 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { | |
411 | - int len; | |
412 | - len = NBITS(LED_MAX) * sizeof(long); | |
413 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
414 | - return copy_to_user(p, dev->led, len) ? -EFAULT : len; | |
415 | - } | |
510 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) | |
511 | + return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), | |
512 | + p, compat_mode); | |
416 | 513 | |
417 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { | |
418 | - int len; | |
419 | - len = NBITS(SND_MAX) * sizeof(long); | |
420 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
421 | - return copy_to_user(p, dev->snd, len) ? -EFAULT : len; | |
422 | - } | |
514 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | |
515 | + return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), | |
516 | + p, compat_mode); | |
423 | 517 | |
424 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) { | |
425 | - int len; | |
426 | - len = NBITS(SW_MAX) * sizeof(long); | |
427 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
428 | - return copy_to_user(p, dev->sw, len) ? -EFAULT : len; | |
429 | - } | |
518 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) | |
519 | + return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), | |
520 | + p, compat_mode); | |
430 | 521 | |
431 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { | |
432 | - int len; | |
433 | - if (!dev->name) return -ENOENT; | |
434 | - len = strlen(dev->name) + 1; | |
435 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
436 | - return copy_to_user(p, dev->name, len) ? -EFAULT : len; | |
437 | - } | |
522 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) | |
523 | + return str_to_user(dev->name, _IOC_SIZE(cmd), p); | |
438 | 524 | |
439 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { | |
440 | - int len; | |
441 | - if (!dev->phys) return -ENOENT; | |
442 | - len = strlen(dev->phys) + 1; | |
443 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
444 | - return copy_to_user(p, dev->phys, len) ? -EFAULT : len; | |
445 | - } | |
525 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) | |
526 | + return str_to_user(dev->phys, _IOC_SIZE(cmd), p); | |
446 | 527 | |
447 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { | |
448 | - int len; | |
449 | - if (!dev->uniq) return -ENOENT; | |
450 | - len = strlen(dev->uniq) + 1; | |
451 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
452 | - return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; | |
453 | - } | |
528 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) | |
529 | + return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); | |
454 | 530 | |
455 | 531 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { |
456 | 532 | |
457 | 533 | |
458 | 534 | |
... | ... | @@ -492,158 +568,15 @@ |
492 | 568 | return -EINVAL; |
493 | 569 | } |
494 | 570 | |
495 | -#ifdef CONFIG_COMPAT | |
571 | +static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |
572 | +{ | |
573 | + return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); | |
574 | +} | |
496 | 575 | |
497 | -#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) | |
498 | -#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1) | |
499 | -#define OFF_COMPAT(x) ((x)%BITS_PER_LONG_COMPAT) | |
500 | -#define BIT_COMPAT(x) (1UL<<OFF_COMPAT(x)) | |
501 | -#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT) | |
502 | -#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1) | |
503 | - | |
504 | -#ifdef __BIG_ENDIAN | |
505 | -#define bit_to_user(bit, max) \ | |
506 | -do { \ | |
507 | - int i; \ | |
508 | - int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ | |
509 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ | |
510 | - for (i = 0; i < len / sizeof(compat_long_t); i++) \ | |
511 | - if (copy_to_user((compat_long_t __user *) p + i, \ | |
512 | - (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \ | |
513 | - sizeof(compat_long_t))) \ | |
514 | - return -EFAULT; \ | |
515 | - return len; \ | |
516 | -} while (0) | |
517 | -#else | |
518 | -#define bit_to_user(bit, max) \ | |
519 | -do { \ | |
520 | - int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \ | |
521 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \ | |
522 | - return copy_to_user(p, (bit), len) ? -EFAULT : len; \ | |
523 | -} while (0) | |
524 | -#endif | |
525 | - | |
576 | +#ifdef CONFIG_COMPAT | |
526 | 577 | static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) |
527 | 578 | { |
528 | - struct evdev_list *list = file->private_data; | |
529 | - struct evdev *evdev = list->evdev; | |
530 | - struct input_dev *dev = evdev->handle.dev; | |
531 | - struct input_absinfo abs; | |
532 | - void __user *p = compat_ptr(arg); | |
533 | - | |
534 | - if (!evdev->exist) return -ENODEV; | |
535 | - | |
536 | - switch (cmd) { | |
537 | - | |
538 | - case EVIOCGVERSION: | |
539 | - case EVIOCGID: | |
540 | - case EVIOCGKEYCODE: | |
541 | - case EVIOCSKEYCODE: | |
542 | - case EVIOCSFF: | |
543 | - case EVIOCRMFF: | |
544 | - case EVIOCGEFFECTS: | |
545 | - case EVIOCGRAB: | |
546 | - return evdev_ioctl(file, cmd, (unsigned long) p); | |
547 | - | |
548 | - default: | |
549 | - | |
550 | - if (_IOC_TYPE(cmd) != 'E') | |
551 | - return -EINVAL; | |
552 | - | |
553 | - if (_IOC_DIR(cmd) == _IOC_READ) { | |
554 | - | |
555 | - if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { | |
556 | - long *bits; | |
557 | - int max; | |
558 | - | |
559 | - switch (_IOC_NR(cmd) & EV_MAX) { | |
560 | - case 0: bits = dev->evbit; max = EV_MAX; break; | |
561 | - case EV_KEY: bits = dev->keybit; max = KEY_MAX; break; | |
562 | - case EV_REL: bits = dev->relbit; max = REL_MAX; break; | |
563 | - case EV_ABS: bits = dev->absbit; max = ABS_MAX; break; | |
564 | - case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break; | |
565 | - case EV_LED: bits = dev->ledbit; max = LED_MAX; break; | |
566 | - case EV_SND: bits = dev->sndbit; max = SND_MAX; break; | |
567 | - case EV_FF: bits = dev->ffbit; max = FF_MAX; break; | |
568 | - case EV_SW: bits = dev->swbit; max = SW_MAX; break; | |
569 | - default: return -EINVAL; | |
570 | - } | |
571 | - bit_to_user(bits, max); | |
572 | - } | |
573 | - | |
574 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) | |
575 | - bit_to_user(dev->key, KEY_MAX); | |
576 | - | |
577 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) | |
578 | - bit_to_user(dev->led, LED_MAX); | |
579 | - | |
580 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | |
581 | - bit_to_user(dev->snd, SND_MAX); | |
582 | - | |
583 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) | |
584 | - bit_to_user(dev->sw, SW_MAX); | |
585 | - | |
586 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { | |
587 | - int len; | |
588 | - if (!dev->name) return -ENOENT; | |
589 | - len = strlen(dev->name) + 1; | |
590 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
591 | - return copy_to_user(p, dev->name, len) ? -EFAULT : len; | |
592 | - } | |
593 | - | |
594 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { | |
595 | - int len; | |
596 | - if (!dev->phys) return -ENOENT; | |
597 | - len = strlen(dev->phys) + 1; | |
598 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
599 | - return copy_to_user(p, dev->phys, len) ? -EFAULT : len; | |
600 | - } | |
601 | - | |
602 | - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { | |
603 | - int len; | |
604 | - if (!dev->uniq) return -ENOENT; | |
605 | - len = strlen(dev->uniq) + 1; | |
606 | - if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
607 | - return copy_to_user(p, dev->uniq, len) ? -EFAULT : len; | |
608 | - } | |
609 | - | |
610 | - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | |
611 | - | |
612 | - int t = _IOC_NR(cmd) & ABS_MAX; | |
613 | - | |
614 | - abs.value = dev->abs[t]; | |
615 | - abs.minimum = dev->absmin[t]; | |
616 | - abs.maximum = dev->absmax[t]; | |
617 | - abs.fuzz = dev->absfuzz[t]; | |
618 | - abs.flat = dev->absflat[t]; | |
619 | - | |
620 | - if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) | |
621 | - return -EFAULT; | |
622 | - | |
623 | - return 0; | |
624 | - } | |
625 | - } | |
626 | - | |
627 | - if (_IOC_DIR(cmd) == _IOC_WRITE) { | |
628 | - | |
629 | - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { | |
630 | - | |
631 | - int t = _IOC_NR(cmd) & ABS_MAX; | |
632 | - | |
633 | - if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) | |
634 | - return -EFAULT; | |
635 | - | |
636 | - dev->abs[t] = abs.value; | |
637 | - dev->absmin[t] = abs.minimum; | |
638 | - dev->absmax[t] = abs.maximum; | |
639 | - dev->absfuzz[t] = abs.fuzz; | |
640 | - dev->absflat[t] = abs.flat; | |
641 | - | |
642 | - return 0; | |
643 | - } | |
644 | - } | |
645 | - } | |
646 | - return -EINVAL; | |
579 | + return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); | |
647 | 580 | } |
648 | 581 | #endif |
649 | 582 |