Skip to content

Commit

Permalink
media: subdev: add stream based configuration
Browse files Browse the repository at this point in the history
Add support to manage configurations (format, crop, compose) per stream,
instead of per pad. This is accomplished with data structures that hold
an array of all subdev's stream configurations.

The number of streams can vary at runtime based on routing. Every time
the routing is changed, the stream configurations need to be
re-initialized.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
  • Loading branch information
tomba authored and mchehab committed Jan 22, 2023
1 parent 70283e9 commit 2f91e10
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ multiple pads of the same sub-device is not defined.
- Frame intervals to be enumerated, from enum
:ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.
* - __u32
- ``reserved``\ [8]
- ``stream``
- Stream identifier.
* - __u32
- ``reserved``\ [7]
- Reserved for future extensions. Applications and drivers must set
the array to zero.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ information about try formats.
- Frame sizes to be enumerated, from enum
:ref:`v4l2_subdev_format_whence <v4l2-subdev-format-whence>`.
* - __u32
- ``reserved``\ [8]
- ``stream``
- Stream identifier.
* - __u32
- ``reserved``\ [7]
- Reserved for future extensions. Applications and drivers must set
the array to zero.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ information about the try formats.
- ``flags``
- See :ref:`v4l2-subdev-mbus-code-flags`
* - __u32
- ``reserved``\ [7]
- ``stream``
- Stream identifier.
* - __u32
- ``reserved``\ [6]
- Reserved for future extensions. Applications and drivers must set
the array to zero.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ modified format should be as close as possible to the original request.
- ``rect``
- Crop rectangle boundaries, in pixels.
* - __u32
- ``reserved``\ [8]
- ``stream``
- Stream identifier.
* - __u32
- ``reserved``\ [7]
- Reserved for future extensions. Applications and drivers must set
the array to zero.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ should be as close as possible to the original request.
- Definition of an image format, see :c:type:`v4l2_mbus_framefmt` for
details.
* - __u32
- ``reserved``\ [8]
- ``stream``
- Stream identifier.
* - __u32
- ``reserved``\ [7]
- Reserved for future extensions. Applications and drivers must set
the array to zero.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ the same sub-device is not defined.
- ``interval``
- Period, in seconds, between consecutive video frames.
* - __u32
- ``reserved``\ [9]
- ``stream``
- Stream identifier.
* - __u32
- ``reserved``\ [8]
- Reserved for future extensions. Applications and drivers must set
the array to zero.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ Selection targets and flags are documented in
- ``r``
- Selection rectangle, in pixels.
* - __u32
- ``reserved``\ [8]
- ``stream``
- Stream identifier.
* - __u32
- ``reserved``\ [7]
- Reserved for future extensions. Applications and drivers must set
the array to zero.

Expand Down
150 changes: 143 additions & 7 deletions drivers/media/v4l2-core/v4l2-subdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,22 @@ static inline int check_pad(struct v4l2_subdev *sd, u32 pad)
return 0;
}

static int check_state_pads(u32 which, struct v4l2_subdev_state *state)
static int check_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
u32 which, u32 pad, u32 stream)
{
if (sd->flags & V4L2_SUBDEV_FL_STREAMS) {
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
if (!v4l2_subdev_state_get_stream_format(state, pad, stream))
return -EINVAL;
return 0;
#else
return -EINVAL;
#endif
}

if (stream != 0)
return -EINVAL;

if (which == V4L2_SUBDEV_FORMAT_TRY && (!state || !state->pads))
return -EINVAL;

Expand All @@ -184,7 +198,7 @@ static inline int check_format(struct v4l2_subdev *sd,
return -EINVAL;

return check_which(format->which) ? : check_pad(sd, format->pad) ? :
check_state_pads(format->which, state);
check_state(sd, state, format->which, format->pad, format->stream);
}

static int call_get_fmt(struct v4l2_subdev *sd,
Expand All @@ -211,7 +225,7 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
return -EINVAL;

return check_which(code->which) ? : check_pad(sd, code->pad) ? :
check_state_pads(code->which, state) ? :
check_state(sd, state, code->which, code->pad, code->stream) ? :
sd->ops->pad->enum_mbus_code(sd, state, code);
}

Expand All @@ -223,7 +237,7 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;

return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
check_state_pads(fse->which, state) ? :
check_state(sd, state, fse->which, fse->pad, fse->stream) ? :
sd->ops->pad->enum_frame_size(sd, state, fse);
}

Expand Down Expand Up @@ -258,7 +272,7 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
return -EINVAL;

return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
check_state_pads(fie->which, state) ? :
check_state(sd, state, fie->which, fie->pad, fie->stream) ? :
sd->ops->pad->enum_frame_interval(sd, state, fie);
}

Expand All @@ -270,7 +284,7 @@ static inline int check_selection(struct v4l2_subdev *sd,
return -EINVAL;

return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
check_state_pads(sel->which, state);
check_state(sd, state, sel->which, sel->pad, sel->stream);
}

