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.h133
1 files changed, 127 insertions, 6 deletions
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index eab8e4342613..f967c27e41c3 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -658,6 +658,8 @@ struct v4l2_subdev_pad_config {
/**
* struct v4l2_subdev_state - Used for storing subdev state information.
*
+ * @_lock: default for 'lock'
+ * @lock: mutex for the state. May be replaced by the user.
* @pads: &struct v4l2_subdev_pad_config array
*
* This structure only needs to be passed to the pad op if the 'which' field
@@ -665,6 +667,9 @@ struct v4l2_subdev_pad_config {
* %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 mutex *lock;
struct v4l2_subdev_pad_config *pads;
};
@@ -888,6 +893,9 @@ 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_lock: A pointer to a lock used for all the subdev's states, set by the
+ * driver. This is optional. If NULL, each state instance will get
+ * a lock of its own.
* @active_state: Active state for the subdev (NULL for subdevs tracking the
* state internally). Initialized by calling
* v4l2_subdev_init_finalize().
@@ -922,6 +930,7 @@ struct v4l2_subdev {
struct v4l2_async_notifier *notifier;
struct v4l2_async_notifier *subdev_notifier;
struct v4l2_subdev_platform_data *pdata;
+ struct mutex *state_lock;
/*
* The fields below are private, and should only be accessed via
@@ -1157,12 +1166,16 @@ int v4l2_subdev_link_validate(struct media_link *link);
* __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.
*
* Not to be called directly by the drivers.
*/
-struct v4l2_subdev_state *__v4l2_subdev_state_alloc(struct v4l2_subdev *sd);
+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
@@ -1187,7 +1200,16 @@ void __v4l2_subdev_state_free(struct v4l2_subdev_state *state);
*
* The user must call v4l2_subdev_cleanup() when the subdev is being removed.
*/
-int v4l2_subdev_init_finalize(struct v4l2_subdev *sd);
+#define v4l2_subdev_init_finalize(sd) \
+ ({ \
+ static struct lock_class_key __key; \
+ const char *name = KBUILD_BASENAME \
+ ":" __stringify(__LINE__) ":sd->active_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_cleanup() - Releases the resources allocated by the subdevice
@@ -1199,16 +1221,85 @@ int v4l2_subdev_init_finalize(struct v4l2_subdev *sd);
void v4l2_subdev_cleanup(struct v4l2_subdev *sd);
/**
- * v4l2_subdev_get_active_state() - Returns the active subdev state for
- * subdevice
+ * v4l2_subdev_lock_state() - Locks the subdev state
+ * @state: The subdevice state
+ *
+ * Locks the given subdev state.
+ *
+ * The state must be unlocked with v4l2_subdev_unlock_state() after use.
+ */
+static inline void v4l2_subdev_lock_state(struct v4l2_subdev_state *state)
+{
+ mutex_lock(state->lock);
+}
+
+/**
+ * v4l2_subdev_unlock_state() - Unlocks the subdev state
+ * @state: The subdevice state
+ *
+ * Unlocks the given subdev state.
+ */
+static inline void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state)
+{
+ mutex_unlock(state->lock);
+}
+
+/**
+ * v4l2_subdev_get_unlocked_active_state() - Checks that the active subdev state
+ * is unlocked and returns it
+ * @sd: The subdevice
+ *
+ * Returns the active state for the subdevice, or NULL if the subdev does not
+ * support active state. If the state is not NULL, calls
+ * lockdep_assert_not_held() to issue a warning if the state is locked.
+ *
+ * This function is to be used e.g. when getting the active state for the sole
+ * purpose of passing it forward, without accessing the state fields.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_get_unlocked_active_state(struct v4l2_subdev *sd)
+{
+ if (sd->active_state)
+ lockdep_assert_not_held(sd->active_state->lock);
+ return sd->active_state;
+}
+
+/**
+ * v4l2_subdev_get_locked_active_state() - Checks that the active subdev state
+ * is locked and returns it
+ *
* @sd: The subdevice
*
* Returns the active state for the subdevice, or NULL if the subdev does not
- * support active state.
+ * support active state. If the state is not NULL, calls lockdep_assert_held()
+ * to issue a warning if the state is not locked.
+ *
+ * This function is to be used when the caller knows that the active state is
+ * already locked.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_get_locked_active_state(struct v4l2_subdev *sd)
+{
+ if (sd->active_state)
+ lockdep_assert_held(sd->active_state->lock);
+ return sd->active_state;
+}
+
+/**
+ * v4l2_subdev_lock_and_get_active_state() - Locks and returns the active subdev
+ * state for the subdevice
+ * @sd: The subdevice
+ *
+ * Returns the locked active state for the subdevice, or NULL if the subdev
+ * does not support active state.
+ *
+ * The state must be unlocked with v4l2_subdev_unlock_state() after use.
*/
static inline struct v4l2_subdev_state *
-v4l2_subdev_get_active_state(struct v4l2_subdev *sd)
+v4l2_subdev_lock_and_get_active_state(struct v4l2_subdev *sd)
{
+ if (sd->active_state)
+ v4l2_subdev_lock_state(sd->active_state);
return sd->active_state;
}
@@ -1256,6 +1347,36 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers;
})
/**
+ * v4l2_subdev_call_state_active - call an operation of a v4l2_subdev which
+ * takes state as a parameter, passing the
+ * subdev its active state.
+ *
+ * @sd: pointer to the &struct v4l2_subdev
+ * @o: name of the element at &struct v4l2_subdev_ops that contains @f.
+ * Each element there groups a set of callbacks functions.
+ * @f: callback function to be called.
+ * The callback functions are defined in groups, according to
+ * each element at &struct v4l2_subdev_ops.
+ * @args: arguments for @f.
+ *
+ * This is similar to v4l2_subdev_call(), except that this version can only be
+ * used for ops that take a subdev state as a parameter. The macro will get the
+ * active state, lock it before calling the op and unlock it after the call.
+ */
+#define v4l2_subdev_call_state_active(sd, o, f, args...) \
+ ({ \
+ int __result; \
+ struct v4l2_subdev_state *state; \
+ state = v4l2_subdev_get_unlocked_active_state(sd); \
+ if (state) \
+ v4l2_subdev_lock_state(state); \
+ __result = v4l2_subdev_call(sd, o, f, state, ##args); \
+ if (state) \
+ v4l2_subdev_unlock_state(state); \
+ __result; \
+ })
+
+/**
* v4l2_subdev_has_op - Checks if a subdev defines a certain operation.
*
* @sd: pointer to the &struct v4l2_subdev