Re: [PATCH v2 5/6] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS

2021-03-12 Thread Laurent Pinchart
Hi Hans,

On Fri, Mar 12, 2021 at 11:22:07AM +0100, Hans Verkuil wrote:
> On 12/03/2021 11:13, Laurent Pinchart wrote:
> > On Fri, Mar 12, 2021 at 10:57:33AM +0100, Ricardo Ribalda Delgado wrote:
> >> On Fri, Mar 12, 2021 at 2:25 AM Laurent Pinchart wrote:
> >>> On Thu, Mar 11, 2021 at 11:19:45PM +0100, Ricardo Ribalda wrote:
>  Create all the class controls for the device defined controls.
> 
>  Fixes v4l2-compliance:
>  Control ioctls (Input 0):
>    fail: v4l2-test-controls.cpp(216): missing control class 
>  for class 0098
>    fail: v4l2-test-controls.cpp(216): missing control tclass 
>  for class 009a
>    test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL
> 
>  Signed-off-by: Ricardo Ribalda 
>  ---
>   drivers/media/usb/uvc/uvc_ctrl.c | 90 
>   drivers/media/usb/uvc/uvcvideo.h |  7 +++
>   2 files changed, 97 insertions(+)
> 
>  diff --git a/drivers/media/usb/uvc/uvc_ctrl.c 
>  b/drivers/media/usb/uvc/uvc_ctrl.c
>  index b3dde98499f4..4e0ed2595ae9 100644
>  --- a/drivers/media/usb/uvc/uvc_ctrl.c
>  +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>  @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
>    },
>   };
> 
>  +static const struct uvc_control_class uvc_control_class[] = {
>  + {
>  + .id = V4L2_CID_CAMERA_CLASS,
>  + .name   = "Camera Controls",
>  + },
>  + {
>  + .id = V4L2_CID_USER_CLASS,
>  + .name   = "User Controls",
>  + },
>  +};
>  +
>   static const struct uvc_menu_info power_line_frequency_controls[] = {
>    { 0, "Disabled" },
>    { 1, "50 Hz" },
>  @@ -1024,6 +1035,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain 
>  *chain,
>    return 0;
>   }
> 
>  +static int __uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
>  +   u32 found_id)
>  +{
>  + bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
>  + int i;
> >>>
> >>> unsigned int as i will never be negative.
> >>
> >> Sometimes you are a bit negative with my patches... :)
> >>
> >> (sorry, it is Friday)
> >>
>  +
>  + req_id &= V4L2_CTRL_ID_MASK;
>  +
>  + for (i = 0; i < ARRAY_SIZE(uvc_control_class); i++) {
>  + if (!(dev->ctrl_class_bitmap & BIT(i)))
>  + continue;
>  + if (!find_next) {
>  + if (uvc_control_class[i].id == req_id)
>  + return i;
>  + continue;
>  + }
>  + if ((uvc_control_class[i].id > req_id) &&
>  + (uvc_control_class[i].id < found_id))
> >>>
> >>> No need for the inner parentheses.
> >>>
>  + return i;
>  + }
>  +
>  + return -ENODEV;
>  +}
>  +
>  +static int uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
>  + u32 found_id, struct v4l2_queryctrl 
>  *v4l2_ctrl)
>  +{
>  + int idx;
>  +
>  + idx = __uvc_query_v4l2_class(dev, req_id, found_id);
>  + if (idx < 0)
>  + return -ENODEV;
>  +
>  + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
>  + v4l2_ctrl->id = uvc_control_class[idx].id;
>  + strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
>  + sizeof(v4l2_ctrl->name));
>  + v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
>  + v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY |
>  + V4L2_CTRL_FLAG_READ_ONLY;
> >>>
> >>> v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY
> >>>  | V4L2_CTRL_FLAG_READ_ONLY;
> >>>
>  + return 0;
>  +}
> >>>
> >>> If you agree with the comments below, you could inline
> >>> __uvc_query_v4l2_class() in uvc_query_v4l2_class() as it won't be called
> >>> separately.
> >>>
>  +
>   static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>    struct uvc_control *ctrl,
>    struct uvc_control_mapping *mapping,
>  @@ -1123,6 +1177,14 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain 
>  *chain,
>    struct uvc_control_mapping *mapping;
>    int ret;
> 
>  + /* Check if the ctrl is a know class */
>  + if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
>  + ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
>  +v4l2_ctrl->id, v4l2_ctrl);
> >>>
> >>> You could pass 0 for found_id here.
> >>>
>  + if (!ret)
>  + return 0;
>  + }
>  +
> >>>
> >>> Should this be done with the 

