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
uvc_meta_v4l2_querycap(struct file * file,void * priv,struct v4l2_capability * cap)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
uvc_meta_v4l2_get_format(struct file * file,void * priv,struct v4l2_format * format)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 = UVC_METADATA_BUF_SIZE;
54
55 return 0;
56 }
57
uvc_meta_v4l2_try_format(struct file * file,void * priv,struct v4l2_format * format)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
67 if (format->type != vfh->vdev->queue->type)
68 return -EINVAL;
69
70 for (unsigned int i = 0; i < dev->nmeta_formats; i++) {
71 if (dev->meta_formats[i] == fmt->dataformat) {
72 fmeta = fmt->dataformat;
73 break;
74 }
75 }
76
77 memset(fmt, 0, sizeof(*fmt));
78
79 fmt->dataformat = fmeta;
80 fmt->buffersize = UVC_METADATA_BUF_SIZE;
81
82 return 0;
83 }
84
uvc_meta_v4l2_set_format(struct file * file,void * priv,struct v4l2_format * format)85 static int uvc_meta_v4l2_set_format(struct file *file, void *priv,
86 struct v4l2_format *format)
87 {
88 struct v4l2_fh *vfh = file_to_v4l2_fh(file);
89 struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
90 struct v4l2_meta_format *fmt = &format->fmt.meta;
91 int ret;
92
93 ret = uvc_meta_v4l2_try_format(file, priv, format);
94 if (ret < 0)
95 return ret;
96
97 /*
98 * We could in principle switch at any time, also during streaming.
99 * Metadata buffers would still be perfectly parseable, but it's more
100 * consistent and cleaner to disallow that.
101 */
102 if (vb2_is_busy(&stream->meta.queue.queue))
103 return -EBUSY;
104
105 stream->meta.format = fmt->dataformat;
106
107 return 0;
108 }
109
uvc_meta_v4l2_enum_formats(struct file * file,void * priv,struct v4l2_fmtdesc * fdesc)110 static int uvc_meta_v4l2_enum_formats(struct file *file, void *priv,
111 struct v4l2_fmtdesc *fdesc)
112 {
113 struct v4l2_fh *vfh = file_to_v4l2_fh(file);
114 struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
115 struct uvc_device *dev = stream->dev;
116
117 if (fdesc->type != vfh->vdev->queue->type)
118 return -EINVAL;
119
120 if (fdesc->index >= dev->nmeta_formats)
121 return -EINVAL;
122
123 fdesc->pixelformat = dev->meta_formats[fdesc->index];
124
125 return 0;
126 }
127
128 static const struct v4l2_ioctl_ops uvc_meta_ioctl_ops = {
129 .vidioc_querycap = uvc_meta_v4l2_querycap,
130 .vidioc_g_fmt_meta_cap = uvc_meta_v4l2_get_format,
131 .vidioc_s_fmt_meta_cap = uvc_meta_v4l2_set_format,
132 .vidioc_try_fmt_meta_cap = uvc_meta_v4l2_try_format,
133 .vidioc_enum_fmt_meta_cap = uvc_meta_v4l2_enum_formats,
134 .vidioc_reqbufs = vb2_ioctl_reqbufs,
135 .vidioc_querybuf = vb2_ioctl_querybuf,
136 .vidioc_qbuf = vb2_ioctl_qbuf,
137 .vidioc_dqbuf = vb2_ioctl_dqbuf,
138 .vidioc_create_bufs = vb2_ioctl_create_bufs,
139 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
140 .vidioc_streamon = vb2_ioctl_streamon,
141 .vidioc_streamoff = vb2_ioctl_streamoff,
142 };
143
144 /* -----------------------------------------------------------------------------
145 * V4L2 File Operations
146 */
147
148 static const struct v4l2_file_operations uvc_meta_fops = {
149 .owner = THIS_MODULE,
150 .unlocked_ioctl = video_ioctl2,
151 .open = v4l2_fh_open,
152 .release = vb2_fop_release,
153 .poll = vb2_fop_poll,
154 .mmap = vb2_fop_mmap,
155 };
156
uvc_meta_find_msxu(struct uvc_device * dev)157 static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev)
158 {
159 static const u8 uvc_msxu_guid[16] = UVC_GUID_MSXU_1_5;
160 struct uvc_entity *entity;
161
162 list_for_each_entry(entity, &dev->entities, list) {
163 if (!memcmp(entity->guid, uvc_msxu_guid, sizeof(entity->guid)))
164 return entity;
165 }
166
167 return NULL;
168 }
169
uvc_meta_detect_msxu(struct uvc_device * dev)170 static int uvc_meta_detect_msxu(struct uvc_device *dev)
171 {
172 u32 *data __free(kfree) = NULL;
173 struct uvc_entity *entity;
174 int ret;
175
176 entity = uvc_meta_find_msxu(dev);
177 if (!entity)
178 return 0;
179
180 /*
181 * USB requires buffers aligned in a special way, simplest way is to
182 * make sure that query_ctrl will work is to kmalloc() them.
183 */
184 data = kmalloc_obj(*data);
185 if (!data)
186 return -ENOMEM;
187
188 /*
189 * Check if the metadata is already enabled, or if the device always
190 * returns metadata.
191 */
192 ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum,
193 UVC_MSXU_CONTROL_METADATA, data, sizeof(*data));
194 if (ret)
195 return 0;
196
197 if (*data) {
198 dev->quirks |= UVC_QUIRK_MSXU_META;
199 return 0;
200 }
201
202 /*
203 * Set the value of UVC_MSXU_CONTROL_METADATA to the value reported by
204 * GET_MAX to enable production of MSXU metadata. The GET_MAX request
205 * reports the maximum size of the metadata, if its value is 0 then MSXU
206 * metadata is not supported. For more information, see
207 * https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5#2229-metadata-control
208 */
209 ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum,
210 UVC_MSXU_CONTROL_METADATA, data, sizeof(*data));
211 if (ret || !*data)
212 return 0;
213
214 /*
215 * If we can set UVC_MSXU_CONTROL_METADATA, the device will report
216 * metadata.
217 */
218 ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum,
219 UVC_MSXU_CONTROL_METADATA, data, sizeof(*data));
220 if (!ret)
221 dev->quirks |= UVC_QUIRK_MSXU_META;
222
223 return 0;
224 }
225
uvc_meta_register(struct uvc_streaming * stream)226 int uvc_meta_register(struct uvc_streaming *stream)
227 {
228 struct uvc_device *dev = stream->dev;
229 struct uvc_video_queue *queue = &stream->meta.queue;
230
231 stream->meta.format = V4L2_META_FMT_UVC;
232
233 return uvc_register_video_device(dev, stream, queue,
234 V4L2_BUF_TYPE_META_CAPTURE,
235 &uvc_meta_fops, &uvc_meta_ioctl_ops);
236 }
237
uvc_meta_init(struct uvc_device * dev)238 int uvc_meta_init(struct uvc_device *dev)
239 {
240 unsigned int i = 0;
241 int ret;
242
243 ret = uvc_meta_detect_msxu(dev);
244 if (ret)
245 return ret;
246
247 dev->meta_formats[i++] = V4L2_META_FMT_UVC;
248
249 if (dev->info->meta_format &&
250 !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC))
251 dev->meta_formats[i++] = dev->info->meta_format;
252
253 if (dev->quirks & UVC_QUIRK_MSXU_META &&
254 !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC_MSXU_1_5))
255 dev->meta_formats[i++] = V4L2_META_FMT_UVC_MSXU_1_5;
256
257 /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */
258 dev->nmeta_formats = i;
259
260 return 0;
261 }
262