linux/drivers/media/v4l2-core/v4l2-ctrls-api.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * V4L2 controls framework uAPI implementation:
 *
 * Copyright (C) 2010-2021  Hans Verkuil <[email protected]>
 */

#define pr_fmt(fmt)

#include <linux/export.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>

#include "v4l2-ctrls-priv.h"

/* Internal temporary helper struct, one for each v4l2_ext_control */
struct v4l2_ctrl_helper {};

/*
 * Helper functions to copy control payload data from kernel space to
 * user space and vice versa.
 */

/* Helper function: copy the given control value back to the caller */
static int ptr_to_user(struct v4l2_ext_control *c,
		       struct v4l2_ctrl *ctrl,
		       union v4l2_ctrl_ptr ptr)
{}

/* Helper function: copy the current control value back to the caller */
static int cur_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
{}

/* Helper function: copy the new control value back to the caller */
static int new_to_user(struct v4l2_ext_control *c,
		       struct v4l2_ctrl *ctrl)
{}

/* Helper function: copy the request value back to the caller */
static int req_to_user(struct v4l2_ext_control *c,
		       struct v4l2_ctrl_ref *ref)
{}

/* Helper function: copy the initial control value back to the caller */
static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
{}

/* Helper function: copy the caller-provider value as the new control value */
static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
{}

/*
 * VIDIOC_G/TRY/S_EXT_CTRLS implementation
 */

/*
 * Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
 *
 * It is not a fully atomic operation, just best-effort only. After all, if
 * multiple controls have to be set through multiple i2c writes (for example)
 * then some initial writes may succeed while others fail. Thus leaving the
 * system in an inconsistent state. The question is how much effort you are
 * willing to spend on trying to make something atomic that really isn't.
 *
 * From the point of view of an application the main requirement is that
 * when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
 * error should be returned without actually affecting any controls.
 *
 * If all the values are correct, then it is acceptable to just give up
 * in case of low-level errors.
 *
 * It is important though that the application can tell when only a partial
 * configuration was done. The way we do that is through the error_idx field
 * of struct v4l2_ext_controls: if that is equal to the count field then no
 * controls were affected. Otherwise all controls before that index were
 * successful in performing their 'get' or 'set' operation, the control at
 * the given index failed, and you don't know what happened with the controls
 * after the failed one. Since if they were part of a control cluster they
 * could have been successfully processed (if a cluster member was encountered
 * at index < error_idx), they could have failed (if a cluster member was at
 * error_idx), or they may not have been processed yet (if the first cluster
 * member appeared after error_idx).
 *
 * It is all fairly theoretical, though. In practice all you can do is to
 * bail out. If error_idx == count, then it is an application bug. If
 * error_idx < count then it is only an application bug if the error code was
 * EBUSY. That usually means that something started streaming just when you
 * tried to set the controls. In all other cases it is a driver/hardware
 * problem and all you can do is to retry or bail out.
 *
 * Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
 * never modifies controls the error_idx is just set to whatever control
 * has an invalid value.
 */

/*
 * Prepare for the extended g/s/try functions.
 * Find the controls in the control array and do some basic checks.
 */
static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
			     struct v4l2_ext_controls *cs,
			     struct v4l2_ctrl_helper *helpers,
			     struct video_device *vdev,
			     bool get)
{}

/*
 * Handles the corner case where cs->count == 0. It checks whether the
 * specified control class exists. If that class ID is 0, then it checks
 * whether there are any controls at all.
 */
static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
{}

/*
 * Get extended controls. Allocates the helpers array if needed.
 *
 * Note that v4l2_g_ext_ctrls_common() with 'which' set to
 * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
 * completed, and in that case p_req_valid is true for all controls.
 */
int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
			    struct v4l2_ext_controls *cs,
			    struct video_device *vdev)
{}

int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
		     struct media_device *mdev, struct v4l2_ext_controls *cs)
{}
EXPORT_SYMBOL();

/* Validate a new control */
static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
{}

/* Validate controls. */
static int validate_ctrls(struct v4l2_ext_controls *cs,
			  struct v4l2_ctrl_helper *helpers,
			  struct video_device *vdev,
			  bool set)
{}

/* Try or try-and-set controls */
int try_set_ext_ctrls_common(struct v4l2_fh *fh,
			     struct v4l2_ctrl_handler *hdl,
			     struct v4l2_ext_controls *cs,
			     struct video_device *vdev, bool set)
{}

static int try_set_ext_ctrls(struct v4l2_fh *fh,
			     struct v4l2_ctrl_handler *hdl,
			     struct video_device *vdev,
			     struct media_device *mdev,
			     struct v4l2_ext_controls *cs, bool set)
{}

int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl,
		       struct video_device *vdev,
		       struct media_device *mdev,
		       struct v4l2_ext_controls *cs)
{}
EXPORT_SYMBOL();

int v4l2_s_ext_ctrls(struct v4l2_fh *fh,
		     struct v4l2_ctrl_handler *hdl,
		     struct video_device *vdev,
		     struct media_device *mdev,
		     struct v4l2_ext_controls *cs)
{}
EXPORT_SYMBOL();

/*
 * VIDIOC_G/S_CTRL implementation
 */

/* Helper function to get a single control */
static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
{}

int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
{}
EXPORT_SYMBOL();

/* Helper function for VIDIOC_S_CTRL compatibility */
static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
{}

/* Helper function for VIDIOC_S_CTRL compatibility */
static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
			 struct v4l2_ext_control *c)
{}

int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
		struct v4l2_control *control)
{}
EXPORT_SYMBOL();

/*
 * Helper functions for drivers to get/set controls.
 */

s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
{}
EXPORT_SYMBOL();

s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
{}
EXPORT_SYMBOL();

int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
{}
EXPORT_SYMBOL();

int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
{}
EXPORT_SYMBOL();

int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
{}
EXPORT_SYMBOL();

int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
				enum v4l2_ctrl_type type, const void *p)
{}
EXPORT_SYMBOL();

/*
 * Modify the range of a control.
 */
int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
			     s64 min, s64 max, u64 step, s64 def)
{}
EXPORT_SYMBOL();

int __v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl,
				  u32 dims[V4L2_CTRL_MAX_DIMS])
{}
EXPORT_SYMBOL();

/* Implement VIDIOC_QUERY_EXT_CTRL */
int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)
{}
EXPORT_SYMBOL();

/* Implement VIDIOC_QUERYCTRL */
int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
{}
EXPORT_SYMBOL();

/* Implement VIDIOC_QUERYMENU */
int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
{}
EXPORT_SYMBOL();

/*
 * VIDIOC_LOG_STATUS helpers
 */

int v4l2_ctrl_log_status(struct file *file, void *fh)
{}
EXPORT_SYMBOL();

int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)
{}
EXPORT_SYMBOL();

/*
 * VIDIOC_(UN)SUBSCRIBE_EVENT implementation
 */

static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev,
			       unsigned int elems)
{}

static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
{}

void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
{}
EXPORT_SYMBOL();

void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
{}
EXPORT_SYMBOL();

const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops =;
EXPORT_SYMBOL();

int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
			      const struct v4l2_event_subscription *sub)
{}
EXPORT_SYMBOL();

int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
				     struct v4l2_event_subscription *sub)
{}
EXPORT_SYMBOL();

/*
 * poll helper
 */
__poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
{}
EXPORT_SYMBOL();