linux/drivers/usb/gadget/function/uvc_v4l2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 *      uvc_v4l2.c  --  USB Video Class Gadget driver
   4 *
   5 *      Copyright (C) 2009-2010
   6 *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   7 */
   8
   9#include <linux/device.h>
  10#include <linux/errno.h>
  11#include <linux/kernel.h>
  12#include <linux/list.h>
  13#include <linux/usb/g_uvc.h>
  14#include <linux/videodev2.h>
  15#include <linux/vmalloc.h>
  16#include <linux/wait.h>
  17
  18#include <media/v4l2-dev.h>
  19#include <media/v4l2-event.h>
  20#include <media/v4l2-ioctl.h>
  21
  22#include "f_uvc.h"
  23#include "uvc.h"
  24#include "uvc_queue.h"
  25#include "uvc_video.h"
  26#include "uvc_v4l2.h"
  27
  28/* --------------------------------------------------------------------------
  29 * Requests handling
  30 */
  31
  32static int
  33uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
  34{
  35        struct usb_composite_dev *cdev = uvc->func.config->cdev;
  36        struct usb_request *req = uvc->control_req;
  37
  38        if (data->length < 0)
  39                return usb_ep_set_halt(cdev->gadget->ep0);
  40
  41        req->length = min_t(unsigned int, uvc->event_length, data->length);
  42        req->zero = data->length < uvc->event_length;
  43
  44        memcpy(req->buf, data->data, req->length);
  45
  46        return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
  47}
  48
  49/* --------------------------------------------------------------------------
  50 * V4L2 ioctls
  51 */
  52
  53struct uvc_format {
  54        u8 bpp;
  55        u32 fcc;
  56};
  57
  58static struct uvc_format uvc_formats[] = {
  59        { 16, V4L2_PIX_FMT_YUYV  },
  60        { 0,  V4L2_PIX_FMT_MJPEG },
  61};
  62
  63static int
  64uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
  65{
  66        struct video_device *vdev = video_devdata(file);
  67        struct uvc_device *uvc = video_get_drvdata(vdev);
  68        struct usb_composite_dev *cdev = uvc->func.config->cdev;
  69
  70        strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
  71        strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
  72        strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
  73                sizeof(cap->bus_info));
  74        return 0;
  75}
  76
  77static int
  78uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
  79{
  80        struct video_device *vdev = video_devdata(file);
  81        struct uvc_device *uvc = video_get_drvdata(vdev);
  82        struct uvc_video *video = &uvc->video;
  83
  84        fmt->fmt.pix.pixelformat = video->fcc;
  85        fmt->fmt.pix.width = video->width;
  86        fmt->fmt.pix.height = video->height;
  87        fmt->fmt.pix.field = V4L2_FIELD_NONE;
  88        fmt->fmt.pix.bytesperline = video->bpp * video->width / 8;
  89        fmt->fmt.pix.sizeimage = video->imagesize;
  90        fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
  91        fmt->fmt.pix.priv = 0;
  92
  93        return 0;
  94}
  95
  96static int
  97uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
  98{
  99        struct video_device *vdev = video_devdata(file);
 100        struct uvc_device *uvc = video_get_drvdata(vdev);
 101        struct uvc_video *video = &uvc->video;
 102        struct uvc_format *format;
 103        unsigned int imagesize;
 104        unsigned int bpl;
 105        unsigned int i;
 106
 107        for (i = 0; i < ARRAY_SIZE(uvc_formats); ++i) {
 108                format = &uvc_formats[i];
 109                if (format->fcc == fmt->fmt.pix.pixelformat)
 110                        break;
 111        }
 112
 113        if (i == ARRAY_SIZE(uvc_formats)) {
 114                uvcg_info(&uvc->func, "Unsupported format 0x%08x.\n",
 115                          fmt->fmt.pix.pixelformat);
 116                return -EINVAL;
 117        }
 118
 119        bpl = format->bpp * fmt->fmt.pix.width / 8;
 120        imagesize = bpl ? bpl * fmt->fmt.pix.height : fmt->fmt.pix.sizeimage;
 121
 122        video->fcc = format->fcc;
 123        video->bpp = format->bpp;
 124        video->width = fmt->fmt.pix.width;
 125        video->height = fmt->fmt.pix.height;
 126        video->imagesize = imagesize;
 127
 128        fmt->fmt.pix.field = V4L2_FIELD_NONE;
 129        fmt->fmt.pix.bytesperline = bpl;
 130        fmt->fmt.pix.sizeimage = imagesize;
 131        fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
 132        fmt->fmt.pix.priv = 0;
 133
 134        return 0;
 135}
 136
 137static int
 138uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
 139{
 140        struct video_device *vdev = video_devdata(file);
 141        struct uvc_device *uvc = video_get_drvdata(vdev);
 142        struct uvc_video *video = &uvc->video;
 143
 144        if (b->type != video->queue.queue.type)
 145                return -EINVAL;
 146
 147        return uvcg_alloc_buffers(&video->queue, b);
 148}
 149
 150static int
 151uvc_v4l2_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
 152{
 153        struct video_device *vdev = video_devdata(file);
 154        struct uvc_device *uvc = video_get_drvdata(vdev);
 155        struct uvc_video *video = &uvc->video;
 156
 157        return uvcg_query_buffer(&video->queue, b);
 158}
 159
 160static int
 161uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 162{
 163        struct video_device *vdev = video_devdata(file);
 164        struct uvc_device *uvc = video_get_drvdata(vdev);
 165        struct uvc_video *video = &uvc->video;
 166        int ret;
 167
 168        ret = uvcg_queue_buffer(&video->queue, b);
 169        if (ret < 0)
 170                return ret;
 171
 172        return uvcg_video_pump(video);
 173}
 174
 175static int
 176uvc_v4l2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 177{
 178        struct video_device *vdev = video_devdata(file);
 179        struct uvc_device *uvc = video_get_drvdata(vdev);
 180        struct uvc_video *video = &uvc->video;
 181
 182        return uvcg_dequeue_buffer(&video->queue, b, file->f_flags & O_NONBLOCK);
 183}
 184
 185static int
 186uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 187{
 188        struct video_device *vdev = video_devdata(file);
 189        struct uvc_device *uvc = video_get_drvdata(vdev);
 190        struct uvc_video *video = &uvc->video;
 191        int ret;
 192
 193        if (type != video->queue.queue.type)
 194                return -EINVAL;
 195
 196        /* Enable UVC video. */
 197        ret = uvcg_video_enable(video, 1);
 198        if (ret < 0)
 199                return ret;
 200
 201        /*
 202         * Complete the alternate setting selection setup phase now that
 203         * userspace is ready to provide video frames.
 204         */
 205        uvc_function_setup_continue(uvc);
 206        uvc->state = UVC_STATE_STREAMING;
 207
 208        return 0;
 209}
 210
 211static int
 212uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 213{
 214        struct video_device *vdev = video_devdata(file);
 215        struct uvc_device *uvc = video_get_drvdata(vdev);
 216        struct uvc_video *video = &uvc->video;
 217
 218        if (type != video->queue.queue.type)
 219                return -EINVAL;
 220
 221        return uvcg_video_enable(video, 0);
 222}
 223
 224static int
 225uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
 226                         const struct v4l2_event_subscription *sub)
 227{
 228        if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
 229                return -EINVAL;
 230
 231        return v4l2_event_subscribe(fh, sub, 2, NULL);
 232}
 233
 234static int
 235uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
 236                           const struct v4l2_event_subscription *sub)
 237{
 238        return v4l2_event_unsubscribe(fh, sub);
 239}
 240
 241static long
 242uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
 243                       unsigned int cmd, void *arg)
 244{
 245        struct video_device *vdev = video_devdata(file);
 246        struct uvc_device *uvc = video_get_drvdata(vdev);
 247
 248        switch (cmd) {
 249        case UVCIOC_SEND_RESPONSE:
 250                return uvc_send_response(uvc, arg);
 251
 252        default:
 253                return -ENOIOCTLCMD;
 254        }
 255}
 256
 257const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
 258        .vidioc_querycap = uvc_v4l2_querycap,
 259        .vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
 260        .vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
 261        .vidioc_reqbufs = uvc_v4l2_reqbufs,
 262        .vidioc_querybuf = uvc_v4l2_querybuf,
 263        .vidioc_qbuf = uvc_v4l2_qbuf,
 264        .vidioc_dqbuf = uvc_v4l2_dqbuf,
 265        .vidioc_streamon = uvc_v4l2_streamon,
 266        .vidioc_streamoff = uvc_v4l2_streamoff,
 267        .vidioc_subscribe_event = uvc_v4l2_subscribe_event,
 268        .vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event,
 269        .vidioc_default = uvc_v4l2_ioctl_default,
 270};
 271
 272/* --------------------------------------------------------------------------
 273 * V4L2
 274 */
 275
 276static int
 277uvc_v4l2_open(struct file *file)
 278{
 279        struct video_device *vdev = video_devdata(file);
 280        struct uvc_device *uvc = video_get_drvdata(vdev);
 281        struct uvc_file_handle *handle;
 282
 283        handle = kzalloc(sizeof(*handle), GFP_KERNEL);
 284        if (handle == NULL)
 285                return -ENOMEM;
 286
 287        v4l2_fh_init(&handle->vfh, vdev);
 288        v4l2_fh_add(&handle->vfh);
 289
 290        handle->device = &uvc->video;
 291        file->private_data = &handle->vfh;
 292
 293        uvc_function_connect(uvc);
 294        return 0;
 295}
 296
 297static int
 298uvc_v4l2_release(struct file *file)
 299{
 300        struct video_device *vdev = video_devdata(file);
 301        struct uvc_device *uvc = video_get_drvdata(vdev);
 302        struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
 303        struct uvc_video *video = handle->device;
 304
 305        uvc_function_disconnect(uvc);
 306
 307        mutex_lock(&video->mutex);
 308        uvcg_video_enable(video, 0);
 309        uvcg_free_buffers(&video->queue);
 310        mutex_unlock(&video->mutex);
 311
 312        file->private_data = NULL;
 313        v4l2_fh_del(&handle->vfh);
 314        v4l2_fh_exit(&handle->vfh);
 315        kfree(handle);
 316
 317        return 0;
 318}
 319
 320static int
 321uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 322{
 323        struct video_device *vdev = video_devdata(file);
 324        struct uvc_device *uvc = video_get_drvdata(vdev);
 325
 326        return uvcg_queue_mmap(&uvc->video.queue, vma);
 327}
 328
 329static __poll_t
 330uvc_v4l2_poll(struct file *file, poll_table *wait)
 331{
 332        struct video_device *vdev = video_devdata(file);
 333        struct uvc_device *uvc = video_get_drvdata(vdev);
 334
 335        return uvcg_queue_poll(&uvc->video.queue, file, wait);
 336}
 337
 338#ifndef CONFIG_MMU
 339static unsigned long uvcg_v4l2_get_unmapped_area(struct file *file,
 340                unsigned long addr, unsigned long len, unsigned long pgoff,
 341                unsigned long flags)
 342{
 343        struct video_device *vdev = video_devdata(file);
 344        struct uvc_device *uvc = video_get_drvdata(vdev);
 345
 346        return uvcg_queue_get_unmapped_area(&uvc->video.queue, pgoff);
 347}
 348#endif
 349
 350const struct v4l2_file_operations uvc_v4l2_fops = {
 351        .owner          = THIS_MODULE,
 352        .open           = uvc_v4l2_open,
 353        .release        = uvc_v4l2_release,
 354        .unlocked_ioctl = video_ioctl2,
 355        .mmap           = uvc_v4l2_mmap,
 356        .poll           = uvc_v4l2_poll,
 357#ifndef CONFIG_MMU
 358        .get_unmapped_area = uvcg_v4l2_get_unmapped_area,
 359#endif
 360};
 361
 362