diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/input.c | 249 |
1 files changed, 104 insertions, 145 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index a8f65fa7e17a..3b1685ff9d10 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -316,125 +316,7 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st | |||
316 | return NULL; | 316 | return NULL; |
317 | } | 317 | } |
318 | 318 | ||
319 | 319 | static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, int max) | |
320 | /* | ||
321 | * Input hotplugging interface - loading event handlers based on | ||
322 | * device bitfields. | ||
323 | */ | ||
324 | |||
325 | #ifdef CONFIG_HOTPLUG | ||
326 | |||
327 | /* | ||
328 | * Input hotplugging invokes what /proc/sys/kernel/hotplug says | ||
329 | * (normally /sbin/hotplug) when input devices get added or removed. | ||
330 | * | ||
331 | * This invokes a user mode policy agent, typically helping to load driver | ||
332 | * or other modules, configure the device, and more. Drivers can provide | ||
333 | * a MODULE_DEVICE_TABLE to help with module loading subtasks. | ||
334 | * | ||
335 | */ | ||
336 | |||
337 | #define SPRINTF_BIT_A(bit, name, max) \ | ||
338 | do { \ | ||
339 | envp[i++] = scratch; \ | ||
340 | scratch += sprintf(scratch, name); \ | ||
341 | for (j = NBITS(max) - 1; j >= 0; j--) \ | ||
342 | if (dev->bit[j]) break; \ | ||
343 | for (; j >= 0; j--) \ | ||
344 | scratch += sprintf(scratch, "%lx ", dev->bit[j]); \ | ||
345 | scratch++; \ | ||
346 | } while (0) | ||
347 | |||
348 | #define SPRINTF_BIT_A2(bit, name, max, ev) \ | ||
349 | do { \ | ||
350 | if (test_bit(ev, dev->evbit)) \ | ||
351 | SPRINTF_BIT_A(bit, name, max); \ | ||
352 | } while (0) | ||
353 | |||
354 | static void input_call_hotplug(char *verb, struct input_dev *dev) | ||
355 | { | ||
356 | char *argv[3], **envp, *buf, *scratch; | ||
357 | int i = 0, j, value; | ||
358 | |||
359 | if (!hotplug_path[0]) { | ||
360 | printk(KERN_ERR "input.c: calling hotplug without a hotplug agent defined\n"); | ||
361 | return; | ||
362 | } | ||
363 | if (in_interrupt()) { | ||
364 | printk(KERN_ERR "input.c: calling hotplug from interrupt\n"); | ||
365 | return; | ||
366 | } | ||
367 | if (!current->fs->root) { | ||
368 | printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n"); | ||
369 | return; | ||
370 | } | ||
371 | if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) { | ||
372 | printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); | ||
373 | return; | ||
374 | } | ||
375 | if (!(buf = kmalloc(1024, GFP_KERNEL))) { | ||
376 | kfree (envp); | ||
377 | printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); | ||
378 | return; | ||
379 | } | ||
380 | |||
381 | argv[0] = hotplug_path; | ||
382 | argv[1] = "input"; | ||
383 | argv[2] = NULL; | ||
384 | |||
385 | envp[i++] = "HOME=/"; | ||
386 | envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | ||
387 | |||
388 | scratch = buf; | ||
389 | |||
390 | envp[i++] = scratch; | ||
391 | scratch += sprintf(scratch, "ACTION=%s", verb) + 1; | ||
392 | |||
393 | envp[i++] = scratch; | ||
394 | scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", | ||
395 | dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version) + 1; | ||
396 | |||
397 | if (dev->name) { | ||
398 | envp[i++] = scratch; | ||
399 | scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; | ||
400 | } | ||
401 | |||
402 | if (dev->phys) { | ||
403 | envp[i++] = scratch; | ||
404 | scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; | ||
405 | } | ||
406 | |||
407 | SPRINTF_BIT_A(evbit, "EV=", EV_MAX); | ||
408 | SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY); | ||
409 | SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL); | ||
410 | SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS); | ||
411 | SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC); | ||
412 | SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED); | ||
413 | SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND); | ||
414 | SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF); | ||
415 | SPRINTF_BIT_A2(swbit, "SW=", SW_MAX, EV_SW); | ||
416 | |||
417 | envp[i++] = NULL; | ||
418 | |||
419 | #ifdef INPUT_DEBUG | ||
420 | printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n", | ||
421 | argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); | ||
422 | #endif | ||
423 | |||
424 | value = call_usermodehelper(argv [0], argv, envp, 0); | ||
425 | |||
426 | kfree(buf); | ||
427 | kfree(envp); | ||
428 | |||
429 | #ifdef INPUT_DEBUG | ||
430 | if (value != 0) | ||
431 | printk(KERN_DEBUG "input.c: hotplug returned %d\n", value); | ||
432 | #endif | ||
433 | } | ||
434 | |||
435 | #endif | ||
436 | |||
437 | static int input_print_bitmap(char *buf, unsigned long *bitmap, int max) | ||
438 | { | 320 | { |
439 | int i; | 321 | int i; |
440 | int len = 0; | 322 | int len = 0; |
@@ -444,10 +326,8 @@ static int input_print_bitmap(char *buf, unsigned long *bitmap, int max) | |||
444 | break; | 326 | break; |
445 | 327 | ||
446 | for (; i >= 0; i--) | 328 | for (; i >= 0; i--) |
447 | len += sprintf(buf + len, "%lx%s", bitmap[i], i > 0 ? " " : ""); | 329 | len += snprintf(buf + len, max(buf_size - len, 0), |
448 | 330 | "%lx%s", bitmap[i], i > 0 ? " " : ""); | |
449 | len += sprintf(buf + len, "\n"); | ||
450 | |||
451 | return len; | 331 | return len; |
452 | } | 332 | } |
453 | 333 | ||
@@ -472,17 +352,18 @@ static unsigned int input_devices_poll(struct file *file, poll_table *wait) | |||
472 | return 0; | 352 | return 0; |
473 | } | 353 | } |
474 | 354 | ||
475 | #define SPRINTF_BIT_B(ev, bm) \ | 355 | #define SPRINTF_BIT(ev, bm) \ |
476 | do { \ | 356 | do { \ |
477 | len += sprintf(buf + len, "B: %s=", #ev); \ | 357 | len += sprintf(buf + len, "B: %s=", #ev); \ |
478 | len += input_print_bitmap(buf + len, \ | 358 | len += input_print_bitmap(buf + len, INT_MAX, \ |
479 | dev->bm##bit, ev##_MAX); \ | 359 | dev->bm##bit, ev##_MAX); \ |
360 | len += sprintf(buf + len, "\n"); \ | ||
480 | } while (0) | 361 | } while (0) |
481 | 362 | ||
482 | #define SPRINTF_BIT_B2(ev, bm) \ | 363 | #define TEST_AND_SPRINTF_BIT(ev, bm) \ |
483 | do { \ | 364 | do { \ |
484 | if (test_bit(EV_##ev, dev->evbit)) \ | 365 | if (test_bit(EV_##ev, dev->evbit)) \ |
485 | SPRINTF_BIT_B(ev, bm); \ | 366 | SPRINTF_BIT(ev, bm); \ |
486 | } while (0) | 367 | } while (0) |
487 | 368 | ||
488 | static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) | 369 | static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) |
@@ -511,15 +392,15 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int | |||
511 | 392 | ||
512 | len += sprintf(buf + len, "\n"); | 393 | len += sprintf(buf + len, "\n"); |
513 | 394 | ||
514 | SPRINTF_BIT_B(EV, ev); | 395 | SPRINTF_BIT(EV, ev); |
515 | SPRINTF_BIT_B2(KEY, key); | 396 | TEST_AND_SPRINTF_BIT(KEY, key); |
516 | SPRINTF_BIT_B2(REL, rel); | 397 | TEST_AND_SPRINTF_BIT(REL, rel); |
517 | SPRINTF_BIT_B2(ABS, abs); | 398 | TEST_AND_SPRINTF_BIT(ABS, abs); |
518 | SPRINTF_BIT_B2(MSC, msc); | 399 | TEST_AND_SPRINTF_BIT(MSC, msc); |
519 | SPRINTF_BIT_B2(LED, led); | 400 | TEST_AND_SPRINTF_BIT(LED, led); |
520 | SPRINTF_BIT_B2(SND, snd); | 401 | TEST_AND_SPRINTF_BIT(SND, snd); |
521 | SPRINTF_BIT_B2(FF, ff); | 402 | TEST_AND_SPRINTF_BIT(FF, ff); |
522 | SPRINTF_BIT_B2(SW, sw); | 403 | TEST_AND_SPRINTF_BIT(SW, sw); |
523 | 404 | ||
524 | len += sprintf(buf + len, "\n"); | 405 | len += sprintf(buf + len, "\n"); |
525 | 406 | ||
@@ -689,7 +570,7 @@ static struct attribute_group input_dev_id_attr_group = { | |||
689 | static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ | 570 | static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ |
690 | { \ | 571 | { \ |
691 | struct input_dev *input_dev = to_input_dev(dev); \ | 572 | struct input_dev *input_dev = to_input_dev(dev); \ |
692 | return input_print_bitmap(buf, input_dev->bm##bit, ev##_MAX); \ | 573 | return input_print_bitmap(buf, PAGE_SIZE, input_dev->bm##bit, ev##_MAX);\ |
693 | } \ | 574 | } \ |
694 | static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); | 575 | static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); |
695 | 576 | ||
@@ -729,9 +610,95 @@ static void input_dev_release(struct class_device *class_dev) | |||
729 | module_put(THIS_MODULE); | 610 | module_put(THIS_MODULE); |
730 | } | 611 | } |
731 | 612 | ||
613 | /* | ||
614 | * Input hotplugging interface - loading event handlers based on | ||
615 | * device bitfields. | ||
616 | */ | ||
617 | static int input_add_hotplug_bm_var(char **envp, int num_envp, int *cur_index, | ||
618 | char *buffer, int buffer_size, int *cur_len, | ||
619 | const char *name, unsigned long *bitmap, int max) | ||
620 | { | ||
621 | if (*cur_index >= num_envp - 1) | ||
622 | return -ENOMEM; | ||
623 | |||
624 | envp[*cur_index] = buffer + *cur_len; | ||
625 | |||
626 | *cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name); | ||
627 | if (*cur_len > buffer_size) | ||
628 | return -ENOMEM; | ||
629 | |||
630 | *cur_len += input_print_bitmap(buffer + *cur_len, | ||
631 | max(buffer_size - *cur_len, 0), | ||
632 | bitmap, max) + 1; | ||
633 | if (*cur_len > buffer_size) | ||
634 | return -ENOMEM; | ||
635 | |||
636 | (*cur_index)++; | ||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | #define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ | ||
641 | do { \ | ||
642 | int err = add_hotplug_env_var(envp, num_envp, &i, \ | ||
643 | buffer, buffer_size, &len, \ | ||
644 | fmt, val); \ | ||
645 | if (err) \ | ||
646 | return err; \ | ||
647 | } while (0) | ||
648 | |||
649 | #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ | ||
650 | do { \ | ||
651 | int err = input_add_hotplug_bm_var(envp, num_envp, &i, \ | ||
652 | buffer, buffer_size, &len, \ | ||
653 | name, bm, max); \ | ||
654 | if (err) \ | ||
655 | return err; \ | ||
656 | } while (0) | ||
657 | |||
658 | static int input_dev_hotplug(struct class_device *cdev, char **envp, | ||
659 | int num_envp, char *buffer, int buffer_size) | ||
660 | { | ||
661 | struct input_dev *dev = to_input_dev(cdev); | ||
662 | int i = 0; | ||
663 | int len = 0; | ||
664 | |||
665 | INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", | ||
666 | dev->id.bustype, dev->id.vendor, | ||
667 | dev->id.product, dev->id.version); | ||
668 | if (dev->name) | ||
669 | INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name); | ||
670 | if (dev->phys) | ||
671 | INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys); | ||
672 | if (dev->phys) | ||
673 | INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq); | ||
674 | |||
675 | INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX); | ||
676 | if (test_bit(EV_KEY, dev->evbit)) | ||
677 | INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX); | ||
678 | if (test_bit(EV_REL, dev->evbit)) | ||
679 | INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX); | ||
680 | if (test_bit(EV_ABS, dev->evbit)) | ||
681 | INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX); | ||
682 | if (test_bit(EV_MSC, dev->evbit)) | ||
683 | INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX); | ||
684 | if (test_bit(EV_LED, dev->evbit)) | ||
685 | INPUT_ADD_HOTPLUG_BM_VAR("LED=", dev->ledbit, LED_MAX); | ||
686 | if (test_bit(EV_SND, dev->evbit)) | ||
687 | INPUT_ADD_HOTPLUG_BM_VAR("SND=", dev->sndbit, SND_MAX); | ||
688 | if (test_bit(EV_FF, dev->evbit)) | ||
689 | INPUT_ADD_HOTPLUG_BM_VAR("FF=", dev->ffbit, FF_MAX); | ||
690 | if (test_bit(EV_SW, dev->evbit)) | ||
691 | INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX); | ||
692 | |||
693 | envp[i] = NULL; | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
732 | struct class input_class = { | 698 | struct class input_class = { |
733 | .name = "input", | 699 | .name = "input", |
734 | .release = input_dev_release, | 700 | .release = input_dev_release, |
701 | .hotplug = input_dev_hotplug, | ||
735 | }; | 702 | }; |
736 | 703 | ||
737 | struct input_dev *input_allocate_device(void) | 704 | struct input_dev *input_allocate_device(void) |
@@ -810,10 +777,6 @@ void input_register_device(struct input_dev *dev) | |||
810 | input_link_handle(handle); | 777 | input_link_handle(handle); |
811 | 778 | ||
812 | 779 | ||
813 | #ifdef CONFIG_HOTPLUG | ||
814 | input_call_hotplug("add", dev); | ||
815 | #endif | ||
816 | |||
817 | input_wakeup_procfs_readers(); | 780 | input_wakeup_procfs_readers(); |
818 | } | 781 | } |
819 | 782 | ||
@@ -832,10 +795,6 @@ void input_unregister_device(struct input_dev *dev) | |||
832 | handle->handler->disconnect(handle); | 795 | handle->handler->disconnect(handle); |
833 | } | 796 | } |
834 | 797 | ||
835 | #ifdef CONFIG_HOTPLUG | ||
836 | input_call_hotplug("remove", dev); | ||
837 | #endif | ||
838 | |||
839 | list_del_init(&dev->node); | 798 | list_del_init(&dev->node); |
840 | 799 | ||
841 | if (dev->dynalloc) { | 800 | if (dev->dynalloc) { |