Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1d27a4b authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Felipe Balbi
Browse files

usb: gadget: f_uvc: Move to video_ioctl2



Simplify ioctl handling by using video_ioctl2.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarAndrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 26a029f2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -414,7 +414,9 @@ uvc_register_video(struct uvc_device *uvc)

	video->v4l2_dev = &uvc->v4l2_dev;
	video->fops = &uvc_v4l2_fops;
	video->ioctl_ops = &uvc_v4l2_ioctl_ops;
	video->release = video_device_release;
	video->vfl_dir = VFL_DIR_TX;
	strlcpy(video->name, cdev->gadget->name, sizeof(video->name));

	uvc->vdev = video;
+157 −141
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
}

/* --------------------------------------------------------------------------
 * V4L2
 * V4L2 ioctls
 */

struct uvc_format
@@ -63,8 +63,29 @@ static struct uvc_format uvc_formats[] = {
};

static int
uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt)
uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct usb_composite_dev *cdev = uvc->func.config->cdev;

	strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
	strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
	strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
		sizeof(cap->bus_info));

	cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;

	return 0;
}

static int
uvc_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *fmt)
{
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_video *video = &uvc->video;

	fmt->fmt.pix.pixelformat = video->fcc;
	fmt->fmt.pix.width = video->width;
	fmt->fmt.pix.height = video->height;
@@ -78,8 +99,11 @@ uvc_v4l2_get_format(struct uvc_video *video, struct v4l2_format *fmt)
}

static int
uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt)
{
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_video *video = &uvc->video;
	struct uvc_format *format;
	unsigned int imagesize;
	unsigned int bpl;
@@ -116,132 +140,62 @@ uvc_v4l2_set_format(struct uvc_video *video, struct v4l2_format *fmt)
}

static int
uvc_v4l2_open(struct file *file)
uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b)
{
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_file_handle *handle;

	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
	if (handle == NULL)
		return -ENOMEM;

	v4l2_fh_init(&handle->vfh, vdev);
	v4l2_fh_add(&handle->vfh);
	struct uvc_video *video = &uvc->video;

	handle->device = &uvc->video;
	file->private_data = &handle->vfh;
	if (b->type != video->queue.queue.type)
		return -EINVAL;

	uvc_function_connect(uvc);
	return 0;
	return uvc_alloc_buffers(&video->queue, b);
}

static int
uvc_v4l2_release(struct file *file)
uvc_v4l2_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
{
	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 uvc_video *video = handle->device;

	uvc_function_disconnect(uvc);

	uvc_video_enable(video, 0);
	uvc_free_buffers(&video->queue);

	file->private_data = NULL;
	v4l2_fh_del(&handle->vfh);
	v4l2_fh_exit(&handle->vfh);
	kfree(handle);
	struct uvc_video *video = &uvc->video;

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

static long
uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
static int
uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
{
	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);
		strlcpy(cap->driver, "g_uvc", sizeof(cap->driver));
		strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card));
		strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev),
			sizeof cap->bus_info);
		cap->version = LINUX_VERSION_CODE;
		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.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.queue.type)
			return -EINVAL;

		return uvc_v4l2_set_format(video, fmt);
	}

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

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

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

		ret = 0;
		break;
	return uvc_video_pump(video);
}

	case VIDIOC_QUERYBUF:
static int
uvc_v4l2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
{
		struct v4l2_buffer *buf = arg;
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_video *video = &uvc->video;

		return uvc_query_buffer(&video->queue, buf);
	return uvc_dequeue_buffer(&video->queue, b, file->f_flags & O_NONBLOCK);
}

	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:
static int
uvc_v4l2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
{
		int *type = arg;
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_video *video = &uvc->video;
	int ret;

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

	/* Enable UVC video. */
@@ -259,49 +213,111 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
	return 0;
}

	case VIDIOC_STREAMOFF:
static int
uvc_v4l2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
{
		int *type = arg;
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_video *video = &uvc->video;

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

	return uvc_video_enable(video, 0);
}

	/* Events */
	case VIDIOC_DQEVENT:
		return v4l2_event_dequeue(&handle->vfh, arg,
					 file->f_flags & O_NONBLOCK);

	case VIDIOC_SUBSCRIBE_EVENT:
static int
uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
			 const struct v4l2_event_subscription *sub)
{
		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);
	return v4l2_event_subscribe(fh, sub, 2, NULL);
}

static int
uvc_v4l2_unsubscribe_event(struct v4l2_fh *fh,
			   const struct v4l2_event_subscription *sub)
{
	return v4l2_event_unsubscribe(fh, sub);
}

	case VIDIOC_UNSUBSCRIBE_EVENT:
		return v4l2_event_unsubscribe(&handle->vfh, arg);
static long
uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio,
		       unsigned int cmd, void *arg)
{
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);

	switch (cmd) {
	case UVCIOC_SEND_RESPONSE:
		ret = uvc_send_response(uvc, arg);
		break;
		return uvc_send_response(uvc, arg);

	default:
		return -ENOIOCTLCMD;
	}
}

	return ret;
static const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = {
	.vidioc_querycap = uvc_v4l2_querycap,
	.vidioc_g_fmt_vid_out = uvc_v4l2_get_format,
	.vidioc_s_fmt_vid_out = uvc_v4l2_set_format,
	.vidioc_reqbufs = uvc_v4l2_reqbufs,
	.vidioc_querybuf = uvc_v4l2_querybuf,
	.vidioc_qbuf = uvc_v4l2_qbuf,
	.vidioc_dqbuf = uvc_v4l2_dqbuf,
	.vidioc_streamon = uvc_v4l2_streamon,
	.vidioc_streamoff = uvc_v4l2_streamoff,
	.vidioc_subscribe_event = uvc_v4l2_subscribe_event,
	.vidioc_unsubscribe_event = uvc_v4l2_unsubscribe_event,
	.vidioc_default = uvc_v4l2_ioctl_default,
};

/* --------------------------------------------------------------------------
 * V4L2
 */

static int
uvc_v4l2_open(struct file *file)
{
	struct video_device *vdev = video_devdata(file);
	struct uvc_device *uvc = video_get_drvdata(vdev);
	struct uvc_file_handle *handle;

	handle = kzalloc(sizeof(*handle), GFP_KERNEL);
	if (handle == NULL)
		return -ENOMEM;

	v4l2_fh_init(&handle->vfh, vdev);
	v4l2_fh_add(&handle->vfh);

	handle->device = &uvc->video;
	file->private_data = &handle->vfh;

	uvc_function_connect(uvc);
	return 0;
}

static long
uvc_v4l2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static int
uvc_v4l2_release(struct file *file)
{
	return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
	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 uvc_video *video = handle->device;

	uvc_function_disconnect(uvc);

	uvc_video_enable(video, 0);
	uvc_free_buffers(&video->queue);

	file->private_data = NULL;
	v4l2_fh_del(&handle->vfh);
	v4l2_fh_exit(&handle->vfh);
	kfree(handle);

	return 0;
}

static int
@@ -338,7 +354,7 @@ static struct v4l2_file_operations uvc_v4l2_fops = {
	.owner		= THIS_MODULE,
	.open		= uvc_v4l2_open,
	.release	= uvc_v4l2_release,
	.ioctl		= uvc_v4l2_ioctl,
	.ioctl		= video_ioctl2,
	.mmap		= uvc_v4l2_mmap,
	.poll		= uvc_v4l2_poll,
#ifndef CONFIG_MMU