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

Sakari Ailus
2026-04-08T15:40:28Z

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.

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);

/**
--
2.47.3