diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index f24978b80440..81b08f66da9b 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -112,56 +112,175 @@ static int subdev_close(struct file *file) return 0; } -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) -static int check_format(struct v4l2_subdev *sd, +static inline int check_which(__u32 which) +{ + if (which != V4L2_SUBDEV_FORMAT_TRY && + which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + return 0; +} + +static inline int check_pad(struct v4l2_subdev *sd, __u32 pad) +{ +#if defined(CONFIG_MEDIA_CONTROLLER) + if (sd->entity.graph_obj.mdev) { + if (pad >= sd->entity.num_pads) + return -EINVAL; + return 0; + } +#endif + /* allow pad 0 on subdevices not registered as media entities */ + if (pad > 0) + return -EINVAL; + return 0; +} + +static inline int check_format(struct v4l2_subdev *sd, + struct v4l2_subdev_format *format) +{ + return check_which(format->which) ? : check_pad(sd, format->pad); +} + +static int call_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { - if (format->which != V4L2_SUBDEV_FORMAT_TRY && - format->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (format->pad >= sd->entity.num_pads) - return -EINVAL; - - return 0; + return check_format(sd, format) ? : + sd->ops->pad->get_fmt(sd, cfg, format); } -static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop) +static int call_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (crop->which != V4L2_SUBDEV_FORMAT_TRY && - crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (crop->pad >= sd->entity.num_pads) - return -EINVAL; - - return 0; + return check_format(sd, format) ? : + sd->ops->pad->set_fmt(sd, cfg, format); } -static int check_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_selection *sel) +static int call_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (sel->which != V4L2_SUBDEV_FORMAT_TRY && - sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (sel->pad >= sd->entity.num_pads) - return -EINVAL; - - return 0; + return check_which(code->which) ? : check_pad(sd, code->pad) ? : + sd->ops->pad->enum_mbus_code(sd, cfg, code); } -static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static int call_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) { - if (edid->pad >= sd->entity.num_pads) - return -EINVAL; + return check_which(fse->which) ? : check_pad(sd, fse->pad) ? : + sd->ops->pad->enum_frame_size(sd, cfg, fse); +} +static inline int check_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + return check_pad(sd, fi->pad); +} + +static int call_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + return check_frame_interval(sd, fi) ? : + sd->ops->video->g_frame_interval(sd, fi); +} + +static int call_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + return check_frame_interval(sd, fi) ? : + sd->ops->video->s_frame_interval(sd, fi); +} + +static int call_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + return check_which(fie->which) ? : check_pad(sd, fie->pad) ? : + sd->ops->pad->enum_frame_interval(sd, cfg, fie); +} + +static inline int check_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_selection *sel) +{ + return check_which(sel->which) ? : check_pad(sd, sel->pad); +} + +static int call_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + return check_selection(sd, sel) ? : + sd->ops->pad->get_selection(sd, cfg, sel); +} + +static int call_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + return check_selection(sd, sel) ? : + sd->ops->pad->set_selection(sd, cfg, sel); +} + +static inline int check_edid(struct v4l2_subdev *sd, + struct v4l2_subdev_edid *edid) +{ if (edid->blocks && edid->edid == NULL) return -EINVAL; - return 0; + return check_pad(sd, edid->pad); } -#endif + +static int call_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +{ + return check_edid(sd, edid) ? : sd->ops->pad->get_edid(sd, edid); +} + +static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +{ + return check_edid(sd, edid) ? : sd->ops->pad->set_edid(sd, edid); +} + +static int call_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + return check_pad(sd, cap->pad) ? : + sd->ops->pad->dv_timings_cap(sd, cap); +} + +static int call_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *dvt) +{ + return check_pad(sd, dvt->pad) ? : + sd->ops->pad->enum_dv_timings(sd, dvt); +} + +static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = { + .get_fmt = call_get_fmt, + .set_fmt = call_set_fmt, + .enum_mbus_code = call_enum_mbus_code, + .enum_frame_size = call_enum_frame_size, + .enum_frame_interval = call_enum_frame_interval, + .get_selection = call_get_selection, + .set_selection = call_set_selection, + .get_edid = call_get_edid, + .set_edid = call_set_edid, + .dv_timings_cap = call_dv_timings_cap, + .enum_dv_timings = call_enum_dv_timings, +}; + +static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = { + .g_frame_interval = call_g_frame_interval, + .s_frame_interval = call_s_frame_interval, +}; + +const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = { + .pad = &v4l2_subdev_call_pad_wrappers, + .video = &v4l2_subdev_call_video_wrappers, +}; +EXPORT_SYMBOL(v4l2_subdev_call_wrappers); static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { @@ -284,10 +403,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; - rval = check_format(sd, format); - if (rval) - return rval; - memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); @@ -296,10 +411,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FMT: { struct v4l2_subdev_format *format = arg; - rval = check_format(sd, format); - if (rval) - return rval; - memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); @@ -309,10 +420,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; - rval = check_crop(sd, crop); - if (rval) - return rval; - memset(crop->reserved, 0, sizeof(crop->reserved)); memset(&sel, 0, sizeof(sel)); sel.which = crop->which; @@ -332,10 +439,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_selection sel; memset(crop->reserved, 0, sizeof(crop->reserved)); - rval = check_crop(sd, crop); - if (rval) - return rval; - memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; @@ -353,13 +456,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; - if (code->which != V4L2_SUBDEV_FORMAT_TRY && - code->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (code->pad >= sd->entity.num_pads) - return -EINVAL; - memset(code->reserved, 0, sizeof(code->reserved)); return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); @@ -368,13 +464,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { struct v4l2_subdev_frame_size_enum *fse = arg; - if (fse->which != V4L2_SUBDEV_FORMAT_TRY && - fse->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (fse->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fse->reserved, 0, sizeof(fse->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); @@ -383,9 +472,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; - if (fi->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, g_frame_interval, arg); } @@ -393,9 +479,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; - if (fi->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, s_frame_interval, arg); } @@ -403,13 +486,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval_enum *fie = arg; - if (fie->which != V4L2_SUBDEV_FORMAT_TRY && - fie->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (fie->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fie->reserved, 0, sizeof(fie->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); @@ -418,10 +494,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_SELECTION: { struct v4l2_subdev_selection *sel = arg; - rval = check_selection(sd, sel); - if (rval) - return rval; - memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, get_selection, subdev_fh->pad, sel); @@ -430,10 +502,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_SELECTION: { struct v4l2_subdev_selection *sel = arg; - rval = check_selection(sd, sel); - if (rval) - return rval; - memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, sel); @@ -442,38 +510,24 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_G_EDID: { struct v4l2_subdev_edid *edid = arg; - rval = check_edid(sd, edid); - if (rval) - return rval; - return v4l2_subdev_call(sd, pad, get_edid, edid); } case VIDIOC_S_EDID: { struct v4l2_subdev_edid *edid = arg; - rval = check_edid(sd, edid); - if (rval) - return rval; - return v4l2_subdev_call(sd, pad, set_edid, edid); } case VIDIOC_SUBDEV_DV_TIMINGS_CAP: { struct v4l2_dv_timings_cap *cap = arg; - if (cap->pad >= sd->entity.num_pads) - return -EINVAL; - return v4l2_subdev_call(sd, pad, dv_timings_cap, cap); } case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: { struct v4l2_enum_dv_timings *dvt = arg; - if (dvt->pad >= sd->entity.num_pads) - return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt); } diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 7168311e8ecc..71f1f2f0da53 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1082,6 +1082,8 @@ void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg); void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops); +extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers; + /** * v4l2_subdev_call - call an operation of a v4l2_subdev. * @@ -1103,6 +1105,10 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, __result = -ENODEV; \ else if (!(__sd->ops->o && __sd->ops->o->f)) \ __result = -ENOIOCTLCMD; \ + else if (v4l2_subdev_call_wrappers.o && \ + v4l2_subdev_call_wrappers.o->f) \ + __result = v4l2_subdev_call_wrappers.o->f( \ + __sd, ##args); \ else \ __result = __sd->ops->o->f(__sd, ##args); \ __result; \