Hi Daniele,

can you please apply this patch on top of current kernel git.
With this patch you can get access to some webcams infos without spaming the sys log. After you compiled kernel and rebooted, or reloaded uvcvideo module, you can do this:
watch cat /sys/kernel/debug/usb/uvcvideo/001.007_046d.0808/stats

or just "cat" it, to monitore what's happening. Instead of "001.007_046d.0808" you need to set some thing different.

The field i interested in, is "error bit" or "uvc_stream_err". Seems like some cams depends on this bit, and current uvcvideo code do not use it. If your cam hangs after it set err_bit than may be we can do some thing. I plan to invest my time to err_bit handler right after uvc_debugfs patch will go upstream.

Regards,
Alexey.

Am 16.10.2011 02:06, schrieb Daniele Coccato:
Hello,
there is a bug of 5986:0203 which causes the webcam to automatically
turn to "red and black" after some seconds since initialization.
This happens only on the FIRST initialization of the webcam, later
initializations will not cause this problem anymore, until reboot.
This bug exists since LONG time (more than 2 years) and it is pretty annoying.
Could any developer please fix it?
If any more info is needed, feel free to ask.
Thanks.
_______________________________________________
Linux-uvc-devel mailing list
Linux-uvc-devel@lists.berlios.de
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel

diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile
index 2071ca8..c26d12f 100644
--- a/drivers/media/video/uvc/Makefile
+++ b/drivers/media/video/uvc/Makefile
@@ -1,5 +1,5 @@
 uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
