diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/evdev.c | 29 | ||||
-rw-r--r-- | drivers/input/input.c | 87 |
2 files changed, 96 insertions, 20 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 6439f378f6cc..64b47de052bb 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -434,32 +434,21 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |||
434 | case EVIOCGKEYCODE: | 434 | case EVIOCGKEYCODE: |
435 | if (get_user(t, ip)) | 435 | if (get_user(t, ip)) |
436 | return -EFAULT; | 436 | return -EFAULT; |
437 | if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) | 437 | |
438 | return -EINVAL; | 438 | error = dev->getkeycode(dev, t, &v); |
439 | if (put_user(INPUT_KEYCODE(dev, t), ip + 1)) | 439 | if (error) |
440 | return error; | ||
441 | |||
442 | if (put_user(v, ip + 1)) | ||
440 | return -EFAULT; | 443 | return -EFAULT; |
444 | |||
441 | return 0; | 445 | return 0; |
442 | 446 | ||
443 | case EVIOCSKEYCODE: | 447 | case EVIOCSKEYCODE: |
444 | if (get_user(t, ip)) | 448 | if (get_user(t, ip) || get_user(v, ip + 1)) |
445 | return -EFAULT; | ||
446 | if (t < 0 || t >= dev->keycodemax || !dev->keycodesize) | ||
447 | return -EINVAL; | ||
448 | if (get_user(v, ip + 1)) | ||
449 | return -EFAULT; | 449 | return -EFAULT; |
450 | if (v < 0 || v > KEY_MAX) | ||
451 | return -EINVAL; | ||
452 | if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8))) | ||
453 | return -EINVAL; | ||
454 | |||
455 | u = SET_INPUT_KEYCODE(dev, t, v); | ||
456 | clear_bit(u, dev->keybit); | ||
457 | set_bit(v, dev->keybit); | ||
458 | for (i = 0; i < dev->keycodemax; i++) | ||
459 | if (INPUT_KEYCODE(dev, i) == u) | ||
460 | set_bit(u, dev->keybit); | ||
461 | 450 | ||
462 | return 0; | 451 | return dev->setkeycode(dev, t, v); |
463 | 452 | ||
464 | case EVIOCSFF: | 453 | case EVIOCSFF: |
465 | if (copy_from_user(&effect, p, sizeof(effect))) | 454 | if (copy_from_user(&effect, p, sizeof(effect))) |
diff --git a/drivers/input/input.c b/drivers/input/input.c index 4486402fbf5d..26393a606e6f 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -299,6 +299,87 @@ void input_close_device(struct input_handle *handle) | |||
299 | } | 299 | } |
300 | EXPORT_SYMBOL(input_close_device); | 300 | EXPORT_SYMBOL(input_close_device); |
301 | 301 | ||
302 | static int input_fetch_keycode(struct input_dev *dev, int scancode) | ||
303 | { | ||
304 | switch (dev->keycodesize) { | ||
305 | case 1: | ||
306 | return ((u8 *)dev->keycode)[scancode]; | ||
307 | |||
308 | case 2: | ||
309 | return ((u16 *)dev->keycode)[scancode]; | ||
310 | |||
311 | default: | ||
312 | return ((u32 *)dev->keycode)[scancode]; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | static int input_default_getkeycode(struct input_dev *dev, | ||
317 | int scancode, int *keycode) | ||
318 | { | ||
319 | if (!dev->keycodesize) | ||
320 | return -EINVAL; | ||
321 | |||
322 | if (scancode < 0 || scancode >= dev->keycodemax) | ||
323 | return -EINVAL; | ||
324 | |||
325 | *keycode = input_fetch_keycode(dev, scancode); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int input_default_setkeycode(struct input_dev *dev, | ||
331 | int scancode, int keycode) | ||
332 | { | ||
333 | int old_keycode; | ||
334 | int i; | ||
335 | |||
336 | if (scancode < 0 || scancode >= dev->keycodemax) | ||
337 | return -EINVAL; | ||
338 | |||
339 | if (keycode < 0 || keycode > KEY_MAX) | ||
340 | return -EINVAL; | ||
341 | |||
342 | if (!dev->keycodesize) | ||
343 | return -EINVAL; | ||
344 | |||
345 | if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8))) | ||
346 | return -EINVAL; | ||
347 | |||
348 | switch (dev->keycodesize) { | ||
349 | case 1: { | ||
350 | u8 *k = (u8 *)dev->keycode; | ||
351 | old_keycode = k[scancode]; | ||
352 | k[scancode] = keycode; | ||
353 | break; | ||
354 | } | ||
355 | case 2: { | ||
356 | u16 *k = (u16 *)dev->keycode; | ||
357 | old_keycode = k[scancode]; | ||
358 | k[scancode] = keycode; | ||
359 | break; | ||
360 | } | ||
361 | default: { | ||
362 | u32 *k = (u32 *)dev->keycode; | ||
363 | old_keycode = k[scancode]; | ||
364 | k[scancode] = keycode; | ||
365 | break; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | clear_bit(old_keycode, dev->keybit); | ||
370 | set_bit(keycode, dev->keybit); | ||
371 | |||
372 | for (i = 0; i < dev->keycodemax; i++) { | ||
373 | if (input_fetch_keycode(dev, i) == old_keycode) { | ||
374 | set_bit(old_keycode, dev->keybit); | ||
375 | break; /* Setting the bit twice is useless, so break */ | ||
376 | } | ||
377 | } | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | |||
302 | static void input_link_handle(struct input_handle *handle) | 383 | static void input_link_handle(struct input_handle *handle) |
303 | { | 384 | { |
304 | list_add_tail(&handle->d_node, &handle->dev->h_list); | 385 | list_add_tail(&handle->d_node, &handle->dev->h_list); |
@@ -978,6 +1059,12 @@ int input_register_device(struct input_dev *dev) | |||
978 | dev->rep[REP_PERIOD] = 33; | 1059 | dev->rep[REP_PERIOD] = 33; |
979 | } | 1060 | } |
980 | 1061 | ||
1062 | if (!dev->getkeycode) | ||
1063 | dev->getkeycode = input_default_getkeycode; | ||
1064 | |||
1065 | if (!dev->setkeycode) | ||
1066 | dev->setkeycode = input_default_setkeycode; | ||
1067 | |||
981 | list_add_tail(&dev->node, &input_dev_list); | 1068 | list_add_tail(&dev->node, &input_dev_list); |
982 | 1069 | ||
983 | snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), | 1070 | snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id), |