diff mbox

[RFC,v2,RFC] v4l2: Support for multiple selections

Message ID 1380616016-32140-1-git-send-email-ricardo.ribalda@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ricardo Ribalda Delgado Oct. 1, 2013, 8:26 a.m. UTC
Extend v4l2 selection API to support multiple selection areas, this way
sensors that support multiple readout areas can work with multiple areas
of insterest.

The struct v4l2_selection and v4l2_subdev_selection has been extented
with a new field rectangles. If it is value is different than zero the
pr array is used instead of the r field.

A new structure v4l2_ext_rect has been defined, containing 4 reserved
fields for future improvements, as suggested by Hans.

Two helper functiona are also added, to help the drivers that support
a single selection.

This Patch ONLY adds the modification to the core. Once it is agreed, a
new version including changes on the drivers that handle the selection
api will come.

struct v4l2_selection has the same size on 32 and 64 bits, therefore I
dont think that any change on v4l2-compat-ioctl32 is needed.

ricardo@neopili:/tmp$ gcc kk.c -m32
ricardo@neopili:/tmp$ ./a.out
Size of v4l2_selection=64
ricardo@neopili:/tmp$ gcc kk.c
ricardo@neopili:/tmp$ ./a.out
Size of v4l2_selection=64

This patch includes all the comments by Hans Verkuil.

Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
 drivers/media/v4l2-core/v4l2-common.c | 39 +++++++++++++++++++++++++++++++++++
 drivers/media/v4l2-core/v4l2-ioctl.c  | 37 ++++++++++++++++++++++++++++-----
 include/media/v4l2-common.h           |  4 ++++
 include/uapi/linux/v4l2-subdev.h      | 10 +++++++--
 include/uapi/linux/videodev2.h        | 21 +++++++++++++++----
 5 files changed, 100 insertions(+), 11 deletions(-)

Comments

Hans Verkuil Oct. 1, 2013, 9:13 a.m. UTC | #1
On Tue 1 October 2013 10:26:56 Ricardo Ribalda Delgado wrote:
> Extend v4l2 selection API to support multiple selection areas, this way
> sensors that support multiple readout areas can work with multiple areas
> of insterest.
> 
> The struct v4l2_selection and v4l2_subdev_selection has been extented
> with a new field rectangles. If it is value is different than zero the
> pr array is used instead of the r field.
> 
> A new structure v4l2_ext_rect has been defined, containing 4 reserved
> fields for future improvements, as suggested by Hans.
> 
> Two helper functiona are also added, to help the drivers that support
> a single selection.
> 
> This Patch ONLY adds the modification to the core. Once it is agreed, a
> new version including changes on the drivers that handle the selection
> api will come.
> 
> struct v4l2_selection has the same size on 32 and 64 bits, therefore I
> dont think that any change on v4l2-compat-ioctl32 is needed.

Yes, you do. The pr pointer is 32-bit for a 32-bit application and the
compat code is needed to convert it to a 64-bit pointer. The struct as a
whole may have the same size, but the pointer in the union definitely has
a different size.

