Re: [PATCH v4 07/10] usb: gadget: uvc: add g_parm and s_parm for frame interval

Laurent Pinchart
2024-08-13T09:28:44Z

On Tue, Aug 13, 2024 at 12:22:55PM +0300, Laurent Pinchart wrote:
> On Tue, Aug 13, 2024 at 11:09:31AM +0200, Michael Grzeschik wrote:
> > The uvc gadget driver is lacking the information which frame interval
> > was set by the host. We add this information by implementing the g_parm
> > and s_parm callbacks.
>
> As I've said countless times, this kind of hack is not the right way to
> pass information that the kernel has no use for between two userspace
> components. Please stop butchering this driver.

Reading further patches in the series I see that you would like to get
more precise bandwidth information from userspace. That is fine, but I
don't think s_parm is the right option. This is not a regular V4L2
driver, pass it the exat information it needs instead, through a
dedicated API that will provide all the needed data.

> > Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> > ---
> > v3 -> v4: -
> > v2 -> v3: -
> > v1 -> v2: -
> > ---
> > drivers/usb/gadget/function/uvc.h | 1 +
> > drivers/usb/gadget/function/uvc_v4l2.c | 52 ++++++++++++++++++++++++++++++++++
> > 2 files changed, 53 insertions(+)
> >
> > diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
> > index b3a5165ac70ec..f6bc58fb02b84 100644
> > --- a/drivers/usb/gadget/function/uvc.h
> > +++ b/drivers/usb/gadget/function/uvc.h
> > @@ -100,6 +100,7 @@ struct uvc_video {
> > unsigned int width;
> > unsigned int height;
> > unsigned int imagesize;
> > + unsigned int interval;
> > struct mutex mutex; /* protects frame parameters */
> >
> > unsigned int uvc_num_requests;
> > diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
> > index de41519ce9aa0..392fb400aad14 100644
> > --- a/drivers/usb/gadget/function/uvc_v4l2.c
> > +++ b/drivers/usb/gadget/function/uvc_v4l2.c
> > @@ -307,6 +307,56 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
> > return ret;
> > }
> >
> > +static int uvc_v4l2_g_parm(struct file *file, void *fh,
> > + struct v4l2_streamparm *parm)
> > +{
> > + struct video_device *vdev = video_devdata(file);
> > + struct uvc_device *uvc = video_get_drvdata(vdev);
> > + struct uvc_video *video = &uvc->video;
> > + struct v4l2_fract timeperframe;
> > +
> > + if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> > + return -EINVAL;
> > +
> > + /* Return the actual frame period. */
> > + timeperframe.numerator = video->interval;
> > + timeperframe.denominator = 10000000;
> > + v4l2_simplify_fraction(&timeperframe.numerator,
> > + &timeperframe.denominator, 8, 333);
> > +
> > + uvcg_dbg(&uvc->func, "Getting frame interval of %u/%u (%u)\n",
> > + timeperframe.numerator, timeperframe.denominator,
> > + video->interval);
> > +
> > + parm->parm.output.timeperframe = timeperframe;
> > + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
> > +
> > + return 0;
> > +}
> > +
> > +static int uvc_v4l2_s_parm(struct file *file, void *fh,
> > + struct v4l2_streamparm *parm)
> > +{
> > + struct video_device *vdev = video_devdata(file);
> > + struct uvc_device *uvc = video_get_drvdata(vdev);
> > + struct uvc_video *video = &uvc->video;
> > + struct v4l2_fract timeperframe;
> > +
> > + if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
> > + return -EINVAL;
> > +
> > + timeperframe = parm->parm.output.timeperframe;
> > +
> > + video->interval = v4l2_fraction_to_interval(timeperframe.numerator,
> > + timeperframe.denominator);
> > +
> > + uvcg_dbg(&uvc->func, "Setting frame interval to %u/%u (%u)\n",
> > + timeperframe.numerator, timeperframe.denominator,
> > + video->interval);
> > +
> > + return 0;
> > +}
> > +
> > static int
> > uvc_v4l2_enum_frameintervals(struct file *file, void *fh,
> > struct v4l2_frmivalenum *fival)
> > @@ -577,6 +627,8 @@ const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
> > .vidioc_dqbuf = uvc_v4l2_dqbuf,
> > .vidioc_streamon = uvc_v4l2_streamon,
> > .vidioc_streamoff = uvc_v4l2_streamoff,
> > + .vidioc_s_parm = uvc_v4l2_s_parm,
> > + .vidioc_g_parm = uvc_v4l2_g_parm,
> > .vidioc_subscribe_event = uvc_v4l2_subscribe_event,
> > .vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event,
> > .vidioc_default = uvc_v4l2_ioctl_default,

--
Regards,

Laurent Pinchart