Esempio n. 1
0
static void
uvc_gadget_events_process(struct uvc_gadget *gadget)
{
	struct v4l2_event v4l2_event;
	struct uvc_event *uvc_event = (struct uvc_event *)&v4l2_event.u.data;
	struct uvc_request_data resp;
	int ret;

	ret = v4l2_dequeue_event(gadget->out->fd, &v4l2_event);
	if (ret < 0)
		return;

	switch (v4l2_event.type) {
	case UVC_EVENT_CONNECT:
		break;
	case UVC_EVENT_SETUP:
		memset(&resp, 0, sizeof(struct uvc_request_data));
		resp.length = -EL2HLT;
		uvc_gadget_events_process_setup(gadget, &uvc_event->req, &resp);
		uvc_send_response(gadget->out->fd, &resp);
		break;
	case UVC_EVENT_DATA:
		uvc_gadget_events_process_data(gadget, &uvc_event->data);
		break;
	case UVC_EVENT_STREAMON:
		ret = uvc_gadget_reqbufs(gadget->in, NR_VIDEO_BUF);
		if (ret < 0)
			goto unreq_inbuf;
		ret = uvc_gadget_reqbufs(gadget->out, NR_VIDEO_BUF);
		if (ret < 0)
			goto unreq_buf;

		uvc_gadget_stream(gadget->in, VIDEO_STREAM_ON);
		uvc_gadget_stream(gadget->out, VIDEO_STREAM_ON);
		break;
	case UVC_EVENT_DISCONNECT:
	case UVC_EVENT_STREAMOFF:
		uvc_gadget_stream(gadget->out, VIDEO_STREAM_OFF);
		uvc_gadget_reqbufs(gadget->out, 0);

		uvc_gadget_stream(gadget->in, VIDEO_STREAM_OFF);
		uvc_gadget_reqbufs(gadget->in, 0);
		break;
	}

	return;

unreq_buf:
	uvc_gadget_reqbufs(gadget->out, 0);
unreq_inbuf:
	uvc_gadget_reqbufs(gadget->in, 0);
}
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;
}