diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-09-15 03:01:55 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 12:52:54 -0400 |
commit | 5c1e9a6a6ab2f4c60462cecb7773860a62d86e39 (patch) | |
tree | c195b9268e80d9e533386f7160abbc3531662f71 /drivers | |
parent | 051b2feaa4a92592d160dcb8715cc4a5faaaa52f (diff) |
[PATCH] Input: export input_dev data via sysfs attributes
Input: export various input device attributes via sysfs
The following structure is exported:
input0/
|-- name
|-- phys
|-- uniq
|-- id/{bustype|vendor|product|version}
`-- capabilities/{ev|abs|rel|key|led|msc|ff|sw}
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/input.c | 156 |
1 files changed, 133 insertions, 23 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index ceaed631d49f..57fbfd907157 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -434,6 +434,23 @@ static void input_call_hotplug(char *verb, struct input_dev *dev) | |||
434 | 434 | ||
435 | #endif | 435 | #endif |
436 | 436 | ||
437 | static int input_print_bitmap(char *buf, unsigned long *bitmap, int max) | ||
438 | { | ||
439 | int i; | ||
440 | int len = 0; | ||
441 | |||
442 | for (i = NBITS(max) - 1; i > 0; i--) | ||
443 | if (bitmap[i]) | ||
444 | break; | ||
445 | |||
446 | for (; i >= 0; i--) | ||
447 | len += sprintf(buf + len, "%lx%s", bitmap[i], i > 0 ? " " : ""); | ||
448 | |||
449 | len += sprintf(buf + len, "\n"); | ||
450 | |||
451 | return len; | ||
452 | } | ||
453 | |||
437 | #ifdef CONFIG_PROC_FS | 454 | #ifdef CONFIG_PROC_FS |
438 | 455 | ||
439 | static struct proc_dir_entry *proc_bus_input_dir; | 456 | static struct proc_dir_entry *proc_bus_input_dir; |
@@ -455,20 +472,17 @@ static unsigned int input_devices_poll(struct file *file, poll_table *wait) | |||
455 | return 0; | 472 | return 0; |
456 | } | 473 | } |
457 | 474 | ||
458 | #define SPRINTF_BIT_B(bit, name, max) \ | 475 | #define SPRINTF_BIT_B(ev, bm) \ |
459 | do { \ | 476 | do { \ |
460 | len += sprintf(buf + len, "B: %s", name); \ | 477 | len += sprintf(buf + len, "B: %s=", #ev); \ |
461 | for (i = NBITS(max) - 1; i >= 0; i--) \ | 478 | len += input_print_bitmap(buf + len, \ |
462 | if (dev->bit[i]) break; \ | 479 | dev->bm##bit, ev##_MAX); \ |
463 | for (; i >= 0; i--) \ | ||
464 | len += sprintf(buf + len, "%lx ", dev->bit[i]); \ | ||
465 | len += sprintf(buf + len, "\n"); \ | ||
466 | } while (0) | 480 | } while (0) |
467 | 481 | ||
468 | #define SPRINTF_BIT_B2(bit, name, max, ev) \ | 482 | #define SPRINTF_BIT_B2(ev, bm) \ |
469 | do { \ | 483 | do { \ |
470 | if (test_bit(ev, dev->evbit)) \ | 484 | if (test_bit(EV_##ev, dev->evbit)) \ |
471 | SPRINTF_BIT_B(bit, name, max); \ | 485 | SPRINTF_BIT_B(ev, bm); \ |
472 | } while (0) | 486 | } while (0) |
473 | 487 | ||
474 | static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) | 488 | static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) |
@@ -478,7 +492,7 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int | |||
478 | const char *path; | 492 | const char *path; |
479 | 493 | ||
480 | off_t at = 0; | 494 | off_t at = 0; |
481 | int i, len, cnt = 0; | 495 | int len, cnt = 0; |
482 | 496 | ||
483 | list_for_each_entry(dev, &input_dev_list, node) { | 497 | list_for_each_entry(dev, &input_dev_list, node) { |
484 | 498 | ||
@@ -497,15 +511,15 @@ static int input_devices_read(char *buf, char **start, off_t pos, int count, int | |||
497 | 511 | ||
498 | len += sprintf(buf + len, "\n"); | 512 | len += sprintf(buf + len, "\n"); |
499 | 513 | ||
500 | SPRINTF_BIT_B(evbit, "EV=", EV_MAX); | 514 | SPRINTF_BIT_B(EV, ev); |
501 | SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); | 515 | SPRINTF_BIT_B2(KEY, key); |
502 | SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); | 516 | SPRINTF_BIT_B2(REL, rel); |
503 | SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); | 517 | SPRINTF_BIT_B2(ABS, abs); |
504 | SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); | 518 | SPRINTF_BIT_B2(MSC, msc); |
505 | SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); | 519 | SPRINTF_BIT_B2(LED, led); |
506 | SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); | 520 | SPRINTF_BIT_B2(SND, snd); |
507 | SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); | 521 | SPRINTF_BIT_B2(FF, ff); |
508 | SPRINTF_BIT_B2(swbit, "SW=", SW_MAX, EV_SW); | 522 | SPRINTF_BIT_B2(SW, sw); |
509 | 523 | ||
510 | len += sprintf(buf + len, "\n"); | 524 | len += sprintf(buf + len, "\n"); |
511 | 525 | ||
@@ -612,6 +626,96 @@ static inline int input_proc_init(void) { return 0; } | |||
612 | static inline void input_proc_exit(void) { } | 626 | static inline void input_proc_exit(void) { } |
613 | #endif | 627 | #endif |
614 | 628 | ||
629 | #define INPUT_DEV_STRING_ATTR_SHOW(name) \ | ||
630 | static ssize_t input_dev_show_##name(struct class_device *dev, char *buf) \ | ||
631 | { \ | ||
632 | struct input_dev *input_dev = to_input_dev(dev); \ | ||
633 | int retval; \ | ||
634 | \ | ||
635 | retval = down_interruptible(&input_dev->sem); \ | ||
636 | if (retval) \ | ||
637 | return retval; \ | ||
638 | \ | ||
639 | retval = sprintf(buf, "%s\n", input_dev->name ? input_dev->name : ""); \ | ||
640 | \ | ||
641 | up(&input_dev->sem); \ | ||
642 | \ | ||
643 | return retval; \ | ||
644 | } | ||
645 | |||
646 | INPUT_DEV_STRING_ATTR_SHOW(name); | ||
647 | INPUT_DEV_STRING_ATTR_SHOW(phys); | ||
648 | INPUT_DEV_STRING_ATTR_SHOW(uniq); | ||
649 | |||
650 | static struct class_device_attribute input_dev_attrs[] = { | ||
651 | __ATTR(name, S_IRUGO, input_dev_show_name, NULL), | ||
652 | __ATTR(phys, S_IRUGO, input_dev_show_phys, NULL), | ||
653 | __ATTR(uniq, S_IRUGO, input_dev_show_uniq, NULL), | ||
654 | __ATTR_NULL | ||
655 | }; | ||
656 | |||
657 | #define INPUT_DEV_ID_ATTR(name) \ | ||
658 | static ssize_t input_dev_show_id_##name(struct class_device *dev, char *buf) \ | ||
659 | { \ | ||
660 | struct input_dev *input_dev = to_input_dev(dev); \ | ||
661 | return sprintf(buf, "%04x\n", input_dev->id.name); \ | ||
662 | } \ | ||
663 | static CLASS_DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL); | ||
664 | |||
665 | INPUT_DEV_ID_ATTR(bustype); | ||
666 | INPUT_DEV_ID_ATTR(vendor); | ||
667 | INPUT_DEV_ID_ATTR(product); | ||
668 | INPUT_DEV_ID_ATTR(version); | ||
669 | |||
670 | static struct attribute *input_dev_id_attrs[] = { | ||
671 | &class_device_attr_bustype.attr, | ||
672 | &class_device_attr_vendor.attr, | ||
673 | &class_device_attr_product.attr, | ||
674 | &class_device_attr_version.attr, | ||
675 | NULL | ||
676 | }; | ||
677 | |||
678 | static struct attribute_group input_dev_id_attr_group = { | ||
679 | .name = "id", | ||
680 | .attrs = input_dev_id_attrs, | ||
681 | }; | ||
682 | |||
683 | #define INPUT_DEV_CAP_ATTR(ev, bm) \ | ||
684 | static ssize_t input_dev_show_cap_##bm(struct class_device *dev, char *buf) \ | ||
685 | { \ | ||
686 | struct input_dev *input_dev = to_input_dev(dev); \ | ||
687 | return input_print_bitmap(buf, input_dev->bm##bit, ev##_MAX); \ | ||
688 | } \ | ||
689 | static CLASS_DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL); | ||
690 | |||
691 | INPUT_DEV_CAP_ATTR(EV, ev); | ||
692 | INPUT_DEV_CAP_ATTR(KEY, key); | ||
693 | INPUT_DEV_CAP_ATTR(REL, rel); | ||
694 | INPUT_DEV_CAP_ATTR(ABS, abs); | ||
695 | INPUT_DEV_CAP_ATTR(MSC, msc); | ||
696 | INPUT_DEV_CAP_ATTR(LED, led); | ||
697 | INPUT_DEV_CAP_ATTR(SND, snd); | ||
698 | INPUT_DEV_CAP_ATTR(FF, ff); | ||
699 | INPUT_DEV_CAP_ATTR(SW, sw); | ||
700 | |||
701 | static struct attribute *input_dev_caps_attrs[] = { | ||
702 | &class_device_attr_ev.attr, | ||
703 | &class_device_attr_key.attr, | ||
704 | &class_device_attr_rel.attr, | ||
705 | &class_device_attr_abs.attr, | ||
706 | &class_device_attr_msc.attr, | ||
707 | &class_device_attr_led.attr, | ||
708 | &class_device_attr_snd.attr, | ||
709 | &class_device_attr_ff.attr, | ||
710 | &class_device_attr_sw.attr, | ||
711 | NULL | ||
712 | }; | ||
713 | |||
714 | static struct attribute_group input_dev_caps_attr_group = { | ||
715 | .name = "capabilities", | ||
716 | .attrs = input_dev_caps_attrs, | ||
717 | }; | ||
718 | |||
615 | static void input_dev_release(struct class_device *class_dev) | 719 | static void input_dev_release(struct class_device *class_dev) |
616 | { | 720 | { |
617 | struct input_dev *dev = to_input_dev(class_dev); | 721 | struct input_dev *dev = to_input_dev(class_dev); |
@@ -623,6 +727,7 @@ static void input_dev_release(struct class_device *class_dev) | |||
623 | static struct class input_dev_class = { | 727 | static struct class input_dev_class = { |
624 | .name = "input_dev", | 728 | .name = "input_dev", |
625 | .release = input_dev_release, | 729 | .release = input_dev_release, |
730 | .class_dev_attrs = input_dev_attrs, | ||
626 | }; | 731 | }; |
627 | 732 | ||
628 | struct input_dev *input_allocate_device(void) | 733 | struct input_dev *input_allocate_device(void) |
@@ -660,6 +765,8 @@ static void input_register_classdevice(struct input_dev *dev) | |||
660 | kfree(path); | 765 | kfree(path); |
661 | 766 | ||
662 | class_device_add(&dev->cdev); | 767 | class_device_add(&dev->cdev); |
768 | sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group); | ||
769 | sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group); | ||
663 | } | 770 | } |
664 | 771 | ||
665 | void input_register_device(struct input_dev *dev) | 772 | void input_register_device(struct input_dev *dev) |
@@ -726,8 +833,11 @@ void input_unregister_device(struct input_dev *dev) | |||
726 | 833 | ||
727 | list_del_init(&dev->node); | 834 | list_del_init(&dev->node); |
728 | 835 | ||
729 | if (dev->dynalloc) | 836 | if (dev->dynalloc) { |
837 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group); | ||
838 | sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group); | ||
730 | class_device_unregister(&dev->cdev); | 839 | class_device_unregister(&dev->cdev); |
840 | } | ||
731 | 841 | ||
732 | input_wakeup_procfs_readers(); | 842 | input_wakeup_procfs_readers(); |
733 | } | 843 | } |