Re: [PATCH v2 5/6] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS

2021-03-12 Thread Hans Verkuil
On 12/03/2021 11:13, Laurent Pinchart wrote:
> Hi Ricardo,
> 
> On Fri, Mar 12, 2021 at 10:57:33AM +0100, Ricardo Ribalda Delgado wrote:
>> On Fri, Mar 12, 2021 at 2:25 AM Laurent Pinchart wrote:
>>> On Thu, Mar 11, 2021 at 11:19:45PM +0100, Ricardo Ribalda wrote:
 Create all the class controls for the device defined controls.

 Fixes v4l2-compliance:
 Control ioctls (Input 0):
   fail: v4l2-test-controls.cpp(216): missing control class for 
 class 0098
   fail: v4l2-test-controls.cpp(216): missing control tclass 
 for class 009a
   test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL

 Signed-off-by: Ricardo Ribalda 
 ---
  drivers/media/usb/uvc/uvc_ctrl.c | 90 
  drivers/media/usb/uvc/uvcvideo.h |  7 +++
  2 files changed, 97 insertions(+)

 diff --git a/drivers/media/usb/uvc/uvc_ctrl.c 
 b/drivers/media/usb/uvc/uvc_ctrl.c
 index b3dde98499f4..4e0ed2595ae9 100644
 --- a/drivers/media/usb/uvc/uvc_ctrl.c
 +++ b/drivers/media/usb/uvc/uvc_ctrl.c
 @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
   },
  };

 +static const struct uvc_control_class uvc_control_class[] = {
 + {
 + .id = V4L2_CID_CAMERA_CLASS,
 + .name   = "Camera Controls",
 + },
 + {
 + .id = V4L2_CID_USER_CLASS,
 + .name   = "User Controls",
 + },
 +};
 +
  static const struct uvc_menu_info power_line_frequency_controls[] = {
   { 0, "Disabled" },
   { 1, "50 Hz" },
 @@ -1024,6 +1035,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain 
 *chain,
   return 0;
  }

 +static int __uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
 +   u32 found_id)
 +{
 + bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
 + int i;
>>>
>>> unsigned int as i will never be negative.
>>
>> Sometimes you are a bit negative with my patches... :)
>>
>> (sorry, it is Friday)
>>
 +
 + req_id &= V4L2_CTRL_ID_MASK;
 +
 + for (i = 0; i < ARRAY_SIZE(uvc_control_class); i++) {
 + if (!(dev->ctrl_class_bitmap & BIT(i)))
 + continue;
 + if (!find_next) {
 + if (uvc_control_class[i].id == req_id)
 + return i;
 + continue;
 + }
 + if ((uvc_control_class[i].id > req_id) &&
 + (uvc_control_class[i].id < found_id))
>>>
>>> No need for the inner parentheses.
>>>
 + return i;
 + }
 +
 + return -ENODEV;
 +}
 +
 +static int uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
 + u32 found_id, struct v4l2_queryctrl 
 *v4l2_ctrl)
 +{
 + int idx;
 +
 + idx = __uvc_query_v4l2_class(dev, req_id, found_id);
 + if (idx < 0)
 + return -ENODEV;
 +
 + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
 + v4l2_ctrl->id = uvc_control_class[idx].id;
 + strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
 + sizeof(v4l2_ctrl->name));
 + v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
 + v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY |
 + V4L2_CTRL_FLAG_READ_ONLY;
