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 */ |
19 | void 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 */ |
28 | void 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 | |
53 | static 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 | |
83 | static 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 | |
95 | static 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 | |
110 | static 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 | |
119 | static 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 | |
125 | struct 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 | } |
139 | EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_find); |
140 | |
141 | struct v4l2_ctrl * |
142 | v4l2_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 | } |
148 | EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find); |
149 | |
150 | static 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 | |
170 | static struct media_request_object * |
171 | v4l2_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 | |
219 | int 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 | |
261 | int 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 | |
324 | void 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 | } |
393 | EXPORT_SYMBOL(v4l2_ctrl_request_complete); |
394 | |
395 | int 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 | |
497 | error: |
498 | media_request_object_put(obj); |
499 | return ret; |
500 | } |
501 | EXPORT_SYMBOL(v4l2_ctrl_request_setup); |
502 | |