V4L/DVB (12378): uvcvideo: Restructure the driver to support multiple simultaneous streams.

As a first step towards multiple streaming interfaces support, reorganize the
driver's data structures to cleanly separate video control and video streaming
data.

Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 87cb9cc..7e847bb 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -103,7 +103,7 @@
 	return interval;
 }
 
-static int uvc_v4l2_try_format(struct uvc_video_device *video,
+static int uvc_v4l2_try_format(struct uvc_streaming *stream,
 	struct v4l2_format *fmt, struct uvc_streaming_control *probe,
 	struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
 {
@@ -116,7 +116,7 @@
 	int ret = 0;
 	__u8 *fcc;
 
-	if (fmt->type != video->streaming->type)
+	if (fmt->type != stream->type)
 		return -EINVAL;
 
 	fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
@@ -126,8 +126,8 @@
 			fmt->fmt.pix.width, fmt->fmt.pix.height);
 
 	/* Check if the hardware supports the requested format. */
-	for (i = 0; i < video->streaming->nformats; ++i) {
-		format = &video->streaming->format[i];
+	for (i = 0; i < stream->nformats; ++i) {
+		format = &stream->format[i];
 		if (format->fcc == fmt->fmt.pix.pixelformat)
 			break;
 	}
@@ -191,12 +191,13 @@
 	 * developers test their webcams with the Linux driver as well as with
 	 * the Windows driver).
 	 */
-	if (video->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
+	if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
 		probe->dwMaxVideoFrameSize =
-			video->streaming->ctrl.dwMaxVideoFrameSize;
+			stream->ctrl.dwMaxVideoFrameSize;
 
 	/* Probe the device. */
-	if ((ret = uvc_probe_video(video, probe)) < 0)
+	ret = uvc_probe_video(stream, probe);
+	if (ret < 0)
 		goto done;
 
 	fmt->fmt.pix.width = frame->wWidth;
@@ -216,13 +217,13 @@
 	return ret;
 }
 
-static int uvc_v4l2_get_format(struct uvc_video_device *video,
+static int uvc_v4l2_get_format(struct uvc_streaming *stream,
 	struct v4l2_format *fmt)
 {
-	struct uvc_format *format = video->streaming->cur_format;
-	struct uvc_frame *frame = video->streaming->cur_frame;
+	struct uvc_format *format = stream->cur_format;
+	struct uvc_frame *frame = stream->cur_frame;
 
-	if (fmt->type != video->streaming->type)
+	if (fmt->type != stream->type)
 		return -EINVAL;
 
 	if (format == NULL || frame == NULL)
@@ -233,14 +234,14 @@
 	fmt->fmt.pix.height = frame->wHeight;
 	fmt->fmt.pix.field = V4L2_FIELD_NONE;
 	fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
-	fmt->fmt.pix.sizeimage = video->streaming->ctrl.dwMaxVideoFrameSize;
+	fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize;
 	fmt->fmt.pix.colorspace = format->colorspace;
 	fmt->fmt.pix.priv = 0;
 
 	return 0;
 }
 
-static int uvc_v4l2_set_format(struct uvc_video_device *video,
+static int uvc_v4l2_set_format(struct uvc_streaming *stream,
 	struct v4l2_format *fmt)
 {
 	struct uvc_streaming_control probe;
@@ -248,39 +249,39 @@
 	struct uvc_frame *frame;
 	int ret;
 
-	if (fmt->type != video->streaming->type)
+	if (fmt->type != stream->type)
 		return -EINVAL;
 
-	if (uvc_queue_allocated(&video->queue))
+	if (uvc_queue_allocated(&stream->queue))
 		return -EBUSY;
 
-	ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
+	ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
 	if (ret < 0)
 		return ret;
 
-	memcpy(&video->streaming->ctrl, &probe, sizeof probe);
-	video->streaming->cur_format = format;
-	video->streaming->cur_frame = frame;
+	memcpy(&stream->ctrl, &probe, sizeof probe);
+	stream->cur_format = format;
+	stream->cur_frame = frame;
 
 	return 0;
 }
 
-static int uvc_v4l2_get_streamparm(struct uvc_video_device *video,
+static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
 		struct v4l2_streamparm *parm)
 {
 	uint32_t numerator, denominator;
 
-	if (parm->type != video->streaming->type)
+	if (parm->type != stream->type)
 		return -EINVAL;
 
-	numerator = video->streaming->ctrl.dwFrameInterval;
+	numerator = stream->ctrl.dwFrameInterval;
 	denominator = 10000000;
 	uvc_simplify_fraction(&numerator, &denominator, 8, 333);
 
 	memset(parm, 0, sizeof *parm);
-	parm->type = video->streaming->type;
+	parm->type = stream->type;
 
-	if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+	if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
 		parm->parm.capture.capturemode = 0;
 		parm->parm.capture.timeperframe.numerator = numerator;
@@ -297,19 +298,19 @@
 	return 0;
 }
 
-static int uvc_v4l2_set_streamparm(struct uvc_video_device *video,
+static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
 		struct v4l2_streamparm *parm)
 {
-	struct uvc_frame *frame = video->streaming->cur_frame;
+	struct uvc_frame *frame = stream->cur_frame;
 	struct uvc_streaming_control probe;
 	struct v4l2_fract timeperframe;
 	uint32_t interval;
 	int ret;
 
-	if (parm->type != video->streaming->type)
+	if (parm->type != stream->type)
 		return -EINVAL;
 
-	if (uvc_queue_streaming(&video->queue))
+	if (uvc_queue_streaming(&stream->queue))
 		return -EBUSY;
 
 	if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -317,7 +318,7 @@
 	else
 		timeperframe = parm->parm.output.timeperframe;
 
-	memcpy(&probe, &video->streaming->ctrl, sizeof probe);
+	memcpy(&probe, &stream->ctrl, sizeof probe);
 	interval = uvc_fraction_to_interval(timeperframe.numerator,
 		timeperframe.denominator);
 
@@ -326,10 +327,11 @@
 	probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
 
 	/* Probe the device with the new settings. */
-	if ((ret = uvc_probe_video(video, &probe)) < 0)
+	ret = uvc_probe_video(stream, &probe);
+	if (ret < 0)
 		return ret;
 
-	memcpy(&video->streaming->ctrl, &probe, sizeof probe);
+	memcpy(&stream->ctrl, &probe, sizeof probe);
 
 	/* Return the actual frame period. */
 	timeperframe.numerator = probe.dwFrameInterval;
@@ -382,8 +384,8 @@
 
 	/* Check if the device already has a privileged handle. */
 	mutex_lock(&uvc_driver.open_mutex);
-	if (atomic_inc_return(&handle->device->active) != 1) {
-		atomic_dec(&handle->device->active);
+	if (atomic_inc_return(&handle->stream->active) != 1) {
+		atomic_dec(&handle->stream->active);
 		ret = -EBUSY;
 		goto done;
 	}
@@ -398,7 +400,7 @@
 static void uvc_dismiss_privileges(struct uvc_fh *handle)
 {
 	if (handle->state == UVC_HANDLE_ACTIVE)
-		atomic_dec(&handle->device->active);
+		atomic_dec(&handle->stream->active);
 
 	handle->state = UVC_HANDLE_PASSIVE;
 }
@@ -414,45 +416,47 @@
 
 static int uvc_v4l2_open(struct file *file)
 {
-	struct uvc_video_device *video;
+	struct uvc_streaming *stream;
 	struct uvc_fh *handle;
 	int ret = 0;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
 	mutex_lock(&uvc_driver.open_mutex);
-	video = video_drvdata(file);
+	stream = video_drvdata(file);
 
-	if (video->dev->state & UVC_DEV_DISCONNECTED) {
+	if (stream->dev->state & UVC_DEV_DISCONNECTED) {
 		ret = -ENODEV;
 		goto done;
 	}
 
-	ret = usb_autopm_get_interface(video->dev->intf);
+	ret = usb_autopm_get_interface(stream->dev->intf);
 	if (ret < 0)
 		goto done;
 
 	/* Create the device handle. */
 	handle = kzalloc(sizeof *handle, GFP_KERNEL);
 	if (handle == NULL) {
-		usb_autopm_put_interface(video->dev->intf);
+		usb_autopm_put_interface(stream->dev->intf);
 		ret = -ENOMEM;
 		goto done;
 	}
 
-	if (atomic_inc_return(&video->dev->users) == 1) {
-		if ((ret = uvc_status_start(video->dev)) < 0) {
-			usb_autopm_put_interface(video->dev->intf);
-			atomic_dec(&video->dev->users);
+	if (atomic_inc_return(&stream->dev->users) == 1) {
+		ret = uvc_status_start(stream->dev);
+		if (ret < 0) {
+			usb_autopm_put_interface(stream->dev->intf);
+			atomic_dec(&stream->dev->users);
 			kfree(handle);
 			goto done;
 		}
 	}
 
-	handle->device = video;
+	handle->video = &stream->dev->video;
+	handle->stream = stream;
 	handle->state = UVC_HANDLE_PASSIVE;
 	file->private_data = handle;
 
-	kref_get(&video->dev->kref);
+	kref_get(&stream->dev->kref);
 
 done:
 	mutex_unlock(&uvc_driver.open_mutex);
@@ -461,20 +465,20 @@
 
 static int uvc_v4l2_release(struct file *file)
 {
-	struct uvc_video_device *video = video_drvdata(file);
 	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_streaming *stream = handle->stream;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
 
 	/* Only free resources if this is a privileged handle. */
 	if (uvc_has_privileges(handle)) {
-		uvc_video_enable(video, 0);
+		uvc_video_enable(stream, 0);
 
-		mutex_lock(&video->queue.mutex);
-		if (uvc_free_buffers(&video->queue) < 0)
+		mutex_lock(&stream->queue.mutex);
+		if (uvc_free_buffers(&stream->queue) < 0)
 			uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
 					"free buffers.\n");
-		mutex_unlock(&video->queue.mutex);
+		mutex_unlock(&stream->queue.mutex);
 	}
 
 	/* Release the file handle. */
@@ -482,19 +486,20 @@
 	kfree(handle);
 	file->private_data = NULL;
 
-	if (atomic_dec_return(&video->dev->users) == 0)
-		uvc_status_stop(video->dev);
+	if (atomic_dec_return(&stream->dev->users) == 0)
+		uvc_status_stop(stream->dev);
 
-	usb_autopm_put_interface(video->dev->intf);
-	kref_put(&video->dev->kref, uvc_delete);
+	usb_autopm_put_interface(stream->dev->intf);
+	kref_put(&stream->dev->kref, uvc_delete);
 	return 0;
 }
 
 static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
 	struct video_device *vdev = video_devdata(file);
-	struct uvc_video_device *video = video_get_drvdata(vdev);
 	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_video_device *video = handle->video;
+	struct uvc_streaming *stream = handle->stream;
 	long ret = 0;
 
 	switch (cmd) {
@@ -506,10 +511,10 @@
 		memset(cap, 0, sizeof *cap);
 		strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
 		strlcpy(cap->card, vdev->name, sizeof cap->card);
-		usb_make_path(video->dev->udev,
+		usb_make_path(stream->dev->udev,
 			      cap->bus_info, sizeof(cap->bus_info));
 		cap->version = DRIVER_VERSION_NUMBER;
-		if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
 			cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
 					  | V4L2_CAP_STREAMING;
 		else
@@ -703,15 +708,15 @@
 		enum v4l2_buf_type type = fmt->type;
 		__u32 index = fmt->index;
 
-		if (fmt->type != video->streaming->type ||
-		    fmt->index >= video->streaming->nformats)
+		if (fmt->type != stream->type ||
+		    fmt->index >= stream->nformats)
 			return -EINVAL;
 
 		memset(fmt, 0, sizeof(*fmt));
 		fmt->index = index;
 		fmt->type = type;
 
-		format = &video->streaming->format[fmt->index];
+		format = &stream->format[fmt->index];
 		fmt->flags = 0;
 		if (format->flags & UVC_FMT_FLAG_COMPRESSED)
 			fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@@ -729,17 +734,17 @@
 		if ((ret = uvc_acquire_privileges(handle)) < 0)
 			return ret;
 
-		return uvc_v4l2_try_format(video, arg, &probe, NULL, NULL);
+		return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
 	}
 
 	case VIDIOC_S_FMT:
 		if ((ret = uvc_acquire_privileges(handle)) < 0)
 			return ret;
 
-		return uvc_v4l2_set_format(video, arg);
+		return uvc_v4l2_set_format(stream, arg);
 
 	case VIDIOC_G_FMT:
-		return uvc_v4l2_get_format(video, arg);
+		return uvc_v4l2_get_format(stream, arg);
 
 	/* Frame size enumeration */
 	case VIDIOC_ENUM_FRAMESIZES:
@@ -750,10 +755,10 @@
 		int i;
 
 		/* Look for the given pixel format */
-		for (i = 0; i < video->streaming->nformats; i++) {
-			if (video->streaming->format[i].fcc ==
+		for (i = 0; i < stream->nformats; i++) {
+			if (stream->format[i].fcc ==
 					fsize->pixel_format) {
-				format = &video->streaming->format[i];
+				format = &stream->format[i];
 				break;
 			}
 		}
@@ -779,10 +784,10 @@
 		int i;
 
 		/* Look for the given pixel format and frame size */
-		for (i = 0; i < video->streaming->nformats; i++) {
-			if (video->streaming->format[i].fcc ==
+		for (i = 0; i < stream->nformats; i++) {
+			if (stream->format[i].fcc ==
 					fival->pixel_format) {
-				format = &video->streaming->format[i];
+				format = &stream->format[i];
 				break;
 			}
 		}
@@ -832,21 +837,21 @@
 
 	/* Get & Set streaming parameters */
 	case VIDIOC_G_PARM:
-		return uvc_v4l2_get_streamparm(video, arg);
+		return uvc_v4l2_get_streamparm(stream, arg);
 
 	case VIDIOC_S_PARM:
 		if ((ret = uvc_acquire_privileges(handle)) < 0)
 			return ret;
 
-		return uvc_v4l2_set_streamparm(video, arg);
+		return uvc_v4l2_set_streamparm(stream, arg);
 
 	/* Cropping and scaling */
 	case VIDIOC_CROPCAP:
 	{
 		struct v4l2_cropcap *ccap = arg;
-		struct uvc_frame *frame = video->streaming->cur_frame;
+		struct uvc_frame *frame = stream->cur_frame;
 
-		if (ccap->type != video->streaming->type)
+		if (ccap->type != stream->type)
 			return -EINVAL;
 
 		ccap->bounds.left = 0;
@@ -870,16 +875,16 @@
 	{
 		struct v4l2_requestbuffers *rb = arg;
 		unsigned int bufsize =
-			video->streaming->ctrl.dwMaxVideoFrameSize;
+			stream->ctrl.dwMaxVideoFrameSize;
 
-		if (rb->type != video->streaming->type ||
+		if (rb->type != stream->type ||
 		    rb->memory != V4L2_MEMORY_MMAP)
 			return -EINVAL;
 
 		if ((ret = uvc_acquire_privileges(handle)) < 0)
 			return ret;
 
-		ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
+		ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
 		if (ret < 0)
 			return ret;
 
@@ -892,39 +897,40 @@
 	{
 		struct v4l2_buffer *buf = arg;
 
-		if (buf->type != video->streaming->type)
+		if (buf->type != stream->type)
 			return -EINVAL;
 
 		if (!uvc_has_privileges(handle))
 			return -EBUSY;
 
-		return uvc_query_buffer(&video->queue, buf);
+		return uvc_query_buffer(&stream->queue, buf);
 	}
 
 	case VIDIOC_QBUF:
 		if (!uvc_has_privileges(handle))
 			return -EBUSY;
 
-		return uvc_queue_buffer(&video->queue, arg);
+		return uvc_queue_buffer(&stream->queue, arg);
 
 	case VIDIOC_DQBUF:
 		if (!uvc_has_privileges(handle))
 			return -EBUSY;
 
-		return uvc_dequeue_buffer(&video->queue, arg,
+		return uvc_dequeue_buffer(&stream->queue, arg,
 			file->f_flags & O_NONBLOCK);
 
 	case VIDIOC_STREAMON:
 	{
 		int *type = arg;
 
-		if (*type != video->streaming->type)
+		if (*type != stream->type)
 			return -EINVAL;
 
 		if (!uvc_has_privileges(handle))
 			return -EBUSY;
 
-		if ((ret = uvc_video_enable(video, 1)) < 0)
+		ret = uvc_video_enable(stream, 1);
+		if (ret < 0)
 			return ret;
 		break;
 	}
@@ -933,13 +939,13 @@
 	{
 		int *type = arg;
 
-		if (*type != video->streaming->type)
+		if (*type != stream->type)
 			return -EINVAL;
 
 		if (!uvc_has_privileges(handle))
 			return -EBUSY;
 
-		return uvc_video_enable(video, 0);
+		return uvc_video_enable(stream, 0);
 	}
 
 	/* Analog video standards make no sense for digital cameras. */
@@ -1070,7 +1076,9 @@
 
 static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct uvc_video_device *video = video_drvdata(file);
+	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_streaming *stream = handle->stream;
+	struct uvc_video_queue *queue = &stream->queue;
 	struct uvc_buffer *uninitialized_var(buffer);
 	struct page *page;
 	unsigned long addr, start, size;
@@ -1082,15 +1090,15 @@
 	start = vma->vm_start;
 	size = vma->vm_end - vma->vm_start;
 
-	mutex_lock(&video->queue.mutex);
+	mutex_lock(&queue->mutex);
 
-	for (i = 0; i < video->queue.count; ++i) {
-		buffer = &video->queue.buffer[i];
+	for (i = 0; i < queue->count; ++i) {
+		buffer = &queue->buffer[i];
 		if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
 			break;
 	}
 
-	if (i == video->queue.count || size != video->queue.buf_size) {
+	if (i == queue->count || size != queue->buf_size) {
 		ret = -EINVAL;
 		goto done;
 	}
@@ -1101,7 +1109,7 @@
 	 */
 	vma->vm_flags |= VM_IO;
 
-	addr = (unsigned long)video->queue.mem + buffer->buf.m.offset;
+	addr = (unsigned long)queue->mem + buffer->buf.m.offset;
 	while (size > 0) {
 		page = vmalloc_to_page((void *)addr);
 		if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -1117,17 +1125,18 @@
 	uvc_vm_open(vma);
 
 done:
-	mutex_unlock(&video->queue.mutex);
+	mutex_unlock(&queue->mutex);
 	return ret;
 }
 
 static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
 {
-	struct uvc_video_device *video = video_drvdata(file);
+	struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+	struct uvc_streaming *stream = handle->stream;
 
 	uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
 
-	return uvc_queue_poll(&video->queue, file, wait);
+	return uvc_queue_poll(&stream->queue, file, wait);
 }
 
 const struct v4l2_file_operations uvc_fops = {