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        schedule_work(&video->pump);
 173
 174        return ret;
 175}
 176
 177static int
 178uvc_v4l2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
 179{
 180        struct video_device *vdev = video_devdata(file);
 181        struct uvc_device *uvc = video_get_drvdata(vdev);
 182        struct uvc_video *video = &uvc->video;
 183
 184        return uvcg_dequeue_buffer(&video->queue, b, file->f_flags & O_NONBLOCK);
 185}
 186
 187static int
 188uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
 189{
 190        struct video_device *vdev = video_devdata(file);
 191        struct uvc_device *uvc = video_get_drvdata(vdev);
 192        struct uvc_video *video = &uvc->video;
 193        int ret;
 194
 195        if (type != video->queue.queue.type)
 196                return -EINVAL;
 197
 198        /* Enable UVC video. */
 199        ret = uvcg_video_enable(video, 1);
 200        if (ret < 0)
 201                return ret;
 202
 203        /*
 204         * Complete the alternate setting selection setup phase now that
 205         * userspace is ready to provide video frames.
 206         */
 207        uvc_function_setup_continue(uvc);
 208        uvc->state = UVC_STATE_STREAMING;
 209
 210        return 0;
 211}
 212
 213static int
 214uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
 215{
 216        struct video_device *vdev = video_devdata(file);
 217        struct uvc_device *uvc = video_get_drvdata(vdev);
 218        struct uvc_video *video = &uvc->video;
 219
 220        if (type != video->queue.queue.type)
 221                return -EINVAL;
 222
 223        return uvcg_video_enable(video, 0);
 224}
 225
 226static int
 227uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
 228                         const struct v4l2_event_subscription *sub)
 229{
 230        if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
 231                return -EINVAL;
 232
 233        return v4l2_event_subscribe(fh, sub, 2, NULL);
 234}
 235
 236static int
 237uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
 238                           const struct v4l2_event_subscription *sub)
 239{
 240        return v4l2_event_unsubscribe(fh, sub);
 241}
 242
 243static long
 244uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
 245                       unsigned int cmd, void *arg)
 246{
 247        struct video_device *vdev = video_devdata(file);
 248        struct uvc_device *uvc = video_get_drvdata(vdev);
 249
 250        switch (cmd) {
 251        case UVCIOC_SEND_RESPONSE:
 252                return uvc_send_response(uvc, arg);
 253
 254        default:
 255                return -ENOIOCTLCMD;
 256        }
 257}
 258
 259const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
 260        .vidioc_querycap = uvc_v4l2_querycap,
 261        .vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
 262        .vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
 263        .vidioc_reqbufs = uvc_v4l2_reqbufs,
 264        .vidioc_querybuf = uvc_v4l2_querybuf,
 265        .vidioc_qbuf = uvc_v4l2_qbuf,
 266        .vidioc_dqbuf = uvc_v4l2_dqbuf,
 267        .vidioc_streamon = uvc_v4l2_streamon,
 268        .vidioc_streamoff = uvc_v4l2_streamoff,
 269        .vidioc_subscribe_event = uvc_v4l2_subscribe_event,
 270        .vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event,
 271        .vidioc_default = uvc_v4l2_ioctl_default,
 272};
 273
 274/* --------------------------------------------------------------------------
 275 * V4L2
 276 */
 277
 278static int
 279uvc_v4l2_open(struct file *file)
 280{
 281        struct video_device *vdev = video_devdata(file);
 282        struct uvc_device *uvc = video_get_drvdata(vdev);
 283        struct uvc_file_handle *handle;
 284
 285        handle = kzalloc(sizeof(*handle), GFP_KERNEL);
 286        if (handle == NULL)
 287                return -ENOMEM;
 288
 289        v4l2_fh_init(&handle->vfh, vdev);
 290        v4l2_fh_add(&handle->vfh);
 291
 292        handle->device = &uvc->video;
 293        file->private_data = &handle->vfh;
 294
 295        uvc_function_connect(uvc);
 296        return 0;
 297}
 298
 299static int
 300uvc_v4l2_release(struct file *file)
 301{
 302        struct video_device *vdev = video_devdata(file);
 303        struct uvc_device *uvc = video_get_drvdata(vdev);
 304        struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
 305        struct uvc_video *video = handle->device;
 306
 307        uvc_function_disconnect(uvc);
 308
 309        mutex_lock(&video->mutex);
 310        uvcg_video_enable(video, 0);
 311        uvcg_free_buffers(&video->queue);
 312        mutex_unlock(&video->mutex);
 313
 314        file->private_data = NULL;
 315        v4l2_fh_del(&handle->vfh);
 316        v4l2_fh_exit(&handle->vfh);
 317        kfree(handle);
 318
 319        return 0;
 320}
 321
 322static int
 323uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 324{
 325        struct video_device *vdev = video_devdata(file);
 326        struct uvc_device *uvc = video_get_drvdata(vdev);
 327
 328        return uvcg_queue_mmap(&uvc->video.queue, vma);
 329}
 330
 331static __poll_t
 332uvc_v4l2_poll(struct file *file, poll_table *wait)
 333{
 334        struct video_device *vdev = video_devdata(file);
 335        struct uvc_device *uvc = video_get_drvdata(vdev);
 336
 337        return uvcg_queue_poll(&uvc->video.queue, file, wait);
 338}
 339
 340#ifndef CONFIG_MMU
 341static unsigned long uvcg_v4l2_get_unmapped_area(struct file *file,
 342                unsigned long addr, unsigned long len, unsigned long pgoff,
 343                unsigned long flags)
 344{
 345        struct video_device *vdev = video_devdata(file);
 346        struct uvc_device *uvc = video_get_drvdata(vdev);
 347
 348        return uvcg_queue_get_unmapped_area(&uvc->video.queue, pgoff);
 349}
 350#endif
 351
 352const struct v4l2_file_operations uvc_v4l2_fops = {
 353        .owner          = THIS_MODULE,
 354        .open           = uvc_v4l2_open,
 355        .release        = uvc_v4l2_release,
 356        .unlocked_ioctl = video_ioctl2,
 357        .mmap           = uvc_v4l2_mmap,
 358        .poll           = uvc_v4l2_poll,
 359#ifndef CONFIG_MMU
 360        .get_unmapped_area = uvcg_v4l2_get_unmapped_area,
 361#endif
 362};
 363
 364