> 
> ricardo@neopili:/tmp$ gcc kk.c -m32
> ricardo@neopili:/tmp$ ./a.out
> Size of v4l2_selection=64
> ricardo@neopili:/tmp$ gcc kk.c
> ricardo@neopili:/tmp$ ./a.out
> Size of v4l2_selection=64
> 
> This patch includes all the comments by Hans Verkuil.
> 
> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
> ---
>  drivers/media/v4l2-core/v4l2-common.c | 39 +++++++++++++++++++++++++++++++++++
>  drivers/media/v4l2-core/v4l2-ioctl.c  | 37 ++++++++++++++++++++++++++++-----
>  include/media/v4l2-common.h           |  4 ++++
>  include/uapi/linux/v4l2-subdev.h      | 10 +++++++--
>  include/uapi/linux/videodev2.h        | 21 +++++++++++++++----
>  5 files changed, 100 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
> index a95e5e2..007ab32 100644
> --- a/drivers/media/v4l2-core/v4l2-common.c
> +++ b/drivers/media/v4l2-core/v4l2-common.c
> @@ -886,3 +886,42 @@ void v4l2_get_timestamp(struct timeval *tv)
>  	tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
>  }
>  EXPORT_SYMBOL_GPL(v4l2_get_timestamp);
> +
> +int v4l2_selection_get_rect(struct v4l2_selection *s, struct v4l2_ext_rect *r)
> +{
> +	if (s->rectangles > 1)
> +		return -EINVAL;
> +	if (s->rectangles == 1) {
> +		*r = s->pr[0];
> +		return 0;
> +	}
> +	if (s->r.width < 0 || s->r.height < 0)
> +		return -EINVAL;
> +	r->left = s->r.left;
> +	r->top = s->r.top;
> +	r->width = s->r.width;
> +	r->height = s->r.height;
> +	memset(r->reserved, 0, sizeof(r->reserved));
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_selection_get_rect);
> +
> +int v4l2_selection_set_rect(struct v4l2_ext_rect *r, struct v4l2_selection *s)
> +{
> +	if (s->rectangles == 0) {
> +		if (s->r.width > UINT_MAX || s->r.height > UINT_MAX)
> +			return -EINVAL;

This makes no sense. You probably mean r->width > INT_MAX, but I would just
skip this whole test: it is the driver that will set these values, and you
can assume that it is correct. You can never rely on what you get from userspace,
but I think this is reasonably in this case to assume that the rectangle is
a reasonable size.

That also means that this can be a void function.

> +		s->r.left = r->left;
> +		s->r.top = r->top;
> +		s->r.width = r->width;
> +		s->r.height = r->height;
> +		return 0;
> +	}
> +	if (s->rectangles > 1) {
> +		s->pr[0] = *r;
> +		s->rectangles = 1;
> +		return 0;
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_selection_set_rect);
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 68e6b5e..29f7cf1 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -572,11 +572,22 @@ static void v4l_print_crop(const void *arg, bool write_only)
>  static void v4l_print_selection(const void *arg, bool write_only)
>  {
>  	const struct v4l2_selection *p = arg;
> +	int i;
>  
> -	pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
> -		prt_names(p->type, v4l2_type_names),
> -		p->target, p->flags,
> -		p->r.width, p->r.height, p->r.left, p->r.top);
> +	if (p->rectangles == 0)
> +		pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
> +			prt_names(p->type, v4l2_type_names),
> +			p->target, p->flags,
> +			p->r.width, p->r.height, p->r.left, p->r.top);
> +	else{
> +		pr_cont("type=%s, target=%d, flags=0x%x rectangles=%d\n",
> +			prt_names(p->type, v4l2_type_names),
> +			p->target, p->flags, p->rectangles);
> +		for (i = 0; i < p->rectangles; i++)
> +			pr_cont("rectangle %d: wxh=%dx%d, x,y=%d,%d\n",
> +				i, p->r.width, p->r.height,
> +				p->r.left, p->r.top);
> +	}
>  }
>  
>  static void v4l_print_jpegcompression(const void *arg, bool write_only)
> @@ -1692,7 +1703,9 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
>  				struct file *file, void *fh, void *arg)
>  {
>  	struct v4l2_cropcap *p = arg;
> -	struct v4l2_selection s = { .type = p->type };
> +	struct v4l2_selection s = {
> +		.type = p->type,
> +	};
>  	int ret;
>  
>  	if (ops->vidioc_cropcap)
> @@ -2253,6 +2266,20 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
>  		}
>  		break;
>  	}
> +
> +	case VIDIOC_G_SELECTION:
> +	case VIDIOC_S_SELECTION: {
> +		struct v4l2_selection *s = parg;
> +
> +		if (s->rectangles) {
> +			*user_ptr = (void __user *)s->pr;
> +			kernel_ptr = (void *)&s->pr;
> +			array_size = sizeof(struct v4l2_ext_rect)
> +				* s->rectangles;
> +			ret = 1;
> +		}
> +		break;
> +	}
>  	}
>  
>  	return ret;
> diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
> index 015ff82..dc96861 100644
> --- a/include/media/v4l2-common.h
> +++ b/include/media/v4l2-common.h
> @@ -216,4 +216,8 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait);
>  
>  void v4l2_get_timestamp(struct timeval *tv);
>  
> +int v4l2_selection_get_rect(struct v4l2_selection *s, struct v4l2_ext_rect *r);
> +
> +int v4l2_selection_set_rect(struct v4l2_ext_rect *r, struct v4l2_selection *s);

