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

Commit 2150158b authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab
Browse files

[media] V4L: add two new ioctl()s for multi-size videobuffer management



A possibility to preallocate and initialise buffers of different sizes
in V4L2 is required for an efficient implementation of a snapshot
mode. This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
VIDIOC_PREPARE_BUF and defines respective data structures.

Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent ebc087d0
Loading
Loading
Loading
Loading
+59 −8
Original line number Diff line number Diff line
@@ -159,11 +159,16 @@ struct v4l2_format32 {
	} fmt;
};

static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
struct v4l2_create_buffers32 {
	__u32			index;		/* output: buffers index...index + count - 1 have been created */
	__u32			count;
	enum v4l2_memory        memory;
	struct v4l2_format32	format;		/* filled in by the user, plane sizes calculated by the driver */
	__u32			reserved[8];
};

static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
			get_user(kp->type, &up->type))
			return -EFAULT;
	switch (kp->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -192,11 +197,24 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
	}
}

static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
		put_user(kp->type, &up->type))
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
			get_user(kp->type, &up->type))
			return -EFAULT;
	return __get_v4l2_format32(kp, up);
}

static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
{
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
	    copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt)))
			return -EFAULT;
	return __get_v4l2_format32(&kp->format, &up->format);
}

static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
	switch (kp->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -225,6 +243,22 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
	}
}

static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
		put_user(kp->type, &up->type))
		return -EFAULT;
	return __put_v4l2_format32(kp, up);
}

static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
	    copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
			return -EFAULT;
	return __put_v4l2_format32(&kp->format, &up->format);
}

struct v4l2_standard32 {
	__u32		     index;
	__u32		     id[2]; /* __u64 would get the alignment wrong */
@@ -702,6 +736,8 @@ static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *u
#define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
#define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
#define	VIDIOC_DQEVENT32	_IOR ('V', 89, struct v4l2_event32)
#define VIDIOC_CREATE_BUFS32	_IOWR('V', 92, struct v4l2_create_buffers32)
#define VIDIOC_PREPARE_BUF32	_IOWR('V', 93, struct v4l2_buffer32)

#define VIDIOC_OVERLAY32	_IOW ('V', 14, s32)
#define VIDIOC_STREAMON32	_IOW ('V', 18, s32)
@@ -721,6 +757,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
		struct v4l2_standard v2s;
		struct v4l2_ext_controls v2ecs;
		struct v4l2_event v2ev;
		struct v4l2_create_buffers v2crt;
		unsigned long vx;
		int vi;
	} karg;
