Hi Andreas,

On Saturday 05 May 2007, Andreas Volz wrote:
> Am Sat, 5 May 2007 21:22:22 +0200 schrieb Laurent Pinchart:
> > could you please set the trace parameter to 65535 with
> >
> > modprobe uvcvideo trace=65535
> >
> > or
> >
> > echo 65535 > /sys/modules/uvcvideo/parameters/trace
> >
> > then plug your camcorder and send me the dmesg output ?
>
> I know berlios often delete attachments. So I put it there:
>
> http://tux-style.de/tmp/dmesg_uvc.txt
>
> I did several plug/unplug actions in DV and webcam mode.

Thanks a lot. Could you perform the same operation after applying the attached 
patch to the latest driver (revision 102) ?

Best regards,

Laurent Pinchart
Index: uvc_ctrl.c
===================================================================
--- uvc_ctrl.c	(revision 101)
+++ uvc_ctrl.c	(working copy)
@@ -418,6 +418,7 @@
 
 static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
 static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
+static const __u8 uvc_media_transport_input_guid[16] = UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
 
 static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
 {
@@ -425,6 +426,9 @@
 	case ITT_CAMERA:
 		return memcmp(uvc_camera_guid, guid, 16) == 0;
 
+	case ITT_MEDIA_TRANSPORT_INPUT:
+		return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
+
 	case VC_PROCESSING_UNIT:
 		return memcmp(uvc_processing_guid, guid, 16) == 0;
 
@@ -471,22 +475,19 @@
 {
 	struct uvc_control *ctrl;
 	struct uvc_entity *entity;
-	unsigned int i;
 
 	/* Find the control. */
 	ctrl = __uvc_find_control(video->processing, v4l2_id, mapping);
 	if (ctrl)
 		return ctrl;
 
-	ctrl = __uvc_find_control(video->iterm, v4l2_id, mapping);
-	if (ctrl)
-		return ctrl;
+	list_for_each_entry(entity, &video->iterms, chain) {
+		ctrl = __uvc_find_control(entity, v4l2_id, mapping);
+		if (ctrl)
+			return ctrl;
+	}
 
-	for (i = 0; i < 8; ++i) {
-		entity = video->extension[i];
-		if (entity == NULL)
-			break;
-
+	list_for_each_entry(entity, &video->extensions, chain) {
 		ctrl = __uvc_find_control(entity, v4l2_id, mapping);
 		if (ctrl)
 			return ctrl;
@@ -632,7 +633,6 @@
 int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback)
 {
 	struct uvc_entity *entity;
-	unsigned int i;
 	int ret = 0;
 
 	/* Find the control. */
@@ -640,15 +640,13 @@
 	if (ret < 0)
 		goto done;
 
-	ret = uvc_ctrl_commit_entity(video, video->iterm, rollback);
-	if (ret < 0)
-		goto done;
+	list_for_each_entry(entity, &video->iterms, chain) {
+		ret = uvc_ctrl_commit_entity(video, entity, rollback);
+		if (ret < 0)
+			goto done;
+	}
 
-	for (i = 0; i < 8; ++i) {
-		entity = video->extension[i];
-		if (entity == NULL)
-			break;
-
+	list_for_each_entry(entity, &video->extensions, chain) {
 		ret = uvc_ctrl_commit_entity(video, entity, rollback);
 		if (ret < 0)
 			goto done;
Index: uvc_driver.c
===================================================================
--- uvc_driver.c	(revision 102)
+++ uvc_driver.c	(working copy)
@@ -63,9 +63,6 @@
 	},
 };
 
-static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
-static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
-
 #if 0
 static void uvc_print_streaming_control(struct uvc_streaming_control *ctrl)
 {
@@ -707,7 +704,7 @@
 	struct usb_host_interface *alts = dev->intf->cur_altsetting;
 	unsigned char *buffer = alts->extra;
 	int buflen = alts->extralen;
-	unsigned int i, n, p;
+	unsigned int i, n, p, len;
 	__u16 type;
 
 	/* Parse the default alternate setting only, as the UVC specification
@@ -793,18 +790,27 @@
 			}
 
 			n = 0;
+			p = 0;
+			len = 8;
 
 			if (type == ITT_CAMERA) {
-				if (buflen < 15 || buflen < 15 + buffer[14]) {
-					uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
-					       "interface %d INPUT_TERMINAL error\n", udev->devnum,
-					       dev->intf->cur_altsetting->desc.bInterfaceNumber);
-					return -EINVAL;
-				}
-				n = buffer[14];
+				n = buflen >= 15 ? buffer[14] : 0;
+				len = 15;
+
+			} else if (type == ITT_MEDIA_TRANSPORT_INPUT) {
+				n = buflen >= 9 ? buffer[8] : 0;
+				p = buflen >= 10 + n ? buffer[9+n] : 0;
+				len = 10;
 			}
 
-			term = kzalloc(sizeof *term + n, GFP_KERNEL);
+			if (buflen < len + n + p) {
+				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
+				       "interface %d INPUT_TERMINAL error\n", udev->devnum,
+				       dev->intf->cur_altsetting->desc.bInterfaceNumber);
+				return -EINVAL;
+			}
+
+			term = kzalloc(sizeof *term + n + p, GFP_KERNEL);
 			if (term == NULL)
 				return -ENOMEM;
 
@@ -818,12 +824,21 @@
 				term->camera.wObjectiveFocalLengthMax = le16_to_cpup((__le16*)&buffer[10]);
 				term->camera.wOcularFocalLength = le16_to_cpup((__le16*)&buffer[12]);
 				memcpy(term->camera.bmControls, &buffer[15], n);
+			} else if (term->type == ITT_MEDIA_TRANSPORT_INPUT) {
+				term->media.bControlSize = n;
+				term->media.bmControls = (__u8*)term + sizeof *term;
+				term->media.bTransportModeSize = p;
+				term->media.bmTransportModes = (__u8*)term + sizeof *term + n;
+				memcpy(term->media.bmControls, &buffer[9], n);
+				memcpy(term->media.bmTransportModes, &buffer[10+n], p);
 			}
 
 			if (buffer[7] != 0)
 				usb_string(udev, buffer[7], term->name, sizeof term->name);
 			else if (term->type == ITT_CAMERA)
 				sprintf(term->name, "Camera %u", buffer[3]);
+			else if (term->type == ITT_MEDIA_TRANSPORT_INPUT)
+				sprintf(term->name, "Media %u", buffer[3]);
 			else
 				sprintf(term->name, "Input %u", buffer[3]);
 
@@ -1013,109 +1028,207 @@
  * - a USB Streaming Output Terminal
  * - zero or one Processing Unit
  * - zero, one or mode single-input Selector Units
+ * - zero or one multiple-input Selector Units, provided all inputs are
+ *   connected to input terminals
  * - zero, one or mode single-input Extension Units
  * - one Camera Input Terminal, or one or more External terminals.
  *
  * A side forward scan is made on each detected entity to check for additional
  * extension units.
  */
-static int uvc_scan_chain(struct uvc_video_device *video)
+static int uvc_scan_chain_entity(struct uvc_video_device *video,
+	struct uvc_entity *entity)
 {
-	struct uvc_entity *entity, *forward;
-	unsigned int ext = 0;
-	int id, found;
+	switch (entity->type) {
+	case VC_EXTENSION_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- XU %d", entity->id);
 
-	entity = video->oterm;
-	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
-	id = entity->output.bSourceID;
-	while (1) {
-		/* Forward scan */
-		forward = NULL;
-		found = 0;
+		if (entity->extension.bNrInPins != 1) {
+			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
+				"than 1 input pin.\n", entity->id);
+			return -1;
+		}
 
-		while (1) {
-			forward = uvc_entity_by_reference(video->dev, id, forward);
-			if (forward == NULL)
-				break;
+		list_add_tail(&entity->chain, &video->extensions);
+		break;
 
-			if (forward == entity || forward->type != VC_EXTENSION_UNIT)
-				continue;
+	case VC_PROCESSING_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- PU %d", entity->id);
 
-			if (forward->extension.bNrInPins != 1) {
-				uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
-					"more than 1 input pin.\n", id);
-				return -1;
-			}
+		if (video->processing != NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found multiple "
+				"Processing Units in chain.\n");
+			return -1;
+		}
 
-			video->extension[ext++] = forward;
-			if (uvc_trace_param & UVC_TRACE_PROBE) {
-				if (!found)
-					printk(" (->");
+		video->processing = entity;
+		break;
 
-				printk(" %d", forward->id);
-				found = 1;
-			}
-		}
-		if (found)
-			printk(")");
+	case VC_SELECTOR_UNIT:
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- SU %d", entity->id);
 
-		/* Backward scan */
-		entity = uvc_entity_by_id(video->dev, id);
-		if (entity == NULL || !UVC_ENTITY_IS_UNIT(entity))
+		/* Single-input selector units are ignored. */
+		if (entity->selector.bNrInPins == 1)
 			break;
 
+		if (video->selector != NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
+				"Units in chain.\n");
+			return -1;
+		}
+
+		video->selector = entity;
+		break;
+
+	case ITT_VENDOR_SPECIFIC:
+	case ITT_CAMERA:
+	case ITT_MEDIA_TRANSPORT_INPUT:
 		if (uvc_trace_param & UVC_TRACE_PROBE)
-			printk(" <- Unit %d", entity->id);
-		switch (entity->type) {
-		case VC_EXTENSION_UNIT:
-			if (entity->extension.bNrInPins != 1) {
-				uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
-					"more than 1 input pin.\n", id);
-				return -1;
-			}
+			printk(" <- IT %d\n", entity->id);
 
-			video->extension[ext++] = entity;
-			id = entity->extension.baSourceID[0];
+		list_add_tail(&entity->chain, &video->iterms);
+		break;
+
+	default:
+		uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
+			"0x%04x found in chain.n", entity->type);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int uvc_scan_chain_forward(struct uvc_video_device *video,
+	struct uvc_entity *entity, struct uvc_entity *prev)
+{
+	struct uvc_entity *forward;
+	int found;
+
+	/* Forward scan */
+	forward = NULL;
+	found = 0;
+
+	while (1) {
+		forward = uvc_entity_by_reference(video->dev, entity->id,
+			forward);
+		if (forward == NULL)
 			break;
 
-		case VC_PROCESSING_UNIT:
-			if (video->processing != NULL) {
-				uvc_trace(UVC_TRACE_DESCR, "Found multiple "
-					"Processing Units in chain.\n");
-				return -1;
-			}
+		if (forward == prev || forward->type != VC_EXTENSION_UNIT)
+			continue;
 
-			video->processing = entity;
-			id = entity->processing.bSourceID;
+		if (forward->extension.bNrInPins != 1) {
+			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+				"more than 1 input pin.\n", entity->id);
+			return -1;
+		}
+
+		list_add_tail(&forward->chain, &video->extensions);
+		if (uvc_trace_param & UVC_TRACE_PROBE) {
+			if (!found)
+				printk(" (-> XU");
+
+			printk(" %d", forward->id);
+			found = 1;
+		}
+	}
+	if (found)
+		printk(")");
+
+	return 0;
+}
+
+static int uvc_scan_chain_backward(struct uvc_video_device *video,
+	struct uvc_entity *entity)
+{
+	struct uvc_entity *term;
+	int id = -1, i;
+
+	switch (entity->type) {
+	case VC_EXTENSION_UNIT:
+		id = entity->extension.baSourceID[0];
+		break;
+
+	case VC_PROCESSING_UNIT:
+		id = entity->processing.bSourceID;
+		break;
+
+	case VC_SELECTOR_UNIT:
+		/* Single-input selector units are ignored. */
+		if (entity->selector.bNrInPins == 1) {
+			id = entity->selector.baSourceID[0];
 			break;
+		}
 
-		case VC_SELECTOR_UNIT:
-			if (entity->selector.bNrInPins != 1) {
-				uvc_trace(UVC_TRACE_DESCR, "Multiple-input "
-					"selector units are not supported "
-					"yet.\n");
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk(" <- IT");
+
+		video->selector = entity;
+		for (i = 0; i < entity->selector.bNrInPins; ++i) {
+			id = entity->selector.baSourceID[i];
+			term = uvc_entity_by_id(video->dev, id);
+			if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
+				uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
+					"input %d isn't connected to an "
+					"input terminal\n", entity->id, i);
 				return -1;
 			}
 
-			id = entity->selector.baSourceID[0];
-			break;
+			if (uvc_trace_param & UVC_TRACE_PROBE)
+				printk(" %d", term->id);
 
-		default:
-			uvc_trace(UVC_TRACE_DESCR, "Unsupported unit type "
-				"0x%04x found in chain.n", entity->type);
-			return -1;
+			list_add_tail(&term->chain, &video->iterms);
+			uvc_scan_chain_forward(video, term, entity);
 		}
+
+		if (uvc_trace_param & UVC_TRACE_PROBE)
+			printk("\n");
+
+		id = 0;
+		break;
 	}
 
-	if (entity == NULL || !UVC_ENTITY_IS_ITERM(entity)) {
-		uvc_trace(UVC_TRACE_DESCR, "Input terminal %d not found.\n", id);
-		return -1;
+	return id;
+}
+
+static int uvc_scan_chain(struct uvc_video_device *video)
+{
+	struct uvc_entity *entity, *prev;
+	int id;
+
+	entity = video->oterm;
+	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);
+	id = entity->output.bSourceID;
+	while (id != 0) {
+		prev = entity;
+		entity = uvc_entity_by_id(video->dev, id);
+		if (entity == NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+				"unknown entity %d.\n", id);
+			return -1;
+		}
+
+		/* Process entity */
+		if (uvc_scan_chain_entity(video, entity) < 0)
+			return -1;
+
+		/* Forward scan */
+		if (uvc_scan_chain_forward(video, entity, prev) < 0)
+			return -1;
+
+		/* Stop when a terminal is found. */
+		if (!UVC_ENTITY_IS_UNIT(entity))
+			break;
+
+		/* Backward scan */
+		id = uvc_scan_chain_backward(video, entity);
+		if (id < 0)
+			return id;
 	}
 
-	if (uvc_trace_param & UVC_TRACE_PROBE)
-		printk(" <- IT %d\n", entity->id);
-	video->iterm = entity;
-
 	/* Initialize the video buffers queue. */
 	uvc_queue_init(&video->queue);
 
@@ -1150,6 +1263,8 @@
 
 		memset(&dev->video, 0, sizeof dev->video);
 		mutex_init(&dev->video.ctrl_mutex);
+		INIT_LIST_HEAD(&dev->video.iterms);
+		INIT_LIST_HEAD(&dev->video.extensions);
 		dev->video.oterm = term;
 		dev->video.dev = dev;
 		if (uvc_scan_chain(&dev->video) < 0)
@@ -1175,8 +1290,15 @@
 		return -1;
 	}
 
