@@ -30,11 +30,16 @@
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
- fh->probe_fmt = kzalloc(sizeof(*fh->probe_fmt) *
- sd->entity.num_pads, GFP_KERNEL);
+ /* Allocate probe format and crop in the same memory block */
+ fh->probe_fmt = kzalloc((sizeof(*fh->probe_fmt) +
+ sizeof(*fh->probe_crop)) * sd->entity.num_pads,
+ GFP_KERNEL);
if (fh->probe_fmt == NULL)
return -ENOMEM;
+ fh->probe_crop = (struct v4l2_rect *)
+ (fh->probe_fmt + sd->entity.num_pads);
+
return 0;
}
@@ -42,6 +47,7 @@ static void subdev_fh_free(struct v4l2_subdev_fh *fh)
{
kfree(fh->probe_fmt);
fh->probe_fmt = NULL;
+ fh->probe_crop = NULL;
}
static int subdev_open(struct file *file)
@@ -188,6 +194,32 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
format->which);
}
+ case VIDIOC_SUBDEV_G_CROP: {
+ struct v4l2_subdev_pad_crop *crop = arg;
+
+ if (crop->which != V4L2_SUBDEV_FORMAT_PROBE &&
+ crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (crop->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+ }
+
+ case VIDIOC_SUBDEV_S_CROP: {
+ struct v4l2_subdev_pad_crop *crop = arg;
+
+ if (crop->which != V4L2_SUBDEV_FORMAT_PROBE &&
+ crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (crop->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+ }
+
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
struct v4l2_subdev_pad_mbus_code_enum *code = arg;
@@ -36,6 +36,16 @@ struct v4l2_subdev_pad_format {
};
/**
+ * struct v4l2_subdev_pad_crop
+ */
+struct v4l2_subdev_pad_crop {
+ __u32 pad;
+ __u32 which;
+ struct v4l2_rect rect;
+ __u32 reserved[10];
+};
+
+/**
* struct v4l2_subdev_pad_mbus_code_enum
*/
struct v4l2_subdev_pad_mbus_code_enum {
@@ -86,5 +96,7 @@ struct v4l2_subdev_frame_interval_enum {
_IOWR('V', 9, struct v4l2_subdev_frame_size_enum)
#define VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
_IOWR('V', 10, struct v4l2_subdev_frame_interval_enum)
+#define VIDIOC_SUBDEV_S_CROP _IOWR('V', 11, struct v4l2_subdev_pad_crop)
+#define VIDIOC_SUBDEV_G_CROP _IOWR('V', 12, struct v4l2_subdev_pad_crop)
#endif
@@ -419,6 +419,10 @@ struct v4l2_subdev_pad_ops {
int (*set_fmt)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format which);
+ int (*set_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_crop *crop);
+ int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_pad_crop *crop);
};
struct v4l2_subdev_ops {
@@ -478,6 +482,7 @@ struct v4l2_subdev {
struct v4l2_subdev_fh {
struct v4l2_fh vfh;
struct v4l2_mbus_framefmt *probe_fmt;
+ struct v4l2_rect *probe_crop;
};
#define to_v4l2_subdev_fh(fh) \
@@ -489,6 +494,12 @@ v4l2_subdev_get_probe_format(struct v4l2_subdev_fh *fh, unsigned int pad)
return &fh->probe_fmt[pad];
}
+static inline struct v4l2_rect *
+v4l2_subdev_get_probe_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
+{
+ return &fh->probe_crop[pad];
+}
+
extern const struct v4l2_file_operations v4l2_subdev_fops;
static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)