diff options
Diffstat (limited to 'drivers/media/video/uvc/uvc_debugfs.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_debugfs.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c new file mode 100644 index 000000000000..14561a5abb79 --- /dev/null +++ b/drivers/media/video/uvc/uvc_debugfs.c | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * uvc_debugfs.c -- USB Video Class driver - Debugging support | ||
3 | * | ||
4 | * Copyright (C) 2011 | ||
5 | * Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/debugfs.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/usb.h> | ||
18 | |||
19 | #include "uvcvideo.h" | ||
20 | |||
21 | /* ----------------------------------------------------------------------------- | ||
22 | * Statistics | ||
23 | */ | ||
24 | |||
25 | #define UVC_DEBUGFS_BUF_SIZE 1024 | ||
26 | |||
27 | struct uvc_debugfs_buffer { | ||
28 | size_t count; | ||
29 | char data[UVC_DEBUGFS_BUF_SIZE]; | ||
30 | }; | ||
31 | |||
32 | static int uvc_debugfs_stats_open(struct inode *inode, struct file *file) | ||
33 | { | ||
34 | struct uvc_streaming *stream = inode->i_private; | ||
35 | struct uvc_debugfs_buffer *buf; | ||
36 | |||
37 | buf = kmalloc(sizeof(*buf), GFP_KERNEL); | ||
38 | if (buf == NULL) | ||
39 | return -ENOMEM; | ||
40 | |||
41 | buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data)); | ||
42 | |||
43 | file->private_data = buf; | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf, | ||
48 | size_t nbytes, loff_t *ppos) | ||
49 | { | ||
50 | struct uvc_debugfs_buffer *buf = file->private_data; | ||
51 | |||
52 | return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data, | ||
53 | buf->count); | ||
54 | } | ||
55 | |||
56 | static int uvc_debugfs_stats_release(struct inode *inode, struct file *file) | ||
57 | { | ||
58 | kfree(file->private_data); | ||
59 | file->private_data = NULL; | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static const struct file_operations uvc_debugfs_stats_fops = { | ||
65 | .owner = THIS_MODULE, | ||
66 | .open = uvc_debugfs_stats_open, | ||
67 | .llseek = no_llseek, | ||
68 | .read = uvc_debugfs_stats_read, | ||
69 | .release = uvc_debugfs_stats_release, | ||
70 | }; | ||
71 | |||
72 | /* ----------------------------------------------------------------------------- | ||
73 | * Global and stream initialization/cleanup | ||
74 | */ | ||
75 | |||
76 | static struct dentry *uvc_debugfs_root_dir; | ||
77 | |||
78 | int uvc_debugfs_init_stream(struct uvc_streaming *stream) | ||
79 | { | ||
80 | struct usb_device *udev = stream->dev->udev; | ||
81 | struct dentry *dent; | ||
82 | char dir_name[32]; | ||
83 | |||
84 | if (uvc_debugfs_root_dir == NULL) | ||
85 | return -ENODEV; | ||
86 | |||
87 | sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum); | ||
88 | |||
89 | dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir); | ||
90 | if (IS_ERR_OR_NULL(dent)) { | ||
91 | uvc_printk(KERN_INFO, "Unable to create debugfs %s " | ||
92 | "directory.\n", dir_name); | ||
93 | return -ENODEV; | ||
94 | } | ||
95 | |||
96 | stream->debugfs_dir = dent; | ||
97 | |||
98 | dent = debugfs_create_file("stats", 0444, stream->debugfs_dir, | ||
99 | stream, &uvc_debugfs_stats_fops); | ||
100 | if (IS_ERR_OR_NULL(dent)) { | ||
101 | uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n"); | ||
102 | uvc_debugfs_cleanup_stream(stream); | ||
103 | return -ENODEV; | ||
104 | } | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream) | ||
110 | { | ||
111 | if (stream->debugfs_dir == NULL) | ||
112 | return; | ||
113 | |||
114 | debugfs_remove_recursive(stream->debugfs_dir); | ||
115 | stream->debugfs_dir = NULL; | ||
116 | } | ||
117 | |||
118 | int uvc_debugfs_init(void) | ||
119 | { | ||
120 | struct dentry *dir; | ||
121 | |||
122 | dir = debugfs_create_dir("uvcvideo", usb_debug_root); | ||
123 | if (IS_ERR_OR_NULL(dir)) { | ||
124 | uvc_printk(KERN_INFO, "Unable to create debugfs directory\n"); | ||
125 | return -ENODATA; | ||
126 | } | ||
127 | |||
128 | uvc_debugfs_root_dir = dir; | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | void uvc_debugfs_cleanup(void) | ||
133 | { | ||
134 | if (uvc_debugfs_root_dir != NULL) | ||
135 | debugfs_remove_recursive(uvc_debugfs_root_dir); | ||
136 | } | ||