diff mbox series

[v7,6/7] media: uvcvideo: support V4L2_CTRL_WHICH_MIN/MAX_VAL

Message ID 20220628075705.2278044-7-yunkec@google.com (mailing list archive)
State New, archived
Headers show
Series media: Implement UVC v1.5 ROI | expand

Commit Message

Yunke Cao June 28, 2022, 7:57 a.m. UTC
Add support for V4L2_CTRL_WHICH_MIN/MAX_VAL in uvc driver.
It is useful for the V4L2_CID_UVC_REGION_OF_INTEREST_RECT control.

Signed-off-by: Yunke Cao <yunkec@google.com>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 73 ++++++++++++++++++++++++++------
 drivers/media/usb/uvc/uvc_v4l2.c | 11 +++--
 drivers/media/usb/uvc/uvcvideo.h |  3 +-
 3 files changed, 70 insertions(+), 17 deletions(-)

Comments

Ricardo Ribalda June 30, 2022, 6:41 a.m. UTC | #1
On Tue, 28 Jun 2022 at 09:57, Yunke Cao <yunkec@google.com> wrote:
>
> Add support for V4L2_CTRL_WHICH_MIN/MAX_VAL in uvc driver.
> It is useful for the V4L2_CID_UVC_REGION_OF_INTEREST_RECT control.
>
> Signed-off-by: Yunke Cao <yunkec@google.com>
Reviewed-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 73 ++++++++++++++++++++++++++------
>  drivers/media/usb/uvc/uvc_v4l2.c | 11 +++--
>  drivers/media/usb/uvc/uvcvideo.h |  3 +-
>  3 files changed, 70 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 00482269233a..b569d6824ac1 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1923,7 +1923,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
>  }
>
>  int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
> -                            struct v4l2_ext_control *xctrl)
> +                            struct v4l2_ext_control *xctrl, u32 v4l2_which)
>  {
>         struct v4l2_queryctrl qc = { .id = xctrl->id };
>         int ret = uvc_query_v4l2_ctrl(chain, &qc);
> @@ -1931,16 +1931,69 @@ int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
>         if (ret < 0)
>                 return ret;
>
> -       xctrl->value = qc.default_value;
> +       switch (v4l2_which) {
> +       case V4L2_CTRL_WHICH_DEF_VAL:
> +               xctrl->value = qc.default_value;
> +               break;
> +       case V4L2_CTRL_WHICH_MIN_VAL:
> +               xctrl->value = qc.minimum;
> +               break;
> +       case V4L2_CTRL_WHICH_MAX_VAL:
> +               xctrl->value = qc.maximum;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
>         return 0;
>  }
>
> +static int __uvc_ctrl_get_fixed_compound(struct uvc_video_chain *chain,
> +                                        struct uvc_control_mapping *mapping,
> +                                        struct uvc_control *ctrl,
> +                                        u32 v4l2_which,
> +                                        struct v4l2_ext_control *xctrl)
> +{
> +       int ret;
> +       u32 flag, id;
> +
> +       if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
> +               return -EINVAL;
> +
> +       switch (v4l2_which) {
> +       case V4L2_CTRL_WHICH_DEF_VAL:
> +               flag = UVC_CTRL_FLAG_GET_DEF;
> +               id = UVC_CTRL_DATA_DEF;
> +               break;
> +       case V4L2_CTRL_WHICH_MIN_VAL:
> +               flag = UVC_CTRL_FLAG_GET_MIN;
> +               id = UVC_CTRL_DATA_MIN;
> +               break;
> +       case V4L2_CTRL_WHICH_MAX_VAL:
> +               flag = UVC_CTRL_FLAG_GET_MAX;
> +               id = UVC_CTRL_DATA_MAX;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       if (!(ctrl->info.flags & flag) && flag != UVC_CTRL_FLAG_GET_DEF)
> +               return -EACCES;
> +
> +       if (!ctrl->cached) {
> +               ret = uvc_ctrl_populate_cache(chain, ctrl);
> +               if (ret < 0)
> +                       return ret;
> +       }
> +
> +       return __uvc_ctrl_get_compound_to_user(mapping, ctrl, id, xctrl);
> +}
> +
>  int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
> -                      struct v4l2_ext_control *xctrl)
> +                      struct v4l2_ext_control *xctrl, u32 v4l2_which)
>  {
>         struct uvc_control *ctrl;
>         struct uvc_control_mapping *mapping;
> -       int ret;
>
>         if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
>                 return -EACCES;
> @@ -1950,16 +2003,10 @@ int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
>                 return -EINVAL;
>
>         if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
> -               return __uvc_ctrl_get_fixed_std(chain, xctrl);
> +               return __uvc_ctrl_get_fixed_std(chain, xctrl, v4l2_which);
>
> -       if (!ctrl->cached) {
> -               ret = uvc_ctrl_populate_cache(chain, ctrl);
> -               if (ret < 0)
> -                       return ret;
> -       }
> -
> -       return __uvc_ctrl_get_compound_to_user(mapping, ctrl, UVC_CTRL_DATA_DEF,
> -                                              xctrl);
> +       return __uvc_ctrl_get_fixed_compound(chain, mapping, ctrl, v4l2_which,
> +                                            xctrl);
>  }
>
>  int __uvc_ctrl_set_compound(struct uvc_control_mapping *mapping,
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index aad61af36271..004e3b764737 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1043,16 +1043,21 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
>         if (ret < 0)
>                 return ret;
>
> -       if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
> +       switch (ctrls->which) {
> +       case V4L2_CTRL_WHICH_DEF_VAL:
> +       case V4L2_CTRL_WHICH_MIN_VAL:
> +       case V4L2_CTRL_WHICH_MAX_VAL:
>                 for (i = 0; i < ctrls->count; ++ctrl, ++i) {
> -                       ret = uvc_ctrl_get_fixed(chain, ctrl);
> +                       ret = uvc_ctrl_get_fixed(chain, ctrl, ctrls->which);
>                         if (ret < 0) {
>                                 ctrls->error_idx = i;
>                                 return ret;
>                         }
>                 }
> -
>                 return 0;
> +
> +       default:
> +               break;
>         }
>
>         ret = uvc_ctrl_begin(chain);
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 9ff95bbad251..54cc47bc2d33 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -913,7 +913,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
>
>  int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
>  int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
> -                      struct v4l2_ext_control *xctrl);
> +                      struct v4l2_ext_control *xctrl,
> +                      u32 v4l2_which);
>  int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
>  int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
>                            bool read);
> --
> 2.37.0.rc0.161.g10f37bed90-goog
>
Laurent Pinchart Aug. 24, 2022, 8:03 p.m. UTC | #2
Hi Yunke,

Thank you for the patch.

On Tue, Jun 28, 2022 at 04:57:04PM +0900, Yunke Cao wrote:
> Add support for V4L2_CTRL_WHICH_MIN/MAX_VAL in uvc driver.
> It is useful for the V4L2_CID_UVC_REGION_OF_INTEREST_RECT control.
> 
> Signed-off-by: Yunke Cao <yunkec@google.com>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 73 ++++++++++++++++++++++++++------
>  drivers/media/usb/uvc/uvc_v4l2.c | 11 +++--
>  drivers/media/usb/uvc/uvcvideo.h |  3 +-
>  3 files changed, 70 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 00482269233a..b569d6824ac1 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1923,7 +1923,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
>  }
>  
>  int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
> -			     struct v4l2_ext_control *xctrl)
> +			     struct v4l2_ext_control *xctrl, u32 v4l2_which)
>  {
>  	struct v4l2_queryctrl qc = { .id = xctrl->id };
>  	int ret = uvc_query_v4l2_ctrl(chain, &qc);
> @@ -1931,16 +1931,69 @@ int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
>  	if (ret < 0)
>  		return ret;
>  
> -	xctrl->value = qc.default_value;
> +	switch (v4l2_which) {
> +	case V4L2_CTRL_WHICH_DEF_VAL:
> +		xctrl->value = qc.default_value;
> +		break;
> +	case V4L2_CTRL_WHICH_MIN_VAL:
> +		xctrl->value = qc.minimum;
> +		break;
> +	case V4L2_CTRL_WHICH_MAX_VAL:
> +		xctrl->value = qc.maximum;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
>  	return 0;
>  }
>  
> +static int __uvc_ctrl_get_fixed_compound(struct uvc_video_chain *chain,
> +					 struct uvc_control_mapping *mapping,
> +					 struct uvc_control *ctrl,
> +					 u32 v4l2_which,
> +					 struct v4l2_ext_control *xctrl)
> +{
> +	int ret;
> +	u32 flag, id;
> +
> +	if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
> +		return -EINVAL;
> +

This can't happen.

> +	switch (v4l2_which) {
> +	case V4L2_CTRL_WHICH_DEF_VAL:
> +		flag = UVC_CTRL_FLAG_GET_DEF;
> +		id = UVC_CTRL_DATA_DEF;
> +		break;
> +	case V4L2_CTRL_WHICH_MIN_VAL:
> +		flag = UVC_CTRL_FLAG_GET_MIN;
> +		id = UVC_CTRL_DATA_MIN;
> +		break;
> +	case V4L2_CTRL_WHICH_MAX_VAL:
> +		flag = UVC_CTRL_FLAG_GET_MAX;
> +		id = UVC_CTRL_DATA_MAX;
> +		break;
> +	default:
> +		return -EINVAL;

Can this happen ?

> +	}
> +
> +	if (!(ctrl->info.flags & flag) && flag != UVC_CTRL_FLAG_GET_DEF)
> +		return -EACCES;
> +
> +	if (!ctrl->cached) {
> +		ret = uvc_ctrl_populate_cache(chain, ctrl);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return __uvc_ctrl_get_compound_to_user(mapping, ctrl, id, xctrl);
> +}
> +
>  int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
> -		       struct v4l2_ext_control *xctrl)
> +		       struct v4l2_ext_control *xctrl, u32 v4l2_which)
>  {
>  	struct uvc_control *ctrl;
>  	struct uvc_control_mapping *mapping;
> -	int ret;
>  
>  	if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
>  		return -EACCES;
> @@ -1950,16 +2003,10 @@ int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
>  		return -EINVAL;
>  
>  	if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
> -		return __uvc_ctrl_get_fixed_std(chain, xctrl);
> +		return __uvc_ctrl_get_fixed_std(chain, xctrl, v4l2_which);
>  
> -	if (!ctrl->cached) {
> -		ret = uvc_ctrl_populate_cache(chain, ctrl);
> -		if (ret < 0)
> -			return ret;
> -	}
> -
> -	return __uvc_ctrl_get_compound_to_user(mapping, ctrl, UVC_CTRL_DATA_DEF,
> -					       xctrl);
> +	return __uvc_ctrl_get_fixed_compound(chain, mapping, ctrl, v4l2_which,
> +					     xctrl);
>  }
>  
>  int __uvc_ctrl_set_compound(struct uvc_control_mapping *mapping,
> diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> index aad61af36271..004e3b764737 100644
> --- a/drivers/media/usb/uvc/uvc_v4l2.c
> +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> @@ -1043,16 +1043,21 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
>  	if (ret < 0)
>  		return ret;
>  
> -	if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
> +	switch (ctrls->which) {
> +	case V4L2_CTRL_WHICH_DEF_VAL:
> +	case V4L2_CTRL_WHICH_MIN_VAL:
> +	case V4L2_CTRL_WHICH_MAX_VAL:
>  		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
> -			ret = uvc_ctrl_get_fixed(chain, ctrl);
> +			ret = uvc_ctrl_get_fixed(chain, ctrl, ctrls->which);
>  			if (ret < 0) {
>  				ctrls->error_idx = i;
>  				return ret;
>  			}
>  		}
> -
>  		return 0;
> +
> +	default:

	case V4L2_CTRL_WHICH_CUR_VAL:

> +		break;

and

	default:
		return -EINVAL;

(please double-check that the error value is the right one). This should
be mentioned in the commit message.

>  	}
>  
>  	ret = uvc_ctrl_begin(chain);
> diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> index 9ff95bbad251..54cc47bc2d33 100644
> --- a/drivers/media/usb/uvc/uvcvideo.h
> +++ b/drivers/media/usb/uvc/uvcvideo.h
> @@ -913,7 +913,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
>  
>  int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
>  int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
> -		       struct v4l2_ext_control *xctrl);
> +		       struct v4l2_ext_control *xctrl,
> +		       u32 v4l2_which);
>  int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
>  int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
>  			   bool read);
Yunke Cao Sept. 20, 2022, 7:52 a.m. UTC | #3
Hi Laurent,

