Right now, there driver supports devices with one or two metadata
formats. Prepare it to support more than two metadata formats.
This is achieved with the introduction of a new field `meta_formats`,
that contains the array of metadata formats supported by the device, in
the order expected by userspace.
Suggested-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
---
drivers/media/usb/uvc/uvc_driver.c | 2 ++
drivers/media/usb/uvc/uvc_metadata.c | 38 +++++++++++++++++++++++++++++-------
drivers/media/usb/uvc/uvcvideo.h | 6 ++++++
3 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 62eb45435d8bec5c955720ecb46fb8936871e6cc..56ea20eeb7b9d5d92f3d837c15bdf11d536e9f2d 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2315,6 +2315,8 @@ static int uvc_probe(struct usb_interface *intf,
goto error;
}
+ uvc_meta_init(dev);
+
if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME)
udev->quirks &= ~USB_QUIRK_RESET_RESUME;
diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c
index 82de7781f5b6b70c5ba16bcba9e0741231231904..4bcbc22f47e67c52baf6e133f240131ff3d32a03 100644
--- a/drivers/media/usb/uvc/uvc_metadata.c
+++ b/drivers/media/usb/uvc/uvc_metadata.c
@@ -64,14 +64,20 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh,
struct uvc_device *dev = stream->dev;
struct v4l2_meta_format *fmt = &format->fmt.meta;
u32 fmeta = fmt->dataformat;
+ u32 i;
if (format->type != vfh->vdev->queue->type)
return -EINVAL;
+ for (i = 0; (fmeta != dev->meta_formats[i]) && dev->meta_formats[i];
+ i++)
+ ;
+ if (!dev->meta_formats[i])
+ fmeta = V4L2_META_FMT_UVC;
+
memset(fmt, 0, sizeof(*fmt));
- fmt->dataformat = fmeta == dev->info->meta_format
- ? fmeta : V4L2_META_FMT_UVC;
+ fmt->dataformat = fmeta;
fmt->buffersize = UVC_METADATA_BUF_SIZE;
return 0;
@@ -112,17 +118,21 @@ static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh,
struct v4l2_fh *vfh = file->private_data;
struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
struct uvc_device *dev = stream->dev;
- u32 index = fdesc->index;
+ u32 i;
+
+ if (fdesc->type != vfh->vdev->queue->type)
+ return -EINVAL;
- if (fdesc->type != vfh->vdev->queue->type ||
- index > 1U || (index && !dev->info->meta_format))
+ for (i = 0; (i < fdesc->index) && dev->meta_formats[i]; i++)
+ ;
+ if (!dev->meta_formats[i])
return -EINVAL;
memset(fdesc, 0, sizeof(*fdesc));
fdesc->type = vfh->vdev->queue->type;
- fdesc->index = index;
- fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC;
+ fdesc->index = i;
+ fdesc->pixelformat = dev->meta_formats[i];
return 0;
}
@@ -174,3 +184,17 @@ int uvc_meta_register(struct uvc_streaming *stream)
V4L2_BUF_TYPE_META_CAPTURE,
&uvc_meta_fops, &uvc_meta_ioctl_ops);
}
+
+void uvc_meta_init(struct uvc_device *dev)
+{
+ unsigned int i = 0;
+
+ dev->meta_formats[i++] = V4L2_META_FMT_UVC;
+
+ if (dev->info->meta_format &&
+ !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC))
+ dev->meta_formats[i++] = dev->info->meta_format;
+
+ /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */
+ dev->meta_formats[i++] = 0;
+}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 11d6e3c2ebdfbabd7bbe5722f88ff85f406d9bb6..b3c094c6591e7a71fc00e1096bcf493a83f330ad 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -572,6 +572,8 @@ struct uvc_status {
};
} __packed;
+#define UVC_MAX_META_DATA_FORMATS 3
+
struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
@@ -582,6 +584,9 @@ struct uvc_device {
const struct uvc_device_info *info;
+ /* Zero-ended list of meta formats */
+ u32 meta_formats[UVC_MAX_META_DATA_FORMATS + 1];
+
atomic_t nmappings;
/* Video control interface */
@@ -751,6 +756,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
void uvc_video_clock_update(struct uvc_streaming *stream,
struct vb2_v4l2_buffer *vbuf,
struct uvc_buffer *buf);
+void uvc_meta_init(struct uvc_device *dev);
int uvc_meta_register(struct uvc_streaming *stream);
int uvc_register_video_device(struct uvc_device *dev,
--
2.50.0.727.gbf7dc18ff4-goog
Hi, On 7-Jul-25 8:34 PM, Ricardo Ribalda wrote: > Right now, there driver supports devices with one or two metadata > formats. Prepare it to support more than two metadata formats. > > This is achieved with the introduction of a new field `meta_formats`, > that contains the array of metadata formats supported by the device, in > the order expected by userspace. > > Suggested-by: Hans de Goede <hansg@kernel.org> > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> Thanks, patch looks good to me: Reviewed-by: Hans de Goede <hansg@kernel.org> Regards, Hans > --- > drivers/media/usb/uvc/uvc_driver.c | 2 ++ > drivers/media/usb/uvc/uvc_metadata.c | 38 +++++++++++++++++++++++++++++------- > drivers/media/usb/uvc/uvcvideo.h | 6 ++++++ > 3 files changed, 39 insertions(+), 7 deletions(-) > > diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c > index 62eb45435d8bec5c955720ecb46fb8936871e6cc..56ea20eeb7b9d5d92f3d837c15bdf11d536e9f2d 100644 > --- a/drivers/media/usb/uvc/uvc_driver.c > +++ b/drivers/media/usb/uvc/uvc_driver.c > @@ -2315,6 +2315,8 @@ static int uvc_probe(struct usb_interface *intf, > goto error; > } > > + uvc_meta_init(dev); > + > if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME) > udev->quirks &= ~USB_QUIRK_RESET_RESUME; > > diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c > index 82de7781f5b6b70c5ba16bcba9e0741231231904..4bcbc22f47e67c52baf6e133f240131ff3d32a03 100644 > --- a/drivers/media/usb/uvc/uvc_metadata.c > +++ b/drivers/media/usb/uvc/uvc_metadata.c > @@ -64,14 +64,20 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, > struct uvc_device *dev = stream->dev; > struct v4l2_meta_format *fmt = &format->fmt.meta; > u32 fmeta = fmt->dataformat; > + u32 i; > > if (format->type != vfh->vdev->queue->type) > return -EINVAL; > > + for (i = 0; (fmeta != dev->meta_formats[i]) && dev->meta_formats[i]; > + i++) > + ; > + if (!dev->meta_formats[i]) > + fmeta = V4L2_META_FMT_UVC; > + > memset(fmt, 0, sizeof(*fmt)); > > - fmt->dataformat = fmeta == dev->info->meta_format > - ? fmeta : V4L2_META_FMT_UVC; > + fmt->dataformat = fmeta; > fmt->buffersize = UVC_METADATA_BUF_SIZE; > > return 0; > @@ -112,17 +118,21 @@ static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, > struct v4l2_fh *vfh = file->private_data; > struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); > struct uvc_device *dev = stream->dev; > - u32 index = fdesc->index; > + u32 i; > + > + if (fdesc->type != vfh->vdev->queue->type) > + return -EINVAL; > > - if (fdesc->type != vfh->vdev->queue->type || > - index > 1U || (index && !dev->info->meta_format)) > + for (i = 0; (i < fdesc->index) && dev->meta_formats[i]; i++) > + ; > + if (!dev->meta_formats[i]) > return -EINVAL; > > memset(fdesc, 0, sizeof(*fdesc)); > > fdesc->type = vfh->vdev->queue->type; > - fdesc->index = index; > - fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC; > + fdesc->index = i; > + fdesc->pixelformat = dev->meta_formats[i]; > > return 0; > } > @@ -174,3 +184,17 @@ int uvc_meta_register(struct uvc_streaming *stream) > V4L2_BUF_TYPE_META_CAPTURE, > &uvc_meta_fops, &uvc_meta_ioctl_ops); > } > + > +void uvc_meta_init(struct uvc_device *dev) > +{ > + unsigned int i = 0; > + > + dev->meta_formats[i++] = V4L2_META_FMT_UVC; > + > + if (dev->info->meta_format && > + !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC)) > + dev->meta_formats[i++] = dev->info->meta_format; > + > + /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */ > + dev->meta_formats[i++] = 0; > +} > diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h > index 11d6e3c2ebdfbabd7bbe5722f88ff85f406d9bb6..b3c094c6591e7a71fc00e1096bcf493a83f330ad 100644 > --- a/drivers/media/usb/uvc/uvcvideo.h > +++ b/drivers/media/usb/uvc/uvcvideo.h > @@ -572,6 +572,8 @@ struct uvc_status { > }; > } __packed; > > +#define UVC_MAX_META_DATA_FORMATS 3 > + > struct uvc_device { > struct usb_device *udev; > struct usb_interface *intf; > @@ -582,6 +584,9 @@ struct uvc_device { > > const struct uvc_device_info *info; > > + /* Zero-ended list of meta formats */ > + u32 meta_formats[UVC_MAX_META_DATA_FORMATS + 1]; > + > atomic_t nmappings; > > /* Video control interface */ > @@ -751,6 +756,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, > void uvc_video_clock_update(struct uvc_streaming *stream, > struct vb2_v4l2_buffer *vbuf, > struct uvc_buffer *buf); > +void uvc_meta_init(struct uvc_device *dev); > int uvc_meta_register(struct uvc_streaming *stream); > > int uvc_register_video_device(struct uvc_device *dev, >
© 2016 - 2025 Red Hat, Inc.