brintos

brintos / linux-shallow public Read only

0
0
Text · 12.5 KiB · c637049 Raw
502 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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: " fmt9 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 main34	 * handler is not used in any request.35	 *36	 * The main handler can be identified by having a NULL ops pointer in37	 * 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 in44	 * outstanding requests, then unbind and put those objects before45	 * 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->p_req_valid) ? 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, and192	 * 2) v4l2_ctrl_request_complete() could not allocate a193	 *    control handler object to store the completed state in.194	 *195	 * So return ENOMEM to indicate that there was an out-of-memory196	 * 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 means336	 * that this request doesn't have any controls and so just337	 * 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->p_req_valid)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 means411	 * that this request doesn't have any controls and so just412	 * 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->p_req_valid) {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				ret = req_to_new(r);462				if (ret) {463					v4l2_ctrl_unlock(master);464					goto error;465				}466				master->cluster[i]->is_new = 1;467				r->req_done = true;468			}469		}470		/*471		 * For volatile autoclusters that are currently in auto mode472		 * we need to discover if it will be set to manual mode.473		 * If so, then we have to copy the current volatile values474		 * first since those will become the new manual values (which475		 * may be overwritten by explicit new values from this set476		 * of controls).477		 */478		if (master->is_auto && master->has_volatiles &&479		    !is_cur_manual(master)) {480			s32 new_auto_val = *master->p_new.p_s32;481 482			/*483			 * If the new value == the manual value, then copy484			 * the current volatile values.485			 */486			if (new_auto_val == master->manual_mode_value)487				update_from_auto_cluster(master);488		}489 490		ret = try_or_set_cluster(NULL, master, true, 0);491		v4l2_ctrl_unlock(master);492 493		if (ret)494			break;495	}496 497error:498	media_request_object_put(obj);499	return ret;500}501EXPORT_SYMBOL(v4l2_ctrl_request_setup);502