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

Commit 7cd5a16b authored by Stanimir Varbanov's avatar Stanimir Varbanov Committed by Mauro Carvalho Chehab
Browse files

[media] v4l: Create v4l2 subdev file handle structure



Used for storing subdev information per file handle and hold V4L2 file
handle.

Signed-off-by: default avatarStanimir Varbanov <svarbanov@mm-sol.com>
Signed-off-by: default avatarAntti Koskipaa <akoskipa@gmail.com>
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent dacdde78
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -53,6 +53,15 @@ config VIDEO_V4L2_COMMON
	depends on (I2C || I2C=n) && VIDEO_DEV
	default (I2C || I2C=n) && VIDEO_DEV

config VIDEO_V4L2_SUBDEV_API
	bool "V4L2 sub-device userspace API (EXPERIMENTAL)"
	depends on VIDEO_DEV && MEDIA_CONTROLLER && EXPERIMENTAL
	---help---
	  Enables the V4L2 sub-device pad-level userspace API used to configure
	  video format, size and frame rate between hardware blocks.

	  This API is mostly used by camera interfaces in embedded platforms.

#
# DVB Core
#
+58 −27
Original line number Diff line number Diff line
@@ -31,36 +31,66 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>

static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
	/* Allocate try format and crop in the same memory block */
	fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
			      * sd->entity.num_pads, GFP_KERNEL);
	if (fh->try_fmt == NULL)
		return -ENOMEM;

	fh->try_crop = (struct v4l2_rect *)
		(fh->try_fmt + sd->entity.num_pads);
#endif
	return 0;
}

static void subdev_fh_free(struct v4l2_subdev_fh *fh)
{
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
	kfree(fh->try_fmt);
	fh->try_fmt = NULL;
	fh->try_crop = NULL;
#endif
}

static int subdev_open(struct file *file)
{
	struct video_device *vdev = video_devdata(file);
	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
	struct v4l2_subdev_fh *subdev_fh;
#if defined(CONFIG_MEDIA_CONTROLLER)
	struct media_entity *entity;
#endif
	struct v4l2_fh *vfh = NULL;
	int ret;

	if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
		vfh = kzalloc(sizeof(*vfh), GFP_KERNEL);
		if (vfh == NULL)
	subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL);
	if (subdev_fh == NULL)
		return -ENOMEM;

		ret = v4l2_fh_init(vfh, vdev);
	ret = subdev_fh_init(subdev_fh, sd);
	if (ret) {
		kfree(subdev_fh);
		return ret;
	}

	ret = v4l2_fh_init(&subdev_fh->vfh, vdev);
	if (ret)
		goto err;

		ret = v4l2_event_init(vfh);
	if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) {
		ret = v4l2_event_init(&subdev_fh->vfh);
		if (ret)
			goto err;

		ret = v4l2_event_alloc(vfh, sd->nevents);
		ret = v4l2_event_alloc(&subdev_fh->vfh, sd->nevents);
		if (ret)
			goto err;

		v4l2_fh_add(vfh);
		file->private_data = vfh;
	}

	v4l2_fh_add(&subdev_fh->vfh);
	file->private_data = &subdev_fh->vfh;
#if defined(CONFIG_MEDIA_CONTROLLER)
	if (sd->v4l2_dev->mdev) {
		entity = media_entity_get(&sd->entity);
@@ -70,14 +100,14 @@ static int subdev_open(struct file *file)
		}
	}
#endif

	return 0;

err:
	if (vfh != NULL) {
		v4l2_fh_del(vfh);
		v4l2_fh_exit(vfh);
		kfree(vfh);
	}
	v4l2_fh_del(&subdev_fh->vfh);
	v4l2_fh_exit(&subdev_fh->vfh);
	subdev_fh_free(subdev_fh);
	kfree(subdev_fh);

	return ret;
}
@@ -89,16 +119,17 @@ static int subdev_close(struct file *file)
	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
#endif
	struct v4l2_fh *vfh = file->private_data;
	struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);

#if defined(CONFIG_MEDIA_CONTROLLER)
	if (sd->v4l2_dev->mdev)
		media_entity_put(&sd->entity);
#endif
	if (vfh != NULL) {
	v4l2_fh_del(vfh);
	v4l2_fh_exit(vfh);
		kfree(vfh);
	}
	subdev_fh_free(subdev_fh);
	kfree(subdev_fh);
	file->private_data = NULL;

	return 0;
}
@@ -107,7 +138,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
	struct video_device *vdev = video_devdata(file);
	struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);
	struct v4l2_fh *fh = file->private_data;
	struct v4l2_fh *vfh = file->private_data;

	switch (cmd) {
	case VIDIOC_QUERYCTRL:
@@ -135,13 +166,13 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
		if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS))
			return -ENOIOCTLCMD;

		return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK);
		return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);

	case VIDIOC_SUBSCRIBE_EVENT:
		return v4l2_subdev_call(sd, core, subscribe_event, fh, arg);
		return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);

	case VIDIOC_UNSUBSCRIBE_EVENT:
		return v4l2_subdev_call(sd, core, unsubscribe_event, fh, arg);
		return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);

	default:
		return -ENOIOCTLCMD;
+29 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <media/media-entity.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-mediabus.h>

/* generic v4l2_device notify callback notification values */
@@ -481,6 +482,34 @@ struct v4l2_subdev {
#define vdev_to_v4l2_subdev(vdev) \
	container_of(vdev, struct v4l2_subdev, devnode)

/*
 * Used for storing subdev information per file handle
 */
struct v4l2_subdev_fh {
	struct v4l2_fh vfh;
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
	struct v4l2_mbus_framefmt *try_fmt;
	struct v4l2_rect *try_crop;
#endif
};

#define to_v4l2_subdev_fh(fh)	\
	container_of(fh, struct v4l2_subdev_fh, vfh)

#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
static inline struct v4l2_mbus_framefmt *
v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
{
	return &fh->try_fmt[pad];
}

static inline struct v4l2_rect *
v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
{
	return &fh->try_crop[pad];
}
#endif

extern const struct v4l2_file_operations v4l2_subdev_fops;

static inline void v4l2_set_subdevdata(struct v4l2_subdev *sd, void *p)