Commit a635f9dd authored by Jiri Kosina's avatar Jiri Kosina

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: default avatarJiri Kosina <jkosina@suse.cz>
parent 8ebf9756
...@@ -31,21 +31,6 @@ config HID ...@@ -31,21 +31,6 @@ config HID
If unsure, say Y. If unsure, say Y.
config HID_DEBUG
bool "HID debugging support"
default y
depends on HID
---help---
This option lets the HID layer output diagnostics about its internal
state, resolve HID usages, dump HID fields, etc. Individual HID drivers
use this debugging facility to output information about individual HID
devices, etc.
This feature is useful for those who are either debugging the HID parser
or any HID hardware device.
If unsure, say Y.
config HIDRAW config HIDRAW
bool "/dev/hidraw raw HID device support" bool "/dev/hidraw raw HID device support"
depends on HID depends on HID
......
...@@ -3,9 +3,12 @@ ...@@ -3,9 +3,12 @@
# #
hid-objs := hid-core.o hid-input.o hid-objs := hid-core.o hid-input.o
ifdef CONFIG_DEBUG_FS
hid-objs += hid-debug.o
endif
obj-$(CONFIG_HID) += hid.o obj-$(CONFIG_HID) += hid.o
hid-$(CONFIG_HID_DEBUG) += hid-debug.o
hid-$(CONFIG_HIDRAW) += hidraw.o hid-$(CONFIG_HIDRAW) += hidraw.o
hid-logitech-objs := hid-lg.o hid-logitech-objs := hid-lg.o
......
...@@ -44,12 +44,10 @@ ...@@ -44,12 +44,10 @@
#define DRIVER_DESC "HID core driver" #define DRIVER_DESC "HID core driver"
#define DRIVER_LICENSE "GPL" #define DRIVER_LICENSE "GPL"
#ifdef CONFIG_HID_DEBUG
int hid_debug = 0; int hid_debug = 0;
module_param_named(debug, hid_debug, int, 0600); module_param_named(debug, hid_debug, int, 0600);
MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)");
EXPORT_SYMBOL_GPL(hid_debug); EXPORT_SYMBOL_GPL(hid_debug);
#endif
/* /*
* Register a new report for a device. * Register a new report for a device.
...@@ -987,7 +985,6 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) ...@@ -987,7 +985,6 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
if (offset >= field->report_count) { if (offset >= field->report_count) {
dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count); dbg_hid("offset (%d) exceeds report_count (%d)\n", offset, field->report_count);
hid_dump_field(field, 8);
return -1; return -1;
} }
if (field->logical_minimum < 0) { if (field->logical_minimum < 0) {
...@@ -1721,6 +1718,8 @@ int hid_add_device(struct hid_device *hdev) ...@@ -1721,6 +1718,8 @@ int hid_add_device(struct hid_device *hdev)
if (!ret) if (!ret)
hdev->status |= HID_STAT_ADDED; hdev->status |= HID_STAT_ADDED;
hid_debug_register(hdev, dev_name(&hdev->dev));
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(hid_add_device); EXPORT_SYMBOL_GPL(hid_add_device);
...@@ -1768,6 +1767,7 @@ static void hid_remove_device(struct hid_device *hdev) ...@@ -1768,6 +1767,7 @@ static void hid_remove_device(struct hid_device *hdev)
{ {
if (hdev->status & HID_STAT_ADDED) { if (hdev->status & HID_STAT_ADDED) {
device_del(&hdev->dev); device_del(&hdev->dev);
hid_debug_unregister(hdev);
hdev->status &= ~HID_STAT_ADDED; hdev->status &= ~HID_STAT_ADDED;
} }
} }
...@@ -1843,6 +1843,10 @@ static int __init hid_init(void) ...@@ -1843,6 +1843,10 @@ static int __init hid_init(void)
{ {
int ret; int ret;
if (hid_debug)
printk(KERN_WARNING "HID: hid_debug parameter has been deprecated. "
"Debugging data are now provided via debugfs\n");
ret = bus_register(&hid_bus_type); ret = bus_register(&hid_bus_type);
if (ret) { if (ret) {
printk(KERN_ERR "HID: can't register hid bus\n"); printk(KERN_ERR "HID: can't register hid bus\n");
...@@ -1853,6 +1857,8 @@ static int __init hid_init(void) ...@@ -1853,6 +1857,8 @@ static int __init hid_init(void)
if (ret) if (ret)
goto err_bus; goto err_bus;
hid_debug_init();
return 0; return 0;
err_bus: err_bus:
bus_unregister(&hid_bus_type); bus_unregister(&hid_bus_type);
...@@ -1862,6 +1868,7 @@ static int __init hid_init(void) ...@@ -1862,6 +1868,7 @@ static int __init hid_init(void)
static void __exit hid_exit(void) static void __exit hid_exit(void)
{ {
hid_debug_exit();
hidraw_exit(); hidraw_exit();
bus_unregister(&hid_bus_type); bus_unregister(&hid_bus_type);
} }
......
This diff is collapsed.
...@@ -159,17 +159,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -159,17 +159,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
field->hidinput = hidinput; field->hidinput = hidinput;
dbg_hid("Mapping: ");
hid_resolv_usage(usage->hid);
dbg_hid_line(" ---> ");
if (field->flags & HID_MAIN_ITEM_CONSTANT) if (field->flags & HID_MAIN_ITEM_CONSTANT)
goto ignore; goto ignore;
/* only LED usages are supported in output fields */ /* only LED usages are supported in output fields */
if (field->report_type == HID_OUTPUT_REPORT && if (field->report_type == HID_OUTPUT_REPORT &&
(usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
dbg_hid_line(" [non-LED output field] ");
goto ignore; goto ignore;
} }
...@@ -561,15 +556,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel ...@@ -561,15 +556,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(MSC_SCAN, input->mscbit); set_bit(MSC_SCAN, input->mscbit);
} }
hid_resolv_event(usage->type, usage->code);
dbg_hid_line("\n");
return;
ignore: ignore:
dbg_hid_line("IGNORED\n");
return; return;
} }
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
* Copyright (c) 1999 Andreas Gal * Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2006-2008 Jiri Kosina
* Copyright (c) 2007-2008 Oliver Neukum * Copyright (c) 2007-2008 Oliver Neukum
* Copyright (c) 2006-2009 Jiri Kosina
*/ */
/* /*
...@@ -886,11 +886,6 @@ static int usbhid_parse(struct hid_device *hid) ...@@ -886,11 +886,6 @@ static int usbhid_parse(struct hid_device *hid)
goto err; goto err;
} }
dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++)
dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
dbg_hid_line("\n");
ret = hid_parse_report(hid, rdesc, rsize); ret = hid_parse_report(hid, rdesc, rsize);
kfree(rdesc); kfree(rdesc);
if (ret) { if (ret) {
...@@ -1005,7 +1000,6 @@ static int usbhid_start(struct hid_device *hid) ...@@ -1005,7 +1000,6 @@ static int usbhid_start(struct hid_device *hid)
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
usbhid_init_reports(hid); usbhid_init_reports(hid);
hid_dump_device(hid);
set_bit(HID_STARTED, &usbhid->iofl); set_bit(HID_STARTED, &usbhid->iofl);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define __HID_DEBUG_H #define __HID_DEBUG_H
/* /*
* Copyright (c) 2007 Jiri Kosina * Copyright (c) 2007-2009 Jiri Kosina
*/ */
/* /*
...@@ -22,13 +22,16 @@ ...@@ -22,13 +22,16 @@
* *
*/ */
#ifdef CONFIG_HID_DEBUG #ifdef CONFIG_DEBUG_FS
void hid_dump_input(struct hid_usage *, __s32); void hid_dump_input(struct hid_usage *, __s32);
void hid_dump_device(struct hid_device *); void hid_dump_device(struct hid_device *, struct seq_file *);
void hid_dump_field(struct hid_field *, int); void hid_dump_field(struct hid_field *, int, struct seq_file *);
void hid_resolv_usage(unsigned); void hid_resolv_usage(unsigned, struct seq_file *);
void hid_resolv_event(__u8, __u16); void hid_debug_register(struct hid_device *, const char *);
void hid_debug_unregister(struct hid_device *);
void hid_debug_init(void);
void hid_debug_exit(void);
#else #else
...@@ -37,9 +40,12 @@ void hid_resolv_event(__u8, __u16); ...@@ -37,9 +40,12 @@ void hid_resolv_event(__u8, __u16);
#define hid_dump_field(a,b) do { } while (0) #define hid_dump_field(a,b) do { } while (0)
#define hid_resolv_usage(a) do { } while (0) #define hid_resolv_usage(a) do { } while (0)
#define hid_resolv_event(a,b) do { } while (0) #define hid_resolv_event(a,b) do { } while (0)
#define hid_debug_register(a, b) do { } while (0)
#define hid_debug_unregister(a) do { } while (0)
#define hid_debug_init() do { } while (0)
#define hid_debug_exit() do { } while (0)
#endif /* CONFIG_HID_DEBUG */ #endif
#endif #endif
...@@ -451,6 +451,10 @@ struct hid_device { /* device report descriptor */ ...@@ -451,6 +451,10 @@ struct hid_device { /* device report descriptor */
char phys[64]; /* Device physical location */ char phys[64]; /* Device physical location */
char uniq[64]; /* Device unique identifier (serial #) */ char uniq[64]; /* Device unique identifier (serial #) */
/* debugfs */
struct dentry *debug_dir;
struct dentry *debug_rdesc;
void *driver_data; void *driver_data;
/* temporary hid_ff handling (until moved to the drivers) */ /* temporary hid_ff handling (until moved to the drivers) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment