static int
uvc_video_enable(struct uvc_video *video, int enable)
{
	unsigned int i;
	int ret;

	if (video->ep == NULL) {
		printk(KERN_INFO "Video enable failed, device is "
			"uninitialized.\n");
		return -ENODEV;
	}

	if (!enable) {
		for (i = 0; i < UVC_NUM_REQUESTS; ++i)
			usb_ep_dequeue(video->ep, video->req[i]);

		uvc_video_free_requests(video);
		uvc_queue_enable(&video->queue, 0);
		return 0;
	}

	if ((ret = uvc_queue_enable(&video->queue, 1)) < 0)
		return ret;

	if ((ret = uvc_video_alloc_requests(video)) < 0)
		return ret;

	if (video->max_payload_size) {
		video->encode = uvc_video_encode_bulk;
		video->payload_size = 0;
	} else
		video->encode = uvc_video_encode_isoc;

	return uvc_video_pump(video);
}
Esempio n. 2
0
static long
uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_file_handle *handle = to_uvc_file_handle(file->private_data);
	struct usb_composite_dev *cdev = uvc->func.config->cdev;
	struct uvc_video *video = &uvc->video;
	int ret = 0;

	switch (cmd) {
	/* Query capabilities */
	case VIDIOC_QUERYCAP:
	{
		struct v4l2_capability *cap = arg;

		memset(cap, 0, sizeof *cap);
		strncpy(cap->driver, "g_uvc", sizeof(cap->driver));
		strncpy(cap->card, cdev->gadget->name, sizeof(cap->card));
		strncpy(cap->bus_info, dev_name(&cdev->gadget->dev),
			sizeof cap->bus_info);
		cap->version = DRIVER_VERSION_NUMBER;
		cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
		break;
	}

	/* Get & Set format */
	case VIDIOC_G_FMT:
	{
		struct v4l2_format *fmt = arg;

		if (fmt->type != video->queue.type)
			return -EINVAL;

		return uvc_v4l2_get_format(video, fmt);
	}

	case VIDIOC_S_FMT:
	{
		struct v4l2_format *fmt = arg;

		if (fmt->type != video->queue.type)
			return -EINVAL;

		return uvc_v4l2_set_format(video, fmt);
	}

	/* Buffers & streaming */
	case VIDIOC_REQBUFS:
	{
		struct v4l2_requestbuffers *rb = arg;

		if (rb->type != video->queue.type ||
		    rb->memory != V4L2_MEMORY_MMAP)
			return -EINVAL;

		ret = uvc_alloc_buffers(&video->queue, rb->count,
					video->imagesize);
		if (ret < 0)
			return ret;

		rb->count = ret;
		ret = 0;
		break;
	}

	case VIDIOC_QUERYBUF:
	{
		struct v4l2_buffer *buf = arg;

		if (buf->type != video->queue.type)
			return -EINVAL;

		return uvc_query_buffer(&video->queue, buf);
	}

	case VIDIOC_QBUF:
		if ((ret = uvc_queue_buffer(&video->queue, arg)) < 0)
			return ret;

		return uvc_video_pump(video);

	case VIDIOC_DQBUF:
		return uvc_dequeue_buffer(&video->queue, arg,
			file->f_flags & O_NONBLOCK);

	case VIDIOC_STREAMON:
	{
		int *type = arg;

		if (*type != video->queue.type)
			return -EINVAL;

		return uvc_video_enable(video, 1);
	}

	case VIDIOC_STREAMOFF:
	{
		int *type = arg;

		if (*type != video->queue.type)
			return -EINVAL;

		return uvc_video_enable(video, 0);
	}

	/* Events */
        case VIDIOC_DQEVENT:
	{
		struct v4l2_event *event = arg;

		ret = v4l2_event_dequeue(&handle->vfh, event,
					 file->f_flags & O_NONBLOCK);
		if (ret == 0 && event->type == UVC_EVENT_SETUP) {
			struct uvc_event *uvc_event = (void *)&event->u.data;

			/* Tell the complete callback to generate an event for
			 * the next request that will be enqueued by
			 * uvc_event_write.
			 */
			uvc->event_setup_out =
				!(uvc_event->req.bRequestType & USB_DIR_IN);
			uvc->event_length = uvc_event->req.wLength;
		}

		return ret;
	}

	case VIDIOC_SUBSCRIBE_EVENT:
	{
		struct v4l2_event_subscription *sub = arg;

		if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
			return -EINVAL;

		return v4l2_event_subscribe(&handle->vfh, arg, 2, NULL);
	}

	case VIDIOC_UNSUBSCRIBE_EVENT:
		return v4l2_event_unsubscribe(&handle->vfh, arg);

	case UVCIOC_SEND_RESPONSE:
		ret = uvc_send_response(uvc, arg);
		break;

	default:
		return -ENOIOCTLCMD;
	}

	return ret;
}