xref: /linux/drivers/media/usb/uvc/uvc_metadata.c (revision 45bd2d77fbedec862204bb5c0fcaba2b7fa5fb56)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *      uvc_metadata.c  --  USB Video Class driver - Metadata handling
4  *
5  *      Copyright (C) 2016
6  *          Guennadi Liakhovetski (guennadi.liakhovetski@intel.com)
7  */
8 
9 #include <linux/kernel.h>
10 #include <linux/list.h>
11 #include <linux/module.h>
12 #include <linux/usb.h>
13 #include <linux/usb/uvc.h>
14 #include <linux/videodev2.h>
15 
16 #include <media/v4l2-ioctl.h>
17 #include <media/videobuf2-v4l2.h>
18 #include <media/videobuf2-vmalloc.h>
19 
20 #include "uvcvideo.h"
21 
22 /* -----------------------------------------------------------------------------
23  * V4L2 ioctls
24  */
25 
26 static int uvc_meta_v4l2_querycap(struct file *file, void *priv,
27 				  struct v4l2_capability *cap)
28 {
29 	struct v4l2_fh *vfh = file_to_v4l2_fh(file);
30 	struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
31 	struct uvc_video_chain *chain = stream->chain;
32 
33 	strscpy(cap->driver, "uvcvideo", sizeof(cap->driver));
34 	strscpy(cap->card, stream->dev->name, sizeof(cap->card));
35 	usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
36 	cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
37 			  | chain->caps;
38 
39 	return 0;
40 }
41 
42 static int uvc_meta_v4l2_get_format(struct file *file, void *priv,
43 				    struct v4l2_format *format)
44 {
45 	struct v4l2_fh *vfh = file_to_v4l2_fh(file);
46 	struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
47 	struct v4l2_meta_format *fmt = &format->fmt.meta;
48 
49 	if (format->type != vfh->vdev->queue->type)
50 		return -EINVAL;
51 
52 	fmt->dataformat = stream->meta.format;
53 	fmt->buffersize = stream->meta.buffersize;
54 
55 	return 0;
56 }
57 
58 static int uvc_meta_v4l2_try_format(struct file *file, void *priv,
59 				    struct v4l2_format *format)
60 {
61 	struct v4l2_fh *vfh = file_to_v4l2_fh(file);
62 	struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
63 	struct uvc_device *dev = stream->dev;
64 	struct v4l2_meta_format *fmt = &format->fmt.meta;
65 	u32 fmeta = V4L2_META_FMT_UVC;
66 	u32 buffersize;
67 
68 	if (format->type != vfh->vdev->queue->type)
69 		return -EINVAL;
70 
71 	for (unsigned int i = 0; i < dev->nmeta_formats; i++) {
72 		if (dev->meta_formats[i] == fmt->dataformat) {
73 			fmeta = fmt->dataformat;
74 			break;
75 		}
76 	}
77 
78 	buffersize = max(UVC_METADATA_BUF_MIN_SIZE, fmt->buffersize);
79 
80 	memset(fmt, 0, sizeof(*fmt));
81 
82 	fmt->dataformat = fmeta;
83 	fmt->buffersize = buffersize;
84 
85 	return 0;
86 }
87 
88 static int uvc_meta_v4l2_set_format(struct file *file, void *priv,
89 				    struct v4l2_format *format)
90 {
91 	struct v4l2_fh *vfh = file_to_v4l2_fh(file);
92 	struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
93 	struct v4l2_meta_format *fmt = &format->fmt.meta;
94 	int ret;
95 
96 	ret = uvc_meta_v4l2_try_format(file, priv, format);
97 	if (ret < 0)
98 		return ret;
99 
100 	/*
101 	 * We could in principle switch at any time, also during streaming.
102 	 * Metadata buffers would still be perfectly parseable, but it's more
103 	 * consistent and cleaner to disallow that.
104 	 */
105 	if (vb2_is_busy(&stream->meta.queue.queue))
106 		return -EBUSY;
107 
108 	stream->meta.format = fmt->dataformat;
109 	stream->meta.buffersize = fmt->buffersize;
110 
111 	return 0;
112 }
113 
114 static int uvc_meta_v4l2_enum_formats(struct file *file, void *priv,
115 				      struct v4l2_fmtdesc *fdesc)
116 {
117 	struct v4l2_fh *vfh = file_to_v4l2_fh(file);
118 	struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
119 	struct uvc_device *dev = stream->dev;
120 
121 	if (fdesc->type != vfh->vdev->queue->type)
122 		return -EINVAL;
123 
124 	if (fdesc->index >= dev->nmeta_formats)
125 		return -EINVAL;
126 
127 	fdesc->pixelformat = dev->meta_formats[fdesc->index];
128 
129 	return 0;
130 }
131 
132 static const struct v4l2_ioctl_ops uvc_meta_ioctl_ops = {
133 	.vidioc_querycap		= uvc_meta_v4l2_querycap,
134 	.vidioc_g_fmt_meta_cap		= uvc_meta_v4l2_get_format,
135 	.vidioc_s_fmt_meta_cap		= uvc_meta_v4l2_set_format,
136 	.vidioc_try_fmt_meta_cap	= uvc_meta_v4l2_try_format,
137 	.vidioc_enum_fmt_meta_cap	= uvc_meta_v4l2_enum_formats,
138 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
139 	.vidioc_querybuf		= vb2_ioctl_querybuf,
140 	.vidioc_qbuf			= vb2_ioctl_qbuf,
141 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
142 	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
143 	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
144 	.vidioc_streamon		= vb2_ioctl_streamon,
145 	.vidioc_streamoff		= vb2_ioctl_streamoff,
146 };
147 
148 /* -----------------------------------------------------------------------------
149  * V4L2 File Operations
150  */
151 
152 static const struct v4l2_file_operations uvc_meta_fops = {
153 	.owner = THIS_MODULE,
154 	.unlocked_ioctl = video_ioctl2,
155 	.open = v4l2_fh_open,
156 	.release = vb2_fop_release,
157 	.poll = vb2_fop_poll,
158 	.mmap = vb2_fop_mmap,
159 };
160 
161 static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev)
162 {
163 	static const u8 uvc_msxu_guid[16] = UVC_GUID_MSXU_1_5;
164 	struct uvc_entity *entity;
165 
166 	list_for_each_entry(entity, &dev->entities, list) {
167 		if (!memcmp(entity->guid, uvc_msxu_guid, sizeof(entity->guid)))
168 			return entity;
169 	}
170 
171 	return NULL;
172 }
173 
174 static int uvc_meta_detect_msxu(struct uvc_device *dev)
175 {
176 	u32 *data __free(kfree) = NULL;
177 	struct uvc_entity *entity;
178 	int ret;
179 
180 	entity = uvc_meta_find_msxu(dev);
181 	if (!entity)
182 		return 0;
183 
184 	/*
185 	 * USB requires buffers aligned in a special way, simplest way is to
186 	 * make sure that query_ctrl will work is to kmalloc() them.
187 	 */
188 	data = kmalloc_obj(*data);
189 	if (!data)
190 		return -ENOMEM;
191 
192 	/*
193 	 * Check if the metadata is already enabled, or if the device always
194 	 * returns metadata.
195 	 */
196 	ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum,
197 			     UVC_MSXU_CONTROL_METADATA, data, sizeof(*data));
198 	if (ret)
199 		return 0;
200 
201 	if (*data) {
202 		dev->quirks |= UVC_QUIRK_MSXU_META;
203 		return 0;
204 	}
205 
206 	/*
207 	 * Set the value of UVC_MSXU_CONTROL_METADATA to the value reported by
208 	 * GET_MAX to enable production of MSXU metadata. The GET_MAX request
209 	 * reports the maximum size of the metadata, if its value is 0 then MSXU
210 	 * metadata is not supported. For more information, see
211 	 * https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5#2229-metadata-control
212 	 */
213 	ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum,
214 			     UVC_MSXU_CONTROL_METADATA, data, sizeof(*data));
215 	if (ret || !*data)
216 		return 0;
217 
218 	/*
219 	 * If we can set UVC_MSXU_CONTROL_METADATA, the device will report
220 	 * metadata.
221 	 */
222 	ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum,
223 			     UVC_MSXU_CONTROL_METADATA, data, sizeof(*data));
224 	if (!ret)
225 		dev->quirks |= UVC_QUIRK_MSXU_META;
226 
227 	return 0;
228 }
229 
230 int uvc_meta_register(struct uvc_streaming *stream)
231 {
232 	struct uvc_device *dev = stream->dev;
233 	struct uvc_video_queue *queue = &stream->meta.queue;
234 
235 	stream->meta.format = V4L2_META_FMT_UVC;
236 	stream->meta.buffersize = UVC_METADATA_BUF_MIN_SIZE;
237 
238 	return uvc_register_video_device(dev, stream, queue,
239 					 V4L2_BUF_TYPE_META_CAPTURE,
240 					 &uvc_meta_fops, &uvc_meta_ioctl_ops);
241 }
242 
243 int uvc_meta_init(struct uvc_device *dev)
244 {
245 	unsigned int i = 0;
246 	int ret;
247 
248 	ret = uvc_meta_detect_msxu(dev);
249 	if (ret)
250 		return ret;
251 
252 	dev->meta_formats[i++] = V4L2_META_FMT_UVC;
253 
254 	if (dev->info->meta_format &&
255 	    !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC))
256 		dev->meta_formats[i++] = dev->info->meta_format;
257 
258 	if (dev->quirks & UVC_QUIRK_MSXU_META &&
259 	    !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC_MSXU_1_5))
260 		dev->meta_formats[i++] = V4L2_META_FMT_UVC_MSXU_1_5;
261 
262 	 /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */
263 	dev->nmeta_formats = i;
264 
265 	return 0;
266 }
267