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