-		  uvc_status.o uvc_isight.o
+		  uvc_status.o uvc_isight.o uvc_debugfs.o
 ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
 uvcvideo-objs  += uvc_entity.o
 endif
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c
new file mode 100644
index 0000000..b0c2313
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_debugfs.c
@@ -0,0 +1,213 @@
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/usb.h>
+
+#include "uvcvideo.h"
+
+#define MAX_DIRNAME 18
+
+#define STAT_BUF_SIZE  1024
+
+struct snap {
+	int slen;
+	char str[STAT_BUF_SIZE];
+};
+
+/* we do not need really precise time, seconds are ok */
+void uvc_debugfs_gettimeofday(__kernel_time_t *time)
+{
+	struct timeval tv;
+
+	do_gettimeofday(&tv);
+	*time = tv.tv_sec;
+}
+
+static int uvc_debugfs_stat_open(struct inode *inode, struct file *file)
+{
+	struct uvc_device *dev = inode->i_private;
+	struct usb_device *udev = dev->udev;
+	struct uvc_debugfs_stat *uvc_stat = dev->debugfs_stat;
+	struct snap *sp;
+
+	sp = kmalloc(sizeof(struct snap), GFP_KERNEL);
+
+	if (sp == NULL)
+		return -ENOMEM;
+
+	sp->slen = 0;
+
+	if (uvc_stat->current_state)
+		uvc_debugfs_gettimeofday(&uvc_stat->last_time);
+
+	/* device descriptor */
+	sp->slen += snprintf(sp->str + sp->slen, STAT_BUF_SIZE - sp->slen,
+		"usb id: %04x:%04x, usb bus: %03i:%03i\n",
+		le16_to_cpu(udev->descriptor.idVendor),
+		le16_to_cpu(udev->descriptor.idProduct),
+		udev->bus->busnum, udev->devnum);
+
+	/* capture state */
+	sp->slen += snprintf(sp->str + sp->slen, STAT_BUF_SIZE - sp->slen,
+		"packet size: %d(%d)\n"
+		"state: %s\n",
+		uvc_stat->best_psize, uvc_stat->altsetting,
+		uvc_stat->current_state ? "capture" : "idle");
+
+	sp->slen += snprintf(sp->str + sp->slen, STAT_BUF_SIZE - sp->slen,
+		"start time: %ld\n"
+		"capture time: %ld\n"
+		"fist data: %ld\n"
+		"first error bit: %ld\n"
+		"first out of sync: %ld\n",
+		uvc_stat->start_time,
+		uvc_stat->last_time - uvc_stat->start_time,
+		uvc_stat->first_data,
+		uvc_stat->first_err_bit,
+		uvc_stat->first_oos);
+
+	/* last/current format decsriptor */
+	sp->slen += snprintf(sp->str + sp->slen, STAT_BUF_SIZE - sp->slen,
+		"format: %s\n"
+		"resolution: %ux%u @ %u\n",
+		uvc_stat->format_name,
+		uvc_stat->width, uvc_stat->height,
+		uvc_stat->frame_interval ?
+			10000000/uvc_stat->frame_interval : 0);
+
+	sp->slen += snprintf(sp->str + sp->slen, STAT_BUF_SIZE - sp->slen,
+		"decode_start: %u\n"
+		"bad_header: %u\n"
+		"uvc_empty: %u\n"
+		"uvc_stream_err: %u\n"
+		"sequence: %u\n"
+		"out_of_sync: %u\n",
+		uvc_stat->decode_start, uvc_stat->bad_header,
+		uvc_stat->uvc_empty,
+		uvc_stat->uvc_stream_err, uvc_stat->sequence,
+		uvc_stat->out_of_sync);
+
+	file->private_data = sp;
+	return 0;
+}
+
+/* nothing to change */
+static ssize_t uvc_debugfs_stat_read(struct file *file, char __user *buf,
+					size_t nbytes, loff_t *ppos)
+{
+	struct snap *sp = file->private_data;
+
+	return simple_read_from_buffer(buf, nbytes, ppos, sp->str, sp->slen);
+}
+
+/* nothing to change */
+static int uvc_debugfs_stat_release(struct inode *inode, struct file *file)
+{
+	struct snap *sp = file->private_data;
+	file->private_data = NULL;
+	kfree(sp);
+	return 0;
+}
+
+/* connect all funcs for debugfs */
+const struct file_operations uvc_debugfs_stat_fops = {
+	.owner =        THIS_MODULE,
+	.open =         uvc_debugfs_stat_open,
+	.llseek =       no_llseek,
+	.read =         uvc_debugfs_stat_read,
+	.release =      uvc_debugfs_stat_release,
+};
+
+void uvc_debugfs_remove_dir(struct dentry **dir)
+{
+	debugfs_remove_recursive(*dir);
+	*dir = NULL;
+}
+
+int uvc_debugfs_create_root_dir(struct dentry **root_dir)
+{
+	/* filter */
+	if (*root_dir != NULL) {
+		uvc_printk(KERN_INFO, "Trying to assign debugfs/uvcvideo "
+			"directory on existing pointer: %p", *root_dir);
+		return -ENOTEMPTY;
+	}
+
+	/* create dir */
+	*root_dir = debugfs_create_dir("uvcvideo", usb_debug_root);
+
+	if (IS_ERR(*root_dir) || *root_dir == NULL) {
+		uvc_printk(KERN_INFO, "Unable to create uvcvideo directory\n");
+		*root_dir = NULL;
+		return -ENODATA;
+	}
+	return 0;
+}
+
+int uvc_debugfs_create_dev_dir(struct dentry **root_dir,
+					struct uvc_device *dev)
+{
+	struct usb_device *udev = dev->udev;
+	char dir_name[MAX_DIRNAME];
+
+	/* filter */
+	if (dev->debugfs_dev_dir != NULL) {
+		uvc_printk(KERN_INFO, "Trying to assign device directory "
+			"on existing pointer: %p", dev->debugfs_dev_dir);
+		return -ENOTEMPTY;
+	}
+
+	/* Some times create_dev_dir called before create_root_dir */
+	if (*root_dir == NULL)
+		if (uvc_debugfs_create_root_dir(root_dir))
+			return -ENODATA;
+
+
+	snprintf(dir_name, MAX_DIRNAME, "%03i.%03i_%04x.%04x",
+		udev->bus->busnum,
+		udev->devnum,
+		le16_to_cpu(udev->descriptor.idVendor),
+		le16_to_cpu(udev->descriptor.idProduct));
+
+
+	dev->debugfs_dev_dir = debugfs_create_dir(dir_name, *root_dir);
+
+	if (IS_ERR(dev->debugfs_dev_dir) || dev->debugfs_dev_dir == NULL) {
+		uvc_printk(KERN_INFO, "Unable to create %s directory. Err:%p\n",
+				dir_name, dev->debugfs_dev_dir);
+		dev->debugfs_dev_dir = NULL;
+		/* root dir will exist, may be we will have more,
+		 *  luck next time */
+		return -ENODATA;
+	}
+
+	dev->debugfs_stat = kzalloc(sizeof(struct uvc_debugfs_stat),
+						GFP_KERNEL);
+	if (dev->debugfs_stat == NULL) {
+		uvc_printk(KERN_INFO, "Unable to allocate memory for stats\n");
+		uvc_debugfs_remove_dir(&dev->debugfs_dev_dir);
+		return -ENOMEM;
+	}
+
+	dev->stat_file = debugfs_create_file("stats", 0600,
+				dev->debugfs_dev_dir,
+				dev, &uvc_debugfs_stat_fops);
+
+	if (IS_ERR(dev->stat_file) || dev->stat_file == NULL) {
+		/* debugfs not available, we can use uvcvideo without it */
+		uvc_printk(KERN_INFO, "Unable to create stat file. Err:%p\n",
+			dev->stat_file);
+		kfree(dev->debugfs_stat);
+		dev->debugfs_stat = NULL;
+		uvc_debugfs_remove_dir(&dev->debugfs_dev_dir);
+		dev->stat_file = NULL;
+		return -ENODATA;
+	}
+
+	return 0;
+}
+
+void uvc_debugfs_reset_stats(struct uvc_debugfs_stat *debugfs_stat)
+{
+	memset(debugfs_stat, 0, sizeof(struct uvc_debugfs_stat));
+}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index d29f9c2..188980d 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -49,6 +49,8 @@ static unsigned int uvc_quirks_param = -1;
 unsigned int uvc_trace_param;
 unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
 
