aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor_core@ameritech.net>2005-12-11 12:40:37 -0500
committerDmitry Torokhov <dtor_core@ameritech.net>2005-12-11 12:40:37 -0500
commit3a51f7c40437077ac4a463307e9a4ae6b78755a8 (patch)
treea28ce7937a2ac917bed4c1993da4c21a1dffb4d4
parente4f5c82a92c2a546a16af1614114eec19120e40a (diff)
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>
-rw-r--r--drivers/input/evdev.c493
1 files changed, 213 insertions, 280 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 9f2352bd8348..0270d1ec9425 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -146,6 +146,7 @@ static int evdev_open(struct inode * inode, struct file * file)
146} 146}
147 147
148#ifdef CONFIG_COMPAT 148#ifdef CONFIG_COMPAT
149
149struct input_event_compat { 150struct input_event_compat {
150 struct compat_timeval time; 151 struct compat_timeval time;
151 __u16 type; 152 __u16 type;
@@ -165,98 +166,107 @@ struct input_event_compat {
165# define COMPAT_TEST test_thread_flag(TIF_32BIT) 166# define COMPAT_TEST test_thread_flag(TIF_32BIT)
166#endif 167#endif
167 168
168static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) 169static inline size_t evdev_event_size(void)
169{ 170{
170 struct evdev_list *list = file->private_data; 171 return COMPAT_TEST ?
171 struct input_event_compat event; 172 sizeof(struct input_event_compat) : sizeof(struct input_event);
172 int retval = 0; 173}
173 174
174 while (retval < count) { 175static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
175 if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat))) 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)))
181 return -EFAULT;
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)))
176 return -EFAULT; 191 return -EFAULT;
177 input_event(list->evdev->handle.dev, event.type, event.code, event.value);
178 retval += sizeof(struct input_event_compat);
179 } 192 }
180 193
181 return retval; 194 return 0;
182} 195}
183#endif
184 196
185static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) 197static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
186{ 198{
187 struct evdev_list *list = file->private_data; 199 if (COMPAT_TEST) {
188 struct input_event event; 200 struct input_event_compat compat_event;
189 int retval = 0;
190
191 if (!list->evdev->exist) return -ENODEV;
192 201
193#ifdef CONFIG_COMPAT 202 compat_event.time.tv_sec = event->time.tv_sec;
194 if (COMPAT_TEST) 203 compat_event.time.tv_usec = event->time.tv_usec;
195 return evdev_write_compat(file, buffer, count, ppos); 204 compat_event.type = event->type;
196#endif 205 compat_event.code = event->code;
206 compat_event.value = event->value;
197 207
198 while (retval < count) { 208 if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat)))
209 return -EFAULT;
199 210
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 return -EFAULT; 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 219#else
210static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos) 220
221static inline size_t evdev_event_size(void)
211{ 222{
212 struct evdev_list *list = file->private_data; 223 return sizeof(struct input_event);
213 int retval; 224}
214 225
215 if (count < sizeof(struct input_event_compat)) 226static int evdev_event_from_user(const char __user *buffer, struct input_event *event)
216 return -EINVAL; 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)) 231 return 0;
219 return -EAGAIN; 232}
220 233
221 retval = wait_event_interruptible(list->evdev->wait, 234static int evdev_event_to_user(char __user *buffer, const struct input_event *event)
222 list->head != list->tail || (!list->evdev->exist)); 235{
236 if (copy_to_user(buffer, event, sizeof(struct input_event)))
237 return -EFAULT;
223 238
224 if (retval) 239 return 0;
225 return retval; 240}
241
242#endif /* CONFIG_COMPAT */
243
244static 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;
226 249
227 if (!list->evdev->exist) 250 if (!list->evdev->exist)
228 return -ENODEV; 251 return -ENODEV;
229 252
230 while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) { 253 while (retval < count) {
231 struct input_event *event = (struct input_event *) list->buffer + list->tail; 254
232 struct input_event_compat event_compat; 255 if (evdev_event_from_user(buffer + retval, &event))
233 event_compat.time.tv_sec = event->time.tv_sec; 256 return -EFAULT;
234 event_compat.time.tv_usec = event->time.tv_usec; 257 input_event(list->evdev->handle.dev, event.type, event.code, event.value);
235 event_compat.type = event->type; 258 retval += evdev_event_size();
236 event_compat.code = event->code;
237 event_compat.value = event->value;
238
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);
243 } 259 }
244 260
245 return retval; 261 return retval;
246} 262}
247#endif
248 263
249static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos) 264static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
250{ 265{
251 struct evdev_list *list = file->private_data; 266 struct evdev_list *list = file->private_data;
252 int retval; 267 int retval;
253 268
254#ifdef CONFIG_COMPAT 269 if (count < evdev_event_size())
255 if (COMPAT_TEST)
256 return evdev_read_compat(file, buffer, count, ppos);
257#endif
258
259 if (count < sizeof(struct input_event))
260 return -EINVAL; 270 return -EINVAL;
261 271
262 if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK)) 272 if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
@@ -271,11 +281,15 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
271 if (!list->evdev->exist) 281 if (!list->evdev->exist)
272 return -ENODEV; 282 return -ENODEV;
273 283
274 while (list->head != list->tail && retval + sizeof(struct input_event) <= count) { 284 while (list->head != list->tail && retval + evdev_event_size() <= count) {
275 if (copy_to_user(buffer + retval, list->buffer + list->tail, 285
276 sizeof(struct input_event))) return -EFAULT; 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 list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1); 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 return retval; 295 return retval;
@@ -290,17 +304,95 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
290 (list->evdev->exist ? 0 : (POLLHUP | POLLERR)); 304 (list->evdev->exist ? 0 : (POLLHUP | POLLERR));
291} 305}
292 306
293static 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
313static int bits_to_user(unsigned long *bits, unsigned int maxbit,
314 unsigned int maxlen, void __user *p, int compat)
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
341static 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
357static 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
370static 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
384static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
385 void __user *p, int compat_mode)
294{ 386{
295 struct evdev_list *list = file->private_data; 387 struct evdev_list *list = file->private_data;
296 struct evdev *evdev = list->evdev; 388 struct evdev *evdev = list->evdev;
297 struct input_dev *dev = evdev->handle.dev; 389 struct input_dev *dev = evdev->handle.dev;
298 struct input_absinfo abs; 390 struct input_absinfo abs;
299 void __user *p = (void __user *)arg; 391 int __user *ip = (int __user *)p;
300 int __user *ip = (int __user *)arg;
301 int i, t, u, v; 392 int i, t, u, v;
302 393
303 if (!evdev->exist) return -ENODEV; 394 if (!evdev->exist)
395 return -ENODEV;
304 396
305 switch (cmd) { 397 switch (cmd) {
306 398
@@ -308,26 +400,39 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
308 return put_user(EV_VERSION, ip); 400 return put_user(EV_VERSION, ip);
309 401
310 case EVIOCGID: 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;
405
406 return 0;
312 407
313 case EVIOCGKEYCODE: 408 case EVIOCGKEYCODE:
314 if (get_user(t, ip)) return -EFAULT; 409 if (get_user(t, ip))
315 if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; 410 return -EFAULT;
316 if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) 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 return 0; 415 return 0;
318 416
319 case EVIOCSKEYCODE: 417 case EVIOCSKEYCODE:
320 if (get_user(t, ip)) return -EFAULT; 418 if (get_user(t, ip))
321 if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) return -EINVAL; 419 return -EFAULT;
322 if (get_user(v, ip + 1)) return -EFAULT; 420 if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
323 if (v < 0 || v > KEY_MAX) return -EINVAL; 421 return -EINVAL;
324 if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) 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 u = SET_INPUT_KEYCODE(dev, t, v); 429 u = SET_INPUT_KEYCODE(dev, t, v);
326 clear_bit(u, dev->keybit); 430 clear_bit(u, dev->keybit);
327 set_bit(v, dev->keybit); 431 set_bit(v, dev->keybit);
328 for (i = 0; i < dev->keycodemax; i++) 432 for (i = 0; i < dev->keycodemax; i++)
329 if (INPUT_KEYCODE(dev,i) == u) 433 if (INPUT_KEYCODE(dev, i) == u)
330 set_bit(u, dev->keybit); 434 set_bit(u, dev->keybit);
435
331 return 0; 436 return 0;
332 437
333 case EVIOCSFF: 438 case EVIOCSFF:
@@ -338,17 +443,17 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
338 if (copy_from_user(&effect, p, sizeof(effect))) 443 if (copy_from_user(&effect, p, sizeof(effect)))
339 return -EFAULT; 444 return -EFAULT;
340 err = dev->upload_effect(dev, &effect); 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 return -EFAULT; 447 return -EFAULT;
343 return err; 448 return err;
344 } 449 } else
345 else return -ENOSYS; 450 return -ENOSYS;
346 451
347 case EVIOCRMFF: 452 case EVIOCRMFF:
348 if (dev->erase_effect) { 453 if (!dev->erase_effect)
349 return dev->erase_effect(dev, (int)arg); 454 return -ENOSYS;
350 } 455
351 else return -ENOSYS; 456 return dev->erase_effect(dev, (int)(unsigned long) p);
352 457
353 case EVIOCGEFFECTS: 458 case EVIOCGEFFECTS:
354 if (put_user(dev->ff_effects_max, ip)) 459 if (put_user(dev->ff_effects_max, ip))
@@ -356,7 +461,7 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
356 return 0; 461 return 0;
357 462
358 case EVIOCGRAB: 463 case EVIOCGRAB:
359 if (arg) { 464 if (p) {
360 if (evdev->grab) 465 if (evdev->grab)
361 return -EBUSY; 466 return -EBUSY;
362 if (input_grab_device(&evdev->handle)) 467 if (input_grab_device(&evdev->handle))
@@ -395,62 +500,33 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
395 case EV_SW: bits = dev->swbit; len = SW_MAX; break; 500 case EV_SW: bits = dev->swbit; len = SW_MAX; break;
396 default: return -EINVAL; 501 default: return -EINVAL;
397 } 502 }
398 len = NBITS(len) * sizeof(long); 503 return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
399 if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
400 return copy_to_user(p, bits, len) ? -EFAULT : len;
401 } 504 }
402 505
403 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { 506 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
404 int len; 507 return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
405 len = NBITS(KEY_MAX) * sizeof(long); 508 p, compat_mode);
406 if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
407 return copy_to_user(p, dev->key, len) ? -EFAULT : len;
408 }
409 509
410 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { 510 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
411 int len; 511 return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd),
412 len = NBITS(LED_MAX) * sizeof(long); 512 p, compat_mode);
413 if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
414 return copy_to_user(p, dev->led, len) ? -EFAULT : len;
415 }
416 513
417 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { 514 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
418 int len; 515 return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd),
419 len = NBITS(SND_MAX) * sizeof(long); 516 p, compat_mode);
420 if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
421 return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
422 }
423 517
424 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) { 518 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0)))
425 int len; 519 return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd),
426 len = NBITS(SW_MAX) * sizeof(long); 520 p, compat_mode);
427 if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
428 return copy_to_user(p, dev->sw, len) ? -EFAULT : len;
429 }
430 521
431 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { 522 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0)))
432 int len; 523 return str_to_user(dev->name, _IOC_SIZE(cmd), p);
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 }
438 524
439 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { 525 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0)))
440 int len; 526 return str_to_user(dev->phys, _IOC_SIZE(cmd), p);
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 }
446 527
447 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { 528 if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0)))
448 int len; 529 return str_to_user(dev->uniq, _IOC_SIZE(cmd), p);
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 }
454 530
455 if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { 531 if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
456 532
@@ -492,158 +568,15 @@ static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
492 return -EINVAL; 568 return -EINVAL;
493} 569}
494 570
495#ifdef CONFIG_COMPAT 571static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
496 572{
497#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) 573 return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0);
498#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1) 574}
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) \
506do { \
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) \
519do { \
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 575
576#ifdef CONFIG_COMPAT
526static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) 577static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
527{ 578{
528 struct evdev_list *list = file->private_data; 579 return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1);
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;
647} 580}
648#endif 581#endif
649 582