>>>
>>> v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY
>>>  | V4L2_CTRL_FLAG_READ_ONLY;
>>>
 + return 0;
 +}
>>>
>>> If you agree with the comments below, you could inline
>>> __uvc_query_v4l2_class() in uvc_query_v4l2_class() as it won't be called
>>> separately.
>>>
 +
  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
   struct uvc_control *ctrl,
   struct uvc_control_mapping *mapping,
 @@ -1123,6 +1177,14 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain 
 *chain,
   struct uvc_control_mapping *mapping;
   int ret;

 + /* Check if the ctrl is a know class */
 + if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
 + ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
 +v4l2_ctrl->id, v4l2_ctrl);
>>>
>>> You could pass 0 for found_id here.
>>>
 + if (!ret)
 + return 0;
 + }
 +
>>>
>>> Should this be done with the chain->ctrl_mutex locked, as
>>> __uvc_query_v4l2_class() accesses dev->ctrl_class_bitmap that could be
>>> modified concurrently ?
>>>
   ret = mutex_lock_interruptible(>ctrl_mutex);
   if (ret < 0)
   return -ERESTARTSYS;
 @@ -1133,6 +1195,13 @@ int uvc_query_v4l2_ctrl(struct 

Re: [PATCH v2 5/6] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS

2021-03-12 Thread Laurent Pinchart
Hi Ricardo,

On Fri, Mar 12, 2021 at 10:57:33AM +0100, Ricardo Ribalda Delgado wrote:
> On Fri, Mar 12, 2021 at 2:25 AM Laurent Pinchart wrote:
> > On Thu, Mar 11, 2021 at 11:19:45PM +0100, Ricardo Ribalda wrote:
> > > Create all the class controls for the device defined controls.
> > >
> > > Fixes v4l2-compliance:
> > > Control ioctls (Input 0):
> > >   fail: v4l2-test-controls.cpp(216): missing control class 
> > > for class 0098
> > >   fail: v4l2-test-controls.cpp(216): missing control tclass 
> > > for class 009a
> > >   test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL
> > >
> > > Signed-off-by: Ricardo Ribalda 
> > > ---
> > >  drivers/media/usb/uvc/uvc_ctrl.c | 90 
> > >  drivers/media/usb/uvc/uvcvideo.h |  7 +++
> > >  2 files changed, 97 insertions(+)
> > >
> > > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c 
> > > b/drivers/media/usb/uvc/uvc_ctrl.c
> > > index b3dde98499f4..4e0ed2595ae9 100644
> > > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > > @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
> > >   },
> > >  };
> > >
> > > +static const struct uvc_control_class uvc_control_class[] = {
> > > + {
> > > + .id = V4L2_CID_CAMERA_CLASS,
> > > + .name   = "Camera Controls",
> > > + },
> > > + {
> > > + .id = V4L2_CID_USER_CLASS,
> > > + .name   = "User Controls",
> > > + },
> > > +};
> > > +
> > >  static const struct uvc_menu_info power_line_frequency_controls[] = {
> > >   { 0, "Disabled" },
> > >   { 1, "50 Hz" },
> > > @@ -1024,6 +1035,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain 
> > > *chain,
> > >   return 0;
> > >  }
> > >
> > > +static int __uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
> > > +   u32 found_id)
> > > +{
> > > + bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
> > > + int i;
> >
> > unsigned int as i will never be negative.
> 
> Sometimes you are a bit negative with my patches... :)
> 
> (sorry, it is Friday)
>
> > > +
> > > + req_id &= V4L2_CTRL_ID_MASK;
> > > +
> > > + for (i = 0; i < ARRAY_SIZE(uvc_control_class); i++) {
> > > + if (!(dev->ctrl_class_bitmap & BIT(i)))
> > > + continue;
> > > + if (!find_next) {
> > > + if (uvc_control_class[i].id == req_id)
> > > + return i;
> > > + continue;
> > > + }
> > > + if ((uvc_control_class[i].id > req_id) &&
> > > + (uvc_control_class[i].id < found_id))
> >
> > No need for the inner parentheses.
> >
> > > + return i;
> > > + }
> > > +
> > > + return -ENODEV;
> > > +}
> > > +
> > > +static int uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
> > > + u32 found_id, struct v4l2_queryctrl 
> > > *v4l2_ctrl)
> > > +{
> > > + int idx;
> > > +
> > > + idx = __uvc_query_v4l2_class(dev, req_id, found_id);
> > > + if (idx < 0)
> > > + return -ENODEV;
> > > +
> > > + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> > > + v4l2_ctrl->id = uvc_control_class[idx].id;
> > > + strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
> > > + sizeof(v4l2_ctrl->name));
> > > + v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
> > > + v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY |
> > > + V4L2_CTRL_FLAG_READ_ONLY;
> >
> > v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY
> >  | V4L2_CTRL_FLAG_READ_ONLY;
> >
> > > + return 0;
> > > +}
> >
> > If you agree with the comments below, you could inline
> > __uvc_query_v4l2_class() in uvc_query_v4l2_class() as it won't be called
> > separately.
> >
> > > +
> > >  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> > >   struct uvc_control *ctrl,
> > >   struct uvc_control_mapping *mapping,
> > > @@ -1123,6 +1177,14 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain 
> > > *chain,
> > >   struct uvc_control_mapping *mapping;
> > >   int ret;
> > >
> > > + /* Check if the ctrl is a know class */
> > > + if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
> > > + ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
> > > +v4l2_ctrl->id, v4l2_ctrl);
> >
> > You could pass 0 for found_id here.
> >
> > > + if (!ret)
> > > + return 0;
> > > + }
> > > +
> >
> > Should this be done with the chain->ctrl_mutex locked, as
> > __uvc_query_v4l2_class() accesses dev->ctrl_class_bitmap that could be
> > modified concurrently ?
> >
> > >   ret = mutex_lock_interruptible(>ctrl_mutex);
> > >   if (ret < 0)
> > >   return -ERESTARTSYS;
> > > @@ -1133,6 

