diff options
Diffstat (limited to 'drivers/media/usb/uvc')
-rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 24 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_queue.c | 29 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_v4l2.c | 11 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_video.c | 23 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvcvideo.h | 16 |
5 files changed, 91 insertions, 12 deletions
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index c3bb2502225b..ad47c5cb539a 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -108,11 +108,31 @@ static struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_Y16, }, { - .name = "RGB Bayer", + .name = "BGGR Bayer (BY8 )", .guid = UVC_GUID_FORMAT_BY8, .fcc = V4L2_PIX_FMT_SBGGR8, }, { + .name = "BGGR Bayer (BA81)", + .guid = UVC_GUID_FORMAT_BA81, + .fcc = V4L2_PIX_FMT_SBGGR8, + }, + { + .name = "GBRG Bayer (GBRG)", + .guid = UVC_GUID_FORMAT_GBRG, + .fcc = V4L2_PIX_FMT_SGBRG8, + }, + { + .name = "GRBG Bayer (GRBG)", + .guid = UVC_GUID_FORMAT_GRBG, + .fcc = V4L2_PIX_FMT_SGRBG8, + }, + { + .name = "RGGB Bayer (RGGB)", + .guid = UVC_GUID_FORMAT_RGGB, + .fcc = V4L2_PIX_FMT_SRGGB8, + }, + { .name = "RGB565", .guid = UVC_GUID_FORMAT_RGBP, .fcc = V4L2_PIX_FMT_RGB565, @@ -925,7 +945,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, case UVC_VC_HEADER: n = buflen >= 12 ? buffer[11] : 0; - if (buflen < 12 || buflen < 12 + n) { + if (buflen < 12 + n) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d HEADER error\n", udev->devnum, alts->desc.bInterfaceNumber); diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cd962be860ca..6e92d2080255 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -48,12 +48,14 @@ static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, struct uvc_streaming *stream = container_of(queue, struct uvc_streaming, queue); - if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) - *nbuffers = UVC_MAX_VIDEO_BUFFERS; + /* Make sure the image size is large enough. */ + if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize) + return -EINVAL; *nplanes = 1; - sizes[0] = stream->ctrl.dwMaxVideoFrameSize; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage + : stream->ctrl.dwMaxVideoFrameSize; return 0; } @@ -104,15 +106,15 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&queue->irqlock, flags); } -static int uvc_buffer_finish(struct vb2_buffer *vb) +static void uvc_buffer_finish(struct vb2_buffer *vb) { struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); struct uvc_streaming *stream = container_of(queue, struct uvc_streaming, queue); struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf); - uvc_video_clock_update(stream, &vb->v4l2_buf, buf); - return 0; + if (vb->state == VB2_BUF_STATE_DONE) + uvc_video_clock_update(stream, &vb->v4l2_buf, buf); } static void uvc_wait_prepare(struct vb2_queue *vq) @@ -149,7 +151,8 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; - queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC + | V4L2_BUF_FLAG_TSTAMP_SRC_SOE; ret = vb2_queue_init(&queue->queue); if (ret) return ret; @@ -196,6 +199,18 @@ int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) return ret; } +int uvc_create_buffers(struct uvc_video_queue *queue, + struct v4l2_create_buffers *cb) +{ + int ret; + + mutex_lock(&queue->mutex); + ret = vb2_create_bufs(&queue->queue, cb); + mutex_unlock(&queue->mutex); + + return ret; +} + int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) { int ret; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 3afff92804d3..378ae02e593b 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -1000,6 +1000,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) return uvc_query_buffer(&stream->queue, buf); } + case VIDIOC_CREATE_BUFS: + { + struct v4l2_create_buffers *cb = arg; + + ret = uvc_acquire_privileges(handle); + if (ret < 0) + return ret; + + return uvc_create_buffers(&stream->queue, cb); + } + case VIDIOC_QBUF: if (!uvc_has_privileges(handle)) return -EBUSY; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 898c208889cd..8d52baf5952b 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1453,6 +1453,9 @@ static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev, case USB_SPEED_HIGH: psize = usb_endpoint_maxp(&ep->desc); return (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + case USB_SPEED_WIRELESS: + psize = usb_endpoint_maxp(&ep->desc); + return psize; default: psize = usb_endpoint_maxp(&ep->desc); return psize & 0x07ff; @@ -1847,7 +1850,25 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) if (!enable) { uvc_uninit_video(stream, 1); - usb_set_interface(stream->dev->udev, stream->intfnum, 0); + if (stream->intf->num_altsetting > 1) { + usb_set_interface(stream->dev->udev, + stream->intfnum, 0); + } else { + /* UVC doesn't specify how to inform a bulk-based device + * when the video stream is stopped. Windows sends a + * CLEAR_FEATURE(HALT) request to the video streaming + * bulk endpoint, mimic the same behaviour. + */ + unsigned int epnum = stream->header.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK; + unsigned int dir = stream->header.bEndpointAddress + & USB_ENDPOINT_DIR_MASK; + unsigned int pipe; + + pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir; + usb_clear_halt(stream->dev->udev, pipe); + } + uvc_queue_enable(&stream->queue, 0); uvc_video_clock_cleanup(stream); return 0; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 9e35982d099a..b1f69a6d4068 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -94,6 +94,18 @@ #define UVC_GUID_FORMAT_BY8 \ { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BA81 \ + { 'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GBRG \ + { 'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GRBG \ + { 'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RGGB \ + { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} #define UVC_GUID_FORMAT_RGBP \ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} @@ -115,8 +127,6 @@ #define UVC_URBS 5 /* Maximum number of packets per URB. */ #define UVC_MAX_PACKETS 32 -/* Maximum number of video buffers. */ -#define UVC_MAX_VIDEO_BUFFERS 32 /* Maximum status buffer size in bytes of interrupt URB. */ #define UVC_MAX_STATUS_SIZE 16 @@ -616,6 +626,8 @@ extern int uvc_alloc_buffers(struct uvc_video_queue *queue, extern void uvc_free_buffers(struct uvc_video_queue *queue); extern int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf); +extern int uvc_create_buffers(struct uvc_video_queue *queue, + struct v4l2_create_buffers *v4l2_cb); extern int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *v4l2_buf); extern int uvc_dequeue_buffer(struct uvc_video_queue *queue, |