Message ID | 20211130141536.891878-1-tomi.valkeinen@ideasonboard.com |
---|---|
Headers | show |
Series | v4l: subdev internal routing and streams | expand |
On 30/11/2021 16:14, Tomi Valkeinen wrote: > Hi, > > This is v10 of the multiplexed streams series. v8 can be found from: That's supposed to be v9, not v8. > https://lore.kernel.org/all/20211005085750.138151-1-tomi.valkeinen@ideasonboard.com/ > > I have pushed my work branch to: > > git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux.git multistream/work-v10 > > which contains the patches in this series, along with subdev drivers > using multiplexed streams. > > I have also pushed v4l-utils changes to: > > https://github.com/tomba/v4l-utils.git streams-review-v1 > > Changes to v9: > > - Add V4L2_SUBDEV_CAP_MPLEXED flag > - Use standard kmalloc and kmemdup for routes > - Allow NULL as pad/stream param for v4l2_state_find_opposite_end > - Add for_each_active_route > - Use _BITUL() in uapi header > - Rearrange struct v4l2_subdev_routing members to align on 64 bit > - Renames: > sd->state -> sd->active_state > v4l2_state_find_opposite_end -> v4l2_subdev_routing_find_opposite_end > v4l2_state_get_opposite_stream_format -> v4l2_subdev_state_get_opposite_stream_format > v4l2_routing_simple_verify -> v4l2_subdev_routing_validate_1_to_1 > v4l2_subdev_validate_and_lock_state -> v4l2_subdev_lock_and_return_state > - Doc & comment updates To help reviews, here's the diff to the v8. Tomi diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst index 410e03a29f2a..1d986e814b4e 100644 --- a/Documentation/driver-api/media/v4l2-subdev.rst +++ b/Documentation/driver-api/media/v4l2-subdev.rst @@ -525,9 +525,9 @@ Traditionally V4L2 subdev drivers maintained internal state for the active configuration for the subdev. This is often implemented as an array of struct v4l2_mbus_framefmt, one entry for each pad. -In addition to the active configuration, each subdev filehandle has contained -an array of struct v4l2_subdev_pad_config, managed by V4L2 core, which -contains the TRY configuration. +In addition to the active configuration, each subdev filehandle has an array of +struct v4l2_subdev_pad_config, managed by V4L2 core, which contains the TRY +configuration. To simplify the subdev drivers the V4L2 subdev API now optionally supports a centrally managed active configuration. A subdev driver must use @@ -535,13 +535,13 @@ v4l2_subdev_init_finalize() to initialize the active state between calls to media_entity_pads_init() and v4l2_*_register_subdev(), and must call v4l2_subdev_cleanup() to free the state. -The active state must be locked before access, and can be done with +The active state must be locked before access, and that can be done with v4l2_subdev_lock_state() or v4l2_subdev_lock_active_state(). The V4L2 core will pass either the TRY or ACTIVE state to various subdev ops. -Unfortunately all the subdev drivers do not comply with this yet, and may pass +Unfortunately not all the subdev drivers comply with this yet, and may pass NULL for the ACTIVE case. This is only a problem for subdev drivers which use -the cetrally managed active state and are used in media pipelines with older +the centrally managed active state and are used in media pipelines with older subdev drivers. In these cases the called subdev ops must also handle the NULL case. This can be easily managed by the use of v4l2_subdev_validate_and_lock_state() helper. diff --git a/Documentation/userspace-api/media/v4l/dev-subdev.rst b/Documentation/userspace-api/media/v4l/dev-subdev.rst index ea3efa97bb08..fd042afeddd6 100644 --- a/Documentation/userspace-api/media/v4l/dev-subdev.rst +++ b/Documentation/userspace-api/media/v4l/dev-subdev.rst @@ -508,7 +508,7 @@ Streams, multiplexed media pads and internal routing ---------------------------------------------------- Commonly V4L2 subdevices support only separate video streams, that is, each -link in the media grap and each pad in a subdevice passes through a single +link in the media graph and each pad in a subdevice pass through a single video stream. Thus each pad contains a format configuration for that single stream. In some cases a subdev can do stream processing and split a stream into two or compose two streams into one, but the inputs and outputs for the @@ -520,22 +520,22 @@ stream and a metadata stream, and a bridge subdev could route the streams from multiple input pads into a single output pad. Subdevice drivers that support multiplexed streams are compatible with -non-multiplexed subdev drivers, but, of course, requires such a routing -configuration where the link between those two types of drivers contain only -a single stream. +non-multiplexed subdev drivers, but, of course, require a routing configuration +where the link between those two types of drivers contains only a single +stream. Understanding streams ^^^^^^^^^^^^^^^^^^^^^ A stream is a stream of content (e.g. pixel data or metadata) flowing through -the media pipeline from a source (e.g. a sensor) towards the final sink -(e.g. a receiver in a SoC). Each media link carries all the streams from -one end of the link to the other, whereas subdevices have routing tables -which describe how the incoming streams from sink pads are routed to the -source pads. +the media pipeline from a source (e.g. a sensor) towards the final sink(e.g. a +receiver and demultiplexer in a SoC). Each media link carries all the streams +from one end of the link to the other, and subdevices have routing tables which +describe how the incoming streams from sink pads are routed to the source +pads. A stream ID (often just "stream") is a media link-local identifier for a -stream. In other words, configuration for a particular stream ID must exist +stream. In other words, a configuration for a particular stream ID must exist on both sides of a media link, but another stream ID can be used for the same stream at the other side of the subdevice. @@ -556,7 +556,8 @@ There are three steps in configuring the streams: Controller API <media_controller>` 2) Routing. The routing table for the subdevice must be set with -:ref:`VIDIOC_SUBDEV_S_ROUTING <VIDIOC_SUBDEV_G_ROUTING>` ioctl. +:ref:`VIDIOC_SUBDEV_S_ROUTING <VIDIOC_SUBDEV_G_ROUTING>` ioctl. Note that +setting the routing table will reset all the stream configurations. 3) Configure streams. Each route endpoint must be configured with :ref:`VIDIOC_SUBDEV_S_FMT <VIDIOC_SUBDEV_G_FMT>`. @@ -662,8 +663,8 @@ not differ from normal non-multiplexed media controller setup. After configuring the routing table, the next step is configuring the streams. This step is similar to configuring the pads in a non-multiplexed streams setup, with the difference that we need to configure each (pad, stream) pair -(i.e. route endpoint), instead of just a pad. +(i.e. route endpoint) instead of just a pad. -Presuming there are no format conversions in the pipeline, the userspace needs -to configure all the route endpoints using four formats (two pixel formats -and two metadata formats) with VIDIOC_SUBDEV_S_FMT. +A common way to accomplish this is to start from the sensors and propagate the +configurations along the stream towards the receiver, using VIDIOC_SUBDEV_S_FMT +to configure each stream endpoint in each subdev. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst index 41f4873c49f7..a0d9c79e162f 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst @@ -41,19 +41,23 @@ The routing configuration determines the flows of data inside an entity. Drivers report their current routing tables using the ``VIDIOC_SUBDEV_G_ROUTING`` ioctl and application may enable or disable routes -with the VIDIOC_SUBDEV_S_ROUTING ioctl, by adding or removing routes and setting -or clearing the ``V4L2_SUBDEV_ROUTE_FL_ACTIVE`` flag of the ``flags`` field of -a struct :c:type:`v4l2_subdev_route`. +with the ``VIDIOC_SUBDEV_S_ROUTING`` ioctl, by adding or removing routes and +setting or clearing flags of the ``flags`` field of a +struct :c:type:`v4l2_subdev_route`. + +All stream configurations are reset when ``VIDIOC_SUBDEV_S_ROUTING`` is called. This +means that the userspace mut reconfigure all streams after calling the ioctl +with e.g. ``VIDIOC_SUBDEV_S_FMT``. A special case for routing are routes marked with ``V4L2_SUBDEV_ROUTE_FL_SOURCE`` flag. These routes are used to describe source endpoints on sensors and the sink fields are unused. -When inspecting routes through VIDIOC_SUBDEV_G_ROUTING and the application +When inspecting routes through ``VIDIOC_SUBDEV_G_ROUTING`` and the application provided ``num_routes`` is not big enough to contain all the available routes the subdevice exposes, drivers return the ENOSPC error code and adjust the value of the ``num_routes`` field. Application should then reserve enough memory -for all the route entries and call VIDIOC_SUBDEV_G_ROUTING again. +for all the route entries and call ``VIDIOC_SUBDEV_G_ROUTING`` again. .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 2a64ff003e4b..dca2bea180ec 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -175,7 +175,7 @@ static int check_state_pad_stream(struct v4l2_subdev *sd, * We need to take the state lock to access the format, but as we then * have to unlock, nothing prevents someone changing the state before * this call thread enters the driver's op and the driver has the - * change to lock the state. + * chance to lock the state. */ v4l2_subdev_lock_state(state); @@ -462,7 +462,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(cap->reserved, 0, sizeof(cap->reserved)); cap->version = LINUX_VERSION_CODE; - cap->capabilities = ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0; + cap->capabilities = + (ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0) | + ((sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED) ? V4L2_SUBDEV_CAP_MPLEXED : 0); return 0; } @@ -1197,7 +1199,11 @@ int v4l2_subdev_link_validate(struct media_link *link) if (ret) goto free_source; - /* It is ok to have more source streams than sink streams */ + /* + * It is ok to have more source streams than sink streams as extra + * source streams can just be ignored (i.e. they go nowhere), but extra + * sink streams is an error. + */ if (num_source_streams < num_sink_streams) { dev_err(dev, "Not enough source streams: %d < %d\n", @@ -1358,7 +1364,7 @@ void __v4l2_subdev_state_free(struct v4l2_subdev_state *state) mutex_destroy(&state->lock); - kvfree(state->routing.routes); + kfree(state->routing.routes); kvfree(state->stream_configs.configs); kvfree(state->pads); kfree(state); @@ -1403,7 +1409,7 @@ int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name, if (IS_ERR(state)) return PTR_ERR(state); - sd->state = state; + sd->active_state = state; return 0; } @@ -1411,16 +1417,16 @@ EXPORT_SYMBOL_GPL(__v4l2_subdev_init_finalize); void v4l2_subdev_cleanup(struct v4l2_subdev *sd) { - __v4l2_subdev_state_free(sd->state); - sd->state = NULL; + __v4l2_subdev_state_free(sd->active_state); + sd->active_state = NULL; } EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup); struct v4l2_subdev_state *v4l2_subdev_lock_active_state(struct v4l2_subdev *sd) { - mutex_lock(&sd->state->lock); + mutex_lock(&sd->active_state->lock); - return sd->state; + return sd->active_state; } EXPORT_SYMBOL_GPL(v4l2_subdev_lock_active_state); @@ -1445,18 +1451,17 @@ int v4l2_subdev_set_routing(struct v4l2_subdev *sd, lockdep_assert_held(&state->lock); - kvfree(dst->routes); + kfree(dst->routes); dst->routes = NULL; dst->num_routes = 0; if (src->num_routes > 0) { - dst->routes = kvmalloc_array(src->num_routes, - sizeof(*src->routes), GFP_KERNEL); + dst->routes = kmemdup(src->routes, + src->num_routes * sizeof(*src->routes), + GFP_KERNEL); if (!dst->routes) return -ENOMEM; - memcpy(dst->routes, src->routes, - src->num_routes * sizeof(*src->routes)); dst->num_routes = src->num_routes; } @@ -1507,8 +1512,9 @@ v4l2_state_get_stream_format(struct v4l2_subdev_state *state, unsigned int pad, } EXPORT_SYMBOL_GPL(v4l2_state_get_stream_format); -int v4l2_state_find_opposite_end(struct v4l2_subdev_krouting *routing, u32 pad, - u32 stream, u32 *other_pad, u32 *other_stream) +int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, + u32 pad, u32 stream, u32 *other_pad, + u32 *other_stream) { unsigned int i; @@ -1517,37 +1523,41 @@ int v4l2_state_find_opposite_end(struct v4l2_subdev_krouting *routing, u32 pad, if (route->source_pad == pad && route->source_stream == stream) { - *other_pad = route->sink_pad; - *other_stream = route->sink_stream; + if (other_pad) + *other_pad = route->sink_pad; + if (other_stream) + *other_stream = route->sink_stream; return 0; } if (route->sink_pad == pad && route->sink_stream == stream) { - *other_pad = route->source_pad; - *other_stream = route->source_stream; + if (other_pad) + *other_pad = route->source_pad; + if (other_stream) + *other_stream = route->source_stream; return 0; } } return -EINVAL; } -EXPORT_SYMBOL_GPL(v4l2_state_find_opposite_end); +EXPORT_SYMBOL_GPL(v4l2_subdev_routing_find_opposite_end); struct v4l2_mbus_framefmt * -v4l2_state_get_opposite_stream_format(struct v4l2_subdev_state *state, u32 pad, - u32 stream) +v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state, + u32 pad, u32 stream) { u32 other_pad, other_stream; int ret; - ret = v4l2_state_find_opposite_end(&state->routing, pad, stream, - &other_pad, &other_stream); + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, pad, stream, + &other_pad, &other_stream); if (ret) return NULL; return v4l2_state_get_stream_format(state, other_pad, other_stream); } -EXPORT_SYMBOL_GPL(v4l2_state_get_opposite_stream_format); +EXPORT_SYMBOL_GPL(v4l2_subdev_state_get_opposite_stream_format); int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format) @@ -1570,7 +1580,7 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, } EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt); -int v4l2_routing_simple_verify(const struct v4l2_subdev_krouting *routing) +int v4l2_subdev_routing_validate_1_to_1(const struct v4l2_subdev_krouting *routing) { unsigned int i, j; @@ -1592,4 +1602,24 @@ int v4l2_routing_simple_verify(const struct v4l2_subdev_krouting *routing) return 0; } -EXPORT_SYMBOL_GPL(v4l2_routing_simple_verify); +EXPORT_SYMBOL_GPL(v4l2_subdev_routing_validate_1_to_1); + +struct v4l2_subdev_route * +__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing, + struct v4l2_subdev_route *route) +{ + if (route) + ++route; + else + route = &routing->routes[0]; + + for (; route < routing->routes + routing->num_routes; ++route) { + if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)) + continue; + + return route; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(__v4l2_subdev_next_active_route); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5e50f2ded653..9754913b34f8 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -687,6 +687,9 @@ struct v4l2_subdev_ir_ops { * This structure only needs to be passed to the pad op if the 'which' field * of the main argument is set to %V4L2_SUBDEV_FORMAT_TRY. For * %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL. + * + * Note: This struct is also used in active state, and the try_ prefix is + * historical and to be removed. */ struct v4l2_subdev_pad_config { struct v4l2_mbus_framefmt try_fmt; @@ -751,6 +754,7 @@ struct v4l2_subdev_krouting { * %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL. */ struct v4l2_subdev_state { + /* lock for the struct v4l2_subdev_state fields */ struct mutex lock; struct v4l2_subdev_pad_config *pads; struct v4l2_subdev_krouting routing; @@ -1008,8 +1012,8 @@ struct v4l2_subdev_platform_data { * @subdev_notifier: A sub-device notifier implicitly registered for the sub- * device using v4l2_async_register_subdev_sensor(). * @pdata: common part of subdevice platform data - * @state: active state for the subdev (NULL for subdevs tracking the state - * internally) + * @active_state: active state for the subdev (NULL for subdevs tracking the + * state internally) * * Each instance of a subdev driver should create this struct, either * stand-alone or embedded in a larger struct. @@ -1053,7 +1057,7 @@ struct v4l2_subdev { * easily catch uses of state in the cases where the driver doesn't * support it. */ - struct v4l2_subdev_state *state; + struct v4l2_subdev_state *active_state; }; @@ -1404,7 +1408,7 @@ void v4l2_subdev_cleanup(struct v4l2_subdev *sd); static inline struct v4l2_subdev_state * v4l2_subdev_get_active_state(struct v4l2_subdev *sd) { - return sd->state; + return sd->active_state; } /** @@ -1438,8 +1442,7 @@ void v4l2_subdev_lock_state(struct v4l2_subdev_state *state); void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state); /** - * v4l2_subdev_validate_and_lock_state() - Gets locked TRY or ACTIVE subdev - * state + * v4l2_subdev_lock_and_return_state() - Gets locked TRY or ACTIVE subdev state * @sd: subdevice * @state: subdevice state as passed to the subdev op * @@ -1448,22 +1451,21 @@ void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state); * state stored privately. * * However, newer state-aware subdev drivers, which store their active state in - * a common place, subdev->state, expect to always get a proper state as a - * parameter. + * a common place, subdev->active_state, expect to always get a proper state as + * a parameter. * - * These state-aware drivers can use v4l2_subdev_validate_and_lock_state() - * instead of v4l2_subdev_lock_state(). v4l2_subdev_validate_and_lock_state() - * solves the issue by using subdev->state in case the passed state is - * NULL. + * These state-aware drivers can use v4l2_subdev_lock_and_return_state() instead + * of v4l2_subdev_lock_state(). v4l2_subdev_lock_and_return_state() solves the + * issue by using subdev->state in case the passed state is NULL. * * This is a temporary helper function, and should be removed when we can ensure * that all drivers pass proper state when calling other subdevs. */ static inline struct v4l2_subdev_state * -v4l2_subdev_validate_and_lock_state(struct v4l2_subdev *sd, - struct v4l2_subdev_state *state) +v4l2_subdev_lock_and_return_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) { - state = state ? state : sd->state; + state = state ? state : sd->active_state; v4l2_subdev_lock_state(state); @@ -1518,7 +1520,7 @@ v4l2_state_get_stream_format(struct v4l2_subdev_state *state, unsigned int pad, u32 stream); /** - * v4l2_state_find_opposite_end() - Find the opposite stream + * v4l2_subdev_routing_find_opposite_end() - Find the opposite stream * @routing: routing used to find the opposite side * @pad: pad id * @stream: stream id @@ -1528,14 +1530,18 @@ v4l2_state_get_stream_format(struct v4l2_subdev_state *state, unsigned int pad, * This function uses the routing table to find the pad + stream which is * opposite the given pad + stream. * + * @other_pad and/or @other_stream can be NULL if the caller does not need the + * value. + * * Returns 0 on success, or -EINVAL if no matching route is found. */ -int v4l2_state_find_opposite_end(struct v4l2_subdev_krouting *routing, u32 pad, - u32 stream, u32 *other_pad, u32 *other_stream); +int v4l2_subdev_routing_find_opposite_end(const struct v4l2_subdev_krouting *routing, + u32 pad, u32 stream, u32 *other_pad, + u32 *other_stream); /** - * v4l2_state_get_opposite_stream_format() - Get pointer to opposite stream - * format + * v4l2_subdev_state_get_opposite_stream_format() - Get pointer to opposite + * stream format * @state: subdevice state * @pad: pad id * @stream: stream id @@ -1546,8 +1552,9 @@ int v4l2_state_find_opposite_end(struct v4l2_subdev_krouting *routing, u32 pad, * If the state does not contain the given pad + stream, NULL is returned. */ struct v4l2_mbus_framefmt * -v4l2_state_get_opposite_stream_format(struct v4l2_subdev_state *state, u32 pad, - u32 stream); +v4l2_subdev_state_get_opposite_stream_format(struct v4l2_subdev_state *state, + u32 pad, u32 stream); + /** * v4l2_subdev_get_fmt() - Fill format based on state * @sd: subdevice @@ -1566,8 +1573,8 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format); /** - * v4l2_routing_simple_verify() - Verify that all streams are non-overlapping - * 1-to-1 streams + * v4l2_subdev_routing_validate_1_to_1() - Verify that all streams are + * non-overlapping 1-to-1 streams * @routing: routing to verify * * This verifies that the given routing contains only non-overlapping 1-to-1 @@ -1577,6 +1584,19 @@ int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, * * Returns 0 on success, error value otherwise. */ -int v4l2_routing_simple_verify(const struct v4l2_subdev_krouting *routing); +int v4l2_subdev_routing_validate_1_to_1(const struct v4l2_subdev_krouting *routing); + +struct v4l2_subdev_route * +__v4l2_subdev_next_active_route(const struct v4l2_subdev_krouting *routing, + struct v4l2_subdev_route *route); + +/** + * for_each_active_route - iterate on all active routes of a routing table + * @routing: The routing table + * @route: The route iterator + */ +#define for_each_active_route(routing, route) \ + for ((route) = NULL; \ + ((route) = __v4l2_subdev_next_active_route((routing), (route)));) #endif diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h index f61ace2b5755..480891dba193 100644 --- a/include/uapi/linux/v4l2-subdev.h +++ b/include/uapi/linux/v4l2-subdev.h @@ -202,17 +202,20 @@ struct v4l2_subdev_capability { /* The v4l2 sub-device video device node is registered in read-only mode. */ #define V4L2_SUBDEV_CAP_RO_SUBDEV 0x00000001 +/* The v4l2 sub-device supports multiplexed streams. */ +#define V4L2_SUBDEV_CAP_MPLEXED 0x00000002 + /* * Is the route active? An active route will start when streaming is enabled * on a video node. */ -#define V4L2_SUBDEV_ROUTE_FL_ACTIVE (1 << 0) +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE _BITUL(0) /* * Is the route immutable, i.e. can it be activated and inactivated? * Set by the driver. */ -#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE (1 << 1) +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE _BITUL(1) /* * Is the route a source endpoint? A source endpoint route refers to a stream @@ -221,7 +224,7 @@ struct v4l2_subdev_capability { * fields are unused. * Set by the driver. */ -#define V4L2_SUBDEV_ROUTE_FL_SOURCE (1 << 2) +#define V4L2_SUBDEV_ROUTE_FL_SOURCE _BITUL(2) /** * struct v4l2_subdev_route - A route inside a subdev @@ -246,15 +249,15 @@ struct v4l2_subdev_route { * struct v4l2_subdev_routing - Subdev routing information * * @which: configuration type (from enum v4l2_subdev_format_whence) - * @routes: pointer to the routes array * @num_routes: the total number of routes in the routes array + * @routes: pointer to the routes array * @reserved: drivers and applications must zero this array */ struct v4l2_subdev_routing { __u32 which; - __u64 routes; __u32 num_routes; - __u32 reserved[5]; + __u64 routes; + __u32 reserved[6]; }; /* Backwards compatibility define --- to be removed */