diff options
Diffstat (limited to 'include/media/v4l2-subdev.h')
-rw-r--r-- | include/media/v4l2-subdev.h | 279 |
1 files changed, 266 insertions, 13 deletions
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 6c153b33bb04..b661e1817470 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -313,6 +313,17 @@ struct v4l2_subdev_audio_ops { }; /** + * struct v4l2_mbus_frame_desc_entry_csi2 + * + * @vc: CSI-2 virtual channel + * @dt: CSI-2 data type ID + */ +struct v4l2_mbus_frame_desc_entry_csi2 { + u8 vc; + u8 dt; +}; + +/** * enum v4l2_mbus_frame_desc_flags - media bus frame description flags * * @V4L2_MBUS_FRAME_DESC_FL_LEN_MAX: @@ -335,21 +346,46 @@ enum v4l2_mbus_frame_desc_flags { * %FRAME_DESC_FL_BLOB is not set. * @length: number of octets per frame, valid if @flags * %V4L2_MBUS_FRAME_DESC_FL_LEN_MAX is set. + * @bus: Bus-specific frame descriptor parameters + * @bus.csi2: CSI-2-specific bus configuration */ struct v4l2_mbus_frame_desc_entry { enum v4l2_mbus_frame_desc_flags flags; u32 pixelcode; u32 length; + union { + struct v4l2_mbus_frame_desc_entry_csi2 csi2; + } bus; }; #define V4L2_FRAME_DESC_ENTRY_MAX 4 /** + * enum v4l2_mbus_frame_desc_type - media bus frame description type + * + * @V4L2_MBUS_FRAME_DESC_TYPE_UNDEFINED: + * Undefined frame desc type. Drivers should not use this, it is + * for backwards compatibility. + * @V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL: + * Parallel media bus. + * @V4L2_MBUS_FRAME_DESC_TYPE_CSI2: + * CSI-2 media bus. Frame desc parameters must be set in + * &struct v4l2_mbus_frame_desc_entry->csi2. + */ +enum v4l2_mbus_frame_desc_type { + V4L2_MBUS_FRAME_DESC_TYPE_UNDEFINED = 0, + V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL, + V4L2_MBUS_FRAME_DESC_TYPE_CSI2, +}; + +/** * struct v4l2_mbus_frame_desc - media bus data frame description + * @type: type of the bus (enum v4l2_mbus_frame_desc_type) * @entry: frame descriptors array * @num_entries: number of entries in @entry array */ struct v4l2_mbus_frame_desc { + enum v4l2_mbus_frame_desc_type type; struct v4l2_mbus_frame_desc_entry entry[V4L2_FRAME_DESC_ENTRY_MAX]; unsigned short num_entries; }; @@ -645,6 +681,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; @@ -655,6 +694,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 @@ -662,6 +703,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; }; @@ -885,6 +929,12 @@ 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(). * * Each instance of a subdev driver should create this struct, either * stand-alone or embedded in a larger struct. @@ -916,6 +966,20 @@ 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 + * appropriate functions. + */ + + /* + * TODO: active_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 active_state in the cases where the driver + * doesn't support it. + */ + struct v4l2_subdev_state *active_state; }; @@ -970,7 +1034,7 @@ struct v4l2_subdev_fh { #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) /** - * v4l2_subdev_get_try_format - ancillary routine to call + * v4l2_subdev_get_pad_format - ancillary routine to call * &struct v4l2_subdev_pad_config->try_fmt * * @sd: pointer to &struct v4l2_subdev @@ -978,7 +1042,7 @@ struct v4l2_subdev_fh { * @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, +v4l2_subdev_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, unsigned int pad) { @@ -988,7 +1052,7 @@ v4l2_subdev_get_try_format(struct v4l2_subdev *sd, } /** - * v4l2_subdev_get_try_crop - ancillary routine to call + * v4l2_subdev_get_pad_crop - ancillary routine to call * &struct v4l2_subdev_pad_config->try_crop * * @sd: pointer to &struct v4l2_subdev @@ -996,7 +1060,7 @@ v4l2_subdev_get_try_format(struct v4l2_subdev *sd, * @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, +v4l2_subdev_get_pad_crop(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, unsigned int pad) { @@ -1006,7 +1070,7 @@ v4l2_subdev_get_try_crop(struct v4l2_subdev *sd, } /** - * v4l2_subdev_get_try_compose - ancillary routine to call + * v4l2_subdev_get_pad_compose - ancillary routine to call * &struct v4l2_subdev_pad_config->try_compose * * @sd: pointer to &struct v4l2_subdev @@ -1014,7 +1078,7 @@ v4l2_subdev_get_try_crop(struct v4l2_subdev *sd, * @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, +v4l2_subdev_get_pad_compose(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, unsigned int pad) { @@ -1023,7 +1087,20 @@ v4l2_subdev_get_try_compose(struct v4l2_subdev *sd, return &state->pads[pad].try_compose; } -#endif +/* + * Temprary helpers until uses of v4l2_subdev_get_try_* functions have been + * renamed + */ +#define v4l2_subdev_get_try_format(sd, state, pad) \ + v4l2_subdev_get_pad_format(sd, state, pad) + +#define v4l2_subdev_get_try_crop(sd, state, pad) \ + v4l2_subdev_get_pad_crop(sd, state, pad) + +#define v4l2_subdev_get_try_compose(sd, state, pad) \ + v4l2_subdev_get_pad_compose(sd, state, pad) + +#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */ extern const struct v4l2_file_operations v4l2_subdev_fops; @@ -1122,20 +1199,166 @@ 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_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. * - * Must call v4l2_subdev_free_state() when state is no longer needed. + * Not to be called directly by the drivers. */ -struct v4l2_subdev_state *v4l2_subdev_alloc_state(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_free_state - free a v4l2_subdev_state + * __v4l2_subdev_state_free - free a v4l2_subdev_state * * @state: v4l2_subdev_state to be freed. + * + * Not to be called directly by the drivers. + */ +void __v4l2_subdev_state_free(struct v4l2_subdev_state *state); + +/** + * v4l2_subdev_init_finalize() - Finalizes the initialization of the subdevice + * @sd: The subdev + * + * This function finalizes the initialization of the subdev, including + * allocation of the active state for the subdev. + * + * This function 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, but before registering the + * subdev. + * + * The user must call v4l2_subdev_cleanup() when the subdev is being removed. + */ +#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 + * @sd: The subdevice + * + * This function will release the resources allocated in + * v4l2_subdev_init_finalize. */ -void v4l2_subdev_free_state(struct v4l2_subdev_state *state); +void v4l2_subdev_cleanup(struct v4l2_subdev *sd); + +/** + * 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. 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_lock_and_get_active_state(struct v4l2_subdev *sd) +{ + if (sd->active_state) + v4l2_subdev_lock_state(sd->active_state); + return sd->active_state; +} + +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + +/** + * v4l2_subdev_get_fmt() - Fill format based on state + * @sd: subdevice + * @state: subdevice state + * @format: pointer to &struct v4l2_subdev_format + * + * Fill @format->format field based on the information in the @format struct. + * + * This function can be used by the subdev drivers which support active state to + * implement v4l2_subdev_pad_ops.get_fmt if the subdev driver does not need to + * do anything special in their get_fmt op. + * + * Returns 0 on success, error value otherwise. + */ +int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format); + +#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */ #endif /* CONFIG_MEDIA_CONTROLLER */ @@ -1181,6 +1404,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 @@ -1204,4 +1457,4 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers; void v4l2_subdev_notify_event(struct v4l2_subdev *sd, const struct v4l2_event *ev); -#endif +#endif /* _V4L2_SUBDEV_H */ |