+static struct dentry *uvc_debugfs_root_dir;
+
 /* ------------------------------------------------------------------------
  * Video formats
  */
@@ -1891,6 +1893,7 @@ static int uvc_probe(struct usb_interface *intf,
 
 	uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
 	usb_enable_autosuspend(udev);
+	uvc_debugfs_create_dev_dir(&uvc_debugfs_root_dir, dev);
 	return 0;
 
 error:
@@ -1913,6 +1916,16 @@ static void uvc_disconnect(struct usb_interface *intf)
 
 	dev->state |= UVC_DEV_DISCONNECTED;
 
+	/* If root dir is cleared, dev dir cleared as well.
+	 * But In this case, debugfs_dev_dir is a pointer to the forrest.
+	 * Remove just in case, some body wont to use it.
+	 */
+	if (uvc_debugfs_root_dir) {
+		kfree(dev->debugfs_stat);
+		uvc_debugfs_remove_dir(&dev->debugfs_dev_dir);
+	} else
+		dev->debugfs_dev_dir = NULL;
+
 	uvc_unregister_video(dev);
 }
 
@@ -2386,13 +2399,16 @@ static int __init uvc_init(void)
 	int result;
 
 	result = usb_register(&uvc_driver.driver);
-	if (result == 0)
+	if (result == 0) {
 		printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
+		uvc_debugfs_create_root_dir(&uvc_debugfs_root_dir);
+	}
 	return result;
 }
 
 static void __exit uvc_cleanup(void)
 {
+	uvc_debugfs_remove_dir(&uvc_debugfs_root_dir);
 	usb_deregister(&uvc_driver.driver);
 }
 
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 8244167..1db4597 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -410,29 +410,44 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
 		struct uvc_buffer *buf, const __u8 *data, int len)
 {
 	__u8 fid;
+	struct uvc_debugfs_stat *debugfs_stat = stream->dev->debugfs_stat;
+
+	debugfs_stat->decode_start++;
 
 	/* Sanity checks:
 	 * - packet must be at least 2 bytes long
 	 * - bHeaderLength value must be at least 2 bytes (see above)
 	 * - bHeaderLength value can't be larger than the packet size.
 	 */
-	if (len < 2 || data[0] < 2 || data[0] > len)
+	if (len < 2 || data[0] < 2 || data[0] > len) {
+		debugfs_stat->bad_header++;
 		return -EINVAL;
+	}
 
 	/* Skip payloads marked with the error bit ("error frames"). */
 	if (data[1] & UVC_STREAM_ERR) {
+		if (debugfs_stat->first_err_bit == 0)
+			uvc_debugfs_gettimeofday(&debugfs_stat->first_err_bit);
+		debugfs_stat->uvc_stream_err++;
 		uvc_trace(UVC_TRACE_FRAME, "Dropping payload (error bit "
 			  "set).\n");
 		return -ENODATA;
 	}
 
+	if (data[0] == len)
+		debugfs_stat->uvc_empty++;
+	else if (debugfs_stat->first_data == 0)
+		uvc_debugfs_gettimeofday(&debugfs_stat->first_data);
+
 	fid = data[1] & UVC_STREAM_FID;
 
 	/* Increase the sequence number regardless of any buffer states, so
 	 * that discontinuous sequence numbers always indicate lost frames.
 	 */
-	if (stream->last_fid != fid)
+	if (stream->last_fid != fid) {
+		debugfs_stat->sequence++;
 		stream->sequence++;
+	}
 
 	/* Store the payload FID bit and return immediately when the buffer is
 	 * NULL.
@@ -454,6 +469,9 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
 		struct timespec ts;
 
 		if (fid == stream->last_fid) {
+			if (debugfs_stat->first_oos == 0)
+				uvc_debugfs_gettimeofday(&debugfs_stat->first_oos);
+			debugfs_stat->out_of_sync++;
 			uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
 				"sync).\n");
 			if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
@@ -858,6 +876,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
  */
 static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
 {
+	struct uvc_debugfs_stat *debugfs_stat = stream->dev->debugfs_stat;
 	struct urb *urb;
 	unsigned int i;
 
@@ -871,6 +890,9 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
 		stream->urb[i] = NULL;
 	}
 
+	debugfs_stat->current_state = 0;
+	uvc_debugfs_gettimeofday(&debugfs_stat->last_time);
+
 	if (free_buffers)
 		uvc_free_urb_buffers(stream);
 }