Re: [PATCH v2 5/6] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS

2021-03-12 Thread Ricardo Ribalda Delgado
HI Laurent

Thanks for the prompt reply :)

On Fri, Mar 12, 2021 at 2:25 AM Laurent Pinchart
 wrote:
>
> Hi Ricardo,
>
> Thank you for the patch.
>
> On Thu, Mar 11, 2021 at 11:19:45PM +0100, Ricardo Ribalda wrote:
> > Create all the class controls for the device defined controls.
> >
> > Fixes v4l2-compliance:
> > Control ioctls (Input 0):
> >   fail: v4l2-test-controls.cpp(216): missing control class for 
> > class 0098
> >   fail: v4l2-test-controls.cpp(216): missing control tclass for 
> > class 009a
> >   test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL
> >
> > Signed-off-by: Ricardo Ribalda 
> > ---
> >  drivers/media/usb/uvc/uvc_ctrl.c | 90 
> >  drivers/media/usb/uvc/uvcvideo.h |  7 +++
> >  2 files changed, 97 insertions(+)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c 
> > b/drivers/media/usb/uvc/uvc_ctrl.c
> > index b3dde98499f4..4e0ed2595ae9 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
> >   },
> >  };
> >
> > +static const struct uvc_control_class uvc_control_class[] = {
> > + {
> > + .id = V4L2_CID_CAMERA_CLASS,
> > + .name   = "Camera Controls",
> > + },
> > + {
> > + .id = V4L2_CID_USER_CLASS,
> > + .name   = "User Controls",
> > + },
> > +};
> > +
> >  static const struct uvc_menu_info power_line_frequency_controls[] = {
> >   { 0, "Disabled" },
> >   { 1, "50 Hz" },
> > @@ -1024,6 +1035,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain 
> > *chain,
> >   return 0;
> >  }
> >
> > +static int __uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
> > +   u32 found_id)
> > +{
> > + bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
> > + int i;
>
> unsigned int as i will never be negative.

Sometimes you are a bit negative with my patches... :)

