1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * uvc_metadata.c -- USB Video Class driver - Metadata handling
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2016
6*4882a593Smuzhiyun * Guennadi Liakhovetski (guennadi.liakhovetski@intel.com)
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/kernel.h>
10*4882a593Smuzhiyun #include <linux/list.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/usb.h>
13*4882a593Smuzhiyun #include <linux/videodev2.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
16*4882a593Smuzhiyun #include <media/videobuf2-v4l2.h>
17*4882a593Smuzhiyun #include <media/videobuf2-vmalloc.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include "uvcvideo.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
22*4882a593Smuzhiyun * V4L2 ioctls
23*4882a593Smuzhiyun */
24*4882a593Smuzhiyun
uvc_meta_v4l2_querycap(struct file * file,void * fh,struct v4l2_capability * cap)25*4882a593Smuzhiyun static int uvc_meta_v4l2_querycap(struct file *file, void *fh,
26*4882a593Smuzhiyun struct v4l2_capability *cap)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun struct v4l2_fh *vfh = file->private_data;
29*4882a593Smuzhiyun struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
30*4882a593Smuzhiyun struct uvc_video_chain *chain = stream->chain;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun strscpy(cap->driver, "uvcvideo", sizeof(cap->driver));
33*4882a593Smuzhiyun strscpy(cap->card, vfh->vdev->name, sizeof(cap->card));
34*4882a593Smuzhiyun usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
35*4882a593Smuzhiyun cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
36*4882a593Smuzhiyun | chain->caps;
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun return 0;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
uvc_meta_v4l2_get_format(struct file * file,void * fh,struct v4l2_format * format)41*4882a593Smuzhiyun static int uvc_meta_v4l2_get_format(struct file *file, void *fh,
42*4882a593Smuzhiyun struct v4l2_format *format)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun struct v4l2_fh *vfh = file->private_data;
45*4882a593Smuzhiyun struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
46*4882a593Smuzhiyun struct v4l2_meta_format *fmt = &format->fmt.meta;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun if (format->type != vfh->vdev->queue->type)
49*4882a593Smuzhiyun return -EINVAL;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun memset(fmt, 0, sizeof(*fmt));
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun fmt->dataformat = stream->meta.format;
54*4882a593Smuzhiyun fmt->buffersize = UVC_METADATA_BUF_SIZE;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return 0;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
uvc_meta_v4l2_try_format(struct file * file,void * fh,struct v4l2_format * format)59*4882a593Smuzhiyun static int uvc_meta_v4l2_try_format(struct file *file, void *fh,
60*4882a593Smuzhiyun struct v4l2_format *format)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun struct v4l2_fh *vfh = file->private_data;
63*4882a593Smuzhiyun struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
64*4882a593Smuzhiyun struct uvc_device *dev = stream->dev;
65*4882a593Smuzhiyun struct v4l2_meta_format *fmt = &format->fmt.meta;
66*4882a593Smuzhiyun u32 fmeta = fmt->dataformat;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun if (format->type != vfh->vdev->queue->type)
69*4882a593Smuzhiyun return -EINVAL;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun memset(fmt, 0, sizeof(*fmt));
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun fmt->dataformat = fmeta == dev->info->meta_format
74*4882a593Smuzhiyun ? fmeta : V4L2_META_FMT_UVC;
75*4882a593Smuzhiyun fmt->buffersize = UVC_METADATA_BUF_SIZE;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
uvc_meta_v4l2_set_format(struct file * file,void * fh,struct v4l2_format * format)80*4882a593Smuzhiyun static int uvc_meta_v4l2_set_format(struct file *file, void *fh,
81*4882a593Smuzhiyun struct v4l2_format *format)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun struct v4l2_fh *vfh = file->private_data;
84*4882a593Smuzhiyun struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
85*4882a593Smuzhiyun struct v4l2_meta_format *fmt = &format->fmt.meta;
86*4882a593Smuzhiyun int ret;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun ret = uvc_meta_v4l2_try_format(file, fh, format);
89*4882a593Smuzhiyun if (ret < 0)
90*4882a593Smuzhiyun return ret;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /*
93*4882a593Smuzhiyun * We could in principle switch at any time, also during streaming.
94*4882a593Smuzhiyun * Metadata buffers would still be perfectly parseable, but it's more
95*4882a593Smuzhiyun * consistent and cleaner to disallow that.
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun mutex_lock(&stream->mutex);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun if (uvc_queue_allocated(&stream->queue))
100*4882a593Smuzhiyun ret = -EBUSY;
101*4882a593Smuzhiyun else
102*4882a593Smuzhiyun stream->meta.format = fmt->dataformat;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun mutex_unlock(&stream->mutex);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun return ret;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
uvc_meta_v4l2_enum_formats(struct file * file,void * fh,struct v4l2_fmtdesc * fdesc)109*4882a593Smuzhiyun static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh,
110*4882a593Smuzhiyun struct v4l2_fmtdesc *fdesc)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun struct v4l2_fh *vfh = file->private_data;
113*4882a593Smuzhiyun struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
114*4882a593Smuzhiyun struct uvc_device *dev = stream->dev;
115*4882a593Smuzhiyun u32 index = fdesc->index;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun if (fdesc->type != vfh->vdev->queue->type ||
118*4882a593Smuzhiyun index > 1U || (index && !dev->info->meta_format))
119*4882a593Smuzhiyun return -EINVAL;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun memset(fdesc, 0, sizeof(*fdesc));
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun fdesc->type = vfh->vdev->queue->type;
124*4882a593Smuzhiyun fdesc->index = index;
125*4882a593Smuzhiyun fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun static const struct v4l2_ioctl_ops uvc_meta_ioctl_ops = {
131*4882a593Smuzhiyun .vidioc_querycap = uvc_meta_v4l2_querycap,
132*4882a593Smuzhiyun .vidioc_g_fmt_meta_cap = uvc_meta_v4l2_get_format,
133*4882a593Smuzhiyun .vidioc_s_fmt_meta_cap = uvc_meta_v4l2_set_format,
134*4882a593Smuzhiyun .vidioc_try_fmt_meta_cap = uvc_meta_v4l2_try_format,
135*4882a593Smuzhiyun .vidioc_enum_fmt_meta_cap = uvc_meta_v4l2_enum_formats,
136*4882a593Smuzhiyun .vidioc_reqbufs = vb2_ioctl_reqbufs,
137*4882a593Smuzhiyun .vidioc_querybuf = vb2_ioctl_querybuf,
138*4882a593Smuzhiyun .vidioc_qbuf = vb2_ioctl_qbuf,
139*4882a593Smuzhiyun .vidioc_dqbuf = vb2_ioctl_dqbuf,
140*4882a593Smuzhiyun .vidioc_create_bufs = vb2_ioctl_create_bufs,
141*4882a593Smuzhiyun .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
142*4882a593Smuzhiyun .vidioc_streamon = vb2_ioctl_streamon,
143*4882a593Smuzhiyun .vidioc_streamoff = vb2_ioctl_streamoff,
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
147*4882a593Smuzhiyun * V4L2 File Operations
148*4882a593Smuzhiyun */
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun static const struct v4l2_file_operations uvc_meta_fops = {
151*4882a593Smuzhiyun .owner = THIS_MODULE,
152*4882a593Smuzhiyun .unlocked_ioctl = video_ioctl2,
153*4882a593Smuzhiyun .open = v4l2_fh_open,
154*4882a593Smuzhiyun .release = vb2_fop_release,
155*4882a593Smuzhiyun .poll = vb2_fop_poll,
156*4882a593Smuzhiyun .mmap = vb2_fop_mmap,
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun
uvc_meta_register(struct uvc_streaming * stream)159*4882a593Smuzhiyun int uvc_meta_register(struct uvc_streaming *stream)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun struct uvc_device *dev = stream->dev;
162*4882a593Smuzhiyun struct video_device *vdev = &stream->meta.vdev;
163*4882a593Smuzhiyun struct uvc_video_queue *queue = &stream->meta.queue;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun stream->meta.format = V4L2_META_FMT_UVC;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun * The video interface queue uses manual locking and thus does not set
169*4882a593Smuzhiyun * the queue pointer. Set it manually here.
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun vdev->queue = &queue->queue;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return uvc_register_video_device(dev, stream, vdev, queue,
174*4882a593Smuzhiyun V4L2_BUF_TYPE_META_CAPTURE,
175*4882a593Smuzhiyun &uvc_meta_fops, &uvc_meta_ioctl_ops);
176*4882a593Smuzhiyun }
177