media: v4l2-ctrls: split up into four source files

The v4l2-ctrls.c source has become much too big, so split it up
into four separate parts:

v4l2-ctrls-core.c: contains the core framework code
v4l2-ctrls-api.c: contains the uAPI interface to the framework
v4l2-ctrls-defs.c: contains the control definitions
v4l2-ctrls-request.c: contains the Request API helpers

And it adds a new v4l2-ctrls-priv.h.

No code was changed, but a number of checkpatch.pl warnings were
fixed (alignment, f == NULL -> !f, long comment block coding style,
unsigned -> unsigned int).

The copyright statements were updated as well since they were
quite out of date.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Hans Verkuil 2021-04-27 14:07:03 +02:00 committed by Mauro Carvalho Chehab
parent c3bf5129f3
commit 71c689dc2e
8 changed files with 5336 additions and 5115 deletions

View File

@ -1353,8 +1353,8 @@ FWHT Flags
* - __u8
- ``picture_coding_type``
- Picture coding type for the frame covered by the current slice
(V4L2_MPEG2_PICTURE_CODING_TYPE_I, V4L2_MPEG2_PICTURE_CODING_TYPE_P or
V4L2_MPEG2_PICTURE_CODING_TYPE_B).
(V4L2_MPEG2_PIC_CODING_TYPE_I, V4L2_MPEG2_PIC_CODING_TYPE_P or
V4L2_MPEG2_PIC_CODING_TYPE_B).
* - __u8
- ``picture_structure``
- Picture structure (1: interlaced top field, 2: interlaced bottom field,

View File

@ -6,8 +6,9 @@
tuner-objs := tuner-core.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
v4l2-event.o v4l2-ctrls.o v4l2-subdev.o \
v4l2-async.o v4l2-common.o
v4l2-event.o v4l2-subdev.o v4l2-async.o v4l2-common.o \
v4l2-ctrls-core.o v4l2-ctrls-api.o \
v4l2-ctrls-request.o v4l2-ctrls-defs.o
videodev-$(CONFIG_COMPAT) += v4l2-compat-ioctl32.o
videodev-$(CONFIG_TRACEPOINTS) += v4l2-trace.o
videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* V4L2 controls framework private header.
*
* Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
*/
#ifndef _V4L2_CTRLS_PRIV_H_
#define _V4L2_CTRLS_PRIV_H_
#define dprintk(vdev, fmt, arg...) do { \
if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \
printk(KERN_DEBUG pr_fmt("%s: %s: " fmt), \
__func__, video_device_node_name(vdev), ##arg); \
} while (0)
#define has_op(master, op) \
((master)->ops && (master)->ops->op)
#define call_op(master, op) \
(has_op(master, op) ? (master)->ops->op(master) : 0)
static inline u32 node2id(struct list_head *node)
{
return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id;
}
/*
* Small helper function to determine if the autocluster is set to manual
* mode.
*/
static inline bool is_cur_manual(const struct v4l2_ctrl *master)
{
return master->is_auto && master->cur.val == master->manual_mode_value;
}
/*
* Small helper function to determine if the autocluster will be set to manual
* mode.
*/
static inline bool is_new_manual(const struct v4l2_ctrl *master)
{
return master->is_auto && master->val == master->manual_mode_value;
}
static inline u32 user_flags(const struct v4l2_ctrl *ctrl)
{
u32 flags = ctrl->flags;
if (ctrl->is_ptr)
flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD;
return flags;
}
/* v4l2-ctrls-core.c */
void cur_to_new(struct v4l2_ctrl *ctrl);
void cur_to_req(struct v4l2_ctrl_ref *ref);
void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags);
void new_to_req(struct v4l2_ctrl_ref *ref);
void req_to_new(struct v4l2_ctrl_ref *ref);
void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl);
void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes);
int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new);
int handler_new_ref(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl *ctrl,
struct v4l2_ctrl_ref **ctrl_ref,
bool from_other_dev, bool allocate_req);
struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id);
struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id);
int check_range(enum v4l2_ctrl_type type,
s64 min, s64 max, u64 step, s64 def);
void update_from_auto_cluster(struct v4l2_ctrl *master);
int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
bool set, u32 ch_flags);
/* v4l2-ctrls-api.c */
int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
struct v4l2_ext_controls *cs,
struct video_device *vdev);
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);
/* v4l2-ctrls-request.c */
void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl);
void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl);
int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
struct media_device *mdev, struct v4l2_ext_controls *cs);
int try_set_ext_ctrls_request(struct v4l2_fh *fh,
struct v4l2_ctrl_handler *hdl,
struct video_device *vdev,
struct media_device *mdev,
struct v4l2_ext_controls *cs, bool set);
#endif

View File

@ -0,0 +1,496 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* V4L2 controls framework Request API implementation.
*
* Copyright (C) 2018-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
*/
#define pr_fmt(fmt) "v4l2-ctrls: " fmt
#include <linux/export.h>
#include <linux/slab.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include "v4l2-ctrls-priv.h"
/* Initialize the request-related fields in a control handler */
void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl)
{
INIT_LIST_HEAD(&hdl->requests);
INIT_LIST_HEAD(&hdl->requests_queued);
hdl->request_is_queued = false;
media_request_object_init(&hdl->req_obj);
}
/* Free the request-related fields in a control handler */
void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl)
{
struct v4l2_ctrl_handler *req, *next_req;
/*
* Do nothing if this isn't the main handler or the main
* handler is not used in any request.
*
* The main handler can be identified by having a NULL ops pointer in
* the request object.
*/
if (hdl->req_obj.ops || list_empty(&hdl->requests))
return;
/*
* If the main handler is freed and it is used by handler objects in
* outstanding requests, then unbind and put those objects before
* freeing the main handler.
*/
list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
media_request_object_unbind(&req->req_obj);
media_request_object_put(&req->req_obj);
}
}
static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_handler *from)
{
struct v4l2_ctrl_ref *ref;
int err = 0;
if (WARN_ON(!hdl || hdl == from))
return -EINVAL;
if (hdl->error)
return hdl->error;
WARN_ON(hdl->lock != &hdl->_lock);
mutex_lock(from->lock);
list_for_each_entry(ref, &from->ctrl_refs, node) {
struct v4l2_ctrl *ctrl = ref->ctrl;
struct v4l2_ctrl_ref *new_ref;
/* Skip refs inherited from other devices */
if (ref->from_other_dev)
continue;
err = handler_new_ref(hdl, ctrl, &new_ref, false, true);
if (err)
break;
}
mutex_unlock(from->lock);
return err;
}
static void v4l2_ctrl_request_queue(struct media_request_object *obj)
{
struct v4l2_ctrl_handler *hdl =
container_of(obj, struct v4l2_ctrl_handler, req_obj);
struct v4l2_ctrl_handler *main_hdl = obj->priv;
mutex_lock(main_hdl->lock);
list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
hdl->request_is_queued = true;
mutex_unlock(main_hdl->lock);
}
static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
{
struct v4l2_ctrl_handler *hdl =
container_of(obj, struct v4l2_ctrl_handler, req_obj);
struct v4l2_ctrl_handler *main_hdl = obj->priv;
mutex_lock(main_hdl->lock);
list_del_init(&hdl->requests);
if (hdl->request_is_queued) {
list_del_init(&hdl->requests_queued);
hdl->request_is_queued = false;
}
mutex_unlock(main_hdl->lock);
}
static void v4l2_ctrl_request_release(struct media_request_object *obj)
{
struct v4l2_ctrl_handler *hdl =
container_of(obj, struct v4l2_ctrl_handler, req_obj);
v4l2_ctrl_handler_free(hdl);
kfree(hdl);
}
static const struct media_request_object_ops req_ops = {
.queue = v4l2_ctrl_request_queue,
.unbind = v4l2_ctrl_request_unbind,
.release = v4l2_ctrl_request_release,
};
struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req,
struct v4l2_ctrl_handler *parent)
{
struct media_request_object *obj;
if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING &&
req->state != MEDIA_REQUEST_STATE_QUEUED))
return NULL;
obj = media_request_object_find(req, &req_ops, parent);
if (obj)
return container_of(obj, struct v4l2_ctrl_handler, req_obj);
return NULL;
}
EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find);
struct v4l2_ctrl *
v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
{
struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
}
EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
static int v4l2_ctrl_request_bind(struct media_request *req,
struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl_handler *from)
{
int ret;
ret = v4l2_ctrl_request_clone(hdl, from);
if (!ret) {
ret = media_request_object_bind(req, &req_ops,
from, false, &hdl->req_obj);
if (!ret) {
mutex_lock(from->lock);
list_add_tail(&hdl->requests, &from->requests);
mutex_unlock(from->lock);
}
}
return ret;
}
static struct media_request_object *
v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
struct media_request *req, bool set)
{
struct media_request_object *obj;
struct v4l2_ctrl_handler *new_hdl;
int ret;
if (IS_ERR(req))
return ERR_CAST(req);
if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
return ERR_PTR(-EBUSY);
obj = media_request_object_find(req, &req_ops, hdl);
if (obj)
return obj;
/*
* If there are no controls in this completed request,
* then that can only happen if:
*
* 1) no controls were present in the queued request, and
* 2) v4l2_ctrl_request_complete() could not allocate a
* control handler object to store the completed state in.
*
* So return ENOMEM to indicate that there was an out-of-memory
* error.
*/
if (!set)
return ERR_PTR(-ENOMEM);
new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
if (!new_hdl)
return ERR_PTR(-ENOMEM);
obj = &new_hdl->req_obj;
ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8);
if (!ret)
ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
if (ret) {
v4l2_ctrl_handler_free(new_hdl);
kfree(new_hdl);
return ERR_PTR(ret);
}
media_request_object_get(obj);
return obj;
}
int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
struct media_device *mdev, struct v4l2_ext_controls *cs)
{
struct media_request_object *obj = NULL;
struct media_request *req = NULL;
int ret;
if (!mdev || cs->request_fd < 0)
return -EINVAL;
req = media_request_get_by_fd(mdev, cs->request_fd);
if (IS_ERR(req))
return PTR_ERR(req);
if (req->state != MEDIA_REQUEST_STATE_COMPLETE) {
media_request_put(req);
return -EACCES;
}
ret = media_request_lock_for_access(req);
if (ret) {
media_request_put(req);
return ret;
}
obj = v4l2_ctrls_find_req_obj(hdl, req, false);
if (IS_ERR(obj)) {
media_request_unlock_for_access(req);
media_request_put(req);
return PTR_ERR(obj);
}
hdl = container_of(obj, struct v4l2_ctrl_handler,
req_obj);
ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev);
media_request_unlock_for_access(req);
media_request_object_put(obj);
media_request_put(req);
return ret;
}
int try_set_ext_ctrls_request(struct v4l2_fh *fh,
struct v4l2_ctrl_handler *hdl,
struct video_device *vdev,
struct media_device *mdev,
struct v4l2_ext_controls *cs, bool set)
{
struct media_request_object *obj = NULL;
struct media_request *req = NULL;
int ret;
if (!mdev) {
dprintk(vdev, "%s: missing media device\n",
video_device_node_name(vdev));
return -EINVAL;
}
if (cs->request_fd < 0) {
dprintk(vdev, "%s: invalid request fd %d\n",
video_device_node_name(vdev), cs->request_fd);
return -EINVAL;
}
req = media_request_get_by_fd(mdev, cs->request_fd);
if (IS_ERR(req)) {
dprintk(vdev, "%s: cannot find request fd %d\n",
video_device_node_name(vdev), cs->request_fd);
return PTR_ERR(req);
}
ret = media_request_lock_for_update(req);
if (ret) {
dprintk(vdev, "%s: cannot lock request fd %d\n",
video_device_node_name(vdev), cs->request_fd);
media_request_put(req);
return ret;
}
obj = v4l2_ctrls_find_req_obj(hdl, req, set);
if (IS_ERR(obj)) {
dprintk(vdev,
"%s: cannot find request object for request fd %d\n",
video_device_node_name(vdev),
cs->request_fd);
media_request_unlock_for_update(req);
media_request_put(req);
return PTR_ERR(obj);
}
hdl = container_of(obj, struct v4l2_ctrl_handler,
req_obj);
ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
if (ret)
dprintk(vdev,
"%s: try_set_ext_ctrls_common failed (%d)\n",
video_device_node_name(vdev), ret);
media_request_unlock_for_update(req);
media_request_object_put(obj);
media_request_put(req);
return ret;
}
void v4l2_ctrl_request_complete(struct media_request *req,
struct v4l2_ctrl_handler *main_hdl)
{
struct media_request_object *obj;
struct v4l2_ctrl_handler *hdl;
struct v4l2_ctrl_ref *ref;
if (!req || !main_hdl)
return;
/*
* Note that it is valid if nothing was found. It means
* that this request doesn't have any controls and so just
* wants to leave the controls unchanged.
*/
obj = media_request_object_find(req, &req_ops, main_hdl);
if (!obj) {
int ret;
/* Create a new request so the driver can return controls */
hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
if (!hdl)
return;
ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8);
if (!ret)
ret = v4l2_ctrl_request_bind(req, hdl, main_hdl);
if (ret) {
v4l2_ctrl_handler_free(hdl);
kfree(hdl);
return;
}
hdl->request_is_queued = true;
obj = media_request_object_find(req, &req_ops, main_hdl);
}
hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
list_for_each_entry(ref, &hdl->ctrl_refs, node) {
struct v4l2_ctrl *ctrl = ref->ctrl;
struct v4l2_ctrl *master = ctrl->cluster[0];
unsigned int i;
if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
v4l2_ctrl_lock(master);
/* g_volatile_ctrl will update the current control values */
for (i = 0; i < master->ncontrols; i++)
cur_to_new(master->cluster[i]);
call_op(master, g_volatile_ctrl);
new_to_req(ref);
v4l2_ctrl_unlock(master);
continue;
}
if (ref->valid_p_req)
continue;
/* Copy the current control value into the request */
v4l2_ctrl_lock(ctrl);
cur_to_req(ref);
v4l2_ctrl_unlock(ctrl);
}
mutex_lock(main_hdl->lock);
WARN_ON(!hdl->request_is_queued);
list_del_init(&hdl->requests_queued);
hdl->request_is_queued = false;
mutex_unlock(main_hdl->lock);
media_request_object_complete(obj);
media_request_object_put(obj);
}
EXPORT_SYMBOL(v4l2_ctrl_request_complete);
int v4l2_ctrl_request_setup(struct media_request *req,
struct v4l2_ctrl_handler *main_hdl)
{
struct media_request_object *obj;
struct v4l2_ctrl_handler *hdl;
struct v4l2_ctrl_ref *ref;
int ret = 0;
if (!req || !main_hdl)
return 0;
if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
return -EBUSY;
/*
* Note that it is valid if nothing was found. It means
* that this request doesn't have any controls and so just
* wants to leave the controls unchanged.
*/
obj = media_request_object_find(req, &req_ops, main_hdl);
if (!obj)
return 0;
if (obj->completed) {
media_request_object_put(obj);
return -EBUSY;
}
hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
list_for_each_entry(ref, &hdl->ctrl_refs, node)
ref->req_done = false;
list_for_each_entry(ref, &hdl->ctrl_refs, node) {
struct v4l2_ctrl *ctrl = ref->ctrl;
struct v4l2_ctrl *master = ctrl->cluster[0];
bool have_new_data = false;
int i;
/*
* Skip if this control was already handled by a cluster.
* Skip button controls and read-only controls.
*/
if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
continue;
v4l2_ctrl_lock(master);
for (i = 0; i < master->ncontrols; i++) {
if (master->cluster[i]) {
struct v4l2_ctrl_ref *r =
find_ref(hdl, master->cluster[i]->id);
if (r->valid_p_req) {
have_new_data = true;
break;
}
}
}
if (!have_new_data) {
v4l2_ctrl_unlock(master);
continue;
}
for (i = 0; i < master->ncontrols; i++) {
if (master->cluster[i]) {
struct v4l2_ctrl_ref *r =
find_ref(hdl, master->cluster[i]->id);
req_to_new(r);
master->cluster[i]->is_new = 1;
r->req_done = true;
}
}
/*
* For volatile autoclusters that are currently in auto mode
* we need to discover if it will be set to manual mode.
* If so, then we have to copy the current volatile values
* first since those will become the new manual values (which
* may be overwritten by explicit new values from this set
* of controls).
*/
if (master->is_auto && master->has_volatiles &&
!is_cur_manual(master)) {
s32 new_auto_val = *master->p_new.p_s32;
/*
* If the new value == the manual value, then copy
* the current volatile values.
*/
if (new_auto_val == master->manual_mode_value)
update_from_auto_cluster(master);
}
ret = try_or_set_cluster(NULL, master, true, 0);
v4l2_ctrl_unlock(master);
if (ret)
break;
}
media_request_object_put(obj);
return ret;
}
EXPORT_SYMBOL(v4l2_ctrl_request_setup);

File diff suppressed because it is too large Load Diff