@@ -984,6 +1006,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
 static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
 {
 	struct usb_interface *intf = stream->intf;
+	struct uvc_debugfs_stat *debugfs_stat = stream->dev->debugfs_stat;
 	struct usb_host_endpoint *ep;
 	unsigned int i;
 	int ret;
@@ -994,6 +1017,8 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
 	stream->bulk.skip_payload = 0;
 	stream->bulk.payload_size = 0;
 
+	uvc_debugfs_reset_stats(debugfs_stat);
+
 	if (intf->num_altsetting > 1) {
 		struct usb_host_endpoint *best_ep = NULL;
 		unsigned int best_psize = 3 * 1024;
@@ -1042,6 +1067,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);
 
+		debugfs_stat->best_psize = best_psize;
+		debugfs_stat->altsetting = altsetting;
+
 		ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
 		if (ret < 0)
 			return ret;
@@ -1071,6 +1099,13 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
 		}
 	}
 
+	debugfs_stat->current_state = 1;
+	strcpy(debugfs_stat->format_name, stream->cur_format->name);
+	debugfs_stat->width = stream->cur_frame->wWidth;
+	debugfs_stat->height = stream->cur_frame->wHeight;
+	debugfs_stat->frame_interval = stream->ctrl.dwFrameInterval;
+	uvc_debugfs_gettimeofday(&debugfs_stat->start_time);
+
 	return 0;
 }
 
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index df32a43..8db5e7d 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -496,6 +496,31 @@ struct uvc_streaming {
 	__u8 last_fid;
 };
 
+struct uvc_debugfs_stat {
+	unsigned int payload_count;
+	unsigned int current_state;
+	unsigned int best_psize;
+	unsigned int altsetting;
+
+	char format_name[32];
+	unsigned int width;
+	unsigned int height;
+	__u32 frame_interval;
+
+	__u32 decode_start;
+	__u32 bad_header;
+	__u32 uvc_stream_err;
+	__u32 uvc_empty;
+	__u32 sequence;
+	__u32 out_of_sync;
+
+	__kernel_time_t start_time;
+	__kernel_time_t last_time;
+	__kernel_time_t first_data;
+	__kernel_time_t first_oos;
+	__kernel_time_t first_err_bit;
+};
+
 enum uvc_device_state {
 	UVC_DEV_DISCONNECTED = 1,
 };
@@ -533,6 +558,11 @@ struct uvc_device {
 	__u8 *status;
 	struct input_dev *input;
 	char input_phys[64];
+
+	/* debugfs device dir */
+	struct dentry *debugfs_dev_dir;
+	struct dentry *stat_file;
+	struct uvc_debugfs_stat *debugfs_stat;
 };
 
 enum uvc_handle_state {
@@ -698,6 +728,14 @@ extern struct usb_host_endpoint *uvc_find_endpoint(
 void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
 		struct uvc_buffer *buf);
 
+/* debugfs functions */
+int uvc_debugfs_create_root_dir(struct dentry **root_dir);
+void uvc_debugfs_remove_dir(struct dentry **dir);
+int uvc_debugfs_create_dev_dir(struct dentry **root_dir,
+				struct uvc_device *dev);
+void uvc_debugfs_reset_stats(struct uvc_debugfs_stat *debugfs_stat);
+void uvc_debugfs_gettimeofday(__kernel_time_t *time);
+
 #endif /* __KERNEL__ */
 
 #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