diff options
| -rw-r--r-- | drivers/hid/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/hid/Makefile | 5 | ||||
| -rw-r--r-- | drivers/hid/hid-core.c | 56 | ||||
| -rw-r--r-- | drivers/hid/hid-debug.c | 439 | ||||
| -rw-r--r-- | drivers/hid/hid-input.c | 13 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-core.c | 8 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-quirks.c | 2 | ||||
| -rw-r--r-- | include/linux/hid-debug.h | 48 | ||||
| -rw-r--r-- | include/linux/hid.h | 22 |
9 files changed, 455 insertions, 153 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index aba8facecce8..111afbe8de03 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 9b9271d6527a..0de2dff5542c 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 48567d8fe358..342b7d36d7bb 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, "toggle HID debugging messages"); |
| 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. |
| @@ -861,7 +859,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, | |||
| 861 | struct hid_driver *hdrv = hid->driver; | 859 | struct hid_driver *hdrv = hid->driver; |
| 862 | int ret; | 860 | int ret; |
| 863 | 861 | ||
| 864 | hid_dump_input(usage, value); | 862 | hid_dump_input(hid, usage, value); |
| 865 | 863 | ||
| 866 | if (hdrv && hdrv->event && hid_match_usage(hid, usage)) { | 864 | if (hdrv && hdrv->event && hid_match_usage(hid, usage)) { |
| 867 | ret = hdrv->event(hid, field, usage, value); | 865 | ret = hdrv->event(hid, field, usage, value); |
| @@ -983,11 +981,10 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) | |||
| 983 | { | 981 | { |
| 984 | unsigned size = field->report_size; | 982 | unsigned size = field->report_size; |
| 985 | 983 | ||
| 986 | hid_dump_input(field->usage + offset, value); | 984 | hid_dump_input(field->report->device, field->usage + offset, 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) { |
| @@ -1078,6 +1075,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
| 1078 | struct hid_report_enum *report_enum; | 1075 | struct hid_report_enum *report_enum; |
| 1079 | struct hid_driver *hdrv; | 1076 | struct hid_driver *hdrv; |
| 1080 | struct hid_report *report; | 1077 | struct hid_report *report; |
| 1078 | char *buf; | ||
| 1081 | unsigned int i; | 1079 | unsigned int i; |
| 1082 | int ret; | 1080 | int ret; |
| 1083 | 1081 | ||
| @@ -1091,18 +1089,38 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i | |||
| 1091 | return -1; | 1089 | return -1; |
| 1092 | } | 1090 | } |
| 1093 | 1091 | ||
| 1094 | dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); | 1092 | buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, |
| 1093 | interrupt ? GFP_ATOMIC : GFP_KERNEL); | ||
| 1094 | |||
| 1095 | if (!buf) { | ||
| 1096 | report = hid_get_report(report_enum, data); | ||
| 1097 | goto nomem; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | ||
| 1101 | "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); | ||
| 1102 | hid_debug_event(hid, buf); | ||
| 1095 | 1103 | ||
| 1096 | report = hid_get_report(report_enum, data); | 1104 | report = hid_get_report(report_enum, data); |
| 1097 | if (!report) | 1105 | if (!report) { |
| 1106 | kfree(buf); | ||
| 1098 | return -1; | 1107 | return -1; |
| 1108 | } | ||
| 1099 | 1109 | ||
| 1100 | /* dump the report */ | 1110 | /* dump the report */ |
| 1101 | dbg_hid("report %d (size %u) = ", report->id, size); | 1111 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, |
| 1102 | for (i = 0; i < size; i++) | 1112 | "report %d (size %u) = ", report->id, size); |
| 1103 | dbg_hid_line(" %02x", data[i]); | 1113 | hid_debug_event(hid, buf); |
| 1104 | dbg_hid_line("\n"); | 1114 | for (i = 0; i < size; i++) { |
| 1115 | snprintf(buf, HID_DEBUG_BUFSIZE - 1, | ||
| 1116 | " %02x", data[i]); | ||
| 1117 | hid_debug_event(hid, buf); | ||
| 1118 | } | ||
| 1119 | hid_debug_event(hid, "\n"); | ||
| 1105 | 1120 | ||
| 1121 | kfree(buf); | ||
| 1122 | |||
| 1123 | nomem: | ||
| 1106 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { | 1124 | if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { |
| 1107 | ret = hdrv->raw_event(hid, report, data, size); | 1125 | ret = hdrv->raw_event(hid, report, data, size); |
| 1108 | if (ret != 0) | 1126 | if (ret != 0) |
| @@ -1323,7 +1341,6 @@ static const struct hid_device_id hid_blacklist[] = { | |||
| 1323 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, | 1341 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, |
| 1324 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, | 1342 | { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, |
| 1325 | 1343 | ||
| 1326 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) }, | ||
| 1327 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, | 1344 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, |
| 1328 | { } | 1345 | { } |
| 1329 | }; | 1346 | }; |
| @@ -1730,6 +1747,8 @@ int hid_add_device(struct hid_device *hdev) | |||
| 1730 | if (!ret) | 1747 | if (!ret) |
| 1731 | hdev->status |= HID_STAT_ADDED; | 1748 | hdev->status |= HID_STAT_ADDED; |
| 1732 | 1749 | ||
| 1750 | hid_debug_register(hdev, dev_name(&hdev->dev)); | ||
| 1751 | |||
| 1733 | return ret; | 1752 | return ret; |
| 1734 | } | 1753 | } |
| 1735 | EXPORT_SYMBOL_GPL(hid_add_device); | 1754 | EXPORT_SYMBOL_GPL(hid_add_device); |
| @@ -1766,6 +1785,9 @@ struct hid_device *hid_allocate_device(void) | |||
| 1766 | for (i = 0; i < HID_REPORT_TYPES; i++) | 1785 | for (i = 0; i < HID_REPORT_TYPES; i++) |
| 1767 | INIT_LIST_HEAD(&hdev->report_enum[i].report_list); | 1786 | INIT_LIST_HEAD(&hdev->report_enum[i].report_list); |
| 1768 | 1787 | ||
| 1788 | init_waitqueue_head(&hdev->debug_wait); | ||
| 1789 | INIT_LIST_HEAD(&hdev->debug_list); | ||
| 1790 | |||
| 1769 | return hdev; | 1791 | return hdev; |
| 1770 | err: | 1792 | err: |
| 1771 | put_device(&hdev->dev); | 1793 | put_device(&hdev->dev); |
| @@ -1777,6 +1799,7 @@ static void hid_remove_device(struct hid_device *hdev) | |||
| 1777 | { | 1799 | { |
| 1778 | if (hdev->status & HID_STAT_ADDED) { | 1800 | if (hdev->status & HID_STAT_ADDED) { |
| 1779 | device_del(&hdev->dev); | 1801 | device_del(&hdev->dev); |
| 1802 | hid_debug_unregister(hdev); | ||
| 1780 | hdev->status &= ~HID_STAT_ADDED; | 1803 | hdev->status &= ~HID_STAT_ADDED; |
| 1781 | } | 1804 | } |
| 1782 | } | 1805 | } |
| @@ -1852,6 +1875,10 @@ static int __init hid_init(void) | |||
| 1852 | { | 1875 | { |
| 1853 | int ret; | 1876 | int ret; |
| 1854 | 1877 | ||
| 1878 | if (hid_debug) | ||
| 1879 | printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n" | ||
| 1880 | "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n"); | ||
| 1881 | |||
| 1855 | ret = bus_register(&hid_bus_type); | 1882 | ret = bus_register(&hid_bus_type); |
| 1856 | if (ret) { | 1883 | if (ret) { |
| 1857 | printk(KERN_ERR "HID: can't register hid bus\n"); | 1884 | printk(KERN_ERR "HID: can't register hid bus\n"); |
| @@ -1862,6 +1889,8 @@ static int __init hid_init(void) | |||
| 1862 | if (ret) | 1889 | if (ret) |
| 1863 | goto err_bus; | 1890 | goto err_bus; |
| 1864 | 1891 | ||
| 1892 | hid_debug_init(); | ||
| 1893 | |||
| 1865 | return 0; | 1894 | return 0; |
| 1866 | err_bus: | 1895 | err_bus: |
| 1867 | bus_unregister(&hid_bus_type); | 1896 | bus_unregister(&hid_bus_type); |
| @@ -1871,6 +1900,7 @@ err: | |||
| 1871 | 1900 | ||
| 1872 | static void __exit hid_exit(void) | 1901 | static void __exit hid_exit(void) |
| 1873 | { | 1902 | { |
| 1903 | hid_debug_exit(); | ||
| 1874 | hidraw_exit(); | 1904 | hidraw_exit(); |
| 1875 | bus_unregister(&hid_bus_type); | 1905 | bus_unregister(&hid_bus_type); |
| 1876 | } | 1906 | } |
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 04359ed64b87..6abd0369aedb 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,17 @@ | |||
| 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> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/uaccess.h> | ||
| 33 | #include <linux/poll.h> | ||
| 34 | |||
| 29 | #include <linux/hid.h> | 35 | #include <linux/hid.h> |
| 30 | #include <linux/hid-debug.h> | 36 | #include <linux/hid-debug.h> |
| 31 | 37 | ||
| 38 | static struct dentry *hid_debug_root; | ||
| 39 | |||
| 32 | struct hid_usage_entry { | 40 | struct hid_usage_entry { |
| 33 | unsigned page; | 41 | unsigned page; |
| 34 | unsigned usage; | 42 | unsigned usage; |
| @@ -339,72 +347,120 @@ static const struct hid_usage_entry hid_usage_table[] = { | |||
| 339 | { 0, 0, NULL } | 347 | { 0, 0, NULL } |
| 340 | }; | 348 | }; |
| 341 | 349 | ||
| 342 | static void resolv_usage_page(unsigned page) { | 350 | /* Either output directly into simple seq_file, or (if f == NULL) |
| 351 | * allocate a separate buffer that will then be passed to the 'events' | ||
| 352 | * ringbuffer. | ||
| 353 | * | ||
| 354 | * This is because these functions can be called both for "one-shot" | ||
| 355 | * "rdesc" while resolving, or for blocking "events". | ||
| 356 | * | ||
| 357 | * This holds both for resolv_usage_page() and hid_resolv_usage(). | ||
| 358 | */ | ||
| 359 | static char *resolv_usage_page(unsigned page, struct seq_file *f) { | ||
| 343 | const struct hid_usage_entry *p; | 360 | const struct hid_usage_entry *p; |
| 361 | char *buf = NULL; | ||
| 362 | |||
| 363 | if (!f) { | ||
| 364 | buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); | ||
| 365 | if (!buf) | ||
| 366 | return ERR_PTR(-ENOMEM); | ||
| 367 | } | ||
| 344 | 368 | ||
| 345 | for (p = hid_usage_table; p->description; p++) | 369 | for (p = hid_usage_table; p->description; p++) |
| 346 | if (p->page == page) { | 370 | if (p->page == page) { |
| 347 | printk("%s", p->description); | 371 | if (!f) { |
| 348 | return; | 372 | snprintf(buf, HID_DEBUG_BUFSIZE, "%s", |
| 373 | p->description); | ||
| 374 | return buf; | ||
| 375 | } | ||
| 376 | else { | ||
| 377 | seq_printf(f, "%s", p->description); | ||
| 378 | return NULL; | ||
| 379 | } | ||
| 349 | } | 380 | } |
| 350 | printk("%04x", page); | 381 | if (!f) |
| 382 | snprintf(buf, HID_DEBUG_BUFSIZE, "%04x", page); | ||
| 383 | else | ||
| 384 | seq_printf(f, "%04x", page); | ||
| 385 | return buf; | ||
| 351 | } | 386 | } |
| 352 | 387 | ||
| 353 | void hid_resolv_usage(unsigned usage) { | 388 | char *hid_resolv_usage(unsigned usage, struct seq_file *f) { |
| 354 | const struct hid_usage_entry *p; | 389 | const struct hid_usage_entry *p; |
| 390 | char *buf = NULL; | ||
| 391 | int len = 0; | ||
| 392 | |||
| 393 | buf = resolv_usage_page(usage >> 16, f); | ||
| 394 | if (IS_ERR(buf)) { | ||
| 395 | printk(KERN_ERR "error allocating HID debug buffer\n"); | ||
| 396 | return NULL; | ||
| 397 | } | ||
| 355 | 398 | ||
| 356 | if (!hid_debug) | ||
| 357 | return; | ||
| 358 | 399 | ||
| 359 | resolv_usage_page(usage >> 16); | 400 | if (!f) { |
| 360 | printk("."); | 401 | len = strlen(buf); |
| 402 | snprintf(buf+len, max(0, HID_DEBUG_BUFSIZE - len), "."); | ||
| 403 | len++; | ||
| 404 | } | ||
| 405 | else { | ||
| 406 | seq_printf(f, "."); | ||
| 407 | } | ||
| 361 | for (p = hid_usage_table; p->description; p++) | 408 | for (p = hid_usage_table; p->description; p++) |
| 362 | if (p->page == (usage >> 16)) { | 409 | if (p->page == (usage >> 16)) { |
| 363 | for(++p; p->description && p->usage != 0; p++) | 410 | for(++p; p->description && p->usage != 0; p++) |
| 364 | if (p->usage == (usage & 0xffff)) { | 411 | if (p->usage == (usage & 0xffff)) { |
| 365 | printk("%s", p->description); | 412 | if (!f) |
| 366 | return; | 413 | snprintf(buf + len, |
| 414 | max(0,HID_DEBUG_BUFSIZE - len - 1), | ||
| 415 | "%s", p->description); | ||
| 416 | else | ||
| 417 | seq_printf(f, | ||
| 418 | "%s", | ||
| 419 | p->description); | ||
| 420 | return buf; | ||
| 367 | } | 421 | } |
| 368 | break; | 422 | break; |
| 369 | } | 423 | } |
| 370 | printk("%04x", usage & 0xffff); | 424 | if (!f) |
| 425 | snprintf(buf + len, max(0, HID_DEBUG_BUFSIZE - len - 1), | ||
| 426 | "%04x", usage & 0xffff); | ||
| 427 | else | ||
| 428 | seq_printf(f, "%04x", usage & 0xffff); | ||
| 429 | return buf; | ||
| 371 | } | 430 | } |
| 372 | EXPORT_SYMBOL_GPL(hid_resolv_usage); | 431 | EXPORT_SYMBOL_GPL(hid_resolv_usage); |
| 373 | 432 | ||
| 374 | static void tab(int n) { | 433 | static void tab(int n, struct seq_file *f) { |
| 375 | printk(KERN_DEBUG "%*s", n, ""); | 434 | seq_printf(f, "%*s", n, ""); |
| 376 | } | 435 | } |
| 377 | 436 | ||
| 378 | void hid_dump_field(struct hid_field *field, int n) { | 437 | void hid_dump_field(struct hid_field *field, int n, struct seq_file *f) { |
| 379 | int j; | 438 | int j; |
| 380 | 439 | ||
| 381 | if (!hid_debug) | ||
| 382 | return; | ||
| 383 | |||
| 384 | if (field->physical) { | 440 | if (field->physical) { |
| 385 | tab(n); | 441 | tab(n, f); |
| 386 | printk("Physical("); | 442 | seq_printf(f, "Physical("); |
| 387 | hid_resolv_usage(field->physical); printk(")\n"); | 443 | hid_resolv_usage(field->physical, f); seq_printf(f, ")\n"); |
| 388 | } | 444 | } |
| 389 | if (field->logical) { | 445 | if (field->logical) { |
| 390 | tab(n); | 446 | tab(n, f); |
| 391 | printk("Logical("); | 447 | seq_printf(f, "Logical("); |
| 392 | hid_resolv_usage(field->logical); printk(")\n"); | 448 | hid_resolv_usage(field->logical, f); seq_printf(f, ")\n"); |
| 393 | } | 449 | } |
| 394 | tab(n); printk("Usage(%d)\n", field->maxusage); | 450 | tab(n, f); seq_printf(f, "Usage(%d)\n", field->maxusage); |
| 395 | for (j = 0; j < field->maxusage; j++) { | 451 | for (j = 0; j < field->maxusage; j++) { |
| 396 | tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n"); | 452 | tab(n+2, f); hid_resolv_usage(field->usage[j].hid, f); seq_printf(f, "\n"); |
| 397 | } | 453 | } |
| 398 | if (field->logical_minimum != field->logical_maximum) { | 454 | if (field->logical_minimum != field->logical_maximum) { |
| 399 | tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); | 455 | tab(n, f); seq_printf(f, "Logical Minimum(%d)\n", field->logical_minimum); |
| 400 | tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); | 456 | tab(n, f); seq_printf(f, "Logical Maximum(%d)\n", field->logical_maximum); |
| 401 | } | 457 | } |
| 402 | if (field->physical_minimum != field->physical_maximum) { | 458 | if (field->physical_minimum != field->physical_maximum) { |
| 403 | tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); | 459 | tab(n, f); seq_printf(f, "Physical Minimum(%d)\n", field->physical_minimum); |
| 404 | tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); | 460 | tab(n, f); seq_printf(f, "Physical Maximum(%d)\n", field->physical_maximum); |
| 405 | } | 461 | } |
| 406 | if (field->unit_exponent) { | 462 | if (field->unit_exponent) { |
| 407 | tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); | 463 | tab(n, f); seq_printf(f, "Unit Exponent(%d)\n", field->unit_exponent); |
| 408 | } | 464 | } |
| 409 | if (field->unit) { | 465 | if (field->unit) { |
| 410 | static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; | 466 | static const char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; |
| @@ -425,77 +481,75 @@ void hid_dump_field(struct hid_field *field, int n) { | |||
| 425 | data >>= 4; | 481 | data >>= 4; |
| 426 | 482 | ||
| 427 | if(sys > 4) { | 483 | if(sys > 4) { |
| 428 | tab(n); printk("Unit(Invalid)\n"); | 484 | tab(n, f); seq_printf(f, "Unit(Invalid)\n"); |
| 429 | } | 485 | } |
| 430 | else { | 486 | else { |
| 431 | int earlier_unit = 0; | 487 | int earlier_unit = 0; |
| 432 | 488 | ||
| 433 | tab(n); printk("Unit(%s : ", systems[sys]); | 489 | tab(n, f); seq_printf(f, "Unit(%s : ", systems[sys]); |
| 434 | 490 | ||
| 435 | for (i=1 ; i<sizeof(__u32)*2 ; i++) { | 491 | for (i=1 ; i<sizeof(__u32)*2 ; i++) { |
| 436 | char nibble = data & 0xf; | 492 | char nibble = data & 0xf; |
| 437 | data >>= 4; | 493 | data >>= 4; |
| 438 | if (nibble != 0) { | 494 | if (nibble != 0) { |
| 439 | if(earlier_unit++ > 0) | 495 | if(earlier_unit++ > 0) |
| 440 | printk("*"); | 496 | seq_printf(f, "*"); |
| 441 | printk("%s", units[sys][i]); | 497 | seq_printf(f, "%s", units[sys][i]); |
| 442 | if(nibble != 1) { | 498 | if(nibble != 1) { |
| 443 | /* This is a _signed_ nibble(!) */ | 499 | /* This is a _signed_ nibble(!) */ |
| 444 | 500 | ||
| 445 | int val = nibble & 0x7; | 501 | int val = nibble & 0x7; |
| 446 | if(nibble & 0x08) | 502 | if(nibble & 0x08) |
| 447 | val = -((0x7 & ~val) +1); | 503 | val = -((0x7 & ~val) +1); |
| 448 | printk("^%d", val); | 504 | seq_printf(f, "^%d", val); |
| 449 | } | 505 | } |
| 450 | } | 506 | } |
| 451 | } | 507 | } |
| 452 | printk(")\n"); | 508 | seq_printf(f, ")\n"); |
| 453 | } | 509 | } |
| 454 | } | 510 | } |
| 455 | tab(n); printk("Report Size(%u)\n", field->report_size); | 511 | tab(n, f); seq_printf(f, "Report Size(%u)\n", field->report_size); |
| 456 | tab(n); printk("Report Count(%u)\n", field->report_count); | 512 | tab(n, f); seq_printf(f, "Report Count(%u)\n", field->report_count); |
| 457 | tab(n); printk("Report Offset(%u)\n", field->report_offset); | 513 | tab(n, f); seq_printf(f, "Report Offset(%u)\n", field->report_offset); |
| 458 | 514 | ||
| 459 | tab(n); printk("Flags( "); | 515 | tab(n, f); seq_printf(f, "Flags( "); |
| 460 | j = field->flags; | 516 | j = field->flags; |
| 461 | printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); | 517 | seq_printf(f, "%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); |
| 462 | printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); | 518 | seq_printf(f, "%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); |
| 463 | printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); | 519 | seq_printf(f, "%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); |
| 464 | printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); | 520 | seq_printf(f, "%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); |
| 465 | printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); | 521 | seq_printf(f, "%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); |
| 466 | printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : ""); | 522 | seq_printf(f, "%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPreferredState " : ""); |
| 467 | printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); | 523 | seq_printf(f, "%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); |
| 468 | printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); | 524 | seq_printf(f, "%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); |
| 469 | printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); | 525 | seq_printf(f, "%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); |
| 470 | printk(")\n"); | 526 | seq_printf(f, ")\n"); |
| 471 | } | 527 | } |
| 472 | EXPORT_SYMBOL_GPL(hid_dump_field); | 528 | EXPORT_SYMBOL_GPL(hid_dump_field); |
| 473 | 529 | ||
| 474 | void hid_dump_device(struct hid_device *device) { | 530 | void hid_dump_device(struct hid_device *device, struct seq_file *f) |
| 531 | { | ||
| 475 | struct hid_report_enum *report_enum; | 532 | struct hid_report_enum *report_enum; |
| 476 | struct hid_report *report; | 533 | struct hid_report *report; |
| 477 | struct list_head *list; | 534 | struct list_head *list; |
| 478 | unsigned i,k; | 535 | unsigned i,k; |
| 479 | static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; | 536 | static const char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; |
| 480 | 537 | ||
| 481 | if (!hid_debug) | ||
| 482 | return; | ||
| 483 | |||
| 484 | for (i = 0; i < HID_REPORT_TYPES; i++) { | 538 | for (i = 0; i < HID_REPORT_TYPES; i++) { |
| 485 | report_enum = device->report_enum + i; | 539 | report_enum = device->report_enum + i; |
| 486 | list = report_enum->report_list.next; | 540 | list = report_enum->report_list.next; |
| 487 | while (list != &report_enum->report_list) { | 541 | while (list != &report_enum->report_list) { |
| 488 | report = (struct hid_report *) list; | 542 | report = (struct hid_report *) list; |
| 489 | tab(2); | 543 | tab(2, f); |
| 490 | printk("%s", table[i]); | 544 | seq_printf(f, "%s", table[i]); |
| 491 | if (report->id) | 545 | if (report->id) |
| 492 | printk("(%d)", report->id); | 546 | seq_printf(f, "(%d)", report->id); |
| 493 | printk("[%s]", table[report->type]); | 547 | seq_printf(f, "[%s]", table[report->type]); |
| 494 | printk("\n"); | 548 | seq_printf(f, "\n"); |
| 495 | for (k = 0; k < report->maxfield; k++) { | 549 | for (k = 0; k < report->maxfield; k++) { |
| 496 | tab(4); | 550 | tab(4, f); |
| 497 | printk("Field(%d)\n", k); | 551 | seq_printf(f, "Field(%d)\n", k); |
| 498 | hid_dump_field(report->field[k], 6); | 552 | hid_dump_field(report->field[k], 6, f); |
| 499 | } | 553 | } |
| 500 | list = list->next; | 554 | list = list->next; |
| 501 | } | 555 | } |
| @@ -503,13 +557,37 @@ void hid_dump_device(struct hid_device *device) { | |||
| 503 | } | 557 | } |
| 504 | EXPORT_SYMBOL_GPL(hid_dump_device); | 558 | EXPORT_SYMBOL_GPL(hid_dump_device); |
| 505 | 559 | ||
| 506 | void hid_dump_input(struct hid_usage *usage, __s32 value) { | 560 | /* enqueue string to 'events' ring buffer */ |
| 507 | if (hid_debug < 2) | 561 | void hid_debug_event(struct hid_device *hdev, char *buf) |
| 562 | { | ||
| 563 | int i; | ||
| 564 | struct hid_debug_list *list; | ||
| 565 | |||
| 566 | list_for_each_entry(list, &hdev->debug_list, node) { | ||
| 567 | for (i = 0; i <= strlen(buf); i++) | ||
| 568 | list->hid_debug_buf[(list->tail + i) % (HID_DEBUG_BUFSIZE - 1)] = | ||
| 569 | buf[i]; | ||
| 570 | list->tail = (list->tail + i) % (HID_DEBUG_BUFSIZE - 1); | ||
| 571 | } | ||
| 572 | } | ||
| 573 | EXPORT_SYMBOL_GPL(hid_debug_event); | ||
| 574 | |||
| 575 | void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value) | ||
| 576 | { | ||
| 577 | char *buf; | ||
| 578 | int len; | ||
| 579 | |||
| 580 | buf = hid_resolv_usage(usage->hid, NULL); | ||
| 581 | if (!buf) | ||
| 508 | return; | 582 | return; |
| 583 | len = strlen(buf); | ||
| 584 | snprintf(buf + len, HID_DEBUG_BUFSIZE - len - 1, " = %d\n", value); | ||
| 585 | |||
| 586 | hid_debug_event(hdev, buf); | ||
| 587 | |||
| 588 | kfree(buf); | ||
| 589 | wake_up_interruptible(&hdev->debug_wait); | ||
| 509 | 590 | ||
| 510 | printk(KERN_DEBUG "hid-debug: input "); | ||
| 511 | hid_resolv_usage(usage->hid); | ||
| 512 | printk(" = %d\n", value); | ||
| 513 | } | 591 | } |
| 514 | EXPORT_SYMBOL_GPL(hid_dump_input); | 592 | EXPORT_SYMBOL_GPL(hid_dump_input); |
| 515 | 593 | ||
| @@ -786,12 +864,221 @@ static const char **names[EV_MAX + 1] = { | |||
| 786 | [EV_SND] = sounds, [EV_REP] = repeats, | 864 | [EV_SND] = sounds, [EV_REP] = repeats, |
| 787 | }; | 865 | }; |
| 788 | 866 | ||
| 789 | void hid_resolv_event(__u8 type, __u16 code) { | 867 | void hid_resolv_event(__u8 type, __u16 code, struct seq_file *f) { |
| 790 | 868 | ||
| 791 | if (!hid_debug) | 869 | seq_printf(f, "%s.%s", events[type] ? events[type] : "?", |
| 792 | return; | ||
| 793 | |||
| 794 | printk("%s.%s", events[type] ? events[type] : "?", | ||
| 795 | names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); | 870 | names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); |
| 796 | } | 871 | } |
| 797 | EXPORT_SYMBOL_GPL(hid_resolv_event); | 872 | |
| 873 | void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f) | ||
| 874 | { | ||
| 875 | int i, j, k; | ||
| 876 | struct hid_report *report; | ||
| 877 | struct hid_usage *usage; | ||
| 878 | |||
| 879 | for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { | ||
| 880 | list_for_each_entry(report, &hid->report_enum[k].report_list, list) { | ||
| 881 | for (i = 0; i < report->maxfield; i++) { | ||
| 882 | for ( j = 0; j < report->field[i]->maxusage; j++) { | ||
| 883 | usage = report->field[i]->usage + j; | ||
| 884 | hid_resolv_usage(usage->hid, f); | ||
| 885 | seq_printf(f, " ---> "); | ||
| 886 | hid_resolv_event(usage->type, usage->code, f); | ||
| 887 | seq_printf(f, "\n"); | ||
| 888 | } | ||
| 889 | } | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 893 | } | ||
| 894 | |||
| 895 | |||
| 896 | static int hid_debug_rdesc_show(struct seq_file *f, void *p) | ||
| 897 | { | ||
| 898 | struct hid_device *hdev = f->private; | ||
| 899 | int i; | ||
| 900 | |||
| 901 | /* dump HID report descriptor */ | ||
| 902 | for (i = 0; i < hdev->rsize; i++) | ||
| 903 | seq_printf(f, "%02x ", hdev->rdesc[i]); | ||
| 904 | seq_printf(f, "\n\n"); | ||
| 905 | |||
| 906 | /* dump parsed data and input mappings */ | ||
| 907 | hid_dump_device(hdev, f); | ||
| 908 | seq_printf(f, "\n"); | ||
| 909 | hid_dump_input_mapping(hdev, f); | ||
| 910 | |||
| 911 | return 0; | ||
| 912 | } | ||
| 913 | |||
| 914 | static int hid_debug_rdesc_open(struct inode *inode, struct file *file) | ||
| 915 | { | ||
| 916 | return single_open(file, hid_debug_rdesc_show, inode->i_private); | ||
| 917 | } | ||
| 918 | |||
| 919 | static int hid_debug_events_open(struct inode *inode, struct file *file) | ||
| 920 | { | ||
| 921 | int err = 0; | ||
| 922 | struct hid_debug_list *list; | ||
| 923 | |||
| 924 | if (!(list = kzalloc(sizeof(struct hid_debug_list), GFP_KERNEL))) { | ||
| 925 | err = -ENOMEM; | ||
| 926 | goto out; | ||
| 927 | } | ||
| 928 | |||
| 929 | if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) { | ||
| 930 | err = -ENOMEM; | ||
| 931 | kfree(list); | ||
| 932 | goto out; | ||
| 933 | } | ||
| 934 | list->hdev = (struct hid_device *) inode->i_private; | ||
| 935 | file->private_data = list; | ||
| 936 | mutex_init(&list->read_mutex); | ||
| 937 | |||
| 938 | list_add_tail(&list->node, &list->hdev->debug_list); | ||
| 939 | |||
| 940 | out: | ||
| 941 | return err; | ||
| 942 | } | ||
| 943 | |||
| 944 | static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, | ||
| 945 | size_t count, loff_t *ppos) | ||
| 946 | { | ||
| 947 | struct hid_debug_list *list = file->private_data; | ||
| 948 | int ret = 0, len; | ||
| 949 | DECLARE_WAITQUEUE(wait, current); | ||
| 950 | |||
| 951 | while (ret == 0) { | ||
| 952 | mutex_lock(&list->read_mutex); | ||
| 953 | if (list->head == list->tail) { | ||
| 954 | add_wait_queue(&list->hdev->debug_wait, &wait); | ||
| 955 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 956 | |||
| 957 | while (list->head == list->tail) { | ||
| 958 | if (file->f_flags & O_NONBLOCK) { | ||
| 959 | ret = -EAGAIN; | ||
| 960 | break; | ||
| 961 | } | ||
| 962 | if (signal_pending(current)) { | ||
| 963 | ret = -ERESTARTSYS; | ||
| 964 | break; | ||
| 965 | } | ||
| 966 | |||
| 967 | if (!list->hdev || !list->hdev->debug) { | ||
| 968 | ret = -EIO; | ||
| 969 | break; | ||
| 970 | } | ||
| 971 | |||
| 972 | /* allow O_NONBLOCK from other threads */ | ||
| 973 | mutex_unlock(&list->read_mutex); | ||
| 974 | schedule(); | ||
| 975 | mutex_lock(&list->read_mutex); | ||
| 976 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 977 | } | ||
| 978 | |||
| 979 | set_current_state(TASK_RUNNING); | ||
| 980 | remove_wait_queue(&list->hdev->debug_wait, &wait); | ||
| 981 | } | ||
| 982 | |||
| 983 | if (ret) | ||
| 984 | goto out; | ||
| 985 | |||
| 986 | /* pass the ringbuffer contents to userspace */ | ||
| 987 | copy_rest: | ||
| 988 | if (list->tail == list->head) | ||
| 989 | goto out; | ||
| 990 | if (list->tail > list->head) { | ||
| 991 | len = list->tail - list->head; | ||
| 992 | |||
| 993 | if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { | ||
| 994 | ret = -EFAULT; | ||
| 995 | goto out; | ||
| 996 | } | ||
| 997 | ret += len; | ||
| 998 | list->head += len; | ||
| 999 | } else { | ||
| 1000 | len = HID_DEBUG_BUFSIZE - list->head; | ||
| 1001 | |||
| 1002 | if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { | ||
| 1003 | ret = -EFAULT; | ||
| 1004 | goto out; | ||
| 1005 | } | ||
| 1006 | list->head = 0; | ||
| 1007 | ret += len; | ||
| 1008 | goto copy_rest; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | } | ||
| 1012 | out: | ||
| 1013 | mutex_unlock(&list->read_mutex); | ||
| 1014 | return ret; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | static unsigned int hid_debug_events_poll(struct file *file, poll_table *wait) | ||
| 1018 | { | ||
| 1019 | struct hid_debug_list *list = file->private_data; | ||
| 1020 | |||
| 1021 | poll_wait(file, &list->hdev->debug_wait, wait); | ||
| 1022 | if (list->head != list->tail) | ||
| 1023 | return POLLIN | POLLRDNORM; | ||
| 1024 | if (!list->hdev->debug) | ||
| 1025 | return POLLERR | POLLHUP; | ||
| 1026 | return 0; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | static int hid_debug_events_release(struct inode *inode, struct file *file) | ||
| 1030 | { | ||
| 1031 | struct hid_debug_list *list = file->private_data; | ||
| 1032 | |||
| 1033 | list_del(&list->node); | ||
| 1034 | kfree(list->hid_debug_buf); | ||
| 1035 | kfree(list); | ||
| 1036 | |||
| 1037 | return 0; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | static const struct file_operations hid_debug_rdesc_fops = { | ||
| 1041 | .open = hid_debug_rdesc_open, | ||
| 1042 | .read = seq_read, | ||
| 1043 | .llseek = seq_lseek, | ||
| 1044 | .release = single_release, | ||
| 1045 | }; | ||
| 1046 | |||
| 1047 | static const struct file_operations hid_debug_events_fops = { | ||
| 1048 | .owner = THIS_MODULE, | ||
| 1049 | .open = hid_debug_events_open, | ||
| 1050 | .read = hid_debug_events_read, | ||
| 1051 | .poll = hid_debug_events_poll, | ||
| 1052 | .release = hid_debug_events_release, | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | |||
| 1056 | void hid_debug_register(struct hid_device *hdev, const char *name) | ||
| 1057 | { | ||
| 1058 | hdev->debug_dir = debugfs_create_dir(name, hid_debug_root); | ||
| 1059 | hdev->debug_rdesc = debugfs_create_file("rdesc", 0400, | ||
| 1060 | hdev->debug_dir, hdev, &hid_debug_rdesc_fops); | ||
| 1061 | hdev->debug_events = debugfs_create_file("events", 0400, | ||
| 1062 | hdev->debug_dir, hdev, &hid_debug_events_fops); | ||
| 1063 | hdev->debug = 1; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | void hid_debug_unregister(struct hid_device *hdev) | ||
| 1067 | { | ||
| 1068 | hdev->debug = 0; | ||
| 1069 | wake_up_interruptible(&hdev->debug_wait); | ||
| 1070 | debugfs_remove(hdev->debug_rdesc); | ||
| 1071 | debugfs_remove(hdev->debug_events); | ||
| 1072 | debugfs_remove(hdev->debug_dir); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | void hid_debug_init(void) | ||
| 1076 | { | ||
| 1077 | hid_debug_root = debugfs_create_dir("hid", NULL); | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | void hid_debug_exit(void) | ||
| 1081 | { | ||
| 1082 | debugfs_remove_recursive(hid_debug_root); | ||
| 1083 | } | ||
| 1084 | |||
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 7f183b7147e1..5862b0f3b55d 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c | |||
| @@ -159,17 +159,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel | |||
| 159 | 159 | ||
| 160 | field->hidinput = hidinput; | 160 | field->hidinput = hidinput; |
| 161 | 161 | ||
| 162 | dbg_hid("Mapping: "); | ||
| 163 | hid_resolv_usage(usage->hid); | ||
| 164 | dbg_hid_line(" ---> "); | ||
| 165 | |||
| 166 | if (field->flags & HID_MAIN_ITEM_CONSTANT) | 162 | if (field->flags & HID_MAIN_ITEM_CONSTANT) |
| 167 | goto ignore; | 163 | goto ignore; |
| 168 | 164 | ||
| 169 | /* only LED usages are supported in output fields */ | 165 | /* only LED usages are supported in output fields */ |
| 170 | if (field->report_type == HID_OUTPUT_REPORT && | 166 | if (field->report_type == HID_OUTPUT_REPORT && |
| 171 | (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { | 167 | (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { |
| 172 | dbg_hid_line(" [non-LED output field] "); | ||
| 173 | goto ignore; | 168 | goto ignore; |
| 174 | } | 169 | } |
| 175 | 170 | ||
| @@ -561,15 +556,9 @@ mapped: | |||
| 561 | set_bit(MSC_SCAN, input->mscbit); | 556 | set_bit(MSC_SCAN, input->mscbit); |
| 562 | } | 557 | } |
| 563 | 558 | ||
| 564 | hid_resolv_event(usage->type, usage->code); | ||
| 565 | |||
| 566 | dbg_hid_line("\n"); | ||
| 567 | |||
| 568 | return; | ||
| 569 | |||
| 570 | ignore: | 559 | ignore: |
| 571 | dbg_hid_line("IGNORED\n"); | ||
| 572 | return; | 560 | return; |
| 561 | |||
| 573 | } | 562 | } |
| 574 | 563 | ||
| 575 | void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) | 564 | void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) |
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 25f38a5af269..1b0e07a67d6d 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
| @@ -4,8 +4,8 @@ | |||
| 4 | * Copyright (c) 1999 Andreas Gal | 4 | * Copyright (c) 1999 Andreas Gal |
| 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> | 5 | * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> |
| 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc | 6 | * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc |
| 7 | * Copyright (c) 2006-2008 Jiri Kosina | ||
| 8 | * Copyright (c) 2007-2008 Oliver Neukum | 7 | * Copyright (c) 2007-2008 Oliver Neukum |
| 8 | * Copyright (c) 2006-2009 Jiri Kosina | ||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* | 11 | /* |
| @@ -886,11 +886,6 @@ static int usbhid_parse(struct hid_device *hid) | |||
| 886 | goto err; | 886 | goto err; |
| 887 | } | 887 | } |
| 888 | 888 | ||
| 889 | dbg_hid("report descriptor (size %u, read %d) = ", rsize, n); | ||
| 890 | for (n = 0; n < rsize; n++) | ||
| 891 | dbg_hid_line(" %02x", (unsigned char) rdesc[n]); | ||
| 892 | dbg_hid_line("\n"); | ||
| 893 | |||
| 894 | ret = hid_parse_report(hid, rdesc, rsize); | 889 | ret = hid_parse_report(hid, rdesc, rsize); |
| 895 | kfree(rdesc); | 890 | kfree(rdesc); |
| 896 | if (ret) { | 891 | if (ret) { |
| @@ -1004,7 +999,6 @@ static int usbhid_start(struct hid_device *hid) | |||
| 1004 | usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); | 999 | usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); |
| 1005 | 1000 | ||
| 1006 | usbhid_init_reports(hid); | 1001 | usbhid_init_reports(hid); |
| 1007 | hid_dump_device(hid); | ||
| 1008 | 1002 | ||
| 1009 | set_bit(HID_STARTED, &usbhid->iofl); | 1003 | set_bit(HID_STARTED, &usbhid->iofl); |
| 1010 | 1004 | ||
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index d8f7423f363e..0d9045aa2c4b 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c | |||
| @@ -201,7 +201,7 @@ int usbhid_quirks_init(char **quirks_param) | |||
| 201 | u32 quirks; | 201 | u32 quirks; |
| 202 | int n = 0, m; | 202 | int n = 0, m; |
| 203 | 203 | ||
| 204 | for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) { | 204 | for (; n < MAX_USBHID_BOOT_QUIRKS && quirks_param[n]; n++) { |
| 205 | 205 | ||
| 206 | m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", | 206 | m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x", |
| 207 | &idVendor, &idProduct, &quirks); | 207 | &idVendor, &idProduct, &quirks); |
diff --git a/include/linux/hid-debug.h b/include/linux/hid-debug.h index 50d568ec178a..53744fa1c8b7 100644 --- a/include/linux/hid-debug.h +++ b/include/linux/hid-debug.h | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | #define __HID_DEBUG_H | 2 | #define __HID_DEBUG_H |
| 3 | 3 | ||
| 4 | /* | 4 | /* |
| 5 | * Copyright (c) 2007 Jiri Kosina | 5 | * Copyright (c) 2007-2009 Jiri Kosina |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | /* | 8 | /* |
| @@ -22,24 +22,44 @@ | |||
| 22 | * | 22 | * |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #ifdef CONFIG_HID_DEBUG | 25 | #define HID_DEBUG_BUFSIZE 512 |
| 26 | 26 | ||
| 27 | void hid_dump_input(struct hid_usage *, __s32); | 27 | #ifdef CONFIG_DEBUG_FS |
| 28 | void hid_dump_device(struct hid_device *); | 28 | |
| 29 | void hid_dump_field(struct hid_field *, int); | 29 | void hid_dump_input(struct hid_device *, struct hid_usage *, __s32); |
| 30 | void hid_resolv_usage(unsigned); | 30 | void hid_dump_device(struct hid_device *, struct seq_file *); |
| 31 | void hid_resolv_event(__u8, __u16); | 31 | void hid_dump_field(struct hid_field *, int, struct seq_file *); |
| 32 | char *hid_resolv_usage(unsigned, struct seq_file *); | ||
| 33 | void hid_debug_register(struct hid_device *, const char *); | ||
| 34 | void hid_debug_unregister(struct hid_device *); | ||
| 35 | void hid_debug_init(void); | ||
| 36 | void hid_debug_exit(void); | ||
| 37 | void hid_debug_event(struct hid_device *, char *); | ||
| 32 | 38 | ||
| 33 | #else | ||
| 34 | 39 | ||
| 35 | #define hid_dump_input(a,b) do { } while (0) | 40 | struct hid_debug_list { |
| 36 | #define hid_dump_device(c) do { } while (0) | 41 | char *hid_debug_buf; |
| 37 | #define hid_dump_field(a,b) do { } while (0) | 42 | int head; |
| 38 | #define hid_resolv_usage(a) do { } while (0) | 43 | int tail; |
| 39 | #define hid_resolv_event(a,b) do { } while (0) | 44 | struct fasync_struct *fasync; |
| 45 | struct hid_device *hdev; | ||
| 46 | struct list_head node; | ||
| 47 | struct mutex read_mutex; | ||
| 48 | }; | ||
| 40 | 49 | ||
| 41 | #endif /* CONFIG_HID_DEBUG */ | 50 | #else |
| 42 | 51 | ||
| 52 | #define hid_dump_input(a,b,c) do { } while (0) | ||
| 53 | #define hid_dump_device(a,b) do { } while (0) | ||
| 54 | #define hid_dump_field(a,b,c) do { } while (0) | ||
| 55 | #define hid_resolv_usage(a,b) do { } while (0) | ||
| 56 | #define hid_debug_register(a, b) do { } while (0) | ||
| 57 | #define hid_debug_unregister(a) do { } while (0) | ||
| 58 | #define hid_debug_init() do { } while (0) | ||
| 59 | #define hid_debug_exit() do { } while (0) | ||
| 60 | #define hid_debug_event(a,b) do { } while (0) | ||
| 61 | |||
| 62 | #endif | ||
| 43 | 63 | ||
| 44 | #endif | 64 | #endif |
| 45 | 65 | ||
diff --git a/include/linux/hid.h b/include/linux/hid.h index 53489fd4d700..a0ebdace7baa 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
| @@ -500,6 +500,14 @@ struct hid_device { /* device report descriptor */ | |||
| 500 | 500 | ||
| 501 | /* handler for raw output data, used by hidraw */ | 501 | /* handler for raw output data, used by hidraw */ |
| 502 | int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t); | 502 | int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t); |
| 503 | |||
| 504 | /* debugging support via debugfs */ | ||
| 505 | unsigned short debug; | ||
| 506 | struct dentry *debug_dir; | ||
| 507 | struct dentry *debug_rdesc; | ||
| 508 | struct dentry *debug_events; | ||
| 509 | struct list_head debug_list; | ||
| 510 | wait_queue_head_t debug_wait; | ||
| 503 | }; | 511 | }; |
| 504 | 512 | ||
| 505 | static inline void *hid_get_drvdata(struct hid_device *hdev) | 513 | static inline void *hid_get_drvdata(struct hid_device *hdev) |
| @@ -657,9 +665,7 @@ struct hid_ll_driver { | |||
| 657 | 665 | ||
| 658 | /* HID core API */ | 666 | /* HID core API */ |
| 659 | 667 | ||
| 660 | #ifdef CONFIG_HID_DEBUG | ||
| 661 | extern int hid_debug; | 668 | extern int hid_debug; |
| 662 | #endif | ||
| 663 | 669 | ||
| 664 | extern int hid_add_device(struct hid_device *); | 670 | extern int hid_add_device(struct hid_device *); |
| 665 | extern void hid_destroy_device(struct hid_device *); | 671 | extern void hid_destroy_device(struct hid_device *); |
| @@ -815,21 +821,9 @@ int hid_pidff_init(struct hid_device *hid); | |||
| 815 | #define hid_pidff_init NULL | 821 | #define hid_pidff_init NULL |
| 816 | #endif | 822 | #endif |
| 817 | 823 | ||
| 818 | #ifdef CONFIG_HID_DEBUG | ||
| 819 | #define dbg_hid(format, arg...) if (hid_debug) \ | 824 | #define dbg_hid(format, arg...) if (hid_debug) \ |
| 820 | printk(KERN_DEBUG "%s: " format ,\ | 825 | printk(KERN_DEBUG "%s: " format ,\ |
| 821 | __FILE__ , ## arg) | 826 | __FILE__ , ## arg) |
| 822 | #define dbg_hid_line(format, arg...) if (hid_debug) \ | ||
| 823 | printk(format, ## arg) | ||
| 824 | #else | ||
| 825 | static inline int __attribute__((format(printf, 1, 2))) | ||
| 826 | dbg_hid(const char *fmt, ...) | ||
| 827 | { | ||
| 828 | return 0; | ||
| 829 | } | ||
| 830 | #define dbg_hid_line dbg_hid | ||
| 831 | #endif /* HID_DEBUG */ | ||
| 832 | |||
| 833 | #define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ | 827 | #define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \ |
| 834 | __FILE__ , ## arg) | 828 | __FILE__ , ## arg) |
| 835 | #endif /* HID_FF */ | 829 | #endif /* HID_FF */ |