-	uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%d -> %d).\n",
-		dev->video.iterm->id, dev->video.oterm->id);
+	if (uvc_trace_param & UVC_TRACE_PROBE) {
+		uvc_printk(KERN_INFO, "Found a valid video chain (");
+		list_for_each_entry(term, &dev->video.iterms, chain) {
+			printk("%d", term->id);
+			if (term->chain.next != &dev->video.iterms)
+				printk(",");
+		}
+		printk(" -> %d).\n", dev->video.oterm->id);
+	}
 
 	/* Initialize the streaming interface with default streaming
 	 * parameters.
Index: uvcvideo.h
===================================================================
--- uvcvideo.h	(revision 102)
+++ uvcvideo.h	(working copy)
@@ -192,6 +192,9 @@
 				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
 #define UVC_GUID_UVC_OUTPUT	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
 				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
+#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
+				{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
 #define UVC_GUID_UVC_PROCESSING	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
 				 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
 #define UVC_GUID_UVC_SELECTOR	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
@@ -341,8 +344,9 @@
  */
 
 struct uvc_entity {
-	struct list_head list;
-
+	struct list_head list;		/* Entity as part of a UVC device. */
+	struct list_head chain;		/* Entity as part of a video device
+					 * chain. */
 	__u8 id;
 	__u16 type;
 	char name[64];
@@ -357,6 +361,13 @@
 		} camera;
 
 		struct {
+			__u8  bControlSize;
+			__u8  *bmControls;
+			__u8  bTransportModeSize;
+			__u8  *bmTransportModes;
+		} media;
+
+		struct {
 			__u8  bSourceID;
 		} output;
 
@@ -500,10 +511,11 @@
 
 	enum uvc_stream_state stream;
 
-	struct uvc_entity *iterm;
+	struct list_head iterms;
 	struct uvc_entity *oterm;
 	struct uvc_entity *processing;
-	struct uvc_entity *extension[8];
+	struct uvc_entity *selector;
+	struct list_head extensions;
 	struct mutex ctrl_mutex;
 
 	struct uvc_video_queue queue;
_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel

Reply via email to