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(list: &hdl->requests);
22 INIT_LIST_HEAD(list: &hdl->requests_queued);
23 hdl->request_is_queued = false;
24 media_request_object_init(obj: &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(head: &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(obj: &req->req_obj);
49 media_request_object_put(obj: &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, ctrl_ref: &new_ref, from_other_dev: false, allocate_req: true);
76 if (err)
77 break;
78 }
79 mutex_unlock(lock: 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(new: &hdl->requests_queued, head: &main_hdl->requests_queued);
91 hdl->request_is_queued = true;
92 mutex_unlock(lock: 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(entry: &hdl->requests);
103 if (hdl->request_is_queued) {
104 list_del_init(entry: &hdl->requests_queued);
105 hdl->request_is_queued = false;
106 }
107 mutex_unlock(lock: 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(objp: 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, ops: &req_ops, priv: 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, ops: &req_ops,
160 priv: from, is_buffer: false, obj: &hdl->req_obj);
161 if (!ret) {
162 mutex_lock(from->lock);
163 list_add_tail(new: &hdl->requests, head: &from->requests);
164 mutex_unlock(lock: 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(ptr: req))
179 return ERR_CAST(ptr: req);
180
181 if (set && WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
182 return ERR_PTR(error: -EBUSY);
183
184 obj = media_request_object_find(req, ops: &req_ops, priv: 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(error: -ENOMEM);
200
201 new_hdl = kzalloc(size: sizeof(*new_hdl), GFP_KERNEL);
202 if (!new_hdl)
203 return ERR_PTR(error: -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, hdl: new_hdl, from: hdl);
209 if (ret) {
210 v4l2_ctrl_handler_free(hdl: new_hdl);
211 kfree(objp: new_hdl);
212 return ERR_PTR(error: 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, request_fd: cs->request_fd);
230 if (IS_ERR(ptr: req))
231 return PTR_ERR(ptr: 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, set: false);
245 if (IS_ERR(ptr: obj)) {
246 media_request_unlock_for_access(req);
247 media_request_put(req);
248 return PTR_ERR(ptr: 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, request_fd: cs->request_fd);
284 if (IS_ERR(ptr: req)) {
285 dprintk(vdev, "%s: cannot find request fd %d\n",
286 video_device_node_name(vdev), cs->request_fd);
287 return PTR_ERR(ptr: 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(ptr: 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(ptr: 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, ops: &req_ops, priv: main_hdl);
340 if (!obj) {
341 int ret;
342
343 /* Create a new request so the driver can return controls */
344 hdl = kzalloc(size: 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, from: main_hdl);
351 if (ret) {
352 v4l2_ctrl_handler_free(hdl);
353 kfree(objp: hdl);
354 return;
355 }
356 hdl->request_is_queued = true;
357 obj = media_request_object_find(req, ops: &req_ops, priv: 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(ctrl: master);
368 /* g_volatile_ctrl will update the current control values */
369 for (i = 0; i < master->ncontrols; i++)
370 cur_to_new(ctrl: master->cluster[i]);
371 call_op(master, g_volatile_ctrl);
372 new_to_req(ref);
373 v4l2_ctrl_unlock(ctrl: 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(entry: &hdl->requests_queued);
388 hdl->request_is_queued = false;
389 mutex_unlock(lock: 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, ops: &req_ops, priv: 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(ctrl: master);
440 for (i = 0; i < master->ncontrols; i++) {
441 if (master->cluster[i]) {
442 struct v4l2_ctrl_ref *r =
443 find_ref(hdl, id: 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(ctrl: 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, id: master->cluster[i]->id);
460
461 ret = req_to_new(ref: r);
462 if (ret) {
463 v4l2_ctrl_unlock(ctrl: 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 mode
472 * we need to discover if it will be set to manual mode.
473 * If so, then we have to copy the current volatile values
474 * first since those will become the new manual values (which
475 * may be overwritten by explicit new values from this set
476 * 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 copy
484 * 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, set: true, ch_flags: 0);
491 v4l2_ctrl_unlock(ctrl: 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

source code of linux/drivers/media/v4l2-core/v4l2-ctrls-request.c