Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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