Re: [PATCH v4 26/29] media: v4l2-subdev: Add struct v4l2_subdev_client_info pointer to pad ops

Laurent Pinchart
2026-04-16T17:32:08Z

On Wed, Apr 08, 2026 at 06:39:35PM +0300, Sakari Ailus wrote:
> Add a pointer to const struct v4l2_subdev_client_info to the get_fmt,
> set_fmt, get_selection and set_selection sub-device pad ops. The client
> info struct will soon be used to differentiate UAPI based on client
> capabilities.

I don't think we need to add the client info to .get_fmt(). .get_fmt()
should just retrieve the format from the state, and that should not
depend on whether or not V4L2_SUBDEV_CLIENT_CAP_COMMON_RAW_SENSOR is
set.

> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---
> drivers/media/v4l2-core/v4l2-subdev.c | 72 +++++++++++++++++++--------
> include/media/v4l2-subdev.h | 9 +++-
> 2 files changed, 60 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> index eaa408832c6b..7723e37a0ff5 100644
> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> @@ -246,19 +246,21 @@ static inline int check_format(struct v4l2_subdev *sd,
> }
>
> static int call_get_fmt(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_format *format)
> {
> return check_format(sd, state, format) ? :
> - sd->ops->pad->get_fmt(sd, state, format);
> + sd->ops->pad->get_fmt(sd, ci, state, format);
> }
>
> static int call_set_fmt(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_format *format)
> {
> return check_format(sd, state, format) ? :
> - sd->ops->pad->set_fmt(sd, state, format);
> + sd->ops->pad->set_fmt(sd, ci, state, format);
> }
>
> static int call_enum_mbus_code(struct v4l2_subdev *sd,
> @@ -309,19 +311,21 @@ static inline int check_selection(struct v4l2_subdev *sd,
> }
>
> static int call_get_selection(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_selection *sel)
> {
> return check_selection(sd, state, sel) ? :
> - sd->ops->pad->get_selection(sd, state, sel);
> + sd->ops->pad->get_selection(sd, ci, state, sel);
> }
>
> static int call_set_selection(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_selection *sel)
> {
> return check_selection(sd, state, sel) ? :
> - sd->ops->pad->set_selection(sd, state, sel);
> + sd->ops->pad->set_selection(sd, ci, state, sel);
> }
>
> static inline int check_frame_interval(struct v4l2_subdev *sd,
> @@ -524,6 +528,21 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
> v4l2_subdev_unlock_state(state); \
> return ret; \
> }
> +#define DEFINE_CI_STATE_WRAPPER(f, arg_type) \
> + static int call_##f##_state(struct v4l2_subdev *sd, \
> + const struct v4l2_subdev_client_info *ci, \
> + struct v4l2_subdev_state *_state, \
> + arg_type *arg) \
> + { \
> + struct v4l2_subdev_state *state = _state; \
> + int ret; \
> + if (!_state) \
> + state = v4l2_subdev_lock_and_get_active_state(sd); \
> + ret = call_##f(sd, ci, state, arg); \
> + if (!_state && state) \
> + v4l2_subdev_unlock_state(state); \
> + return ret; \
> + }
>
> #else /* CONFIG_MEDIA_CONTROLLER */
>
> @@ -535,15 +554,24 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
> return call_##f(sd, state, arg); \
> }
>
> +#define DEFINE_CI_STATE_WRAPPER(f, arg_type) \
> + static int call_##f##_state(struct v4l2_subdev *sd, \
> + const struct v4l2_subdev_client_info *ci, \
> + struct v4l2_subdev_state *state, \
> + arg_type *arg) \
> + { \
> + return call_##f(sd, ci, state, arg); \
> + }
> +
> #endif /* CONFIG_MEDIA_CONTROLLER */
>
> -DEFINE_STATE_WRAPPER(get_fmt, struct v4l2_subdev_format);
> -DEFINE_STATE_WRAPPER(set_fmt, struct v4l2_subdev_format);
> +DEFINE_CI_STATE_WRAPPER(get_fmt, struct v4l2_subdev_format);
> +DEFINE_CI_STATE_WRAPPER(set_fmt, struct v4l2_subdev_format);
> DEFINE_STATE_WRAPPER(enum_mbus_code, struct v4l2_subdev_mbus_code_enum);
> DEFINE_STATE_WRAPPER(enum_frame_size, struct v4l2_subdev_frame_size_enum);
> DEFINE_STATE_WRAPPER(enum_frame_interval, struct v4l2_subdev_frame_interval_enum);
> -DEFINE_STATE_WRAPPER(get_selection, struct v4l2_subdev_selection);
> -DEFINE_STATE_WRAPPER(set_selection, struct v4l2_subdev_selection);
> +DEFINE_CI_STATE_WRAPPER(get_selection, struct v4l2_subdev_selection);
> +DEFINE_CI_STATE_WRAPPER(set_selection, struct v4l2_subdev_selection);
>
> static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
> .get_fmt = call_get_fmt_state,
> @@ -805,7 +833,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
>
> memset(format->reserved, 0, sizeof(format->reserved));
> memset(format->format.reserved, 0, sizeof(format->format.reserved));
> - return v4l2_subdev_call(sd, pad, get_fmt, state, format);
> + return v4l2_subdev_call(sd, pad, get_fmt, &subdev_fh->ci, state,
> + format);
> }
>
> case VIDIOC_SUBDEV_S_FMT: {
> @@ -819,7 +848,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
>
> memset(format->reserved, 0, sizeof(format->reserved));
> memset(format->format.reserved, 0, sizeof(format->format.reserved));
> - return v4l2_subdev_call(sd, pad, set_fmt, state, format);
> + return v4l2_subdev_call(sd, pad, set_fmt, &subdev_fh->ci, state,
> + format);
> }
>
> case VIDIOC_SUBDEV_G_CROP: {
> @@ -836,8 +866,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
> sel.stream = crop->stream;
> sel.target = V4L2_SEL_TGT_CROP;
>
> - rval = v4l2_subdev_call(
> - sd, pad, get_selection, state, &sel);
> + rval = v4l2_subdev_call(sd, pad, get_selection, &subdev_fh->ci,
> + state, &sel);
>
> crop->rect = sel.r;
>
> @@ -862,8 +892,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
> sel.target = V4L2_SEL_TGT_CROP;
> sel.r = crop->rect;
>
> - rval = v4l2_subdev_call(
> - sd, pad, set_selection, state, &sel);
> + rval = v4l2_subdev_call(sd, pad, set_selection, &subdev_fh->ci,
> + state, &sel);
>
> crop->rect = sel.r;
>
> @@ -933,8 +963,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
> sel->stream = 0;
>
> memset(sel->reserved, 0, sizeof(sel->reserved));
> - return v4l2_subdev_call(
> - sd, pad, get_selection, state, sel);
> + return v4l2_subdev_call(sd, pad, get_selection, &subdev_fh->ci,
> + state, sel);
> }
>
> case VIDIOC_SUBDEV_S_SELECTION: {
> @@ -947,8 +977,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
> sel->stream = 0;
>
> memset(sel->reserved, 0, sizeof(sel->reserved));
> - return v4l2_subdev_call(
> - sd, pad, set_selection, state, sel);
> + return v4l2_subdev_call(sd, pad, set_selection, &subdev_fh->ci,
> + state, sel);
> }
>
> case VIDIOC_G_EDID: {
> @@ -1343,7 +1373,7 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, u32 stream,
> else
> state = v4l2_subdev_lock_and_get_active_state(sd);
>
> - ret = v4l2_subdev_call(sd, pad, get_fmt, state, fmt);
> + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, state, fmt);
>
> if (!states_locked && state)
> v4l2_subdev_unlock_state(state);
> @@ -1924,7 +1954,9 @@ v4l2_subdev_init_stream_configs(struct v4l2_subdev_stream_configs *stream_config
> return 0;
> }
>
> -int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
> +int v4l2_subdev_get_fmt(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> + struct v4l2_subdev_state *state,
> struct v4l2_subdev_format *format)
> {
> struct v4l2_mbus_framefmt *fmt;
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index e0861acc638d..1ce1c18f84a9 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -850,15 +850,19 @@ struct v4l2_subdev_pad_ops {
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_frame_interval_enum *fie);
> int (*get_fmt)(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_format *format);
> int (*set_fmt)(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_format *format);
> int (*get_selection)(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_selection *sel);
> int (*set_selection)(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> struct v4l2_subdev_state *state,
> struct v4l2_subdev_selection *sel);
> int (*get_frame_interval)(struct v4l2_subdev *sd,
> @@ -1461,6 +1465,7 @@ __v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
> * @sd: subdevice
> * @state: subdevice state
> * @format: pointer to &struct v4l2_subdev_format
> + * @ci: pointer to sub-device client information, including client capabilities
> *
> * Fill @format->format field based on the information in the @format struct.
> *
> @@ -1470,7 +1475,9 @@ __v4l2_subdev_state_get_interval(struct v4l2_subdev_state *state,
> *
> * Returns 0 on success, error value otherwise.
> */
> -int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
> +int v4l2_subdev_get_fmt(struct v4l2_subdev *sd,
> + const struct v4l2_subdev_client_info *ci,
> + struct v4l2_subdev_state *state,
> struct v4l2_subdev_format *format);
>
> /**

--
Regards,

Laurent Pinchart