(sorry, it is Friday)
>
> > +
> > + req_id &= V4L2_CTRL_ID_MASK;
> > +
> > + for (i = 0; i < ARRAY_SIZE(uvc_control_class); i++) {
> > + if (!(dev->ctrl_class_bitmap & BIT(i)))
> > + continue;
> > + if (!find_next) {
> > + if (uvc_control_class[i].id == req_id)
> > + return i;
> > + continue;
> > + }
> > + if ((uvc_control_class[i].id > req_id) &&
> > + (uvc_control_class[i].id < found_id))
>
> No need for the inner parentheses.
>
> > + return i;
> > + }
> > +
> > + return -ENODEV;
> > +}
> > +
> > +static int uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
> > + u32 found_id, struct v4l2_queryctrl 
> > *v4l2_ctrl)
> > +{
> > + int idx;
> > +
> > + idx = __uvc_query_v4l2_class(dev, req_id, found_id);
> > + if (idx < 0)
> > + return -ENODEV;
> > +
> > + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> > + v4l2_ctrl->id = uvc_control_class[idx].id;
> > + strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
> > + sizeof(v4l2_ctrl->name));
> > + v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
> > + v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY |
> > + V4L2_CTRL_FLAG_READ_ONLY;
>
> v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY
>  | V4L2_CTRL_FLAG_READ_ONLY;
>
> > + return 0;
> > +}
>
> If you agree with the comments below, you could inline
> __uvc_query_v4l2_class() in uvc_query_v4l2_class() as it won't be called
> separately.
>
> > +
> >  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
> >   struct uvc_control *ctrl,
> >   struct uvc_control_mapping *mapping,
> > @@ -1123,6 +1177,14 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain 
> > *chain,
> >   struct uvc_control_mapping *mapping;
> >   int ret;
> >
> > + /* Check if the ctrl is a know class */
> > + if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
> > + ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
> > +v4l2_ctrl->id, v4l2_ctrl);
>
> You could pass 0 for found_id here.
>
> > + if (!ret)
> > + return 0;
> > + }
> > +
>
> Should this be done with the chain->ctrl_mutex locked, as
> __uvc_query_v4l2_class() accesses dev->ctrl_class_bitmap that could be
> modified concurrently ?
>
> >   ret = mutex_lock_interruptible(>ctrl_mutex);
> >   if (ret < 0)
> >   return -ERESTARTSYS;
> > @@ -1133,6 +1195,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain 
> > *chain,
> >   goto done;
> >   }
> >
>
> A comment here along the lines of
>
> /*
>  * If we're enumerating control with V4L2_CTRL_FLAG_NEXT_CTRL, check 
> if
>  * 

Re: [PATCH v2 5/6] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS

2021-03-11 Thread Laurent Pinchart
Hi Ricardo,

Thank you for the patch.

On Thu, Mar 11, 2021 at 11:19:45PM +0100, Ricardo Ribalda wrote:
> Create all the class controls for the device defined controls.
> 
> Fixes v4l2-compliance:
> Control ioctls (Input 0):
>   fail: v4l2-test-controls.cpp(216): missing control class for 
> class 0098
>   fail: v4l2-test-controls.cpp(216): missing control tclass for 
> class 009a
>   test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL
> 
> Signed-off-by: Ricardo Ribalda 
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 90 
>  drivers/media/usb/uvc/uvcvideo.h |  7 +++
>  2 files changed, 97 insertions(+)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c 
> b/drivers/media/usb/uvc/uvc_ctrl.c
> index b3dde98499f4..4e0ed2595ae9 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
>   },
>  };
>  
> +static const struct uvc_control_class uvc_control_class[] = {
> + {
> + .id = V4L2_CID_CAMERA_CLASS,
> + .name   = "Camera Controls",
> + },
> + {
> + .id = V4L2_CID_USER_CLASS,
> + .name   = "User Controls",
> + },
> +};
> +
>  static const struct uvc_menu_info power_line_frequency_controls[] = {
>   { 0, "Disabled" },
>   { 1, "50 Hz" },
> @@ -1024,6 +1035,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain 
> *chain,
>   return 0;
>  }
>  
> +static int __uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
> +   u32 found_id)
> +{
> + bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
> + int i;

unsigned int as i will never be negative.

> +
> + req_id &= V4L2_CTRL_ID_MASK;
> +
> + for (i = 0; i < ARRAY_SIZE(uvc_control_class); i++) {
> + if (!(dev->ctrl_class_bitmap & BIT(i)))
> + continue;
> + if (!find_next) {
> + if (uvc_control_class[i].id == req_id)
> + return i;
> + continue;
> + }
> + if ((uvc_control_class[i].id > req_id) &&
> + (uvc_control_class[i].id < found_id))

No need for the inner parentheses.

> + return i;
> + }
> +
> + return -ENODEV;
> +}
> +
> +static int uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
> + u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
> +{
> + int idx;
> +
> + idx = __uvc_query_v4l2_class(dev, req_id, found_id);
> + if (idx < 0)
> + return -ENODEV;
> +
> + memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
> + v4l2_ctrl->id = uvc_control_class[idx].id;
> + strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
> + sizeof(v4l2_ctrl->name));
> + v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
> + v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY |
> + V4L2_CTRL_FLAG_READ_ONLY;

v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY
 | V4L2_CTRL_FLAG_READ_ONLY;

> + return 0;
> +}

If you agree with the comments below, you could inline
__uvc_query_v4l2_class() in uvc_query_v4l2_class() as it won't be called
separately.

> +
>  static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>   struct uvc_control *ctrl,
>   struct uvc_control_mapping *mapping,
> @@ -1123,6 +1177,14 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>   struct uvc_control_mapping *mapping;
>   int ret;
>  
> + /* Check if the ctrl is a know class */
> + if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
> + ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
> +v4l2_ctrl->id, v4l2_ctrl);

