/**
* v4l2_subdev_init_finalize() - Finalize the initialization of the subdevice
* @sd: The subdev
*
* This finalizes the initialization of the subdev, including allocation of
* the active state for the subdev.
*
* 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 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__) ":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)
{
struct v4l2_subdev_state *state;
state = __v4l2_subdev_state_alloc(sd, name, key);
if (IS_ERR(state))
return PTR_ERR(state);
sd->state = state;
return 0;
}
struct v4l2_subdev_state *
__v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
struct lock_class_key *lock_key)
{
struct v4l2_subdev_state *state;
int ret;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return ERR_PTR(-ENOMEM);
__mutex_init(&state->lock, lock_name, lock_key);
/* Drivers that support streams do not need the legacy pad config */
if (!(sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED) && sd->entity.num_pads) {
state->pads = kvmalloc_array(sd->entity.num_pads,
sizeof(*state->pads),
GFP_KERNEL | __GFP_ZERO);
if (!state->pads) {
ret = -ENOMEM;
goto err;
}
}
ret = v4l2_subdev_call(sd, pad, init_cfg, state);
if (ret < 0 && ret != -ENOIOCTLCMD)
goto err;
return state;
err:
if (state && state->pads)
kvfree(state->pads);
kfree(state);
return ERR_PTR(ret);
}