Hi Laurent,
here is my version of bug_report file for debugfs.
It include usb.id, dmi.system.product (for upsidedown report). And
stream specific information. I think it is good size for initial patch.
I near future i would like to add control call count and control error
rate to stats. And probably firs urb error number to report file.
I think it will be enough to provide needed info for troubleshooting.
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c
index 1b0087b..3a4edce 100644
--- a/drivers/media/video/uvc/uvc_debugfs.c
+++ b/drivers/media/video/uvc/uvc_debugfs.c
@@ -28,6 +28,25 @@ struct uvc_debugfs_buffer {
char data[UVC_DEBUGFS_BUF_SIZE];
};
+static ssize_t uvc_debugfs_read(struct file *file, char __user *user_buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct uvc_debugfs_buffer *buf = file->private_data;
+
+ return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data,
+ buf->count);
+}
+
+static int uvc_debugfs_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+/* stats */
+
static int uvc_debugfs_stats_open(struct inode *inode, struct file *file)
{
struct uvc_streaming *stream = inode->i_private;
@@ -43,29 +62,38 @@ static int uvc_debugfs_stats_open(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf,
- size_t nbytes, loff_t *ppos)
-{
- struct uvc_debugfs_buffer *buf = file->private_data;
- return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data,
- buf->count);
-}
+static const struct file_operations uvc_debugfs_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = uvc_debugfs_stats_open,
+ .llseek = no_llseek,
+ .read = uvc_debugfs_read,
+ .release = uvc_debugfs_release,
+};
+
+/* report */
-static int uvc_debugfs_stats_release(struct inode *inode, struct file *file)
+static int uvc_debugfs_report_open(struct inode *inode, struct file *file)
{
- kfree(file->private_data);
- file->private_data = NULL;
+ struct uvc_streaming *stream = inode->i_private;
+ struct uvc_debugfs_buffer *buf;
+
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ buf->count = uvc_video_report_dump(stream, buf->data, sizeof(buf->data));
+ file->private_data = buf;
return 0;
}
-static const struct file_operations uvc_debugfs_stats_fops = {
+static const struct file_operations uvc_debugfs_report_fops = {
.owner = THIS_MODULE,
- .open = uvc_debugfs_stats_open,
+ .open = uvc_debugfs_report_open,
.llseek = no_llseek,
- .read = uvc_debugfs_stats_read,
- .release = uvc_debugfs_stats_release,
+ .read = uvc_debugfs_read,
+ .release = uvc_debugfs_release,
};
/* -----------------------------------------------------------------------------
@@ -102,6 +130,14 @@ int uvc_debugfs_init_stream(struct uvc_streaming *stream)
return -ENODEV;
}
+ dent = debugfs_create_file("report", 0600, stream->debugfs_dir,
+ stream, &uvc_debugfs_report_fops);
+ if (IS_ERR_OR_NULL(dent)) {
+ uvc_printk(KERN_INFO, "Unable to create debugfs report file.\n");
+ uvc_debugfs_cleanup_stream(stream);
+ return -ENODEV;
+ }
+
return 0;
}
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index d0600a5..db0ba20 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -21,6 +21,7 @@
#include <linux/wait.h>
#include <linux/atomic.h>
#include <asm/unaligned.h>
+#include <linux/dmi.h>
#include <media/v4l2-common.h>
@@ -892,6 +893,55 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream)
ktime_get_ts(&stream->stats.stream.stop_ts);
}
+/* report */
+void uvc_video_report_start(struct uvc_streaming *stream)
+{
+ memset(&stream->report, 0, sizeof(stream->report));
+}
+void uvc_video_report_update(struct uvc_streaming *stream)
+{
+ stream->report.current_state = 1;
+ strcpy(stream->report.format_name, stream->cur_format->name);
+ stream->report.width = stream->cur_frame->wWidth;
+ stream->report.height = stream->cur_frame->wHeight;
+ stream->report.frame_interval = stream->ctrl.dwFrameInterval;
+
+}
+
+size_t uvc_video_report_dump(struct uvc_streaming *stream, char *buf,
+ size_t size)
+{
+ struct uvc_report_stream *report = &stream->report;
+ struct usb_device *udev = stream->dev->udev;
+ size_t count = 0;
+
+ /* assign usb id to every report */
+ count += scnprintf(buf + count, size - count,
+ "usb.id: %04x:%04x\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+ /* in case of vendor bug, like upside down webcam, report dmi product */
+ count += scnprintf(buf + count, size - count,
+ "dmi.sys.vendor: '%s'\ndmi.sys.product: '%s'\n"
+ "dmi.base.vendor: '%s'\ndmi.base.product: '%s'\n",
+ dmi_get_system_info(DMI_SYS_VENDOR),
+ dmi_get_system_info(DMI_PRODUCT_NAME),
+ dmi_get_system_info(DMI_BOARD_VENDOR),
+ dmi_get_system_info(DMI_BOARD_NAME));
+ count += scnprintf(buf + count, size - count,
+ "stream.packet.size: %d(%d)\nstream.state: %s\n",
+ report->best_psize, report->altsetting,
+ report->current_state ? "capture" : "idle");
+ count += scnprintf(buf + count, size - count,
+ "stream.format: %s\nstream.resolution: %ux%u @ %u\n",
+ report->format_name,
+ report->width, report->height,
+ report->frame_interval ?
+ 10000000/report->frame_interval : 0);
+
+ return count;
+}
+
/* ------------------------------------------------------------------------
* Video codecs
*/
@@ -1415,6 +1465,8 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
stream->urb[i] = NULL;
}
+ stream->report.current_state = 0;
+
if (free_buffers)
uvc_free_urb_buffers(stream);
@@ -1547,6 +1599,7 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
stream->bulk.payload_size = 0;
uvc_video_stats_start(stream);
+ uvc_video_report_start(stream);
ret = uvc_video_clock_init(stream);
if (ret < 0)
@@ -1600,6 +1653,9 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
"(%u B/frame bandwidth).\n", altsetting, best_psize);
+ stream->report.best_psize = best_psize;
+ stream->report.altsetting = altsetting;
+
ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
if (ret < 0)
return ret;
@@ -1629,6 +1685,8 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
}
}
+ uvc_video_report_update(stream);
+
return 0;
}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index e9c19f5..50c9490 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -403,6 +403,17 @@ struct uvc_stats_stream {
unsigned int max_sof; /* Maximum STC.SOF value */
};
+struct uvc_report_stream {
+ int current_state;
+ unsigned int best_psize;
+ unsigned int altsetting;
+
+ char format_name[32];
+ unsigned int width;
+ unsigned int height;
+ __u32 frame_interval;
+};
+
struct uvc_streaming {
struct list_head list;
struct uvc_device *dev;
@@ -457,6 +468,7 @@ struct uvc_streaming {
struct uvc_stats_frame frame;
struct uvc_stats_stream stream;
} stats;
+ struct uvc_report_stream report;
/* Timestamps support. */
struct uvc_clock {
@@ -692,5 +704,7 @@ void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
size_t size);
+size_t uvc_video_report_dump(struct uvc_streaming *stream, char *buf,
+ size_t size);
#endif
_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel