cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

v4l2-ctrls-request.c (12731B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * V4L2 controls framework Request API implementation.
      4 *
      5 * Copyright (C) 2018-2021  Hans Verkuil <hverkuil-cisco@xs4all.nl>
      6 */
      7
      8#define pr_fmt(fmt) "v4l2-ctrls: " fmt
      9
     10#include <linux/export.h>
     11#include <linux/slab.h>
     12#include <media/v4l2-ctrls.h>
     13#include <media/v4l2-dev.h>
     14#include <media/v4l2-ioctl.h>
     15
     16#include "v4l2-ctrls-priv.h"
     17
     18/* Initialize the request-related fields in a control handler */
     19void v4l2_ctrl_handler_init_request(struct v4l2_ctrl_handler *hdl)
     20{
     21	INIT_LIST_HEAD(&hdl->requests);
     22	INIT_LIST_HEAD(&hdl->requests_queued);
     23	hdl->request_is_queued = false;
     24	media_request_object_init(&hdl->req_obj);
     25}
     26
     27/* Free the request-related fields in a control handler */
     28void v4l2_ctrl_handler_free_request(struct v4l2_ctrl_handler *hdl)
     29{
     30	struct v4l2_ctrl_handler *req, *next_req;
     31
     32	/*
     33	 * Do nothing if this isn't the main handler or the main
     34	 * handler is not used in any request.
     35	 *
     36	 * The main handler can be identified by having a NULL ops pointer in
     37	 * the request object.
     38	 */
     39	if (hdl->req_obj.ops || list_empty(&hdl->requests))
     40		return;
     41
     42	/*
     43	 * If the main handler is freed and it is used by handler objects in
     44	 * outstanding requests, then unbind and put those objects before
     45	 * freeing the main handler.
     46	 */
     47	list_for_each_entry_safe(req, next_req, &hdl->requests, requests) {
     48		media_request_object_unbind(&req->req_obj);
     49		media_request_object_put(&req->req_obj);
     50	}
     51}
     52
     53static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl,
     54				   const struct v4l2_ctrl_handler *from)
     55{
     56	struct v4l2_ctrl_ref *ref;
     57	int err = 0;
     58
     59	if (WARN_ON(!hdl || hdl == from))
     60		return -EINVAL;
     61
     62	if (hdl->error)
     63		return hdl->error;
     64
     65	WARN_ON(hdl->lock != &hdl->_lock);
     66
     67	mutex_lock(from->lock);
     68	list_for_each_entry(ref, &from->ctrl_refs, node) {
     69		struct v4l2_ctrl *ctrl = ref->ctrl;
     70		struct v4l2_ctrl_ref *new_ref;
     71
     72		/* Skip refs inherited from other devices */
     73		if (ref->from_other_dev)
     74			continue;
     75		err = handler_new_ref(hdl, ctrl, &new_ref, false, true);
     76		if (err)
     77			break;
     78	}
     79	mutex_unlock(from->lock);
     80	return err;
     81}
     82
     83static void v4l2_ctrl_request_queue(struct media_request_object *obj)
     84{
     85	struct v4l2_ctrl_handler *hdl =
     86		container_of(obj, struct v4l2_ctrl_handler, req_obj);
     87	struct v4l2_ctrl_handler *main_hdl = obj->priv;
     88
     89	mutex_lock(main_hdl->lock);
     90	list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
     91	hdl->request_is_queued = true;
     92	mutex_unlock(main_hdl->lock);
     93}
     94
     95static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
     96{
     97	struct v4l2_ctrl_handler *hdl =
     98		container_of(obj, struct v4l2_ctrl_handler, req_obj);
     99	struct v4l2_ctrl_handler *main_hdl = obj->priv;
    100
    101	mutex_lock(main_hdl->lock);
    102	list_del_init(&hdl->requests);
    103	if (hdl->request_is_queued) {
    104		list_del_init(&hdl->requests_queued);
    105		hdl->request_is_queued = false;
    106	}
    107	mutex_unlock(main_hdl->lock);
    108}
    109
    110static void v4l2_ctrl_request_release(struct media_request_object *obj)
    111{
    112	struct v4l2_ctrl_handler *hdl =
    113		container_of(obj, struct v4l2_ctrl_handler, req_obj);
    114
    115	v4l2_ctrl_handler_free(hdl);
    116	kfree(hdl);
    117}
    118
    119static const struct media_request_object_ops req_ops = {
    120	.queue = v4l2_ctrl_request_queue,
    121	.unbind = v4l2_ctrl_request_unbind,
    122	.release = v4l2_ctrl_request_release,
    123};
    124
    125struct v4l2_ctrl_handler *v4l2_ctrl_request_hdl_find(struct media_request *req,
    126						     struct v4l2_ctrl_handler *parent)
    127{
    128	struct media_request_object *obj;
    129
    130	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_VALIDATING &&
    131		    req->state != MEDIA_REQUEST_STATE_QUEUED))
    132		return NULL;
    133
    134	obj = media_request_object_find(req, &req_ops, parent);
    135	if (obj)
    136		return container_of(obj, struct v4l2_ctrl_handler, req_obj);
    137	return NULL;
    138}
    139EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find);
    140
    141struct v4l2_ctrl *
    142v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
    143{
    144	struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
    145
    146	return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
    147}
    148EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
    149
    150static int v4l2_ctrl_request_bind(struct media_request *req,
    151				  struct v4l2_ctrl_handler *hdl,
    152				  struct v4l2_ctrl_handler *from)
    153{
    154	int ret;
    155
    156	ret = v4l2_ctrl_request_clone(hdl, from);
    157
    158	if (!ret) {
    159		ret = media_request_object_bind(req, &req_ops,
    160						from, false, &hdl->req_obj);
    161		if (!ret) {
    162			mutex_lock(from->lock);
    163			list_add_tail(&hdl->requests, &from->requests);
    164			mutex_unlock(from->lock);
    165		}
    166	}
    167	return ret;
    168}
    169
    170static struct media_request_object *
    171v4l2_ctrls_find_req_obj(struct v4l2_ctrl_handler *hdl,
    172			struct media_request *req, bool set)
    173{
    174	struct media_request_object *obj;
    175	struct v4l2_ctrl_handler *new_hdl;
    176	int ret;
    177
    178	if (IS_ERR(req))
    179		return ERR_CAST(req);
    180
    181	if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
    182		return ERR_PTR(-EBUSY);
    183
    184	obj = media_request_object_find(req, &req_ops, hdl);
    185	if (obj)
    186		return obj;
    187	/*
    188	 * If there are no controls in this completed request,
    189	 * then that can only happen if:
    190	 *
    191	 * 1) no controls were present in the queued request, and
    192	 * 2) v4l2_ctrl_request_complete() could not allocate a
    193	 *    control handler object to store the completed state in.
    194	 *
    195	 * So return ENOMEM to indicate that there was an out-of-memory
    196	 * error.
    197	 */
    198	if (!set)
    199		return ERR_PTR(-ENOMEM);
    200
    201	new_hdl = kzalloc(sizeof(*new_hdl), GFP_KERNEL);
    202	if (!new_hdl)
    203		return ERR_PTR(-ENOMEM);
    204
    205	obj = &new_hdl->req_obj;
    206	ret = v4l2_ctrl_handler_init(new_hdl, (hdl->nr_of_buckets - 1) * 8);
    207	if (!ret)
    208		ret = v4l2_ctrl_request_bind(req, new_hdl, hdl);
    209	if (ret) {
    210		v4l2_ctrl_handler_free(new_hdl);
    211		kfree(new_hdl);
    212		return ERR_PTR(ret);
    213	}
    214
    215	media_request_object_get(obj);
    216	return obj;
    217}
    218
    219int v4l2_g_ext_ctrls_request(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
    220			     struct media_device *mdev, struct v4l2_ext_controls *cs)
    221{
    222	struct media_request_object *obj = NULL;
    223	struct media_request *req = NULL;
    224	int ret;
    225
    226	if (!mdev || cs->request_fd < 0)
    227		return -EINVAL;
    228
    229	req = media_request_get_by_fd(mdev, cs->request_fd);
    230	if (IS_ERR(req))
    231		return PTR_ERR(req);
    232
    233	if (req->state != MEDIA_REQUEST_STATE_COMPLETE) {
    234		media_request_put(req);
    235		return -EACCES;
    236	}
    237
    238	ret = media_request_lock_for_access(req);
    239	if (ret) {
    240		media_request_put(req);
    241		return ret;
    242	}
    243
    244	obj = v4l2_ctrls_find_req_obj(hdl, req, false);
    245	if (IS_ERR(obj)) {
    246		media_request_unlock_for_access(req);
    247		media_request_put(req);
    248		return PTR_ERR(obj);
    249	}
    250
    251	hdl = container_of(obj, struct v4l2_ctrl_handler,
    252			   req_obj);
    253	ret = v4l2_g_ext_ctrls_common(hdl, cs, vdev);
    254
    255	media_request_unlock_for_access(req);
    256	media_request_object_put(obj);
    257	media_request_put(req);
    258	return ret;
    259}
    260
    261int try_set_ext_ctrls_request(struct v4l2_fh *fh,
    262			      struct v4l2_ctrl_handler *hdl,
    263			      struct video_device *vdev,
    264			      struct media_device *mdev,
    265			      struct v4l2_ext_controls *cs, bool set)
    266{
    267	struct media_request_object *obj = NULL;
    268	struct media_request *req = NULL;
    269	int ret;
    270
    271	if (!mdev) {
    272		dprintk(vdev, "%s: missing media device\n",
    273			video_device_node_name(vdev));
    274		return -EINVAL;
    275	}
    276
    277	if (cs->request_fd < 0) {
    278		dprintk(vdev, "%s: invalid request fd %d\n",
    279			video_device_node_name(vdev), cs->request_fd);
    280		return -EINVAL;
    281	}
    282
    283	req = media_request_get_by_fd(mdev, cs->request_fd);
    284	if (IS_ERR(req)) {
    285		dprintk(vdev, "%s: cannot find request fd %d\n",
    286			video_device_node_name(vdev), cs->request_fd);
    287		return PTR_ERR(req);
    288	}
    289
    290	ret = media_request_lock_for_update(req);
    291	if (ret) {
    292		dprintk(vdev, "%s: cannot lock request fd %d\n",
    293			video_device_node_name(vdev), cs->request_fd);
    294		media_request_put(req);
    295		return ret;
    296	}
    297
    298	obj = v4l2_ctrls_find_req_obj(hdl, req, set);
    299	if (IS_ERR(obj)) {
    300		dprintk(vdev,
    301			"%s: cannot find request object for request fd %d\n",
    302			video_device_node_name(vdev),
    303			cs->request_fd);
    304		media_request_unlock_for_update(req);
    305		media_request_put(req);
    306		return PTR_ERR(obj);
    307	}
    308
    309	hdl = container_of(obj, struct v4l2_ctrl_handler,
    310			   req_obj);
    311	ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
    312	if (ret)
    313		dprintk(vdev,
    314			"%s: try_set_ext_ctrls_common failed (%d)\n",
    315			video_device_node_name(vdev), ret);
    316
    317	media_request_unlock_for_update(req);
    318	media_request_object_put(obj);
    319	media_request_put(req);
    320
    321	return ret;
    322}
    323
    324void v4l2_ctrl_request_complete(struct media_request *req,
    325				struct v4l2_ctrl_handler *main_hdl)
    326{
    327	struct media_request_object *obj;
    328	struct v4l2_ctrl_handler *hdl;
    329	struct v4l2_ctrl_ref *ref;
    330
    331	if (!req || !main_hdl)
    332		return;
    333
    334	/*
    335	 * Note that it is valid if nothing was found. It means
    336	 * that this request doesn't have any controls and so just
    337	 * wants to leave the controls unchanged.
    338	 */
    339	obj = media_request_object_find(req, &req_ops, main_hdl);
    340	if (!obj) {
    341		int ret;
    342
    343		/* Create a new request so the driver can return controls */
    344		hdl = kzalloc(sizeof(*hdl), GFP_KERNEL);
    345		if (!hdl)
    346			return;
    347
    348		ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8);
    349		if (!ret)
    350			ret = v4l2_ctrl_request_bind(req, hdl, main_hdl);
    351		if (ret) {
    352			v4l2_ctrl_handler_free(hdl);
    353			kfree(hdl);
    354			return;
    355		}
    356		hdl->request_is_queued = true;
    357		obj = media_request_object_find(req, &req_ops, main_hdl);
    358	}
    359	hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
    360
    361	list_for_each_entry(ref, &hdl->ctrl_refs, node) {
    362		struct v4l2_ctrl *ctrl = ref->ctrl;
    363		struct v4l2_ctrl *master = ctrl->cluster[0];
    364		unsigned int i;
    365
    366		if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
    367			v4l2_ctrl_lock(master);
    368			/* g_volatile_ctrl will update the current control values */
    369			for (i = 0; i < master->ncontrols; i++)
    370				cur_to_new(master->cluster[i]);
    371			call_op(master, g_volatile_ctrl);
    372			new_to_req(ref);
    373			v4l2_ctrl_unlock(master);
    374			continue;
    375		}
    376		if (ref->valid_p_req)
    377			continue;
    378
    379		/* Copy the current control value into the request */
    380		v4l2_ctrl_lock(ctrl);
    381		cur_to_req(ref);
    382		v4l2_ctrl_unlock(ctrl);
    383	}
    384
    385	mutex_lock(main_hdl->lock);
    386	WARN_ON(!hdl->request_is_queued);
    387	list_del_init(&hdl->requests_queued);
    388	hdl->request_is_queued = false;
    389	mutex_unlock(main_hdl->lock);
    390	media_request_object_complete(obj);
    391	media_request_object_put(obj);
    392}
    393EXPORT_SYMBOL(v4l2_ctrl_request_complete);
    394
    395int v4l2_ctrl_request_setup(struct media_request *req,
    396			    struct v4l2_ctrl_handler *main_hdl)
    397{
    398	struct media_request_object *obj;
    399	struct v4l2_ctrl_handler *hdl;
    400	struct v4l2_ctrl_ref *ref;
    401	int ret = 0;
    402
    403	if (!req || !main_hdl)
    404		return 0;
    405
    406	if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
    407		return -EBUSY;
    408
    409	/*
    410	 * Note that it is valid if nothing was found. It means
    411	 * that this request doesn't have any controls and so just
    412	 * wants to leave the controls unchanged.
    413	 */
    414	obj = media_request_object_find(req, &req_ops, main_hdl);
    415	if (!obj)
    416		return 0;
    417	if (obj->completed) {
    418		media_request_object_put(obj);
    419		return -EBUSY;
    420	}
    421	hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
    422
    423	list_for_each_entry(ref, &hdl->ctrl_refs, node)
    424		ref->req_done = false;
    425
    426	list_for_each_entry(ref, &hdl->ctrl_refs, node) {
    427		struct v4l2_ctrl *ctrl = ref->ctrl;
    428		struct v4l2_ctrl *master = ctrl->cluster[0];
    429		bool have_new_data = false;
    430		int i;
    431
    432		/*
    433		 * Skip if this control was already handled by a cluster.
    434		 * Skip button controls and read-only controls.
    435		 */
    436		if (ref->req_done || (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
    437			continue;
    438
    439		v4l2_ctrl_lock(master);
    440		for (i = 0; i < master->ncontrols; i++) {
    441			if (master->cluster[i]) {
    442				struct v4l2_ctrl_ref *r =
    443					find_ref(hdl, master->cluster[i]->id);
    444
    445				if (r->valid_p_req) {
    446					have_new_data = true;
    447					break;
    448				}
    449			}
    450		}
    451		if (!have_new_data) {
    452			v4l2_ctrl_unlock(master);
    453			continue;
    454		}
    455
    456		for (i = 0; i < master->ncontrols; i++) {
    457			if (master->cluster[i]) {
    458				struct v4l2_ctrl_ref *r =
    459					find_ref(hdl, master->cluster[i]->id);
    460
    461				req_to_new(r);
    462				master->cluster[i]->is_new = 1;
    463				r->req_done = true;
    464			}
    465		}
    466		/*
    467		 * For volatile autoclusters that are currently in auto mode
    468		 * we need to discover if it will be set to manual mode.
    469		 * If so, then we have to copy the current volatile values
    470		 * first since those will become the new manual values (which
    471		 * may be overwritten by explicit new values from this set
    472		 * of controls).
    473		 */
    474		if (master->is_auto && master->has_volatiles &&
    475		    !is_cur_manual(master)) {
    476			s32 new_auto_val = *master->p_new.p_s32;
    477
    478			/*
    479			 * If the new value == the manual value, then copy
    480			 * the current volatile values.
    481			 */
    482			if (new_auto_val == master->manual_mode_value)
    483				update_from_auto_cluster(master);
    484		}
    485
    486		ret = try_or_set_cluster(NULL, master, true, 0);
    487		v4l2_ctrl_unlock(master);
    488
    489		if (ret)
    490			break;
    491	}
    492
    493	media_request_object_put(obj);
    494	return ret;
    495}
    496EXPORT_SYMBOL(v4l2_ctrl_request_setup);