static int call_get_selection(struct v4l2_subdev *sd,
Expand Down Expand Up @@ -1122,7 +1136,8 @@ __v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
else
state->lock = &state->_lock;

if (sd->entity.num_pads) {
/* Drivers that support streams do not need the legacy pad config */
if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS) && sd->entity.num_pads) {
state->pads = kvcalloc(sd->entity.num_pads,
sizeof(*state->pads), GFP_KERNEL);
if (!state->pads) {
Expand Down Expand Up @@ -1162,6 +1177,7 @@ void __v4l2_subdev_state_free(struct v4l2_subdev_state *state)
mutex_destroy(&state->_lock);

kfree(state->routing.routes);
kvfree(state->stream_configs.configs);
kvfree(state->pads);
kfree(state);
}
Expand Down Expand Up @@ -1191,6 +1207,55 @@ EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup);

#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)

static int
v4l2_subdev_init_stream_configs(struct v4l2_subdev_stream_configs *stream_configs,
const struct v4l2_subdev_krouting *routing)
{
struct v4l2_subdev_stream_configs new_configs = { 0 };
struct v4l2_subdev_route *route;
u32 idx;

/* Count number of formats needed */
for_each_active_route(routing, route) {
/*
* Each route needs a format on both ends of the route.
*/
new_configs.num_configs += 2;
}

if (new_configs.num_configs) {
new_configs.configs = kvcalloc(new_configs.num_configs,
sizeof(*new_configs.configs),
GFP_KERNEL);

if (!new_configs.configs)
return -ENOMEM;
}

/*
* Fill in the 'pad' and stream' value for each item in the array from
* the routing table
*/
idx = 0;

for_each_active_route(routing, route) {
new_configs.configs[idx].pad = route->sink_pad;
new_configs.configs[idx].stream = route->sink_stream;

idx++;

new_configs.configs[idx].pad = route->source_pad;
new_configs.configs[idx].stream = route->source_stream;

idx++;
}

kvfree(stream_configs->configs);
*stream_configs = new_configs;

return 0;
}

int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
Expand All @@ -1217,6 +1282,7 @@ int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
const struct v4l2_subdev_krouting *src = routing;
struct v4l2_subdev_krouting new_routing = { 0 };
size_t bytes;
int r;

if (unlikely(check_mul_overflow((size_t)src->num_routes,
sizeof(*src->routes), &bytes)))
Expand All @@ -1232,6 +1298,13 @@ int v4l2_subdev_set_routing(struct v4l2_subdev *sd,

new_routing.num_routes = src->num_routes;

r = v4l2_subdev_init_stream_configs(&state->stream_configs,
&new_routing);
if (r) {
kfree(new_routing.routes);
return r;
}

kfree(dst->routes);
*dst = new_routing;

Expand Down Expand Up @@ -1259,6 +1332,69 @@ __v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing,
}
EXPORT_SYMBOL_GPL(__v4l2_subdev_next_active_route);

struct v4l2_mbus_framefmt *
v4l2_subdev_state_get_stream_format(struct v4l2_subdev_state *state,
unsigned int pad, u32 stream)
{
struct v4l2_subdev_stream_configs *stream_configs;
unsigned int i;

lockdep_assert_held(state->lock);

stream_configs = &state->stream_configs;

for (i = 0; i < stream_configs->num_configs; ++i) {
if (stream_configs->configs[i].pad == pad &&
stream_configs->configs[i].stream == stream)
return &stream_configs->configs[i].fmt;
}

return NULL;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_format);

struct v4l2_rect *
v4l2_subdev_state_get_stream_crop(struct v4l2_subdev_state *state,
unsigned int pad, u32 stream)
{
struct v4l2_subdev_stream_configs *stream_configs;
unsigned int i;

lockdep_assert_held(state->lock);

stream_configs = &state->stream_configs;

for (i = 0; i < stream_configs->num_configs; ++i) {
if (stream_configs->configs[i].pad == pad &&
stream_configs->configs[i].stream == stream)
return &stream_configs->configs[i].crop;
}

return NULL;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_crop);

struct v4l2_rect *
v4l2_subdev_state_get_stream_compose(struct v4l2_subdev_state *state,
unsigned int pad, u32 stream)
{
struct v4l2_subdev_stream_configs *stream_configs;
unsigned int i;

lockdep_assert_held(state->lock);

stream_configs = &state->stream_configs;

for (i = 0; i < stream_configs->num_configs; ++i) {
if (stream_configs->configs[i].pad == pad &&
stream_configs->configs[i].stream == stream)
return &stream_configs->configs[i].compose;
}

return NULL;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_stream_compose);

#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */

#endif /* CONFIG_MEDIA_CONTROLLER */
Expand Down
Loading

0 comments on commit 2f91e10

Please sign in to comment.