Thanks for the review.

On Thu, Aug 25, 2022 at 5:04 AM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Yunke,
>
> Thank you for the patch.
>
> On Tue, Jun 28, 2022 at 04:57:04PM +0900, Yunke Cao wrote:
> > Add support for V4L2_CTRL_WHICH_MIN/MAX_VAL in uvc driver.
> > It is useful for the V4L2_CID_UVC_REGION_OF_INTEREST_RECT control.
> >
> > Signed-off-by: Yunke Cao <yunkec@google.com>
> > ---
> >  drivers/media/usb/uvc/uvc_ctrl.c | 73 ++++++++++++++++++++++++++------
> >  drivers/media/usb/uvc/uvc_v4l2.c | 11 +++--
> >  drivers/media/usb/uvc/uvcvideo.h |  3 +-
> >  3 files changed, 70 insertions(+), 17 deletions(-)
> >
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> > index 00482269233a..b569d6824ac1 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -1923,7 +1923,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
> >  }
> >
> >  int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
> > -                          struct v4l2_ext_control *xctrl)
> > +                          struct v4l2_ext_control *xctrl, u32 v4l2_which)
> >  {
> >       struct v4l2_queryctrl qc = { .id = xctrl->id };
> >       int ret = uvc_query_v4l2_ctrl(chain, &qc);
> > @@ -1931,16 +1931,69 @@ int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
> >       if (ret < 0)
> >               return ret;
> >
> > -     xctrl->value = qc.default_value;
> > +     switch (v4l2_which) {
> > +     case V4L2_CTRL_WHICH_DEF_VAL:
> > +             xctrl->value = qc.default_value;
> > +             break;
> > +     case V4L2_CTRL_WHICH_MIN_VAL:
> > +             xctrl->value = qc.minimum;
> > +             break;
> > +     case V4L2_CTRL_WHICH_MAX_VAL:
> > +             xctrl->value = qc.maximum;
> > +             break;
> > +     default:
> > +             return -EINVAL;
> > +     }
> > +
> >       return 0;
> >  }
> >
> > +static int __uvc_ctrl_get_fixed_compound(struct uvc_video_chain *chain,
> > +                                      struct uvc_control_mapping *mapping,
> > +                                      struct uvc_control *ctrl,
> > +                                      u32 v4l2_which,
> > +                                      struct v4l2_ext_control *xctrl)
> > +{
> > +     int ret;
> > +     u32 flag, id;
> > +
> > +     if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
> > +             return -EINVAL;
> > +
>
> This can't happen.
>
> > +     switch (v4l2_which) {
> > +     case V4L2_CTRL_WHICH_DEF_VAL:
> > +             flag = UVC_CTRL_FLAG_GET_DEF;
> > +             id = UVC_CTRL_DATA_DEF;
> > +             break;
> > +     case V4L2_CTRL_WHICH_MIN_VAL:
> > +             flag = UVC_CTRL_FLAG_GET_MIN;
> > +             id = UVC_CTRL_DATA_MIN;
> > +             break;
> > +     case V4L2_CTRL_WHICH_MAX_VAL:
> > +             flag = UVC_CTRL_FLAG_GET_MAX;
> > +             id = UVC_CTRL_DATA_MAX;
> > +             break;
> > +     default:
> > +             return -EINVAL;
>
> Can this happen ?
>

Will remove.

> > +     }
> > +
> > +     if (!(ctrl->info.flags & flag) && flag != UVC_CTRL_FLAG_GET_DEF)
> > +             return -EACCES;
> > +
> > +     if (!ctrl->cached) {
> > +             ret = uvc_ctrl_populate_cache(chain, ctrl);
> > +             if (ret < 0)
> > +                     return ret;
> > +     }
> > +
> > +     return __uvc_ctrl_get_compound_to_user(mapping, ctrl, id, xctrl);
> > +}
> > +
> >  int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
> > -                    struct v4l2_ext_control *xctrl)
> > +                    struct v4l2_ext_control *xctrl, u32 v4l2_which)
> >  {
> >       struct uvc_control *ctrl;
> >       struct uvc_control_mapping *mapping;
> > -     int ret;
> >
> >       if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
> >               return -EACCES;
> > @@ -1950,16 +2003,10 @@ int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
> >               return -EINVAL;
> >
> >       if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
> > -             return __uvc_ctrl_get_fixed_std(chain, xctrl);
> > +             return __uvc_ctrl_get_fixed_std(chain, xctrl, v4l2_which);
> >
> > -     if (!ctrl->cached) {
> > -             ret = uvc_ctrl_populate_cache(chain, ctrl);
> > -             if (ret < 0)
> > -                     return ret;
> > -     }
> > -
> > -     return __uvc_ctrl_get_compound_to_user(mapping, ctrl, UVC_CTRL_DATA_DEF,
> > -                                            xctrl);
> > +     return __uvc_ctrl_get_fixed_compound(chain, mapping, ctrl, v4l2_which,
> > +                                          xctrl);
> >  }
> >
> >  int __uvc_ctrl_set_compound(struct uvc_control_mapping *mapping,
> > diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
> > index aad61af36271..004e3b764737 100644
> > --- a/drivers/media/usb/uvc/uvc_v4l2.c
> > +++ b/drivers/media/usb/uvc/uvc_v4l2.c
> > @@ -1043,16 +1043,21 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
> >       if (ret < 0)
> >               return ret;
> >
> > -     if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
> > +     switch (ctrls->which) {
> > +     case V4L2_CTRL_WHICH_DEF_VAL:
> > +     case V4L2_CTRL_WHICH_MIN_VAL:
> > +     case V4L2_CTRL_WHICH_MAX_VAL:
> >               for (i = 0; i < ctrls->count; ++ctrl, ++i) {
> > -                     ret = uvc_ctrl_get_fixed(chain, ctrl);
> > +                     ret = uvc_ctrl_get_fixed(chain, ctrl, ctrls->which);
> >                       if (ret < 0) {
> >                               ctrls->error_idx = i;
> >                               return ret;
> >                       }
> >               }
> > -
> >               return 0;
> > +
> > +     default:
>
>         case V4L2_CTRL_WHICH_CUR_VAL:
>
> > +             break;
>
> and
>
>         default:
>                 return -EINVAL;
>
> (please double-check that the error value is the right one). This should
> be mentioned in the commit message.
>

Thanks for catching this!
What specifictly should be in the commit message? Sorry, I didn't get it.

Best,
Yunke

> >       }
> >
> >       ret = uvc_ctrl_begin(chain);
> > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
> > index 9ff95bbad251..54cc47bc2d33 100644
> > --- a/drivers/media/usb/uvc/uvcvideo.h
> > +++ b/drivers/media/usb/uvc/uvcvideo.h
> > @@ -913,7 +913,8 @@ static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
> >
> >  int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
> >  int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
> > -                    struct v4l2_ext_control *xctrl);
> > +                    struct v4l2_ext_control *xctrl,
> > +                    u32 v4l2_which);
> >  int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
> >  int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
> >                          bool read);
>
> --
> Regards,
>
> Laurent Pinchart
diff mbox series

