diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2009-06-12 09:20:55 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2009-06-12 09:20:55 -0400 |
| commit | a635f9dd83f3382577f4544a96df12356e951a40 (patch) | |
| tree | c6fa27df6d01c34e304a32c9f423d569f7358346 | |
| parent | 8ebf975608aaebd7feb33d77f07ba21a6380e086 (diff) | |
HID: use debugfs for report dumping descriptor
It is a little bit inconvenient for people who have some non-standard
HID hardware (usually violating the HID specification) to have to
recompile kernel with CONFIG_HID_DEBUG to be able to see kernel's perspective
of the HID report descriptor and observe the parsed events. Plus the messages
are then mixed up inconveniently with the rest of the dmesg stuff.
This patch implements /sys/kernel/debug/hid/<device>/rdesc file, which
represents the kernel's view of report descriptor (both the raw report
descriptor data and parsed contents).
With all the device-specific debug data being available through debugfs, there
is no need for keeping CONFIG_HID_DEBUG, as the 'debug' parameter to the
hid module will now only output only driver-specific debugging options, which has
absolutely minimal memory footprint, just a few error messages and one global
flag (hid_debug).
We use the current set of output formatting functions. The ones that need to be
used both for one-shot rdesc seq_file and also for continuous flow of data
(individual reports, as being sent by the device) distinguish according to the
passed seq_file parameter, and if it is NULL, it still output to kernel ringbuffer,
otherwise the corresponding seq_file is used for output.
The format of the output is preserved.
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
| -rw-r--r-- | drivers/hid/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/hid/Makefile | 5 | ||||
| -rw-r--r-- | drivers/hid/hid-core.c | 13 | ||||
| -rw-r--r-- | drivers/hid/hid-debug.c | 227 | ||||
| -rw-r--r-- | drivers/hid/hid-input.c | 13 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-core.c | 8 | ||||
| -rw-r--r-- | include/linux/hid-debug.h | 32 | ||||
| -rw-r--r-- | include/linux/hid.h | 4 |
8 files changed, 195 insertions, 122 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7e67dcb3d4f6..05950a783560 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig | |||
| @@ -31,21 +31,6 @@ config HID | |||
| 31 | 31 | ||
| 32 | If unsure, say Y. | 32 | If unsure, say Y. |
| 33 | 33 | ||
| 34 | config HID_DEBUG | ||
| 35 | bool "HID debugging support" | ||
| 36 | default y | ||
| 37 | depends on HID | ||
| 38 | ---help--- | ||
| 39 | This option lets the HID layer output diagnostics about its internal | ||
| 40 | state, resolve HID usages, dump HID fields, etc. Individual HID drivers | ||
| 41 | use this debugging facility to output information about individual HID | ||
| 42 | devices, etc. | ||
| 43 | |||
| 44 | This feature is useful for those who are either debugging the HID parser | ||
| 45 | or any HID hardware device. | ||
| 46 | |||
| 47 | If unsure, say Y. | ||
| 48 | |||
| 49 | config HIDRAW | 34 | config HIDRAW |
| 50 | bool "/dev/hidraw raw HID device support" | 35 | bool "/dev/hidraw raw HID device support" |
| 51 | depends on HID | 36 | depends on HID |
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1f7cb0fd4505..cf3687d1ed63 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile | |||
| @@ -3,9 +3,12 @@ | |||
| 3 | # | 3 | # |
| 4 | hid-objs := hid-core.o hid-input.o | 4 | hid-objs := hid-core.o hid-input.o |
| 5 | 5 | ||
| 6 | ifdef CONFIG_DEBUG_FS | ||
| 7 | hid-objs += hid-debug.o | ||
| 8 | endif | ||
| 9 | |||
| 6 | obj-$(CONFIG_HID) += hid.o | 10 | obj-$(CONFIG_HID) += hid.o |
| 7 | 11 | ||
| 8 | hid-$(CONFIG_HID_DEBUG) += hid-debug.o | ||
| 9 | hid-$(CONFIG_HIDRAW) += hidraw.o | 12 | hid-$(CONFIG_HIDRAW) += hidraw.o |
| 10 | 13 | ||
| 11 | hid-logitech-objs := hid-lg.o | 14 | hid-logitech-objs := hid-lg.o |
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8551693d645f..d4317db85b54 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
| @@ -44,12 +44,10 @@ | |||
| 44 | #define DRIVER_DESC "HID core driver" | 44 | #define DRIVER_DESC "HID core driver" |
| 45 | #define DRIVER_LICENSE "GPL" | 45 | #define DRIVER_LICENSE "GPL" |
| 46 | 46 | ||
| 47 | #ifdef CONFIG_HID_DEBUG | ||
| 48 | int hid_debug = 0; | 47 | int hid_debug = 0; |
| 49 | module_param_named(debug, hid_debug, int, 0600); | 48 | module_param_named(debug, hid_debug, int, 0600); |
| 50 | MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); | 49 | MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); |
| 51 | EXPORT_SYMBOL_GPL(hid_debug); | 50 | EXPORT_SYMBOL_GPL(hid_debug); |
| 52 | #endif | ||
| 53 | 51 | ||
| 54 | /* | 52 | /* |
| 55 | * Register a new report for a device. | 53 | * Register a new report for a device. |
| @@ -987,7 +985,6 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) | |||
| 987 | 985 | ||
| 988 | if (offset >= field->report_count) { | 986 | if (offset >= field->report_count) { |
| 989 | dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count); | 987 | dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count); |
| 990 | hid_dump_field(field, 8); | ||
| 991 | return -1; | 988 | return -1; |
| 992 | } | 989 | } |
| 993 | if (field->logical_minimum < 0) { | 990 | if (field->logical_minimum < 0) { |
| @@ -1721,6 +1718,8 @@ int hid_add_device(struct hid_device *hdev) | |||
| 1721 | if (!ret) | 1718 | if (!ret) |
| 1722 | hdev->status |= HID_STAT_ADDED; | 1719 | hdev->status |= HID_STAT_ADDED; |
| 1723 | 1720 | ||
| 1721 | hid_debug_register(hdev, dev_name(&hdev->dev)); | ||
| 1722 | |||
| 1724 | return ret; | 1723 | return ret; |
| 1725 | } | 1724 | } |
| 1726 | EXPORT_SYMBOL_GPL(hid_add_device); | 1725 | EXPORT_SYMBOL_GPL(hid_add_device); |
| @@ -1768,6 +1767,7 @@ static void hid_remove_device(struct hid_device *hdev) | |||
| 1768 | { | 1767 | { |
| 1769 | if (hdev->status & HID_STAT_ADDED) { | 1768 | if (hdev->status & HID_STAT_ADDED) { |
| 1770 | device_del(&hdev->dev); | 1769 | device_del(&hdev->dev); |
| 1770 | hid_debug_unregister(hdev); | ||
| 1771 | hdev->status &= ~HID_STAT_ADDED; | 1771 | hdev->status &= ~HID_STAT_ADDED; |
| 1772 | } | 1772 | } |
| 1773 | } | 1773 | } |
| @@ -1843,6 +1843,10 @@ static int __init hid_init(void) | |||
| 1843 | { | 1843 | { |
| 1844 | int ret; | 1844 | int ret; |
| 1845 | 1845 | ||
| 1846 | if (hid_debug) | ||
| 1847 | printk(KERN_WARNING "HID: hid_debug parameter has been deprecated. " | ||
| 1848 | "Debugging data are now provided via debugfs\n"); | ||
| 1849 | |||
| 1846 | ret = bus_register(&hid_bus_type); | 1850 | ret = bus_register(&hid_bus_type); |
| 1847 | if (ret) { | 1851 | if (ret) { |
| 1848 | printk(KERN_ERR "HID: can't register hid bus\n"); | 1852 | printk(KERN_ERR "HID: can't register hid bus\n"); |
| @@ -1853,6 +1857,8 @@ static int __init hid_init(void) | |||
| 1853 | if (ret) | 1857 | if (ret) |
| 1854 | goto err_bus; | 1858 | goto err_bus; |
| 1855 | 1859 | ||
| 1860 | hid_debug_init(); | ||
| 1861 | |||
| 1856 | return 0; | 1862 | return 0; |
| 1857 | err_bus: | 1863 | err_bus: |
| 1858 | bus_unregister(&hid_bus_type); | 1864 | bus_unregister(&hid_bus_type); |
| @@ -1862,6 +1868,7 @@ err: | |||
| 1862 | 1868 | ||
| 1863 | static void __exit hid_exit(void) | 1869 | static void __exit hid_exit(void) |
| 1864 | { | 1870 | { |
| 1871 | hid_debug_exit(); | ||
| 1865 | hidraw_exit(); | 1872 | hidraw_exit(); |
| 1866 | bus_unregister(&hid_bus_type); | 1873 | bus_unregister(&hid_bus_type); |
| 1867 | } | 1874 | } |
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 47ac1a7d66e1..067e173aa3e4 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de> | 2 | * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de> |
| 3 | * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> | 3 | * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> |
| 4 | * (c) 2007 Jiri Kosina | 4 | * (c) 2007-2009 Jiri Kosina |
| 5 | * | 5 | * |
| 6 | * Some debug stuff for the HID parser. | 6 | * HID debugging support |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | /* | 9 | /* |
| @@ -26,9 +26,13 @@ | |||
| 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
| 27 | */ | 27 | */ |
| 28 | 28 | ||
| 29 | #include <linux/debugfs.h> | ||
| 30 | #include <linux/seq_file.h> | ||
| 29 | #include <linux/hid.h> | 31 | #include <linux/hid.h> |
| 30 | #include <linux/hid-debug.h> | 32 | #include <linux/hid-debug.h> |
| 31 | 33 | ||
| 34 | static struct dentry *hid_debug_root; | ||
| 35 | |||
| 32 | struct hid_usage_entry { | 36 | struct hid_usage_entry { |
| 33 | unsigned page; | 37 | unsigned page; |
| 34 | unsigned usage; | 38 | unsigned usage; |
| @@ -331,72 +335,83 @@ static const struct hid_usage_entry hid_usage_table[] = { | |||
| 331 | { 0, 0, NULL } | 335 | { 0, 0, NULL } |
| 332 | }; | 336 | }; |
| 333 | 337 | ||
| 334 | static void resolv_usage_page(unsigned page) { | 338 | static void resolv_usage_page(unsigned page, struct seq_file *f) { |
| 335 | const struct hid_usage_entry *p; | 339 | const struct hid_usage_entry *p; |
| 336 | 340 | ||
| 337 | for (p = hid_usage_table; p->description; p++) | 341 | for (p = hid_usage_table; p->description; p++) |
| 338 | if (p->page == page) { | 342 | if (p->page == page) { |
| 339 | printk("%s", p->description); | 343 | if (!f) |
| 344 | printk("%s", p->description); | ||
| 345 | else | ||
| 346 | seq_printf(f, "%s", p->description); | ||
| 340 | return; | 347 | return; |
| 341 | } | 348 | } |
