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