media: uvcvideo: Introduce dev->meta_formats

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>
Reviewed-by: Hans de Goede <hansg@kernel.org>
Link: https://lore.kernel.org/r/20250707-uvc-meta-v8-3-ed17f8b1218b@chromium.org
Signed-off-by: Hans de Goede <hansg@kernel.org>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
This commit is contained in:
Ricardo Ribalda 2025-07-07 18:34:03 +00:00 committed by Hans Verkuil
parent e1ad270275
commit 0bb51c8897
3 changed files with 39 additions and 7 deletions

View File

@ -2293,6 +2293,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;

View File

@ -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 ||
index > 1U || (index && !dev->info->meta_format))
if (fdesc->type != vfh->vdev->queue->type)
return -EINVAL;
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;
}
@ -168,3 +178,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;
}

View File

@ -575,6 +575,8 @@ struct uvc_status {
};
} __packed;
#define UVC_MAX_META_DATA_FORMATS 3
struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
@ -585,6 +587,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 */
@ -722,6 +727,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,