summaryrefslogtreecommitdiff
path: root/include/media/v4l2-subdev.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/media/v4l2-subdev.h')
-rw-r--r--include/media/v4l2-subdev.h314
1 files changed, 239 insertions, 75 deletions
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index e25a304cd0c8..fdeaae7f4e44 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -693,7 +693,7 @@ struct v4l2_subdev_stream_config {
* struct v4l2_subdev_stream_configs - A collection of stream configs.
*
* @num_configs: number of entries in @config.
- * @config: an array of &struct v4l2_subdev_stream_configs.
+ * @configs: an array of &struct v4l2_subdev_stream_configs.
*/
struct v4l2_subdev_stream_configs {
u32 num_configs;
@@ -703,22 +703,20 @@ struct v4l2_subdev_stream_configs {
/**
* struct v4l2_subdev_krouting - subdev routing table
*
- * @which: format type (from enum v4l2_subdev_format_whence)
- * @routes: &struct v4l2_subdev_route
* @num_routes: number of routes
+ * @routes: &struct v4l2_subdev_route
*
- * This structure is used to translate arguments received from
- * VIDIOC_SUBDEV_G/S_ROUTING() ioctl to subdev device drivers operations.
+ * This structure contains the routing table for a subdev.
*/
struct v4l2_subdev_krouting {
- u32 which;
- struct v4l2_subdev_route *routes;
unsigned int num_routes;
+ struct v4l2_subdev_route *routes;
};
/**
- * struct v4l2_subdev_state - Used for storing subdev information.
+ * struct v4l2_subdev_state - Used for storing subdev state information.
*
+ * @lock: mutex for the state
* @pads: &struct v4l2_subdev_pad_config array
* @routing: routing table for the subdev
* @stream_configs: stream configurations (only for V4L2_SUBDEV_FL_MULTIPLEXED)
@@ -728,6 +726,7 @@ struct v4l2_subdev_krouting {
* %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL.
*/
struct v4l2_subdev_state {
+ struct mutex lock;
struct v4l2_subdev_pad_config *pads;
struct v4l2_subdev_krouting routing;
struct v4l2_subdev_stream_configs stream_configs;
@@ -795,7 +794,6 @@ struct v4l2_subdev_state {
* pad index it has been called on is not valid or in case of
* unrecoverable failures.
*
- * @get_routing: get the subdevice routing table.
* @set_routing: enable or disable data connection routes described in the
* subdevice routing table.
*/
@@ -842,11 +840,9 @@ struct v4l2_subdev_pad_ops {
struct v4l2_mbus_config *config);
int (*set_mbus_config)(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_mbus_config *config);
- int (*get_routing)(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- struct v4l2_subdev_krouting *route);
int (*set_routing)(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
struct v4l2_subdev_krouting *route);
};
@@ -925,7 +921,12 @@ struct v4l2_subdev_internal_ops {
/*
* Set this flag if this subdev supports multiplexed streams. This means
* that the driver supports routing and handles the stream parameter in its
- * v4l2_subdev_pad_ops handlers.
+ * v4l2_subdev_pad_ops handlers. More specifically, this means:
+ *
+ * - Centrally managed active state is enabled
+ * - Legacy pad config is _not_ supported (state->pads)
+ * - Routing ioctls are available
+ * - Multiple streams per pad are supported
*/
#define V4L2_SUBDEV_FL_MULTIPLEXED (1U << 4)
@@ -982,6 +983,8 @@ struct v4l2_subdev_platform_data {
* @subdev_notifier: A sub-device notifier implicitly registered for the sub-
* device using v4l2_device_register_sensor_subdev().
* @pdata: common part of subdevice platform data
+ * @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.
@@ -1013,6 +1016,19 @@ struct v4l2_subdev {
struct v4l2_async_notifier *notifier;
struct v4l2_async_notifier *subdev_notifier;
struct v4l2_subdev_platform_data *pdata;
+
+ /*
+ * The fields below are private, and should only be accessed via
+ * appropriate functions.
+ */
+
+ /*
+ * TODO: state should most likely be changed from a pointer to an
+ * embedded field. For the time being it's kept as a pointer to more
+ * easily catch uses of state in the cases where the driver doesn't
+ * support it.
+ */
+ struct v4l2_subdev_state *state;
};
@@ -1071,8 +1087,8 @@ struct v4l2_subdev_fh {
* &struct v4l2_subdev_pad_config->try_fmt
*
* @sd: pointer to &struct v4l2_subdev
- * @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the @state array.
+ * @state: pointer to &struct v4l2_subdev_state
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array
*/
static inline struct v4l2_mbus_framefmt *
v4l2_subdev_get_try_format(struct v4l2_subdev *sd,
@@ -1090,7 +1106,7 @@ v4l2_subdev_get_try_format(struct v4l2_subdev *sd,
*
* @sd: pointer to &struct v4l2_subdev
* @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the @state array.
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
*/
static inline struct v4l2_rect *
v4l2_subdev_get_try_crop(struct v4l2_subdev *sd,
@@ -1108,7 +1124,7 @@ v4l2_subdev_get_try_crop(struct v4l2_subdev *sd,
*
* @sd: pointer to &struct v4l2_subdev
* @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the @state array.
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
*/
static inline struct v4l2_rect *
v4l2_subdev_get_try_compose(struct v4l2_subdev *sd,
@@ -1219,16 +1235,40 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
int v4l2_subdev_link_validate(struct media_link *link);
/**
- * v4l2_subdev_alloc_state - allocate v4l2_subdev_state
+ * v4l2_subdev_has_route - MC has_route implementation for subdevs
*
- * Must call v4l2_subdev_free_state() when state is no longer needed.
+ * @entity: pointer to &struct media_entity
+ * @pad0: pad number for the first pad
+ * @pad1: pad number for the second pad
+ *
+ * This function looks at the routing in subdev's active state and returns if
+ * there is a route connecting pad0 and pad1.
+ *
+ * This function can be used as implementation for
+ * media_entity_operations.has_route.
*/
-struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd);
+bool v4l2_subdev_has_route(struct media_entity *entity, unsigned int pad0,
+ unsigned int pad1);
/**
- * v4l2_subdev_free_state - uninitialize v4l2_subdev_state
+ * __v4l2_subdev_state_alloc - allocate v4l2_subdev_state
+ *
+ * @sd: pointer to &struct v4l2_subdev for which the state is being allocated.
+ * @lock_name: name of the state lock
+ * @key: lock_class_key for the lock
+ *
+ * Must call __v4l2_subdev_state_free() when state is no longer needed.
*/
-void v4l2_subdev_free_state(struct v4l2_subdev_state *state);
+struct v4l2_subdev_state *__v4l2_subdev_state_alloc(struct v4l2_subdev *sd,
+ const char *lock_name,
+ struct lock_class_key *key);
+
+/**
+ * __v4l2_subdev_state_free - free a v4l2_subdev_state
+ *
+ * @state: v4l2_subdev_state to be freed.
+ */
+void __v4l2_subdev_state_free(struct v4l2_subdev_state *state);
#endif /* CONFIG_MEDIA_CONTROLLER */
@@ -1298,96 +1338,220 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
const struct v4l2_event *ev);
/**
- * v4l2_subdev_get_routing() - Get routing from a subdevice
+ * v4l2_subdev_init_finalize() - Finalize the initialization of the subdevice
+ * @sd: The subdev
*
- * @sd: The subdev from which to get the routing
- * @state: Pointer to &struct v4l2_subdev_state
- * @routing: Pointer to the target &struct v4l2_subdev_krouting
+ * This finalizes the initialization of the subdev, including allocation of
+ * the active state for the subdev.
*
- * Get a copy of the subdevice's routing table.
+ * This must be called by the subdev drivers that use the centralized active
+ * state, after the subdev struct has been initialized and
+ * media_entity_pads_init() has been called.
*
- * Must be freed with v4l2_subdev_free_routing after use.
+ * Must call v4l2_subdev_cleanup() when the subdev is being removed.
*/
-int v4l2_subdev_get_routing(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- struct v4l2_subdev_krouting *routing);
+#define v4l2_subdev_init_finalize(sd) \
+ ({ \
+ static struct lock_class_key __key; \
+ const char *name = KBUILD_BASENAME \
+ ":" __stringify(__LINE__) ":subdev->state->lock"; \
+ __v4l2_subdev_init_finalize(sd, name, &__key); \
+ })
+
+int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
+ struct lock_class_key *key);
/**
- * v4l2_subdev_free_routing() - Free the routing
+ * v4l2_subdev_cleanup() - Release the resources needed by the subdevice
+ * @sd: The subdevice
*
- * @routing: The routing to be freed
- *
- * Frees the routing data in @routing.
+ * This will release the resources allocated in v4l2_subdev_init_finalize.
*/
-void v4l2_subdev_free_routing(struct v4l2_subdev_krouting *routing);
+void v4l2_subdev_cleanup(struct v4l2_subdev *sd);
/**
- * v4l2_subdev_cpy_routing() - Copy the routing
+ * v4l2_subdev_get_active_state() - Return the active subdev state for subdevice
+ * @sd: The subdevice
*
- * @dst: The destination routing
- * @src: The source routing
+ * Return the active state for the subdevice, or NULL if the subdev does not
+ * support active state.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_get_active_state(struct v4l2_subdev *sd)
+{
+ return sd->state;
+}
+
+/**
+ * v4l2_subdev_lock_active_state() - Lock and return the active subdev state for
+ * subdevice
+ * @sd: The subdevice
*
- * Copies routing from @src to @dst without allocating space. If @dst does not
- * have enough space, set dst->num_routes to the required number of routes, and
- * return -ENOSPC.
+ * Return the locked active state for the subdevice, or NULL if the subdev
+ * does not support active state.
*
- * Can be used in subdevice's v4l2_subdev_pad_ops.get_routing() callback.
+ * Must be unlocked with v4l2_subdev_unlock_state() after use.
*/
-int v4l2_subdev_cpy_routing(struct v4l2_subdev_krouting *dst,
- const struct v4l2_subdev_krouting *src);
+struct v4l2_subdev_state *v4l2_subdev_lock_active_state(struct v4l2_subdev *sd);
/**
- * v4l2_subdev_dup_routing() - Duplicate the routing
+ * v4l2_subdev_lock_state() - Lock the subdev state
+ * @state: The subdevice state
*
- * @dst: The destination routing
- * @src: The source routing
+ * Lock the given subdev state.
*
- * Makes a duplicate of the routing from @src to @dst by allocating enough
- * memory and making a copy of the routing.
+ * Must be unlocked with v4l2_subdev_unlock_state() after use.
+ */
+void v4l2_subdev_lock_state(struct v4l2_subdev_state *state);
+
+/**
+ * v4l2_subdev_unlock_state() - Unlock the subdev state
+ * @state: The subdevice state
+ *
+ * Unlock the given subdev state.
+ */
+void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state);
+
+/**
+ * v4l2_subdev_validate_and_lock_state() - Gets locked TRY or ACTIVE subdev
+ * state
+ * @sd: subdevice
+ * @state: subdevice state as passed to the subdev op
+ *
+ * Due to legacy reasons, when subdev drivers call ops in other subdevs they use
+ * NULL as the state parameter, as subdevs always used to have their active
+ * 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.
+ *
+ * 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.
+ *
+ * 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)
+{
+ state = state ? state : sd->state;
+
+ v4l2_subdev_lock_state(state);
+
+ return state;
+}
+
+/**
+ * v4l2_subdev_set_routing() - Set given routing to subdev state
+ * @sd: The subdevice
+ * @state: The subdevice state
+ * @routing: Routing that will be copied to subdev state
*
- * Can be used in subdevice's v4l2_subdev_pad_ops.set_routing() callback
- * to store the given routing.
+ * This will release old routing table (if any) from the state, allocate
+ * enough space for the given routing, and copy the routing.
*
- * Must be freed with v4l2_subdev_free_routing after use.
+ * This can be used from the subdev driver's set_routing op, after validating
+ * the routing.
*/
-int v4l2_subdev_dup_routing(struct v4l2_subdev_krouting *dst,
- const struct v4l2_subdev_krouting *src);
+int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing);
/**
- * v4l2_subdev_has_route() - Check if there is a route between two pads
+ * v4l2_subdev_set_routing_with_fmt() - Set given routing and format to subdev
+ * state
+ * @sd: The subdevice
+ * @state: The subdevice state
+ * @routing: Routing that will be copied to subdev state
+ * @fmt: Format used to initialize all the streams
+ *
+ * This is the same as v4l2_subdev_set_routing, but additionally initializes
+ * all the streams using the given format.
+ */
+int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing,
+ const struct v4l2_mbus_framefmt *fmt);
+
+/**
+ * v4l2_state_get_stream_format() - Get pointer to a stream format
+ * @state: subdevice state
+ * @pad: pad id
+ * @stream: stream id
*
- * @routing: The subdevice's routing
- * @pad0: First pad
- * @pad1: Second pad
+ * This returns a pointer to &struct v4l2_mbus_framefmt for the given pad +
+ * stream in the subdev state.
*
- * Returns whether there is a route between @pad0 and @pad1 of the same
- * subdevice according to the given routing.
+ * If the state does not contain the given pad + stream, NULL is returned.
*/
-bool v4l2_subdev_has_route(struct v4l2_subdev_krouting *routing,
- unsigned int pad0, unsigned int pad1);
+struct v4l2_mbus_framefmt *
+v4l2_state_get_stream_format(struct v4l2_subdev_state *state, unsigned int pad,
+ u32 stream);
+/**
+ * v4l2_state_find_opposite_end() - Find the opposite stream
+ * @routing: routing used to find the opposite side
+ * @pad: pad id
+ * @stream: stream id
+ * @other_pad: pointer used to return the opposite pad
+ * @other_stream: pointer used to return the opposite stream
+ *
+ * This function uses the routing table to find the pad + stream which is
+ * opposite the given pad + stream.
+ *
+ * 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);
/**
- * v4l2_init_stream_configs() - Initialize stream configs according to routing
+ * v4l2_state_get_opposite_stream_format() - Get pointer to opposite stream
+ * format
+ * @state: subdevice state
+ * @pad: pad id
+ * @stream: stream id
+ *
+ * This returns a pointer to &struct v4l2_mbus_framefmt for the pad + stream
+ * that is opposite the given pad + stream in the subdev state.
+ *
+ * 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_get_fmt() - Fill format based on state
+ * @sd: subdevice
+ * @state: subdevice state
+ * @format: pointer to &struct v4l2_subdev_format
*
- * @stream_configs: The stream configs to initialize
- * @routing: The routing used for the stream configs
+ * Fill @format based on the pad and stream given in the @format struct.
*
- * Initializes @stream_configs according to @routing, allocating enough
- * space to hold configuration for each route endpoint.
+ * This function can be used by the subdev drivers to implement
+ * v4l2_subdev_pad_ops.get_fmt if the subdev driver does not need to do
+ * anything special in their get_fmt op.
*
- * Must be freed with v4l2_uninit_stream_configs().
+ * Returns 0 on success, error value otherwise.
*/
-int v4l2_init_stream_configs(struct v4l2_subdev_stream_configs *stream_configs,
- const struct v4l2_subdev_krouting *routing);
+int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format);
/**
- * v4l2_uninit_stream_configs() - Uninitialize stream configs
+ * v4l2_routing_simple_verify() - Verify that all streams are non-overlapping
+ * 1-to-1 streams
+ * @routing: routing to verify
*
- * @stream_configs: The stream configs to uninitialize
+ * This verifies that the given routing contains only non-overlapping 1-to-1
+ * streams. In other words, no two streams have the same source or sink
+ * stream ID on a single pad. This is the most common case of routing
+ * supported by devices.
*
- * Frees any allocated memory in @stream_configs.
+ * Returns 0 on success, error value otherwise.
*/
-void v4l2_uninit_stream_configs(struct v4l2_subdev_stream_configs *stream_configs);
+int v4l2_routing_simple_verify(const struct v4l2_subdev_krouting *routing);
#endif