Patch

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 00482269233a..b569d6824ac1 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1923,7 +1923,7 @@  int uvc_ctrl_get(struct uvc_video_chain *chain,
 }
 
 int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
-			     struct v4l2_ext_control *xctrl)
+			     struct v4l2_ext_control *xctrl, u32 v4l2_which)
 {
 	struct v4l2_queryctrl qc = { .id = xctrl->id };
 	int ret = uvc_query_v4l2_ctrl(chain, &qc);
@@ -1931,16 +1931,69 @@  int __uvc_ctrl_get_fixed_std(struct uvc_video_chain *chain,
 	if (ret < 0)
 		return ret;
 
-	xctrl->value = qc.default_value;
+	switch (v4l2_which) {
+	case V4L2_CTRL_WHICH_DEF_VAL:
+		xctrl->value = qc.default_value;
+		break;
+	case V4L2_CTRL_WHICH_MIN_VAL:
+		xctrl->value = qc.minimum;
+		break;
+	case V4L2_CTRL_WHICH_MAX_VAL:
+		xctrl->value = qc.maximum;
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
+static int __uvc_ctrl_get_fixed_compound(struct uvc_video_chain *chain,
+					 struct uvc_control_mapping *mapping,
+					 struct uvc_control *ctrl,
+					 u32 v4l2_which,
+					 struct v4l2_ext_control *xctrl)
+{
+	int ret;
+	u32 flag, id;
+
+	if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
+		return -EINVAL;
+
+	switch (v4l2_which) {
+	case V4L2_CTRL_WHICH_DEF_VAL:
+		flag = UVC_CTRL_FLAG_GET_DEF;
+		id = UVC_CTRL_DATA_DEF;
+		break;
+	case V4L2_CTRL_WHICH_MIN_VAL:
+		flag = UVC_CTRL_FLAG_GET_MIN;
+		id = UVC_CTRL_DATA_MIN;
+		break;
+	case V4L2_CTRL_WHICH_MAX_VAL:
+		flag = UVC_CTRL_FLAG_GET_MAX;
+		id = UVC_CTRL_DATA_MAX;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (!(ctrl->info.flags & flag) && flag != UVC_CTRL_FLAG_GET_DEF)
+		return -EACCES;
+
+	if (!ctrl->cached) {
+		ret = uvc_ctrl_populate_cache(chain, ctrl);
+		if (ret < 0)
+			return ret;
+	}
+
+	return __uvc_ctrl_get_compound_to_user(mapping, ctrl, id, xctrl);
+}
+
 int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
-		       struct v4l2_ext_control *xctrl)
+		       struct v4l2_ext_control *xctrl, u32 v4l2_which)
 {
 	struct uvc_control *ctrl;
 	struct uvc_control_mapping *mapping;
-	int ret;
 
 	if (__uvc_query_v4l2_class(chain, xctrl->id, 0) >= 0)
 		return -EACCES;
@@ -1950,16 +2003,10 @@  int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
 		return -EINVAL;
 
 	if (mapping->v4l2_type < V4L2_CTRL_COMPOUND_TYPES)
-		return __uvc_ctrl_get_fixed_std(chain, xctrl);
+		return __uvc_ctrl_get_fixed_std(chain, xctrl, v4l2_which);
 
-	if (!ctrl->cached) {
-		ret = uvc_ctrl_populate_cache(chain, ctrl);
-		if (ret < 0)
-			return ret;
-	}
-
-	return __uvc_ctrl_get_compound_to_user(mapping, ctrl, UVC_CTRL_DATA_DEF,
-					       xctrl);
+	return __uvc_ctrl_get_fixed_compound(chain, mapping, ctrl, v4l2_which,
+					     xctrl);
 }
 
 int __uvc_ctrl_set_compound(struct uvc_control_mapping *mapping,
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index aad61af36271..004e3b764737 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -1043,16 +1043,21 @@  static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
 	if (ret < 0)
 		return ret;
 
-	if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
+	switch (ctrls->which) {
+	case V4L2_CTRL_WHICH_DEF_VAL:
+	case V4L2_CTRL_WHICH_MIN_VAL:
+	case V4L2_CTRL_WHICH_MAX_VAL:
 		for (i = 0; i < ctrls->count; ++ctrl, ++i) {
-			ret = uvc_ctrl_get_fixed(chain, ctrl);
+			ret = uvc_ctrl_get_fixed(chain, ctrl, ctrls->which);
 			if (ret < 0) {
 				ctrls->error_idx = i;
 				return ret;
 			}
 		}
-
 		return 0;
+
+	default:
+		break;
 	}
 
 	ret = uvc_ctrl_begin(chain);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 9ff95bbad251..54cc47bc2d33 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -913,7 +913,8 @@  static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
 
 int uvc_ctrl_get(struct uvc_video_chain *chain, struct v4l2_ext_control *xctrl);
 int uvc_ctrl_get_fixed(struct uvc_video_chain *chain,
-		       struct v4l2_ext_control *xctrl);
+		       struct v4l2_ext_control *xctrl,
+		       u32 v4l2_which);
 int uvc_ctrl_set(struct uvc_fh *handle, struct v4l2_ext_control *xctrl);
 int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
 			   bool read);