diff options
Diffstat (limited to 'drivers/media/usb/uvc')
| -rw-r--r-- | drivers/media/usb/uvc/uvc_ctrl.c | 4 | ||||
| -rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 42 | ||||
| -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 | 64 | ||||
| -rw-r--r-- | drivers/media/usb/uvc/uvcvideo.h | 16 | 
6 files changed, 139 insertions, 27 deletions
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index a2f4501c23c..0eb82106d2f 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -664,7 +664,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {  		.size		= 32,  		.offset		= 0,  		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER, -		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED, +		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,  	},  	{  		.id		= V4L2_CID_TILT_ABSOLUTE, @@ -674,7 +674,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {  		.size		= 32,  		.offset		= 32,  		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER, -		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED, +		.data_type	= UVC_CTRL_DATA_TYPE_SIGNED,  	},  	{  		.id		= V4L2_CID_PRIVACY, diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 81695d48c13..ad47c5cb539 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); @@ -2090,6 +2110,15 @@ static struct usb_device_id uvc_ids[] = {  	  .bInterfaceSubClass	= 1,  	  .bInterfaceProtocol	= 0,  	  .driver_info		= UVC_QUIRK_PROBE_MINMAX }, +	/* Microsoft Lifecam NX-3000 */ +	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE +				| USB_DEVICE_ID_MATCH_INT_INFO, +	  .idVendor		= 0x045e, +	  .idProduct		= 0x0721, +	  .bInterfaceClass	= USB_CLASS_VIDEO, +	  .bInterfaceSubClass	= 1, +	  .bInterfaceProtocol	= 0, +	  .driver_info		= UVC_QUIRK_PROBE_DEF },  	/* Microsoft Lifecam VX-7000 */  	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE  				| USB_DEVICE_ID_MATCH_INT_INFO, @@ -2174,6 +2203,15 @@ static struct usb_device_id uvc_ids[] = {  	  .bInterfaceSubClass	= 1,  	  .bInterfaceProtocol	= 0,  	  .driver_info 		= UVC_QUIRK_PROBE_DEF }, +	/* Dell SP2008WFP Monitor */ +	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE +				| USB_DEVICE_ID_MATCH_INT_INFO, +	  .idVendor		= 0x05a9, +	  .idProduct		= 0x2641, +	  .bInterfaceClass	= USB_CLASS_VIDEO, +	  .bInterfaceSubClass	= 1, +	  .bInterfaceProtocol	= 0, +	  .driver_info 		= UVC_QUIRK_PROBE_DEF },  	/* Dell Alienware X51 */  	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE  				| USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cd962be860c..6e92d208025 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 3afff92804d..378ae02e593 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 3394c343201..9144a2f3ed8 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -361,6 +361,14 @@ static int uvc_commit_video(struct uvc_streaming *stream,   * Clocks and timestamps   */ +static inline void uvc_video_get_ts(struct timespec *ts) +{ +	if (uvc_clock_param == CLOCK_MONOTONIC) +		ktime_get_ts(ts); +	else +		ktime_get_real_ts(ts); +} +  static void  uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,  		       const __u8 *data, int len) @@ -420,7 +428,7 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,  	stream->clock.last_sof = dev_sof;  	host_sof = usb_get_current_frame_number(stream->dev->udev); -	ktime_get_ts(&ts); +	uvc_video_get_ts(&ts);  	/* The UVC specification allows device implementations that can't obtain  	 * the USB frame number to keep their own frame counters as long as they @@ -556,7 +564,7 @@ static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample)   *   * SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1)   (1)   * - * to avoid loosing precision in the division. Similarly, the host timestamp is + * to avoid losing precision in the division. Similarly, the host timestamp is   * computed with   *   * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1)	     (2) @@ -680,7 +688,8 @@ void uvc_video_clock_update(struct uvc_streaming *stream,  		  stream->dev->name,  		  sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),  		  y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC, -		  v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec, +		  v4l2_buf->timestamp.tv_sec, +		  (unsigned long)v4l2_buf->timestamp.tv_usec,  		  x1, first->host_sof, first->dev_sof,  		  x2, last->host_sof, last->dev_sof, y1, y2); @@ -1010,10 +1019,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,  			return -ENODATA;  		} -		if (uvc_clock_param == CLOCK_MONOTONIC) -			ktime_get_ts(&ts); -		else -			ktime_get_real_ts(&ts); +		uvc_video_get_ts(&ts);  		buf->buf.v4l2_buf.sequence = stream->sequence;  		buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec; @@ -1132,6 +1138,17 @@ static int uvc_video_encode_data(struct uvc_streaming *stream,   */  /* + * Set error flag for incomplete buffer. + */ +static void uvc_video_validate_buffer(const struct uvc_streaming *stream, +				      struct uvc_buffer *buf) +{ +	if (buf->length != buf->bytesused && +	    !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED)) +		buf->error = 1; +} + +/*   * Completion handler for video URBs.   */  static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, @@ -1155,9 +1172,11 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,  		do {  			ret = uvc_video_decode_start(stream, buf, mem,  				urb->iso_frame_desc[i].actual_length); -			if (ret == -EAGAIN) +			if (ret == -EAGAIN) { +				uvc_video_validate_buffer(stream, buf);  				buf = uvc_queue_next_buffer(&stream->queue,  							    buf); +			}  		} while (ret == -EAGAIN);  		if (ret < 0) @@ -1172,11 +1191,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,  			urb->iso_frame_desc[i].actual_length);  		if (buf->state == UVC_BUF_STATE_READY) { -			if (buf->length != buf->bytesused && -			    !(stream->cur_format->flags & -			      UVC_FMT_FLAG_COMPRESSED)) -				buf->error = 1; - +			uvc_video_validate_buffer(stream, buf);  			buf = uvc_queue_next_buffer(&stream->queue, buf);  		}  	} @@ -1452,6 +1467,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; @@ -1846,7 +1864,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 9e35982d099..b1f69a6d406 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,  | 