Swap the arguments to be consistent with get_rect. The v4l2_ext_rect argument can
be const as well since you don't want set_rect to modify *r.

> +
>  #endif /* V4L2_COMMON_H_ */
> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index a33c4da..c02a886 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -133,6 +133,8 @@ struct v4l2_subdev_frame_interval_enum {
>   *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
>   * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
>   * @r: coordinates of the selection window
> + * @pr:		array of rectangles containing the selection windows
> + * @rectangles:	Number of rectangles in pr structure. If zero, r is used instead
>   * @reserved: for future use, set to zero for now
>   *
>   * Hardware may use multiple helper windows to process a video stream.
> @@ -144,8 +146,12 @@ struct v4l2_subdev_selection {
>  	__u32 pad;
>  	__u32 target;
>  	__u32 flags;
> -	struct v4l2_rect r;
> -	__u32 reserved[8];
> +	union {
> +		struct v4l2_rect r;
> +		struct v4l2_ext_rect *pr;
> +	};
> +	__u32 rectangles;
> +	__u32 reserved[7];
>  };
>  
>  struct v4l2_subdev_edid {
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 95ef455..a4a7902 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -211,6 +211,14 @@ struct v4l2_rect {
>  	__s32   height;
>  };
>  
> +struct v4l2_ext_rect {
> +	__s32   left;
> +	__s32   top;
> +	__u32   width;
> +	__u32   height;
> +	__u32   reserved[4];
> +};
> +
>  struct v4l2_fract {
>  	__u32   numerator;
>  	__u32   denominator;
> @@ -804,6 +812,8 @@ struct v4l2_crop {
>   *		defined in v4l2-common.h; V4L2_SEL_TGT_* .
>   * @flags:	constraints flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
>   * @r:		coordinates of selection window
> + * @pr:		array of rectangles containing the selection windows
> + * @rectangles:	Number of rectangles in pr structure. If zero, r is used instead
>   * @reserved:	for future use, rounds structure size to 64 bytes, set to zero
>   *
>   * Hardware may use multiple helper windows to process a video stream.
> @@ -814,10 +824,13 @@ struct v4l2_selection {
>  	__u32			type;
>  	__u32			target;
>  	__u32                   flags;
> -	struct v4l2_rect        r;
> -	__u32                   reserved[9];
> -};
> -
> +	union {
> +		struct v4l2_rect        r;
> +		struct v4l2_ext_rect    *pr;
> +	};
> +	__u32                   rectangles;
> +	__u32                   reserved[8];
> +} __packed;
>  
>  /*
>   *      A N A L O G   V I D E O   S T A N D A R D
> 

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ricardo Ribalda Delgado Oct. 1, 2013, 10:34 a.m. UTC | #2
Hello Hans

Thanks for your comments

I have just posted a new version.

Regards!

On Tue, Oct 1, 2013 at 11:13 AM, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On Tue 1 October 2013 10:26:56 Ricardo Ribalda Delgado wrote:
>> Extend v4l2 selection API to support multiple selection areas, this way
>> sensors that support multiple readout areas can work with multiple areas
>> of insterest.
>>
>> The struct v4l2_selection and v4l2_subdev_selection has been extented
>> with a new field rectangles. If it is value is different than zero the
>> pr array is used instead of the r field.
>>
>> A new structure v4l2_ext_rect has been defined, containing 4 reserved
>> fields for future improvements, as suggested by Hans.
>>
>> Two helper functiona are also added, to help the drivers that support
>> a single selection.
>>
>> This Patch ONLY adds the modification to the core. Once it is agreed, a
>> new version including changes on the drivers that handle the selection
>> api will come.
>>
>> struct v4l2_selection has the same size on 32 and 64 bits, therefore I
>> dont think that any change on v4l2-compat-ioctl32 is needed.
>
> Yes, you do. The pr pointer is 32-bit for a 32-bit application and the
> compat code is needed to convert it to a 64-bit pointer. The struct as a
> whole may have the same size, but the pointer in the union definitely has
> a different size.
>
>>
>> ricardo@neopili:/tmp$ gcc kk.c -m32
>> ricardo@neopili:/tmp$ ./a.out
>> Size of v4l2_selection=64
>> ricardo@neopili:/tmp$ gcc kk.c
>> ricardo@neopili:/tmp$ ./a.out
>> Size of v4l2_selection=64
>>
>> This patch includes all the comments by Hans Verkuil.
>>
>> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
>> ---
>>  drivers/media/v4l2-core/v4l2-common.c | 39 +++++++++++++++++++++++++++++++++++
>>  drivers/media/v4l2-core/v4l2-ioctl.c  | 37 ++++++++++++++++++++++++++++-----
>>  include/media/v4l2-common.h           |  4 ++++
>>  include/uapi/linux/v4l2-subdev.h      | 10 +++++++--
>>  include/uapi/linux/videodev2.h        | 21 +++++++++++++++----
>>  5 files changed, 100 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
>> index a95e5e2..007ab32 100644
>> --- a/drivers/media/v4l2-core/v4l2-common.c
>> +++ b/drivers/media/v4l2-core/v4l2-common.c
>> @@ -886,3 +886,42 @@ void v4l2_get_timestamp(struct timeval *tv)
>>       tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
>>  }
>>  EXPORT_SYMBOL_GPL(v4l2_get_timestamp);
>> +
>> +int v4l2_selection_get_rect(struct v4l2_selection *s, struct v4l2_ext_rect *r)
>> +{
>> +     if (s->rectangles > 1)
>> +             return -EINVAL;
>> +     if (s->rectangles == 1) {
>> +             *r = s->pr[0];
>> +             return 0;
>> +     }
>> +     if (s->r.width < 0 || s->r.height < 0)
>> +             return -EINVAL;
>> +     r->left = s->r.left;
>> +     r->top = s->r.top;
>> +     r->width = s->r.width;
>> +     r->height = s->r.height;
>> +     memset(r->reserved, 0, sizeof(r->reserved));
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_selection_get_rect);
>> +
>> +int v4l2_selection_set_rect(struct v4l2_ext_rect *r, struct v4l2_selection *s)
>> +{
>> +     if (s->rectangles == 0) {
>> +             if (s->r.width > UINT_MAX || s->r.height > UINT_MAX)
>> +                     return -EINVAL;
>
> This makes no sense. You probably mean r->width > INT_MAX, but I would just
> skip this whole test: it is the driver that will set these values, and you
> can assume that it is correct. You can never rely on what you get from userspace,
> but I think this is reasonably in this case to assume that the rectangle is
> a reasonable size.
>
> That also means that this can be a void function.
>
>> +             s->r.left = r->left;
>> +             s->r.top = r->top;
>> +             s->r.width = r->width;
>> +             s->r.height = r->height;
>> +             return 0;
>> +     }
>> +     if (s->rectangles > 1) {
>> +             s->pr[0] = *r;
>> +             s->rectangles = 1;
>> +             return 0;
>> +     }
>> +     return 0;
>> +}
>> +EXPORT_SYMBOL_GPL(v4l2_selection_set_rect);
>> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
>> index 68e6b5e..29f7cf1 100644
>> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
>> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
>> @@ -572,11 +572,22 @@ static void v4l_print_crop(const void *arg, bool write_only)
>>  static void v4l_print_selection(const void *arg, bool write_only)
>>  {
>>       const struct v4l2_selection *p = arg;
>> +     int i;
>>
>> -     pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
>> -             prt_names(p->type, v4l2_type_names),
>> -             p->target, p->flags,
>> -             p->r.width, p->r.height, p->r.left, p->r.top);
>> +     if (p->rectangles == 0)
>> +             pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
>> +                     prt_names(p->type, v4l2_type_names),
>> +                     p->target, p->flags,
>> +                     p->r.width, p->r.height, p->r.left, p->r.top);
>> +     else{
>> +             pr_cont("type=%s, target=%d, flags=0x%x rectangles=%d\n",
>> +                     prt_names(p->type, v4l2_type_names),
>> +                     p->target, p->flags, p->rectangles);
>> +             for (i = 0; i < p->rectangles; i++)
>> +                     pr_cont("rectangle %d: wxh=%dx%d, x,y=%d,%d\n",
>> +                             i, p->r.width, p->r.height,
>> +                             p->r.left, p->r.top);
>> +     }
>>  }
>>
>>  static void v4l_print_jpegcompression(const void *arg, bool write_only)
>> @@ -1692,7 +1703,9 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
>>                               struct file *file, void *fh, void *arg)
>>  {
>>       struct v4l2_cropcap *p = arg;
>> -     struct v4l2_selection s = { .type = p->type };
>> +     struct v4l2_selection s = {
>> +             .type = p->type,
>> +     };
>>       int ret;
>>
>>       if (ops->vidioc_cropcap)
>> @@ -2253,6 +2266,20 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
>>               }
>>               break;
>>       }
>> +
>> +     case VIDIOC_G_SELECTION:
>> +     case VIDIOC_S_SELECTION: {
>> +             struct v4l2_selection *s = parg;
>> +
>> +             if (s->rectangles) {
>> +                     *user_ptr = (void __user *)s->pr;
>> +                     kernel_ptr = (void *)&s->pr;
>> +                     array_size = sizeof(struct v4l2_ext_rect)
>> +                             * s->rectangles;
>> +                     ret = 1;
>> +             }
>> +             break;
>> +     }
>>       }
>>
>>       return ret;
>> diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
>> index 015ff82..dc96861 100644
>> --- a/include/media/v4l2-common.h
>> +++ b/include/media/v4l2-common.h
>> @@ -216,4 +216,8 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait);
>>
>>  void v4l2_get_timestamp(struct timeval *tv);
>>
>> +int v4l2_selection_get_rect(struct v4l2_selection *s, struct v4l2_ext_rect *r);
>> +
>> +int v4l2_selection_set_rect(struct v4l2_ext_rect *r, struct v4l2_selection *s);
>
> Swap the arguments to be consistent with get_rect. The v4l2_ext_rect argument can
> be const as well since you don't want set_rect to modify *r.
>
>> +
>>  #endif /* V4L2_COMMON_H_ */
>> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
>> index a33c4da..c02a886 100644
>> --- a/include/uapi/linux/v4l2-subdev.h
>> +++ b/include/uapi/linux/v4l2-subdev.h
>> @@ -133,6 +133,8 @@ struct v4l2_subdev_frame_interval_enum {
>>   *       defined in v4l2-common.h; V4L2_SEL_TGT_* .
>>   * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
>>   * @r: coordinates of the selection window
>> + * @pr:              array of rectangles containing the selection windows
>> + * @rectangles:      Number of rectangles in pr structure. If zero, r is used instead
>>   * @reserved: for future use, set to zero for now
>>   *
>>   * Hardware may use multiple helper windows to process a video stream.
>> @@ -144,8 +146,12 @@ struct v4l2_subdev_selection {
>>       __u32 pad;
>>       __u32 target;
>>       __u32 flags;
>> -     struct v4l2_rect r;
>> -     __u32 reserved[8];
>> +     union {
>> +             struct v4l2_rect r;
>> +             struct v4l2_ext_rect *pr;
>> +     };
>> +     __u32 rectangles;
>> +     __u32 reserved[7];
>>  };
>>
>>  struct v4l2_subdev_edid {
>> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
>> index 95ef455..a4a7902 100644
>> --- a/include/uapi/linux/videodev2.h
>> +++ b/include/uapi/linux/videodev2.h
>> @@ -211,6 +211,14 @@ struct v4l2_rect {
>>       __s32   height;
>>  };
>>
>> +struct v4l2_ext_rect {
>> +     __s32   left;
>> +     __s32   top;
>> +     __u32   width;
>> +     __u32   height;
>> +     __u32   reserved[4];
>> +};
>> +
>>  struct v4l2_fract {
>>       __u32   numerator;
>>       __u32   denominator;
>> @@ -804,6 +812,8 @@ struct v4l2_crop {
>>   *           defined in v4l2-common.h; V4L2_SEL_TGT_* .
>>   * @flags:   constraints flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
>>   * @r:               coordinates of selection window
>> + * @pr:              array of rectangles containing the selection windows
>> + * @rectangles:      Number of rectangles in pr structure. If zero, r is used instead
>>   * @reserved:        for future use, rounds structure size to 64 bytes, set to zero
>>   *
>>   * Hardware may use multiple helper windows to process a video stream.
>> @@ -814,10 +824,13 @@ struct v4l2_selection {
>>       __u32                   type;
>>       __u32                   target;
>>       __u32                   flags;
>> -     struct v4l2_rect        r;
>> -     __u32                   reserved[9];
>> -};
>> -
>> +     union {
>> +             struct v4l2_rect        r;
>> +             struct v4l2_ext_rect    *pr;
>> +     };
>> +     __u32                   rectangles;
>> +     __u32                   reserved[8];
>> +} __packed;
>>
>>  /*
>>   *      A N A L O G   V I D E O   S T A N D A R D
>>
>
> Regards,
>
>         Hans
diff mbox

Patch

diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index a95e5e2..007ab32 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -886,3 +886,42 @@  void v4l2_get_timestamp(struct timeval *tv)
 	tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
 }
 EXPORT_SYMBOL_GPL(v4l2_get_timestamp);
+
+int v4l2_selection_get_rect(struct v4l2_selection *s, struct v4l2_ext_rect *r)
+{
+	if (s->rectangles > 1)
+		return -EINVAL;
+	if (s->rectangles == 1) {
+		*r = s->pr[0];
+		return 0;
+	}
+	if (s->r.width < 0 || s->r.height < 0)
+		return -EINVAL;
+	r->left = s->r.left;
+	r->top = s->r.top;
+	r->width = s->r.width;
+	r->height = s->r.height;
+	memset(r->reserved, 0, sizeof(r->reserved));
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_selection_get_rect);
+
+int v4l2_selection_set_rect(struct v4l2_ext_rect *r, struct v4l2_selection *s)
+{
+	if (s->rectangles == 0) {
+		if (s->r.width > UINT_MAX || s->r.height > UINT_MAX)
+			return -EINVAL;
+		s->r.left = r->left;
+		s->r.top = r->top;
+		s->r.width = r->width;
+		s->r.height = r->height;
+		return 0;
+	}
+	if (s->rectangles > 1) {
+		s->pr[0] = *r;
+		s->rectangles = 1;
+		return 0;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_selection_set_rect);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 68e6b5e..29f7cf1 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -572,11 +572,22 @@  static void v4l_print_crop(const void *arg, bool write_only)
 static void v4l_print_selection(const void *arg, bool write_only)
 {
 	const struct v4l2_selection *p = arg;
+	int i;
 
-	pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
-		prt_names(p->type, v4l2_type_names),
-		p->target, p->flags,
-		p->r.width, p->r.height, p->r.left, p->r.top);
+	if (p->rectangles == 0)
+		pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
+			prt_names(p->type, v4l2_type_names),
+			p->target, p->flags,
+			p->r.width, p->r.height, p->r.left, p->r.top);
+	else{
+		pr_cont("type=%s, target=%d, flags=0x%x rectangles=%d\n",
+			prt_names(p->type, v4l2_type_names),
+			p->target, p->flags, p->rectangles);
+		for (i = 0; i < p->rectangles; i++)
+			pr_cont("rectangle %d: wxh=%dx%d, x,y=%d,%d\n",
+				i, p->r.width, p->r.height,
+				p->r.left, p->r.top);
+	}
 }
 
 static void v4l_print_jpegcompression(const void *arg, bool write_only)
@@ -1692,7 +1703,9 @@  static int v4l_cropcap(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
 	struct v4l2_cropcap *p = arg;
-	struct v4l2_selection s = { .type = p->type };
+	struct v4l2_selection s = {
+		.type = p->type,
+	};
 	int ret;
 
 	if (ops->vidioc_cropcap)
@@ -2253,6 +2266,20 @@  static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 		}
 		break;
 	}
+
+	case VIDIOC_G_SELECTION:
+	case VIDIOC_S_SELECTION: {
+		struct v4l2_selection *s = parg;
+
+		if (s->rectangles) {
+			*user_ptr = (void __user *)s->pr;
+			kernel_ptr = (void *)&s->pr;
+			array_size = sizeof(struct v4l2_ext_rect)
+				* s->rectangles;
+			ret = 1;
+		}
+		break;
+	}
 	}
 
 	return ret;
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 015ff82..dc96861 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -216,4 +216,8 @@  struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait);
 
 void v4l2_get_timestamp(struct timeval *tv);
 
+int v4l2_selection_get_rect(struct v4l2_selection *s, struct v4l2_ext_rect *r);
+
+int v4l2_selection_set_rect(struct v4l2_ext_rect *r, struct v4l2_selection *s);
+
 #endif /* V4L2_COMMON_H_ */
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index a33c4da..c02a886 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -133,6 +133,8 @@  struct v4l2_subdev_frame_interval_enum {
  *	    defined in v4l2-common.h; V4L2_SEL_TGT_* .
  * @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
  * @r: coordinates of the selection window
+ * @pr:		array of rectangles containing the selection windows
+ * @rectangles:	Number of rectangles in pr structure. If zero, r is used instead
  * @reserved: for future use, set to zero for now
  *
  * Hardware may use multiple helper windows to process a video stream.
@@ -144,8 +146,12 @@  struct v4l2_subdev_selection {
 	__u32 pad;
 	__u32 target;
 	__u32 flags;
-	struct v4l2_rect r;
-	__u32 reserved[8];
+	union {
+		struct v4l2_rect r;
+		struct v4l2_ext_rect *pr;
+	};
+	__u32 rectangles;
+	__u32 reserved[7];
 };
 
 struct v4l2_subdev_edid {
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 95ef455..a4a7902 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -211,6 +211,14 @@  struct v4l2_rect {
 	__s32   height;
 };
 
+struct v4l2_ext_rect {
+	__s32   left;
+	__s32   top;
+	__u32   width;
+	__u32   height;
+	__u32   reserved[4];
+};
+
 struct v4l2_fract {
 	__u32   numerator;
 	__u32   denominator;
@@ -804,6 +812,8 @@  struct v4l2_crop {
  *		defined in v4l2-common.h; V4L2_SEL_TGT_* .
  * @flags:	constraints flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
  * @r:		coordinates of selection window
+ * @pr:		array of rectangles containing the selection windows
+ * @rectangles:	Number of rectangles in pr structure. If zero, r is used instead
  * @reserved:	for future use, rounds structure size to 64 bytes, set to zero
  *
  * Hardware may use multiple helper windows to process a video stream.
@@ -814,10 +824,13 @@  struct v4l2_selection {
 	__u32			type;
 	__u32			target;
 	__u32                   flags;
-	struct v4l2_rect        r;
-	__u32                   reserved[9];
-};
-
+	union {
+		struct v4l2_rect        r;
+		struct v4l2_ext_rect    *pr;
+	};
+	__u32                   rectangles;
+	__u32                   reserved[8];
+} __packed;
 
 /*
  *      A N A L O G   V I D E O   S T A N D A R D