162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * V4L2 controls framework Request API implementation.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2018-2021  Hans Verkuil <hverkuil-cisco@xs4all.nl>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) "v4l2-ctrls: " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/export.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <media/v4l2-ctrls.h>
1362306a36Sopenharmony_ci#include <media/v4l2-dev.h>
1462306a36Sopenharmony_ci#include <media/v4l2-ioctl.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "v4l2-ctrls-priv.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* Initialize the request-related fields in a control handler */
1962306a36Sopenharmony_civoid v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	INIT_LIST_HEAD(&hdl->requests);
2262306a36Sopenharmony_ci	INIT_LIST_HEAD(&hdl->requests_queued);
2362306a36Sopenharmony_ci	hdl->request_is_queued = false;
2462306a36Sopenharmony_ci	media_request_object_init(&hdl->req_obj);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* Free the request-related fields in a control handler */
2862306a36Sopenharmony_civoid v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct v4l2_ctrl_handler *req, *next_req;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	/*
3362306a36Sopenharmony_ci	 * Do nothing if this isn't the main handler or the main
3462306a36Sopenharmony_ci	 * handler is not used in any request.
3562306a36Sopenharmony_ci	 *
3662306a36Sopenharmony_ci	 * The main handler can be identified by having a NULL ops pointer in
3762306a36Sopenharmony_ci	 * the request object.
3862306a36Sopenharmony_ci	 */
3962306a36Sopenharmony_ci	if (hdl->req_obj.ops || list_empty(&hdl->requests))
4062306a36Sopenharmony_ci		return;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	/*
4362306a36Sopenharmony_ci	 * If the main handler is freed and it is used by handler objects in
4462306a36Sopenharmony_ci	 * outstanding requests, then unbind and put those objects before
4562306a36Sopenharmony_ci	 * freeing the main handler.
4662306a36Sopenharmony_ci	 */
4762306a36Sopenharmony_ci	list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
4862306a36Sopenharmony_ci		media_request_object_unbind(&req->req_obj);
4962306a36Sopenharmony_ci		media_request_object_put(&req->req_obj);
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
5462306a36Sopenharmony_ci				   const struct v4l2_ctrl_handler *from)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct v4l2_ctrl_ref *ref;
5762306a36Sopenharmony_ci	int err = 0;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (WARN_ON(!hdl || hdl == from))
6062306a36Sopenharmony_ci		return -EINVAL;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	if (hdl->error)
6362306a36Sopenharmony_ci		return hdl->error;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	WARN_ON(hdl->lock != &hdl->_lock);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	mutex_lock(from->lock);
6862306a36Sopenharmony_ci	list_for_each_entry(ref, &from->ctrl_refs, node) {
6962306a36Sopenharmony_ci		struct v4l2_ctrl *ctrl = ref->ctrl;
7062306a36Sopenharmony_ci		struct v4l2_ctrl_ref *new_ref;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		/* Skip refs inherited from other devices */
7362306a36Sopenharmony_ci		if (ref->from_other_dev)
7462306a36Sopenharmony_ci			continue;
7562306a36Sopenharmony_ci		err = handler_new_ref(hdl, ctrl, &new_ref, false, true);
7662306a36Sopenharmony_ci		if (err)
7762306a36Sopenharmony_ci			break;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	mutex_unlock(from->lock);
8062306a36Sopenharmony_ci	return err;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic void v4l2_ctrl_request_queue(struct media_request_object *obj)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl =
8662306a36Sopenharmony_ci		container_of(obj, struct v4l2_ctrl_handler, req_obj);
8762306a36Sopenharmony_ci	struct v4l2_ctrl_handler *main_hdl = obj->priv;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	mutex_lock(main_hdl->lock);
9062306a36Sopenharmony_ci	list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
9162306a36Sopenharmony_ci	hdl->request_is_queued = true;
9262306a36Sopenharmony_ci	mutex_unlock(main_hdl->lock);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void v4l2_ctrl_request_unbind(struct media_request_object *obj)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl =
9862306a36Sopenharmony_ci		container_of(obj, struct v4l2_ctrl_handler, req_obj);
9962306a36Sopenharmony_ci	struct v4l2_ctrl_handler *main_hdl = obj->priv;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	mutex_lock(main_hdl->lock);
10262306a36Sopenharmony_ci	list_del_init(&hdl->requests);
10362306a36Sopenharmony_ci	if (hdl->request_is_queued) {
10462306a36Sopenharmony_ci		list_del_init(&hdl->requests_queued);
10562306a36Sopenharmony_ci		hdl->request_is_queued = false;
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci	mutex_unlock(main_hdl->lock);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void v4l2_ctrl_request_release(struct media_request_object *obj)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl =
11362306a36Sopenharmony_ci		container_of(obj, struct v4l2_ctrl_handler, req_obj);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	v4l2_ctrl_handler_free(hdl);
11662306a36Sopenharmony_ci	kfree(hdl);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic const struct media_request_object_ops req_ops = {
12062306a36Sopenharmony_ci	.queue = v4l2_ctrl_request_queue,
12162306a36Sopenharmony_ci	.unbind = v4l2_ctrl_request_unbind,
12262306a36Sopenharmony_ci	.release = v4l2_ctrl_request_release,
12362306a36Sopenharmony_ci};
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistruct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req,
12662306a36Sopenharmony_ci						     struct v4l2_ctrl_handler *parent)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct media_request_object *obj;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING &&
13162306a36Sopenharmony_ci		    req->state != MEDIA_REQUEST_STATE_QUEUED))
13262306a36Sopenharmony_ci		return NULL;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	obj = media_request_object_find(req, &req_ops, parent);
13562306a36Sopenharmony_ci	if (obj)
13662306a36Sopenharmony_ci		return container_of(obj, struct v4l2_ctrl_handler, req_obj);
13762306a36Sopenharmony_ci	return NULL;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistruct v4l2_ctrl *
14262306a36Sopenharmony_civ4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	return (ref && ref->p_req_valid) ? ref->ctrl : NULL;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic int v4l2_ctrl_request_bind(struct media_request *req,
15162306a36Sopenharmony_ci				  struct v4l2_ctrl_handler *hdl,
15262306a36Sopenharmony_ci				  struct v4l2_ctrl_handler *from)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	int ret;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	ret = v4l2_ctrl_request_clone(hdl, from);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (!ret) {
15962306a36Sopenharmony_ci		ret = media_request_object_bind(req, &req_ops,
16062306a36Sopenharmony_ci						from, false, &hdl->req_obj);
16162306a36Sopenharmony_ci		if (!ret) {
16262306a36Sopenharmony_ci			mutex_lock(from->lock);
16362306a36Sopenharmony_ci			list_add_tail(&hdl->requests, &from->requests);
16462306a36Sopenharmony_ci			mutex_unlock(from->lock);
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci	return ret;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic struct media_request_object *
17162306a36Sopenharmony_civ4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
17262306a36Sopenharmony_ci			struct media_request *req, bool set)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	struct media_request_object *obj;
17562306a36Sopenharmony_ci	struct v4l2_ctrl_handler *new_hdl;
17662306a36Sopenharmony_ci	int ret;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	if (IS_ERR(req))
17962306a36Sopenharmony_ci		return ERR_CAST(req);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
18262306a36Sopenharmony_ci		return ERR_PTR(-EBUSY);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	obj = media_request_object_find(req, &req_ops, hdl);
18562306a36Sopenharmony_ci	if (obj)
18662306a36Sopenharmony_ci		return obj;
18762306a36Sopenharmony_ci	/*
18862306a36Sopenharmony_ci	 * If there are no controls in this completed request,
18962306a36Sopenharmony_ci	 * then that can only happen if:
19062306a36Sopenharmony_ci	 *
19162306a36Sopenharmony_ci	 * 1) no controls were present in the queued request, and
19262306a36Sopenharmony_ci	 * 2) v4l2_ctrl_request_complete() could not allocate a
19362306a36Sopenharmony_ci	 *    control handler object to store the completed state in.
19462306a36Sopenharmony_ci	 *
19562306a36Sopenharmony_ci	 * So return ENOMEM to indicate that there was an out-of-memory
19662306a36Sopenharmony_ci	 * error.
19762306a36Sopenharmony_ci	 */
19862306a36Sopenharmony_ci	if (!set)
19962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
20262306a36Sopenharmony_ci	if (!new_hdl)
20362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	obj = &new_hdl->req_obj;
20662306a36Sopenharmony_ci	ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8);
20762306a36Sopenharmony_ci	if (!ret)
20862306a36Sopenharmony_ci		ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
20962306a36Sopenharmony_ci	if (ret) {
21062306a36Sopenharmony_ci		v4l2_ctrl_handler_free(new_hdl);
21162306a36Sopenharmony_ci		kfree(new_hdl);
21262306a36Sopenharmony_ci		return ERR_PTR(ret);
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	media_request_object_get(obj);
21662306a36Sopenharmony_ci	return obj;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ciint v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
22062306a36Sopenharmony_ci			     struct media_device *mdev, struct v4l2_ext_controls *cs)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct media_request_object *obj = NULL;
22362306a36Sopenharmony_ci	struct media_request *req = NULL;
22462306a36Sopenharmony_ci	int ret;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	if (!mdev || cs->request_fd < 0)
22762306a36Sopenharmony_ci		return -EINVAL;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	req = media_request_get_by_fd(mdev, cs->request_fd);
23062306a36Sopenharmony_ci	if (IS_ERR(req))
23162306a36Sopenharmony_ci		return PTR_ERR(req);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (req->state != MEDIA_REQUEST_STATE_COMPLETE) {
23462306a36Sopenharmony_ci		media_request_put(req);
23562306a36Sopenharmony_ci		return -EACCES;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	ret = media_request_lock_for_access(req);
23962306a36Sopenharmony_ci	if (ret) {
24062306a36Sopenharmony_ci		media_request_put(req);
24162306a36Sopenharmony_ci		return ret;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	obj = v4l2_ctrls_find_req_obj(hdl, req, false);
24562306a36Sopenharmony_ci	if (IS_ERR(obj)) {
24662306a36Sopenharmony_ci		media_request_unlock_for_access(req);
24762306a36Sopenharmony_ci		media_request_put(req);
24862306a36Sopenharmony_ci		return PTR_ERR(obj);
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	hdl = container_of(obj, struct v4l2_ctrl_handler,
25262306a36Sopenharmony_ci			   req_obj);
25362306a36Sopenharmony_ci	ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	media_request_unlock_for_access(req);
25662306a36Sopenharmony_ci	media_request_object_put(obj);
25762306a36Sopenharmony_ci	media_request_put(req);
25862306a36Sopenharmony_ci	return ret;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ciint try_set_ext_ctrls_request(struct v4l2_fh *fh,
26262306a36Sopenharmony_ci			      struct v4l2_ctrl_handler *hdl,
26362306a36Sopenharmony_ci			      struct video_device *vdev,
26462306a36Sopenharmony_ci			      struct media_device *mdev,
26562306a36Sopenharmony_ci			      struct v4l2_ext_controls *cs, bool set)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct media_request_object *obj = NULL;
26862306a36Sopenharmony_ci	struct media_request *req = NULL;
26962306a36Sopenharmony_ci	int ret;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (!mdev) {
27262306a36Sopenharmony_ci		dprintk(vdev, "%s: missing media device\n",
27362306a36Sopenharmony_ci			video_device_node_name(vdev));
27462306a36Sopenharmony_ci		return -EINVAL;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (cs->request_fd < 0) {
27862306a36Sopenharmony_ci		dprintk(vdev, "%s: invalid request fd %d\n",
27962306a36Sopenharmony_ci			video_device_node_name(vdev), cs->request_fd);
28062306a36Sopenharmony_ci		return -EINVAL;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	req = media_request_get_by_fd(mdev, cs->request_fd);
28462306a36Sopenharmony_ci	if (IS_ERR(req)) {
28562306a36Sopenharmony_ci		dprintk(vdev, "%s: cannot find request fd %d\n",
28662306a36Sopenharmony_ci			video_device_node_name(vdev), cs->request_fd);
28762306a36Sopenharmony_ci		return PTR_ERR(req);
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	ret = media_request_lock_for_update(req);
29162306a36Sopenharmony_ci	if (ret) {
29262306a36Sopenharmony_ci		dprintk(vdev, "%s: cannot lock request fd %d\n",
29362306a36Sopenharmony_ci			video_device_node_name(vdev), cs->request_fd);
29462306a36Sopenharmony_ci		media_request_put(req);
29562306a36Sopenharmony_ci		return ret;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	obj = v4l2_ctrls_find_req_obj(hdl, req, set);
29962306a36Sopenharmony_ci	if (IS_ERR(obj)) {
30062306a36Sopenharmony_ci		dprintk(vdev,
30162306a36Sopenharmony_ci			"%s: cannot find request object for request fd %d\n",
30262306a36Sopenharmony_ci			video_device_node_name(vdev),
30362306a36Sopenharmony_ci			cs->request_fd);
30462306a36Sopenharmony_ci		media_request_unlock_for_update(req);
30562306a36Sopenharmony_ci		media_request_put(req);
30662306a36Sopenharmony_ci		return PTR_ERR(obj);
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	hdl = container_of(obj, struct v4l2_ctrl_handler,
31062306a36Sopenharmony_ci			   req_obj);
31162306a36Sopenharmony_ci	ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
31262306a36Sopenharmony_ci	if (ret)
31362306a36Sopenharmony_ci		dprintk(vdev,
31462306a36Sopenharmony_ci			"%s: try_set_ext_ctrls_common failed (%d)\n",
31562306a36Sopenharmony_ci			video_device_node_name(vdev), ret);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	media_request_unlock_for_update(req);
31862306a36Sopenharmony_ci	media_request_object_put(obj);
31962306a36Sopenharmony_ci	media_request_put(req);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return ret;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_civoid v4l2_ctrl_request_complete(struct media_request *req,
32562306a36Sopenharmony_ci				struct v4l2_ctrl_handler *main_hdl)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct media_request_object *obj;
32862306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl;
32962306a36Sopenharmony_ci	struct v4l2_ctrl_ref *ref;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (!req || !main_hdl)
33262306a36Sopenharmony_ci		return;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/*
33562306a36Sopenharmony_ci	 * Note that it is valid if nothing was found. It means
33662306a36Sopenharmony_ci	 * that this request doesn't have any controls and so just
33762306a36Sopenharmony_ci	 * wants to leave the controls unchanged.
33862306a36Sopenharmony_ci	 */
33962306a36Sopenharmony_ci	obj = media_request_object_find(req, &req_ops, main_hdl);
34062306a36Sopenharmony_ci	if (!obj) {
34162306a36Sopenharmony_ci		int ret;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		/* Create a new request so the driver can return controls */
34462306a36Sopenharmony_ci		hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
34562306a36Sopenharmony_ci		if (!hdl)
34662306a36Sopenharmony_ci			return;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8);
34962306a36Sopenharmony_ci		if (!ret)
35062306a36Sopenharmony_ci			ret = v4l2_ctrl_request_bind(req, hdl, main_hdl);
35162306a36Sopenharmony_ci		if (ret) {
35262306a36Sopenharmony_ci			v4l2_ctrl_handler_free(hdl);
35362306a36Sopenharmony_ci			kfree(hdl);
35462306a36Sopenharmony_ci			return;
35562306a36Sopenharmony_ci		}
35662306a36Sopenharmony_ci		hdl->request_is_queued = true;
35762306a36Sopenharmony_ci		obj = media_request_object_find(req, &req_ops, main_hdl);
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	list_for_each_entry(ref, &hdl->ctrl_refs, node) {
36262306a36Sopenharmony_ci		struct v4l2_ctrl *ctrl = ref->ctrl;
36362306a36Sopenharmony_ci		struct v4l2_ctrl *master = ctrl->cluster[0];
36462306a36Sopenharmony_ci		unsigned int i;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
36762306a36Sopenharmony_ci			v4l2_ctrl_lock(master);
36862306a36Sopenharmony_ci			/* g_volatile_ctrl will update the current control values */
36962306a36Sopenharmony_ci			for (i = 0; i < master->ncontrols; i++)
37062306a36Sopenharmony_ci				cur_to_new(master->cluster[i]);
37162306a36Sopenharmony_ci			call_op(master, g_volatile_ctrl);
37262306a36Sopenharmony_ci			new_to_req(ref);
37362306a36Sopenharmony_ci			v4l2_ctrl_unlock(master);
37462306a36Sopenharmony_ci			continue;
37562306a36Sopenharmony_ci		}
37662306a36Sopenharmony_ci		if (ref->p_req_valid)
37762306a36Sopenharmony_ci			continue;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		/* Copy the current control value into the request */
38062306a36Sopenharmony_ci		v4l2_ctrl_lock(ctrl);
38162306a36Sopenharmony_ci		cur_to_req(ref);
38262306a36Sopenharmony_ci		v4l2_ctrl_unlock(ctrl);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	mutex_lock(main_hdl->lock);
38662306a36Sopenharmony_ci	WARN_ON(!hdl->request_is_queued);
38762306a36Sopenharmony_ci	list_del_init(&hdl->requests_queued);
38862306a36Sopenharmony_ci	hdl->request_is_queued = false;
38962306a36Sopenharmony_ci	mutex_unlock(main_hdl->lock);
39062306a36Sopenharmony_ci	media_request_object_complete(obj);
39162306a36Sopenharmony_ci	media_request_object_put(obj);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ciEXPORT_SYMBOL(v4l2_ctrl_request_complete);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ciint v4l2_ctrl_request_setup(struct media_request *req,
39662306a36Sopenharmony_ci			    struct v4l2_ctrl_handler *main_hdl)
39762306a36Sopenharmony_ci{
39862306a36Sopenharmony_ci	struct media_request_object *obj;
39962306a36Sopenharmony_ci	struct v4l2_ctrl_handler *hdl;
40062306a36Sopenharmony_ci	struct v4l2_ctrl_ref *ref;
40162306a36Sopenharmony_ci	int ret = 0;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (!req || !main_hdl)
40462306a36Sopenharmony_ci		return 0;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
40762306a36Sopenharmony_ci		return -EBUSY;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * Note that it is valid if nothing was found. It means
41162306a36Sopenharmony_ci	 * that this request doesn't have any controls and so just
41262306a36Sopenharmony_ci	 * wants to leave the controls unchanged.
41362306a36Sopenharmony_ci	 */
41462306a36Sopenharmony_ci	obj = media_request_object_find(req, &req_ops, main_hdl);
41562306a36Sopenharmony_ci	if (!obj)
41662306a36Sopenharmony_ci		return 0;
41762306a36Sopenharmony_ci	if (obj->completed) {
41862306a36Sopenharmony_ci		media_request_object_put(obj);
41962306a36Sopenharmony_ci		return -EBUSY;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci	hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	list_for_each_entry(ref, &hdl->ctrl_refs, node)
42462306a36Sopenharmony_ci		ref->req_done = false;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	list_for_each_entry(ref, &hdl->ctrl_refs, node) {
42762306a36Sopenharmony_ci		struct v4l2_ctrl *ctrl = ref->ctrl;
42862306a36Sopenharmony_ci		struct v4l2_ctrl *master = ctrl->cluster[0];
42962306a36Sopenharmony_ci		bool have_new_data = false;
43062306a36Sopenharmony_ci		int i;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		/*
43362306a36Sopenharmony_ci		 * Skip if this control was already handled by a cluster.
43462306a36Sopenharmony_ci		 * Skip button controls and read-only controls.
43562306a36Sopenharmony_ci		 */
43662306a36Sopenharmony_ci		if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
43762306a36Sopenharmony_ci			continue;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		v4l2_ctrl_lock(master);
44062306a36Sopenharmony_ci		for (i = 0; i < master->ncontrols; i++) {
44162306a36Sopenharmony_ci			if (master->cluster[i]) {
44262306a36Sopenharmony_ci				struct v4l2_ctrl_ref *r =
44362306a36Sopenharmony_ci					find_ref(hdl, master->cluster[i]->id);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci				if (r->p_req_valid) {
44662306a36Sopenharmony_ci					have_new_data = true;
44762306a36Sopenharmony_ci					break;
44862306a36Sopenharmony_ci				}
44962306a36Sopenharmony_ci			}
45062306a36Sopenharmony_ci		}
45162306a36Sopenharmony_ci		if (!have_new_data) {
45262306a36Sopenharmony_ci			v4l2_ctrl_unlock(master);
45362306a36Sopenharmony_ci			continue;
45462306a36Sopenharmony_ci		}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		for (i = 0; i < master->ncontrols; i++) {
45762306a36Sopenharmony_ci			if (master->cluster[i]) {
45862306a36Sopenharmony_ci				struct v4l2_ctrl_ref *r =
45962306a36Sopenharmony_ci					find_ref(hdl, master->cluster[i]->id);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci				ret = req_to_new(r);
46262306a36Sopenharmony_ci				if (ret) {
46362306a36Sopenharmony_ci					v4l2_ctrl_unlock(master);
46462306a36Sopenharmony_ci					goto error;
46562306a36Sopenharmony_ci				}
46662306a36Sopenharmony_ci				master->cluster[i]->is_new = 1;
46762306a36Sopenharmony_ci				r->req_done = true;
46862306a36Sopenharmony_ci			}
46962306a36Sopenharmony_ci		}
47062306a36Sopenharmony_ci		/*
47162306a36Sopenharmony_ci		 * For volatile autoclusters that are currently in auto mode
47262306a36Sopenharmony_ci		 * we need to discover if it will be set to manual mode.
47362306a36Sopenharmony_ci		 * If so, then we have to copy the current volatile values
47462306a36Sopenharmony_ci		 * first since those will become the new manual values (which
47562306a36Sopenharmony_ci		 * may be overwritten by explicit new values from this set
47662306a36Sopenharmony_ci		 * of controls).
47762306a36Sopenharmony_ci		 */
47862306a36Sopenharmony_ci		if (master->is_auto && master->has_volatiles &&
47962306a36Sopenharmony_ci		    !is_cur_manual(master)) {
48062306a36Sopenharmony_ci			s32 new_auto_val = *master->p_new.p_s32;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci			/*
48362306a36Sopenharmony_ci			 * If the new value == the manual value, then copy
48462306a36Sopenharmony_ci			 * the current volatile values.
48562306a36Sopenharmony_ci			 */
48662306a36Sopenharmony_ci			if (new_auto_val == master->manual_mode_value)
48762306a36Sopenharmony_ci				update_from_auto_cluster(master);
48862306a36Sopenharmony_ci		}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		ret = try_or_set_cluster(NULL, master, true, 0);
49162306a36Sopenharmony_ci		v4l2_ctrl_unlock(master);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		if (ret)
49462306a36Sopenharmony_ci			break;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cierror:
49862306a36Sopenharmony_ci	media_request_object_put(obj);
49962306a36Sopenharmony_ci	return ret;
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ciEXPORT_SYMBOL(v4l2_ctrl_request_setup);
502