You could pass 0 for found_id here.

> + if (!ret)
> + return 0;
> + }
> +

Should this be done with the chain->ctrl_mutex locked, as
__uvc_query_v4l2_class() accesses dev->ctrl_class_bitmap that could be
modified concurrently ?

>   ret = mutex_lock_interruptible(>ctrl_mutex);
>   if (ret < 0)
>   return -ERESTARTSYS;
> @@ -1133,6 +1195,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
>   goto done;
>   }
>  

A comment here along the lines of

/*
 * If we're enumerating control with V4L2_CTRL_FLAG_NEXT_CTRL, check if
 * a class should be inserted between the previous control and the one
 * we have just found.
 */

could be useful, as it's not trivial.

> + if (v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
> + ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
> +mapping->id, v4l2_ctrl);
> + if (!ret)
> + goto done;
> + }
> +
>   ret = 

[PATCH v2 5/6] media: uvcvideo: Add support for V4L2_CTRL_TYPE_CTRL_CLASS

2021-03-11 Thread Ricardo Ribalda
Create all the class controls for the device defined controls.

Fixes v4l2-compliance:
Control ioctls (Input 0):
fail: v4l2-test-controls.cpp(216): missing control class for 
class 0098
fail: v4l2-test-controls.cpp(216): missing control tclass for 
class 009a
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: FAIL

Signed-off-by: Ricardo Ribalda 
---
 drivers/media/usb/uvc/uvc_ctrl.c | 90 
 drivers/media/usb/uvc/uvcvideo.h |  7 +++
 2 files changed, 97 insertions(+)

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index b3dde98499f4..4e0ed2595ae9 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -357,6 +357,17 @@ static const struct uvc_control_info uvc_ctrls[] = {
},
 };
 
