aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-debug.c
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/hid-debug.c
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/hid-debug.c')
-rw-r--r--drivers/hid/hid-debug.c239
1 files changed, 220 insertions, 19 deletions
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