On 4 June 2018 at 08:46, Hans Verkuil <hverkuil@xxxxxxxxx> wrote: > From: Hans Verkuil <hans.verkuil@xxxxxxxxx> > > Integrate the request support. This adds the v4l2_ctrl_request_complete > and v4l2_ctrl_request_setup functions to complete a request and (as a > helper function) to apply a request to the hardware. > > It takes care of queuing requests and correctly chaining control values > in the request queue. > > Note that when a request is marked completed it will copy control values > to the internal request state. This can be optimized in the future since > this is sub-optimal when dealing with large compound and/or array controls. > > For the initial 'stateless codec' use-case the current implementation is > sufficient. > > Signed-off-by: Hans Verkuil <hans.verkuil@xxxxxxxxx> > --- > drivers/media/v4l2-core/v4l2-ctrls.c | 331 ++++++++++++++++++++++++++- > include/media/v4l2-ctrls.h | 51 +++++ > 2 files changed, 376 insertions(+), 6 deletions(-) > > diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c > index da4cc1485dc4..bd4818507486 100644 > --- a/drivers/media/v4l2-core/v4l2-ctrls.c > +++ b/drivers/media/v4l2-core/v4l2-ctrls.c > @@ -1647,6 +1647,13 @@ static int new_to_user(struct v4l2_ext_control *c, > return ptr_to_user(c, ctrl, ctrl->p_new); > } > > +/* Helper function: copy the request value back to the caller */ > +static int req_to_user(struct v4l2_ext_control *c, > + struct v4l2_ctrl_ref *ref) > +{ > + return ptr_to_user(c, ref->ctrl, ref->p_req); > +} > + > /* Helper function: copy the initial control value back to the caller */ > static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) > { > @@ -1766,6 +1773,26 @@ static void cur_to_new(struct v4l2_ctrl *ctrl) > ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new); > } > > +/* Copy the new value to the request value */ > +static void new_to_req(struct v4l2_ctrl_ref *ref) > +{ > + if (!ref) > + return; > + ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req); > + ref->req = ref; > +} > + > +/* Copy the request value to the new value */ > +static void req_to_new(struct v4l2_ctrl_ref *ref) > +{ > + if (!ref) > + return; > + if (ref->req) > + ptr_to_ptr(ref->ctrl, ref->req->p_req, ref->ctrl->p_new); > + else > + ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new); > +} > + > /* Return non-zero if one or more of the controls in the cluster has a new > value that differs from the current value. */ > static int cluster_changed(struct v4l2_ctrl *master) > @@ -1875,6 +1902,9 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, > lockdep_set_class_and_name(hdl->lock, key, name); > INIT_LIST_HEAD(&hdl->ctrls); > INIT_LIST_HEAD(&hdl->ctrl_refs); > + INIT_LIST_HEAD(&hdl->requests); > + INIT_LIST_HEAD(&hdl->requests_queued); > + hdl->request_is_queued = false; > hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; > hdl->buckets = kvmalloc_array(hdl->nr_of_buckets, > sizeof(hdl->buckets[0]), > @@ -1895,6 +1925,14 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) > if (hdl == NULL || hdl->buckets == NULL) > return; > > + if (!hdl->req_obj.req && !list_empty(&hdl->requests)) { > + struct v4l2_ctrl_handler *req, *next_req; > + > + list_for_each_entry_safe(req, next_req, &hdl->requests, requests) { > + media_request_object_unbind(&req->req_obj); > + media_request_object_put(&req->req_obj); > + } > + } > mutex_lock(hdl->lock); > /* Free all nodes */ > list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) { > @@ -2816,6 +2854,128 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) > } > EXPORT_SYMBOL(v4l2_querymenu); > > +static int v4l2_ctrl_request_clone(struct v4l2_ctrl_handler *hdl, > + const struct v4l2_ctrl_handler *from) > +{ > + struct v4l2_ctrl_ref *ref; > + int err; > + > + if (WARN_ON(!hdl || hdl == from)) > + return -EINVAL; > + > + if (hdl->error) > + return hdl->error; > + > + WARN_ON(hdl->lock != &hdl->_lock); > + > + mutex_lock(from->lock); > + list_for_each_entry(ref, &from->ctrl_refs, node) { > + struct v4l2_ctrl *ctrl = ref->ctrl; > + struct v4l2_ctrl_ref *new_ref; > + > + /* Skip refs inherited from other devices */ > + if (ref->from_other_dev) > + continue; > + /* And buttons */ > + if (ctrl->type == V4L2_CTRL_TYPE_BUTTON) > + continue; > + err = handler_new_ref(hdl, ctrl, &new_ref, false, true); > + if (err) { > + printk("%s: handler_new_ref on control %x (%s) returned %d\n", __func__, ctrl->id, ctrl->name, err); Nit: pr_err + pr_fmt above? -- Ezequiel García, VanguardiaSur www.vanguardiasur.com.ar