+static const struct uvc_control_class uvc_control_class[] = {
+   {
+   .id = V4L2_CID_CAMERA_CLASS,
+   .name   = "Camera Controls",
+   },
+   {
+   .id = V4L2_CID_USER_CLASS,
+   .name   = "User Controls",
+   },
+};
+
 static const struct uvc_menu_info power_line_frequency_controls[] = {
{ 0, "Disabled" },
{ 1, "50 Hz" },
@@ -1024,6 +1035,49 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain,
return 0;
 }
 
+static int __uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
+ u32 found_id)
+{
+   bool find_next = req_id & V4L2_CTRL_FLAG_NEXT_CTRL;
+   int i;
+
+   req_id &= V4L2_CTRL_ID_MASK;
+
+   for (i = 0; i < ARRAY_SIZE(uvc_control_class); i++) {
+   if (!(dev->ctrl_class_bitmap & BIT(i)))
+   continue;
+   if (!find_next) {
+   if (uvc_control_class[i].id == req_id)
+   return i;
+   continue;
+   }
+   if ((uvc_control_class[i].id > req_id) &&
+   (uvc_control_class[i].id < found_id))
+   return i;
+   }
+
+   return -ENODEV;
+}
+
+static int uvc_query_v4l2_class(struct uvc_device *dev, u32 req_id,
+   u32 found_id, struct v4l2_queryctrl *v4l2_ctrl)
+{
+   int idx;
+
+   idx = __uvc_query_v4l2_class(dev, req_id, found_id);
+   if (idx < 0)
+   return -ENODEV;
+
+   memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
+   v4l2_ctrl->id = uvc_control_class[idx].id;
+   strscpy(v4l2_ctrl->name, uvc_control_class[idx].name,
+   sizeof(v4l2_ctrl->name));
+   v4l2_ctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
+   v4l2_ctrl->flags = V4L2_CTRL_FLAG_WRITE_ONLY |
+   V4L2_CTRL_FLAG_READ_ONLY;
+   return 0;
+}
+
 static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
struct uvc_control_mapping *mapping,
@@ -1123,6 +1177,14 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct uvc_control_mapping *mapping;
int ret;
 
+   /* Check if the ctrl is a know class */
+   if (!(v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) {
+   ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
+  v4l2_ctrl->id, v4l2_ctrl);
+   if (!ret)
+   return 0;
+   }
+
ret = mutex_lock_interruptible(>ctrl_mutex);
if (ret < 0)
return -ERESTARTSYS;
@@ -1133,6 +1195,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
goto done;
}
 
+   if (v4l2_ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+   ret = uvc_query_v4l2_class(chain->dev, v4l2_ctrl->id,
+  mapping->id, v4l2_ctrl);
+   if (!ret)
+   goto done;
+   }
+
ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
 done:
mutex_unlock(>ctrl_mutex);
@@ -1422,6 +1491,9 @@ static int uvc_ctrl_add_event(struct 
v4l2_subscribed_event *sev, unsigned elems)
struct uvc_control *ctrl;
int ret;
 
+   if (__uvc_query_v4l2_class(handle->chain->dev, sev->id, 0) >= 0)
+   return 0;
+
ret = mutex_lock_interruptible(>chain->ctrl_mutex);
if (ret < 0)
return -ERESTARTSYS;
@@ -1458,6 +1530,9 @@ static void uvc_ctrl_del_event(struct 
v4l2_subscribed_event *sev)
 {
struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
 
+   if (__uvc_query_v4l2_class(handle->chain->dev, sev->id, 0) >= 0)
+   return;
+
mutex_lock(>chain->ctrl_mutex);
list_del(>node);
mutex_unlock(>chain->ctrl_mutex);
@@ -1577,6 +1652,9 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
struct uvc_control *ctrl;
struct uvc_control_mapping *mapping;
 
+   if