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