forked from Minki/linux
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:
parent
c3bf5129f3
commit
71c689dc2e
@ -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,
|
||||
|
@ -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
|
||||
|
1225
drivers/media/v4l2-core/v4l2-ctrls-api.c
Normal file
1225
drivers/media/v4l2-core/v4l2-ctrls-api.c
Normal file
File diff suppressed because it is too large
Load Diff
1939
drivers/media/v4l2-core/v4l2-ctrls-core.c
Normal file
1939
drivers/media/v4l2-core/v4l2-ctrls-core.c
Normal file
File diff suppressed because it is too large
Load Diff
1575
drivers/media/v4l2-core/v4l2-ctrls-defs.c
Normal file
1575
drivers/media/v4l2-core/v4l2-ctrls-defs.c
Normal file
File diff suppressed because it is too large
Load Diff
96
drivers/media/v4l2-core/v4l2-ctrls-priv.h
Normal file
96
drivers/media/v4l2-core/v4l2-ctrls-priv.h
Normal 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
|
496
drivers/media/v4l2-core/v4l2-ctrls-request.c
Normal file
496
drivers/media/v4l2-core/v4l2-ctrls-request.c
Normal 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
Loading…
Reference in New Issue
Block a user