@@ -751,6 +788,8 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
	case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
	case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
	case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
	case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
	}

	switch (cmd) {
@@ -775,6 +814,12 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
		compatible_arg = 0;
		break;

	case VIDIOC_CREATE_BUFS:
		err = get_v4l2_create32(&karg.v2crt, up);
		compatible_arg = 0;
		break;

	case VIDIOC_PREPARE_BUF:
	case VIDIOC_QUERYBUF:
	case VIDIOC_QBUF:
	case VIDIOC_DQBUF:
@@ -860,6 +905,10 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
		err = put_v4l2_format32(&karg.v2f, up);
		break;

	case VIDIOC_CREATE_BUFS:
		err = put_v4l2_create32(&karg.v2crt, up);
		break;

	case VIDIOC_QUERYBUF:
	case VIDIOC_QBUF:
	case VIDIOC_DQBUF:
@@ -959,6 +1008,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
	case VIDIOC_DQEVENT32:
	case VIDIOC_SUBSCRIBE_EVENT:
	case VIDIOC_UNSUBSCRIBE_EVENT:
	case VIDIOC_CREATE_BUFS32:
	case VIDIOC_PREPARE_BUF32:
		ret = do_video_ioctl(file, cmd, arg);
		break;

+36 −0
Original line number Diff line number Diff line
@@ -273,6 +273,8 @@ static const char *v4l2_ioctls[] = {
	[_IOC_NR(VIDIOC_DQEVENT)]	   = "VIDIOC_DQEVENT",
	[_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)]  = "VIDIOC_SUBSCRIBE_EVENT",
	[_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
	[_IOC_NR(VIDIOC_CREATE_BUFS)]      = "VIDIOC_CREATE_BUFS",
	[_IOC_NR(VIDIOC_PREPARE_BUF)]      = "VIDIOC_PREPARE_BUF",
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)

@@ -2104,6 +2106,40 @@ static long __video_do_ioctl(struct file *file,
		dbgarg(cmd, "type=0x%8.8x", sub->type);
		break;
	}
	case VIDIOC_CREATE_BUFS:
	{
		struct v4l2_create_buffers *create = arg;

		if (!ops->vidioc_create_bufs)
			break;
		if (ret_prio) {
			ret = ret_prio;
			break;
		}
		ret = check_fmt(ops, create->format.type);
		if (ret)
			break;

		ret = ops->vidioc_create_bufs(file, fh, create);

		dbgarg(cmd, "count=%d @ %d\n", create->count, create->index);
		break;
	}
	case VIDIOC_PREPARE_BUF:
	{
		struct v4l2_buffer *b = arg;

		if (!ops->vidioc_prepare_buf)
			break;
		ret = check_fmt(ops, b->type);
		if (ret)
			break;

		ret = ops->vidioc_prepare_buf(file, fh, b);

		dbgarg(cmd, "index=%d", b->index);
		break;
	}
	default:
		if (!ops->vidioc_default)
			break;
+18 −0
Original line number Diff line number Diff line
@@ -653,6 +653,10 @@ struct v4l2_buffer {
#define V4L2_BUF_FLAG_ERROR	0x0040
#define V4L2_BUF_FLAG_TIMECODE	0x0100	/* timecode field is valid */
#define V4L2_BUF_FLAG_INPUT     0x0200  /* input field is valid */
#define V4L2_BUF_FLAG_PREPARED	0x0400	/* Buffer is prepared for queuing */
/* Cache handling flags */
#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0800
#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x1000

/*
 *	O V E R L A Y   P R E V I E W
@@ -2138,6 +2142,15 @@ struct v4l2_dbg_chip_ident {
	__u32 revision;    /* chip revision, chip specific */
} __attribute__ ((packed));

/* VIDIOC_CREATE_BUFS */
struct v4l2_create_buffers {
	__u32			index;		/* output: buffers index...index + count - 1 have been created */
	__u32			count;
	enum v4l2_memory        memory;
	struct v4l2_format	format;		/* "type" is used always, the rest if sizeimage == 0 */
	__u32			reserved[8];
};

/*
 *	I O C T L   C O D E S   F O R   V I D E O   D E V I C E S
 *
@@ -2228,6 +2241,11 @@ struct v4l2_dbg_chip_ident {
#define	VIDIOC_SUBSCRIBE_EVENT	 _IOW('V', 90, struct v4l2_event_subscription)
#define	VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)

/* Experimental, the below two ioctls may change over the next couple of kernel
   versions */
#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
#define VIDIOC_PREPARE_BUF	_IOWR('V', 93, struct v4l2_buffer)

/* Reminder: when adding new ioctls please add support for them to
   drivers/media/video/v4l2-compat-ioctl32.c as well! */

+2 −0
Original line number Diff line number Diff line
@@ -122,6 +122,8 @@ struct v4l2_ioctl_ops {
	int (*vidioc_qbuf)    (struct file *file, void *fh, struct v4l2_buffer *b);
	int (*vidioc_dqbuf)   (struct file *file, void *fh, struct v4l2_buffer *b);

	int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b);
	int (*vidioc_prepare_buf)(struct file *file, void *fh, struct v4l2_buffer *b);

	int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
	int (*vidioc_g_fbuf)   (struct file *file, void *fh,