171c689dcSHans Verkuil // SPDX-License-Identifier: GPL-2.0-or-later
271c689dcSHans Verkuil /*
371c689dcSHans Verkuil * V4L2 controls framework uAPI implementation:
471c689dcSHans Verkuil *
571c689dcSHans Verkuil * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
671c689dcSHans Verkuil */
771c689dcSHans Verkuil
871c689dcSHans Verkuil #define pr_fmt(fmt) "v4l2-ctrls: " fmt
971c689dcSHans Verkuil
1071c689dcSHans Verkuil #include <linux/export.h>
1171c689dcSHans Verkuil #include <linux/mm.h>
1271c689dcSHans Verkuil #include <linux/slab.h>
1371c689dcSHans Verkuil #include <media/v4l2-ctrls.h>
1471c689dcSHans Verkuil #include <media/v4l2-dev.h>
1571c689dcSHans Verkuil #include <media/v4l2-device.h>
1671c689dcSHans Verkuil #include <media/v4l2-event.h>
1771c689dcSHans Verkuil #include <media/v4l2-ioctl.h>
1871c689dcSHans Verkuil
1971c689dcSHans Verkuil #include "v4l2-ctrls-priv.h"
2071c689dcSHans Verkuil
2171c689dcSHans Verkuil /* Internal temporary helper struct, one for each v4l2_ext_control */
2271c689dcSHans Verkuil struct v4l2_ctrl_helper {
2371c689dcSHans Verkuil /* Pointer to the control reference of the master control */
2471c689dcSHans Verkuil struct v4l2_ctrl_ref *mref;
2571c689dcSHans Verkuil /* The control ref corresponding to the v4l2_ext_control ID field. */
2671c689dcSHans Verkuil struct v4l2_ctrl_ref *ref;
2771c689dcSHans Verkuil /*
2871c689dcSHans Verkuil * v4l2_ext_control index of the next control belonging to the
2971c689dcSHans Verkuil * same cluster, or 0 if there isn't any.
3071c689dcSHans Verkuil */
3171c689dcSHans Verkuil u32 next;
3271c689dcSHans Verkuil };
3371c689dcSHans Verkuil
3471c689dcSHans Verkuil /*
3571c689dcSHans Verkuil * Helper functions to copy control payload data from kernel space to
3671c689dcSHans Verkuil * user space and vice versa.
3771c689dcSHans Verkuil */
3871c689dcSHans Verkuil
3971c689dcSHans Verkuil /* Helper function: copy the given control value back to the caller */
ptr_to_user(struct v4l2_ext_control * c,struct v4l2_ctrl * ctrl,union v4l2_ctrl_ptr ptr)4071c689dcSHans Verkuil static int ptr_to_user(struct v4l2_ext_control *c,
4171c689dcSHans Verkuil struct v4l2_ctrl *ctrl,
4271c689dcSHans Verkuil union v4l2_ctrl_ptr ptr)
4371c689dcSHans Verkuil {
4471c689dcSHans Verkuil u32 len;
4571c689dcSHans Verkuil
4671c689dcSHans Verkuil if (ctrl->is_ptr && !ctrl->is_string)
4771c689dcSHans Verkuil return copy_to_user(c->ptr, ptr.p_const, c->size) ?
4871c689dcSHans Verkuil -EFAULT : 0;
4971c689dcSHans Verkuil
5071c689dcSHans Verkuil switch (ctrl->type) {
5171c689dcSHans Verkuil case V4L2_CTRL_TYPE_STRING:
5271c689dcSHans Verkuil len = strlen(ptr.p_char);
5371c689dcSHans Verkuil if (c->size < len + 1) {
5471c689dcSHans Verkuil c->size = ctrl->elem_size;
5571c689dcSHans Verkuil return -ENOSPC;
5671c689dcSHans Verkuil }
5771c689dcSHans Verkuil return copy_to_user(c->string, ptr.p_char, len + 1) ?
5871c689dcSHans Verkuil -EFAULT : 0;
5971c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER64:
6071c689dcSHans Verkuil c->value64 = *ptr.p_s64;
6171c689dcSHans Verkuil break;
6271c689dcSHans Verkuil default:
6371c689dcSHans Verkuil c->value = *ptr.p_s32;
6471c689dcSHans Verkuil break;
6571c689dcSHans Verkuil }
6671c689dcSHans Verkuil return 0;
6771c689dcSHans Verkuil }
6871c689dcSHans Verkuil
6971c689dcSHans Verkuil /* Helper function: copy the current control value back to the caller */
cur_to_user(struct v4l2_ext_control * c,struct v4l2_ctrl * ctrl)7071c689dcSHans Verkuil static int cur_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
7171c689dcSHans Verkuil {
7271c689dcSHans Verkuil return ptr_to_user(c, ctrl, ctrl->p_cur);
7371c689dcSHans Verkuil }
7471c689dcSHans Verkuil
7571c689dcSHans Verkuil /* Helper function: copy the new control value back to the caller */
new_to_user(struct v4l2_ext_control * c,struct v4l2_ctrl * ctrl)7671c689dcSHans Verkuil static int new_to_user(struct v4l2_ext_control *c,
7771c689dcSHans Verkuil struct v4l2_ctrl *ctrl)
7871c689dcSHans Verkuil {
7971c689dcSHans Verkuil return ptr_to_user(c, ctrl, ctrl->p_new);
8071c689dcSHans Verkuil }
8171c689dcSHans Verkuil
8271c689dcSHans Verkuil /* Helper function: copy the request value back to the caller */
req_to_user(struct v4l2_ext_control * c,struct v4l2_ctrl_ref * ref)8371c689dcSHans Verkuil static int req_to_user(struct v4l2_ext_control *c,
8471c689dcSHans Verkuil struct v4l2_ctrl_ref *ref)
8571c689dcSHans Verkuil {
8671c689dcSHans Verkuil return ptr_to_user(c, ref->ctrl, ref->p_req);
8771c689dcSHans Verkuil }
8871c689dcSHans Verkuil
8971c689dcSHans Verkuil /* Helper function: copy the initial control value back to the caller */
def_to_user(struct v4l2_ext_control * c,struct v4l2_ctrl * ctrl)9071c689dcSHans Verkuil static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
9171c689dcSHans Verkuil {
92cd75981eSHans Verkuil ctrl->type_ops->init(ctrl, 0, ctrl->p_new);
9371c689dcSHans Verkuil
9471c689dcSHans Verkuil return ptr_to_user(c, ctrl, ctrl->p_new);
9571c689dcSHans Verkuil }
9671c689dcSHans Verkuil
97fb582cbaSHans Verkuil /* Helper function: copy the caller-provider value as the new control value */
user_to_new(struct v4l2_ext_control * c,struct v4l2_ctrl * ctrl)98fb582cbaSHans Verkuil static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
9971c689dcSHans Verkuil {
10071c689dcSHans Verkuil int ret;
10171c689dcSHans Verkuil u32 size;
10271c689dcSHans Verkuil
103fb582cbaSHans Verkuil ctrl->is_new = 0;
104fb582cbaSHans Verkuil if (ctrl->is_dyn_array &&
1055f2c5c69SHans Verkuil c->size > ctrl->p_array_alloc_elems * ctrl->elem_size) {
1065f2c5c69SHans Verkuil void *old = ctrl->p_array;
107fb582cbaSHans Verkuil void *tmp = kvzalloc(2 * c->size, GFP_KERNEL);
108fb582cbaSHans Verkuil
109fb582cbaSHans Verkuil if (!tmp)
110fb582cbaSHans Verkuil return -ENOMEM;
111fb582cbaSHans Verkuil memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size);
112fb582cbaSHans Verkuil memcpy(tmp + c->size, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size);
113fb582cbaSHans Verkuil ctrl->p_new.p = tmp;
114fb582cbaSHans Verkuil ctrl->p_cur.p = tmp + c->size;
1155f2c5c69SHans Verkuil ctrl->p_array = tmp;
1165f2c5c69SHans Verkuil ctrl->p_array_alloc_elems = c->size / ctrl->elem_size;
117fb582cbaSHans Verkuil kvfree(old);
118fb582cbaSHans Verkuil }
119fb582cbaSHans Verkuil
12071c689dcSHans Verkuil if (ctrl->is_ptr && !ctrl->is_string) {
121fb582cbaSHans Verkuil unsigned int elems = c->size / ctrl->elem_size;
12271c689dcSHans Verkuil
123fb582cbaSHans Verkuil if (copy_from_user(ctrl->p_new.p, c->ptr, c->size))
124fb582cbaSHans Verkuil return -EFAULT;
125fb582cbaSHans Verkuil ctrl->is_new = 1;
126fb582cbaSHans Verkuil if (ctrl->is_dyn_array)
127fb582cbaSHans Verkuil ctrl->new_elems = elems;
128fb582cbaSHans Verkuil else if (ctrl->is_array)
129cd75981eSHans Verkuil ctrl->type_ops->init(ctrl, elems, ctrl->p_new);
13071c689dcSHans Verkuil return 0;
13171c689dcSHans Verkuil }
13271c689dcSHans Verkuil
13371c689dcSHans Verkuil switch (ctrl->type) {
13471c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER64:
135fb582cbaSHans Verkuil *ctrl->p_new.p_s64 = c->value64;
13671c689dcSHans Verkuil break;
13771c689dcSHans Verkuil case V4L2_CTRL_TYPE_STRING:
13871c689dcSHans Verkuil size = c->size;
13971c689dcSHans Verkuil if (size == 0)
14071c689dcSHans Verkuil return -ERANGE;
14171c689dcSHans Verkuil if (size > ctrl->maximum + 1)
14271c689dcSHans Verkuil size = ctrl->maximum + 1;
143fb582cbaSHans Verkuil ret = copy_from_user(ctrl->p_new.p_char, c->string, size) ? -EFAULT : 0;
14471c689dcSHans Verkuil if (!ret) {
145fb582cbaSHans Verkuil char last = ctrl->p_new.p_char[size - 1];
14671c689dcSHans Verkuil
147fb582cbaSHans Verkuil ctrl->p_new.p_char[size - 1] = 0;
14871c689dcSHans Verkuil /*
14971c689dcSHans Verkuil * If the string was longer than ctrl->maximum,
15071c689dcSHans Verkuil * then return an error.
15171c689dcSHans Verkuil */
152fb582cbaSHans Verkuil if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last)
15371c689dcSHans Verkuil return -ERANGE;
154a1550700SHans Verkuil ctrl->is_new = 1;
15571c689dcSHans Verkuil }
15671c689dcSHans Verkuil return ret;
15771c689dcSHans Verkuil default:
158fb582cbaSHans Verkuil *ctrl->p_new.p_s32 = c->value;
15971c689dcSHans Verkuil break;
16071c689dcSHans Verkuil }
161fb582cbaSHans Verkuil ctrl->is_new = 1;
16271c689dcSHans Verkuil return 0;
16371c689dcSHans Verkuil }
16471c689dcSHans Verkuil
16571c689dcSHans Verkuil /*
16671c689dcSHans Verkuil * VIDIOC_G/TRY/S_EXT_CTRLS implementation
16771c689dcSHans Verkuil */
16871c689dcSHans Verkuil
16971c689dcSHans Verkuil /*
17071c689dcSHans Verkuil * Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
17171c689dcSHans Verkuil *
17271c689dcSHans Verkuil * It is not a fully atomic operation, just best-effort only. After all, if
17371c689dcSHans Verkuil * multiple controls have to be set through multiple i2c writes (for example)
17471c689dcSHans Verkuil * then some initial writes may succeed while others fail. Thus leaving the
17571c689dcSHans Verkuil * system in an inconsistent state. The question is how much effort you are
17671c689dcSHans Verkuil * willing to spend on trying to make something atomic that really isn't.
17771c689dcSHans Verkuil *
17871c689dcSHans Verkuil * From the point of view of an application the main requirement is that
17971c689dcSHans Verkuil * when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
18071c689dcSHans Verkuil * error should be returned without actually affecting any controls.
18171c689dcSHans Verkuil *
18271c689dcSHans Verkuil * If all the values are correct, then it is acceptable to just give up
18371c689dcSHans Verkuil * in case of low-level errors.
18471c689dcSHans Verkuil *
18571c689dcSHans Verkuil * It is important though that the application can tell when only a partial
18671c689dcSHans Verkuil * configuration was done. The way we do that is through the error_idx field
18771c689dcSHans Verkuil * of struct v4l2_ext_controls: if that is equal to the count field then no
18871c689dcSHans Verkuil * controls were affected. Otherwise all controls before that index were
18971c689dcSHans Verkuil * successful in performing their 'get' or 'set' operation, the control at
19071c689dcSHans Verkuil * the given index failed, and you don't know what happened with the controls
19171c689dcSHans Verkuil * after the failed one. Since if they were part of a control cluster they
19271c689dcSHans Verkuil * could have been successfully processed (if a cluster member was encountered
19371c689dcSHans Verkuil * at index < error_idx), they could have failed (if a cluster member was at
19471c689dcSHans Verkuil * error_idx), or they may not have been processed yet (if the first cluster
19571c689dcSHans Verkuil * member appeared after error_idx).
19671c689dcSHans Verkuil *
19771c689dcSHans Verkuil * It is all fairly theoretical, though. In practice all you can do is to
19871c689dcSHans Verkuil * bail out. If error_idx == count, then it is an application bug. If
19971c689dcSHans Verkuil * error_idx < count then it is only an application bug if the error code was
20071c689dcSHans Verkuil * EBUSY. That usually means that something started streaming just when you
20171c689dcSHans Verkuil * tried to set the controls. In all other cases it is a driver/hardware
20271c689dcSHans Verkuil * problem and all you can do is to retry or bail out.
20371c689dcSHans Verkuil *
20471c689dcSHans Verkuil * Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
20571c689dcSHans Verkuil * never modifies controls the error_idx is just set to whatever control
20671c689dcSHans Verkuil * has an invalid value.
20771c689dcSHans Verkuil */
20871c689dcSHans Verkuil
20971c689dcSHans Verkuil /*
21071c689dcSHans Verkuil * Prepare for the extended g/s/try functions.
21171c689dcSHans Verkuil * Find the controls in the control array and do some basic checks.
21271c689dcSHans Verkuil */
prepare_ext_ctrls(struct v4l2_ctrl_handler * hdl,struct v4l2_ext_controls * cs,struct v4l2_ctrl_helper * helpers,struct video_device * vdev,bool get)21371c689dcSHans Verkuil static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
21471c689dcSHans Verkuil struct v4l2_ext_controls *cs,
21571c689dcSHans Verkuil struct v4l2_ctrl_helper *helpers,
21671c689dcSHans Verkuil struct video_device *vdev,
21771c689dcSHans Verkuil bool get)
21871c689dcSHans Verkuil {
21971c689dcSHans Verkuil struct v4l2_ctrl_helper *h;
22071c689dcSHans Verkuil bool have_clusters = false;
22171c689dcSHans Verkuil u32 i;
22271c689dcSHans Verkuil
22371c689dcSHans Verkuil for (i = 0, h = helpers; i < cs->count; i++, h++) {
22471c689dcSHans Verkuil struct v4l2_ext_control *c = &cs->controls[i];
22571c689dcSHans Verkuil struct v4l2_ctrl_ref *ref;
22671c689dcSHans Verkuil struct v4l2_ctrl *ctrl;
22771c689dcSHans Verkuil u32 id = c->id & V4L2_CTRL_ID_MASK;
22871c689dcSHans Verkuil
22971c689dcSHans Verkuil cs->error_idx = i;
23071c689dcSHans Verkuil
23171c689dcSHans Verkuil if (cs->which &&
23271c689dcSHans Verkuil cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
23371c689dcSHans Verkuil cs->which != V4L2_CTRL_WHICH_REQUEST_VAL &&
23471c689dcSHans Verkuil V4L2_CTRL_ID2WHICH(id) != cs->which) {
23571c689dcSHans Verkuil dprintk(vdev,
23671c689dcSHans Verkuil "invalid which 0x%x or control id 0x%x\n",
23771c689dcSHans Verkuil cs->which, id);
23871c689dcSHans Verkuil return -EINVAL;
23971c689dcSHans Verkuil }
24071c689dcSHans Verkuil
24171c689dcSHans Verkuil /*
24271c689dcSHans Verkuil * Old-style private controls are not allowed for
24371c689dcSHans Verkuil * extended controls.
24471c689dcSHans Verkuil */
24571c689dcSHans Verkuil if (id >= V4L2_CID_PRIVATE_BASE) {
24671c689dcSHans Verkuil dprintk(vdev,
24771c689dcSHans Verkuil "old-style private controls not allowed\n");
24871c689dcSHans Verkuil return -EINVAL;
24971c689dcSHans Verkuil }
25071c689dcSHans Verkuil ref = find_ref_lock(hdl, id);
25171c689dcSHans Verkuil if (!ref) {
25271c689dcSHans Verkuil dprintk(vdev, "cannot find control id 0x%x\n", id);
25371c689dcSHans Verkuil return -EINVAL;
25471c689dcSHans Verkuil }
25571c689dcSHans Verkuil h->ref = ref;
25671c689dcSHans Verkuil ctrl = ref->ctrl;
25771c689dcSHans Verkuil if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) {
25871c689dcSHans Verkuil dprintk(vdev, "control id 0x%x is disabled\n", id);
25971c689dcSHans Verkuil return -EINVAL;
26071c689dcSHans Verkuil }
26171c689dcSHans Verkuil
26271c689dcSHans Verkuil if (ctrl->cluster[0]->ncontrols > 1)
26371c689dcSHans Verkuil have_clusters = true;
26471c689dcSHans Verkuil if (ctrl->cluster[0] != ctrl)
26571c689dcSHans Verkuil ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
266fb582cbaSHans Verkuil if (ctrl->is_dyn_array) {
267fb582cbaSHans Verkuil unsigned int max_size = ctrl->dims[0] * ctrl->elem_size;
268fb582cbaSHans Verkuil unsigned int tot_size = ctrl->elem_size;
269fb582cbaSHans Verkuil
270fb582cbaSHans Verkuil if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
271fb582cbaSHans Verkuil tot_size *= ref->p_req_elems;
272fb582cbaSHans Verkuil else
273fb582cbaSHans Verkuil tot_size *= ctrl->elems;
274fb582cbaSHans Verkuil
275fb582cbaSHans Verkuil c->size = ctrl->elem_size * (c->size / ctrl->elem_size);
276fb582cbaSHans Verkuil if (get) {
277fb582cbaSHans Verkuil if (c->size < tot_size) {
278fb582cbaSHans Verkuil c->size = tot_size;
279fb582cbaSHans Verkuil return -ENOSPC;
280fb582cbaSHans Verkuil }
281fb582cbaSHans Verkuil c->size = tot_size;
282fb582cbaSHans Verkuil } else {
283fb582cbaSHans Verkuil if (c->size > max_size) {
284fb582cbaSHans Verkuil c->size = max_size;
285fb582cbaSHans Verkuil return -ENOSPC;
286fb582cbaSHans Verkuil }
287fb582cbaSHans Verkuil if (!c->size)
288fb582cbaSHans Verkuil return -EFAULT;
289fb582cbaSHans Verkuil }
290fb582cbaSHans Verkuil } else if (ctrl->is_ptr && !ctrl->is_string) {
29171c689dcSHans Verkuil unsigned int tot_size = ctrl->elems * ctrl->elem_size;
29271c689dcSHans Verkuil
29371c689dcSHans Verkuil if (c->size < tot_size) {
29471c689dcSHans Verkuil /*
29571c689dcSHans Verkuil * In the get case the application first
29671c689dcSHans Verkuil * queries to obtain the size of the control.
29771c689dcSHans Verkuil */
29871c689dcSHans Verkuil if (get) {
29971c689dcSHans Verkuil c->size = tot_size;
30071c689dcSHans Verkuil return -ENOSPC;
30171c689dcSHans Verkuil }
30271c689dcSHans Verkuil dprintk(vdev,
30371c689dcSHans Verkuil "pointer control id 0x%x size too small, %d bytes but %d bytes needed\n",
30471c689dcSHans Verkuil id, c->size, tot_size);
30571c689dcSHans Verkuil return -EFAULT;
30671c689dcSHans Verkuil }
30771c689dcSHans Verkuil c->size = tot_size;
30871c689dcSHans Verkuil }
30971c689dcSHans Verkuil /* Store the ref to the master control of the cluster */
31071c689dcSHans Verkuil h->mref = ref;
31171c689dcSHans Verkuil /*
31271c689dcSHans Verkuil * Initially set next to 0, meaning that there is no other
31371c689dcSHans Verkuil * control in this helper array belonging to the same
31471c689dcSHans Verkuil * cluster.
31571c689dcSHans Verkuil */
31671c689dcSHans Verkuil h->next = 0;
31771c689dcSHans Verkuil }
31871c689dcSHans Verkuil
31971c689dcSHans Verkuil /*
32071c689dcSHans Verkuil * We are done if there were no controls that belong to a multi-
32171c689dcSHans Verkuil * control cluster.
32271c689dcSHans Verkuil */
32371c689dcSHans Verkuil if (!have_clusters)
32471c689dcSHans Verkuil return 0;
32571c689dcSHans Verkuil
32671c689dcSHans Verkuil /*
32771c689dcSHans Verkuil * The code below figures out in O(n) time which controls in the list
32871c689dcSHans Verkuil * belong to the same cluster.
32971c689dcSHans Verkuil */
33071c689dcSHans Verkuil
33171c689dcSHans Verkuil /* This has to be done with the handler lock taken. */
33271c689dcSHans Verkuil mutex_lock(hdl->lock);
33371c689dcSHans Verkuil
33471c689dcSHans Verkuil /* First zero the helper field in the master control references */
33571c689dcSHans Verkuil for (i = 0; i < cs->count; i++)
33671c689dcSHans Verkuil helpers[i].mref->helper = NULL;
33771c689dcSHans Verkuil for (i = 0, h = helpers; i < cs->count; i++, h++) {
33871c689dcSHans Verkuil struct v4l2_ctrl_ref *mref = h->mref;
33971c689dcSHans Verkuil
34071c689dcSHans Verkuil /*
34171c689dcSHans Verkuil * If the mref->helper is set, then it points to an earlier
34271c689dcSHans Verkuil * helper that belongs to the same cluster.
34371c689dcSHans Verkuil */
34471c689dcSHans Verkuil if (mref->helper) {
34571c689dcSHans Verkuil /*
34671c689dcSHans Verkuil * Set the next field of mref->helper to the current
34771c689dcSHans Verkuil * index: this means that the earlier helper now
34871c689dcSHans Verkuil * points to the next helper in the same cluster.
34971c689dcSHans Verkuil */
35071c689dcSHans Verkuil mref->helper->next = i;
35171c689dcSHans Verkuil /*
35271c689dcSHans Verkuil * mref should be set only for the first helper in the
35371c689dcSHans Verkuil * cluster, clear the others.
35471c689dcSHans Verkuil */
35571c689dcSHans Verkuil h->mref = NULL;
35671c689dcSHans Verkuil }
35771c689dcSHans Verkuil /* Point the mref helper to the current helper struct. */
35871c689dcSHans Verkuil mref->helper = h;
35971c689dcSHans Verkuil }
36071c689dcSHans Verkuil mutex_unlock(hdl->lock);
36171c689dcSHans Verkuil return 0;
36271c689dcSHans Verkuil }
36371c689dcSHans Verkuil
36471c689dcSHans Verkuil /*
36571c689dcSHans Verkuil * Handles the corner case where cs->count == 0. It checks whether the
36671c689dcSHans Verkuil * specified control class exists. If that class ID is 0, then it checks
36771c689dcSHans Verkuil * whether there are any controls at all.
36871c689dcSHans Verkuil */
class_check(struct v4l2_ctrl_handler * hdl,u32 which)36971c689dcSHans Verkuil static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
37071c689dcSHans Verkuil {
37171c689dcSHans Verkuil if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL ||
37271c689dcSHans Verkuil which == V4L2_CTRL_WHICH_REQUEST_VAL)
37371c689dcSHans Verkuil return 0;
37471c689dcSHans Verkuil return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
37571c689dcSHans Verkuil }
37671c689dcSHans Verkuil
37771c689dcSHans Verkuil /*
37871c689dcSHans Verkuil * Get extended controls. Allocates the helpers array if needed.
37971c689dcSHans Verkuil *
38071c689dcSHans Verkuil * Note that v4l2_g_ext_ctrls_common() with 'which' set to
38171c689dcSHans Verkuil * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
382fb582cbaSHans Verkuil * completed, and in that case p_req_valid is true for all controls.
38371c689dcSHans Verkuil */
v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler * hdl,struct v4l2_ext_controls * cs,struct video_device * vdev)38471c689dcSHans Verkuil int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
38571c689dcSHans Verkuil struct v4l2_ext_controls *cs,
38671c689dcSHans Verkuil struct video_device *vdev)
38771c689dcSHans Verkuil {
38871c689dcSHans Verkuil struct v4l2_ctrl_helper helper[4];
38971c689dcSHans Verkuil struct v4l2_ctrl_helper *helpers = helper;
39071c689dcSHans Verkuil int ret;
39171c689dcSHans Verkuil int i, j;
39271c689dcSHans Verkuil bool is_default, is_request;
39371c689dcSHans Verkuil
39471c689dcSHans Verkuil is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
39571c689dcSHans Verkuil is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL);
39671c689dcSHans Verkuil
39771c689dcSHans Verkuil cs->error_idx = cs->count;
39871c689dcSHans Verkuil cs->which = V4L2_CTRL_ID2WHICH(cs->which);
39971c689dcSHans Verkuil
40071c689dcSHans Verkuil if (!hdl)
40171c689dcSHans Verkuil return -EINVAL;
40271c689dcSHans Verkuil
40371c689dcSHans Verkuil if (cs->count == 0)
40471c689dcSHans Verkuil return class_check(hdl, cs->which);
40571c689dcSHans Verkuil
40671c689dcSHans Verkuil if (cs->count > ARRAY_SIZE(helper)) {
40771c689dcSHans Verkuil helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
40871c689dcSHans Verkuil GFP_KERNEL);
40971c689dcSHans Verkuil if (!helpers)
41071c689dcSHans Verkuil return -ENOMEM;
41171c689dcSHans Verkuil }
41271c689dcSHans Verkuil
41371c689dcSHans Verkuil ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, true);
41471c689dcSHans Verkuil cs->error_idx = cs->count;
41571c689dcSHans Verkuil
41671c689dcSHans Verkuil for (i = 0; !ret && i < cs->count; i++)
41771c689dcSHans Verkuil if (helpers[i].ref->ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
41871c689dcSHans Verkuil ret = -EACCES;
41971c689dcSHans Verkuil
42071c689dcSHans Verkuil for (i = 0; !ret && i < cs->count; i++) {
42171c689dcSHans Verkuil struct v4l2_ctrl *master;
42271c689dcSHans Verkuil bool is_volatile = false;
42371c689dcSHans Verkuil u32 idx = i;
42471c689dcSHans Verkuil
42571c689dcSHans Verkuil if (!helpers[i].mref)
42671c689dcSHans Verkuil continue;
42771c689dcSHans Verkuil
42871c689dcSHans Verkuil master = helpers[i].mref->ctrl;
42971c689dcSHans Verkuil cs->error_idx = i;
43071c689dcSHans Verkuil
43171c689dcSHans Verkuil v4l2_ctrl_lock(master);
43271c689dcSHans Verkuil
43371c689dcSHans Verkuil /*
43471c689dcSHans Verkuil * g_volatile_ctrl will update the new control values.
43571c689dcSHans Verkuil * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and
43671c689dcSHans Verkuil * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests
43771c689dcSHans Verkuil * it is v4l2_ctrl_request_complete() that copies the
43871c689dcSHans Verkuil * volatile controls at the time of request completion
43971c689dcSHans Verkuil * to the request, so you don't want to do that again.
44071c689dcSHans Verkuil */
44171c689dcSHans Verkuil if (!is_default && !is_request &&
44271c689dcSHans Verkuil ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
44371c689dcSHans Verkuil (master->has_volatiles && !is_cur_manual(master)))) {
44471c689dcSHans Verkuil for (j = 0; j < master->ncontrols; j++)
44571c689dcSHans Verkuil cur_to_new(master->cluster[j]);
44671c689dcSHans Verkuil ret = call_op(master, g_volatile_ctrl);
44771c689dcSHans Verkuil is_volatile = true;
44871c689dcSHans Verkuil }
44971c689dcSHans Verkuil
45071c689dcSHans Verkuil if (ret) {
45171c689dcSHans Verkuil v4l2_ctrl_unlock(master);
45271c689dcSHans Verkuil break;
45371c689dcSHans Verkuil }
45471c689dcSHans Verkuil
45571c689dcSHans Verkuil /*
45671c689dcSHans Verkuil * Copy the default value (if is_default is true), the
45771c689dcSHans Verkuil * request value (if is_request is true and p_req is valid),
45871c689dcSHans Verkuil * the new volatile value (if is_volatile is true) or the
45971c689dcSHans Verkuil * current value.
46071c689dcSHans Verkuil */
46171c689dcSHans Verkuil do {
46271c689dcSHans Verkuil struct v4l2_ctrl_ref *ref = helpers[idx].ref;
46371c689dcSHans Verkuil
46471c689dcSHans Verkuil if (is_default)
46571c689dcSHans Verkuil ret = def_to_user(cs->controls + idx, ref->ctrl);
4667392d87aSHans Verkuil else if (is_request && ref->p_req_array_enomem)
467fb582cbaSHans Verkuil ret = -ENOMEM;
468fb582cbaSHans Verkuil else if (is_request && ref->p_req_valid)
46971c689dcSHans Verkuil ret = req_to_user(cs->controls + idx, ref);
47071c689dcSHans Verkuil else if (is_volatile)
47171c689dcSHans Verkuil ret = new_to_user(cs->controls + idx, ref->ctrl);
47271c689dcSHans Verkuil else
47371c689dcSHans Verkuil ret = cur_to_user(cs->controls + idx, ref->ctrl);
47471c689dcSHans Verkuil idx = helpers[idx].next;
47571c689dcSHans Verkuil } while (!ret && idx);
47671c689dcSHans Verkuil
47771c689dcSHans Verkuil v4l2_ctrl_unlock(master);
47871c689dcSHans Verkuil }
47971c689dcSHans Verkuil
48071c689dcSHans Verkuil if (cs->count > ARRAY_SIZE(helper))
48171c689dcSHans Verkuil kvfree(helpers);
48271c689dcSHans Verkuil return ret;
48371c689dcSHans Verkuil }
48471c689dcSHans Verkuil
v4l2_g_ext_ctrls(struct v4l2_ctrl_handler * hdl,struct video_device * vdev,struct media_device * mdev,struct v4l2_ext_controls * cs)48571c689dcSHans Verkuil int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
48671c689dcSHans Verkuil struct media_device *mdev, struct v4l2_ext_controls *cs)
48771c689dcSHans Verkuil {
48871c689dcSHans Verkuil if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
48971c689dcSHans Verkuil return v4l2_g_ext_ctrls_request(hdl, vdev, mdev, cs);
49071c689dcSHans Verkuil
49171c689dcSHans Verkuil return v4l2_g_ext_ctrls_common(hdl, cs, vdev);
49271c689dcSHans Verkuil }
49371c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_g_ext_ctrls);
49471c689dcSHans Verkuil
495fb582cbaSHans Verkuil /* Validate a new control */
validate_new(const struct v4l2_ctrl * ctrl,union v4l2_ctrl_ptr p_new)496fb582cbaSHans Verkuil static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
497fb582cbaSHans Verkuil {
498cd75981eSHans Verkuil return ctrl->type_ops->validate(ctrl, p_new);
499fb582cbaSHans Verkuil }
500fb582cbaSHans Verkuil
50171c689dcSHans Verkuil /* Validate controls. */
validate_ctrls(struct v4l2_ext_controls * cs,struct v4l2_ctrl_helper * helpers,struct video_device * vdev,bool set)50271c689dcSHans Verkuil static int validate_ctrls(struct v4l2_ext_controls *cs,
50371c689dcSHans Verkuil struct v4l2_ctrl_helper *helpers,
50471c689dcSHans Verkuil struct video_device *vdev,
50571c689dcSHans Verkuil bool set)
50671c689dcSHans Verkuil {
50771c689dcSHans Verkuil unsigned int i;
50871c689dcSHans Verkuil int ret = 0;
50971c689dcSHans Verkuil
51071c689dcSHans Verkuil cs->error_idx = cs->count;
51171c689dcSHans Verkuil for (i = 0; i < cs->count; i++) {
51271c689dcSHans Verkuil struct v4l2_ctrl *ctrl = helpers[i].ref->ctrl;
51371c689dcSHans Verkuil union v4l2_ctrl_ptr p_new;
51471c689dcSHans Verkuil
51571c689dcSHans Verkuil cs->error_idx = i;
51671c689dcSHans Verkuil
51771c689dcSHans Verkuil if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) {
51871c689dcSHans Verkuil dprintk(vdev,
51971c689dcSHans Verkuil "control id 0x%x is read-only\n",
52071c689dcSHans Verkuil ctrl->id);
52171c689dcSHans Verkuil return -EACCES;
52271c689dcSHans Verkuil }
52371c689dcSHans Verkuil /*
52471c689dcSHans Verkuil * This test is also done in try_set_control_cluster() which
52571c689dcSHans Verkuil * is called in atomic context, so that has the final say,
52671c689dcSHans Verkuil * but it makes sense to do an up-front check as well. Once
52771c689dcSHans Verkuil * an error occurs in try_set_control_cluster() some other
52871c689dcSHans Verkuil * controls may have been set already and we want to do a
52971c689dcSHans Verkuil * best-effort to avoid that.
53071c689dcSHans Verkuil */
53171c689dcSHans Verkuil if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) {
53271c689dcSHans Verkuil dprintk(vdev,
53371c689dcSHans Verkuil "control id 0x%x is grabbed, cannot set\n",
53471c689dcSHans Verkuil ctrl->id);
53571c689dcSHans Verkuil return -EBUSY;
53671c689dcSHans Verkuil }
53771c689dcSHans Verkuil /*
53871c689dcSHans Verkuil * Skip validation for now if the payload needs to be copied
53971c689dcSHans Verkuil * from userspace into kernelspace. We'll validate those later.
54071c689dcSHans Verkuil */
54171c689dcSHans Verkuil if (ctrl->is_ptr)
54271c689dcSHans Verkuil continue;
54371c689dcSHans Verkuil if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
54471c689dcSHans Verkuil p_new.p_s64 = &cs->controls[i].value64;
54571c689dcSHans Verkuil else
54671c689dcSHans Verkuil p_new.p_s32 = &cs->controls[i].value;
54771c689dcSHans Verkuil ret = validate_new(ctrl, p_new);
54871c689dcSHans Verkuil if (ret)
54971c689dcSHans Verkuil return ret;
55071c689dcSHans Verkuil }
55171c689dcSHans Verkuil return 0;
55271c689dcSHans Verkuil }
55371c689dcSHans Verkuil
55471c689dcSHans Verkuil /* Try or try-and-set controls */
try_set_ext_ctrls_common(struct v4l2_fh * fh,struct v4l2_ctrl_handler * hdl,struct v4l2_ext_controls * cs,struct video_device * vdev,bool set)55571c689dcSHans Verkuil int try_set_ext_ctrls_common(struct v4l2_fh *fh,
55671c689dcSHans Verkuil struct v4l2_ctrl_handler *hdl,
55771c689dcSHans Verkuil struct v4l2_ext_controls *cs,
55871c689dcSHans Verkuil struct video_device *vdev, bool set)
55971c689dcSHans Verkuil {
56071c689dcSHans Verkuil struct v4l2_ctrl_helper helper[4];
56171c689dcSHans Verkuil struct v4l2_ctrl_helper *helpers = helper;
56271c689dcSHans Verkuil unsigned int i, j;
56371c689dcSHans Verkuil int ret;
56471c689dcSHans Verkuil
56571c689dcSHans Verkuil cs->error_idx = cs->count;
56671c689dcSHans Verkuil
56771c689dcSHans Verkuil /* Default value cannot be changed */
56871c689dcSHans Verkuil if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) {
56971c689dcSHans Verkuil dprintk(vdev, "%s: cannot change default value\n",
57071c689dcSHans Verkuil video_device_node_name(vdev));
57171c689dcSHans Verkuil return -EINVAL;
57271c689dcSHans Verkuil }
57371c689dcSHans Verkuil
57471c689dcSHans Verkuil cs->which = V4L2_CTRL_ID2WHICH(cs->which);
57571c689dcSHans Verkuil
57671c689dcSHans Verkuil if (!hdl) {
57771c689dcSHans Verkuil dprintk(vdev, "%s: invalid null control handler\n",
57871c689dcSHans Verkuil video_device_node_name(vdev));
57971c689dcSHans Verkuil return -EINVAL;
58071c689dcSHans Verkuil }
58171c689dcSHans Verkuil
58271c689dcSHans Verkuil if (cs->count == 0)
58371c689dcSHans Verkuil return class_check(hdl, cs->which);
58471c689dcSHans Verkuil
58571c689dcSHans Verkuil if (cs->count > ARRAY_SIZE(helper)) {
58671c689dcSHans Verkuil helpers = kvmalloc_array(cs->count, sizeof(helper[0]),
58771c689dcSHans Verkuil GFP_KERNEL);
58871c689dcSHans Verkuil if (!helpers)
58971c689dcSHans Verkuil return -ENOMEM;
59071c689dcSHans Verkuil }
59171c689dcSHans Verkuil ret = prepare_ext_ctrls(hdl, cs, helpers, vdev, false);
59271c689dcSHans Verkuil if (!ret)
59371c689dcSHans Verkuil ret = validate_ctrls(cs, helpers, vdev, set);
59471c689dcSHans Verkuil if (ret && set)
59571c689dcSHans Verkuil cs->error_idx = cs->count;
59671c689dcSHans Verkuil for (i = 0; !ret && i < cs->count; i++) {
59771c689dcSHans Verkuil struct v4l2_ctrl *master;
59871c689dcSHans Verkuil u32 idx = i;
59971c689dcSHans Verkuil
60071c689dcSHans Verkuil if (!helpers[i].mref)
60171c689dcSHans Verkuil continue;
60271c689dcSHans Verkuil
60371c689dcSHans Verkuil cs->error_idx = i;
60471c689dcSHans Verkuil master = helpers[i].mref->ctrl;
60571c689dcSHans Verkuil v4l2_ctrl_lock(master);
60671c689dcSHans Verkuil
60771c689dcSHans Verkuil /* Reset the 'is_new' flags of the cluster */
60871c689dcSHans Verkuil for (j = 0; j < master->ncontrols; j++)
60971c689dcSHans Verkuil if (master->cluster[j])
61071c689dcSHans Verkuil master->cluster[j]->is_new = 0;
61171c689dcSHans Verkuil
61271c689dcSHans Verkuil /*
61371c689dcSHans Verkuil * For volatile autoclusters that are currently in auto mode
61471c689dcSHans Verkuil * we need to discover if it will be set to manual mode.
61571c689dcSHans Verkuil * If so, then we have to copy the current volatile values
61671c689dcSHans Verkuil * first since those will become the new manual values (which
61771c689dcSHans Verkuil * may be overwritten by explicit new values from this set
61871c689dcSHans Verkuil * of controls).
61971c689dcSHans Verkuil */
62071c689dcSHans Verkuil if (master->is_auto && master->has_volatiles &&
62171c689dcSHans Verkuil !is_cur_manual(master)) {
62271c689dcSHans Verkuil /* Pick an initial non-manual value */
62371c689dcSHans Verkuil s32 new_auto_val = master->manual_mode_value + 1;
62471c689dcSHans Verkuil u32 tmp_idx = idx;
62571c689dcSHans Verkuil
62671c689dcSHans Verkuil do {
62771c689dcSHans Verkuil /*
62871c689dcSHans Verkuil * Check if the auto control is part of the
62971c689dcSHans Verkuil * list, and remember the new value.
63071c689dcSHans Verkuil */
63171c689dcSHans Verkuil if (helpers[tmp_idx].ref->ctrl == master)
63271c689dcSHans Verkuil new_auto_val = cs->controls[tmp_idx].value;
63371c689dcSHans Verkuil tmp_idx = helpers[tmp_idx].next;
63471c689dcSHans Verkuil } while (tmp_idx);
63571c689dcSHans Verkuil /*
63671c689dcSHans Verkuil * If the new value == the manual value, then copy
63771c689dcSHans Verkuil * the current volatile values.
63871c689dcSHans Verkuil */
63971c689dcSHans Verkuil if (new_auto_val == master->manual_mode_value)
64071c689dcSHans Verkuil update_from_auto_cluster(master);
64171c689dcSHans Verkuil }
64271c689dcSHans Verkuil
64371c689dcSHans Verkuil /*
64471c689dcSHans Verkuil * Copy the new caller-supplied control values.
64571c689dcSHans Verkuil * user_to_new() sets 'is_new' to 1.
64671c689dcSHans Verkuil */
64771c689dcSHans Verkuil do {
64871c689dcSHans Verkuil struct v4l2_ctrl *ctrl = helpers[idx].ref->ctrl;
64971c689dcSHans Verkuil
65071c689dcSHans Verkuil ret = user_to_new(cs->controls + idx, ctrl);
65171c689dcSHans Verkuil if (!ret && ctrl->is_ptr) {
65271c689dcSHans Verkuil ret = validate_new(ctrl, ctrl->p_new);
65371c689dcSHans Verkuil if (ret)
65471c689dcSHans Verkuil dprintk(vdev,
65571c689dcSHans Verkuil "failed to validate control %s (%d)\n",
65671c689dcSHans Verkuil v4l2_ctrl_get_name(ctrl->id), ret);
65771c689dcSHans Verkuil }
65871c689dcSHans Verkuil idx = helpers[idx].next;
65971c689dcSHans Verkuil } while (!ret && idx);
66071c689dcSHans Verkuil
66171c689dcSHans Verkuil if (!ret)
66271c689dcSHans Verkuil ret = try_or_set_cluster(fh, master,
66371c689dcSHans Verkuil !hdl->req_obj.req && set, 0);
66471c689dcSHans Verkuil if (!ret && hdl->req_obj.req && set) {
66571c689dcSHans Verkuil for (j = 0; j < master->ncontrols; j++) {
66671c689dcSHans Verkuil struct v4l2_ctrl_ref *ref =
66771c689dcSHans Verkuil find_ref(hdl, master->cluster[j]->id);
66871c689dcSHans Verkuil
66971c689dcSHans Verkuil new_to_req(ref);
67071c689dcSHans Verkuil }
67171c689dcSHans Verkuil }
67271c689dcSHans Verkuil
67371c689dcSHans Verkuil /* Copy the new values back to userspace. */
67471c689dcSHans Verkuil if (!ret) {
67571c689dcSHans Verkuil idx = i;
67671c689dcSHans Verkuil do {
67771c689dcSHans Verkuil ret = new_to_user(cs->controls + idx,
67871c689dcSHans Verkuil helpers[idx].ref->ctrl);
67971c689dcSHans Verkuil idx = helpers[idx].next;
68071c689dcSHans Verkuil } while (!ret && idx);
68171c689dcSHans Verkuil }
68271c689dcSHans Verkuil v4l2_ctrl_unlock(master);
68371c689dcSHans Verkuil }
68471c689dcSHans Verkuil
68571c689dcSHans Verkuil if (cs->count > ARRAY_SIZE(helper))
68671c689dcSHans Verkuil kvfree(helpers);
68771c689dcSHans Verkuil return ret;
68871c689dcSHans Verkuil }
68971c689dcSHans Verkuil
try_set_ext_ctrls(struct v4l2_fh * fh,struct v4l2_ctrl_handler * hdl,struct video_device * vdev,struct media_device * mdev,struct v4l2_ext_controls * cs,bool set)69071c689dcSHans Verkuil static int try_set_ext_ctrls(struct v4l2_fh *fh,
69171c689dcSHans Verkuil struct v4l2_ctrl_handler *hdl,
69271c689dcSHans Verkuil struct video_device *vdev,
69371c689dcSHans Verkuil struct media_device *mdev,
69471c689dcSHans Verkuil struct v4l2_ext_controls *cs, bool set)
69571c689dcSHans Verkuil {
69671c689dcSHans Verkuil int ret;
69771c689dcSHans Verkuil
69871c689dcSHans Verkuil if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
69971c689dcSHans Verkuil return try_set_ext_ctrls_request(fh, hdl, vdev, mdev, cs, set);
70071c689dcSHans Verkuil
70171c689dcSHans Verkuil ret = try_set_ext_ctrls_common(fh, hdl, cs, vdev, set);
70271c689dcSHans Verkuil if (ret)
70371c689dcSHans Verkuil dprintk(vdev,
70471c689dcSHans Verkuil "%s: try_set_ext_ctrls_common failed (%d)\n",
70571c689dcSHans Verkuil video_device_node_name(vdev), ret);
70671c689dcSHans Verkuil
70771c689dcSHans Verkuil return ret;
70871c689dcSHans Verkuil }
70971c689dcSHans Verkuil
v4l2_try_ext_ctrls(struct v4l2_ctrl_handler * hdl,struct video_device * vdev,struct media_device * mdev,struct v4l2_ext_controls * cs)71071c689dcSHans Verkuil int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl,
71171c689dcSHans Verkuil struct video_device *vdev,
71271c689dcSHans Verkuil struct media_device *mdev,
71371c689dcSHans Verkuil struct v4l2_ext_controls *cs)
71471c689dcSHans Verkuil {
71571c689dcSHans Verkuil return try_set_ext_ctrls(NULL, hdl, vdev, mdev, cs, false);
71671c689dcSHans Verkuil }
71771c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_try_ext_ctrls);
71871c689dcSHans Verkuil
v4l2_s_ext_ctrls(struct v4l2_fh * fh,struct v4l2_ctrl_handler * hdl,struct video_device * vdev,struct media_device * mdev,struct v4l2_ext_controls * cs)71971c689dcSHans Verkuil int v4l2_s_ext_ctrls(struct v4l2_fh *fh,
72071c689dcSHans Verkuil struct v4l2_ctrl_handler *hdl,
72171c689dcSHans Verkuil struct video_device *vdev,
72271c689dcSHans Verkuil struct media_device *mdev,
72371c689dcSHans Verkuil struct v4l2_ext_controls *cs)
72471c689dcSHans Verkuil {
72571c689dcSHans Verkuil return try_set_ext_ctrls(fh, hdl, vdev, mdev, cs, true);
72671c689dcSHans Verkuil }
72771c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_s_ext_ctrls);
72871c689dcSHans Verkuil
72971c689dcSHans Verkuil /*
73071c689dcSHans Verkuil * VIDIOC_G/S_CTRL implementation
73171c689dcSHans Verkuil */
73271c689dcSHans Verkuil
73371c689dcSHans Verkuil /* Helper function to get a single control */
get_ctrl(struct v4l2_ctrl * ctrl,struct v4l2_ext_control * c)73471c689dcSHans Verkuil static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
73571c689dcSHans Verkuil {
73671c689dcSHans Verkuil struct v4l2_ctrl *master = ctrl->cluster[0];
73771c689dcSHans Verkuil int ret = 0;
73871c689dcSHans Verkuil int i;
73971c689dcSHans Verkuil
74071c689dcSHans Verkuil /* Compound controls are not supported. The new_to_user() and
74171c689dcSHans Verkuil * cur_to_user() calls below would need to be modified not to access
74271c689dcSHans Verkuil * userspace memory when called from get_ctrl().
74371c689dcSHans Verkuil */
74471c689dcSHans Verkuil if (!ctrl->is_int && ctrl->type != V4L2_CTRL_TYPE_INTEGER64)
74571c689dcSHans Verkuil return -EINVAL;
74671c689dcSHans Verkuil
74771c689dcSHans Verkuil if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
74871c689dcSHans Verkuil return -EACCES;
74971c689dcSHans Verkuil
75071c689dcSHans Verkuil v4l2_ctrl_lock(master);
75171c689dcSHans Verkuil /* g_volatile_ctrl will update the current control values */
75271c689dcSHans Verkuil if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
75371c689dcSHans Verkuil for (i = 0; i < master->ncontrols; i++)
75471c689dcSHans Verkuil cur_to_new(master->cluster[i]);
75571c689dcSHans Verkuil ret = call_op(master, g_volatile_ctrl);
756*32adcb83SMauro Carvalho Chehab if (!ret)
757*32adcb83SMauro Carvalho Chehab ret = new_to_user(c, ctrl);
75871c689dcSHans Verkuil } else {
759*32adcb83SMauro Carvalho Chehab ret = cur_to_user(c, ctrl);
76071c689dcSHans Verkuil }
76171c689dcSHans Verkuil v4l2_ctrl_unlock(master);
76271c689dcSHans Verkuil return ret;
76371c689dcSHans Verkuil }
76471c689dcSHans Verkuil
v4l2_g_ctrl(struct v4l2_ctrl_handler * hdl,struct v4l2_control * control)76571c689dcSHans Verkuil int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
76671c689dcSHans Verkuil {
76771c689dcSHans Verkuil struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
76871c689dcSHans Verkuil struct v4l2_ext_control c;
76971c689dcSHans Verkuil int ret;
77071c689dcSHans Verkuil
77171c689dcSHans Verkuil if (!ctrl || !ctrl->is_int)
77271c689dcSHans Verkuil return -EINVAL;
77371c689dcSHans Verkuil ret = get_ctrl(ctrl, &c);
774*32adcb83SMauro Carvalho Chehab
775*32adcb83SMauro Carvalho Chehab if (!ret)
77671c689dcSHans Verkuil control->value = c.value;
777*32adcb83SMauro Carvalho Chehab
77871c689dcSHans Verkuil return ret;
77971c689dcSHans Verkuil }
78071c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_g_ctrl);
78171c689dcSHans Verkuil
78271c689dcSHans Verkuil /* Helper function for VIDIOC_S_CTRL compatibility */
set_ctrl(struct v4l2_fh * fh,struct v4l2_ctrl * ctrl,u32 ch_flags)78371c689dcSHans Verkuil static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
78471c689dcSHans Verkuil {
78571c689dcSHans Verkuil struct v4l2_ctrl *master = ctrl->cluster[0];
78671c689dcSHans Verkuil int ret;
78771c689dcSHans Verkuil int i;
78871c689dcSHans Verkuil
78971c689dcSHans Verkuil /* Reset the 'is_new' flags of the cluster */
79071c689dcSHans Verkuil for (i = 0; i < master->ncontrols; i++)
79171c689dcSHans Verkuil if (master->cluster[i])
79271c689dcSHans Verkuil master->cluster[i]->is_new = 0;
79371c689dcSHans Verkuil
79471c689dcSHans Verkuil ret = validate_new(ctrl, ctrl->p_new);
79571c689dcSHans Verkuil if (ret)
79671c689dcSHans Verkuil return ret;
79771c689dcSHans Verkuil
79871c689dcSHans Verkuil /*
79971c689dcSHans Verkuil * For autoclusters with volatiles that are switched from auto to
80071c689dcSHans Verkuil * manual mode we have to update the current volatile values since
80171c689dcSHans Verkuil * those will become the initial manual values after such a switch.
80271c689dcSHans Verkuil */
80371c689dcSHans Verkuil if (master->is_auto && master->has_volatiles && ctrl == master &&
80471c689dcSHans Verkuil !is_cur_manual(master) && ctrl->val == master->manual_mode_value)
80571c689dcSHans Verkuil update_from_auto_cluster(master);
80671c689dcSHans Verkuil
80771c689dcSHans Verkuil ctrl->is_new = 1;
80871c689dcSHans Verkuil return try_or_set_cluster(fh, master, true, ch_flags);
80971c689dcSHans Verkuil }
81071c689dcSHans Verkuil
81171c689dcSHans Verkuil /* Helper function for VIDIOC_S_CTRL compatibility */
set_ctrl_lock(struct v4l2_fh * fh,struct v4l2_ctrl * ctrl,struct v4l2_ext_control * c)81271c689dcSHans Verkuil static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
81371c689dcSHans Verkuil struct v4l2_ext_control *c)
81471c689dcSHans Verkuil {
81571c689dcSHans Verkuil int ret;
81671c689dcSHans Verkuil
81771c689dcSHans Verkuil v4l2_ctrl_lock(ctrl);
818*32adcb83SMauro Carvalho Chehab ret = user_to_new(c, ctrl);
819*32adcb83SMauro Carvalho Chehab if (!ret)
82071c689dcSHans Verkuil ret = set_ctrl(fh, ctrl, 0);
82171c689dcSHans Verkuil if (!ret)
822*32adcb83SMauro Carvalho Chehab ret = cur_to_user(c, ctrl);
82371c689dcSHans Verkuil v4l2_ctrl_unlock(ctrl);
82471c689dcSHans Verkuil return ret;
82571c689dcSHans Verkuil }
82671c689dcSHans Verkuil
v4l2_s_ctrl(struct v4l2_fh * fh,struct v4l2_ctrl_handler * hdl,struct v4l2_control * control)82771c689dcSHans Verkuil int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
82871c689dcSHans Verkuil struct v4l2_control *control)
82971c689dcSHans Verkuil {
83071c689dcSHans Verkuil struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
83171c689dcSHans Verkuil struct v4l2_ext_control c = { control->id };
83271c689dcSHans Verkuil int ret;
83371c689dcSHans Verkuil
83471c689dcSHans Verkuil if (!ctrl || !ctrl->is_int)
83571c689dcSHans Verkuil return -EINVAL;
83671c689dcSHans Verkuil
83771c689dcSHans Verkuil if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
83871c689dcSHans Verkuil return -EACCES;
83971c689dcSHans Verkuil
84071c689dcSHans Verkuil c.value = control->value;
84171c689dcSHans Verkuil ret = set_ctrl_lock(fh, ctrl, &c);
84271c689dcSHans Verkuil control->value = c.value;
84371c689dcSHans Verkuil return ret;
84471c689dcSHans Verkuil }
84571c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_s_ctrl);
84671c689dcSHans Verkuil
84771c689dcSHans Verkuil /*
84871c689dcSHans Verkuil * Helper functions for drivers to get/set controls.
84971c689dcSHans Verkuil */
85071c689dcSHans Verkuil
v4l2_ctrl_g_ctrl(struct v4l2_ctrl * ctrl)85171c689dcSHans Verkuil s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
85271c689dcSHans Verkuil {
85371c689dcSHans Verkuil struct v4l2_ext_control c;
85471c689dcSHans Verkuil
85571c689dcSHans Verkuil /* It's a driver bug if this happens. */
85671c689dcSHans Verkuil if (WARN_ON(!ctrl->is_int))
85771c689dcSHans Verkuil return 0;
85871c689dcSHans Verkuil c.value = 0;
85971c689dcSHans Verkuil get_ctrl(ctrl, &c);
86071c689dcSHans Verkuil return c.value;
86171c689dcSHans Verkuil }
86271c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
86371c689dcSHans Verkuil
v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl * ctrl)86471c689dcSHans Verkuil s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl)
86571c689dcSHans Verkuil {
86671c689dcSHans Verkuil struct v4l2_ext_control c;
86771c689dcSHans Verkuil
86871c689dcSHans Verkuil /* It's a driver bug if this happens. */
86971c689dcSHans Verkuil if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
87071c689dcSHans Verkuil return 0;
87171c689dcSHans Verkuil c.value64 = 0;
87271c689dcSHans Verkuil get_ctrl(ctrl, &c);
87371c689dcSHans Verkuil return c.value64;
87471c689dcSHans Verkuil }
87571c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_g_ctrl_int64);
87671c689dcSHans Verkuil
__v4l2_ctrl_s_ctrl(struct v4l2_ctrl * ctrl,s32 val)87771c689dcSHans Verkuil int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
87871c689dcSHans Verkuil {
87971c689dcSHans Verkuil lockdep_assert_held(ctrl->handler->lock);
88071c689dcSHans Verkuil
88171c689dcSHans Verkuil /* It's a driver bug if this happens. */
88271c689dcSHans Verkuil if (WARN_ON(!ctrl->is_int))
88371c689dcSHans Verkuil return -EINVAL;
88471c689dcSHans Verkuil ctrl->val = val;
88571c689dcSHans Verkuil return set_ctrl(NULL, ctrl, 0);
88671c689dcSHans Verkuil }
88771c689dcSHans Verkuil EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
88871c689dcSHans Verkuil
__v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl * ctrl,s64 val)88971c689dcSHans Verkuil int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
89071c689dcSHans Verkuil {
89171c689dcSHans Verkuil lockdep_assert_held(ctrl->handler->lock);
89271c689dcSHans Verkuil
89371c689dcSHans Verkuil /* It's a driver bug if this happens. */
89471c689dcSHans Verkuil if (WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64))
89571c689dcSHans Verkuil return -EINVAL;
89671c689dcSHans Verkuil *ctrl->p_new.p_s64 = val;
89771c689dcSHans Verkuil return set_ctrl(NULL, ctrl, 0);
89871c689dcSHans Verkuil }
89971c689dcSHans Verkuil EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
90071c689dcSHans Verkuil
__v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl * ctrl,const char * s)90171c689dcSHans Verkuil int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
90271c689dcSHans Verkuil {
90371c689dcSHans Verkuil lockdep_assert_held(ctrl->handler->lock);
90471c689dcSHans Verkuil
90571c689dcSHans Verkuil /* It's a driver bug if this happens. */
90671c689dcSHans Verkuil if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING))
90771c689dcSHans Verkuil return -EINVAL;
90871c689dcSHans Verkuil strscpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
90971c689dcSHans Verkuil return set_ctrl(NULL, ctrl, 0);
91071c689dcSHans Verkuil }
91171c689dcSHans Verkuil EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
91271c689dcSHans Verkuil
__v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl * ctrl,enum v4l2_ctrl_type type,const void * p)91371c689dcSHans Verkuil int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
91471c689dcSHans Verkuil enum v4l2_ctrl_type type, const void *p)
91571c689dcSHans Verkuil {
91671c689dcSHans Verkuil lockdep_assert_held(ctrl->handler->lock);
91771c689dcSHans Verkuil
91871c689dcSHans Verkuil /* It's a driver bug if this happens. */
91971c689dcSHans Verkuil if (WARN_ON(ctrl->type != type))
92071c689dcSHans Verkuil return -EINVAL;
921fb582cbaSHans Verkuil /* Setting dynamic arrays is not (yet?) supported. */
922fb582cbaSHans Verkuil if (WARN_ON(ctrl->is_dyn_array))
923fb582cbaSHans Verkuil return -EINVAL;
92471c689dcSHans Verkuil memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size);
92571c689dcSHans Verkuil return set_ctrl(NULL, ctrl, 0);
92671c689dcSHans Verkuil }
92771c689dcSHans Verkuil EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound);
92871c689dcSHans Verkuil
92971c689dcSHans Verkuil /*
93071c689dcSHans Verkuil * Modify the range of a control.
93171c689dcSHans Verkuil */
__v4l2_ctrl_modify_range(struct v4l2_ctrl * ctrl,s64 min,s64 max,u64 step,s64 def)93271c689dcSHans Verkuil int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
93371c689dcSHans Verkuil s64 min, s64 max, u64 step, s64 def)
93471c689dcSHans Verkuil {
93571c689dcSHans Verkuil bool value_changed;
93671c689dcSHans Verkuil bool range_changed = false;
93771c689dcSHans Verkuil int ret;
93871c689dcSHans Verkuil
93971c689dcSHans Verkuil lockdep_assert_held(ctrl->handler->lock);
94071c689dcSHans Verkuil
94171c689dcSHans Verkuil switch (ctrl->type) {
94271c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER:
94371c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER64:
94471c689dcSHans Verkuil case V4L2_CTRL_TYPE_BOOLEAN:
94571c689dcSHans Verkuil case V4L2_CTRL_TYPE_MENU:
94671c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER_MENU:
94771c689dcSHans Verkuil case V4L2_CTRL_TYPE_BITMASK:
94871c689dcSHans Verkuil case V4L2_CTRL_TYPE_U8:
94971c689dcSHans Verkuil case V4L2_CTRL_TYPE_U16:
95071c689dcSHans Verkuil case V4L2_CTRL_TYPE_U32:
95171c689dcSHans Verkuil if (ctrl->is_array)
95271c689dcSHans Verkuil return -EINVAL;
95371c689dcSHans Verkuil ret = check_range(ctrl->type, min, max, step, def);
95471c689dcSHans Verkuil if (ret)
95571c689dcSHans Verkuil return ret;
95671c689dcSHans Verkuil break;
95771c689dcSHans Verkuil default:
95871c689dcSHans Verkuil return -EINVAL;
95971c689dcSHans Verkuil }
96071c689dcSHans Verkuil if (ctrl->minimum != min || ctrl->maximum != max ||
96171c689dcSHans Verkuil ctrl->step != step || ctrl->default_value != def) {
96271c689dcSHans Verkuil range_changed = true;
96371c689dcSHans Verkuil ctrl->minimum = min;
96471c689dcSHans Verkuil ctrl->maximum = max;
96571c689dcSHans Verkuil ctrl->step = step;
96671c689dcSHans Verkuil ctrl->default_value = def;
96771c689dcSHans Verkuil }
96871c689dcSHans Verkuil cur_to_new(ctrl);
96971c689dcSHans Verkuil if (validate_new(ctrl, ctrl->p_new)) {
97071c689dcSHans Verkuil if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
97171c689dcSHans Verkuil *ctrl->p_new.p_s64 = def;
97271c689dcSHans Verkuil else
97371c689dcSHans Verkuil *ctrl->p_new.p_s32 = def;
97471c689dcSHans Verkuil }
97571c689dcSHans Verkuil
97671c689dcSHans Verkuil if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
97771c689dcSHans Verkuil value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
97871c689dcSHans Verkuil else
97971c689dcSHans Verkuil value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
98071c689dcSHans Verkuil if (value_changed)
98171c689dcSHans Verkuil ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
98271c689dcSHans Verkuil else if (range_changed)
98371c689dcSHans Verkuil send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
98471c689dcSHans Verkuil return ret;
98571c689dcSHans Verkuil }
98671c689dcSHans Verkuil EXPORT_SYMBOL(__v4l2_ctrl_modify_range);
98771c689dcSHans Verkuil
__v4l2_ctrl_modify_dimensions(struct v4l2_ctrl * ctrl,u32 dims[V4L2_CTRL_MAX_DIMS])98809752745SHans Verkuil int __v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl,
98909752745SHans Verkuil u32 dims[V4L2_CTRL_MAX_DIMS])
99009752745SHans Verkuil {
99109752745SHans Verkuil unsigned int elems = 1;
99209752745SHans Verkuil unsigned int i;
99309752745SHans Verkuil void *p_array;
99409752745SHans Verkuil
99509752745SHans Verkuil lockdep_assert_held(ctrl->handler->lock);
99609752745SHans Verkuil
99709752745SHans Verkuil if (!ctrl->is_array || ctrl->is_dyn_array)
99809752745SHans Verkuil return -EINVAL;
99909752745SHans Verkuil
100009752745SHans Verkuil for (i = 0; i < ctrl->nr_of_dims; i++)
100109752745SHans Verkuil elems *= dims[i];
100209752745SHans Verkuil if (elems == 0)
100309752745SHans Verkuil return -EINVAL;
100409752745SHans Verkuil p_array = kvzalloc(2 * elems * ctrl->elem_size, GFP_KERNEL);
100509752745SHans Verkuil if (!p_array)
100609752745SHans Verkuil return -ENOMEM;
100709752745SHans Verkuil kvfree(ctrl->p_array);
100809752745SHans Verkuil ctrl->p_array_alloc_elems = elems;
100909752745SHans Verkuil ctrl->elems = elems;
101009752745SHans Verkuil ctrl->new_elems = elems;
101109752745SHans Verkuil ctrl->p_array = p_array;
101209752745SHans Verkuil ctrl->p_new.p = p_array;
101309752745SHans Verkuil ctrl->p_cur.p = p_array + elems * ctrl->elem_size;
101409752745SHans Verkuil for (i = 0; i < ctrl->nr_of_dims; i++)
101509752745SHans Verkuil ctrl->dims[i] = dims[i];
1016cd75981eSHans Verkuil ctrl->type_ops->init(ctrl, 0, ctrl->p_cur);
101709752745SHans Verkuil cur_to_new(ctrl);
101843cc0ec3SHans Verkuil send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_VALUE |
101943cc0ec3SHans Verkuil V4L2_EVENT_CTRL_CH_DIMENSIONS);
102009752745SHans Verkuil return 0;
102109752745SHans Verkuil }
102209752745SHans Verkuil EXPORT_SYMBOL(__v4l2_ctrl_modify_dimensions);
102309752745SHans Verkuil
102471c689dcSHans Verkuil /* Implement VIDIOC_QUERY_EXT_CTRL */
v4l2_query_ext_ctrl(struct v4l2_ctrl_handler * hdl,struct v4l2_query_ext_ctrl * qc)102571c689dcSHans Verkuil int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc)
102671c689dcSHans Verkuil {
102771c689dcSHans Verkuil const unsigned int next_flags = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
102871c689dcSHans Verkuil u32 id = qc->id & V4L2_CTRL_ID_MASK;
102971c689dcSHans Verkuil struct v4l2_ctrl_ref *ref;
103071c689dcSHans Verkuil struct v4l2_ctrl *ctrl;
103171c689dcSHans Verkuil
103271c689dcSHans Verkuil if (!hdl)
103371c689dcSHans Verkuil return -EINVAL;
103471c689dcSHans Verkuil
103571c689dcSHans Verkuil mutex_lock(hdl->lock);
103671c689dcSHans Verkuil
103771c689dcSHans Verkuil /* Try to find it */
103871c689dcSHans Verkuil ref = find_ref(hdl, id);
103971c689dcSHans Verkuil
104071c689dcSHans Verkuil if ((qc->id & next_flags) && !list_empty(&hdl->ctrl_refs)) {
104171c689dcSHans Verkuil bool is_compound;
104271c689dcSHans Verkuil /* Match any control that is not hidden */
104371c689dcSHans Verkuil unsigned int mask = 1;
104471c689dcSHans Verkuil bool match = false;
104571c689dcSHans Verkuil
104671c689dcSHans Verkuil if ((qc->id & next_flags) == V4L2_CTRL_FLAG_NEXT_COMPOUND) {
104771c689dcSHans Verkuil /* Match any hidden control */
104871c689dcSHans Verkuil match = true;
104971c689dcSHans Verkuil } else if ((qc->id & next_flags) == next_flags) {
105071c689dcSHans Verkuil /* Match any control, compound or not */
105171c689dcSHans Verkuil mask = 0;
105271c689dcSHans Verkuil }
105371c689dcSHans Verkuil
105471c689dcSHans Verkuil /* Find the next control with ID > qc->id */
105571c689dcSHans Verkuil
105671c689dcSHans Verkuil /* Did we reach the end of the control list? */
105771c689dcSHans Verkuil if (id >= node2id(hdl->ctrl_refs.prev)) {
105871c689dcSHans Verkuil ref = NULL; /* Yes, so there is no next control */
105971c689dcSHans Verkuil } else if (ref) {
106071c689dcSHans Verkuil /*
106171c689dcSHans Verkuil * We found a control with the given ID, so just get
106271c689dcSHans Verkuil * the next valid one in the list.
106371c689dcSHans Verkuil */
106471c689dcSHans Verkuil list_for_each_entry_continue(ref, &hdl->ctrl_refs, node) {
106571c689dcSHans Verkuil is_compound = ref->ctrl->is_array ||
106671c689dcSHans Verkuil ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
106771c689dcSHans Verkuil if (id < ref->ctrl->id &&
106871c689dcSHans Verkuil (is_compound & mask) == match)
106971c689dcSHans Verkuil break;
107071c689dcSHans Verkuil }
107171c689dcSHans Verkuil if (&ref->node == &hdl->ctrl_refs)
107271c689dcSHans Verkuil ref = NULL;
107371c689dcSHans Verkuil } else {
107471c689dcSHans Verkuil /*
107571c689dcSHans Verkuil * No control with the given ID exists, so start
107671c689dcSHans Verkuil * searching for the next largest ID. We know there
107771c689dcSHans Verkuil * is one, otherwise the first 'if' above would have
107871c689dcSHans Verkuil * been true.
107971c689dcSHans Verkuil */
108071c689dcSHans Verkuil list_for_each_entry(ref, &hdl->ctrl_refs, node) {
108171c689dcSHans Verkuil is_compound = ref->ctrl->is_array ||
108271c689dcSHans Verkuil ref->ctrl->type >= V4L2_CTRL_COMPOUND_TYPES;
108371c689dcSHans Verkuil if (id < ref->ctrl->id &&
108471c689dcSHans Verkuil (is_compound & mask) == match)
108571c689dcSHans Verkuil break;
108671c689dcSHans Verkuil }
108771c689dcSHans Verkuil if (&ref->node == &hdl->ctrl_refs)
108871c689dcSHans Verkuil ref = NULL;
108971c689dcSHans Verkuil }
109071c689dcSHans Verkuil }
109171c689dcSHans Verkuil mutex_unlock(hdl->lock);
109271c689dcSHans Verkuil
109371c689dcSHans Verkuil if (!ref)
109471c689dcSHans Verkuil return -EINVAL;
109571c689dcSHans Verkuil
109671c689dcSHans Verkuil ctrl = ref->ctrl;
109771c689dcSHans Verkuil memset(qc, 0, sizeof(*qc));
109871c689dcSHans Verkuil if (id >= V4L2_CID_PRIVATE_BASE)
109971c689dcSHans Verkuil qc->id = id;
110071c689dcSHans Verkuil else
110171c689dcSHans Verkuil qc->id = ctrl->id;
110271c689dcSHans Verkuil strscpy(qc->name, ctrl->name, sizeof(qc->name));
110371c689dcSHans Verkuil qc->flags = user_flags(ctrl);
110471c689dcSHans Verkuil qc->type = ctrl->type;
110571c689dcSHans Verkuil qc->elem_size = ctrl->elem_size;
110671c689dcSHans Verkuil qc->elems = ctrl->elems;
110771c689dcSHans Verkuil qc->nr_of_dims = ctrl->nr_of_dims;
110871c689dcSHans Verkuil memcpy(qc->dims, ctrl->dims, qc->nr_of_dims * sizeof(qc->dims[0]));
110971c689dcSHans Verkuil qc->minimum = ctrl->minimum;
111071c689dcSHans Verkuil qc->maximum = ctrl->maximum;
111171c689dcSHans Verkuil qc->default_value = ctrl->default_value;
111271c689dcSHans Verkuil if (ctrl->type == V4L2_CTRL_TYPE_MENU ||
111371c689dcSHans Verkuil ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
111471c689dcSHans Verkuil qc->step = 1;
111571c689dcSHans Verkuil else
111671c689dcSHans Verkuil qc->step = ctrl->step;
111771c689dcSHans Verkuil return 0;
111871c689dcSHans Verkuil }
111971c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_query_ext_ctrl);
112071c689dcSHans Verkuil
112171c689dcSHans Verkuil /* Implement VIDIOC_QUERYCTRL */
v4l2_queryctrl(struct v4l2_ctrl_handler * hdl,struct v4l2_queryctrl * qc)112271c689dcSHans Verkuil int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
112371c689dcSHans Verkuil {
112471c689dcSHans Verkuil struct v4l2_query_ext_ctrl qec = { qc->id };
112571c689dcSHans Verkuil int rc;
112671c689dcSHans Verkuil
112771c689dcSHans Verkuil rc = v4l2_query_ext_ctrl(hdl, &qec);
112871c689dcSHans Verkuil if (rc)
112971c689dcSHans Verkuil return rc;
113071c689dcSHans Verkuil
113171c689dcSHans Verkuil qc->id = qec.id;
113271c689dcSHans Verkuil qc->type = qec.type;
113371c689dcSHans Verkuil qc->flags = qec.flags;
113471c689dcSHans Verkuil strscpy(qc->name, qec.name, sizeof(qc->name));
113571c689dcSHans Verkuil switch (qc->type) {
113671c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER:
113771c689dcSHans Verkuil case V4L2_CTRL_TYPE_BOOLEAN:
113871c689dcSHans Verkuil case V4L2_CTRL_TYPE_MENU:
113971c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER_MENU:
114071c689dcSHans Verkuil case V4L2_CTRL_TYPE_STRING:
114171c689dcSHans Verkuil case V4L2_CTRL_TYPE_BITMASK:
114271c689dcSHans Verkuil qc->minimum = qec.minimum;
114371c689dcSHans Verkuil qc->maximum = qec.maximum;
114471c689dcSHans Verkuil qc->step = qec.step;
114571c689dcSHans Verkuil qc->default_value = qec.default_value;
114671c689dcSHans Verkuil break;
114771c689dcSHans Verkuil default:
114871c689dcSHans Verkuil qc->minimum = 0;
114971c689dcSHans Verkuil qc->maximum = 0;
115071c689dcSHans Verkuil qc->step = 0;
115171c689dcSHans Verkuil qc->default_value = 0;
115271c689dcSHans Verkuil break;
115371c689dcSHans Verkuil }
115471c689dcSHans Verkuil return 0;
115571c689dcSHans Verkuil }
115671c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_queryctrl);
115771c689dcSHans Verkuil
115871c689dcSHans Verkuil /* Implement VIDIOC_QUERYMENU */
v4l2_querymenu(struct v4l2_ctrl_handler * hdl,struct v4l2_querymenu * qm)115971c689dcSHans Verkuil int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
116071c689dcSHans Verkuil {
116171c689dcSHans Verkuil struct v4l2_ctrl *ctrl;
116271c689dcSHans Verkuil u32 i = qm->index;
116371c689dcSHans Verkuil
116471c689dcSHans Verkuil ctrl = v4l2_ctrl_find(hdl, qm->id);
116571c689dcSHans Verkuil if (!ctrl)
116671c689dcSHans Verkuil return -EINVAL;
116771c689dcSHans Verkuil
116871c689dcSHans Verkuil qm->reserved = 0;
116971c689dcSHans Verkuil /* Sanity checks */
117071c689dcSHans Verkuil switch (ctrl->type) {
117171c689dcSHans Verkuil case V4L2_CTRL_TYPE_MENU:
117271c689dcSHans Verkuil if (!ctrl->qmenu)
117371c689dcSHans Verkuil return -EINVAL;
117471c689dcSHans Verkuil break;
117571c689dcSHans Verkuil case V4L2_CTRL_TYPE_INTEGER_MENU:
117671c689dcSHans Verkuil if (!ctrl->qmenu_int)
117771c689dcSHans Verkuil return -EINVAL;
117871c689dcSHans Verkuil break;
117971c689dcSHans Verkuil default:
118071c689dcSHans Verkuil return -EINVAL;
118171c689dcSHans Verkuil }
118271c689dcSHans Verkuil
118371c689dcSHans Verkuil if (i < ctrl->minimum || i > ctrl->maximum)
118471c689dcSHans Verkuil return -EINVAL;
118571c689dcSHans Verkuil
118671c689dcSHans Verkuil /* Use mask to see if this menu item should be skipped */
118771c689dcSHans Verkuil if (ctrl->menu_skip_mask & (1ULL << i))
118871c689dcSHans Verkuil return -EINVAL;
118971c689dcSHans Verkuil /* Empty menu items should also be skipped */
119071c689dcSHans Verkuil if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
119171c689dcSHans Verkuil if (!ctrl->qmenu[i] || ctrl->qmenu[i][0] == '\0')
119271c689dcSHans Verkuil return -EINVAL;
119371c689dcSHans Verkuil strscpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
119471c689dcSHans Verkuil } else {
119571c689dcSHans Verkuil qm->value = ctrl->qmenu_int[i];
119671c689dcSHans Verkuil }
119771c689dcSHans Verkuil return 0;
119871c689dcSHans Verkuil }
119971c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_querymenu);
120071c689dcSHans Verkuil
120171c689dcSHans Verkuil /*
120271c689dcSHans Verkuil * VIDIOC_LOG_STATUS helpers
120371c689dcSHans Verkuil */
120471c689dcSHans Verkuil
v4l2_ctrl_log_status(struct file * file,void * fh)120571c689dcSHans Verkuil int v4l2_ctrl_log_status(struct file *file, void *fh)
120671c689dcSHans Verkuil {
120771c689dcSHans Verkuil struct video_device *vfd = video_devdata(file);
120871c689dcSHans Verkuil struct v4l2_fh *vfh = file->private_data;
120971c689dcSHans Verkuil
121071c689dcSHans Verkuil if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev)
121171c689dcSHans Verkuil v4l2_ctrl_handler_log_status(vfh->ctrl_handler,
121271c689dcSHans Verkuil vfd->v4l2_dev->name);
121371c689dcSHans Verkuil return 0;
121471c689dcSHans Verkuil }
121571c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_log_status);
121671c689dcSHans Verkuil
v4l2_ctrl_subdev_log_status(struct v4l2_subdev * sd)121771c689dcSHans Verkuil int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd)
121871c689dcSHans Verkuil {
121971c689dcSHans Verkuil v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name);
122071c689dcSHans Verkuil return 0;
122171c689dcSHans Verkuil }
122271c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_subdev_log_status);
122371c689dcSHans Verkuil
122471c689dcSHans Verkuil /*
122571c689dcSHans Verkuil * VIDIOC_(UN)SUBSCRIBE_EVENT implementation
122671c689dcSHans Verkuil */
122771c689dcSHans Verkuil
v4l2_ctrl_add_event(struct v4l2_subscribed_event * sev,unsigned int elems)122871c689dcSHans Verkuil static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev,
122971c689dcSHans Verkuil unsigned int elems)
123071c689dcSHans Verkuil {
123171c689dcSHans Verkuil struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
123271c689dcSHans Verkuil
123371c689dcSHans Verkuil if (!ctrl)
123471c689dcSHans Verkuil return -EINVAL;
123571c689dcSHans Verkuil
123671c689dcSHans Verkuil v4l2_ctrl_lock(ctrl);
123771c689dcSHans Verkuil list_add_tail(&sev->node, &ctrl->ev_subs);
123871c689dcSHans Verkuil if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
123971c689dcSHans Verkuil (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL))
124071c689dcSHans Verkuil send_initial_event(sev->fh, ctrl);
124171c689dcSHans Verkuil v4l2_ctrl_unlock(ctrl);
124271c689dcSHans Verkuil return 0;
124371c689dcSHans Verkuil }
124471c689dcSHans Verkuil
v4l2_ctrl_del_event(struct v4l2_subscribed_event * sev)124571c689dcSHans Verkuil static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
124671c689dcSHans Verkuil {
124771c689dcSHans Verkuil struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
124871c689dcSHans Verkuil
124971c689dcSHans Verkuil if (!ctrl)
125071c689dcSHans Verkuil return;
125171c689dcSHans Verkuil
125271c689dcSHans Verkuil v4l2_ctrl_lock(ctrl);
125371c689dcSHans Verkuil list_del(&sev->node);
125471c689dcSHans Verkuil v4l2_ctrl_unlock(ctrl);
125571c689dcSHans Verkuil }
125671c689dcSHans Verkuil
v4l2_ctrl_replace(struct v4l2_event * old,const struct v4l2_event * new)125771c689dcSHans Verkuil void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
125871c689dcSHans Verkuil {
125971c689dcSHans Verkuil u32 old_changes = old->u.ctrl.changes;
126071c689dcSHans Verkuil
126171c689dcSHans Verkuil old->u.ctrl = new->u.ctrl;
126271c689dcSHans Verkuil old->u.ctrl.changes |= old_changes;
126371c689dcSHans Verkuil }
126471c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_replace);
126571c689dcSHans Verkuil
v4l2_ctrl_merge(const struct v4l2_event * old,struct v4l2_event * new)126671c689dcSHans Verkuil void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
126771c689dcSHans Verkuil {
126871c689dcSHans Verkuil new->u.ctrl.changes |= old->u.ctrl.changes;
126971c689dcSHans Verkuil }
127071c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_merge);
127171c689dcSHans Verkuil
127271c689dcSHans Verkuil const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
127371c689dcSHans Verkuil .add = v4l2_ctrl_add_event,
127471c689dcSHans Verkuil .del = v4l2_ctrl_del_event,
127571c689dcSHans Verkuil .replace = v4l2_ctrl_replace,
127671c689dcSHans Verkuil .merge = v4l2_ctrl_merge,
127771c689dcSHans Verkuil };
127871c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
127971c689dcSHans Verkuil
v4l2_ctrl_subscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)128071c689dcSHans Verkuil int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
128171c689dcSHans Verkuil const struct v4l2_event_subscription *sub)
128271c689dcSHans Verkuil {
128371c689dcSHans Verkuil if (sub->type == V4L2_EVENT_CTRL)
128471c689dcSHans Verkuil return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
128571c689dcSHans Verkuil return -EINVAL;
128671c689dcSHans Verkuil }
128771c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
128871c689dcSHans Verkuil
v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)128971c689dcSHans Verkuil int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
129071c689dcSHans Verkuil struct v4l2_event_subscription *sub)
129171c689dcSHans Verkuil {
129271c689dcSHans Verkuil if (!sd->ctrl_handler)
129371c689dcSHans Verkuil return -EINVAL;
129471c689dcSHans Verkuil return v4l2_ctrl_subscribe_event(fh, sub);
129571c689dcSHans Verkuil }
129671c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event);
129771c689dcSHans Verkuil
129871c689dcSHans Verkuil /*
129971c689dcSHans Verkuil * poll helper
130071c689dcSHans Verkuil */
v4l2_ctrl_poll(struct file * file,struct poll_table_struct * wait)130171c689dcSHans Verkuil __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait)
130271c689dcSHans Verkuil {
130371c689dcSHans Verkuil struct v4l2_fh *fh = file->private_data;
130471c689dcSHans Verkuil
130571c689dcSHans Verkuil poll_wait(file, &fh->wait, wait);
130671c689dcSHans Verkuil if (v4l2_event_pending(fh))
130771c689dcSHans Verkuil return EPOLLPRI;
130871c689dcSHans Verkuil return 0;
130971c689dcSHans Verkuil }
131071c689dcSHans Verkuil EXPORT_SYMBOL(v4l2_ctrl_poll);
1311