uvcvideo: Apply flags from device to actual properties

Message ID 7807bf0a-a0a1-65ad-1a10-3a3234e566e9@edgarthier.net (mailing list archive)
State Superseded, archived
Delegated to: Laurent Pinchart
Headers

Commit Message

Edgar Thier Oct. 12, 2017, 7:54 a.m. UTC
  Use flags the device exposes for UVC controls.
This allows the device to define which property flags are set.

Since some cameras offer auto-adjustments for properties (e.g. auto-gain),
the values of other properties (e.g. gain) can change in the camera.
Examining the flags ensures that the driver is aware of such properties.

Signed-off-by: Edgar Thier <info@edgarthier.net>
---
 drivers/media/usb/uvc/uvc_ctrl.c | 64 ++++++++++++++++++++++++++++++----------
 1 file changed, 49 insertions(+), 15 deletions(-)
  

Comments

Edgar Thier Nov. 15, 2017, 8:11 a.m. UTC | #1
Hi,

I was wondering if there are any problems with my latest patch or if it simply slipped through.

Regards,

Edgar

On 10/12/2017 09:54 AM, Edgar Thier wrote:
> 
> Use flags the device exposes for UVC controls.
> This allows the device to define which property flags are set.
> 
> Since some cameras offer auto-adjustments for properties (e.g. auto-gain),
> the values of other properties (e.g. gain) can change in the camera.
> Examining the flags ensures that the driver is aware of such properties.
> 
> Signed-off-by: Edgar Thier <info@edgarthier.net>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 64 ++++++++++++++++++++++++++++++----------
>  1 file changed, 49 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 20397aba..8f902a41 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1629,6 +1629,40 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
>  	}
>  }
> 
> +/*
> + * Retrieve flags for a given control
> + */
> +static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct uvc_control *ctrl,
> +	const struct uvc_control_info *info)
> +{
> +	u8 *data;
> +	int ret = 0;
> +	int flags = 0;
> +
> +	data = kmalloc(2, GFP_KERNEL);
> +	if (data == NULL)
> +		return -ENOMEM;
> +
> +	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> +						 info->selector, data, 1);
> +	if (ret < 0) {
> +		uvc_trace(UVC_TRACE_CONTROL,
> +				  "GET_INFO failed on control %pUl/%u (%d).\n",
> +				  info->entity, info->selector, ret);
> +	} else {
> +		flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> +			| UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> +			| (data[0] & UVC_CONTROL_CAP_GET ?
> +			   UVC_CTRL_FLAG_GET_CUR : 0)
> +			| (data[0] & UVC_CONTROL_CAP_SET ?
> +			   UVC_CTRL_FLAG_SET_CUR : 0)
> +			| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> +			   UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> +	}
> +	kfree(data);
> +	return flags;
> +}
> +
>  /*
>   * Query control information (size and flags) for XU controls.
>   */
> @@ -1636,6 +1670,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
>  	const struct uvc_control *ctrl, struct uvc_control_info *info)
>  {
>  	u8 *data;
> +	int flags;
>  	int ret;
> 
>  	data = kmalloc(2, GFP_KERNEL);
> @@ -1659,24 +1694,15 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
> 
>  	info->size = le16_to_cpup((__le16 *)data);
> 
> -	/* Query the control information (GET_INFO) */
> -	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> -			     info->selector, data, 1);
> -	if (ret < 0) {
> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> +
> +	if (flags < 0) {
>  		uvc_trace(UVC_TRACE_CONTROL,
> -			  "GET_INFO failed on control %pUl/%u (%d).\n",
> -			  info->entity, info->selector, ret);
> +			  "Failed to retrieve flags (%d).\n", ret);
> + 		ret = flags;
>  		goto done;
>  	}
> -
> -	info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> -		    | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> -		    | (data[0] & UVC_CONTROL_CAP_GET ?
> -		       UVC_CTRL_FLAG_GET_CUR : 0)
> -		    | (data[0] & UVC_CONTROL_CAP_SET ?
> -		       UVC_CTRL_FLAG_SET_CUR : 0)
> -		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> -		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> +	info->flags = flags;
> 
>  	uvc_ctrl_fixup_xu_info(dev, ctrl, info);
> 
> @@ -1890,6 +1916,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>  	const struct uvc_control_info *info)
>  {
>  	int ret = 0;
> +	int flags = 0;
> 
>  	ctrl->info = *info;
>  	INIT_LIST_HEAD(&ctrl->info.mappings);
> @@ -1902,6 +1929,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>  		goto done;
>  	}
> 
> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> +	if (flags < 0)
> +		uvc_trace(UVC_TRACE_CONTROL,
> +			  "Failed to retrieve flags (%d).\n", ret);
> +	else
> +		ctrl->info.flags = flags;
> +
>  	ctrl->initialized = 1;
> 
>  	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
>
  
Kieran Bingham Nov. 15, 2017, 11:53 a.m. UTC | #2
Hi Edgar,

On 15/11/17 08:11, Edgar Thier wrote:
> Hi,
> 
> I was wondering if there are any problems with my latest patch or if it simply slipped through.

Slipped though in high mail volumes :)

I think it's easier to see updated patches if they are posted as a new thread,
with an increased version number. [PATCH v2], [PATCH v3] etc...

Not a problem now - but might help your updated patches get seen next time.

Looks like my concerns were addressed, so that's a Reviewed-by: tag from me.

--
Kieran

> 
> Regards,
> 
> Edgar
> 
> On 10/12/2017 09:54 AM, Edgar Thier wrote:
>>
>> Use flags the device exposes for UVC controls.
>> This allows the device to define which property flags are set.
>>
>> Since some cameras offer auto-adjustments for properties (e.g. auto-gain),
>> the values of other properties (e.g. gain) can change in the camera.
>> Examining the flags ensures that the driver is aware of such properties.
>>
>> Signed-off-by: Edgar Thier <info@edgarthier.net>
>> ---
>>  drivers/media/usb/uvc/uvc_ctrl.c | 64 ++++++++++++++++++++++++++++++----------
>>  1 file changed, 49 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>> index 20397aba..8f902a41 100644
>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>> @@ -1629,6 +1629,40 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
>>  	}
>>  }
>>
>> +/*
>> + * Retrieve flags for a given control
>> + */
>> +static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct uvc_control *ctrl,
>> +	const struct uvc_control_info *info)
>> +{
>> +	u8 *data;
>> +	int ret = 0;
>> +	int flags = 0;
>> +
>> +	data = kmalloc(2, GFP_KERNEL);
>> +	if (data == NULL)
>> +		return -ENOMEM;
>> +
>> +	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
>> +						 info->selector, data, 1);
>> +	if (ret < 0) {
>> +		uvc_trace(UVC_TRACE_CONTROL,
>> +				  "GET_INFO failed on control %pUl/%u (%d).\n",
>> +				  info->entity, info->selector, ret);
>> +	} else {
>> +		flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
>> +			| UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
>> +			| (data[0] & UVC_CONTROL_CAP_GET ?
>> +			   UVC_CTRL_FLAG_GET_CUR : 0)
>> +			| (data[0] & UVC_CONTROL_CAP_SET ?
>> +			   UVC_CTRL_FLAG_SET_CUR : 0)
>> +			| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
>> +			   UVC_CTRL_FLAG_AUTO_UPDATE : 0);
>> +	}
>> +	kfree(data);
>> +	return flags;
>> +}
>> +
>>  /*
>>   * Query control information (size and flags) for XU controls.
>>   */
>> @@ -1636,6 +1670,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
>>  	const struct uvc_control *ctrl, struct uvc_control_info *info)
>>  {
>>  	u8 *data;
>> +	int flags;
>>  	int ret;
>>
>>  	data = kmalloc(2, GFP_KERNEL);
>> @@ -1659,24 +1694,15 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
>>
>>  	info->size = le16_to_cpup((__le16 *)data);
>>
>> -	/* Query the control information (GET_INFO) */
>> -	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
>> -			     info->selector, data, 1);
>> -	if (ret < 0) {
>> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
>> +
>> +	if (flags < 0) {
>>  		uvc_trace(UVC_TRACE_CONTROL,
>> -			  "GET_INFO failed on control %pUl/%u (%d).\n",
>> -			  info->entity, info->selector, ret);
>> +			  "Failed to retrieve flags (%d).\n", ret);
>> + 		ret = flags;
>>  		goto done;
>>  	}
>> -
>> -	info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
>> -		    | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
>> -		    | (data[0] & UVC_CONTROL_CAP_GET ?
>> -		       UVC_CTRL_FLAG_GET_CUR : 0)
>> -		    | (data[0] & UVC_CONTROL_CAP_SET ?
>> -		       UVC_CTRL_FLAG_SET_CUR : 0)
>> -		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
>> -		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
>> +	info->flags = flags;
>>
>>  	uvc_ctrl_fixup_xu_info(dev, ctrl, info);
>>
>> @@ -1890,6 +1916,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>>  	const struct uvc_control_info *info)
>>  {
>>  	int ret = 0;
>> +	int flags = 0;
>>
>>  	ctrl->info = *info;
>>  	INIT_LIST_HEAD(&ctrl->info.mappings);
>> @@ -1902,6 +1929,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>>  		goto done;
>>  	}
>>
>> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
>> +	if (flags < 0)
>> +		uvc_trace(UVC_TRACE_CONTROL,
>> +			  "Failed to retrieve flags (%d).\n", ret);
>> +	else
>> +		ctrl->info.flags = flags;
>> +
>>  	ctrl->initialized = 1;
>>
>>  	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
>>
  
