Re: [PATCH v1 03/19] uvcvideo: Add support for multiple chains with common roots.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,
I'm repeating myself, but this seems the proper place to post this.

This patch causes a regression with the logitech c930e.

Please see comments below:


2013/11/10 Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>:
> Hi Pawel,
>
> Thank you for the patch.
>
> On Friday 30 August 2013 11:17:02 Pawel Osciak wrote:
>> This adds support for pipelines that fork into branches consisting of more
>> than one entity, creating a chain for each fork and putting common entities
>> on all chains that share them.
>>
>> This requires us to share the ctrl_mutex across forked chains. Whenever we
>> discover a shared part of a chain, we assign the pointer to an existing
>> mutex to the sharing chain instead of creating a new one.
>>
>> The "forward scan" is not needed anymore, as after scanning back from OTs,
>> we go over all entities which are not on a path from an OT and accept
>> single-XU branches, adding them to the existing chains.
>>
>> Also extract control locking into __uvc_ctrl_{lock,unlock} functions.
>
> This is one core piece of the UVC 1.5 rework, and I have mixed feelings about
> it.
>
> Adding entities to multiple overlapping chains somehow doesn't feel right.
> What would you think about using a pipeline object instead, which would store
> all entities in the pipeline ?
>
> The driver currently iterates over all entities in a chain for several
> purposes:
>
> - registering streaming terminals as video nodes (uvc_driver.c)
> - registering MC entities (uvc_entity.c)
> - enumerating inputs (uvc_v4l2.c)
> - finding controls and extension units (uvc_ctrl.c)
>
> The first two uses could easily be replaced by iterations over the whole
> pipeline. Input enumeration would probably require a bit of custom code
> anyway, so we would be left with controls.
>
> At first sight it would make sense to expose on a video node only the controls
> that can be reached from that video node moving up the pipeline (relatively to
> the video flow). However, this might break existing applications, as the
> driver currently also includes controls reacheable by forward scans of side
> branches. We thus need to carefully think about what controls to include, and
> we need to take into account output video nodes corresponding to input
> streaming terminals.
>
>> Signed-off-by: Pawel Osciak <posciak@xxxxxxxxxxxx>
>> ---
>>  drivers/media/usb/uvc/uvc_ctrl.c   |  70 ++++++++-----
>>  drivers/media/usb/uvc/uvc_driver.c | 210  +++++++++++++++++++--------------
>>  drivers/media/usb/uvc/uvc_entity.c |  15 ++-
>>  drivers/media/usb/uvc/uvc_v4l2.c   |   9 +-
>>  drivers/media/usb/uvc/uvcvideo.h   |  20 +++-
>>  5 files changed, 199 insertions(+), 125 deletions(-)
>>
>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c
>> b/drivers/media/usb/uvc/uvc_ctrl.c index a2f4501..ba159a4 100644
>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>> @@ -841,6 +841,7 @@ static struct uvc_control *uvc_find_control(struct
>> uvc_video_chain *chain, {
>>       struct uvc_control *ctrl = NULL;
>>       struct uvc_entity *entity;
>> +     struct uvc_chain_entry *entry;
>>       int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
>>
>>       *mapping = NULL;
>> @@ -849,7 +850,8 @@ static struct uvc_control *uvc_find_control(struct
>> uvc_video_chain *chain, v4l2_id &= V4L2_CTRL_ID_MASK;
>>
>>       /* Find the control. */
>> -     list_for_each_entry(entity, &chain->entities, chain) {
>> +     list_for_each_entry(entry, &chain->entities, chain_entry) {
>> +             entity = entry->entity;
>>               __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
>>               if (ctrl && !next)
>>                       return ctrl;
>> @@ -1048,6 +1050,16 @@ static int __uvc_query_v4l2_ctrl(struct
>> uvc_video_chain *chain, return 0;
>>  }
>>
>> +int __uvc_ctrl_lock(struct uvc_video_chain *chain)
>> +{
>> +     return mutex_lock_interruptible(&chain->pipeline->ctrl_mutex) ?
>> +                                     -ERESTARTSYS : 0;
>> +}
>> +void __uvc_ctrl_unlock(struct uvc_video_chain *chain)
>> +{
>> +     mutex_unlock(&chain->pipeline->ctrl_mutex);
>> +}
>> +
>>  int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>       struct v4l2_queryctrl *v4l2_ctrl)
>>  {
>> @@ -1055,9 +1067,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>> struct uvc_control_mapping *mapping;
>>       int ret;
>>
>> -     ret = mutex_lock_interruptible(&chain->ctrl_mutex);
>> +     ret = __uvc_ctrl_lock(chain);
>>       if (ret < 0)
>> -             return -ERESTARTSYS;
>> +             return ret;
>>
>>       ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
>>       if (ctrl == NULL) {
>> @@ -1067,7 +1079,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>>
>>       ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
>>  done:
>> -     mutex_unlock(&chain->ctrl_mutex);
>> +     __uvc_ctrl_unlock(chain);
>>       return ret;
>>  }
>>
>> @@ -1094,9 +1106,9 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
>> query_menu->id = id;
>>       query_menu->index = index;
>>
>> -     ret = mutex_lock_interruptible(&chain->ctrl_mutex);
>> +     ret = __uvc_ctrl_lock(chain);
>>       if (ret < 0)
>> -             return -ERESTARTSYS;
>> +             return ret;
>>
>>       ctrl = uvc_find_control(chain, query_menu->id, &mapping);
>>       if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
>> @@ -1132,7 +1144,7 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
>> strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
>>
>>  done:
>> -     mutex_unlock(&chain->ctrl_mutex);
>> +     __uvc_ctrl_unlock(chain);
>>       return ret;
>>  }
>>
>> @@ -1257,9 +1269,9 @@ static int uvc_ctrl_add_event(struct
>> v4l2_subscribed_event *sev, unsigned elems) struct uvc_control *ctrl;
>>       int ret;
>>
>> -     ret = mutex_lock_interruptible(&handle->chain->ctrl_mutex);
>> +     ret = __uvc_ctrl_lock(handle->chain);
>>       if (ret < 0)
>> -             return -ERESTARTSYS;
>> +             return ret;
>>
>>       ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
>>       if (ctrl == NULL) {
>> @@ -1285,7 +1297,7 @@ static int uvc_ctrl_add_event(struct
>> v4l2_subscribed_event *sev, unsigned elems) }
>>
>>  done:
>> -     mutex_unlock(&handle->chain->ctrl_mutex);
>> +     __uvc_ctrl_unlock(handle->chain);
>>       return ret;
>>  }
>>
>> @@ -1293,9 +1305,9 @@ static void uvc_ctrl_del_event(struct
>> v4l2_subscribed_event *sev) {
>>       struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
>>
>> -     mutex_lock(&handle->chain->ctrl_mutex);
>> +     __uvc_ctrl_lock(handle->chain);
>>       list_del(&sev->node);
>> -     mutex_unlock(&handle->chain->ctrl_mutex);
>> +     __uvc_ctrl_unlock(handle->chain);
>>  }
>>
>>  const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops = {
>> @@ -1331,7 +1343,7 @@ const struct v4l2_subscribed_event_ops
>> uvc_ctrl_sub_ev_ops = { */
>>  int uvc_ctrl_begin(struct uvc_video_chain *chain)
>>  {
>> -     return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
>> +     return __uvc_ctrl_lock(chain);
>>  }
>>
>>  static int uvc_ctrl_commit_entity(struct uvc_device *dev,
>> @@ -1390,10 +1402,12 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int
>> rollback, {
>>       struct uvc_video_chain *chain = handle->chain;
>>       struct uvc_entity *entity;
>> +     struct uvc_chain_entry *entry;
>>       int ret = 0;
>>
>>       /* Find the control. */
>> -     list_for_each_entry(entity, &chain->entities, chain) {
>> +     list_for_each_entry(entry, &chain->entities, chain_entry) {
>> +             entity = entry->entity;
>>               ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
>>               if (ret < 0)
>>                       goto done;
>> @@ -1402,7 +1416,7 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int
>> rollback, if (!rollback)
>>               uvc_ctrl_send_events(handle, xctrls, xctrls_count);
>>  done:
>> -     mutex_unlock(&chain->ctrl_mutex);
>> +     __uvc_ctrl_unlock(chain);
>>       return ret;
>>  }
>>
>> @@ -1667,7 +1681,8 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device
>> *dev, int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
>>       struct uvc_xu_control_query *xqry)
>>  {
>> -     struct uvc_entity *entity;
>> +     struct uvc_entity *entity = NULL;
>> +     struct uvc_chain_entry *entry;
>>       struct uvc_control *ctrl;
>>       unsigned int i, found = 0;
>>       __u32 reqflags;
>> @@ -1676,13 +1691,14 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
>> int ret;
>>
>>       /* Find the extension unit. */
>> -     list_for_each_entry(entity, &chain->entities, chain) {
>> +     list_for_each_entry(entry, &chain->entities, chain_entry) {
>> +             entity = entry->entity;
>>               if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
>>                   entity->id == xqry->unit)
>>                       break;
>>       }
>>
>> -     if (entity->id != xqry->unit) {
>> +     if (!entity || entity->id != xqry->unit) {
>>               uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
>>                       xqry->unit);
>>               return -ENOENT;
>> @@ -1703,8 +1719,9 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
>>               return -ENOENT;
>>       }
>>
>> -     if (mutex_lock_interruptible(&chain->ctrl_mutex))
>> -             return -ERESTARTSYS;
>> +     ret = __uvc_ctrl_lock(chain);
>> +     if (ret < 0)
>> +             return ret;
>>
>>       ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl);
>>       if (ret < 0) {
>> @@ -1778,7 +1795,7 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
>>               ret = -EFAULT;
>>  done:
>>       kfree(data);
>> -     mutex_unlock(&chain->ctrl_mutex);
>> +     __uvc_ctrl_unlock(chain);
>>       return ret;
>>  }
>>
>> @@ -1904,6 +1921,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain
>> *chain, const struct uvc_control_mapping *mapping)
>>  {
>>       struct uvc_device *dev = chain->dev;
>> +     struct uvc_chain_entry *entry;
>>       struct uvc_control_mapping *map;
>>       struct uvc_entity *entity;
>>       struct uvc_control *ctrl;
>> @@ -1918,8 +1936,9 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain
>> *chain, }
>>
>>       /* Search for the matching (GUID/CS) control on the current chain */
>> -     list_for_each_entry(entity, &chain->entities, chain) {
>> +     list_for_each_entry(entry, &chain->entities, chain_entry) {
>>               unsigned int i;
>> +             entity = entry->entity;
>>
>>               if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT ||
>>                   !uvc_entity_match_guid(entity, mapping->entity))
>> @@ -1939,8 +1958,9 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain
>> *chain, if (!found)
>>               return -ENOENT;
>>
>> -     if (mutex_lock_interruptible(&chain->ctrl_mutex))
>> -             return -ERESTARTSYS;
>> +     ret = __uvc_ctrl_lock(chain);
>> +     if (ret < 0)
>> +             return ret;
>>
>>       /* Perform delayed initialization of XU controls */
>>       ret = uvc_ctrl_init_xu_ctrl(dev, ctrl);
>> @@ -1974,7 +1994,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain
>> *chain, atomic_dec(&dev->nmappings);
>>
>>  done:
>> -     mutex_unlock(&chain->ctrl_mutex);
>> +     __uvc_ctrl_unlock(chain);
>>       return ret;
>>  }
>>
>> diff --git a/drivers/media/usb/uvc/uvc_driver.c
>> b/drivers/media/usb/uvc/uvc_driver.c index 81695d4..d7ff707 100644
>> --- a/drivers/media/usb/uvc/uvc_driver.c
>> +++ b/drivers/media/usb/uvc/uvc_driver.c
>> @@ -1215,6 +1215,36 @@ next_descriptor:
>>   * UVC device scan
>>   */
>>
>> +static int uvc_add_chain_entry(struct uvc_video_chain *chain,
>> +                             struct uvc_entity *entity)
>> +{
>> +     struct uvc_chain_entry *chain_entry;
>> +
>> +     chain_entry = kzalloc(sizeof(struct uvc_chain_entry), GFP_KERNEL);
>> +     if (!chain_entry)
>> +             return -ENOMEM;
>> +
>> +     chain_entry->entity = entity;
>> +     list_add_tail(&chain_entry->chain_entry, &chain->entities);
>> +     if (!entity->chain)
>> +             entity->chain = chain;
>> +
>> +     return 0;
>> +}
>> +
>> +static void uvc_delete_chain(struct uvc_video_chain *chain)
>> +{
>> +     struct list_head *p, *n;
>> +     struct uvc_chain_entry *entry;
>> +
>> +     list_for_each_safe(p, n, &chain->entities) {
>> +             entry = list_entry(p, struct uvc_chain_entry, chain_entry);
>> +             kfree(entry);
>> +     }
>> +
>> +     kfree(chain);
>> +}
>> +
>>  /*
>>   * Scan the UVC descriptors to locate a chain starting at an Output
>> Terminal * and containing the following units:
>> @@ -1320,72 +1350,7 @@ static int uvc_scan_chain_entity(struct
>> uvc_video_chain *chain, return -1;
>>       }
>>
>> -     list_add_tail(&entity->chain, &chain->entities);
>> -     return 0;
>> -}
>> -
>> -static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
>> -     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(chain->dev, entity->id,
>> -                     forward);
>> -             if (forward == NULL)
>> -                     break;
>> -             if (forward == prev)
>> -                     continue;
>> -
>> -             switch (UVC_ENTITY_TYPE(forward)) {
>> -             case UVC_VC_EXTENSION_UNIT:
>> -                     if (forward->bNrInPins != 1) {
>> -                             uvc_trace(UVC_TRACE_DESCR, "Extension unit %d "
>> -                                       "has more than 1 input pin.\n",
>> -                                       entity->id);
>> -                             return -EINVAL;
>> -                     }
>> -
>> -                     list_add_tail(&forward->chain, &chain->entities);
>> -                     if (uvc_trace_param & UVC_TRACE_PROBE) {
>> -                             if (!found)
>> -                                     printk(" (->");
>> -
>> -                             printk(" XU %d", forward->id);
>> -                             found = 1;
>> -                     }
>> -                     break;
>> -
>> -             case UVC_OTT_VENDOR_SPECIFIC:
>> -             case UVC_OTT_DISPLAY:
>> -             case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
>> -             case UVC_TT_STREAMING:
>> -                     if (UVC_ENTITY_IS_ITERM(forward)) {
>> -                             uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
>> -                                     "terminal %u.\n", forward->id);
>> -                             return -EINVAL;
>> -                     }
>> -
>> -                     list_add_tail(&forward->chain, &chain->entities);
>> -                     if (uvc_trace_param & UVC_TRACE_PROBE) {
>> -                             if (!found)
>> -                                     printk(" (->");
>> -
>> -                             printk(" OT %d", forward->id);
>> -                             found = 1;
>> -                     }
>> -                     break;
>> -             }
>> -     }
>> -     if (found)
>> -             printk(")");
>> -
>> -     return 0;
>> +     return uvc_add_chain_entry(chain, entity);
>>  }
>>
>>  static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
>> @@ -1394,6 +1359,7 @@ static int uvc_scan_chain_backward(struct
>> uvc_video_chain *chain, struct uvc_entity *entity = *_entity;
>>       struct uvc_entity *term;
>>       int id = -EINVAL, i;
>> +     int ret;
>>
>>       switch (UVC_ENTITY_TYPE(entity)) {
>>       case UVC_VC_EXTENSION_UNIT:
>> @@ -1425,8 +1391,9 @@ static int uvc_scan_chain_backward(struct
>> uvc_video_chain *chain, if (uvc_trace_param & UVC_TRACE_PROBE)
>>                               printk(" %d", term->id);
>>
>> -                     list_add_tail(&term->chain, &chain->entities);
>> -                     uvc_scan_chain_forward(chain, term, entity);
>> +                     ret = uvc_add_chain_entry(chain, term);
>> +                     if (ret)
>> +                             return ret;
>>               }
>>
>>               if (uvc_trace_param & UVC_TRACE_PROBE)
>> @@ -1473,23 +1440,23 @@ static int uvc_scan_chain(struct uvc_video_chain
>> *chain, prev = NULL;
>>
>>       while (entity != NULL) {
>> -             /* Entity must not be part of an existing chain */
>> -             if (entity->chain.next || entity->chain.prev) {
>> -                     uvc_trace(UVC_TRACE_DESCR, "Found reference to "
>> -                             "entity %d already in chain.\n", entity->id);
>> +             if (entity->chain == chain) {
>> +                     uvc_trace(UVC_TRACE_DESCR, "Found a cycle in the "
>> +                                     "chain");
>>                       return -EINVAL;
>>               }
>>
>> +             /* If this entity is a part of an existing chain, the
>> +              * current chain belongs to the same pipeline.
>> +              */
>> +             if (entity->chain)
>> +                     chain->pipeline = entity->chain->pipeline;
>> +
>>               /* Process entity */
>>               if (uvc_scan_chain_entity(chain, entity) < 0)
>>                       return -EINVAL;
>>
>> -             /* Forward scan */
>> -             if (uvc_scan_chain_forward(chain, entity, prev) < 0)
>> -                     return -EINVAL;
>> -
>>               /* Backward scan */
>> -             prev = entity;
>>               if (uvc_scan_chain_backward(chain, &entity) < 0)
>>                       return -EINVAL;
>>       }
>> @@ -1501,10 +1468,12 @@ static unsigned int uvc_print_terms(struct list_head
>> *terms, u16 dir, char *buffer)
>>  {
>>       struct uvc_entity *term;
>> +     struct uvc_chain_entry *entry;
>>       unsigned int nterms = 0;
>>       char *p = buffer;
>>
>> -     list_for_each_entry(term, terms, chain) {
>> +     list_for_each_entry(entry, terms, chain_entry) {
>> +             term = entry->entity;
>>               if (!UVC_ENTITY_IS_TERM(term) ||
>>                   UVC_TERM_DIRECTION(term) != dir)
>>                       continue;
>> @@ -1541,39 +1510,58 @@ static const char *uvc_print_chain(struct
>> uvc_video_chain *chain) static int uvc_scan_device(struct uvc_device *dev)
>>  {
>>       struct uvc_video_chain *chain;
>> -     struct uvc_entity *term;
>> +     struct uvc_entity *entity, *source;
>> +     int ret;
>>
>> -     list_for_each_entry(term, &dev->entities, list) {
>> -             if (!UVC_ENTITY_IS_OTERM(term))
>> +     list_for_each_entry(entity, &dev->entities, list) {
>> +             if (!UVC_ENTITY_IS_OTERM(entity))
>>                       continue;
>>
>> -             /* If the terminal is already included in a chain, skip it.
>> -              * This can happen for chains that have multiple output
>> -              * terminals, where all output terminals beside the first one
>> -              * will be inserted in the chain in forward scans.
>> +             /* Allow single-unit branches of Output Terminals to reside
>> +              * on the existing chains.
>>                */
>> -             if (term->chain.next || term->chain.prev)
>> -                     continue;
>> +             source = uvc_entity_by_id(dev, entity->baSourceID[0]);
>> +             if (entity == NULL) {
>> +                     uvc_trace(UVC_TRACE_DESCR, "Found reference to "
>> +                             "unknown entity %d.\n", entity->baSourceID[0]);
>> +                     return -EINVAL;
>> +             }
>>
>>               chain = kzalloc(sizeof(*chain), GFP_KERNEL);
>>               if (chain == NULL)
>>                       return -ENOMEM;
>>
>>               INIT_LIST_HEAD(&chain->entities);
>> -             mutex_init(&chain->ctrl_mutex);
>>               chain->dev = dev;
>>               v4l2_prio_init(&chain->prio);
>>
>> -             term->flags |= UVC_ENTITY_FLAG_DEFAULT;
>> +             entity->flags |= UVC_ENTITY_FLAG_DEFAULT;
>>
>> -             if (uvc_scan_chain(chain, term) < 0) {
>> -                     kfree(chain);
>> +             if (uvc_scan_chain(chain, entity) < 0) {
>> +                     uvc_delete_chain(chain);
>>                       continue;
>>               }
>>
>>               uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",
>>                         uvc_print_chain(chain));
>>
>> +             /*
>> +              * If none of the entities are shared, allocate a new pipeline.
>> +              * Otherwise, the shared pipeline is already set up.
>> +              */
>> +             if (!chain->pipeline) {
>> +                     chain->pipeline = kzalloc(sizeof(*chain->pipeline),
>> +                                               GFP_KERNEL);
>> +                     if (!chain->pipeline) {
>> +                             uvc_delete_chain(chain);
>> +                             return -ENOMEM;
>> +                     }
>> +                     mutex_init(&chain->pipeline->ctrl_mutex);
>> +                     atomic_set(&chain->pipeline->num_chains, 1);
>> +             } else {
>> +                     atomic_inc(&chain->pipeline->num_chains);
>> +             }
>> +
>>               list_add_tail(&chain->list, &dev->chains);
>>       }
>>
>> @@ -1582,6 +1570,38 @@ static int uvc_scan_device(struct uvc_device *dev)
>>               return -1;
>>       }
>>
>> +     /* Find branches with no OTERMs (if any) by looking for entities not
>> +      * on any chain. Accept only branches with a single Extension Unit.
>> +      */
>> +     list_for_each_entry(entity, &dev->entities, list) {
>> +             if (entity->chain)
>> +                     continue;
>> +
>> +             if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT
>> +                     || entity->bNrInPins != 1
>> +                     || uvc_entity_by_reference(dev, entity->id, NULL)) {
>> +                     uvc_printk(KERN_INFO, "Found an invalid branch "
>> +                             "starting at entity id %d.\n", entity->id);
>> +                     return -1;
>> +             }


This fails for the c930e, to be more exact 'uvc_entity_by_reference'
fails for unit 12 (the h264 extension unit).
This prevents the driver from creating the video node, making the
camera unusable.
As a simple test I commented this line ( /* ||
uvc_entity_by_reference(dev, entity->id, NULL) */ ), the video node is
created and the camera works fine.

>> +
>> +             /* Single-unit XU branch. */
>> +             source = uvc_entity_by_id(dev, entity->baSourceID[0]);
>> +             if (source == NULL) {
>> +                     uvc_trace(UVC_TRACE_DESCR, "Found reference to "
>> +                             "unknown entity %d.\n", entity->baSourceID[0]);
>> +                     return -EINVAL;
>> +             }
>> +             if (!source->chain)
>> +                     continue;
>> +
>> +             ret = uvc_add_chain_entry(source->chain, entity);
>> +             if (ret)
>> +                     return ret;
>> +             uvc_trace(UVC_TRACE_DESCR, "XU %d <- (%d)\n",
>> +                             entity->id, source->id);
>> +     }
>> +
>>       return 0;
>>  }
>>
>> @@ -1619,7 +1639,9 @@ static void uvc_delete(struct uvc_device *dev)
>>       list_for_each_safe(p, n, &dev->chains) {
>>               struct uvc_video_chain *chain;
>>               chain = list_entry(p, struct uvc_video_chain, list);
>> -             kfree(chain);
>> +             if (atomic_dec_and_test(&chain->pipeline->num_chains))
>> +                     kfree(chain->pipeline);
>> +             uvc_delete_chain(chain);
>>       }
>>
>>       list_for_each_safe(p, n, &dev->entities) {
>> @@ -1763,9 +1785,11 @@ static int uvc_register_terms(struct uvc_device *dev,
>> {
>>       struct uvc_streaming *stream;
>>       struct uvc_entity *term;
>> +     struct uvc_chain_entry *entry;
>>       int ret;
>>
>> -     list_for_each_entry(term, &chain->entities, chain) {
>> +     list_for_each_entry(entry, &chain->entities, chain_entry) {
>> +             term = entry->entity;
>>               if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
>>                       continue;
>>
>> diff --git a/drivers/media/usb/uvc/uvc_entity.c
>> b/drivers/media/usb/uvc/uvc_entity.c index dc56a59..657f49a 100644
>> --- a/drivers/media/usb/uvc/uvc_entity.c
>> +++ b/drivers/media/usb/uvc/uvc_entity.c
>> @@ -104,9 +104,14 @@ static int uvc_mc_init_entity(struct uvc_entity
>> *entity) int uvc_mc_register_entities(struct uvc_video_chain *chain)
>>  {
>>       struct uvc_entity *entity;
>> +     struct uvc_chain_entry *entry;
>>       int ret;
>>
>> -     list_for_each_entry(entity, &chain->entities, chain) {
>> +     list_for_each_entry(entry, &chain->entities, chain_entry) {
>> +             entity = entry->entity;
>> +             if (entity->registered)
>> +                     continue;
>> +
>>               ret = uvc_mc_init_entity(entity);
>>               if (ret < 0) {
>>                       uvc_printk(KERN_INFO, "Failed to initialize entity for "
>> @@ -115,13 +120,19 @@ int uvc_mc_register_entities(struct uvc_video_chain
>> *chain) }
>>       }
>>
>> -     list_for_each_entry(entity, &chain->entities, chain) {
>> +     list_for_each_entry(entry, &chain->entities, chain_entry) {
>> +             entity = entry->entity;
>> +             if (entity->registered)
>> +                     continue;
>> +
>>               ret = uvc_mc_register_entity(chain, entity);
>>               if (ret < 0) {
>>                       uvc_printk(KERN_INFO, "Failed to register entity for "
>>                                  "entity %u\n", entity->id);
>>                       return ret;
>>               }
>> +
>> +             entity->registered = true;
>>       }
>>
>>       return 0;
>> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c
>> b/drivers/media/usb/uvc/uvc_v4l2.c index 3afff92..a899159 100644
>> --- a/drivers/media/usb/uvc/uvc_v4l2.c
>> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
>> @@ -713,6 +713,7 @@ static long uvc_v4l2_do_ioctl(struct file *file,
>> unsigned int cmd, void *arg) const struct uvc_entity *selector =
>> chain->selector;
>>               struct v4l2_input *input = arg;
>>               struct uvc_entity *iterm = NULL;
>> +             struct uvc_chain_entry *entry;
>>               u32 index = input->index;
>>               int pin = 0;
>>
>> @@ -720,14 +721,18 @@ static long uvc_v4l2_do_ioctl(struct file *file,
>> unsigned int cmd, void *arg) (chain->dev->quirks &
>> UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
>>                       if (index != 0)
>>                               return -EINVAL;
>> -                     list_for_each_entry(iterm, &chain->entities, chain) {
>> +                     list_for_each_entry(entry, &chain->entities,
>> +                                             chain_entry) {
>> +                             iterm = entry->entity;
>>                               if (UVC_ENTITY_IS_ITERM(iterm))
>>                                       break;
>>                       }
>>                       pin = iterm->id;
>>               } else if (index < selector->bNrInPins) {
>>                       pin = selector->baSourceID[index];
>> -                     list_for_each_entry(iterm, &chain->entities, chain) {
>> +                     list_for_each_entry(entry, &chain->entities,
>> +                                             chain_entry) {
>> +                             iterm = entry->entity;
>>                               if (!UVC_ENTITY_IS_ITERM(iterm))
>>                                       continue;
>>                               if (iterm->id == pin)
>> diff --git a/drivers/media/usb/uvc/uvcvideo.h
>> b/drivers/media/usb/uvc/uvcvideo.h index 75e0153..731b378 100644
>> --- a/drivers/media/usb/uvc/uvcvideo.h
>> +++ b/drivers/media/usb/uvc/uvcvideo.h
>> @@ -229,8 +229,8 @@ struct uvc_format_desc {
>>
>>  struct uvc_entity {
>>       struct list_head list;          /* Entity as part of a UVC device. */
>> -     struct list_head chain;         /* Entity as part of a video device
>> -                                      * chain. */
>> +     struct uvc_video_chain *chain;  /* Entity as a part of a video device
>> +                                        chain. */
>>       unsigned int flags;
>>
>>       __u8 id;
>> @@ -243,6 +243,7 @@ struct uvc_entity {
>>       unsigned int num_pads;
>>       unsigned int num_links;
>>       struct media_pad *pads;
>> +     bool registered;                /* True if already registered with MC */
>>
>>       union {
>>               struct {
>> @@ -289,6 +290,12 @@ struct uvc_entity {
>>       struct uvc_control *controls;
>>  };
>>
>> +struct uvc_chain_entry {
>> +     struct list_head chain_entry;
>> +     struct uvc_entity *entity;
>> +     struct uvc_video_chain *chain;
>> +};
>> +
>>  struct uvc_frame {
>>       __u8  bFrameIndex;
>>       __u8  bmCapabilities;
>> @@ -366,6 +373,12 @@ struct uvc_video_queue {
>>       struct list_head irqqueue;
>>  };
>>
>> +struct uvc_video_pipeline {
>> +     struct mutex ctrl_mutex;                /* Protects controls in all
>> +                                                chains of this pipeline */
>> +     atomic_t num_chains;
>> +};
>> +
>>  struct uvc_video_chain {
>>       struct uvc_device *dev;
>>       struct list_head list;
>> @@ -374,7 +387,8 @@ struct uvc_video_chain {
>>       struct uvc_entity *processing;          /* Processing unit */
>>       struct uvc_entity *selector;            /* Selector unit */
>>
>> -     struct mutex ctrl_mutex;                /* Protects ctrl.info */
>> +     struct uvc_video_pipeline *pipeline;    /* Pipeline this chain
>> +                                                belongs to */
>>
>>       struct v4l2_prio_state prio;            /* V4L2 priority state */
>>       u32 caps;                               /* V4L2 chain-wide caps */
> --
> Regards,
>
> Laurent Pinchart
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Regards,
Paulo
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux