diff options
Diffstat (limited to 'drivers/hid')
-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 |
7 files changed, 413 insertions, 125 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); |