Kieran Bingham Nov. 15, 2017, 11:54 a.m. UTC | #3
Hi Edgar,

Thanks for addressing my concerns in this updated patch.

On 12/10/17 08:54, Edgar Thier wrote:
> 
> Use flags the device exposes for UVC controls.
> This allows the device to define which property flags are set.
> 
> Since some cameras offer auto-adjustments for properties (e.g. auto-gain),
> the values of other properties (e.g. gain) can change in the camera.
> Examining the flags ensures that the driver is aware of such properties.
> 
> Signed-off-by: Edgar Thier <info@edgarthier.net>

Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>

> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 64 ++++++++++++++++++++++++++++++----------
>  1 file changed, 49 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
> index 20397aba..8f902a41 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1629,6 +1629,40 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
>  	}
>  }
> 
> +/*
> + * Retrieve flags for a given control
> + */
> +static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct uvc_control *ctrl,
> +	const struct uvc_control_info *info)
> +{
> +	u8 *data;
> +	int ret = 0;
> +	int flags = 0;
> +
> +	data = kmalloc(2, GFP_KERNEL);
> +	if (data == NULL)
> +		return -ENOMEM;
> +
> +	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> +						 info->selector, data, 1);
> +	if (ret < 0) {
> +		uvc_trace(UVC_TRACE_CONTROL,
> +				  "GET_INFO failed on control %pUl/%u (%d).\n",
> +				  info->entity, info->selector, ret);
> +	} else {
> +		flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> +			| UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> +			| (data[0] & UVC_CONTROL_CAP_GET ?
> +			   UVC_CTRL_FLAG_GET_CUR : 0)
> +			| (data[0] & UVC_CONTROL_CAP_SET ?
> +			   UVC_CTRL_FLAG_SET_CUR : 0)
> +			| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> +			   UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> +	}
> +	kfree(data);
> +	return flags;
> +}
> +
>  /*
>   * Query control information (size and flags) for XU controls.
>   */
> @@ -1636,6 +1670,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
>  	const struct uvc_control *ctrl, struct uvc_control_info *info)
>  {
>  	u8 *data;
> +	int flags;
>  	int ret;
> 
>  	data = kmalloc(2, GFP_KERNEL);
> @@ -1659,24 +1694,15 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
> 
>  	info->size = le16_to_cpup((__le16 *)data);
> 
> -	/* Query the control information (GET_INFO) */
> -	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> -			     info->selector, data, 1);
> -	if (ret < 0) {
> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> +
> +	if (flags < 0) {
>  		uvc_trace(UVC_TRACE_CONTROL,
> -			  "GET_INFO failed on control %pUl/%u (%d).\n",
> -			  info->entity, info->selector, ret);
> +			  "Failed to retrieve flags (%d).\n", ret);
> + 		ret = flags;
>  		goto done;
>  	}
> -
> -	info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> -		    | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> -		    | (data[0] & UVC_CONTROL_CAP_GET ?
> -		       UVC_CTRL_FLAG_GET_CUR : 0)
> -		    | (data[0] & UVC_CONTROL_CAP_SET ?
> -		       UVC_CTRL_FLAG_SET_CUR : 0)
> -		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> -		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> +	info->flags = flags;
> 
>  	uvc_ctrl_fixup_xu_info(dev, ctrl, info);
> 
> @@ -1890,6 +1916,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>  	const struct uvc_control_info *info)
>  {
>  	int ret = 0;
> +	int flags = 0;
> 
>  	ctrl->info = *info;
>  	INIT_LIST_HEAD(&ctrl->info.mappings);
> @@ -1902,6 +1929,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>  		goto done;
>  	}
> 
> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> +	if (flags < 0)
> +		uvc_trace(UVC_TRACE_CONTROL,
> +			  "Failed to retrieve flags (%d).\n", ret);
> +	else
> +		ctrl->info.flags = flags;
> +
>  	ctrl->initialized = 1;
> 
>  	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
>
  
Edgar Thier Nov. 15, 2017, 12:01 p.m. UTC | #4
Hi Kieran,

> I think it's easier to see updated patches if they are posted as a new thread,
> with an increased version number. [PATCH v2], [PATCH v3] etc...
>
> Not a problem now - but might help your updated patches get seen next time.

I will keep that in mind for next time. :)

> Looks like my concerns were addressed, so that's a Reviewed-by: tag from me.

Thanks!

Regards,

Edgar
  
Edgar Thier Dec. 15, 2017, 7:07 a.m. UTC | #5
Hi,

Another month, another mail. Are there still issues keeping this from being merged?

Regards,

Edgar

On 11/15/2017 12:54 PM, Kieran Bingham wrote:
> Hi Edgar,
> 
> Thanks for addressing my concerns in this updated patch.
> 
> On 12/10/17 08:54, Edgar Thier wrote:
>>
>> Use flags the device exposes for UVC controls.
>> This allows the device to define which property flags are set.
>>
>> Since some cameras offer auto-adjustments for properties (e.g. auto-gain),
>> the values of other properties (e.g. gain) can change in the camera.
>> Examining the flags ensures that the driver is aware of such properties.
>>
>> Signed-off-by: Edgar Thier <info@edgarthier.net>
> 
> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> 
>> ---
>>  drivers/media/usb/uvc/uvc_ctrl.c | 64 ++++++++++++++++++++++++++++++----------
>>  1 file changed, 49 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
>> index 20397aba..8f902a41 100644
>> --- a/drivers/media/usb/uvc/uvc_ctrl.c
>> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
>> @@ -1629,6 +1629,40 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
>>  	}
>>  }
>>
>> +/*
>> + * Retrieve flags for a given control
>> + */
>> +static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct uvc_control *ctrl,
>> +	const struct uvc_control_info *info)
>> +{
>> +	u8 *data;
>> +	int ret = 0;
>> +	int flags = 0;
>> +
>> +	data = kmalloc(2, GFP_KERNEL);
>> +	if (data == NULL)
>> +		return -ENOMEM;
>> +
>> +	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
>> +						 info->selector, data, 1);
>> +	if (ret < 0) {
>> +		uvc_trace(UVC_TRACE_CONTROL,
>> +				  "GET_INFO failed on control %pUl/%u (%d).\n",
>> +				  info->entity, info->selector, ret);
>> +	} else {
>> +		flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
>> +			| UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
>> +			| (data[0] & UVC_CONTROL_CAP_GET ?
>> +			   UVC_CTRL_FLAG_GET_CUR : 0)
>> +			| (data[0] & UVC_CONTROL_CAP_SET ?
>> +			   UVC_CTRL_FLAG_SET_CUR : 0)
>> +			| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
>> +			   UVC_CTRL_FLAG_AUTO_UPDATE : 0);
>> +	}
>> +	kfree(data);
>> +	return flags;
>> +}
>> +
>>  /*
>>   * Query control information (size and flags) for XU controls.
>>   */
>> @@ -1636,6 +1670,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
>>  	const struct uvc_control *ctrl, struct uvc_control_info *info)
>>  {
>>  	u8 *data;
>> +	int flags;
>>  	int ret;
>>
>>  	data = kmalloc(2, GFP_KERNEL);
>> @@ -1659,24 +1694,15 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
>>
>>  	info->size = le16_to_cpup((__le16 *)data);
>>
>> -	/* Query the control information (GET_INFO) */
>> -	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
>> -			     info->selector, data, 1);
>> -	if (ret < 0) {
>> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
>> +
>> +	if (flags < 0) {
>>  		uvc_trace(UVC_TRACE_CONTROL,
>> -			  "GET_INFO failed on control %pUl/%u (%d).\n",
>> -			  info->entity, info->selector, ret);
>> +			  "Failed to retrieve flags (%d).\n", ret);
>> + 		ret = flags;
>>  		goto done;
>>  	}
>> -
>> -	info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
>> -		    | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
>> -		    | (data[0] & UVC_CONTROL_CAP_GET ?
>> -		       UVC_CTRL_FLAG_GET_CUR : 0)
>> -		    | (data[0] & UVC_CONTROL_CAP_SET ?
>> -		       UVC_CTRL_FLAG_SET_CUR : 0)
>> -		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
>> -		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
>> +	info->flags = flags;
>>
>>  	uvc_ctrl_fixup_xu_info(dev, ctrl, info);
>>
>> @@ -1890,6 +1916,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>>  	const struct uvc_control_info *info)
>>  {
>>  	int ret = 0;
>> +	int flags = 0;
>>
>>  	ctrl->info = *info;
>>  	INIT_LIST_HEAD(&ctrl->info.mappings);
>> @@ -1902,6 +1929,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
>>  		goto done;
>>  	}
>>
>> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
>> +	if (flags < 0)
>> +		uvc_trace(UVC_TRACE_CONTROL,
>> +			  "Failed to retrieve flags (%d).\n", ret);
>> +	else
>> +		ctrl->info.flags = flags;
>> +
>>  	ctrl->initialized = 1;
>>
>>  	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
>>
  
Laurent Pinchart Jan. 2, 2018, 8:07 p.m. UTC | #6
Hi Edgar,

Thank you for the patch.

On Thursday, 12 October 2017 10:54:17 EET Edgar Thier wrote:
> Use flags the device exposes for UVC controls.
> This allows the device to define which property flags are set.
> 
> Since some cameras offer auto-adjustments for properties (e.g. auto-gain),
> the values of other properties (e.g. gain) can change in the camera.
> Examining the flags ensures that the driver is aware of such properties.
> 
> Signed-off-by: Edgar Thier <info@edgarthier.net>
> ---
>  drivers/media/usb/uvc/uvc_ctrl.c | 64 +++++++++++++++++++++++++++----------
>  1 file changed, 49 insertions(+), 15 deletions(-)

Running scripts/checkpatch.pl on the patch produces the following warning and 
errors.

WARNING: line over 80 characters
#83: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1635:
+static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct 
uvc_control *ctrl,

ERROR: code indent should use tabs where possible
#140: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1702:
+ ^I^Iret = flags;$

WARNING: please, no space before tabs
#140: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1702:
+ ^I^Iret = flags;$

WARNING: please, no spaces at the start of a line
#140: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1702:
+ ^I^Iret = flags;$

The last three should be fixed. The first one can sometimes be considered a 
matter of taste, but in this case it's easy to fix so we should address it 
too.

> diff --git a/drivers/media/usb/uvc/uvc_ctrl.c
> b/drivers/media/usb/uvc/uvc_ctrl.c index 20397aba..8f902a41 100644
> --- a/drivers/media/usb/uvc/uvc_ctrl.c
> +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> @@ -1629,6 +1629,40 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device
> *dev, }
>  }
> 
> +/*
> + * Retrieve flags for a given control
> + */
> +static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct
> uvc_control *ctrl,
> +	const struct uvc_control_info *info)
> +{
> +	u8 *data;
> +	int ret = 0;

No need to initialize ret to 0.

> +	int flags = 0;
> +
> +	data = kmalloc(2, GFP_KERNEL);
> +	if (data == NULL)
> +		return -ENOMEM;
> +
> +	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> +						 info->selector, data, 1);
> +	if (ret < 0) {
> +		uvc_trace(UVC_TRACE_CONTROL,
> +				  "GET_INFO failed on control %pUl/%u (%d).\n",
> +				  info->entity, info->selector, ret);
> +	} else {
> +		flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> +			| UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> +			| (data[0] & UVC_CONTROL_CAP_GET ?
> +			   UVC_CTRL_FLAG_GET_CUR : 0)
> +			| (data[0] & UVC_CONTROL_CAP_SET ?
> +			   UVC_CTRL_FLAG_SET_CUR : 0)
> +			| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> +			   UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> +	}
> +	kfree(data);
> +	return flags;

So in case of failure you will return 0, and the caller will ignore the 
failure. This changes the behaviour of uvc_ctrl_fill_xu_info() which I don't 
think is a good idea. For uvc_ctrl_add_info(), on the other hand, ignoring 
errors is probably good, as otherwise we could introduce regressions with 
devices that don't implement GET_INFO properly on standard controls (the 
driver currently doesn't query information for standard controls so doesn't 
catch those devices).

> +}
> +
>  /*
>   * Query control information (size and flags) for XU controls.
>   */
> @@ -1636,6 +1670,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device
> *dev, const struct uvc_control *ctrl, struct uvc_control_info *info)
>  {
>  	u8 *data;
> +	int flags;
>  	int ret;
> 
>  	data = kmalloc(2, GFP_KERNEL);
> @@ -1659,24 +1694,15 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device
> *dev,
> 
>  	info->size = le16_to_cpup((__le16 *)data);
> 
> -	/* Query the control information (GET_INFO) */
> -	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> -			     info->selector, data, 1);
> -	if (ret < 0) {
> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> +

No need for a blank line here.

> +	if (flags < 0) {
>  		uvc_trace(UVC_TRACE_CONTROL,
> -			  "GET_INFO failed on control %pUl/%u (%d).\n",
> -			  info->entity, info->selector, ret);
> +			  "Failed to retrieve flags (%d).\n", ret);
> + 		ret = flags;
>  		goto done;
>  	}
> -
> -	info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> -		    | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> -		    | (data[0] & UVC_CONTROL_CAP_GET ?
> -		       UVC_CTRL_FLAG_GET_CUR : 0)
> -		    | (data[0] & UVC_CONTROL_CAP_SET ?
> -		       UVC_CTRL_FLAG_SET_CUR : 0)
> -		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> -		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> +	info->flags = flags;
> 
>  	uvc_ctrl_fixup_xu_info(dev, ctrl, info);
> 
> @@ -1890,6 +1916,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev,
> struct uvc_control *ctrl, const struct uvc_control_info *info)
>  {
>  	int ret = 0;
> +	int flags = 0;

There's no need to initialize the flags variable to 0.

> 
>  	ctrl->info = *info;
>  	INIT_LIST_HEAD(&ctrl->info.mappings);
> @@ -1902,6 +1929,13 @@ static int uvc_ctrl_add_info(struct uvc_device *dev,
> struct uvc_control *ctrl, goto done;
>  	}
> 
> +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> +	if (flags < 0)
> +		uvc_trace(UVC_TRACE_CONTROL,
> +			  "Failed to retrieve flags (%d).\n", ret);
> +	else
> +		ctrl->info.flags = flags;
> +
>  	ctrl->initialized = 1;
> 
>  	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "

All these are small issues. Let me try to address them, I'll send you an 
updated patch shortly.
  
Laurent Pinchart Jan. 2, 2018, 11:33 p.m. UTC | #7
Hi Edgar,

A few more comments.

On Tuesday, 2 January 2018 22:07:24 EET Laurent Pinchart wrote:
> On Thursday, 12 October 2017 10:54:17 EET Edgar Thier wrote:
> > Use flags the device exposes for UVC controls.
> > This allows the device to define which property flags are set.
> > 
> > Since some cameras offer auto-adjustments for properties (e.g. auto-gain),
> > the values of other properties (e.g. gain) can change in the camera.
> > Examining the flags ensures that the driver is aware of such properties.
> > 
> > Signed-off-by: Edgar Thier <info@edgarthier.net>
> > ---
> > 
> >  drivers/media/usb/uvc/uvc_ctrl.c | 64 +++++++++++++++++++++++++----------
> >  1 file changed, 49 insertions(+), 15 deletions(-)
> 
> Running scripts/checkpatch.pl on the patch produces the following warning
> and errors.
> 
> WARNING: line over 80 characters
> #83: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1635:
> +static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct
> uvc_control *ctrl,
> 
> ERROR: code indent should use tabs where possible
> #140: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1702:
> + ^I^Iret = flags;$
> 
> WARNING: please, no space before tabs
> #140: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1702:
> + ^I^Iret = flags;$
> 
> WARNING: please, no spaces at the start of a line
> #140: FILE: drivers/media/usb/uvc/uvc_ctrl.c:1702:
> + ^I^Iret = flags;$
> 
> The last three should be fixed. The first one can sometimes be considered a
> matter of taste, but in this case it's easy to fix so we should address it
> too.
> 
> > diff --git a/drivers/media/usb/uvc/uvc_ctrl.c
> > b/drivers/media/usb/uvc/uvc_ctrl.c index 20397aba..8f902a41 100644
> > --- a/drivers/media/usb/uvc/uvc_ctrl.c
> > +++ b/drivers/media/usb/uvc/uvc_ctrl.c
> > @@ -1629,6 +1629,40 @@ static void uvc_ctrl_fixup_xu_info(struct
> > uvc_device
> > *dev, }
> > 
> >  }
> > 
> > +/*
> > + * Retrieve flags for a given control
> > + */
> > +static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct
> > uvc_control *ctrl,
> > +	const struct uvc_control_info *info)
> > +{
> > +	u8 *data;
> > +	int ret = 0;
> 
> No need to initialize ret to 0.
> 
> > +	int flags = 0;
> > +
> > +	data = kmalloc(2, GFP_KERNEL);

Isn't 1 byte enough ?

> > +	if (data == NULL)
> > +		return -ENOMEM;
> > +
> > +	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> > +						 info->selector, data, 1);

Indentation is incorrect here.

> > +	if (ret < 0) {
> > +		uvc_trace(UVC_TRACE_CONTROL,
> > +				  "GET_INFO failed on control %pUl/%u (%d).\n",
> > +				  info->entity, info->selector, ret);

And here too.

> > +	} else {
> > +		flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> > +			| UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> > +			| (data[0] & UVC_CONTROL_CAP_GET ?
> > +			   UVC_CTRL_FLAG_GET_CUR : 0)
> > +			| (data[0] & UVC_CONTROL_CAP_SET ?
> > +			   UVC_CTRL_FLAG_SET_CUR : 0)
> > +			| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> > +			   UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> > +	}
> > +	kfree(data);
> > +	return flags;
> 
> So in case of failure you will return 0, and the caller will ignore the
> failure. This changes the behaviour of uvc_ctrl_fill_xu_info() which I don't
> think is a good idea. For uvc_ctrl_add_info(), on the other hand, ignoring
> errors is probably good, as otherwise we could introduce regressions with
> devices that don't implement GET_INFO properly on standard controls (the
> driver currently doesn't query information for standard controls so doesn't
> catch those devices).
> 
> > +}
> > +
> >  /*
> >   * Query control information (size and flags) for XU controls.
> >   */
> > @@ -1636,6 +1670,7 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device
> > *dev, const struct uvc_control *ctrl, struct uvc_control_info *info)
> >  {
> >  	u8 *data;
> > +	int flags;
> >  	int ret;
> >  	
> >  	data = kmalloc(2, GFP_KERNEL);
> > @@ -1659,24 +1694,15 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device
> > *dev,
> > 
> >  	info->size = le16_to_cpup((__le16 *)data);
> > 
> > -	/* Query the control information (GET_INFO) */
> > -	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
> > -			     info->selector, data, 1);
> > -	if (ret < 0) {
> > +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> > +
> 
> No need for a blank line here.
> 
> > +	if (flags < 0) {
> >  		uvc_trace(UVC_TRACE_CONTROL,
> > -			  "GET_INFO failed on control %pUl/%u (%d).\n",
> > -			  info->entity, info->selector, ret);
> > +			  "Failed to retrieve flags (%d).\n", ret);
> > + 		ret = flags;
> >  		goto done;
> >  	}
> > -
> > -	info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
> > -		    | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
> > -		    | (data[0] & UVC_CONTROL_CAP_GET ?
> > -		       UVC_CTRL_FLAG_GET_CUR : 0)
> > -		    | (data[0] & UVC_CONTROL_CAP_SET ?
> > -		       UVC_CTRL_FLAG_SET_CUR : 0)
> > -		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
> > -		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
> > +	info->flags = flags;
> > 
> >  	uvc_ctrl_fixup_xu_info(dev, ctrl, info);
> > 
> > @@ -1890,6 +1916,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev,
> > struct uvc_control *ctrl, const struct uvc_control_info *info)
> >  {
> >  	int ret = 0;
> > +	int flags = 0;
> 
> There's no need to initialize the flags variable to 0.
> 
> >  	ctrl->info = *info;
> >  	INIT_LIST_HEAD(&ctrl->info.mappings);
> > 
> > @@ -1902,6 +1929,13 @@ static int uvc_ctrl_add_info(struct uvc_device
> > *dev, struct uvc_control *ctrl,
> >  		goto done;
> >  	}
> > 
> > +	flags = uvc_ctrl_get_flags(dev, ctrl, info);
> > +	if (flags < 0)
> > +		uvc_trace(UVC_TRACE_CONTROL,
> > +			  "Failed to retrieve flags (%d).\n", ret);
> > +	else
> > +		ctrl->info.flags = flags;
> > +
> >  	ctrl->initialized = 1;
> >  	
> >  	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
> 
> All these are small issues. Let me try to address them, I'll send you an
> updated patch shortly.
  
Edgar Thier Jan. 3, 2018, 6:07 a.m. UTC | #8
Hi Emmanuel,

>>> +	int flags = 0;
>>> +
>>> +	data = kmalloc(2, GFP_KERNEL);
> 
> Isn't 1 byte enough ?
> 

To quote from Kieran further up this thread:
>> kmalloc seems a bit of an overhead for 2 bytes (only one of which is used).
>> Can this use local stack storage?
>>
>> (Laurent, looks like you originally wrote the code that did that, was there a
>> reason for the kmalloc for 2 bytes?)
> Aha - OK, Just spoke with Laurent and - yes this is needed, as we can't DMA to
> the stack  - I hadn't realised the 'data' was being DMA'd ..

>>
>> All these are small issues. Let me try to address them, I'll send you an
>> updated patch shortly.

I'll be waiting.

Regards,

Edgar
  
Laurent Pinchart Jan. 3, 2018, 10:57 a.m. UTC | #9
Hi Edgar,

On Wednesday, 3 January 2018 08:07:44 EET Edgar Thier wrote:
> Hi Emmanuel,

If we pick names randomly I'll call you David :-)

> >>> +	int flags = 0;
> >>> +
> >>> +	data = kmalloc(2, GFP_KERNEL);
> > 
> > Isn't 1 byte enough ?
> 
> To quote from Kieran further up this thread:
> 
> >> kmalloc seems a bit of an overhead for 2 bytes (only one of which is
> >> used). Can this use local stack storage?
> >> 
> >> (Laurent, looks like you originally wrote the code that did that, was
> >> there a reason for the kmalloc for 2 bytes?)
> > 
> > Aha - OK, Just spoke with Laurent and - yes this is needed, as we can't
> > DMA to the stack  - I hadn't realised the 'data' was being DMA'd ..

I don't dispute the fact that we need to kmalloc the memory, but I think we 
only need to kmalloc one byte, not two. The existing 2 bytes allocation comes 
from the size of the GET_LEN reply. Now that you only issue a GET_INFO here, 
one byte is enough.

> >> All these are small issues. Let me try to address them, I'll send you an
> >> updated patch shortly.
> 
> I'll be waiting.
  

Patch

diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 20397aba..8f902a41 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -1629,6 +1629,40 @@  static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
 	}
 }

+/*
+ * Retrieve flags for a given control
+ */
+static int uvc_ctrl_get_flags(struct uvc_device *dev, const struct uvc_control *ctrl,
+	const struct uvc_control_info *info)
+{
+	u8 *data;
+	int ret = 0;
+	int flags = 0;
+
+	data = kmalloc(2, GFP_KERNEL);
+	if (data == NULL)
+		return -ENOMEM;
+
+	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
+						 info->selector, data, 1);
+	if (ret < 0) {
+		uvc_trace(UVC_TRACE_CONTROL,
+				  "GET_INFO failed on control %pUl/%u (%d).\n",
+				  info->entity, info->selector, ret);
+	} else {
+		flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
+			| UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
+			| (data[0] & UVC_CONTROL_CAP_GET ?
+			   UVC_CTRL_FLAG_GET_CUR : 0)
+			| (data[0] & UVC_CONTROL_CAP_SET ?
+			   UVC_CTRL_FLAG_SET_CUR : 0)
+			| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
+			   UVC_CTRL_FLAG_AUTO_UPDATE : 0);
+	}
+	kfree(data);
+	return flags;
+}
+
 /*
  * Query control information (size and flags) for XU controls.
  */
@@ -1636,6 +1670,7 @@  static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
 	const struct uvc_control *ctrl, struct uvc_control_info *info)
 {
 	u8 *data;
+	int flags;
 	int ret;

 	data = kmalloc(2, GFP_KERNEL);
@@ -1659,24 +1694,15 @@  static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,

 	info->size = le16_to_cpup((__le16 *)data);

-	/* Query the control information (GET_INFO) */
-	ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
-			     info->selector, data, 1);
-	if (ret < 0) {
+	flags = uvc_ctrl_get_flags(dev, ctrl, info);
+
+	if (flags < 0) {
 		uvc_trace(UVC_TRACE_CONTROL,
-			  "GET_INFO failed on control %pUl/%u (%d).\n",
-			  info->entity, info->selector, ret);
+			  "Failed to retrieve flags (%d).\n", ret);
+ 		ret = flags;
 		goto done;
 	}
-
-	info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
-		    | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
-		    | (data[0] & UVC_CONTROL_CAP_GET ?
-		       UVC_CTRL_FLAG_GET_CUR : 0)
-		    | (data[0] & UVC_CONTROL_CAP_SET ?
-		       UVC_CTRL_FLAG_SET_CUR : 0)
-		    | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
-		       UVC_CTRL_FLAG_AUTO_UPDATE : 0);
+	info->flags = flags;

 	uvc_ctrl_fixup_xu_info(dev, ctrl, info);

@@ -1890,6 +1916,7 @@  static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
 	const struct uvc_control_info *info)
 {
 	int ret = 0;
+	int flags = 0;

 	ctrl->info = *info;
 	INIT_LIST_HEAD(&ctrl->info.mappings);
@@ -1902,6 +1929,13 @@  static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
 		goto done;
 	}

+	flags = uvc_ctrl_get_flags(dev, ctrl, info);
+	if (flags < 0)
+		uvc_trace(UVC_TRACE_CONTROL,
+			  "Failed to retrieve flags (%d).\n", ret);
+	else
+		ctrl->info.flags = flags;
+
 	ctrl->initialized = 1;

 	uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "