aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2009-06-12 09:20:57 -0400
committerJiri Kosina <jkosina@suse.cz>2009-06-12 09:20:57 -0400
commitcd667ce24796700e1a0e6e7528efc61c96ff832e (patch)
tree6279001dbecb476588873402668aa761ee2f4a8f /drivers/hid
parenta635f9dd83f3382577f4544a96df12356e951a40 (diff)
HID: use debugfs for events/reports dumping
This is a followup patch to the one implemeting rdesc representation in debugfs rather than being dependent on compile-time CONFIG_HID_DEBUG setting. The API of the appropriate formatting functions is slightly modified -- if they are passed seq_file pointer, the one-shot output for 'rdesc' file mode is used, and therefore the message is formatted into the corresponding seq_file immediately. Otherwise the called function allocated a new buffer, formats the text into the buffer and returns the pointer to it, so that it can be queued into the ring-buffer of the processess blocked waiting on input on 'events' file in debugfs. 'debug' parameter to the 'hid' module is now used solely for the prupose of inetrnal driver state debugging (parser, transport, etc). Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/hid-core.c42
-rw-r--r--drivers/hid/hid-debug.c239
2 files changed, 252 insertions, 29 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index d4317db85b54..449bd747d116 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -46,7 +46,7 @@
46 46
47int hid_debug = 0; 47int hid_debug = 0;
48module_param_named(debug, hid_debug, int, 0600); 48module_param_named(debug, hid_debug, int, 0600);
49MODULE_PARM_DESC(debug, "HID debugging (0=off, 1=probing info, 2=continuous data dumping)"); 49MODULE_PARM_DESC(debug, "toggle HID debugging messages");
50EXPORT_SYMBOL_GPL(hid_debug); 50EXPORT_SYMBOL_GPL(hid_debug);
51 51
52/* 52/*
@@ -859,7 +859,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
859 struct hid_driver *hdrv = hid->driver; 859 struct hid_driver *hdrv = hid->driver;
860 int ret; 860 int ret;
861 861
862 hid_dump_input(usage, value); 862 hid_dump_input(hid, usage, value);
863 863
864 if (hdrv && hdrv->event && hid_match_usage(hid, usage)) { 864 if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
865 ret = hdrv->event(hid, field, usage, value); 865 ret = hdrv->event(hid, field, usage, value);
@@ -981,7 +981,7 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
981{ 981{
982 unsigned size = field->report_size; 982 unsigned size = field->report_size;
983 983
984 hid_dump_input(field->usage + offset, value); 984 hid_dump_input(field->report->device, field->usage + offset, value);
985 985
986 if (offset >= field->report_count) { 986 if (offset >= field->report_count) {
987 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);
@@ -1075,6 +1075,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
1075 struct hid_report_enum *report_enum = hid->report_enum + type; 1075 struct hid_report_enum *report_enum = hid->report_enum + type;
1076 struct hid_driver *hdrv = hid->driver; 1076 struct hid_driver *hdrv = hid->driver;
1077 struct hid_report *report; 1077 struct hid_report *report;
1078 char *buf;
1078 unsigned int i; 1079 unsigned int i;
1079 int ret; 1080 int ret;
1080 1081
@@ -1086,18 +1087,36 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
1086 return -1; 1087 return -1;
1087 } 1088 }
1088 1089
1089 dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); 1090 buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE,
1091 interrupt ? GFP_ATOMIC : GFP_KERNEL);
1092
1093 if (!buf) {
1094 report = hid_get_report(report_enum, data);
1095 goto nomem;
1096 }
1097
1098 snprintf(buf, HID_DEBUG_BUFSIZE - 1,
1099 "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
1100 hid_debug_event(hid, buf);
1090 1101
1091 report = hid_get_report(report_enum, data); 1102 report = hid_get_report(report_enum, data);
1092 if (!report) 1103 if (!report)
1093 return -1; 1104 return -1;
1094 1105
1095 /* dump the report */ 1106 /* dump the report */
1096 dbg_hid("report %d (size %u) = ", report->id, size); 1107 snprintf(buf, HID_DEBUG_BUFSIZE - 1,
1097 for (i = 0; i < size; i++) 1108 "report %d (size %u) = ", report->id, size);
1098 dbg_hid_line(" %02x", data[i]); 1109 hid_debug_event(hid, buf);
1099 dbg_hid_line("\n"); 1110 for (i = 0; i < size; i++) {
1111 snprintf(buf, HID_DEBUG_BUFSIZE - 1,
1112 " %02x", data[i]);
1113 hid_debug_event(hid, buf);
1114 }
1115 hid_debug_event(hid, "\n");
1116
1117 kfree(buf);
1100 1118
1119nomem:
1101 if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { 1120 if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
1102 ret = hdrv->raw_event(hid, report, data, size); 1121 ret = hdrv->raw_event(hid, report, data, size);
1103 if (ret != 0) 1122 if (ret != 0)
@@ -1756,6 +1775,9 @@ struct hid_device *hid_allocate_device(void)
1756 for (i = 0; i < HID_REPORT_TYPES; i++) 1775 for (i = 0; i < HID_REPORT_TYPES; i++)
1757 INIT_LIST_HEAD(&hdev->report_enum[i].report_list); 1776 INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
1758 1777
1778 init_waitqueue_head(&hdev->debug_wait);
1779 INIT_LIST_HEAD(&hdev->debug_list);
1780
1759 return hdev; 1781 return hdev;
1760err: 1782err:
1761 put_device(&hdev->dev); 1783 put_device(&hdev->dev);
@@ -1844,8 +1866,8 @@ static int __init hid_init(void)
1844 int ret; 1866 int ret;
1845 1867
1846 if (hid_debug) 1868 if (hid_debug)
1847 printk(KERN_WARNING "HID: hid_debug parameter has been deprecated. " 1869 printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n"
1848 "Debugging data are now provided via debugfs\n"); 1870 "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n");
1849 1871
1850 ret = bus_register(&hid_bus_type); 1872 ret = bus_register(&hid_bus_type);
1851 if (ret) { 1873 if (ret) {
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 067e173aa3e4..a331a1821e85 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -28,6 +28,10 @@
28 28
29#include <linux/debugfs.h> 29#include <linux/debugfs.h>
30#include <linux/seq_file.h> 30#include <linux/seq_file.h>
31#include <linux/sched.h>
32#include <linux/uaccess.h>
33#include <linux/poll.h>
34
31#include <linux/hid.h> 35#include <linux/hid.h>
32#include <linux/hid-debug.h> 36#include <linux/hid-debug.h>
33 37
@@ -335,49 +339,86 @@ static const struct hid_usage_entry hid_usage_table[] = {
335 { 0, 0, NULL } 339 { 0, 0, NULL }
336}; 340};
337 341
338static void resolv_usage_page(unsigned page, struct seq_file *f) { 342/* Either output directly into simple seq_file, or (if f == NULL)
343 * allocate a separate buffer that will then be passed to the 'events'
344 * ringbuffer.
345 *
346 * This is because these functions can be called both for "one-shot"
347 * "rdesc" while resolving, or for blocking "events".
348 *
349 * This holds both for resolv_usage_page() and hid_resolv_usage().
350 */
351static char *resolv_usage_page(unsigned page, struct seq_file *f) {
339 const struct hid_usage_entry *p; 352 const struct hid_usage_entry *p;
353 char *buf = NULL;
354
355 if (!f) {
356 buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
357 if (!buf)
358 return ERR_PTR(-ENOMEM);
359 }
340 360
341 for (p = hid_usage_table; p->description; p++) 361 for (p = hid_usage_table; p->description; p++)
342 if (p->page == page) { 362 if (p->page == page) {
343 if (!f) 363 if (!f) {
344 printk("%s", p->description); 364 snprintf(buf, HID_DEBUG_BUFSIZE, "%s",
345 else 365 p->description);
366 return buf;
367 }
368 else {
346 seq_printf(f, "%s", p->description); 369 seq_printf(f, "%s", p->description);
347 return; 370 return NULL;
371 }
348 } 372 }
349 if (!f) 373 if (!f)
350 printk("%04x", page); 374 snprintf(buf, HID_DEBUG_BUFSIZE, "%04x", page);
351 else 375 else
352 seq_printf(f, "%04x", page); 376 seq_printf(f, "%04x", page);
377 return buf;
353} 378}
354 379
355void hid_resolv_usage(unsigned usage, struct seq_file *f) { 380char *hid_resolv_usage(unsigned usage, struct seq_file *f) {
356 const struct hid_usage_entry *p; 381 const struct hid_usage_entry *p;
382 char *buf = NULL;
383 int len = 0;
357 384
358 resolv_usage_page(usage >> 16, f); 385 buf = resolv_usage_page(usage >> 16, f);
359 if (!f) 386 if (IS_ERR(buf)) {
360 printk("."); 387 printk(KERN_ERR "error allocating HID debug buffer\n");
361 else 388 return NULL;
389 }
390
391
392 if (!f) {
393 len = strlen(buf);
394 snprintf(buf+len, max(0, HID_DEBUG_BUFSIZE - len), ".");
395 len++;
396 }
397 else {
362 seq_printf(f, "."); 398 seq_printf(f, ".");
399 }
363 for (p = hid_usage_table; p->description; p++) 400 for (p = hid_usage_table; p->description; p++)
364 if (p->page == (usage >> 16)) { 401 if (p->page == (usage >> 16)) {
365 for(++p; p->description && p->usage != 0; p++) 402 for(++p; p->description && p->usage != 0; p++)
366 if (p->usage == (usage & 0xffff)) { 403 if (p->usage == (usage & 0xffff)) {
367 if (!f) 404 if (!f)
368 printk("%s", p->description); 405 snprintf(buf + len,
406 max(0,HID_DEBUG_BUFSIZE - len - 1),
407 "%s", p->description);
369 else 408 else
370 seq_printf(f, 409 seq_printf(f,
371 "%s", 410 "%s",
372 p->description); 411 p->description);
373 return; 412 return buf;
374 } 413 }
375 break; 414 break;
376 } 415 }
377 if (!f) 416 if (!f)
378 printk("%04x", usage & 0xffff); 417 snprintf(buf + len, max(0, HID_DEBUG_BUFSIZE - len - 1),
418 "%04x", usage & 0xffff);
379 else 419 else
380 seq_printf(f, "%04x", usage & 0xffff); 420 seq_printf(f, "%04x", usage & 0xffff);
421 return buf;
381} 422}
382EXPORT_SYMBOL_GPL(hid_resolv_usage); 423EXPORT_SYMBOL_GPL(hid_resolv_usage);
383 424
@@ -508,13 +549,37 @@ void hid_dump_device(struct hid_device *device, struct seq_file *f)
508} 549}
509EXPORT_SYMBOL_GPL(hid_dump_device); 550EXPORT_SYMBOL_GPL(hid_dump_device);
510 551
511void hid_dump_input(struct hid_usage *usage, __s32 value) { 552/* enqueue string to 'events' ring buffer */
512 if (hid_debug < 2) 553void hid_debug_event(struct hid_device *hdev, char *buf)
554{
555 int i;
556 struct hid_debug_list *list;
557
558 list_for_each_entry(list, &hdev->debug_list, node) {
559 for (i = 0; i <= strlen(buf); i++)
560 list->hid_debug_buf[(list->tail + i) % (HID_DEBUG_BUFSIZE - 1)] =
561 buf[i];
562 list->tail = (list->tail + i) % (HID_DEBUG_BUFSIZE - 1);
563 }
564}
565EXPORT_SYMBOL_GPL(hid_debug_event);
566
567void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value)
568{
569 char *buf;
570 int len;
571
572 buf = hid_resolv_usage(usage->hid, NULL);
573 if (!buf)
513 return; 574 return;
575 len = strlen(buf);
576 snprintf(buf + len, HID_DEBUG_BUFSIZE - len - 1, " = %d\n", value);
577
578 hid_debug_event(hdev, buf);
579
580 kfree(buf);
581 wake_up_interruptible(&hdev->debug_wait);
514 582
515 printk(KERN_DEBUG "hid-debug: input ");
516 hid_resolv_usage(usage->hid, NULL);
517 printk(" = %d\n", value);
518} 583}
519EXPORT_SYMBOL_GPL(hid_dump_input); 584EXPORT_SYMBOL_GPL(hid_dump_input);
520 585
@@ -808,6 +873,7 @@ void hid_dump_input_mapping(struct hid_device *hid, struct seq_file *f)
808 873
809} 874}
810 875
876
811static int hid_debug_rdesc_show(struct seq_file *f, void *p) 877static int hid_debug_rdesc_show(struct seq_file *f, void *p)
812{ 878{
813 struct hid_device *hdev = f->private; 879 struct hid_device *hdev = f->private;
@@ -831,6 +897,126 @@ static int hid_debug_rdesc_open(struct inode *inode, struct file *file)
831 return single_open(file, hid_debug_rdesc_show, inode->i_private); 897 return single_open(file, hid_debug_rdesc_show, inode->i_private);
832} 898}
833 899
900static int hid_debug_events_open(struct inode *inode, struct file *file)
901{
902 int err = 0;
903 struct hid_debug_list *list;
904
905 if (!(list = kzalloc(sizeof(struct hid_debug_list), GFP_KERNEL))) {
906 err = -ENOMEM;
907 goto out;
908 }
909
910 if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) {
911 err = -ENOMEM;
912 goto out;
913 }
914 list->hdev = (struct hid_device *) inode->i_private;
915 file->private_data = list;
916 mutex_init(&list->read_mutex);
917
918 list_add_tail(&list->node, &list->hdev->debug_list);
919
920out:
921 return err;
922}
923
924static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
925 size_t count, loff_t *ppos)
926{
927 struct hid_debug_list *list = file->private_data;
928 int ret = 0, len;
929 DECLARE_WAITQUEUE(wait, current);
930
931 while (ret == 0) {
932 mutex_lock(&list->read_mutex);
933 if (list->head == list->tail) {
934 add_wait_queue(&list->hdev->debug_wait, &wait);
935 set_current_state(TASK_INTERRUPTIBLE);
936
937 while (list->head == list->tail) {
938 if (file->f_flags & O_NONBLOCK) {
939 ret = -EAGAIN;
940 break;
941 }
942 if (signal_pending(current)) {
943 ret = -ERESTARTSYS;
944 break;
945 }
946
947 if (!list->hdev || !list->hdev->debug) {
948 ret = -EIO;
949 break;
950 }
951
952 /* allow O_NONBLOCK from other threads */
953 mutex_unlock(&list->read_mutex);
954 schedule();
955 mutex_lock(&list->read_mutex);
956 set_current_state(TASK_INTERRUPTIBLE);
957 }
958
959 set_current_state(TASK_RUNNING);
960 remove_wait_queue(&list->hdev->debug_wait, &wait);
961 }
962
963 if (ret)
964 goto out;
965
966 /* pass the ringbuffer contents to userspace */
967copy_rest:
968 if (list->tail == list->head)
969 goto out;
970 if (list->tail > list->head) {
971 len = list->tail - list->head;
972
973 if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) {
974 ret = -EFAULT;
975 goto out;
976 }
977 ret += len;
978 list->head += len;
979 } else {
980 len = HID_DEBUG_BUFSIZE - list->head;
981
982 if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) {
983 ret = -EFAULT;
984 goto out;
985 }
986 list->head = 0;
987 ret += len;
988 goto copy_rest;
989 }
990
991 }
992out:
993 mutex_unlock(&list->read_mutex);
994 return ret;
995}
996
997static unsigned int hid_debug_events_poll(struct file *file, poll_table *wait)
998{
999 struct hid_debug_list *list = file->private_data;
1000
1001 poll_wait(file, &list->hdev->debug_wait, wait);
1002 if (list->head != list->tail)
1003 return POLLIN | POLLRDNORM;
1004 if (!list->hdev->debug)
1005 return POLLERR | POLLHUP;
1006 return 0;
1007}
1008
1009static int hid_debug_events_release(struct inode *inode, struct file *file)
1010{
1011 struct hid_debug_list *list = file->private_data;
1012
1013 list_del(&list->node);
1014 kfree(list->hid_debug_buf);
1015 kfree(list);
1016
1017 return 0;
1018}
1019
834static const struct file_operations hid_debug_rdesc_fops = { 1020static const struct file_operations hid_debug_rdesc_fops = {
835 .open = hid_debug_rdesc_open, 1021 .open = hid_debug_rdesc_open,
836 .read = seq_read, 1022 .read = seq_read,
@@ -838,16 +1024,31 @@ static const struct file_operations hid_debug_rdesc_fops = {
838 .release = single_release, 1024 .release = single_release,
839}; 1025};
840 1026
1027static const struct file_operations hid_debug_events_fops = {
1028 .owner = THIS_MODULE,
1029 .open = hid_debug_events_open,
1030 .read = hid_debug_events_read,
1031 .poll = hid_debug_events_poll,
1032 .release = hid_debug_events_release,
1033};
1034
1035
841void hid_debug_register(struct hid_device *hdev, const char *name) 1036void hid_debug_register(struct hid_device *hdev, const char *name)
842{ 1037{
843 hdev->debug_dir = debugfs_create_dir(name, hid_debug_root); 1038 hdev->debug_dir = debugfs_create_dir(name, hid_debug_root);
844 hdev->debug_rdesc = debugfs_create_file("rdesc", 0400, 1039 hdev->debug_rdesc = debugfs_create_file("rdesc", 0400,
845 hdev->debug_dir, hdev, &hid_debug_rdesc_fops); 1040 hdev->debug_dir, hdev, &hid_debug_rdesc_fops);
1041 hdev->debug_events = debugfs_create_file("events", 0400,
1042 hdev->debug_dir, hdev, &hid_debug_events_fops);
1043 hdev->debug = 1;
846} 1044}
847 1045
848void hid_debug_unregister(struct hid_device *hdev) 1046void hid_debug_unregister(struct hid_device *hdev)
849{ 1047{
1048 hdev->debug = 0;
1049 wake_up_interruptible(&hdev->debug_wait);
850 debugfs_remove(hdev->debug_rdesc); 1050 debugfs_remove(hdev->debug_rdesc);
1051 debugfs_remove(hdev->debug_events);
851 debugfs_remove(hdev->debug_dir); 1052 debugfs_remove(hdev->debug_dir);
852} 1053}
853 1054