On 2/27/19 6:07 PM, Ezequiel Garcia wrote: > Currently, the v4l2 control code is a bit silent on errors. > Now that we have a debug parameter, it's possible to enable > debugging messages here. > > Add debug messages on (hopefully) most of the error paths. > Since it's really hard to associate all these errors > to video device instance, we are forced to use the global > debug parameter only. > > Add a warning in case the user enables control debugging > at the per-device dev_debug level. > > Signed-off-by: Ezequiel Garcia <ezequiel@xxxxxxxxxxxxx> > --- > drivers/media/v4l2-core/v4l2-ctrls.c | 93 +++++++++++++++++++++------ > drivers/media/v4l2-core/v4l2-dev.c | 2 + > drivers/media/v4l2-core/v4l2-ioctl.c | 8 +-- > drivers/media/v4l2-core/v4l2-subdev.c | 4 +- > include/media/v4l2-ctrls.h | 9 ++- > include/media/v4l2-ioctl.h | 2 + > 6 files changed, 91 insertions(+), 27 deletions(-) > > diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c > index b79d3bbd8350..af8ad83d1e08 100644 > --- a/drivers/media/v4l2-core/v4l2-ctrls.c > +++ b/drivers/media/v4l2-core/v4l2-ctrls.c > @@ -18,6 +18,8 @@ > Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > */ > > +#define pr_fmt(fmt) "v4l2-ctrls: " fmt > + > #include <linux/ctype.h> > #include <linux/mm.h> > #include <linux/slab.h> > @@ -28,6 +30,14 @@ > #include <media/v4l2-event.h> > #include <media/v4l2-dev.h> > > +extern unsigned int videodev_debug; > + > +#define dprintk(fmt, arg...) do { \ > + if (videodev_debug & V4L2_DEV_DEBUG_CTRL) \ > + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ > + __func__, ##arg); \ > +} while (0) > + > #define has_op(master, op) \ > (master->ops && master->ops->op) > #define call_op(master, op) \ > @@ -1952,8 +1962,11 @@ static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) > unsigned idx; > int err = 0; > > - for (idx = 0; !err && idx < ctrl->elems; idx++) > + for (idx = 0; !err && idx < ctrl->elems; idx++) { > err = ctrl->type_ops->validate(ctrl, idx, p_new); > + if (err) > + dprintk("failed to validate control id 0x%x (%d)\n", ctrl->id, err); > + } > return err; > } > > @@ -3136,20 +3149,28 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, > if (cs->which && > cs->which != V4L2_CTRL_WHICH_DEF_VAL && > cs->which != V4L2_CTRL_WHICH_REQUEST_VAL && > - V4L2_CTRL_ID2WHICH(id) != cs->which) > + V4L2_CTRL_ID2WHICH(id) != cs->which) { > + dprintk("invalid which 0x%x or control id 0x%x\n", cs->which, id); > return -EINVAL; > + } > > /* Old-style private controls are not allowed for > extended controls */ > - if (id >= V4L2_CID_PRIVATE_BASE) > + if (id >= V4L2_CID_PRIVATE_BASE) { > + dprintk("old-style private controls not allowed for extended controls\n"); > return -EINVAL; > + } > ref = find_ref_lock(hdl, id); > - if (ref == NULL) > + if (ref == NULL) { > + dprintk("cannot find control id 0x%x\n", id); > return -EINVAL; > + } > h->ref = ref; > ctrl = ref->ctrl; > - if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) > + if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED) { > + dprintk("control id 0x%x is disabled\n", id); > return -EINVAL; > + } > > if (ctrl->cluster[0]->ncontrols > 1) > have_clusters = true; > @@ -3159,10 +3180,16 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, > unsigned tot_size = ctrl->elems * ctrl->elem_size; > > if (c->size < tot_size) { > + /* > + * In the get case the application first queries > + * to obtain the size of the control. > + */ > if (get) { > c->size = tot_size; > return -ENOSPC; > } > + dprintk("pointer control id 0x%x size too small, %d bytes but %d bytes needed\n", > + id, c->size, tot_size); > return -EFAULT; > } > c->size = tot_size; > @@ -3534,16 +3561,20 @@ static int validate_ctrls(struct v4l2_ext_controls *cs, > > cs->error_idx = i; > > - if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) > + if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY) { > + dprintk("control id 0x%x is read-only\n", ctrl->id); > return -EACCES; > + } > /* This test is also done in try_set_control_cluster() which > is called in atomic context, so that has the final say, > but it makes sense to do an up-front check as well. Once > an error occurs in try_set_control_cluster() some other > controls may have been set already and we want to do a > best-effort to avoid that. */ > - if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) > + if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)) { > + dprintk("control id 0x%x is grabbed, cannot set\n", ctrl->id); > return -EBUSY; > + } > /* > * Skip validation for now if the payload needs to be copied > * from userspace into kernelspace. We'll validate those later. > @@ -3576,7 +3607,8 @@ static void update_from_auto_cluster(struct v4l2_ctrl *master) > } > > /* Try or try-and-set controls */ > -static int try_set_ext_ctrls_common(struct v4l2_fh *fh, > +static int try_set_ext_ctrls_common(struct video_device *vdev, > + struct v4l2_fh *fh, > struct v4l2_ctrl_handler *hdl, > struct v4l2_ext_controls *cs, bool set) > { > @@ -3588,13 +3620,17 @@ static int try_set_ext_ctrls_common(struct v4l2_fh *fh, > cs->error_idx = cs->count; > > /* Default value cannot be changed */ > - if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) > + if (cs->which == V4L2_CTRL_WHICH_DEF_VAL) { > + dprintk("%s: cannot change default value\n", video_device_node_name(vdev)); > return -EINVAL; > + } > > cs->which = V4L2_CTRL_ID2WHICH(cs->which); > > - if (hdl == NULL) > + if (hdl == NULL) { > + dprintk("%s: invalid null control handler\n", video_device_node_name(vdev)); > return -EINVAL; > + } > > if (cs->count == 0) > return class_check(hdl, cs->which); > @@ -3691,7 +3727,8 @@ static int try_set_ext_ctrls_common(struct v4l2_fh *fh, > return ret; > } > > -static int try_set_ext_ctrls(struct v4l2_fh *fh, > +static int try_set_ext_ctrls(struct video_device *vdev, > + struct v4l2_fh *fh, > struct v4l2_ctrl_handler *hdl, struct media_device *mdev, > struct v4l2_ext_controls *cs, bool set) > { > @@ -3700,21 +3737,32 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, > int ret; > > if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL) { > - if (!mdev || cs->request_fd < 0) > + if (!mdev) { > + dprintk("%s: missing media device\n", video_device_node_name(vdev)); > + return -EINVAL; > + } > + > + if (cs->request_fd < 0) { > + dprintk("%s: invalid request fd %d\n", video_device_node_name(vdev), cs->request_fd); > return -EINVAL; > + } > > req = media_request_get_by_fd(mdev, cs->request_fd); > - if (IS_ERR(req)) > + if (IS_ERR(req)) { > + dprintk("%s: cannot find request fd %d\n", video_device_node_name(vdev), cs->request_fd); > return PTR_ERR(req); > + } > > ret = media_request_lock_for_update(req); > if (ret) { > + dprintk("%s: cannot lock request fd %d\n", video_device_node_name(vdev), cs->request_fd); > media_request_put(req); > return ret; > } > > obj = v4l2_ctrls_find_req_obj(hdl, req, set); > if (IS_ERR(obj)) { > + dprintk("%s: cannot find request object for request fd %d\n", video_device_node_name(vdev), cs->request_fd); These lines are way too long. Just add a newline after the first comma. Same elsewhere. > media_request_unlock_for_update(req); > media_request_put(req); > return PTR_ERR(obj); > @@ -3723,7 +3771,9 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, > req_obj); > } > > - ret = try_set_ext_ctrls_common(fh, hdl, cs, set); > + ret = try_set_ext_ctrls_common(vdev, fh, hdl, cs, set); > + if (ret) > + dprintk("%s: try_set_ext_ctrls_common failed (%d)\n", video_device_node_name(vdev), ret); > > if (obj) { > media_request_unlock_for_update(req); > @@ -3734,17 +3784,22 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, > return ret; > } > > -int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct media_device *mdev, > +int v4l2_try_ext_ctrls(struct video_device *vdev, > + struct v4l2_ctrl_handler *hdl, > + struct media_device *mdev, > struct v4l2_ext_controls *cs) > { > - return try_set_ext_ctrls(NULL, hdl, mdev, cs, false); > + return try_set_ext_ctrls(vdev, NULL, hdl, mdev, cs, false); > } > EXPORT_SYMBOL(v4l2_try_ext_ctrls); > > -int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, > - struct media_device *mdev, struct v4l2_ext_controls *cs) > +int v4l2_s_ext_ctrls(struct video_device *vdev, > + struct v4l2_fh *fh, > + struct v4l2_ctrl_handler *hdl, > + struct media_device *mdev, > + struct v4l2_ext_controls *cs) > { > - return try_set_ext_ctrls(fh, hdl, mdev, cs, true); > + return try_set_ext_ctrls(vdev, fh, hdl, mdev, cs, true); > } > EXPORT_SYMBOL(v4l2_s_ext_ctrls); > > diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c > index 39d22bfbe420..c6bcc9ea1122 100644 > --- a/drivers/media/v4l2-core/v4l2-dev.c > +++ b/drivers/media/v4l2-core/v4l2-dev.c > @@ -83,6 +83,8 @@ static ssize_t dev_debug_store(struct device *cd, struct device_attribute *attr, > if (res) > return res; > > + if (value & V4L2_DEV_DEBUG_CTRL) > + pr_warn_once("Warning: V4L2_DEV_DEBUG_CTRL cannot be enabled via the dev_debug attribute.\n"); Actually, you can for those functions that have the vdev pointer. And I think you can pass vdev on to more functions. Certainly validate_ctrls() and possibly all of them. > vdev->dev_debug = value; > return len; > } > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c > index 6f707466b5d2..078f75eb0a19 100644 > --- a/drivers/media/v4l2-core/v4l2-ioctl.c > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c > @@ -2180,9 +2180,9 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, > > p->error_idx = p->count; > if (vfh && vfh->ctrl_handler) > - return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, vfd->v4l2_dev->mdev, p); > + return v4l2_s_ext_ctrls(vfd, vfh, vfh->ctrl_handler, vfd->v4l2_dev->mdev, p); > if (vfd->ctrl_handler) > - return v4l2_s_ext_ctrls(NULL, vfd->ctrl_handler, vfd->v4l2_dev->mdev, p); > + return v4l2_s_ext_ctrls(vfd, vfh, vfd->ctrl_handler, vfd->v4l2_dev->mdev, p); Copy-and-paste error: vfh should be NULL. > if (ops->vidioc_s_ext_ctrls == NULL) > return -ENOTTY; > return check_ext_ctrls(p, 0) ? ops->vidioc_s_ext_ctrls(file, fh, p) : > @@ -2199,9 +2199,9 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, > > p->error_idx = p->count; > if (vfh && vfh->ctrl_handler) > - return v4l2_try_ext_ctrls(vfh->ctrl_handler, vfd->v4l2_dev->mdev, p); > + return v4l2_try_ext_ctrls(vfd, vfh->ctrl_handler, vfd->v4l2_dev->mdev, p); > if (vfd->ctrl_handler) > - return v4l2_try_ext_ctrls(vfd->ctrl_handler, vfd->v4l2_dev->mdev, p); > + return v4l2_try_ext_ctrls(vfd, vfd->ctrl_handler, vfd->v4l2_dev->mdev, p); > if (ops->vidioc_try_ext_ctrls == NULL) > return -ENOTTY; > return check_ext_ctrls(p, 0) ? ops->vidioc_try_ext_ctrls(file, fh, p) : > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c > index f5f0d71ec745..3a09d4441ca3 100644 > --- a/drivers/media/v4l2-core/v4l2-subdev.c > +++ b/drivers/media/v4l2-core/v4l2-subdev.c > @@ -228,13 +228,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) > case VIDIOC_S_EXT_CTRLS: > if (!vfh->ctrl_handler) > return -ENOTTY; > - return v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, > + return v4l2_s_ext_ctrls(vdev, vfh, vfh->ctrl_handler, > sd->v4l2_dev->mdev, arg); > > case VIDIOC_TRY_EXT_CTRLS: > if (!vfh->ctrl_handler) > return -ENOTTY; > - return v4l2_try_ext_ctrls(vfh->ctrl_handler, > + return v4l2_try_ext_ctrls(vdev, vfh->ctrl_handler, > sd->v4l2_dev->mdev, arg); > > case VIDIOC_DQEVENT: > diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h > index d63cf227b0ab..0e38a59c80dd 100644 > --- a/include/media/v4l2-ctrls.h > +++ b/include/media/v4l2-ctrls.h > @@ -1272,13 +1272,15 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct media_device *mdev, > * v4l2_try_ext_ctrls - Helper function to implement > * :ref:`VIDIOC_TRY_EXT_CTRLS <vidioc_g_ext_ctrls>` ioctl > * > + * @vdev: pointer to &struct video_device > * @hdl: pointer to &struct v4l2_ctrl_handler > * @mdev: pointer to &struct media_device > * @c: pointer to &struct v4l2_ext_controls > * > * If hdl == NULL then they will all return -EINVAL. > */ > -int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, > +int v4l2_try_ext_ctrls(struct video_device *vdev, > + struct v4l2_ctrl_handler *hdl, > struct media_device *mdev, > struct v4l2_ext_controls *c); > > @@ -1286,6 +1288,7 @@ int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, > * v4l2_s_ext_ctrls - Helper function to implement > * :ref:`VIDIOC_S_EXT_CTRLS <vidioc_g_ext_ctrls>` ioctl > * > + * @vdev: pointer to &struct video_device > * @fh: pointer to &struct v4l2_fh > * @hdl: pointer to &struct v4l2_ctrl_handler > * @mdev: pointer to &struct media_device > @@ -1293,7 +1296,9 @@ int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, > * > * If hdl == NULL then they will all return -EINVAL. > */ > -int v4l2_s_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl, > +int v4l2_s_ext_ctrls(struct video_device *vdev, > + struct v4l2_fh *fh, > + struct v4l2_ctrl_handler *hdl, > struct media_device *mdev, > struct v4l2_ext_controls *c); > > diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h > index 8533ece5026e..0ecd4e3e76a4 100644 > --- a/include/media/v4l2-ioctl.h > +++ b/include/media/v4l2-ioctl.h > @@ -612,6 +612,8 @@ struct v4l2_ioctl_ops { > #define V4L2_DEV_DEBUG_STREAMING 0x08 > /* Log poll() */ > #define V4L2_DEV_DEBUG_POLL 0x10 > +/* Log controls */ > +#define V4L2_DEV_DEBUG_CTRL 0x20 > > /* Video standard functions */ > > Regards, Hans