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
Linux-uvc-devel@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel

Reply via email to