diff mbox

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

Message ID Pine.LNX.4.64.1107201025120.12084@axis700.grange (mailing list archive)
State RFC
Headers show

Commit Message

Guennadi Liakhovetski July 20, 2011, 8:43 a.m. UTC
A possibility to preallocate and initialise buffers of different sizes
in V4L2 is required for an efficient implementation of asnapshot mode.
This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
VIDIOC_PREPARE_BUF and defines respective data structures.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
---

It's been almost a month since v2, the only comments were a request to 
increase the reserved space in the new ioctl() and to improve 
documentation. The reserved field is increased in this version, 
documentation also has been improved in multiple locations. I think, 
documentation can be further improved at any time, but if there are no 
objections against the actual contents of this patch, maybe we can commit 
this version. I still don't see v3.0;-), so, maybe we even can push it for 
3.1. A trivial comparison with v2 shows the size of the reserved field as 
the only change in the API, and the compatibility fix as the only two 
functional changes.

v3: addressed multiple comments by Sakari Ailus

1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
   ints
2. multiple documentation fixes and improvements
3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
   processing

v2:

1. add preliminary Documentation
2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
3. remove VIDIOC_DESTROY_BUFS
4. rename SUBMIT to VIDIOC_PREPARE_BUF
5. add reserved field to struct v4l2_create_buffers
6. cache handling flags moved to struct v4l2_buffer for processing during 
   VIDIOC_PREPARE_BUF
7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument


 Documentation/DocBook/media/v4l/io.xml             |   17 +++
 Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
 .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
 .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
 drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
 drivers/media/video/v4l2-ioctl.c                   |   32 ++++
 include/linux/videodev2.h                          |   16 ++
 include/media/v4l2-ioctl.h                         |    2 +
 8 files changed, 377 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
 create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml

Comments

Sakari Ailus July 20, 2011, 2:30 p.m. UTC | #1
Hi, Guennadi!

Thanks for the patch!

On Wed, Jul 20, 2011 at 10:43:08AM +0200, Guennadi Liakhovetski wrote:
> A possibility to preallocate and initialise buffers of different sizes
> in V4L2 is required for an efficient implementation of asnapshot mode.
> This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> VIDIOC_PREPARE_BUF and defines respective data structures.
> 
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
> 
> It's been almost a month since v2, the only comments were a request to 
> increase the reserved space in the new ioctl() and to improve 
> documentation. The reserved field is increased in this version, 
> documentation also has been improved in multiple locations. I think, 
> documentation can be further improved at any time, but if there are no 
> objections against the actual contents of this patch, maybe we can commit 
> this version. I still don't see v3.0;-), so, maybe we even can push it for 
> 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> the only change in the API, and the compatibility fix as the only two 
> functional changes.
> 
> v3: addressed multiple comments by Sakari Ailus
> 
> 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
>    ints
> 2. multiple documentation fixes and improvements
> 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
>    processing
> 
> v2:
> 
> 1. add preliminary Documentation
> 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> 3. remove VIDIOC_DESTROY_BUFS
> 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> 5. add reserved field to struct v4l2_create_buffers
> 6. cache handling flags moved to struct v4l2_buffer for processing during 
>    VIDIOC_PREPARE_BUF
> 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> 
> 
>  Documentation/DocBook/media/v4l/io.xml             |   17 +++
>  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
>  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
>  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
>  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
>  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
>  include/linux/videodev2.h                          |   16 ++
>  include/media/v4l2-ioctl.h                         |    2 +
>  8 files changed, 377 insertions(+), 8 deletions(-)
>  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
>  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> 
> diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> index 227e7ac..6249d0e 100644
> --- a/Documentation/DocBook/media/v4l/io.xml
> +++ b/Documentation/DocBook/media/v4l/io.xml
> @@ -927,6 +927,23 @@ ioctl is called.</entry>
>  Applications set or clear this flag before calling the
>  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
>  	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> +	    <entry>0x0400</entry>
> +	    <entry>Caches do not have to be invalidated for this buffer.
> +Typically applications shall use this flag, if the data, captured in the buffer
> +is not going to br touched by the CPU, instead the buffer will, probably, be
> +passed on to a DMA-capable hardware unit for further processing or output.
> +</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> +	    <entry>0x0800</entry>
> +	    <entry>Caches do not have to be cleaned for this buffer.
> +Typically applications shall use this flag for output buffers, if the data
> +in this buffer has not been created by the CPU, but by some DMA-capable unit,
> +in which case caches have not been used.</entry>
> +	  </row>
>  	</tbody>
>        </tgroup>
>      </table>
> diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> index 0d05e87..06bb179 100644
> --- a/Documentation/DocBook/media/v4l/v4l2.xml
> +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
>      &sub-close;
>      &sub-ioctl;
>      <!-- All ioctls go here. -->
> +    &sub-create-bufs;
>      &sub-cropcap;
>      &sub-dbg-g-chip-ident;
>      &sub-dbg-g-register;
> @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
>      &sub-queryctrl;
>      &sub-query-dv-preset;
>      &sub-querystd;
> +    &sub-prepare-buf;
>      &sub-reqbufs;
>      &sub-s-hw-freq-seek;
>      &sub-streamon;
> diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> new file mode 100644
> index 0000000..5f0158c
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> @@ -0,0 +1,152 @@
> +<refentry id="vidioc-create-bufs">
> +  <refmeta>
> +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> +    &manvol;
> +  </refmeta>
> +
> +  <refnamediv>
> +    <refname>VIDIOC_CREATE_BUFS</refname>
> +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> +  </refnamediv>
> +
> +  <refsynopsisdiv>
> +    <funcsynopsis>
> +      <funcprototype>
> +	<funcdef>int <function>ioctl</function></funcdef>
> +	<paramdef>int <parameter>fd</parameter></paramdef>
> +	<paramdef>int <parameter>request</parameter></paramdef>
> +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> +      </funcprototype>
> +    </funcsynopsis>
> +  </refsynopsisdiv>
> +
> +  <refsect1>
> +    <title>Arguments</title>
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><parameter>fd</parameter></term>
> +	<listitem>
> +	  <para>&fd;</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>request</parameter></term>
> +	<listitem>
> +	  <para>VIDIOC_CREATE_BUFS</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>argp</parameter></term>
> +	<listitem>
> +	  <para></para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +
> +  <refsect1>
> +    <title>Description</title>
> +
> +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> +mapped</link> or <link linkend="userp">user pointer</link>
> +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> +ioctl, when a tighter control over buffers is required. This ioctl can be called
> +multiple times to create buffers of different sizes.
> +
> +    <para>To allocate device buffers applications initialize all
> +fields of the <structname>v4l2_create_buffers</structname> structure.
> +They set the <structfield>type</structfield> field in the
> +<structname>v4l2_format</structname> structure, embedded in this
> +structure, to the respective stream or buffer type.
> +<structfield>count</structfield> must be set to the number of required
> +buffers. <structfield>memory</structfield> specifies the required I/O
> +method. Applications have two possibilities to specify the size of buffers
> +to be prepared: they can either set the <structfield>size</structfield>
> +field explicitly to a non-zero value, or fill in the frame format data in the
> +<structfield>format</structfield> field. In the latter case buffer sizes
> +will be calculated automatically by the driver. The
> +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> +is called with a pointer to this structure the driver will attempt to allocate
> +up to the requested number of buffers and store the actual number allocated
> +and the starting index in the <structfield>count</structfield> and
> +the <structfield>index</structfield> fields respectively.
> +<structfield>count</structfield> can be smaller than the number requested.
> +-ENOMEM is returned, if the driver runs out of free memory.</para>

No need to mention -ENOMEM here. It's already in the return values below;
the same goes for the EINVAL just below.

> +    <para>When the I/O method is not supported the ioctl
> +returns an &EINVAL;.</para>
> +
> +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> +      <title>struct <structname>v4l2_create_buffers</structname></title>
> +      <tgroup cols="3">
> +	&cs-str;
> +	<tbody valign="top">
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>index</structfield></entry>
> +	    <entry>The starting buffer index, returned by the driver.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>count</structfield></entry>
> +	    <entry>The number of buffers requested or granted.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>&v4l2-memory;</entry>
> +	    <entry><structfield>memory</structfield></entry>
> +	    <entry>Applications set this field to
> +<constant>V4L2_MEMORY_MMAP</constant> or
> +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>size</structfield></entry>
> +	    <entry>Explicit size of buffers, being created.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>&v4l2-format;</entry>
> +	    <entry><structfield>format</structfield></entry>
> +	    <entry>Application has to set the <structfield>type</structfield>
> +field, other fields should be used, if the application wants to allocate buffers
> +for a specific frame format.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>reserved</structfield>[8]</entry>
> +	    <entry>A place holder for future extensions.</entry>
> +	  </row>
> +	</tbody>
> +      </tgroup>
> +    </table>
> +  </refsect1>
> +
> +  <refsect1>
> +    &return-value;
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><errorcode>ENOMEM</errorcode></term>
> +	<listitem>
> +	  <para>No memory to allocate buffers for <link linkend="mmap">memory
> +mapped</link> I/O.</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><errorcode>EINVAL</errorcode></term>
> +	<listitem>
> +	  <para>The buffer type (<structfield>type</structfield> field) or the
> +requested I/O method (<structfield>memory</structfield>) is not
> +supported.</para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +</refentry>
> +
> +<!--
> +Local Variables:
> +mode: sgml
> +sgml-parent-document: "v4l2.sgml"
> +indent-tabs-mode: nil
> +End:
> +-->
> diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> new file mode 100644
> index 0000000..509e752
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> @@ -0,0 +1,96 @@
> +<refentry id="vidioc-prepare-buf">
> +  <refmeta>
> +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> +    &manvol;
> +  </refmeta>
> +
> +  <refnamediv>
> +    <refname>VIDIOC_PREPARE_BUF</refname>
> +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> +  </refnamediv>
> +
> +  <refsynopsisdiv>
> +    <funcsynopsis>
> +      <funcprototype>
> +	<funcdef>int <function>ioctl</function></funcdef>
> +	<paramdef>int <parameter>fd</parameter></paramdef>
> +	<paramdef>int <parameter>request</parameter></paramdef>
> +	<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>

I'm not sure if we want to use struct v4l2_buffer here. It's an obvious
choice, but there's an issue in using it.

The struct is almost full i.e. there are very few reserved fields in it,
namely two, counting the input field which was unused AFAIR. There are now
three ioctls using it as their argument.

Future functionality which would be nice:

- Format counters. Every format set by S_FMT (or gotten by G_FMT) should
  come with a counter value so that the user would know the format of
  dequeued buffers when setting the format on-the-fly. Currently there are
  only bytesperline and length, but the format can't be explicitly
  determined from those.

- Binding to generic DMA buffers. This can likely be achieved by using the m
  union in struct v4l2_buffer. (Speaking of which: these buffers likely have
  a cache behaviour defined for them, e.g. they might be non-cacheable. This
  probably has no effect on the cache flags in V4L2 but it might still be
  good to keep this in mind.)

I don't have an obvious replacement for it either. There are two options I
can see: Create a new struct v4l2_ext_buffer which contains the old
v4l2_buffer plus a bunch of reserved fields, or use the two last fields to
hold a pointer to an extension struct, v4l2_buffer_ext. The new structure
would later be used to contain the reserved fields.

I admit that this is not an issue right now, myt point is that I don't want
this to be an issue in the future either.

> +      </funcprototype>
> +    </funcsynopsis>
> +  </refsynopsisdiv>
> +
> +  <refsect1>
> +    <title>Arguments</title>
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><parameter>fd</parameter></term>
> +	<listitem>
> +	  <para>&fd;</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>request</parameter></term>
> +	<listitem>
> +	  <para>VIDIOC_PREPARE_BUF</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>argp</parameter></term>
> +	<listitem>
> +	  <para></para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +
> +  <refsect1>
> +    <title>Description</title>
> +
> +    <para>Applications can optionally call the
> +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> +to the driver before actually enqueuing it, using the
> +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> +Such preparations may include cache invalidation or cleaning. Performing them
> +in advance saves time during the actual I/O. In case such cache operations are
> +not required, the application can use one of
> +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> +step.</para>
> +
> +    <para>The <structname>v4l2_buffer</structname> structure is
> +specified in <xref linkend="buffer" />.</para>
> +  </refsect1>
> +
> +  <refsect1>
> +    &return-value;
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><errorcode>EBUSY</errorcode></term>
> +	<listitem>
> +	  <para>File I/O is in progress.</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><errorcode>EINVAL</errorcode></term>
> +	<listitem>
> +	  <para>The buffer <structfield>type</structfield> is not
> +supported, or the <structfield>index</structfield> is out of bounds,
> +or no buffers have been allocated yet, or the
> +<structfield>userptr</structfield> or
> +<structfield>length</structfield> are invalid.</para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +</refentry>
> +
> +<!--
> +Local Variables:
> +mode: sgml
> +sgml-parent-document: "v4l2.sgml"
> +indent-tabs-mode: nil
> +End:
> +-->
> diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
> index 61979b7..4105f69 100644
> --- a/drivers/media/video/v4l2-compat-ioctl32.c
> +++ b/drivers/media/video/v4l2-compat-ioctl32.c
> @@ -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;
> +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> +	struct v4l2_format32	format;		/* "type" is used always, the rest if size == 0 */
> +};
> +
> +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_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)
>  {
> -	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
> -		put_user(kp->type, &up->type))
> -		return -EFAULT;
>  	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,11 @@ 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_PREPARE_BUF:
>  	case VIDIOC_QUERYBUF:
>  	case VIDIOC_QBUF:
>  	case VIDIOC_DQBUF:
> @@ -959,6 +1009,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;
>  
> diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
> index 002ce13..7824152 100644
> --- a/drivers/media/video/v4l2-ioctl.c
> +++ b/drivers/media/video/v4l2-ioctl.c
> @@ -260,6 +260,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)
>  
> @@ -2216,6 +2218,36 @@ 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;
> +		ret = check_fmt(ops, create->format.type);
> +		if (ret)
> +			break;
> +
> +		if (create->size)
> +			CLEAR_AFTER_FIELD(create, count);
> +		ret = ops->vidioc_create_bufs(file, fh, create);
> +
> +		dbgarg(cmd, "count=%d\n", create->count);
> +		break;
> +	}
> +	case VIDIOC_PREPARE_BUF:
> +	{
> +		struct v4l2_buffer *b = arg;
> +
> +		if (!ops->vidioc_prepare_buf)
> +			break;
> +
> +		ret = ops->vidioc_prepare_buf(file, fh, b);
> +
> +		dbgarg(cmd, "index=%d", b->index);
> +		break;
> +	}
>  	default:
>  	{
>  		bool valid_prio = true;
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index fca24cc..0b594c7 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -653,6 +653,9 @@ 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 */
> +/* Cache handling flags */
> +#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0400
> +#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x0800
>  
>  /*
>   *	O V E R L A Y   P R E V I E W
> @@ -2092,6 +2095,16 @@ 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;

Aren't enums something to avoid in public APIs? -> __u32?

> +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> +	struct v4l2_format	format;		/* "type" is used always, the rest if size == 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
>   *
> @@ -2182,6 +2195,9 @@ 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)
>  
> +#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
> +#define VIDIOC_PREPARE_BUF	 _IOW('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! */
>  
> diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
> index dd9f1e7..4d1c74a 100644
> --- a/include/media/v4l2-ioctl.h
> +++ b/include/media/v4l2-ioctl.h
> @@ -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,
> -- 
> 1.7.2.5
> 

Regards,
Guennadi Liakhovetski July 20, 2011, 2:47 p.m. UTC | #2
On Wed, 20 Jul 2011, Sakari Ailus wrote:

> Hi, Guennadi!
> 
> Thanks for the patch!
> 
> On Wed, Jul 20, 2011 at 10:43:08AM +0200, Guennadi Liakhovetski wrote:
> > A possibility to preallocate and initialise buffers of different sizes
> > in V4L2 is required for an efficient implementation of asnapshot mode.
> > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > VIDIOC_PREPARE_BUF and defines respective data structures.
> > 
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
> > 
> > It's been almost a month since v2, the only comments were a request to 
> > increase the reserved space in the new ioctl() and to improve 
> > documentation. The reserved field is increased in this version, 
> > documentation also has been improved in multiple locations. I think, 
> > documentation can be further improved at any time, but if there are no 
> > objections against the actual contents of this patch, maybe we can commit 
> > this version. I still don't see v3.0;-), so, maybe we even can push it for 
> > 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> > the only change in the API, and the compatibility fix as the only two 
> > functional changes.
> > 
> > v3: addressed multiple comments by Sakari Ailus
> > 
> > 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
> >    ints
> > 2. multiple documentation fixes and improvements
> > 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
> >    processing
> > 
> > v2:
> > 
> > 1. add preliminary Documentation
> > 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> > 3. remove VIDIOC_DESTROY_BUFS
> > 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> > 5. add reserved field to struct v4l2_create_buffers
> > 6. cache handling flags moved to struct v4l2_buffer for processing during 
> >    VIDIOC_PREPARE_BUF
> > 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> > 
> > 
> >  Documentation/DocBook/media/v4l/io.xml             |   17 +++
> >  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
> >  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
> >  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
> >  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
> >  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
> >  include/linux/videodev2.h                          |   16 ++
> >  include/media/v4l2-ioctl.h                         |    2 +
> >  8 files changed, 377 insertions(+), 8 deletions(-)
> >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > 
> > diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> > index 227e7ac..6249d0e 100644
> > --- a/Documentation/DocBook/media/v4l/io.xml
> > +++ b/Documentation/DocBook/media/v4l/io.xml
> > @@ -927,6 +927,23 @@ ioctl is called.</entry>
> >  Applications set or clear this flag before calling the
> >  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
> >  	  </row>
> > +	  <row>
> > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> > +	    <entry>0x0400</entry>
> > +	    <entry>Caches do not have to be invalidated for this buffer.
> > +Typically applications shall use this flag, if the data, captured in the buffer
> > +is not going to br touched by the CPU, instead the buffer will, probably, be
> > +passed on to a DMA-capable hardware unit for further processing or output.
> > +</entry>
> > +	  </row>
> > +	  <row>
> > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> > +	    <entry>0x0800</entry>
> > +	    <entry>Caches do not have to be cleaned for this buffer.
> > +Typically applications shall use this flag for output buffers, if the data
> > +in this buffer has not been created by the CPU, but by some DMA-capable unit,
> > +in which case caches have not been used.</entry>
> > +	  </row>
> >  	</tbody>
> >        </tgroup>
> >      </table>
> > diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> > index 0d05e87..06bb179 100644
> > --- a/Documentation/DocBook/media/v4l/v4l2.xml
> > +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> > @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
> >      &sub-close;
> >      &sub-ioctl;
> >      <!-- All ioctls go here. -->
> > +    &sub-create-bufs;
> >      &sub-cropcap;
> >      &sub-dbg-g-chip-ident;
> >      &sub-dbg-g-register;
> > @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
> >      &sub-queryctrl;
> >      &sub-query-dv-preset;
> >      &sub-querystd;
> > +    &sub-prepare-buf;
> >      &sub-reqbufs;
> >      &sub-s-hw-freq-seek;
> >      &sub-streamon;
> > diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > new file mode 100644
> > index 0000000..5f0158c
> > --- /dev/null
> > +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > @@ -0,0 +1,152 @@
> > +<refentry id="vidioc-create-bufs">
> > +  <refmeta>
> > +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> > +    &manvol;
> > +  </refmeta>
> > +
> > +  <refnamediv>
> > +    <refname>VIDIOC_CREATE_BUFS</refname>
> > +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> > +  </refnamediv>
> > +
> > +  <refsynopsisdiv>
> > +    <funcsynopsis>
> > +      <funcprototype>
> > +	<funcdef>int <function>ioctl</function></funcdef>
> > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > +	<paramdef>int <parameter>request</parameter></paramdef>
> > +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> > +      </funcprototype>
> > +    </funcsynopsis>
> > +  </refsynopsisdiv>
> > +
> > +  <refsect1>
> > +    <title>Arguments</title>
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +	<term><parameter>fd</parameter></term>
> > +	<listitem>
> > +	  <para>&fd;</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><parameter>request</parameter></term>
> > +	<listitem>
> > +	  <para>VIDIOC_CREATE_BUFS</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><parameter>argp</parameter></term>
> > +	<listitem>
> > +	  <para></para>
> > +	</listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    <title>Description</title>
> > +
> > +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> > +mapped</link> or <link linkend="userp">user pointer</link>
> > +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> > +ioctl, when a tighter control over buffers is required. This ioctl can be called
> > +multiple times to create buffers of different sizes.
> > +
> > +    <para>To allocate device buffers applications initialize all
> > +fields of the <structname>v4l2_create_buffers</structname> structure.
> > +They set the <structfield>type</structfield> field in the
> > +<structname>v4l2_format</structname> structure, embedded in this
> > +structure, to the respective stream or buffer type.
> > +<structfield>count</structfield> must be set to the number of required
> > +buffers. <structfield>memory</structfield> specifies the required I/O
> > +method. Applications have two possibilities to specify the size of buffers
> > +to be prepared: they can either set the <structfield>size</structfield>
> > +field explicitly to a non-zero value, or fill in the frame format data in the
> > +<structfield>format</structfield> field. In the latter case buffer sizes
> > +will be calculated automatically by the driver. The
> > +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> > +is called with a pointer to this structure the driver will attempt to allocate
> > +up to the requested number of buffers and store the actual number allocated
> > +and the starting index in the <structfield>count</structfield> and
> > +the <structfield>index</structfield> fields respectively.
> > +<structfield>count</structfield> can be smaller than the number requested.
> > +-ENOMEM is returned, if the driver runs out of free memory.</para>
> 
> No need to mention -ENOMEM here. It's already in the return values below;
> the same goes for the EINVAL just below.

Yes, incremental patches welcome.

> 
> > +    <para>When the I/O method is not supported the ioctl
> > +returns an &EINVAL;.</para>
> > +
> > +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> > +      <title>struct <structname>v4l2_create_buffers</structname></title>
> > +      <tgroup cols="3">
> > +	&cs-str;
> > +	<tbody valign="top">
> > +	  <row>
> > +	    <entry>__u32</entry>
> > +	    <entry><structfield>index</structfield></entry>
> > +	    <entry>The starting buffer index, returned by the driver.</entry>
> > +	  </row>
> > +	  <row>
> > +	    <entry>__u32</entry>
> > +	    <entry><structfield>count</structfield></entry>
> > +	    <entry>The number of buffers requested or granted.</entry>
> > +	  </row>
> > +	  <row>
> > +	    <entry>&v4l2-memory;</entry>
> > +	    <entry><structfield>memory</structfield></entry>
> > +	    <entry>Applications set this field to
> > +<constant>V4L2_MEMORY_MMAP</constant> or
> > +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> > +	  </row>
> > +	  <row>
> > +	    <entry>__u32</entry>
> > +	    <entry><structfield>size</structfield></entry>
> > +	    <entry>Explicit size of buffers, being created.</entry>
> > +	  </row>
> > +	  <row>
> > +	    <entry>&v4l2-format;</entry>
> > +	    <entry><structfield>format</structfield></entry>
> > +	    <entry>Application has to set the <structfield>type</structfield>
> > +field, other fields should be used, if the application wants to allocate buffers
> > +for a specific frame format.</entry>
> > +	  </row>
> > +	  <row>
> > +	    <entry>__u32</entry>
> > +	    <entry><structfield>reserved</structfield>[8]</entry>
> > +	    <entry>A place holder for future extensions.</entry>
> > +	  </row>
> > +	</tbody>
> > +      </tgroup>
> > +    </table>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    &return-value;
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +	<term><errorcode>ENOMEM</errorcode></term>
> > +	<listitem>
> > +	  <para>No memory to allocate buffers for <link linkend="mmap">memory
> > +mapped</link> I/O.</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><errorcode>EINVAL</errorcode></term>
> > +	<listitem>
> > +	  <para>The buffer type (<structfield>type</structfield> field) or the
> > +requested I/O method (<structfield>memory</structfield>) is not
> > +supported.</para>
> > +	</listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +</refentry>
> > +
> > +<!--
> > +Local Variables:
> > +mode: sgml
> > +sgml-parent-document: "v4l2.sgml"
> > +indent-tabs-mode: nil
> > +End:
> > +-->
> > diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > new file mode 100644
> > index 0000000..509e752
> > --- /dev/null
> > +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > @@ -0,0 +1,96 @@
> > +<refentry id="vidioc-prepare-buf">
> > +  <refmeta>
> > +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> > +    &manvol;
> > +  </refmeta>
> > +
> > +  <refnamediv>
> > +    <refname>VIDIOC_PREPARE_BUF</refname>
> > +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> > +  </refnamediv>
> > +
> > +  <refsynopsisdiv>
> > +    <funcsynopsis>
> > +      <funcprototype>
> > +	<funcdef>int <function>ioctl</function></funcdef>
> > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > +	<paramdef>int <parameter>request</parameter></paramdef>
> > +	<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> 
> I'm not sure if we want to use struct v4l2_buffer here. It's an obvious
> choice, but there's an issue in using it.
> 
> The struct is almost full i.e. there are very few reserved fields in it,
> namely two, counting the input field which was unused AFAIR. There are now
> three ioctls using it as their argument.
> 
> Future functionality which would be nice:
> 
> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
>   come with a counter value so that the user would know the format of
>   dequeued buffers when setting the format on-the-fly. Currently there are
>   only bytesperline and length, but the format can't be explicitly
>   determined from those.
> 
> - Binding to generic DMA buffers. This can likely be achieved by using the m
>   union in struct v4l2_buffer. (Speaking of which: these buffers likely have
>   a cache behaviour defined for them, e.g. they might be non-cacheable. This
>   probably has no effect on the cache flags in V4L2 but it might still be
>   good to keep this in mind.)
> 
> I don't have an obvious replacement for it either. There are two options I
> can see: Create a new struct v4l2_ext_buffer which contains the old
> v4l2_buffer plus a bunch of reserved fields, or use the two last fields to
> hold a pointer to an extension struct, v4l2_buffer_ext. The new structure
> would later be used to contain the reserved fields.
> 
> I admit that this is not an issue right now, myt point is that I don't want
> this to be an issue in the future either.

Good, then we'll address it, when it becomes an issue.

> 
> > +      </funcprototype>
> > +    </funcsynopsis>
> > +  </refsynopsisdiv>
> > +
> > +  <refsect1>
> > +    <title>Arguments</title>
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +	<term><parameter>fd</parameter></term>
> > +	<listitem>
> > +	  <para>&fd;</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><parameter>request</parameter></term>
> > +	<listitem>
> > +	  <para>VIDIOC_PREPARE_BUF</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><parameter>argp</parameter></term>
> > +	<listitem>
> > +	  <para></para>
> > +	</listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    <title>Description</title>
> > +
> > +    <para>Applications can optionally call the
> > +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> > +to the driver before actually enqueuing it, using the
> > +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> > +Such preparations may include cache invalidation or cleaning. Performing them
> > +in advance saves time during the actual I/O. In case such cache operations are
> > +not required, the application can use one of
> > +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> > +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> > +step.</para>
> > +
> > +    <para>The <structname>v4l2_buffer</structname> structure is
> > +specified in <xref linkend="buffer" />.</para>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    &return-value;
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +	<term><errorcode>EBUSY</errorcode></term>
> > +	<listitem>
> > +	  <para>File I/O is in progress.</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><errorcode>EINVAL</errorcode></term>
> > +	<listitem>
> > +	  <para>The buffer <structfield>type</structfield> is not
> > +supported, or the <structfield>index</structfield> is out of bounds,
> > +or no buffers have been allocated yet, or the
> > +<structfield>userptr</structfield> or
> > +<structfield>length</structfield> are invalid.</para>
> > +	</listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +</refentry>
> > +
> > +<!--
> > +Local Variables:
> > +mode: sgml
> > +sgml-parent-document: "v4l2.sgml"
> > +indent-tabs-mode: nil
> > +End:
> > +-->
> > diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
> > index 61979b7..4105f69 100644
> > --- a/drivers/media/video/v4l2-compat-ioctl32.c
> > +++ b/drivers/media/video/v4l2-compat-ioctl32.c
> > @@ -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;
> > +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> > +	struct v4l2_format32	format;		/* "type" is used always, the rest if size == 0 */
> > +};
> > +
> > +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_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)
> >  {
> > -	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
> > -		put_user(kp->type, &up->type))
> > -		return -EFAULT;
> >  	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,11 @@ 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_PREPARE_BUF:
> >  	case VIDIOC_QUERYBUF:
> >  	case VIDIOC_QBUF:
> >  	case VIDIOC_DQBUF:
> > @@ -959,6 +1009,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;
> >  
> > diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
> > index 002ce13..7824152 100644
> > --- a/drivers/media/video/v4l2-ioctl.c
> > +++ b/drivers/media/video/v4l2-ioctl.c
> > @@ -260,6 +260,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)
> >  
> > @@ -2216,6 +2218,36 @@ 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;
> > +		ret = check_fmt(ops, create->format.type);
> > +		if (ret)
> > +			break;
> > +
> > +		if (create->size)
> > +			CLEAR_AFTER_FIELD(create, count);
> > +		ret = ops->vidioc_create_bufs(file, fh, create);
> > +
> > +		dbgarg(cmd, "count=%d\n", create->count);
> > +		break;
> > +	}
> > +	case VIDIOC_PREPARE_BUF:
> > +	{
> > +		struct v4l2_buffer *b = arg;
> > +
> > +		if (!ops->vidioc_prepare_buf)
> > +			break;
> > +
> > +		ret = ops->vidioc_prepare_buf(file, fh, b);
> > +
> > +		dbgarg(cmd, "index=%d", b->index);
> > +		break;
> > +	}
> >  	default:
> >  	{
> >  		bool valid_prio = true;
> > diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> > index fca24cc..0b594c7 100644
> > --- a/include/linux/videodev2.h
> > +++ b/include/linux/videodev2.h
> > @@ -653,6 +653,9 @@ 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 */
> > +/* Cache handling flags */
> > +#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0400
> > +#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x0800
> >  
> >  /*
> >   *	O V E R L A Y   P R E V I E W
> > @@ -2092,6 +2095,16 @@ 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;
> 
> Aren't enums something to avoid in public APIs? -> __u32?

They are, but this specific enum is already used in "struct 
v4l2_requestbuffers" and "struct v4l2_buffer" so, I decided, it would be 
consistent to use it here too, even if it involves extra compat craft, and 
the embedded struct v4l2_format also includes an enum in it anyway, so, 
basically, they are all over the place.

> 
> > +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> > +	struct v4l2_format	format;		/* "type" is used always, the rest if size == 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
> >   *
> > @@ -2182,6 +2195,9 @@ 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)
> >  
> > +#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
> > +#define VIDIOC_PREPARE_BUF	 _IOW('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! */
> >  
> > diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
> > index dd9f1e7..4d1c74a 100644
> > --- a/include/media/v4l2-ioctl.h
> > +++ b/include/media/v4l2-ioctl.h
> > @@ -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,
> > -- 
> > 1.7.2.5
> > 
> 
> Regards,

So, I take it as an ack;-)

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus July 20, 2011, 3:19 p.m. UTC | #3
On Wed, Jul 20, 2011 at 04:47:46PM +0200, Guennadi Liakhovetski wrote:
> On Wed, 20 Jul 2011, Sakari Ailus wrote:
> 
> > Hi, Guennadi!
> > 
> > Thanks for the patch!
> > 
> > On Wed, Jul 20, 2011 at 10:43:08AM +0200, Guennadi Liakhovetski wrote:
> > > A possibility to preallocate and initialise buffers of different sizes
> > > in V4L2 is required for an efficient implementation of asnapshot mode.
> > > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > > VIDIOC_PREPARE_BUF and defines respective data structures.
> > > 
> > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > ---
> > > 
> > > It's been almost a month since v2, the only comments were a request to 
> > > increase the reserved space in the new ioctl() and to improve 
> > > documentation. The reserved field is increased in this version, 
> > > documentation also has been improved in multiple locations. I think, 
> > > documentation can be further improved at any time, but if there are no 
> > > objections against the actual contents of this patch, maybe we can commit 
> > > this version. I still don't see v3.0;-), so, maybe we even can push it for 
> > > 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> > > the only change in the API, and the compatibility fix as the only two 
> > > functional changes.
> > > 
> > > v3: addressed multiple comments by Sakari Ailus
> > > 
> > > 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
> > >    ints
> > > 2. multiple documentation fixes and improvements
> > > 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
> > >    processing
> > > 
> > > v2:
> > > 
> > > 1. add preliminary Documentation
> > > 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> > > 3. remove VIDIOC_DESTROY_BUFS
> > > 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> > > 5. add reserved field to struct v4l2_create_buffers
> > > 6. cache handling flags moved to struct v4l2_buffer for processing during 
> > >    VIDIOC_PREPARE_BUF
> > > 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> > > 
> > > 
> > >  Documentation/DocBook/media/v4l/io.xml             |   17 +++
> > >  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
> > >  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
> > >  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
> > >  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
> > >  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
> > >  include/linux/videodev2.h                          |   16 ++
> > >  include/media/v4l2-ioctl.h                         |    2 +
> > >  8 files changed, 377 insertions(+), 8 deletions(-)
> > >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > 
> > > diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> > > index 227e7ac..6249d0e 100644
> > > --- a/Documentation/DocBook/media/v4l/io.xml
> > > +++ b/Documentation/DocBook/media/v4l/io.xml
> > > @@ -927,6 +927,23 @@ ioctl is called.</entry>
> > >  Applications set or clear this flag before calling the
> > >  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
> > >  	  </row>
> > > +	  <row>
> > > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> > > +	    <entry>0x0400</entry>
> > > +	    <entry>Caches do not have to be invalidated for this buffer.
> > > +Typically applications shall use this flag, if the data, captured in the buffer
> > > +is not going to br touched by the CPU, instead the buffer will, probably, be
> > > +passed on to a DMA-capable hardware unit for further processing or output.
> > > +</entry>
> > > +	  </row>
> > > +	  <row>
> > > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> > > +	    <entry>0x0800</entry>
> > > +	    <entry>Caches do not have to be cleaned for this buffer.
> > > +Typically applications shall use this flag for output buffers, if the data
> > > +in this buffer has not been created by the CPU, but by some DMA-capable unit,
> > > +in which case caches have not been used.</entry>
> > > +	  </row>
> > >  	</tbody>
> > >        </tgroup>
> > >      </table>
> > > diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> > > index 0d05e87..06bb179 100644
> > > --- a/Documentation/DocBook/media/v4l/v4l2.xml
> > > +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> > > @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
> > >      &sub-close;
> > >      &sub-ioctl;
> > >      <!-- All ioctls go here. -->
> > > +    &sub-create-bufs;
> > >      &sub-cropcap;
> > >      &sub-dbg-g-chip-ident;
> > >      &sub-dbg-g-register;
> > > @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
> > >      &sub-queryctrl;
> > >      &sub-query-dv-preset;
> > >      &sub-querystd;
> > > +    &sub-prepare-buf;
> > >      &sub-reqbufs;
> > >      &sub-s-hw-freq-seek;
> > >      &sub-streamon;
> > > diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > new file mode 100644
> > > index 0000000..5f0158c
> > > --- /dev/null
> > > +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > @@ -0,0 +1,152 @@
> > > +<refentry id="vidioc-create-bufs">
> > > +  <refmeta>
> > > +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> > > +    &manvol;
> > > +  </refmeta>
> > > +
> > > +  <refnamediv>
> > > +    <refname>VIDIOC_CREATE_BUFS</refname>
> > > +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> > > +  </refnamediv>
> > > +
> > > +  <refsynopsisdiv>
> > > +    <funcsynopsis>
> > > +      <funcprototype>
> > > +	<funcdef>int <function>ioctl</function></funcdef>
> > > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > > +	<paramdef>int <parameter>request</parameter></paramdef>
> > > +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> > > +      </funcprototype>
> > > +    </funcsynopsis>
> > > +  </refsynopsisdiv>
> > > +
> > > +  <refsect1>
> > > +    <title>Arguments</title>
> > > +
> > > +    <variablelist>
> > > +      <varlistentry>
> > > +	<term><parameter>fd</parameter></term>
> > > +	<listitem>
> > > +	  <para>&fd;</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +      <varlistentry>
> > > +	<term><parameter>request</parameter></term>
> > > +	<listitem>
> > > +	  <para>VIDIOC_CREATE_BUFS</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +      <varlistentry>
> > > +	<term><parameter>argp</parameter></term>
> > > +	<listitem>
> > > +	  <para></para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +    </variablelist>
> > > +  </refsect1>
> > > +
> > > +  <refsect1>
> > > +    <title>Description</title>
> > > +
> > > +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> > > +mapped</link> or <link linkend="userp">user pointer</link>
> > > +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> > > +ioctl, when a tighter control over buffers is required. This ioctl can be called
> > > +multiple times to create buffers of different sizes.
> > > +
> > > +    <para>To allocate device buffers applications initialize all
> > > +fields of the <structname>v4l2_create_buffers</structname> structure.
> > > +They set the <structfield>type</structfield> field in the
> > > +<structname>v4l2_format</structname> structure, embedded in this
> > > +structure, to the respective stream or buffer type.
> > > +<structfield>count</structfield> must be set to the number of required
> > > +buffers. <structfield>memory</structfield> specifies the required I/O
> > > +method. Applications have two possibilities to specify the size of buffers
> > > +to be prepared: they can either set the <structfield>size</structfield>
> > > +field explicitly to a non-zero value, or fill in the frame format data in the
> > > +<structfield>format</structfield> field. In the latter case buffer sizes
> > > +will be calculated automatically by the driver. The
> > > +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> > > +is called with a pointer to this structure the driver will attempt to allocate
> > > +up to the requested number of buffers and store the actual number allocated
> > > +and the starting index in the <structfield>count</structfield> and
> > > +the <structfield>index</structfield> fields respectively.
> > > +<structfield>count</structfield> can be smaller than the number requested.
> > > +-ENOMEM is returned, if the driver runs out of free memory.</para>
> > 
> > No need to mention -ENOMEM here. It's already in the return values below;
> > the same goes for the EINVAL just below.
> 
> Yes, incremental patches welcome.
> 
> > 
> > > +    <para>When the I/O method is not supported the ioctl
> > > +returns an &EINVAL;.</para>
> > > +
> > > +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> > > +      <title>struct <structname>v4l2_create_buffers</structname></title>
> > > +      <tgroup cols="3">
> > > +	&cs-str;
> > > +	<tbody valign="top">
> > > +	  <row>
> > > +	    <entry>__u32</entry>
> > > +	    <entry><structfield>index</structfield></entry>
> > > +	    <entry>The starting buffer index, returned by the driver.</entry>
> > > +	  </row>
> > > +	  <row>
> > > +	    <entry>__u32</entry>
> > > +	    <entry><structfield>count</structfield></entry>
> > > +	    <entry>The number of buffers requested or granted.</entry>
> > > +	  </row>
> > > +	  <row>
> > > +	    <entry>&v4l2-memory;</entry>
> > > +	    <entry><structfield>memory</structfield></entry>
> > > +	    <entry>Applications set this field to
> > > +<constant>V4L2_MEMORY_MMAP</constant> or
> > > +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> > > +	  </row>
> > > +	  <row>
> > > +	    <entry>__u32</entry>
> > > +	    <entry><structfield>size</structfield></entry>
> > > +	    <entry>Explicit size of buffers, being created.</entry>
> > > +	  </row>
> > > +	  <row>
> > > +	    <entry>&v4l2-format;</entry>
> > > +	    <entry><structfield>format</structfield></entry>
> > > +	    <entry>Application has to set the <structfield>type</structfield>
> > > +field, other fields should be used, if the application wants to allocate buffers
> > > +for a specific frame format.</entry>
> > > +	  </row>
> > > +	  <row>
> > > +	    <entry>__u32</entry>
> > > +	    <entry><structfield>reserved</structfield>[8]</entry>
> > > +	    <entry>A place holder for future extensions.</entry>
> > > +	  </row>
> > > +	</tbody>
> > > +      </tgroup>
> > > +    </table>
> > > +  </refsect1>
> > > +
> > > +  <refsect1>
> > > +    &return-value;
> > > +
> > > +    <variablelist>
> > > +      <varlistentry>
> > > +	<term><errorcode>ENOMEM</errorcode></term>
> > > +	<listitem>
> > > +	  <para>No memory to allocate buffers for <link linkend="mmap">memory
> > > +mapped</link> I/O.</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +      <varlistentry>
> > > +	<term><errorcode>EINVAL</errorcode></term>
> > > +	<listitem>
> > > +	  <para>The buffer type (<structfield>type</structfield> field) or the
> > > +requested I/O method (<structfield>memory</structfield>) is not
> > > +supported.</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +    </variablelist>
> > > +  </refsect1>
> > > +</refentry>
> > > +
> > > +<!--
> > > +Local Variables:
> > > +mode: sgml
> > > +sgml-parent-document: "v4l2.sgml"
> > > +indent-tabs-mode: nil
> > > +End:
> > > +-->
> > > diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > new file mode 100644
> > > index 0000000..509e752
> > > --- /dev/null
> > > +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > @@ -0,0 +1,96 @@
> > > +<refentry id="vidioc-prepare-buf">
> > > +  <refmeta>
> > > +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> > > +    &manvol;
> > > +  </refmeta>
> > > +
> > > +  <refnamediv>
> > > +    <refname>VIDIOC_PREPARE_BUF</refname>
> > > +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> > > +  </refnamediv>
> > > +
> > > +  <refsynopsisdiv>
> > > +    <funcsynopsis>
> > > +      <funcprototype>
> > > +	<funcdef>int <function>ioctl</function></funcdef>
> > > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > > +	<paramdef>int <parameter>request</parameter></paramdef>
> > > +	<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> > 
> > I'm not sure if we want to use struct v4l2_buffer here. It's an obvious
> > choice, but there's an issue in using it.
> > 
> > The struct is almost full i.e. there are very few reserved fields in it,
> > namely two, counting the input field which was unused AFAIR. There are now
> > three ioctls using it as their argument.
> > 
> > Future functionality which would be nice:
> > 
> > - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> >   come with a counter value so that the user would know the format of
> >   dequeued buffers when setting the format on-the-fly. Currently there are
> >   only bytesperline and length, but the format can't be explicitly
> >   determined from those.
> > 
> > - Binding to generic DMA buffers. This can likely be achieved by using the m
> >   union in struct v4l2_buffer. (Speaking of which: these buffers likely have
> >   a cache behaviour defined for them, e.g. they might be non-cacheable. This
> >   probably has no effect on the cache flags in V4L2 but it might still be
> >   good to keep this in mind.)
> > 
> > I don't have an obvious replacement for it either. There are two options I
> > can see: Create a new struct v4l2_ext_buffer which contains the old
> > v4l2_buffer plus a bunch of reserved fields, or use the two last fields to
> > hold a pointer to an extension struct, v4l2_buffer_ext. The new structure
> > would later be used to contain the reserved fields.
> > 
> > I admit that this is not an issue right now, myt point is that I don't want
> > this to be an issue in the future either.
> 
> Good, then we'll address it, when it becomes an issue.

Defining v4l2_ext_buffer will mean there's a new ioctl. I think we should be
a little more future proof if we can. Extending the current v4l2_buffer by
another structure with a pointer from v4l2_buffer doesn't need this.

I would like to have someone else's opinion on what to do with this. The
resolution might as well be to accept the situation and resolve it when
there's an absolute need to.

> > 
> > > +      </funcprototype>
> > > +    </funcsynopsis>
> > > +  </refsynopsisdiv>
> > > +
> > > +  <refsect1>
> > > +    <title>Arguments</title>
> > > +
> > > +    <variablelist>
> > > +      <varlistentry>
> > > +	<term><parameter>fd</parameter></term>
> > > +	<listitem>
> > > +	  <para>&fd;</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +      <varlistentry>
> > > +	<term><parameter>request</parameter></term>
> > > +	<listitem>
> > > +	  <para>VIDIOC_PREPARE_BUF</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +      <varlistentry>
> > > +	<term><parameter>argp</parameter></term>
> > > +	<listitem>
> > > +	  <para></para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +    </variablelist>
> > > +  </refsect1>
> > > +
> > > +  <refsect1>
> > > +    <title>Description</title>
> > > +
> > > +    <para>Applications can optionally call the
> > > +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> > > +to the driver before actually enqueuing it, using the
> > > +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> > > +Such preparations may include cache invalidation or cleaning. Performing them
> > > +in advance saves time during the actual I/O. In case such cache operations are
> > > +not required, the application can use one of
> > > +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> > > +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> > > +step.</para>
> > > +
> > > +    <para>The <structname>v4l2_buffer</structname> structure is
> > > +specified in <xref linkend="buffer" />.</para>
> > > +  </refsect1>
> > > +
> > > +  <refsect1>
> > > +    &return-value;
> > > +
> > > +    <variablelist>
> > > +      <varlistentry>
> > > +	<term><errorcode>EBUSY</errorcode></term>
> > > +	<listitem>
> > > +	  <para>File I/O is in progress.</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +      <varlistentry>
> > > +	<term><errorcode>EINVAL</errorcode></term>
> > > +	<listitem>
> > > +	  <para>The buffer <structfield>type</structfield> is not
> > > +supported, or the <structfield>index</structfield> is out of bounds,
> > > +or no buffers have been allocated yet, or the
> > > +<structfield>userptr</structfield> or
> > > +<structfield>length</structfield> are invalid.</para>
> > > +	</listitem>
> > > +      </varlistentry>
> > > +    </variablelist>
> > > +  </refsect1>
> > > +</refentry>
> > > +
> > > +<!--
> > > +Local Variables:
> > > +mode: sgml
> > > +sgml-parent-document: "v4l2.sgml"
> > > +indent-tabs-mode: nil
> > > +End:
> > > +-->
> > > diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
> > > index 61979b7..4105f69 100644
> > > --- a/drivers/media/video/v4l2-compat-ioctl32.c
> > > +++ b/drivers/media/video/v4l2-compat-ioctl32.c
> > > @@ -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;
> > > +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> > > +	struct v4l2_format32	format;		/* "type" is used always, the rest if size == 0 */
> > > +};
> > > +
> > > +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_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)
> > >  {
> > > -	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
> > > -		put_user(kp->type, &up->type))
> > > -		return -EFAULT;
> > >  	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,11 @@ 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_PREPARE_BUF:
> > >  	case VIDIOC_QUERYBUF:
> > >  	case VIDIOC_QBUF:
> > >  	case VIDIOC_DQBUF:
> > > @@ -959,6 +1009,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;
> > >  
> > > diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
> > > index 002ce13..7824152 100644
> > > --- a/drivers/media/video/v4l2-ioctl.c
> > > +++ b/drivers/media/video/v4l2-ioctl.c
> > > @@ -260,6 +260,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)
> > >  
> > > @@ -2216,6 +2218,36 @@ 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;
> > > +		ret = check_fmt(ops, create->format.type);
> > > +		if (ret)
> > > +			break;
> > > +
> > > +		if (create->size)
> > > +			CLEAR_AFTER_FIELD(create, count);
> > > +		ret = ops->vidioc_create_bufs(file, fh, create);
> > > +
> > > +		dbgarg(cmd, "count=%d\n", create->count);
> > > +		break;
> > > +	}
> > > +	case VIDIOC_PREPARE_BUF:
> > > +	{
> > > +		struct v4l2_buffer *b = arg;
> > > +
> > > +		if (!ops->vidioc_prepare_buf)
> > > +			break;
> > > +
> > > +		ret = ops->vidioc_prepare_buf(file, fh, b);
> > > +
> > > +		dbgarg(cmd, "index=%d", b->index);
> > > +		break;
> > > +	}
> > >  	default:
> > >  	{
> > >  		bool valid_prio = true;
> > > diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> > > index fca24cc..0b594c7 100644
> > > --- a/include/linux/videodev2.h
> > > +++ b/include/linux/videodev2.h
> > > @@ -653,6 +653,9 @@ 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 */
> > > +/* Cache handling flags */
> > > +#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0400
> > > +#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x0800
> > >  
> > >  /*
> > >   *	O V E R L A Y   P R E V I E W
> > > @@ -2092,6 +2095,16 @@ 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;
> > 
> > Aren't enums something to avoid in public APIs? -> __u32?
> 
> They are, but this specific enum is already used in "struct 
> v4l2_requestbuffers" and "struct v4l2_buffer" so, I decided, it would be 
> consistent to use it here too, even if it involves extra compat craft, and 
> the embedded struct v4l2_format also includes an enum in it anyway, so, 
> basically, they are all over the place.

In my understanding that goes for all enums, not only those that would be
newly introduced to the API. E.g. struct v4l2_event_ctrl.type is actually
enum v4l2_ctrl_type rather than __u32. struct v4l2_queryctrl uses the enum,
v4l2_event_ctrl does not.

> > 
> > > +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> > > +	struct v4l2_format	format;		/* "type" is used always, the rest if size == 0 */
> > > +	__u32			reserved[8];
> > > +};

Btw. what about __attribute__ ((packed)) for the structure? Not all
interface structs use it, though.

> > >  /*
> > >   *	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
> > >   *
> > > @@ -2182,6 +2195,9 @@ 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)
> > >  
> > > +#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
> > > +#define VIDIOC_PREPARE_BUF	 _IOW('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! */
> > >  
> > > diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
> > > index dd9f1e7..4d1c74a 100644
> > > --- a/include/media/v4l2-ioctl.h
> > > +++ b/include/media/v4l2-ioctl.h
> > > @@ -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,
> > > -- 
> > > 1.7.2.5
> > > 
> > 
> > Regards,
> 
> So, I take it as an ack;-)

It's not an ack yet but we're definitely close. :-)
Hans Verkuil July 26, 2011, 10:41 a.m. UTC | #4
Just some typos/documentation improvements:

On Wednesday, July 20, 2011 10:43:08 Guennadi Liakhovetski wrote:
> A possibility to preallocate and initialise buffers of different sizes
> in V4L2 is required for an efficient implementation of asnapshot mode.
> This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> VIDIOC_PREPARE_BUF and defines respective data structures.
> 
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
> 
> It's been almost a month since v2, the only comments were a request to 
> increase the reserved space in the new ioctl() and to improve 
> documentation. The reserved field is increased in this version, 
> documentation also has been improved in multiple locations. I think, 
> documentation can be further improved at any time, but if there are no 
> objections against the actual contents of this patch, maybe we can commit 
> this version. I still don't see v3.0;-), so, maybe we even can push it for 
> 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> the only change in the API, and the compatibility fix as the only two 
> functional changes.
> 
> v3: addressed multiple comments by Sakari Ailus
> 
> 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
>    ints
> 2. multiple documentation fixes and improvements
> 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
>    processing
> 
> v2:
> 
> 1. add preliminary Documentation
> 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> 3. remove VIDIOC_DESTROY_BUFS
> 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> 5. add reserved field to struct v4l2_create_buffers
> 6. cache handling flags moved to struct v4l2_buffer for processing during 
>    VIDIOC_PREPARE_BUF
> 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> 
> 
>  Documentation/DocBook/media/v4l/io.xml             |   17 +++
>  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
>  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
>  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
>  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
>  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
>  include/linux/videodev2.h                          |   16 ++
>  include/media/v4l2-ioctl.h                         |    2 +
>  8 files changed, 377 insertions(+), 8 deletions(-)
>  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
>  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> 
> diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> index 227e7ac..6249d0e 100644
> --- a/Documentation/DocBook/media/v4l/io.xml
> +++ b/Documentation/DocBook/media/v4l/io.xml
> @@ -927,6 +927,23 @@ ioctl is called.</entry>
>  Applications set or clear this flag before calling the
>  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
>  	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> +	    <entry>0x0400</entry>
> +	    <entry>Caches do not have to be invalidated for this buffer.
> +Typically applications shall use this flag, if the data, captured in the buffer

The two commas can be removed in the line above.

> +is not going to br touched by the CPU, instead the buffer will, probably, be

typo: br -> be

> +passed on to a DMA-capable hardware unit for further processing or output.
> +</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> +	    <entry>0x0800</entry>
> +	    <entry>Caches do not have to be cleaned for this buffer.
> +Typically applications shall use this flag for output buffers, if the data

Comma can be removed.

> +in this buffer has not been created by the CPU, but by some DMA-capable unit,

Comma before 'but' can be removed.

> +in which case caches have not been used.</entry>
> +	  </row>
>  	</tbody>
>        </tgroup>
>      </table>
> diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> index 0d05e87..06bb179 100644
> --- a/Documentation/DocBook/media/v4l/v4l2.xml
> +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
>      &sub-close;
>      &sub-ioctl;
>      <!-- All ioctls go here. -->
> +    &sub-create-bufs;
>      &sub-cropcap;
>      &sub-dbg-g-chip-ident;
>      &sub-dbg-g-register;
> @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
>      &sub-queryctrl;
>      &sub-query-dv-preset;
>      &sub-querystd;
> +    &sub-prepare-buf;
>      &sub-reqbufs;
>      &sub-s-hw-freq-seek;
>      &sub-streamon;
> diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> new file mode 100644
> index 0000000..5f0158c
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> @@ -0,0 +1,152 @@
> +<refentry id="vidioc-create-bufs">
> +  <refmeta>
> +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> +    &manvol;
> +  </refmeta>
> +
> +  <refnamediv>
> +    <refname>VIDIOC_CREATE_BUFS</refname>
> +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> +  </refnamediv>
> +
> +  <refsynopsisdiv>
> +    <funcsynopsis>
> +      <funcprototype>
> +	<funcdef>int <function>ioctl</function></funcdef>
> +	<paramdef>int <parameter>fd</parameter></paramdef>
> +	<paramdef>int <parameter>request</parameter></paramdef>
> +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> +      </funcprototype>
> +    </funcsynopsis>
> +  </refsynopsisdiv>
> +
> +  <refsect1>
> +    <title>Arguments</title>
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><parameter>fd</parameter></term>
> +	<listitem>
> +	  <para>&fd;</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>request</parameter></term>
> +	<listitem>
> +	  <para>VIDIOC_CREATE_BUFS</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>argp</parameter></term>
> +	<listitem>
> +	  <para></para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +
> +  <refsect1>
> +    <title>Description</title>
> +
> +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> +mapped</link> or <link linkend="userp">user pointer</link>
> +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> +ioctl, when a tighter control over buffers is required. This ioctl can be called
> +multiple times to create buffers of different sizes.
> +
> +    <para>To allocate device buffers applications initialize all
> +fields of the <structname>v4l2_create_buffers</structname> structure.
> +They set the <structfield>type</structfield> field in the
> +<structname>v4l2_format</structname> structure, embedded in this
> +structure, to the respective stream or buffer type.
> +<structfield>count</structfield> must be set to the number of required
> +buffers. <structfield>memory</structfield> specifies the required I/O
> +method. Applications have two possibilities to specify the size of buffers
> +to be prepared: they can either set the <structfield>size</structfield>
> +field explicitly to a non-zero value, or fill in the frame format data in the
> +<structfield>format</structfield> field. In the latter case buffer sizes
> +will be calculated automatically by the driver. The
> +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> +is called with a pointer to this structure the driver will attempt to allocate
> +up to the requested number of buffers and store the actual number allocated
> +and the starting index in the <structfield>count</structfield> and
> +the <structfield>index</structfield> fields respectively.
> +<structfield>count</structfield> can be smaller than the number requested.
> +-ENOMEM is returned, if the driver runs out of free memory.</para>
> +    <para>When the I/O method is not supported the ioctl
> +returns an &EINVAL;.</para>
> +
> +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> +      <title>struct <structname>v4l2_create_buffers</structname></title>
> +      <tgroup cols="3">
> +	&cs-str;
> +	<tbody valign="top">
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>index</structfield></entry>
> +	    <entry>The starting buffer index, returned by the driver.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>count</structfield></entry>
> +	    <entry>The number of buffers requested or granted.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>&v4l2-memory;</entry>
> +	    <entry><structfield>memory</structfield></entry>
> +	    <entry>Applications set this field to
> +<constant>V4L2_MEMORY_MMAP</constant> or
> +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>size</structfield></entry>
> +	    <entry>Explicit size of buffers, being created.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>&v4l2-format;</entry>
> +	    <entry><structfield>format</structfield></entry>
> +	    <entry>Application has to set the <structfield>type</structfield>
> +field, other fields should be used, if the application wants to allocate buffers
> +for a specific frame format.</entry>

This sentence doesn't make sense to me.

I suggest:

	    <entry>The application must always set the <structfield>type</structfield>
field of &v4l2-format. The other fields only need to be set if the application set the
<structfield>size</structfield> field to 0. In that case the driver will allocated
buffers for that specific frame format.</entry>

> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>reserved</structfield>[8]</entry>
> +	    <entry>A place holder for future extensions.</entry>
> +	  </row>
> +	</tbody>
> +      </tgroup>
> +    </table>
> +  </refsect1>
> +
> +  <refsect1>
> +    &return-value;
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><errorcode>ENOMEM</errorcode></term>
> +	<listitem>
> +	  <para>No memory to allocate buffers for <link linkend="mmap">memory
> +mapped</link> I/O.</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><errorcode>EINVAL</errorcode></term>
> +	<listitem>
> +	  <para>The buffer type (<structfield>type</structfield> field) or the
> +requested I/O method (<structfield>memory</structfield>) is not
> +supported.</para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +</refentry>
> +
> +<!--
> +Local Variables:
> +mode: sgml
> +sgml-parent-document: "v4l2.sgml"
> +indent-tabs-mode: nil
> +End:
> +-->
> diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> new file mode 100644
> index 0000000..509e752
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> @@ -0,0 +1,96 @@
> +<refentry id="vidioc-prepare-buf">
> +  <refmeta>
> +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> +    &manvol;
> +  </refmeta>
> +
> +  <refnamediv>
> +    <refname>VIDIOC_PREPARE_BUF</refname>
> +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> +  </refnamediv>
> +
> +  <refsynopsisdiv>
> +    <funcsynopsis>
> +      <funcprototype>
> +	<funcdef>int <function>ioctl</function></funcdef>
> +	<paramdef>int <parameter>fd</parameter></paramdef>
> +	<paramdef>int <parameter>request</parameter></paramdef>
> +	<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> +      </funcprototype>
> +    </funcsynopsis>
> +  </refsynopsisdiv>
> +
> +  <refsect1>
> +    <title>Arguments</title>
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><parameter>fd</parameter></term>
> +	<listitem>
> +	  <para>&fd;</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>request</parameter></term>
> +	<listitem>
> +	  <para>VIDIOC_PREPARE_BUF</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>argp</parameter></term>
> +	<listitem>
> +	  <para></para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +
> +  <refsect1>
> +    <title>Description</title>
> +
> +    <para>Applications can optionally call the
> +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> +to the driver before actually enqueuing it, using the
> +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> +Such preparations may include cache invalidation or cleaning. Performing them
> +in advance saves time during the actual I/O. In case such cache operations are
> +not required, the application can use one of
> +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> +step.</para>
> +
> +    <para>The <structname>v4l2_buffer</structname> structure is
> +specified in <xref linkend="buffer" />.</para>
> +  </refsect1>
> +
> +  <refsect1>
> +    &return-value;
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><errorcode>EBUSY</errorcode></term>
> +	<listitem>
> +	  <para>File I/O is in progress.</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><errorcode>EINVAL</errorcode></term>
> +	<listitem>
> +	  <para>The buffer <structfield>type</structfield> is not
> +supported, or the <structfield>index</structfield> is out of bounds,
> +or no buffers have been allocated yet, or the
> +<structfield>userptr</structfield> or
> +<structfield>length</structfield> are invalid.</para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +</refentry>
> +
> +<!--
> +Local Variables:
> +mode: sgml
> +sgml-parent-document: "v4l2.sgml"
> +indent-tabs-mode: nil
> +End:
> +-->
> diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
> index 61979b7..4105f69 100644
> --- a/drivers/media/video/v4l2-compat-ioctl32.c
> +++ b/drivers/media/video/v4l2-compat-ioctl32.c
> @@ -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;
> +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> +	struct v4l2_format32	format;		/* "type" is used always, the rest if size == 0 */
> +};
> +
> +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_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)
>  {
> -	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
> -		put_user(kp->type, &up->type))
> -		return -EFAULT;
>  	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,11 @@ 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_PREPARE_BUF:
>  	case VIDIOC_QUERYBUF:
>  	case VIDIOC_QBUF:
>  	case VIDIOC_DQBUF:
> @@ -959,6 +1009,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;
>  
> diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
> index 002ce13..7824152 100644
> --- a/drivers/media/video/v4l2-ioctl.c
> +++ b/drivers/media/video/v4l2-ioctl.c
> @@ -260,6 +260,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)
>  
> @@ -2216,6 +2218,36 @@ 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;
> +		ret = check_fmt(ops, create->format.type);
> +		if (ret)
> +			break;
> +
> +		if (create->size)
> +			CLEAR_AFTER_FIELD(create, count);
> +
> +		ret = ops->vidioc_create_bufs(file, fh, create);
> +
> +		dbgarg(cmd, "count=%d\n", create->count);
> +		break;
> +	}
> +	case VIDIOC_PREPARE_BUF:
> +	{
> +		struct v4l2_buffer *b = arg;
> +
> +		if (!ops->vidioc_prepare_buf)
> +			break;
> +
> +		ret = ops->vidioc_prepare_buf(file, fh, b);
> +
> +		dbgarg(cmd, "index=%d", b->index);
> +		break;
> +	}
>  	default:
>  	{
>  		bool valid_prio = true;
> diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> index fca24cc..0b594c7 100644
> --- a/include/linux/videodev2.h
> +++ b/include/linux/videodev2.h
> @@ -653,6 +653,9 @@ 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 */
> +/* Cache handling flags */
> +#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0400
> +#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x0800
>  
>  /*
>   *	O V E R L A Y   P R E V I E W
> @@ -2092,6 +2095,16 @@ 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;
> +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> +	struct v4l2_format	format;		/* "type" is used always, the rest if size == 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
>   *
> @@ -2182,6 +2195,9 @@ 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)
>  
> +#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
> +#define VIDIOC_PREPARE_BUF	 _IOW('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! */
>  
> diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
> index dd9f1e7..4d1c74a 100644
> --- a/include/media/v4l2-ioctl.h
> +++ b/include/media/v4l2-ioctl.h
> @@ -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,
> 

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hans Verkuil July 26, 2011, 11:05 a.m. UTC | #5
On Wednesday, July 20, 2011 17:19:46 Sakari Ailus wrote:
> On Wed, Jul 20, 2011 at 04:47:46PM +0200, Guennadi Liakhovetski wrote:
> > On Wed, 20 Jul 2011, Sakari Ailus wrote:
> > 
> > > Hi, Guennadi!
> > > 
> > > Thanks for the patch!
> > > 
> > > On Wed, Jul 20, 2011 at 10:43:08AM +0200, Guennadi Liakhovetski wrote:
> > > > A possibility to preallocate and initialise buffers of different sizes
> > > > in V4L2 is required for an efficient implementation of asnapshot mode.
> > > > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > > > VIDIOC_PREPARE_BUF and defines respective data structures.
> > > > 
> > > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > > ---
> > > > 
> > > > It's been almost a month since v2, the only comments were a request to 
> > > > increase the reserved space in the new ioctl() and to improve 
> > > > documentation. The reserved field is increased in this version, 
> > > > documentation also has been improved in multiple locations. I think, 
> > > > documentation can be further improved at any time, but if there are no 
> > > > objections against the actual contents of this patch, maybe we can commit 
> > > > this version. I still don't see v3.0;-), so, maybe we even can push it for 
> > > > 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> > > > the only change in the API, and the compatibility fix as the only two 
> > > > functional changes.
> > > > 
> > > > v3: addressed multiple comments by Sakari Ailus
> > > > 
> > > > 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
> > > >    ints
> > > > 2. multiple documentation fixes and improvements
> > > > 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
> > > >    processing
> > > > 
> > > > v2:
> > > > 
> > > > 1. add preliminary Documentation
> > > > 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> > > > 3. remove VIDIOC_DESTROY_BUFS
> > > > 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> > > > 5. add reserved field to struct v4l2_create_buffers
> > > > 6. cache handling flags moved to struct v4l2_buffer for processing during 
> > > >    VIDIOC_PREPARE_BUF
> > > > 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> > > > 
> > > > 
> > > >  Documentation/DocBook/media/v4l/io.xml             |   17 +++
> > > >  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
> > > >  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
> > > >  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
> > > >  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
> > > >  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
> > > >  include/linux/videodev2.h                          |   16 ++
> > > >  include/media/v4l2-ioctl.h                         |    2 +
> > > >  8 files changed, 377 insertions(+), 8 deletions(-)
> > > >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > > 
> > > > diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> > > > index 227e7ac..6249d0e 100644
> > > > --- a/Documentation/DocBook/media/v4l/io.xml
> > > > +++ b/Documentation/DocBook/media/v4l/io.xml
> > > > @@ -927,6 +927,23 @@ ioctl is called.</entry>
> > > >  Applications set or clear this flag before calling the
> > > >  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
> > > >  	  </row>
> > > > +	  <row>
> > > > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> > > > +	    <entry>0x0400</entry>
> > > > +	    <entry>Caches do not have to be invalidated for this buffer.
> > > > +Typically applications shall use this flag, if the data, captured in the buffer
> > > > +is not going to br touched by the CPU, instead the buffer will, probably, be
> > > > +passed on to a DMA-capable hardware unit for further processing or output.
> > > > +</entry>
> > > > +	  </row>
> > > > +	  <row>
> > > > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> > > > +	    <entry>0x0800</entry>
> > > > +	    <entry>Caches do not have to be cleaned for this buffer.
> > > > +Typically applications shall use this flag for output buffers, if the data
> > > > +in this buffer has not been created by the CPU, but by some DMA-capable unit,
> > > > +in which case caches have not been used.</entry>
> > > > +	  </row>
> > > >  	</tbody>
> > > >        </tgroup>
> > > >      </table>
> > > > diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> > > > index 0d05e87..06bb179 100644
> > > > --- a/Documentation/DocBook/media/v4l/v4l2.xml
> > > > +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> > > > @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
> > > >      &sub-close;
> > > >      &sub-ioctl;
> > > >      <!-- All ioctls go here. -->
> > > > +    &sub-create-bufs;
> > > >      &sub-cropcap;
> > > >      &sub-dbg-g-chip-ident;
> > > >      &sub-dbg-g-register;
> > > > @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
> > > >      &sub-queryctrl;
> > > >      &sub-query-dv-preset;
> > > >      &sub-querystd;
> > > > +    &sub-prepare-buf;
> > > >      &sub-reqbufs;
> > > >      &sub-s-hw-freq-seek;
> > > >      &sub-streamon;
> > > > diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > > new file mode 100644
> > > > index 0000000..5f0158c
> > > > --- /dev/null
> > > > +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > > @@ -0,0 +1,152 @@
> > > > +<refentry id="vidioc-create-bufs">
> > > > +  <refmeta>
> > > > +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> > > > +    &manvol;
> > > > +  </refmeta>
> > > > +
> > > > +  <refnamediv>
> > > > +    <refname>VIDIOC_CREATE_BUFS</refname>
> > > > +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> > > > +  </refnamediv>
> > > > +
> > > > +  <refsynopsisdiv>
> > > > +    <funcsynopsis>
> > > > +      <funcprototype>
> > > > +	<funcdef>int <function>ioctl</function></funcdef>
> > > > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > > > +	<paramdef>int <parameter>request</parameter></paramdef>
> > > > +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> > > > +      </funcprototype>
> > > > +    </funcsynopsis>
> > > > +  </refsynopsisdiv>
> > > > +
> > > > +  <refsect1>
> > > > +    <title>Arguments</title>
> > > > +
> > > > +    <variablelist>
> > > > +      <varlistentry>
> > > > +	<term><parameter>fd</parameter></term>
> > > > +	<listitem>
> > > > +	  <para>&fd;</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +      <varlistentry>
> > > > +	<term><parameter>request</parameter></term>
> > > > +	<listitem>
> > > > +	  <para>VIDIOC_CREATE_BUFS</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +      <varlistentry>
> > > > +	<term><parameter>argp</parameter></term>
> > > > +	<listitem>
> > > > +	  <para></para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +    </variablelist>
> > > > +  </refsect1>
> > > > +
> > > > +  <refsect1>
> > > > +    <title>Description</title>
> > > > +
> > > > +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> > > > +mapped</link> or <link linkend="userp">user pointer</link>
> > > > +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> > > > +ioctl, when a tighter control over buffers is required. This ioctl can be called
> > > > +multiple times to create buffers of different sizes.

I realized that it is not clear from the documentation whether it is possible to call
VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.

I can't remember whether the code allows it or not, but it should be clearly documented.

> > > > +
> > > > +    <para>To allocate device buffers applications initialize all
> > > > +fields of the <structname>v4l2_create_buffers</structname> structure.
> > > > +They set the <structfield>type</structfield> field in the
> > > > +<structname>v4l2_format</structname> structure, embedded in this
> > > > +structure, to the respective stream or buffer type.
> > > > +<structfield>count</structfield> must be set to the number of required
> > > > +buffers. <structfield>memory</structfield> specifies the required I/O
> > > > +method. Applications have two possibilities to specify the size of buffers
> > > > +to be prepared: they can either set the <structfield>size</structfield>
> > > > +field explicitly to a non-zero value, or fill in the frame format data in the
> > > > +<structfield>format</structfield> field. In the latter case buffer sizes
> > > > +will be calculated automatically by the driver. The
> > > > +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> > > > +is called with a pointer to this structure the driver will attempt to allocate
> > > > +up to the requested number of buffers and store the actual number allocated
> > > > +and the starting index in the <structfield>count</structfield> and
> > > > +the <structfield>index</structfield> fields respectively.
> > > > +<structfield>count</structfield> can be smaller than the number requested.
> > > > +-ENOMEM is returned, if the driver runs out of free memory.</para>
> > > 
> > > No need to mention -ENOMEM here. It's already in the return values below;
> > > the same goes for the EINVAL just below.
> > 
> > Yes, incremental patches welcome.
> > 
> > > 
> > > > +    <para>When the I/O method is not supported the ioctl
> > > > +returns an &EINVAL;.</para>
> > > > +
> > > > +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> > > > +      <title>struct <structname>v4l2_create_buffers</structname></title>
> > > > +      <tgroup cols="3">
> > > > +	&cs-str;
> > > > +	<tbody valign="top">
> > > > +	  <row>
> > > > +	    <entry>__u32</entry>
> > > > +	    <entry><structfield>index</structfield></entry>
> > > > +	    <entry>The starting buffer index, returned by the driver.</entry>
> > > > +	  </row>
> > > > +	  <row>
> > > > +	    <entry>__u32</entry>
> > > > +	    <entry><structfield>count</structfield></entry>
> > > > +	    <entry>The number of buffers requested or granted.</entry>
> > > > +	  </row>
> > > > +	  <row>
> > > > +	    <entry>&v4l2-memory;</entry>
> > > > +	    <entry><structfield>memory</structfield></entry>
> > > > +	    <entry>Applications set this field to
> > > > +<constant>V4L2_MEMORY_MMAP</constant> or
> > > > +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> > > > +	  </row>
> > > > +	  <row>
> > > > +	    <entry>__u32</entry>
> > > > +	    <entry><structfield>size</structfield></entry>
> > > > +	    <entry>Explicit size of buffers, being created.</entry>
> > > > +	  </row>
> > > > +	  <row>
> > > > +	    <entry>&v4l2-format;</entry>
> > > > +	    <entry><structfield>format</structfield></entry>
> > > > +	    <entry>Application has to set the <structfield>type</structfield>
> > > > +field, other fields should be used, if the application wants to allocate buffers
> > > > +for a specific frame format.</entry>
> > > > +	  </row>
> > > > +	  <row>
> > > > +	    <entry>__u32</entry>
> > > > +	    <entry><structfield>reserved</structfield>[8]</entry>
> > > > +	    <entry>A place holder for future extensions.</entry>
> > > > +	  </row>
> > > > +	</tbody>
> > > > +      </tgroup>
> > > > +    </table>
> > > > +  </refsect1>
> > > > +
> > > > +  <refsect1>
> > > > +    &return-value;
> > > > +
> > > > +    <variablelist>
> > > > +      <varlistentry>
> > > > +	<term><errorcode>ENOMEM</errorcode></term>
> > > > +	<listitem>
> > > > +	  <para>No memory to allocate buffers for <link linkend="mmap">memory
> > > > +mapped</link> I/O.</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +      <varlistentry>
> > > > +	<term><errorcode>EINVAL</errorcode></term>
> > > > +	<listitem>
> > > > +	  <para>The buffer type (<structfield>type</structfield> field) or the
> > > > +requested I/O method (<structfield>memory</structfield>) is not
> > > > +supported.</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +    </variablelist>
> > > > +  </refsect1>
> > > > +</refentry>
> > > > +
> > > > +<!--
> > > > +Local Variables:
> > > > +mode: sgml
> > > > +sgml-parent-document: "v4l2.sgml"
> > > > +indent-tabs-mode: nil
> > > > +End:
> > > > +-->
> > > > diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > > new file mode 100644
> > > > index 0000000..509e752
> > > > --- /dev/null
> > > > +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > > @@ -0,0 +1,96 @@
> > > > +<refentry id="vidioc-prepare-buf">
> > > > +  <refmeta>
> > > > +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> > > > +    &manvol;
> > > > +  </refmeta>
> > > > +
> > > > +  <refnamediv>
> > > > +    <refname>VIDIOC_PREPARE_BUF</refname>
> > > > +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> > > > +  </refnamediv>
> > > > +
> > > > +  <refsynopsisdiv>
> > > > +    <funcsynopsis>
> > > > +      <funcprototype>
> > > > +	<funcdef>int <function>ioctl</function></funcdef>
> > > > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > > > +	<paramdef>int <parameter>request</parameter></paramdef>
> > > > +	<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> > > 
> > > I'm not sure if we want to use struct v4l2_buffer here. It's an obvious
> > > choice, but there's an issue in using it.
> > > 
> > > The struct is almost full i.e. there are very few reserved fields in it,
> > > namely two, counting the input field which was unused AFAIR. There are now
> > > three ioctls using it as their argument.
> > > 
> > > Future functionality which would be nice:
> > > 
> > > - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> > >   come with a counter value so that the user would know the format of
> > >   dequeued buffers when setting the format on-the-fly. Currently there are
> > >   only bytesperline and length, but the format can't be explicitly
> > >   determined from those.

Actually, the index field will give you that information. When you create the
buffers you know that range [index, index + count - 1] is associated with that
specific format.

> > > - Binding to generic DMA buffers. This can likely be achieved by using the m
> > >   union in struct v4l2_buffer. (Speaking of which: these buffers likely have
> > >   a cache behaviour defined for them, e.g. they might be non-cacheable. This
> > >   probably has no effect on the cache flags in V4L2 but it might still be
> > >   good to keep this in mind.)

That will definitely be done through the 'm' union.

> > > I don't have an obvious replacement for it either. There are two options I
> > > can see: Create a new struct v4l2_ext_buffer which contains the old
> > > v4l2_buffer plus a bunch of reserved fields, or use the two last fields to
> > > hold a pointer to an extension struct, v4l2_buffer_ext. The new structure
> > > would later be used to contain the reserved fields.
> > > 
> > > I admit that this is not an issue right now, myt point is that I don't want
> > > this to be an issue in the future either.
> > 
> > Good, then we'll address it, when it becomes an issue.
> 
> Defining v4l2_ext_buffer will mean there's a new ioctl. I think we should be
> a little more future proof if we can. Extending the current v4l2_buffer by
> another structure with a pointer from v4l2_buffer doesn't need this.
> 
> I would like to have someone else's opinion on what to do with this. The
> resolution might as well be to accept the situation and resolve it when
> there's an absolute need to.

Trying to define a new structure when we don't know if we need one, let alone
what should be in there, doesn't seem useful to me. Especially since it would
require yet another struct. I'm with Guennadi on this one.

> 
> > > 
> > > > +      </funcprototype>
> > > > +    </funcsynopsis>
> > > > +  </refsynopsisdiv>
> > > > +
> > > > +  <refsect1>
> > > > +    <title>Arguments</title>
> > > > +
> > > > +    <variablelist>
> > > > +      <varlistentry>
> > > > +	<term><parameter>fd</parameter></term>
> > > > +	<listitem>
> > > > +	  <para>&fd;</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +      <varlistentry>
> > > > +	<term><parameter>request</parameter></term>
> > > > +	<listitem>
> > > > +	  <para>VIDIOC_PREPARE_BUF</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +      <varlistentry>
> > > > +	<term><parameter>argp</parameter></term>
> > > > +	<listitem>
> > > > +	  <para></para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +    </variablelist>
> > > > +  </refsect1>
> > > > +
> > > > +  <refsect1>
> > > > +    <title>Description</title>
> > > > +
> > > > +    <para>Applications can optionally call the
> > > > +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> > > > +to the driver before actually enqueuing it, using the
> > > > +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> > > > +Such preparations may include cache invalidation or cleaning. Performing them
> > > > +in advance saves time during the actual I/O. In case such cache operations are
> > > > +not required, the application can use one of
> > > > +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> > > > +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> > > > +step.</para>
> > > > +
> > > > +    <para>The <structname>v4l2_buffer</structname> structure is
> > > > +specified in <xref linkend="buffer" />.</para>
> > > > +  </refsect1>
> > > > +
> > > > +  <refsect1>
> > > > +    &return-value;
> > > > +
> > > > +    <variablelist>
> > > > +      <varlistentry>
> > > > +	<term><errorcode>EBUSY</errorcode></term>
> > > > +	<listitem>
> > > > +	  <para>File I/O is in progress.</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +      <varlistentry>
> > > > +	<term><errorcode>EINVAL</errorcode></term>
> > > > +	<listitem>
> > > > +	  <para>The buffer <structfield>type</structfield> is not
> > > > +supported, or the <structfield>index</structfield> is out of bounds,
> > > > +or no buffers have been allocated yet, or the
> > > > +<structfield>userptr</structfield> or
> > > > +<structfield>length</structfield> are invalid.</para>
> > > > +	</listitem>
> > > > +      </varlistentry>
> > > > +    </variablelist>
> > > > +  </refsect1>
> > > > +</refentry>
> > > > +
> > > > +<!--
> > > > +Local Variables:
> > > > +mode: sgml
> > > > +sgml-parent-document: "v4l2.sgml"
> > > > +indent-tabs-mode: nil
> > > > +End:
> > > > +-->
> > > > diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
> > > > index 61979b7..4105f69 100644
> > > > --- a/drivers/media/video/v4l2-compat-ioctl32.c
> > > > +++ b/drivers/media/video/v4l2-compat-ioctl32.c
> > > > @@ -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;
> > > > +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> > > > +	struct v4l2_format32	format;		/* "type" is used always, the rest if size == 0 */
> > > > +};
> > > > +
> > > > +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_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)
> > > >  {
> > > > -	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
> > > > -		put_user(kp->type, &up->type))
> > > > -		return -EFAULT;
> > > >  	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,11 @@ 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_PREPARE_BUF:
> > > >  	case VIDIOC_QUERYBUF:
> > > >  	case VIDIOC_QBUF:
> > > >  	case VIDIOC_DQBUF:
> > > > @@ -959,6 +1009,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;
> > > >  
> > > > diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
> > > > index 002ce13..7824152 100644
> > > > --- a/drivers/media/video/v4l2-ioctl.c
> > > > +++ b/drivers/media/video/v4l2-ioctl.c
> > > > @@ -260,6 +260,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)
> > > >  
> > > > @@ -2216,6 +2218,36 @@ 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;
> > > > +		ret = check_fmt(ops, create->format.type);
> > > > +		if (ret)
> > > > +			break;
> > > > +
> > > > +		if (create->size)
> > > > +			CLEAR_AFTER_FIELD(create, count);
> > > > +		ret = ops->vidioc_create_bufs(file, fh, create);
> > > > +
> > > > +		dbgarg(cmd, "count=%d\n", create->count);
> > > > +		break;
> > > > +	}
> > > > +	case VIDIOC_PREPARE_BUF:
> > > > +	{
> > > > +		struct v4l2_buffer *b = arg;
> > > > +
> > > > +		if (!ops->vidioc_prepare_buf)
> > > > +			break;
> > > > +
> > > > +		ret = ops->vidioc_prepare_buf(file, fh, b);
> > > > +
> > > > +		dbgarg(cmd, "index=%d", b->index);
> > > > +		break;
> > > > +	}
> > > >  	default:
> > > >  	{
> > > >  		bool valid_prio = true;
> > > > diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
> > > > index fca24cc..0b594c7 100644
> > > > --- a/include/linux/videodev2.h
> > > > +++ b/include/linux/videodev2.h
> > > > @@ -653,6 +653,9 @@ 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 */
> > > > +/* Cache handling flags */
> > > > +#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0400
> > > > +#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x0800
> > > >  
> > > >  /*
> > > >   *	O V E R L A Y   P R E V I E W
> > > > @@ -2092,6 +2095,16 @@ 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;
> > > 
> > > Aren't enums something to avoid in public APIs? -> __u32?
> > 
> > They are, but this specific enum is already used in "struct 
> > v4l2_requestbuffers" and "struct v4l2_buffer" so, I decided, it would be 
> > consistent to use it here too, even if it involves extra compat craft, and 
> > the embedded struct v4l2_format also includes an enum in it anyway, so, 
> > basically, they are all over the place.
> 
> In my understanding that goes for all enums, not only those that would be
> newly introduced to the API. E.g. struct v4l2_event_ctrl.type is actually
> enum v4l2_ctrl_type rather than __u32. struct v4l2_queryctrl uses the enum,
> v4l2_event_ctrl does not.

True, but since v4l2_create_buffers uses struct v4l2_format already which
has enums I see no advantage to using __u32 over enum. In struct v4l2_event_ctrl
the use of __u32 prevented needing more complex compat code.

> 
> > > 
> > > > +	__u32			size;		/* Explicit size, e.g., for compressed streams */
> > > > +	struct v4l2_format	format;		/* "type" is used always, the rest if size == 0 */
> > > > +	__u32			reserved[8];
> > > > +};
> 
> Btw. what about __attribute__ ((packed)) for the structure? Not all
> interface structs use it, though.

It doesn't really help you here. In some cases it prevents having to make
compat32 code, but since we need it anyway...

> 
> > > >  /*
> > > >   *	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
> > > >   *
> > > > @@ -2182,6 +2195,9 @@ 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)
> > > >  
> > > > +#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
> > > > +#define VIDIOC_PREPARE_BUF	 _IOW('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! */
> > > >  
> > > > diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
> > > > index dd9f1e7..4d1c74a 100644
> > > > --- a/include/media/v4l2-ioctl.h
> > > > +++ b/include/media/v4l2-ioctl.h
> > > > @@ -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,
> > > 
> > > Regards,
> > 
> > So, I take it as an ack;-)
> 
> It's not an ack yet but we're definitely close. :-)
> 
> 

I am happy with the API. The only thing that's unclear to me is whether you can call
CREATE_BUFS after REQBUFS. And if not, then why not? It would also be helpful to see
the full patch series as the last one was from April. It is interesting to see how
this will interface with vb2.

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus July 26, 2011, 11:44 a.m. UTC | #6
Hi Hans and Guennadi,

On Tue, Jul 26, 2011 at 01:05:29PM +0200, Hans Verkuil wrote:
> On Wednesday, July 20, 2011 17:19:46 Sakari Ailus wrote:
> > On Wed, Jul 20, 2011 at 04:47:46PM +0200, Guennadi Liakhovetski wrote:
> > > On Wed, 20 Jul 2011, Sakari Ailus wrote:
> > > 
> > > > Hi, Guennadi!
> > > > 
> > > > Thanks for the patch!
> > > > 
> > > > On Wed, Jul 20, 2011 at 10:43:08AM +0200, Guennadi Liakhovetski wrote:
> > > > > A possibility to preallocate and initialise buffers of different sizes
> > > > > in V4L2 is required for an efficient implementation of asnapshot mode.
> > > > > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > > > > VIDIOC_PREPARE_BUF and defines respective data structures.
> > > > > 
> > > > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > > > ---
> > > > > 
> > > > > It's been almost a month since v2, the only comments were a request to 
> > > > > increase the reserved space in the new ioctl() and to improve 
> > > > > documentation. The reserved field is increased in this version, 
> > > > > documentation also has been improved in multiple locations. I think, 
> > > > > documentation can be further improved at any time, but if there are no 
> > > > > objections against the actual contents of this patch, maybe we can commit 
> > > > > this version. I still don't see v3.0;-), so, maybe we even can push it for 
> > > > > 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> > > > > the only change in the API, and the compatibility fix as the only two 
> > > > > functional changes.
> > > > > 
> > > > > v3: addressed multiple comments by Sakari Ailus
> > > > > 
> > > > > 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
> > > > >    ints
> > > > > 2. multiple documentation fixes and improvements
> > > > > 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
> > > > >    processing
> > > > > 
> > > > > v2:
> > > > > 
> > > > > 1. add preliminary Documentation
> > > > > 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> > > > > 3. remove VIDIOC_DESTROY_BUFS
> > > > > 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> > > > > 5. add reserved field to struct v4l2_create_buffers
> > > > > 6. cache handling flags moved to struct v4l2_buffer for processing during 
> > > > >    VIDIOC_PREPARE_BUF
> > > > > 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> > > > > 
> > > > > 
> > > > >  Documentation/DocBook/media/v4l/io.xml             |   17 +++
> > > > >  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
> > > > >  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
> > > > >  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
> > > > >  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
> > > > >  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
> > > > >  include/linux/videodev2.h                          |   16 ++
> > > > >  include/media/v4l2-ioctl.h                         |    2 +
> > > > >  8 files changed, 377 insertions(+), 8 deletions(-)
> > > > >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > > >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > > > 
> > > > > diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> > > > > index 227e7ac..6249d0e 100644
> > > > > --- a/Documentation/DocBook/media/v4l/io.xml
> > > > > +++ b/Documentation/DocBook/media/v4l/io.xml
> > > > > @@ -927,6 +927,23 @@ ioctl is called.</entry>
> > > > >  Applications set or clear this flag before calling the
> > > > >  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
> > > > >  	  </row>
> > > > > +	  <row>
> > > > > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> > > > > +	    <entry>0x0400</entry>
> > > > > +	    <entry>Caches do not have to be invalidated for this buffer.
> > > > > +Typically applications shall use this flag, if the data, captured in the buffer
> > > > > +is not going to br touched by the CPU, instead the buffer will, probably, be
> > > > > +passed on to a DMA-capable hardware unit for further processing or output.
> > > > > +</entry>
> > > > > +	  </row>
> > > > > +	  <row>
> > > > > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> > > > > +	    <entry>0x0800</entry>
> > > > > +	    <entry>Caches do not have to be cleaned for this buffer.
> > > > > +Typically applications shall use this flag for output buffers, if the data
> > > > > +in this buffer has not been created by the CPU, but by some DMA-capable unit,
> > > > > +in which case caches have not been used.</entry>
> > > > > +	  </row>
> > > > >  	</tbody>
> > > > >        </tgroup>
> > > > >      </table>
> > > > > diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> > > > > index 0d05e87..06bb179 100644
> > > > > --- a/Documentation/DocBook/media/v4l/v4l2.xml
> > > > > +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> > > > > @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
> > > > >      &sub-close;
> > > > >      &sub-ioctl;
> > > > >      <!-- All ioctls go here. -->
> > > > > +    &sub-create-bufs;
> > > > >      &sub-cropcap;
> > > > >      &sub-dbg-g-chip-ident;
> > > > >      &sub-dbg-g-register;
> > > > > @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
> > > > >      &sub-queryctrl;
> > > > >      &sub-query-dv-preset;
> > > > >      &sub-querystd;
> > > > > +    &sub-prepare-buf;
> > > > >      &sub-reqbufs;
> > > > >      &sub-s-hw-freq-seek;
> > > > >      &sub-streamon;
> > > > > diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > > > new file mode 100644
> > > > > index 0000000..5f0158c
> > > > > --- /dev/null
> > > > > +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > > > > @@ -0,0 +1,152 @@
> > > > > +<refentry id="vidioc-create-bufs">
> > > > > +  <refmeta>
> > > > > +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> > > > > +    &manvol;
> > > > > +  </refmeta>
> > > > > +
> > > > > +  <refnamediv>
> > > > > +    <refname>VIDIOC_CREATE_BUFS</refname>
> > > > > +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> > > > > +  </refnamediv>
> > > > > +
> > > > > +  <refsynopsisdiv>
> > > > > +    <funcsynopsis>
> > > > > +      <funcprototype>
> > > > > +	<funcdef>int <function>ioctl</function></funcdef>
> > > > > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > > > > +	<paramdef>int <parameter>request</parameter></paramdef>
> > > > > +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> > > > > +      </funcprototype>
> > > > > +    </funcsynopsis>
> > > > > +  </refsynopsisdiv>
> > > > > +
> > > > > +  <refsect1>
> > > > > +    <title>Arguments</title>
> > > > > +
> > > > > +    <variablelist>
> > > > > +      <varlistentry>
> > > > > +	<term><parameter>fd</parameter></term>
> > > > > +	<listitem>
> > > > > +	  <para>&fd;</para>
> > > > > +	</listitem>
> > > > > +      </varlistentry>
> > > > > +      <varlistentry>
> > > > > +	<term><parameter>request</parameter></term>
> > > > > +	<listitem>
> > > > > +	  <para>VIDIOC_CREATE_BUFS</para>
> > > > > +	</listitem>
> > > > > +      </varlistentry>
> > > > > +      <varlistentry>
> > > > > +	<term><parameter>argp</parameter></term>
> > > > > +	<listitem>
> > > > > +	  <para></para>
> > > > > +	</listitem>
> > > > > +      </varlistentry>
> > > > > +    </variablelist>
> > > > > +  </refsect1>
> > > > > +
> > > > > +  <refsect1>
> > > > > +    <title>Description</title>
> > > > > +
> > > > > +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> > > > > +mapped</link> or <link linkend="userp">user pointer</link>
> > > > > +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> > > > > +ioctl, when a tighter control over buffers is required. This ioctl can be called
> > > > > +multiple times to create buffers of different sizes.
> 
> I realized that it is not clear from the documentation whether it is possible to call
> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.

That's actually a must if one wants to release buffers. Currently no other
method than requesting 0 buffers using REQBUFS is provided (apart from
closing the file handle).

> I can't remember whether the code allows it or not, but it should be clearly documented.

I would guess no user application would have to call REQBUFS with other than
zero buffers when using CREATE_BUFS. This must be an exception if mixing
REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
reason to prohibit either, but perhaps Guennadi has more informed opinion
on this.

> > > > > +
> > > > > +    <para>To allocate device buffers applications initialize all
> > > > > +fields of the <structname>v4l2_create_buffers</structname> structure.
> > > > > +They set the <structfield>type</structfield> field in the
> > > > > +<structname>v4l2_format</structname> structure, embedded in this
> > > > > +structure, to the respective stream or buffer type.
> > > > > +<structfield>count</structfield> must be set to the number of required
> > > > > +buffers. <structfield>memory</structfield> specifies the required I/O
> > > > > +method. Applications have two possibilities to specify the size of buffers
> > > > > +to be prepared: they can either set the <structfield>size</structfield>
> > > > > +field explicitly to a non-zero value, or fill in the frame format data in the
> > > > > +<structfield>format</structfield> field. In the latter case buffer sizes
> > > > > +will be calculated automatically by the driver. The
> > > > > +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> > > > > +is called with a pointer to this structure the driver will attempt to allocate
> > > > > +up to the requested number of buffers and store the actual number allocated
> > > > > +and the starting index in the <structfield>count</structfield> and
> > > > > +the <structfield>index</structfield> fields respectively.
> > > > > +<structfield>count</structfield> can be smaller than the number requested.
> > > > > +-ENOMEM is returned, if the driver runs out of free memory.</para>
> > > > 
> > > > No need to mention -ENOMEM here. It's already in the return values below;
> > > > the same goes for the EINVAL just below.
> > > 
> > > Yes, incremental patches welcome.
> > > 
> > > > 
> > > > > +    <para>When the I/O method is not supported the ioctl
> > > > > +returns an &EINVAL;.</para>
> > > > > +
> > > > > +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> > > > > +      <title>struct <structname>v4l2_create_buffers</structname></title>
> > > > > +      <tgroup cols="3">
> > > > > +	&cs-str;
> > > > > +	<tbody valign="top">
> > > > > +	  <row>
> > > > > +	    <entry>__u32</entry>
> > > > > +	    <entry><structfield>index</structfield></entry>
> > > > > +	    <entry>The starting buffer index, returned by the driver.</entry>
> > > > > +	  </row>
> > > > > +	  <row>
> > > > > +	    <entry>__u32</entry>
> > > > > +	    <entry><structfield>count</structfield></entry>
> > > > > +	    <entry>The number of buffers requested or granted.</entry>
> > > > > +	  </row>
> > > > > +	  <row>
> > > > > +	    <entry>&v4l2-memory;</entry>
> > > > > +	    <entry><structfield>memory</structfield></entry>
> > > > > +	    <entry>Applications set this field to
> > > > > +<constant>V4L2_MEMORY_MMAP</constant> or
> > > > > +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> > > > > +	  </row>
> > > > > +	  <row>
> > > > > +	    <entry>__u32</entry>
> > > > > +	    <entry><structfield>size</structfield></entry>
> > > > > +	    <entry>Explicit size of buffers, being created.</entry>
> > > > > +	  </row>
> > > > > +	  <row>
> > > > > +	    <entry>&v4l2-format;</entry>
> > > > > +	    <entry><structfield>format</structfield></entry>
> > > > > +	    <entry>Application has to set the <structfield>type</structfield>
> > > > > +field, other fields should be used, if the application wants to allocate buffers
> > > > > +for a specific frame format.</entry>
> > > > > +	  </row>
> > > > > +	  <row>
> > > > > +	    <entry>__u32</entry>
> > > > > +	    <entry><structfield>reserved</structfield>[8]</entry>
> > > > > +	    <entry>A place holder for future extensions.</entry>
> > > > > +	  </row>
> > > > > +	</tbody>
> > > > > +      </tgroup>
> > > > > +    </table>
> > > > > +  </refsect1>
> > > > > +
> > > > > +  <refsect1>
> > > > > +    &return-value;
> > > > > +
> > > > > +    <variablelist>
> > > > > +      <varlistentry>
> > > > > +	<term><errorcode>ENOMEM</errorcode></term>
> > > > > +	<listitem>
> > > > > +	  <para>No memory to allocate buffers for <link linkend="mmap">memory
> > > > > +mapped</link> I/O.</para>
> > > > > +	</listitem>
> > > > > +      </varlistentry>
> > > > > +      <varlistentry>
> > > > > +	<term><errorcode>EINVAL</errorcode></term>
> > > > > +	<listitem>
> > > > > +	  <para>The buffer type (<structfield>type</structfield> field) or the
> > > > > +requested I/O method (<structfield>memory</structfield>) is not
> > > > > +supported.</para>
> > > > > +	</listitem>
> > > > > +      </varlistentry>
> > > > > +    </variablelist>
> > > > > +  </refsect1>
> > > > > +</refentry>
> > > > > +
> > > > > +<!--
> > > > > +Local Variables:
> > > > > +mode: sgml
> > > > > +sgml-parent-document: "v4l2.sgml"
> > > > > +indent-tabs-mode: nil
> > > > > +End:
> > > > > +-->
> > > > > diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > > > new file mode 100644
> > > > > index 0000000..509e752
> > > > > --- /dev/null
> > > > > +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > > > > @@ -0,0 +1,96 @@
> > > > > +<refentry id="vidioc-prepare-buf">
> > > > > +  <refmeta>
> > > > > +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> > > > > +    &manvol;
> > > > > +  </refmeta>
> > > > > +
> > > > > +  <refnamediv>
> > > > > +    <refname>VIDIOC_PREPARE_BUF</refname>
> > > > > +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> > > > > +  </refnamediv>
> > > > > +
> > > > > +  <refsynopsisdiv>
> > > > > +    <funcsynopsis>
> > > > > +      <funcprototype>
> > > > > +	<funcdef>int <function>ioctl</function></funcdef>
> > > > > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > > > > +	<paramdef>int <parameter>request</parameter></paramdef>
> > > > > +	<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> > > > 
> > > > I'm not sure if we want to use struct v4l2_buffer here. It's an obvious
> > > > choice, but there's an issue in using it.
> > > > 
> > > > The struct is almost full i.e. there are very few reserved fields in it,
> > > > namely two, counting the input field which was unused AFAIR. There are now
> > > > three ioctls using it as their argument.
> > > > 
> > > > Future functionality which would be nice:
> > > > 
> > > > - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> > > >   come with a counter value so that the user would know the format of
> > > >   dequeued buffers when setting the format on-the-fly. Currently there are
> > > >   only bytesperline and length, but the format can't be explicitly
> > > >   determined from those.
> 
> Actually, the index field will give you that information. When you create the
> buffers you know that range [index, index + count - 1] is associated with that
> specific format.

Some hardware is able to change the format while streaming is ongoing (for
example: OMAP 3). The problem is that the user should be able to know which
frame has the new format.

Of course one could stop streaming but this would mean lost frames.

A flag has been proposed to this previously. That's one option but forces
the user to keep track of the changes since only one change is allowed until
it has taken effect.

> > > > - Binding to generic DMA buffers. This can likely be achieved by using the m
> > > >   union in struct v4l2_buffer. (Speaking of which: these buffers likely have
> > > >   a cache behaviour defined for them, e.g. they might be non-cacheable. This
> > > >   probably has no effect on the cache flags in V4L2 but it might still be
> > > >   good to keep this in mind.)
> 
> That will definitely be done through the 'm' union.
> 
> > > > I don't have an obvious replacement for it either. There are two options I
> > > > can see: Create a new struct v4l2_ext_buffer which contains the old
> > > > v4l2_buffer plus a bunch of reserved fields, or use the two last fields to
> > > > hold a pointer to an extension struct, v4l2_buffer_ext. The new structure
> > > > would later be used to contain the reserved fields.
> > > > 
> > > > I admit that this is not an issue right now, myt point is that I don't want
> > > > this to be an issue in the future either.
> > > 
> > > Good, then we'll address it, when it becomes an issue.
> > 
> > Defining v4l2_ext_buffer will mean there's a new ioctl. I think we should be
> > a little more future proof if we can. Extending the current v4l2_buffer by
> > another structure with a pointer from v4l2_buffer doesn't need this.
> > 
> > I would like to have someone else's opinion on what to do with this. The
> > resolution might as well be to accept the situation and resolve it when
> > there's an absolute need to.
> 
> Trying to define a new structure when we don't know if we need one, let alone
> what should be in there, doesn't seem useful to me. Especially since it would
> require yet another struct. I'm with Guennadi on this one.

Then this is settled on my behalf.

[clip]

Regards,
Hans Verkuil July 26, 2011, 11:57 a.m. UTC | #7
On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
> Hi Hans and Guennadi,

<snip>

> > I realized that it is not clear from the documentation whether it is possible to call
> > VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
> 
> That's actually a must if one wants to release buffers. Currently no other
> method than requesting 0 buffers using REQBUFS is provided (apart from
> closing the file handle).

I was referring to the non-0 use-case :-)

> > I can't remember whether the code allows it or not, but it should be clearly documented.
> 
> I would guess no user application would have to call REQBUFS with other than
> zero buffers when using CREATE_BUFS. This must be an exception if mixing
> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
> reason to prohibit either, but perhaps Guennadi has more informed opinion
> on this.
 
<snip>

> > > > > Future functionality which would be nice:
> > > > > 
> > > > > - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> > > > >   come with a counter value so that the user would know the format of
> > > > >   dequeued buffers when setting the format on-the-fly. Currently there are
> > > > >   only bytesperline and length, but the format can't be explicitly
> > > > >   determined from those.
> > 
> > Actually, the index field will give you that information. When you create the
> > buffers you know that range [index, index + count - 1] is associated with that
> > specific format.
> 
> Some hardware is able to change the format while streaming is ongoing (for
> example: OMAP 3). The problem is that the user should be able to know which
> frame has the new format.

Ah, of course.

> Of course one could stop streaming but this would mean lost frames.
> 
> A flag has been proposed to this previously. That's one option but forces
> the user to keep track of the changes since only one change is allowed until
> it has taken effect.

Something to discuss next week, I think.

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hi Gueannadi,

On 07/20/2011 10:43 AM, Guennadi Liakhovetski wrote:
> A possibility to preallocate and initialise buffers of different sizes
> in V4L2 is required for an efficient implementation of asnapshot mode.
> This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> VIDIOC_PREPARE_BUF and defines respective data structures.
> 
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
> 
> It's been almost a month since v2, the only comments were a request to 
> increase the reserved space in the new ioctl() and to improve 
> documentation. The reserved field is increased in this version, 
> documentation also has been improved in multiple locations. I think, 
> documentation can be further improved at any time, but if there are no 
> objections against the actual contents of this patch, maybe we can commit 
> this version. I still don't see v3.0;-), so, maybe we even can push it for 
> 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> the only change in the API, and the compatibility fix as the only two 
> functional changes.
> 
> v3: addressed multiple comments by Sakari Ailus
> 
> 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
>    ints
> 2. multiple documentation fixes and improvements
> 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
>    processing
> 
> v2:
> 
> 1. add preliminary Documentation
> 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> 3. remove VIDIOC_DESTROY_BUFS
> 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> 5. add reserved field to struct v4l2_create_buffers
> 6. cache handling flags moved to struct v4l2_buffer for processing during 
>    VIDIOC_PREPARE_BUF
> 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> 
> 
>  Documentation/DocBook/media/v4l/io.xml             |   17 +++
>  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
>  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
>  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
>  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
>  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
>  include/linux/videodev2.h                          |   16 ++
>  include/media/v4l2-ioctl.h                         |    2 +
>  8 files changed, 377 insertions(+), 8 deletions(-)
>  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
>  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> 
> diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> index 227e7ac..6249d0e 100644
> --- a/Documentation/DocBook/media/v4l/io.xml
> +++ b/Documentation/DocBook/media/v4l/io.xml
> @@ -927,6 +927,23 @@ ioctl is called.</entry>
>  Applications set or clear this flag before calling the
>  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
>  	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> +	    <entry>0x0400</entry>
> +	    <entry>Caches do not have to be invalidated for this buffer.
> +Typically applications shall use this flag, if the data, captured in the buffer
> +is not going to br touched by the CPU, instead the buffer will, probably, be
> +passed on to a DMA-capable hardware unit for further processing or output.
> +</entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> +	    <entry>0x0800</entry>
> +	    <entry>Caches do not have to be cleaned for this buffer.
> +Typically applications shall use this flag for output buffers, if the data
> +in this buffer has not been created by the CPU, but by some DMA-capable unit,
> +in which case caches have not been used.</entry>
> +	  </row>
>  	</tbody>
>        </tgroup>
>      </table>
> diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> index 0d05e87..06bb179 100644
> --- a/Documentation/DocBook/media/v4l/v4l2.xml
> +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
>      &sub-close;
>      &sub-ioctl;
>      <!-- All ioctls go here. -->
> +    &sub-create-bufs;
>      &sub-cropcap;
>      &sub-dbg-g-chip-ident;
>      &sub-dbg-g-register;
> @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
>      &sub-queryctrl;
>      &sub-query-dv-preset;
>      &sub-querystd;
> +    &sub-prepare-buf;
>      &sub-reqbufs;
>      &sub-s-hw-freq-seek;
>      &sub-streamon;
> diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> new file mode 100644
> index 0000000..5f0158c
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> @@ -0,0 +1,152 @@
> +<refentry id="vidioc-create-bufs">
> +  <refmeta>
> +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> +    &manvol;
> +  </refmeta>
> +
> +  <refnamediv>
> +    <refname>VIDIOC_CREATE_BUFS</refname>
> +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> +  </refnamediv>
> +
> +  <refsynopsisdiv>
> +    <funcsynopsis>
> +      <funcprototype>
> +	<funcdef>int <function>ioctl</function></funcdef>
> +	<paramdef>int <parameter>fd</parameter></paramdef>
> +	<paramdef>int <parameter>request</parameter></paramdef>
> +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> +      </funcprototype>
> +    </funcsynopsis>
> +  </refsynopsisdiv>
> +
> +  <refsect1>
> +    <title>Arguments</title>
> +
> +    <variablelist>
> +      <varlistentry>
> +	<term><parameter>fd</parameter></term>
> +	<listitem>
> +	  <para>&fd;</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>request</parameter></term>
> +	<listitem>
> +	  <para>VIDIOC_CREATE_BUFS</para>
> +	</listitem>
> +      </varlistentry>
> +      <varlistentry>
> +	<term><parameter>argp</parameter></term>
> +	<listitem>
> +	  <para></para>
> +	</listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +
> +  <refsect1>
> +    <title>Description</title>
> +
> +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> +mapped</link> or <link linkend="userp">user pointer</link>
> +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> +ioctl, when a tighter control over buffers is required. This ioctl can be called
> +multiple times to create buffers of different sizes.

It looks like there is a </para> tag missing, that line should be:

+multiple times to create buffers of different sizes. </para>

Otherwise the compilation fails.


--
Regards,
Sylwester Nawrocki
Pawel Osciak July 28, 2011, 4:11 a.m. UTC | #9
Hi Guennadi,

On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
<g.liakhovetski@gmx.de> wrote:
> A possibility to preallocate and initialise buffers of different sizes
> in V4L2 is required for an efficient implementation of asnapshot mode.
> This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> VIDIOC_PREPARE_BUF and defines respective data structures.
>
> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> ---
>
<snip>

This looks nicer, I like how we got rid of destroy and gave up on
making holes, it would've given us a lot of headaches. I'm thinking
about some issues though and also have some comments/questions further
below.

Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
Personally I'd like to allow mixing, including REQBUFS for non-zero,
because I think it would be easy to do. I think it could work in the
same way as REQBUFS for !=0 works currently (at least in vb2), if we
already have some buffers allocated and they are not in use, we free
them and a new set is allocated. So I guess it could just stay this
way. REQBUFS(0) would of course free everything.

Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
would have to pass it forward to the driver somehow. The obvious way
would be just vb2 calling the driver's s_fmt handler, but that won't
work, as you can't pass indexes to s_fmt. So we'd have to implement a
new driver callback for setting formats per index. I guess there is no
way around it, unless we actually take the format struct out of
CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
is full already though, the only way would be to use
v4l2_pix_format_mplane instead with plane count = 1 (or more if
needed).

Another thing is the case of passing size to CREATE_BUFS. vb2, when
allocating buffers, gets their sizes from the driver (via
queue_setup), it never "suggest" any particular size. So that flow
would have to be changed as well. I guess vb2 could pass the size to
queue_setup in a similar way as it does with buffer count. This would
mean though that the ioctl would fail if the driver didn't agree to
the given size. Right now I don't see an option to "negotiate" the
size with the driver via this option.

The more I think of it though, why do we need the size argument? It's
not needed in the existing flows (that use S_FMT) and, more
importantly, I don't think the application can know more than the
driver can, so why giving that option? The driver should know the size
for a format at least as well as the application... Also, is there a
real use case of providing just size, will the driver know which
format to use given a size?


> +    <para>To allocate device buffers applications initialize all
> +fields of the <structname>v4l2_create_buffers</structname> structure.
> +They set the <structfield>type</structfield> field in the
> +<structname>v4l2_format</structname> structure, embedded in this
> +structure, to the respective stream or buffer type.
> +<structfield>count</structfield> must be set to the number of required
> +buffers. <structfield>memory</structfield> specifies the required I/O
> +method. Applications have two possibilities to specify the size of buffers
> +to be prepared: they can either set the <structfield>size</structfield>
> +field explicitly to a non-zero value, or fill in the frame format data in the
> +<structfield>format</structfield> field. In the latter case buffer sizes
> +will be calculated automatically by the driver. The

Technically, we shouldn't say "applications initialize all fields" in
the first sentence if they do not have to initialize both size and
format fields at the same time.

> +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> +is called with a pointer to this structure the driver will attempt to allocate
> +up to the requested number of buffers and store the actual number allocated
> +and the starting index in the <structfield>count</structfield> and
> +the <structfield>index</structfield> fields respectively.
> +<structfield>count</structfield> can be smaller than the number requested.
> +-ENOMEM is returned, if the driver runs out of free memory.</para>
> +    <para>When the I/O method is not supported the ioctl
> +returns an &EINVAL;.</para>
> +
> +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> +      <title>struct <structname>v4l2_create_buffers</structname></title>
> +      <tgroup cols="3">
> +       &cs-str;
> +       <tbody valign="top">
> +         <row>
> +           <entry>__u32</entry>
> +           <entry><structfield>index</structfield></entry>
> +           <entry>The starting buffer index, returned by the driver.</entry>
> +         </row>
> +         <row>
> +           <entry>__u32</entry>
> +           <entry><structfield>count</structfield></entry>
> +           <entry>The number of buffers requested or granted.</entry>
> +         </row>
> +         <row>
> +           <entry>&v4l2-memory;</entry>
> +           <entry><structfield>memory</structfield></entry>
> +           <entry>Applications set this field to
> +<constant>V4L2_MEMORY_MMAP</constant> or
> +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> +         </row>
> +         <row>
> +           <entry>__u32</entry>
> +           <entry><structfield>size</structfield></entry>
> +           <entry>Explicit size of buffers, being created.</entry>
> +         </row>
> +         <row>
> +           <entry>&v4l2-format;</entry>
> +           <entry><structfield>format</structfield></entry>
> +           <entry>Application has to set the <structfield>type</structfield>
> +field, other fields should be used, if the application wants to allocate buffers
> +for a specific frame format.</entry>
> +         </row>
> +         <row>
> +           <entry>__u32</entry>
> +           <entry><structfield>reserved</structfield>[8]</entry>
> +           <entry>A place holder for future extensions.</entry>
> +         </row>
> +       </tbody>
> +      </tgroup>
> +    </table>
> +  </refsect1>
> +
> +  <refsect1>
> +    &return-value;
> +
> +    <variablelist>
> +      <varlistentry>
> +       <term><errorcode>ENOMEM</errorcode></term>
> +       <listitem>
> +         <para>No memory to allocate buffers for <link linkend="mmap">memory
> +mapped</link> I/O.</para>
> +       </listitem>
> +      </varlistentry>
> +      <varlistentry>
> +       <term><errorcode>EINVAL</errorcode></term>
> +       <listitem>
> +         <para>The buffer type (<structfield>type</structfield> field) or the
> +requested I/O method (<structfield>memory</structfield>) is not
> +supported.</para>
> +       </listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +</refentry>
> +

What happens if the driver does not agree to the provided size? EINVAL?

> +<!--
> +Local Variables:
> +mode: sgml
> +sgml-parent-document: "v4l2.sgml"
> +indent-tabs-mode: nil
> +End:
> +-->
> diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> new file mode 100644
> index 0000000..509e752
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> @@ -0,0 +1,96 @@
> +<refentry id="vidioc-prepare-buf">
> +  <refmeta>
> +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> +    &manvol;
> +  </refmeta>
> +
> +  <refnamediv>
> +    <refname>VIDIOC_PREPARE_BUF</refname>
> +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> +  </refnamediv>
> +
> +  <refsynopsisdiv>
> +    <funcsynopsis>
> +      <funcprototype>
> +       <funcdef>int <function>ioctl</function></funcdef>
> +       <paramdef>int <parameter>fd</parameter></paramdef>
> +       <paramdef>int <parameter>request</parameter></paramdef>
> +       <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> +      </funcprototype>
> +    </funcsynopsis>
> +  </refsynopsisdiv>
> +
> +  <refsect1>
> +    <title>Arguments</title>
> +
> +    <variablelist>
> +      <varlistentry>
> +       <term><parameter>fd</parameter></term>
> +       <listitem>
> +         <para>&fd;</para>
> +       </listitem>
> +      </varlistentry>
> +      <varlistentry>
> +       <term><parameter>request</parameter></term>
> +       <listitem>
> +         <para>VIDIOC_PREPARE_BUF</para>
> +       </listitem>
> +      </varlistentry>
> +      <varlistentry>
> +       <term><parameter>argp</parameter></term>
> +       <listitem>
> +         <para></para>
> +       </listitem>
> +      </varlistentry>
> +    </variablelist>
> +  </refsect1>
> +
> +  <refsect1>
> +    <title>Description</title>
> +
> +    <para>Applications can optionally call the
> +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> +to the driver before actually enqueuing it, using the
> +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> +Such preparations may include cache invalidation or cleaning. Performing them
> +in advance saves time during the actual I/O. In case such cache operations are
> +not required, the application can use one of
> +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> +step.</para>
> +

I'm probably forgetting something, but why would we want to do both
PREPARE_BUF and QBUF? Why not queue in advance?
Could you give a full sequence of ioctls how it will be used
(including streamons, etc.)? I'm trying to picture how passing of both
types of buffers will have to look like between vb2 and a driver.

<snip>

--
Best regards,
Pawel Osciak
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hans Verkuil July 28, 2011, 6:56 a.m. UTC | #10
On Thursday, July 28, 2011 06:11:38 Pawel Osciak wrote:
> Hi Guennadi,
> 
> On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > A possibility to preallocate and initialise buffers of different sizes
> > in V4L2 is required for an efficient implementation of asnapshot mode.
> > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > VIDIOC_PREPARE_BUF and defines respective data structures.
> >
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
> >
> <snip>
> 
> This looks nicer, I like how we got rid of destroy and gave up on
> making holes, it would've given us a lot of headaches. I'm thinking
> about some issues though and also have some comments/questions further
> below.
> 
> Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
> Personally I'd like to allow mixing, including REQBUFS for non-zero,
> because I think it would be easy to do. I think it could work in the
> same way as REQBUFS for !=0 works currently (at least in vb2), if we
> already have some buffers allocated and they are not in use, we free
> them and a new set is allocated. So I guess it could just stay this
> way. REQBUFS(0) would of course free everything.
> 
> Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
> would have to pass it forward to the driver somehow. The obvious way
> would be just vb2 calling the driver's s_fmt handler, but that won't
> work, as you can't pass indexes to s_fmt. So we'd have to implement a
> new driver callback for setting formats per index. I guess there is no
> way around it, unless we actually take the format struct out of
> CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
> is full already though, the only way would be to use
> v4l2_pix_format_mplane instead with plane count = 1 (or more if
> needed).

I just got an idea for this: use TRY_FMT. That will do exactly what
you want. In fact, perhaps we should remove the format struct from
CREATE_BUFS and use __u32 sizes[VIDEO_MAX_PLANES] instead. Let the
application call TRY_FMT and initialize the sizes array instead of
putting that into vb2. We may need a num_planes field as well. If the
sizes are all 0 (or num_planes is 0), then the driver can use the current
format, just as it does with REQBUFS.

Or am I missing something?

> Another thing is the case of passing size to CREATE_BUFS. vb2, when
> allocating buffers, gets their sizes from the driver (via
> queue_setup), it never "suggest" any particular size. So that flow
> would have to be changed as well. I guess vb2 could pass the size to
> queue_setup in a similar way as it does with buffer count. This would
> mean though that the ioctl would fail if the driver didn't agree to
> the given size. Right now I don't see an option to "negotiate" the
> size with the driver via this option.

I think the driver can always increase the size if needed and return the
new size.

> 
> The more I think of it though, why do we need the size argument? It's
> not needed in the existing flows (that use S_FMT) and, more
> importantly, I don't think the application can know more than the
> driver can, so why giving that option? The driver should know the size
> for a format at least as well as the application... Also, is there a
> real use case of providing just size, will the driver know which
> format to use given a size?

There are cases where you want a larger buffer size than the format
really required. The most common case being 1920x1080 formats where you
want to capture in a 1920x1088 buffer (since 1088 is a multiple of 16
and is more suitable for MPEG et al encoding).

So, yes, you do want the option to set the size explicitly.

> 
> 
> > +    <para>To allocate device buffers applications initialize all
> > +fields of the <structname>v4l2_create_buffers</structname> structure.
> > +They set the <structfield>type</structfield> field in the
> > +<structname>v4l2_format</structname> structure, embedded in this
> > +structure, to the respective stream or buffer type.
> > +<structfield>count</structfield> must be set to the number of required
> > +buffers. <structfield>memory</structfield> specifies the required I/O
> > +method. Applications have two possibilities to specify the size of buffers
> > +to be prepared: they can either set the <structfield>size</structfield>
> > +field explicitly to a non-zero value, or fill in the frame format data in the
> > +<structfield>format</structfield> field. In the latter case buffer sizes
> > +will be calculated automatically by the driver. The
> 
> Technically, we shouldn't say "applications initialize all fields" in
> the first sentence if they do not have to initialize both size and
> format fields at the same time.
> 
> > +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> > +is called with a pointer to this structure the driver will attempt to allocate
> > +up to the requested number of buffers and store the actual number allocated
> > +and the starting index in the <structfield>count</structfield> and
> > +the <structfield>index</structfield> fields respectively.
> > +<structfield>count</structfield> can be smaller than the number requested.
> > +-ENOMEM is returned, if the driver runs out of free memory.</para>
> > +    <para>When the I/O method is not supported the ioctl
> > +returns an &EINVAL;.</para>
> > +
> > +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> > +      <title>struct <structname>v4l2_create_buffers</structname></title>
> > +      <tgroup cols="3">
> > +       &cs-str;
> > +       <tbody valign="top">
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>index</structfield></entry>
> > +           <entry>The starting buffer index, returned by the driver.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>count</structfield></entry>
> > +           <entry>The number of buffers requested or granted.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>&v4l2-memory;</entry>
> > +           <entry><structfield>memory</structfield></entry>
> > +           <entry>Applications set this field to
> > +<constant>V4L2_MEMORY_MMAP</constant> or
> > +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>size</structfield></entry>
> > +           <entry>Explicit size of buffers, being created.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>&v4l2-format;</entry>
> > +           <entry><structfield>format</structfield></entry>
> > +           <entry>Application has to set the <structfield>type</structfield>
> > +field, other fields should be used, if the application wants to allocate buffers
> > +for a specific frame format.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>reserved</structfield>[8]</entry>
> > +           <entry>A place holder for future extensions.</entry>
> > +         </row>
> > +       </tbody>
> > +      </tgroup>
> > +    </table>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    &return-value;
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +       <term><errorcode>ENOMEM</errorcode></term>
> > +       <listitem>
> > +         <para>No memory to allocate buffers for <link linkend="mmap">memory
> > +mapped</link> I/O.</para>
> > +       </listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +       <term><errorcode>EINVAL</errorcode></term>
> > +       <listitem>
> > +         <para>The buffer type (<structfield>type</structfield> field) or the
> > +requested I/O method (<structfield>memory</structfield>) is not
> > +supported.</para>
> > +       </listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +</refentry>
> > +
> 
> What happens if the driver does not agree to the provided size? EINVAL?
> 
> > +<!--
> > +Local Variables:
> > +mode: sgml
> > +sgml-parent-document: "v4l2.sgml"
> > +indent-tabs-mode: nil
> > +End:
> > +-->
> > diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > new file mode 100644
> > index 0000000..509e752
> > --- /dev/null
> > +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > @@ -0,0 +1,96 @@
> > +<refentry id="vidioc-prepare-buf">
> > +  <refmeta>
> > +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> > +    &manvol;
> > +  </refmeta>
> > +
> > +  <refnamediv>
> > +    <refname>VIDIOC_PREPARE_BUF</refname>
> > +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> > +  </refnamediv>
> > +
> > +  <refsynopsisdiv>
> > +    <funcsynopsis>
> > +      <funcprototype>
> > +       <funcdef>int <function>ioctl</function></funcdef>
> > +       <paramdef>int <parameter>fd</parameter></paramdef>
> > +       <paramdef>int <parameter>request</parameter></paramdef>
> > +       <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> > +      </funcprototype>
> > +    </funcsynopsis>
> > +  </refsynopsisdiv>
> > +
> > +  <refsect1>
> > +    <title>Arguments</title>
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +       <term><parameter>fd</parameter></term>
> > +       <listitem>
> > +         <para>&fd;</para>
> > +       </listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +       <term><parameter>request</parameter></term>
> > +       <listitem>
> > +         <para>VIDIOC_PREPARE_BUF</para>
> > +       </listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +       <term><parameter>argp</parameter></term>
> > +       <listitem>
> > +         <para></para>
> > +       </listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    <title>Description</title>
> > +
> > +    <para>Applications can optionally call the
> > +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> > +to the driver before actually enqueuing it, using the
> > +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> > +Such preparations may include cache invalidation or cleaning. Performing them
> > +in advance saves time during the actual I/O. In case such cache operations are
> > +not required, the application can use one of
> > +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> > +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> > +step.</para>
> > +
> 
> I'm probably forgetting something, but why would we want to do both
> PREPARE_BUF and QBUF? Why not queue in advance?

QBUF both prepares the buffer and makes it available for use with DMA. You don't want
that. You just want to prepare it (that's the part that is expensive) and postpone
the actual queuing until the buffer is needed to e.g. take a snapshot.

Regards,

	Hans

> Could you give a full sequence of ioctls how it will be used
> (including streamons, etc.)? I'm trying to picture how passing of both
> types of buffers will have to look like between vb2 and a driver.
> 
> <snip>
> 
> --
> Best regards,
> Pawel Osciak
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski July 28, 2011, 10:26 a.m. UTC | #11
On Tue, 26 Jul 2011, Hans Verkuil wrote:

[snip]

> I am happy with the API. The only thing that's unclear to me is whether you can call
> CREATE_BUFS after REQBUFS. And if not, then why not? It would also be helpful to see
> the full patch series as the last one was from April. It is interesting to see how
> this will interface with vb2.

I think it would be logical to allow both, since we anyway need 
REQBUFS(count=0) for freeing of buffers. This would confirm, that buffers 
vreated with either of these methods are indistinguishable. Then we shall 
define:

CREATE_BUFS after REQBUFS or after earlier CREATE_BUFS adds more buffers
REQBUFS(count=0) frees all buffers
REQBUFS(count > 0) frees all buffers and allocates new ones

Yes, I'll extend the documentation with this.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski July 28, 2011, 10:28 a.m. UTC | #12
Hi Sylwester

On Wed, 27 Jul 2011, Sylwester Nawrocki wrote:

> Hi Gueannadi,
> 
> On 07/20/2011 10:43 AM, Guennadi Liakhovetski wrote:
> > A possibility to preallocate and initialise buffers of different sizes
> > in V4L2 is required for an efficient implementation of asnapshot mode.
> > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > VIDIOC_PREPARE_BUF and defines respective data structures.
> > 
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
> > 
> > It's been almost a month since v2, the only comments were a request to 
> > increase the reserved space in the new ioctl() and to improve 
> > documentation. The reserved field is increased in this version, 
> > documentation also has been improved in multiple locations. I think, 
> > documentation can be further improved at any time, but if there are no 
> > objections against the actual contents of this patch, maybe we can commit 
> > this version. I still don't see v3.0;-), so, maybe we even can push it for 
> > 3.1. A trivial comparison with v2 shows the size of the reserved field as 
> > the only change in the API, and the compatibility fix as the only two 
> > functional changes.
> > 
> > v3: addressed multiple comments by Sakari Ailus
> > 
> > 1. increased reserved field in "struct v4l2_create_buffers" to 8 32-bit 
> >    ints
> > 2. multiple documentation fixes and improvements
> > 3. fixed misplaced "case VIDIOC_PREPARE_BUF" in ioctl 32-bit compatibility 
> >    processing
> > 
> > v2:
> > 
> > 1. add preliminary Documentation
> > 2. add flag V4L2_BUFFER_FLAG_NO_CACHE_CLEAN
> > 3. remove VIDIOC_DESTROY_BUFS
> > 4. rename SUBMIT to VIDIOC_PREPARE_BUF
> > 5. add reserved field to struct v4l2_create_buffers
> > 6. cache handling flags moved to struct v4l2_buffer for processing during 
> >    VIDIOC_PREPARE_BUF
> > 7. VIDIOC_PREPARE_BUF now uses struct v4l2_buffer as its argument
> > 
> > 
> >  Documentation/DocBook/media/v4l/io.xml             |   17 +++
> >  Documentation/DocBook/media/v4l/v4l2.xml           |    2 +
> >  .../DocBook/media/v4l/vidioc-create-bufs.xml       |  152 ++++++++++++++++++++
> >  .../DocBook/media/v4l/vidioc-prepare-buf.xml       |   96 ++++++++++++
> >  drivers/media/video/v4l2-compat-ioctl32.c          |   68 ++++++++-
> >  drivers/media/video/v4l2-ioctl.c                   |   32 ++++
> >  include/linux/videodev2.h                          |   16 ++
> >  include/media/v4l2-ioctl.h                         |    2 +
> >  8 files changed, 377 insertions(+), 8 deletions(-)
> >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> >  create mode 100644 Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > 
> > diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
> > index 227e7ac..6249d0e 100644
> > --- a/Documentation/DocBook/media/v4l/io.xml
> > +++ b/Documentation/DocBook/media/v4l/io.xml
> > @@ -927,6 +927,23 @@ ioctl is called.</entry>
> >  Applications set or clear this flag before calling the
> >  <constant>VIDIOC_QBUF</constant> ioctl.</entry>
> >  	  </row>
> > +	  <row>
> > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
> > +	    <entry>0x0400</entry>
> > +	    <entry>Caches do not have to be invalidated for this buffer.
> > +Typically applications shall use this flag, if the data, captured in the buffer
> > +is not going to br touched by the CPU, instead the buffer will, probably, be
> > +passed on to a DMA-capable hardware unit for further processing or output.
> > +</entry>
> > +	  </row>
> > +	  <row>
> > +	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
> > +	    <entry>0x0800</entry>
> > +	    <entry>Caches do not have to be cleaned for this buffer.
> > +Typically applications shall use this flag for output buffers, if the data
> > +in this buffer has not been created by the CPU, but by some DMA-capable unit,
> > +in which case caches have not been used.</entry>
> > +	  </row>
> >  	</tbody>
> >        </tgroup>
> >      </table>
> > diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> > index 0d05e87..06bb179 100644
> > --- a/Documentation/DocBook/media/v4l/v4l2.xml
> > +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> > @@ -462,6 +462,7 @@ and discussions on the V4L mailing list.</revremark>
> >      &sub-close;
> >      &sub-ioctl;
> >      <!-- All ioctls go here. -->
> > +    &sub-create-bufs;
> >      &sub-cropcap;
> >      &sub-dbg-g-chip-ident;
> >      &sub-dbg-g-register;
> > @@ -504,6 +505,7 @@ and discussions on the V4L mailing list.</revremark>
> >      &sub-queryctrl;
> >      &sub-query-dv-preset;
> >      &sub-querystd;
> > +    &sub-prepare-buf;
> >      &sub-reqbufs;
> >      &sub-s-hw-freq-seek;
> >      &sub-streamon;
> > diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > new file mode 100644
> > index 0000000..5f0158c
> > --- /dev/null
> > +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
> > @@ -0,0 +1,152 @@
> > +<refentry id="vidioc-create-bufs">
> > +  <refmeta>
> > +    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
> > +    &manvol;
> > +  </refmeta>
> > +
> > +  <refnamediv>
> > +    <refname>VIDIOC_CREATE_BUFS</refname>
> > +    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
> > +  </refnamediv>
> > +
> > +  <refsynopsisdiv>
> > +    <funcsynopsis>
> > +      <funcprototype>
> > +	<funcdef>int <function>ioctl</function></funcdef>
> > +	<paramdef>int <parameter>fd</parameter></paramdef>
> > +	<paramdef>int <parameter>request</parameter></paramdef>
> > +	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
> > +      </funcprototype>
> > +    </funcsynopsis>
> > +  </refsynopsisdiv>
> > +
> > +  <refsect1>
> > +    <title>Arguments</title>
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +	<term><parameter>fd</parameter></term>
> > +	<listitem>
> > +	  <para>&fd;</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><parameter>request</parameter></term>
> > +	<listitem>
> > +	  <para>VIDIOC_CREATE_BUFS</para>
> > +	</listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +	<term><parameter>argp</parameter></term>
> > +	<listitem>
> > +	  <para></para>
> > +	</listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    <title>Description</title>
> > +
> > +    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
> > +mapped</link> or <link linkend="userp">user pointer</link>
> > +I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
> > +ioctl, when a tighter control over buffers is required. This ioctl can be called
> > +multiple times to create buffers of different sizes.
> 
> It looks like there is a </para> tag missing, that line should be:
> 
> +multiple times to create buffers of different sizes. </para>
> 
> Otherwise the compilation fails.

Right, will be fixed.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski July 28, 2011, 12:29 p.m. UTC | #13
On Thu, 28 Jul 2011, Hans Verkuil wrote:

> On Thursday, July 28, 2011 06:11:38 Pawel Osciak wrote:
> > Hi Guennadi,
> > 
> > On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
> > <g.liakhovetski@gmx.de> wrote:
> > > A possibility to preallocate and initialise buffers of different sizes
> > > in V4L2 is required for an efficient implementation of asnapshot mode.
> > > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > > VIDIOC_PREPARE_BUF and defines respective data structures.
> > >
> > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > ---
> > >
> > <snip>
> > 
> > This looks nicer, I like how we got rid of destroy and gave up on
> > making holes, it would've given us a lot of headaches. I'm thinking
> > about some issues though and also have some comments/questions further
> > below.
> > 
> > Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
> > Personally I'd like to allow mixing, including REQBUFS for non-zero,
> > because I think it would be easy to do. I think it could work in the
> > same way as REQBUFS for !=0 works currently (at least in vb2), if we
> > already have some buffers allocated and they are not in use, we free
> > them and a new set is allocated. So I guess it could just stay this
> > way. REQBUFS(0) would of course free everything.
> > 
> > Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
> > would have to pass it forward to the driver somehow. The obvious way
> > would be just vb2 calling the driver's s_fmt handler, but that won't
> > work, as you can't pass indexes to s_fmt. So we'd have to implement a
> > new driver callback for setting formats per index. I guess there is no
> > way around it, unless we actually take the format struct out of
> > CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
> > is full already though, the only way would be to use
> > v4l2_pix_format_mplane instead with plane count = 1 (or more if
> > needed).
> 
> I just got an idea for this: use TRY_FMT. That will do exactly what
> you want. In fact, perhaps we should remove the format struct from
> CREATE_BUFS and use __u32 sizes[VIDEO_MAX_PLANES] instead. Let the
> application call TRY_FMT and initialize the sizes array instead of
> putting that into vb2. We may need a num_planes field as well. If the
> sizes are all 0 (or num_planes is 0), then the driver can use the current
> format, just as it does with REQBUFS.

Hm, I think, I like this idea. It gives applications more flexibility and 
removes the size == 0 vs. size != 0 dilemma. So, we get

/* VIDIOC_CREATE_BUFS */
struct v4l2_create_buffers {
	__u32			index;		/* output: buffers index...index + count - 1 have been created */
	__u32			count;
	__u32			num_planes;
	__u32			sizes[VIDEO_MAX_PLANES];
	enum v4l2_memory        memory;
	enum v4l2_buf_type	type;
	__u32			reserved[8];
};

?

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Hans Verkuil (hansverk) July 28, 2011, 12:42 p.m. UTC | #14
On Thursday, July 28, 2011 14:29:38 Guennadi Liakhovetski wrote:
> On Thu, 28 Jul 2011, Hans Verkuil wrote:
> 
> > On Thursday, July 28, 2011 06:11:38 Pawel Osciak wrote:
> > > Hi Guennadi,
> > > 
> > > On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
> > > <g.liakhovetski@gmx.de> wrote:
> > > > A possibility to preallocate and initialise buffers of different sizes
> > > > in V4L2 is required for an efficient implementation of asnapshot mode.
> > > > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > > > VIDIOC_PREPARE_BUF and defines respective data structures.
> > > >
> > > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > > ---
> > > >
> > > <snip>
> > > 
> > > This looks nicer, I like how we got rid of destroy and gave up on
> > > making holes, it would've given us a lot of headaches. I'm thinking
> > > about some issues though and also have some comments/questions further
> > > below.
> > > 
> > > Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
> > > Personally I'd like to allow mixing, including REQBUFS for non-zero,
> > > because I think it would be easy to do. I think it could work in the
> > > same way as REQBUFS for !=0 works currently (at least in vb2), if we
> > > already have some buffers allocated and they are not in use, we free
> > > them and a new set is allocated. So I guess it could just stay this
> > > way. REQBUFS(0) would of course free everything.
> > > 
> > > Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
> > > would have to pass it forward to the driver somehow. The obvious way
> > > would be just vb2 calling the driver's s_fmt handler, but that won't
> > > work, as you can't pass indexes to s_fmt. So we'd have to implement a
> > > new driver callback for setting formats per index. I guess there is no
> > > way around it, unless we actually take the format struct out of
> > > CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
> > > is full already though, the only way would be to use
> > > v4l2_pix_format_mplane instead with plane count = 1 (or more if
> > > needed).
> > 
> > I just got an idea for this: use TRY_FMT. That will do exactly what
> > you want. In fact, perhaps we should remove the format struct from
> > CREATE_BUFS and use __u32 sizes[VIDEO_MAX_PLANES] instead. Let the
> > application call TRY_FMT and initialize the sizes array instead of
> > putting that into vb2. We may need a num_planes field as well. If the
> > sizes are all 0 (or num_planes is 0), then the driver can use the current
> > format, just as it does with REQBUFS.
> 
> Hm, I think, I like this idea. It gives applications more flexibility and 
> removes the size == 0 vs. size != 0 dilemma. So, we get
> 
> /* VIDIOC_CREATE_BUFS */
> struct v4l2_create_buffers {
> 	__u32			index;		/* output: buffers index...index + count - 1 have been created */
> 	__u32			count;
> 	__u32			num_planes;
> 	__u32			sizes[VIDEO_MAX_PLANES];
> 	enum v4l2_memory        memory;
> 	enum v4l2_buf_type	type;
> 	__u32			reserved[8];
> };
> 
> ?

Yes. I'd probably rearrange the fields a bit, though:

/* VIDIOC_CREATE_BUFS */
struct v4l2_create_buffers {
	__u32			index;		/* output: buffers index...index + count - 1 have been created */
	__u32			count;
	__u32			type;
	__u32			memory;
	__u32			num_planes;
	__u32			sizes[VIDEO_MAX_PLANES];
	__u32			reserved[8];
};

The order of the count, type and memory fields is now identical to that of
v4l2_requestbuffers.

I also changed the enums to u32 since without the v4l2_format struct we shouldn't
use enums. As an additional bonus this also simplifies the compat32 code.

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus July 29, 2011, 7:59 a.m. UTC | #15
On Thu, Jul 28, 2011 at 02:42:52PM +0200, Hans Verkuil wrote:
> On Thursday, July 28, 2011 14:29:38 Guennadi Liakhovetski wrote:
> > On Thu, 28 Jul 2011, Hans Verkuil wrote:
> > 
> > > On Thursday, July 28, 2011 06:11:38 Pawel Osciak wrote:
> > > > Hi Guennadi,
> > > > 
> > > > On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
> > > > <g.liakhovetski@gmx.de> wrote:
> > > > > A possibility to preallocate and initialise buffers of different sizes
> > > > > in V4L2 is required for an efficient implementation of asnapshot mode.
> > > > > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > > > > VIDIOC_PREPARE_BUF and defines respective data structures.
> > > > >
> > > > > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > > > > ---
> > > > >
> > > > <snip>
> > > > 
> > > > This looks nicer, I like how we got rid of destroy and gave up on
> > > > making holes, it would've given us a lot of headaches. I'm thinking
> > > > about some issues though and also have some comments/questions further
> > > > below.
> > > > 
> > > > Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
> > > > Personally I'd like to allow mixing, including REQBUFS for non-zero,
> > > > because I think it would be easy to do. I think it could work in the
> > > > same way as REQBUFS for !=0 works currently (at least in vb2), if we
> > > > already have some buffers allocated and they are not in use, we free
> > > > them and a new set is allocated. So I guess it could just stay this
> > > > way. REQBUFS(0) would of course free everything.
> > > > 
> > > > Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
> > > > would have to pass it forward to the driver somehow. The obvious way
> > > > would be just vb2 calling the driver's s_fmt handler, but that won't
> > > > work, as you can't pass indexes to s_fmt. So we'd have to implement a
> > > > new driver callback for setting formats per index. I guess there is no
> > > > way around it, unless we actually take the format struct out of
> > > > CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
> > > > is full already though, the only way would be to use
> > > > v4l2_pix_format_mplane instead with plane count = 1 (or more if
> > > > needed).
> > > 
> > > I just got an idea for this: use TRY_FMT. That will do exactly what
> > > you want. In fact, perhaps we should remove the format struct from
> > > CREATE_BUFS and use __u32 sizes[VIDEO_MAX_PLANES] instead. Let the
> > > application call TRY_FMT and initialize the sizes array instead of
> > > putting that into vb2. We may need a num_planes field as well. If the
> > > sizes are all 0 (or num_planes is 0), then the driver can use the current
> > > format, just as it does with REQBUFS.
> > 
> > Hm, I think, I like this idea. It gives applications more flexibility and 
> > removes the size == 0 vs. size != 0 dilemma. So, we get
> > 
> > /* VIDIOC_CREATE_BUFS */
> > struct v4l2_create_buffers {
> > 	__u32			index;		/* output: buffers index...index + count - 1 have been created */
> > 	__u32			count;
> > 	__u32			num_planes;
> > 	__u32			sizes[VIDEO_MAX_PLANES];
> > 	enum v4l2_memory        memory;
> > 	enum v4l2_buf_type	type;
> > 	__u32			reserved[8];
> > };
> > 
> > ?
> 
> Yes. I'd probably rearrange the fields a bit, though:
> 
> /* VIDIOC_CREATE_BUFS */
> struct v4l2_create_buffers {
> 	__u32			index;		/* output: buffers index...index + count - 1 have been created */
> 	__u32			count;
> 	__u32			type;
> 	__u32			memory;
> 	__u32			num_planes;
> 	__u32			sizes[VIDEO_MAX_PLANES];
> 	__u32			reserved[8];
> };
> 
> The order of the count, type and memory fields is now identical to that of
> v4l2_requestbuffers.
> 
> I also changed the enums to u32 since without the v4l2_format struct we shouldn't
> use enums. As an additional bonus this also simplifies the compat32 code.

I have to say I like what I see above. :-)

I have one comment at this point, which is what I always have: reserved
fields. If we want to later add per-plane fields, 8 u32s isn't much for
that. CREATE_BUFS isn't time critical either at all, so I'd go with 19 (to
align the buffer size to a power of 2) or even more.
Pawel Osciak July 30, 2011, 4:21 a.m. UTC | #16
Hi Hans,

On Wed, Jul 27, 2011 at 23:56, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> On Thursday, July 28, 2011 06:11:38 Pawel Osciak wrote:
>> Hi Guennadi,
>>
>> On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
>> <g.liakhovetski@gmx.de> wrote:
>> > A possibility to preallocate and initialise buffers of different sizes
>> > in V4L2 is required for an efficient implementation of asnapshot mode.
>> > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
>> > VIDIOC_PREPARE_BUF and defines respective data structures.
>> >
>> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
>> > ---
>> >
>> <snip>
>>
>> This looks nicer, I like how we got rid of destroy and gave up on
>> making holes, it would've given us a lot of headaches. I'm thinking
>> about some issues though and also have some comments/questions further
>> below.
>>
>> Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
>> Personally I'd like to allow mixing, including REQBUFS for non-zero,
>> because I think it would be easy to do. I think it could work in the
>> same way as REQBUFS for !=0 works currently (at least in vb2), if we
>> already have some buffers allocated and they are not in use, we free
>> them and a new set is allocated. So I guess it could just stay this
>> way. REQBUFS(0) would of course free everything.
>>
>> Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
>> would have to pass it forward to the driver somehow. The obvious way
>> would be just vb2 calling the driver's s_fmt handler, but that won't
>> work, as you can't pass indexes to s_fmt. So we'd have to implement a
>> new driver callback for setting formats per index. I guess there is no
>> way around it, unless we actually take the format struct out of
>> CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
>> is full already though, the only way would be to use
>> v4l2_pix_format_mplane instead with plane count = 1 (or more if
>> needed).
>
> I just got an idea for this: use TRY_FMT. That will do exactly what
> you want. In fact, perhaps we should remove the format struct from
> CREATE_BUFS and use __u32 sizes[VIDEO_MAX_PLANES] instead. Let the
> application call TRY_FMT and initialize the sizes array instead of
> putting that into vb2. We may need a num_planes field as well. If the
> sizes are all 0 (or num_planes is 0), then the driver can use the current
> format, just as it does with REQBUFS.
>
> Or am I missing something?
>

I'm not sure I'm following. Could you give a usage example? Do you
mean we want the application to:
- SET_FMT and REQBUFS for normal buffers
- TRY_FMT and CREATE_BUFS for additional buffers?

I'm still not clear how would driver know for which set of buffers the
*_FMT is being called... I'm pretty sure I'm misunderstanding your
idea though...

>> Another thing is the case of passing size to CREATE_BUFS. vb2, when
>> allocating buffers, gets their sizes from the driver (via
>> queue_setup), it never "suggest" any particular size. So that flow
>> would have to be changed as well. I guess vb2 could pass the size to
>> queue_setup in a similar way as it does with buffer count. This would
>> mean though that the ioctl would fail if the driver didn't agree to
>> the given size. Right now I don't see an option to "negotiate" the
>> size with the driver via this option.
>
> I think the driver can always increase the size if needed and return the
> new size.
>

Right, this can easily be done in vb2. But if we do that, it will
introduce asymmetry with REQBUFS. For SET_FMT/TRY_FMT+REQBUFS the
driver would only be able to adjust buffer sizes on *_FMT, while with
*_FMT+CREATE_BUFS it could do that for both calls. Why do we need an
additional chance to adjust? Or am I misunderstanding your suggestion?

>>
>> The more I think of it though, why do we need the size argument? It's
>> not needed in the existing flows (that use S_FMT) and, more
>> importantly, I don't think the application can know more than the
>> driver can, so why giving that option? The driver should know the size
>> for a format at least as well as the application... Also, is there a
>> real use case of providing just size, will the driver know which
>> format to use given a size?
>
> There are cases where you want a larger buffer size than the format
> really required. The most common case being 1920x1080 formats where you
> want to capture in a 1920x1088 buffer (since 1088 is a multiple of 16
> and is more suitable for MPEG et al encoding).
>
> So, yes, you do want the option to set the size explicitly.

Yes, that's true, but my point is in the current API it works too,
because the driver can adjust the size on TRY/S_FMT. Even though the
application knows that 1088 is needed instead of 1080, shouldn't the
driver know it as well (or actually, know even better than the app)
and be able to adjust? So when we CREATE_BUFS, the driver can adjust
the format struct (or if we somehow use *_FMT for CREATE_BUFS buffers,
it could adjust the size there). Sorry, I still can't see why we need
an explicit size argument...

<snip>

>>
>> I'm probably forgetting something, but why would we want to do both
>> PREPARE_BUF and QBUF? Why not queue in advance?
>
> QBUF both prepares the buffer and makes it available for use with DMA. You don't want
> that. You just want to prepare it (that's the part that is expensive) and postpone
> the actual queuing until the buffer is needed to e.g. take a snapshot.

Just to confirm I understood correctly: we don't want to QBUF, because
then it'd would immediately be used and we want to time when it is to
be used? So when the driver sees a larger buffer being queued, it is
to change the current streaming format for the duration of filling
that buffer and switch back afterwards?
Hans Verkuil July 30, 2011, 1:50 p.m. UTC | #17
On Saturday, July 30, 2011 06:21:37 Pawel Osciak wrote:
> Hi Hans,
> 
> On Wed, Jul 27, 2011 at 23:56, Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > On Thursday, July 28, 2011 06:11:38 Pawel Osciak wrote:
> >> Hi Guennadi,
> >>
> >> On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
> >> <g.liakhovetski@gmx.de> wrote:
> >> > A possibility to preallocate and initialise buffers of different sizes
> >> > in V4L2 is required for an efficient implementation of asnapshot mode.
> >> > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> >> > VIDIOC_PREPARE_BUF and defines respective data structures.
> >> >
> >> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> >> > ---
> >> >
> >> <snip>
> >>
> >> This looks nicer, I like how we got rid of destroy and gave up on
> >> making holes, it would've given us a lot of headaches. I'm thinking
> >> about some issues though and also have some comments/questions further
> >> below.
> >>
> >> Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
> >> Personally I'd like to allow mixing, including REQBUFS for non-zero,
> >> because I think it would be easy to do. I think it could work in the
> >> same way as REQBUFS for !=0 works currently (at least in vb2), if we
> >> already have some buffers allocated and they are not in use, we free
> >> them and a new set is allocated. So I guess it could just stay this
> >> way. REQBUFS(0) would of course free everything.
> >>
> >> Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
> >> would have to pass it forward to the driver somehow. The obvious way
> >> would be just vb2 calling the driver's s_fmt handler, but that won't
> >> work, as you can't pass indexes to s_fmt. So we'd have to implement a
> >> new driver callback for setting formats per index. I guess there is no
> >> way around it, unless we actually take the format struct out of
> >> CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
> >> is full already though, the only way would be to use
> >> v4l2_pix_format_mplane instead with plane count = 1 (or more if
> >> needed).
> >
> > I just got an idea for this: use TRY_FMT. That will do exactly what
> > you want. In fact, perhaps we should remove the format struct from
> > CREATE_BUFS and use __u32 sizes[VIDEO_MAX_PLANES] instead. Let the
> > application call TRY_FMT and initialize the sizes array instead of
> > putting that into vb2. We may need a num_planes field as well. If the
> > sizes are all 0 (or num_planes is 0), then the driver can use the current
> > format, just as it does with REQBUFS.
> >
> > Or am I missing something?
> >
> 
> I'm not sure I'm following. Could you give a usage example? Do you
> mean we want the application to:
> - SET_FMT and REQBUFS for normal buffers
> - TRY_FMT and CREATE_BUFS for additional buffers?

Right.

> 
> I'm still not clear how would driver know for which set of buffers the
> *_FMT is being called... I'm pretty sure I'm misunderstanding your
> idea though...

S_FMT programs the pipeline. It is up to the application to ensure that the
buffers queued to the DMA engine are big enough to handle it (and up to the
driver to reject buffers if they are too small).

REQBUFS just calculates the size of the mmap buffers based on the current format.
This is very limiting in certain situations. With CREATE_BUFS I would prefer
being more flexible and let the application determine the buffer sizes, possibly
based on what TRY_FMT returns.

> >> Another thing is the case of passing size to CREATE_BUFS. vb2, when
> >> allocating buffers, gets their sizes from the driver (via
> >> queue_setup), it never "suggest" any particular size. So that flow
> >> would have to be changed as well. I guess vb2 could pass the size to
> >> queue_setup in a similar way as it does with buffer count. This would
> >> mean though that the ioctl would fail if the driver didn't agree to
> >> the given size. Right now I don't see an option to "negotiate" the
> >> size with the driver via this option.
> >
> > I think the driver can always increase the size if needed and return the
> > new size.
> >
> 
> Right, this can easily be done in vb2. But if we do that, it will
> introduce asymmetry with REQBUFS. For SET_FMT/TRY_FMT+REQBUFS the
> driver would only be able to adjust buffer sizes on *_FMT, while with
> *_FMT+CREATE_BUFS it could do that for both calls. Why do we need an
> additional chance to adjust? Or am I misunderstanding your suggestion?

I don't really understand your question. With REQBUFS the size used to allocate
the mmap buffers is derived from the current format by the driver. You have no
chance to change that for the V4L2_MEMORY_MMAP buffers. It would be much more
flexible if you let the application set up the buffer size(s). The application
can always call TRY_FMT (or G_FMT) to learn the buffer size and fill it in for
CREATE_BUFS.
 
> >>
> >> The more I think of it though, why do we need the size argument? It's
> >> not needed in the existing flows (that use S_FMT) and, more
> >> importantly, I don't think the application can know more than the
> >> driver can, so why giving that option? The driver should know the size
> >> for a format at least as well as the application... Also, is there a
> >> real use case of providing just size, will the driver know which
> >> format to use given a size?
> >
> > There are cases where you want a larger buffer size than the format
> > really required. The most common case being 1920x1080 formats where you
> > want to capture in a 1920x1088 buffer (since 1088 is a multiple of 16
> > and is more suitable for MPEG et al encoding).
> >
> > So, yes, you do want the option to set the size explicitly.
> 
> Yes, that's true, but my point is in the current API it works too,
> because the driver can adjust the size on TRY/S_FMT. Even though the
> application knows that 1088 is needed instead of 1080, shouldn't the
> driver know it as well (or actually, know even better than the app)
> and be able to adjust?

The driver will of course adjust it if hardware limitations require it.
But it shouldn't make assumptions on how the buffer is going to be used.
To take this example: an application that will just capture 1920x1080 and
output it on another HDMI output without any encoding doesn't need 1088.
But if it is fed to an encoder, then selecting 1088 as size is very useful.
Perhaps the application would also like to record meta data after the
picture, thus requiring an even larger size.

> So when we CREATE_BUFS, the driver can adjust
> the format struct (or if we somehow use *_FMT for CREATE_BUFS buffers,
> it could adjust the size there). Sorry, I still can't see why we need
> an explicit size argument...

The size is what vb2 needs. It shouldn't care about the format. The format
is only used one time to calculate the sizes. By moving that to the application
you allow the application to modify sizes as needed.

Suppose we pass in the format to CREATE_BUFS as originally proposed. What
would happen is that vb2 would probably call TRY_FMT and use the returned
imagesize(s) to fill in the vb2 internals. And the application would have
no way of changing those.

> 
> <snip>
> 
> >>
> >> I'm probably forgetting something, but why would we want to do both
> >> PREPARE_BUF and QBUF? Why not queue in advance?
> >
> > QBUF both prepares the buffer and makes it available for use with DMA. You don't want
> > that. You just want to prepare it (that's the part that is expensive) and postpone
> > the actual queuing until the buffer is needed to e.g. take a snapshot.
> 
> Just to confirm I understood correctly: we don't want to QBUF, because
> then it'd would immediately be used and we want to time when it is to
> be used? 

Right.

> So when the driver sees a larger buffer being queued, it is
> to change the current streaming format for the duration of filling
> that buffer and switch back afterwards?

No. We do not have a mechanism (yet) to tie a pipeline configuration to
a queued buffer (to be discussed in next week in Cambourne).

It is my understanding that you change the current streaming format, and
then queue the large (prepared) buffer and switch back afterwards.

Somebody please correct me if I am wrong.

Regards,

	Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski July 30, 2011, 5:06 p.m. UTC | #18
On Sat, 30 Jul 2011, Hans Verkuil wrote:

> On Saturday, July 30, 2011 06:21:37 Pawel Osciak wrote:

[snip]

> > So when the driver sees a larger buffer being queued, it is
> > to change the current streaming format for the duration of filling
> > that buffer and switch back afterwards?
> 
> No. We do not have a mechanism (yet) to tie a pipeline configuration to
> a queued buffer (to be discussed in next week in Cambourne).
> 
> It is my understanding that you change the current streaming format, and
> then queue the large (prepared) buffer and switch back afterwards.

Yes, this is also how I see it - the driver just has a chance to verify, 
whether the queued buffer is not large enough for the current format and 
fail QBUF, although this behaviour is currently not documented in the QBUF 
specification...

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski Aug. 1, 2011, 8:42 a.m. UTC | #19
On Tue, 26 Jul 2011, Hans Verkuil wrote:

> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
> > Hi Hans and Guennadi,
> 
> <snip>
> 
> > > I realized that it is not clear from the documentation whether it is possible to call
> > > VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
> > 
> > That's actually a must if one wants to release buffers. Currently no other
> > method than requesting 0 buffers using REQBUFS is provided (apart from
> > closing the file handle).
> 
> I was referring to the non-0 use-case :-)
> 
> > > I can't remember whether the code allows it or not, but it should be clearly documented.
> > 
> > I would guess no user application would have to call REQBUFS with other than
> > zero buffers when using CREATE_BUFS. This must be an exception if mixing
> > REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
> > reason to prohibit either, but perhaps Guennadi has more informed opinion
> > on this.
>  
> <snip>
> 
> > > > > > Future functionality which would be nice:
> > > > > > 
> > > > > > - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> > > > > >   come with a counter value so that the user would know the format of
> > > > > >   dequeued buffers when setting the format on-the-fly. Currently there are
> > > > > >   only bytesperline and length, but the format can't be explicitly
> > > > > >   determined from those.
> > > 
> > > Actually, the index field will give you that information. When you create the
> > > buffers you know that range [index, index + count - 1] is associated with that
> > > specific format.
> > 
> > Some hardware is able to change the format while streaming is ongoing (for
> > example: OMAP 3). The problem is that the user should be able to know which
> > frame has the new format.

How exactly does this work or should it work? You mean, you just configure 
your hardware with new frame size parameters without stopping the current 
streaming, and the ISP will change frame sizes, beginning with some future 
frame? How does the driver then get to know, which frame already has the 
new sizes? You actually want to know this in advance to already queue a 
suitably sized buffer to the hardware?

Thanks
Guennadi

> Ah, of course.
> 
> > Of course one could stop streaming but this would mean lost frames.
> > 
> > A flag has been proposed to this previously. That's one option but forces
> > the user to keep track of the changes since only one change is allowed until
> > it has taken effect.
> 
> Something to discuss next week, I think.
> 
> Regards,
> 
> 	Hans
> 

---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Guennadi Liakhovetski Aug. 1, 2011, 10:55 a.m. UTC | #20
On Sat, 30 Jul 2011, Hans Verkuil wrote:

[snip]

> No. We do not have a mechanism (yet) to tie a pipeline configuration to
> a queued buffer (to be discussed in next week in Cambourne).
> 
> It is my understanding that you change the current streaming format, and
> then queue the large (prepared) buffer and switch back afterwards.

As far as I understand, currently we have 2 unclarified points with this 
patch:

1. size of the reserved field. Sakari proposed 19 32-bit words for 
possible per-plane extensions with a max of 8 planes. That would make up 
to 2 32-bit words per plane plus 3 words for the common part. So, although 
reserving 76 bytes "just in case" seems like a huge overkill to me, I 
kinda can see the reasoning... We could also do with 10 reserved words - 1 
word per plane + 2 common. What do others think?

2. as in the above quote - we do not know yet, how to tell the user, when 
the format changes.

AFAIU, the problem is the following:

(a) we prepare buffers of two sizes, say - small for preview and large for 
snapshot
(b) S_FMT(preview)
(c) QBUF(preview)...
(d) STREAMON
(e) capture for some time...
(f) S_FMT(snapshot)
(g) now, we do not yet necessarily want to queue our big buffers, because 
the hardware will not switch immediately
(h) when the hardware has switch we QBUF(snapshor)
...

Currently, there's no way to find out when the hardware switched to the 
new frame format. Maybe an event is needed?

Besides, the TRY_FMT idea is nice, but it doesn't give us an ultimate 
solution either. What if a TRY_FMT now returns different plane sizes, than 
when we actually perform S_FMT? E.g., if the user also issues an S_CROP 
between those and that also changes the output format because of driver 
limitations?

So, my question is: shall I prepare a new version of this RFC now, also 
providing examples for vb2 and a hardware driver, or we're waiting for the 
brainstorming and following ML discussion results on the above?

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus Aug. 1, 2011, 2:55 p.m. UTC | #21
Guennadi Liakhovetski wrote:
> On Tue, 26 Jul 2011, Hans Verkuil wrote:
> 
>> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
>>> Hi Hans and Guennadi,
>>
>> <snip>
>>
>>>> I realized that it is not clear from the documentation whether it is possible to call
>>>> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
>>>
>>> That's actually a must if one wants to release buffers. Currently no other
>>> method than requesting 0 buffers using REQBUFS is provided (apart from
>>> closing the file handle).
>>
>> I was referring to the non-0 use-case :-)
>>
>>>> I can't remember whether the code allows it or not, but it should be clearly documented.
>>>
>>> I would guess no user application would have to call REQBUFS with other than
>>> zero buffers when using CREATE_BUFS. This must be an exception if mixing
>>> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
>>> reason to prohibit either, but perhaps Guennadi has more informed opinion
>>> on this.
>>  
>> <snip>
>>
>>>>>>> Future functionality which would be nice:
>>>>>>>
>>>>>>> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
>>>>>>>   come with a counter value so that the user would know the format of
>>>>>>>   dequeued buffers when setting the format on-the-fly. Currently there are
>>>>>>>   only bytesperline and length, but the format can't be explicitly
>>>>>>>   determined from those.
>>>>
>>>> Actually, the index field will give you that information. When you create the
>>>> buffers you know that range [index, index + count - 1] is associated with that
>>>> specific format.
>>>
>>> Some hardware is able to change the format while streaming is ongoing (for
>>> example: OMAP 3). The problem is that the user should be able to know which
>>> frame has the new format.
> 
> How exactly does this work or should it work? You mean, you just configure 
> your hardware with new frame size parameters without stopping the current 
> streaming, and the ISP will change frame sizes, beginning with some future 
> frame? How does the driver then get to know, which frame already has the 

That's correct.

> new sizes? You actually want to know this in advance to already queue a 
> suitably sized buffer to the hardware?

The driver knows that since it has configured the hardware to produce
that frame size.

The assumption is that all the buffers have suitable size for all the
formats. This must be checked by the driver, something which also must
be taken into account.
Guennadi Liakhovetski Aug. 1, 2011, 3:05 p.m. UTC | #22
On Mon, 1 Aug 2011, Sakari Ailus wrote:

> Guennadi Liakhovetski wrote:
> > On Tue, 26 Jul 2011, Hans Verkuil wrote:
> > 
> >> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
> >>> Hi Hans and Guennadi,
> >>
> >> <snip>
> >>
> >>>> I realized that it is not clear from the documentation whether it is possible to call
> >>>> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
> >>>
> >>> That's actually a must if one wants to release buffers. Currently no other
> >>> method than requesting 0 buffers using REQBUFS is provided (apart from
> >>> closing the file handle).
> >>
> >> I was referring to the non-0 use-case :-)
> >>
> >>>> I can't remember whether the code allows it or not, but it should be clearly documented.
> >>>
> >>> I would guess no user application would have to call REQBUFS with other than
> >>> zero buffers when using CREATE_BUFS. This must be an exception if mixing
> >>> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
> >>> reason to prohibit either, but perhaps Guennadi has more informed opinion
> >>> on this.
> >>  
> >> <snip>
> >>
> >>>>>>> Future functionality which would be nice:
> >>>>>>>
> >>>>>>> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> >>>>>>>   come with a counter value so that the user would know the format of
> >>>>>>>   dequeued buffers when setting the format on-the-fly. Currently there are
> >>>>>>>   only bytesperline and length, but the format can't be explicitly
> >>>>>>>   determined from those.
> >>>>
> >>>> Actually, the index field will give you that information. When you create the
> >>>> buffers you know that range [index, index + count - 1] is associated with that
> >>>> specific format.
> >>>
> >>> Some hardware is able to change the format while streaming is ongoing (for
> >>> example: OMAP 3). The problem is that the user should be able to know which
> >>> frame has the new format.
> > 
> > How exactly does this work or should it work? You mean, you just configure 
> > your hardware with new frame size parameters without stopping the current 
> > streaming, and the ISP will change frame sizes, beginning with some future 
> > frame? How does the driver then get to know, which frame already has the 
> 
> That's correct.
> 
> > new sizes? You actually want to know this in advance to already queue a 
> > suitably sized buffer to the hardware?
> 
> The driver knows that since it has configured the hardware to produce
> that frame size.
> 
> The assumption is that all the buffers have suitable size for all the
> formats. This must be checked by the driver, something which also must
> be taken into account.

Hm, but do you then at all need different buffers?

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus Aug. 2, 2011, 8:08 a.m. UTC | #23
Guennadi Liakhovetski wrote:
> On Mon, 1 Aug 2011, Sakari Ailus wrote:
> 
>> Guennadi Liakhovetski wrote:
>>> On Tue, 26 Jul 2011, Hans Verkuil wrote:
>>>
>>>> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
>>>>> Hi Hans and Guennadi,
>>>>
>>>> <snip>
>>>>
>>>>>> I realized that it is not clear from the documentation whether it is possible to call
>>>>>> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
>>>>>
>>>>> That's actually a must if one wants to release buffers. Currently no other
>>>>> method than requesting 0 buffers using REQBUFS is provided (apart from
>>>>> closing the file handle).
>>>>
>>>> I was referring to the non-0 use-case :-)
>>>>
>>>>>> I can't remember whether the code allows it or not, but it should be clearly documented.
>>>>>
>>>>> I would guess no user application would have to call REQBUFS with other than
>>>>> zero buffers when using CREATE_BUFS. This must be an exception if mixing
>>>>> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
>>>>> reason to prohibit either, but perhaps Guennadi has more informed opinion
>>>>> on this.
>>>>  
>>>> <snip>
>>>>
>>>>>>>>> Future functionality which would be nice:
>>>>>>>>>
>>>>>>>>> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
>>>>>>>>>   come with a counter value so that the user would know the format of
>>>>>>>>>   dequeued buffers when setting the format on-the-fly. Currently there are
>>>>>>>>>   only bytesperline and length, but the format can't be explicitly
>>>>>>>>>   determined from those.
>>>>>>
>>>>>> Actually, the index field will give you that information. When you create the
>>>>>> buffers you know that range [index, index + count - 1] is associated with that
>>>>>> specific format.
>>>>>
>>>>> Some hardware is able to change the format while streaming is ongoing (for
>>>>> example: OMAP 3). The problem is that the user should be able to know which
>>>>> frame has the new format.
>>>
>>> How exactly does this work or should it work? You mean, you just configure 
>>> your hardware with new frame size parameters without stopping the current 
>>> streaming, and the ISP will change frame sizes, beginning with some future 
>>> frame? How does the driver then get to know, which frame already has the 
>>
>> That's correct.
>>
>>> new sizes? You actually want to know this in advance to already queue a 
>>> suitably sized buffer to the hardware?
>>
>> The driver knows that since it has configured the hardware to produce
>> that frame size.
>>
>> The assumption is that all the buffers have suitable size for all the
>> formats. This must be checked by the driver, something which also must
>> be taken into account.
> 
> Hm, but do you then at all need different buffers?

Not in this case, but this is a different case after all: streaming with
buffers of different size, not still capture.
Guennadi Liakhovetski Aug. 2, 2011, 8:20 a.m. UTC | #24
On Tue, 2 Aug 2011, Sakari Ailus wrote:

> Guennadi Liakhovetski wrote:
> > On Mon, 1 Aug 2011, Sakari Ailus wrote:
> > 
> >> Guennadi Liakhovetski wrote:
> >>> On Tue, 26 Jul 2011, Hans Verkuil wrote:
> >>>
> >>>> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
> >>>>> Hi Hans and Guennadi,
> >>>>
> >>>> <snip>
> >>>>
> >>>>>> I realized that it is not clear from the documentation whether it is possible to call
> >>>>>> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
> >>>>>
> >>>>> That's actually a must if one wants to release buffers. Currently no other
> >>>>> method than requesting 0 buffers using REQBUFS is provided (apart from
> >>>>> closing the file handle).
> >>>>
> >>>> I was referring to the non-0 use-case :-)
> >>>>
> >>>>>> I can't remember whether the code allows it or not, but it should be clearly documented.
> >>>>>
> >>>>> I would guess no user application would have to call REQBUFS with other than
> >>>>> zero buffers when using CREATE_BUFS. This must be an exception if mixing
> >>>>> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
> >>>>> reason to prohibit either, but perhaps Guennadi has more informed opinion
> >>>>> on this.
> >>>>  
> >>>> <snip>
> >>>>
> >>>>>>>>> Future functionality which would be nice:
> >>>>>>>>>
> >>>>>>>>> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> >>>>>>>>>   come with a counter value so that the user would know the format of
> >>>>>>>>>   dequeued buffers when setting the format on-the-fly. Currently there are
> >>>>>>>>>   only bytesperline and length, but the format can't be explicitly
> >>>>>>>>>   determined from those.
> >>>>>>
> >>>>>> Actually, the index field will give you that information. When you create the
> >>>>>> buffers you know that range [index, index + count - 1] is associated with that
> >>>>>> specific format.
> >>>>>
> >>>>> Some hardware is able to change the format while streaming is ongoing (for
> >>>>> example: OMAP 3). The problem is that the user should be able to know which
> >>>>> frame has the new format.
> >>>
> >>> How exactly does this work or should it work? You mean, you just configure 
> >>> your hardware with new frame size parameters without stopping the current 
> >>> streaming, and the ISP will change frame sizes, beginning with some future 
> >>> frame? How does the driver then get to know, which frame already has the 
> >>
> >> That's correct.
> >>
> >>> new sizes? You actually want to know this in advance to already queue a 
> >>> suitably sized buffer to the hardware?
> >>
> >> The driver knows that since it has configured the hardware to produce
> >> that frame size.
> >>
> >> The assumption is that all the buffers have suitable size for all the
> >> formats. This must be checked by the driver, something which also must
> >> be taken into account.
> > 
> > Hm, but do you then at all need different buffers?
> 
> Not in this case, but this is a different case after all: streaming with
> buffers of different size, not still capture.

Sorry, I've lost you completely. Do you have a real-life example, where 
your software does not know which buffer type must be used with a specific 
frame or you don't have such examples?

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus Aug. 2, 2011, 10:45 a.m. UTC | #25
Guennadi Liakhovetski wrote:
> On Tue, 2 Aug 2011, Sakari Ailus wrote:
> 
>> Guennadi Liakhovetski wrote:
>>> On Mon, 1 Aug 2011, Sakari Ailus wrote:
>>>
>>>> Guennadi Liakhovetski wrote:
>>>>> On Tue, 26 Jul 2011, Hans Verkuil wrote:
>>>>>
>>>>>> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
>>>>>>> Hi Hans and Guennadi,
>>>>>>
>>>>>> <snip>
>>>>>>
>>>>>>>> I realized that it is not clear from the documentation whether it is possible to call
>>>>>>>> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
>>>>>>>
>>>>>>> That's actually a must if one wants to release buffers. Currently no other
>>>>>>> method than requesting 0 buffers using REQBUFS is provided (apart from
>>>>>>> closing the file handle).
>>>>>>
>>>>>> I was referring to the non-0 use-case :-)
>>>>>>
>>>>>>>> I can't remember whether the code allows it or not, but it should be clearly documented.
>>>>>>>
>>>>>>> I would guess no user application would have to call REQBUFS with other than
>>>>>>> zero buffers when using CREATE_BUFS. This must be an exception if mixing
>>>>>>> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
>>>>>>> reason to prohibit either, but perhaps Guennadi has more informed opinion
>>>>>>> on this.
>>>>>>  
>>>>>> <snip>
>>>>>>
>>>>>>>>>>> Future functionality which would be nice:
>>>>>>>>>>>
>>>>>>>>>>> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
>>>>>>>>>>>   come with a counter value so that the user would know the format of
>>>>>>>>>>>   dequeued buffers when setting the format on-the-fly. Currently there are
>>>>>>>>>>>   only bytesperline and length, but the format can't be explicitly
>>>>>>>>>>>   determined from those.
>>>>>>>>
>>>>>>>> Actually, the index field will give you that information. When you create the
>>>>>>>> buffers you know that range [index, index + count - 1] is associated with that
>>>>>>>> specific format.
>>>>>>>
>>>>>>> Some hardware is able to change the format while streaming is ongoing (for
>>>>>>> example: OMAP 3). The problem is that the user should be able to know which
>>>>>>> frame has the new format.
>>>>>
>>>>> How exactly does this work or should it work? You mean, you just configure 
>>>>> your hardware with new frame size parameters without stopping the current 
>>>>> streaming, and the ISP will change frame sizes, beginning with some future 
>>>>> frame? How does the driver then get to know, which frame already has the 
>>>>
>>>> That's correct.
>>>>
>>>>> new sizes? You actually want to know this in advance to already queue a 
>>>>> suitably sized buffer to the hardware?
>>>>
>>>> The driver knows that since it has configured the hardware to produce
>>>> that frame size.
>>>>
>>>> The assumption is that all the buffers have suitable size for all the
>>>> formats. This must be checked by the driver, something which also must
>>>> be taken into account.
>>>
>>> Hm, but do you then at all need different buffers?
>>
>> Not in this case, but this is a different case after all: streaming with
>> buffers of different size, not still capture.
> 
> Sorry, I've lost you completely. Do you have a real-life example, where 
> your software does not know which buffer type must be used with a specific 
> frame or you don't have such examples?

There is one, now that you asked. It's not a buffer type but format.

In video calls the resolution of the video frames need to be changed,
along with the frame rate, depending on the quality of the link, for
example.

In this case it's important to know which format a dequeued frame has.
The alternative is to stop streaming, reconfigure and start it again,
but this leads to lost frames. The hardware can do this so I don't think
the interface should prevent it.
Guennadi Liakhovetski Aug. 2, 2011, 11:11 a.m. UTC | #26
On Tue, 2 Aug 2011, Sakari Ailus wrote:

> Guennadi Liakhovetski wrote:
> > On Tue, 2 Aug 2011, Sakari Ailus wrote:
> > 
> >> Guennadi Liakhovetski wrote:
> >>> On Mon, 1 Aug 2011, Sakari Ailus wrote:
> >>>
> >>>> Guennadi Liakhovetski wrote:
> >>>>> On Tue, 26 Jul 2011, Hans Verkuil wrote:
> >>>>>
> >>>>>> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
> >>>>>>> Hi Hans and Guennadi,
> >>>>>>
> >>>>>> <snip>
> >>>>>>
> >>>>>>>> I realized that it is not clear from the documentation whether it is possible to call
> >>>>>>>> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
> >>>>>>>
> >>>>>>> That's actually a must if one wants to release buffers. Currently no other
> >>>>>>> method than requesting 0 buffers using REQBUFS is provided (apart from
> >>>>>>> closing the file handle).
> >>>>>>
> >>>>>> I was referring to the non-0 use-case :-)
> >>>>>>
> >>>>>>>> I can't remember whether the code allows it or not, but it should be clearly documented.
> >>>>>>>
> >>>>>>> I would guess no user application would have to call REQBUFS with other than
> >>>>>>> zero buffers when using CREATE_BUFS. This must be an exception if mixing
> >>>>>>> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
> >>>>>>> reason to prohibit either, but perhaps Guennadi has more informed opinion
> >>>>>>> on this.
> >>>>>>  
> >>>>>> <snip>
> >>>>>>
> >>>>>>>>>>> Future functionality which would be nice:
> >>>>>>>>>>>
> >>>>>>>>>>> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
> >>>>>>>>>>>   come with a counter value so that the user would know the format of
> >>>>>>>>>>>   dequeued buffers when setting the format on-the-fly. Currently there are
> >>>>>>>>>>>   only bytesperline and length, but the format can't be explicitly
> >>>>>>>>>>>   determined from those.
> >>>>>>>>
> >>>>>>>> Actually, the index field will give you that information. When you create the
> >>>>>>>> buffers you know that range [index, index + count - 1] is associated with that
> >>>>>>>> specific format.
> >>>>>>>
> >>>>>>> Some hardware is able to change the format while streaming is ongoing (for
> >>>>>>> example: OMAP 3). The problem is that the user should be able to know which
> >>>>>>> frame has the new format.
> >>>>>
> >>>>> How exactly does this work or should it work? You mean, you just configure 
> >>>>> your hardware with new frame size parameters without stopping the current 
> >>>>> streaming, and the ISP will change frame sizes, beginning with some future 
> >>>>> frame? How does the driver then get to know, which frame already has the 
> >>>>
> >>>> That's correct.
> >>>>
> >>>>> new sizes? You actually want to know this in advance to already queue a 
> >>>>> suitably sized buffer to the hardware?
> >>>>
> >>>> The driver knows that since it has configured the hardware to produce
> >>>> that frame size.
> >>>>
> >>>> The assumption is that all the buffers have suitable size for all the
> >>>> formats. This must be checked by the driver, something which also must
> >>>> be taken into account.
> >>>
> >>> Hm, but do you then at all need different buffers?
> >>
> >> Not in this case, but this is a different case after all: streaming with
> >> buffers of different size, not still capture.
> > 
> > Sorry, I've lost you completely. Do you have a real-life example, where 
> > your software does not know which buffer type must be used with a specific 
> > frame or you don't have such examples?
> 
> There is one, now that you asked. It's not a buffer type but format.
> 
> In video calls the resolution of the video frames need to be changed,
> along with the frame rate, depending on the quality of the link, for
> example.
> 
> In this case it's important to know which format a dequeued frame has.
> The alternative is to stop streaming, reconfigure and start it again,
> but this leads to lost frames. The hardware can do this so I don't think
> the interface should prevent it.

Sorry, let me try again. Yes, we already know, that OMAP3 can switch from 
one frame format to another one on the fly. And you told us, that for this 
to work you need buffers, that can hold both frame formats, because 
otherwise you have no chance to identify when the hardware is going to 
switch and you have no time to queue another buffer type.

But this doesn't concern us atm. We're not discussing how to inform the 
user-space about the new frame format, we're discussing switching between 
different buffer types.

AFAICS, you don't have such an example. So, unless I'm missing something, 
I'd say: case dismissed.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus Aug. 2, 2011, 1:46 p.m. UTC | #27
Guennadi Liakhovetski wrote:
> On Tue, 2 Aug 2011, Sakari Ailus wrote:
> 
>> Guennadi Liakhovetski wrote:
>>> On Tue, 2 Aug 2011, Sakari Ailus wrote:
>>>
>>>> Guennadi Liakhovetski wrote:
>>>>> On Mon, 1 Aug 2011, Sakari Ailus wrote:
>>>>>
>>>>>> Guennadi Liakhovetski wrote:
>>>>>>> On Tue, 26 Jul 2011, Hans Verkuil wrote:
>>>>>>>
>>>>>>>> On Tuesday, July 26, 2011 13:44:28 Sakari Ailus wrote:
>>>>>>>>> Hi Hans and Guennadi,
>>>>>>>>
>>>>>>>> <snip>
>>>>>>>>
>>>>>>>>>> I realized that it is not clear from the documentation whether it is possible to call
>>>>>>>>>> VIDIOC_REQBUFS and make additional calls to VIDIOC_CREATE_BUFS afterwards.
>>>>>>>>>
>>>>>>>>> That's actually a must if one wants to release buffers. Currently no other
>>>>>>>>> method than requesting 0 buffers using REQBUFS is provided (apart from
>>>>>>>>> closing the file handle).
>>>>>>>>
>>>>>>>> I was referring to the non-0 use-case :-)
>>>>>>>>
>>>>>>>>>> I can't remember whether the code allows it or not, but it should be clearly documented.
>>>>>>>>>
>>>>>>>>> I would guess no user application would have to call REQBUFS with other than
>>>>>>>>> zero buffers when using CREATE_BUFS. This must be an exception if mixing
>>>>>>>>> REQBUFS and CREATE_BUFS is not allowed in general. That said, I don't see a
>>>>>>>>> reason to prohibit either, but perhaps Guennadi has more informed opinion
>>>>>>>>> on this.
>>>>>>>>  
>>>>>>>> <snip>
>>>>>>>>
>>>>>>>>>>>>> Future functionality which would be nice:
>>>>>>>>>>>>>
>>>>>>>>>>>>> - Format counters. Every format set by S_FMT (or gotten by G_FMT) should
>>>>>>>>>>>>>   come with a counter value so that the user would know the format of
>>>>>>>>>>>>>   dequeued buffers when setting the format on-the-fly. Currently there are
>>>>>>>>>>>>>   only bytesperline and length, but the format can't be explicitly
>>>>>>>>>>>>>   determined from those.
>>>>>>>>>>
>>>>>>>>>> Actually, the index field will give you that information. When you create the
>>>>>>>>>> buffers you know that range [index, index + count - 1] is associated with that
>>>>>>>>>> specific format.
>>>>>>>>>
>>>>>>>>> Some hardware is able to change the format while streaming is ongoing (for
>>>>>>>>> example: OMAP 3). The problem is that the user should be able to know which
>>>>>>>>> frame has the new format.
>>>>>>>
>>>>>>> How exactly does this work or should it work? You mean, you just configure 
>>>>>>> your hardware with new frame size parameters without stopping the current 
>>>>>>> streaming, and the ISP will change frame sizes, beginning with some future 
>>>>>>> frame? How does the driver then get to know, which frame already has the 
>>>>>>
>>>>>> That's correct.
>>>>>>
>>>>>>> new sizes? You actually want to know this in advance to already queue a 
>>>>>>> suitably sized buffer to the hardware?
>>>>>>
>>>>>> The driver knows that since it has configured the hardware to produce
>>>>>> that frame size.
>>>>>>
>>>>>> The assumption is that all the buffers have suitable size for all the
>>>>>> formats. This must be checked by the driver, something which also must
>>>>>> be taken into account.
>>>>>
>>>>> Hm, but do you then at all need different buffers?
>>>>
>>>> Not in this case, but this is a different case after all: streaming with
>>>> buffers of different size, not still capture.
>>>
>>> Sorry, I've lost you completely. Do you have a real-life example, where 
>>> your software does not know which buffer type must be used with a specific 
>>> frame or you don't have such examples?
>>
>> There is one, now that you asked. It's not a buffer type but format.
>>
>> In video calls the resolution of the video frames need to be changed,
>> along with the frame rate, depending on the quality of the link, for
>> example.
>>
>> In this case it's important to know which format a dequeued frame has.
>> The alternative is to stop streaming, reconfigure and start it again,
>> but this leads to lost frames. The hardware can do this so I don't think
>> the interface should prevent it.
> 
> Sorry, let me try again. Yes, we already know, that OMAP3 can switch from 
> one frame format to another one on the fly. And you told us, that for this 
> to work you need buffers, that can hold both frame formats, because 
> otherwise you have no chance to identify when the hardware is going to 
> switch and you have no time to queue another buffer type.
> 
> But this doesn't concern us atm. We're not discussing how to inform the 
> user-space about the new frame format, we're discussing switching between 
> different buffer types.

That is a different topic then.

I gave an example of the "future functionality which would be nice"
above and that had no direct dependency to this patchset --- it was
related to whether a new structure to replace v4l2_buffer is needed, but
the conclusion to that discussion has been already reached: we're fine
with the current v4l2_buffer. The format counters can be implemented (if
that's the solution) later when the driver will be able to do this. Also
pipeline configuration needs to change to implement this.

> AFAICS, you don't have such an example. So, unless I'm missing something, 
> I'd say: case dismissed.

Uh, I'm a bit lost now. Do different buffer types (e.g. capture, overlay
and input) need to be taken into account here, and if so, how? My
understanding was this is not related to preparing buffers.

Regards,
Guennadi Liakhovetski Aug. 2, 2011, 2:28 p.m. UTC | #28
On Tue, 2 Aug 2011, Sakari Ailus wrote:

> Uh, I'm a bit lost now. Do different buffer types (e.g. capture, overlay
> and input) need to be taken into account here, and if so, how? My
> understanding was this is not related to preparing buffers.

They all should be dealt with correctly. If you find any problems, please, 
report.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Sakari Ailus Aug. 2, 2011, 9:38 p.m. UTC | #29
On Wed, Jul 27, 2011 at 09:11:38PM -0700, Pawel Osciak wrote:
> Hi Guennadi,

Hi Pawel,

> On Wed, Jul 20, 2011 at 01:43, Guennadi Liakhovetski
> <g.liakhovetski@gmx.de> wrote:
> > A possibility to preallocate and initialise buffers of different sizes
> > in V4L2 is required for an efficient implementation of asnapshot mode.
> > This patch adds two new ioctl()s: VIDIOC_CREATE_BUFS and
> > VIDIOC_PREPARE_BUF and defines respective data structures.
> >
> > Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
> > ---
> >
> <snip>
> 
> This looks nicer, I like how we got rid of destroy and gave up on
> making holes, it would've given us a lot of headaches. I'm thinking
> about some issues though and also have some comments/questions further
> below.

Holes could be re-introduced by defining DESTROY_BUFS. But it would be up to
the application to use it or not.

> Already mentioned by others mixing of REQBUFS and CREATE_BUFS.
> Personally I'd like to allow mixing, including REQBUFS for non-zero,
> because I think it would be easy to do. I think it could work in the
> same way as REQBUFS for !=0 works currently (at least in vb2), if we
> already have some buffers allocated and they are not in use, we free
> them and a new set is allocated. So I guess it could just stay this
> way. REQBUFS(0) would of course free everything.
> 
> Passing format to CREATE_BUFS will make vb2 a bit format-aware, as it
> would have to pass it forward to the driver somehow. The obvious way
> would be just vb2 calling the driver's s_fmt handler, but that won't
> work, as you can't pass indexes to s_fmt. So we'd have to implement a
> new driver callback for setting formats per index. I guess there is no
> way around it, unless we actually take the format struct out of
> CREATE_BUFS and somehow do it via S_FMT. The single-planar structure
> is full already though, the only way would be to use
> v4l2_pix_format_mplane instead with plane count = 1 (or more if
> needed).

I've been pondering a while an idea to change v4l2_format. None of the
structures in the union use the full size of it. This would allow adding
fields to the end of the union and reduce its size accordingly. No-one would
be harmed in the process, struct v4l2_format would just change slightly.

Guennadi might have thought this in the past but at least I misunderstood it
at the time. :-)

> Another thing is the case of passing size to CREATE_BUFS. vb2, when
> allocating buffers, gets their sizes from the driver (via
> queue_setup), it never "suggest" any particular size. So that flow
> would have to be changed as well. I guess vb2 could pass the size to
> queue_setup in a similar way as it does with buffer count. This would
> mean though that the ioctl would fail if the driver didn't agree to
> the given size. Right now I don't see an option to "negotiate" the
> size with the driver via this option.
> 
> The more I think of it though, why do we need the size argument? It's
> not needed in the existing flows (that use S_FMT) and, more
> importantly, I don't think the application can know more than the
> driver can, so why giving that option? The driver should know the size
> for a format at least as well as the application... Also, is there a
> real use case of providing just size, will the driver know which
> format to use given a size?
> 
> 
> > +    <para>To allocate device buffers applications initialize all
> > +fields of the <structname>v4l2_create_buffers</structname> structure.
> > +They set the <structfield>type</structfield> field in the
> > +<structname>v4l2_format</structname> structure, embedded in this
> > +structure, to the respective stream or buffer type.
> > +<structfield>count</structfield> must be set to the number of required
> > +buffers. <structfield>memory</structfield> specifies the required I/O
> > +method. Applications have two possibilities to specify the size of buffers
> > +to be prepared: they can either set the <structfield>size</structfield>
> > +field explicitly to a non-zero value, or fill in the frame format data in the
> > +<structfield>format</structfield> field. In the latter case buffer sizes
> > +will be calculated automatically by the driver. The
> 
> Technically, we shouldn't say "applications initialize all fields" in
> the first sentence if they do not have to initialize both size and
> format fields at the same time.
> 
> > +<structfield>reserved</structfield> array must be zeroed. When the ioctl
> > +is called with a pointer to this structure the driver will attempt to allocate
> > +up to the requested number of buffers and store the actual number allocated
> > +and the starting index in the <structfield>count</structfield> and
> > +the <structfield>index</structfield> fields respectively.
> > +<structfield>count</structfield> can be smaller than the number requested.
> > +-ENOMEM is returned, if the driver runs out of free memory.</para>
> > +    <para>When the I/O method is not supported the ioctl
> > +returns an &EINVAL;.</para>
> > +
> > +    <table pgwide="1" frame="none" id="v4l2-create-buffers">
> > +      <title>struct <structname>v4l2_create_buffers</structname></title>
> > +      <tgroup cols="3">
> > +       &cs-str;
> > +       <tbody valign="top">
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>index</structfield></entry>
> > +           <entry>The starting buffer index, returned by the driver.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>count</structfield></entry>
> > +           <entry>The number of buffers requested or granted.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>&v4l2-memory;</entry>
> > +           <entry><structfield>memory</structfield></entry>
> > +           <entry>Applications set this field to
> > +<constant>V4L2_MEMORY_MMAP</constant> or
> > +<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>size</structfield></entry>
> > +           <entry>Explicit size of buffers, being created.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>&v4l2-format;</entry>
> > +           <entry><structfield>format</structfield></entry>
> > +           <entry>Application has to set the <structfield>type</structfield>
> > +field, other fields should be used, if the application wants to allocate buffers
> > +for a specific frame format.</entry>
> > +         </row>
> > +         <row>
> > +           <entry>__u32</entry>
> > +           <entry><structfield>reserved</structfield>[8]</entry>
> > +           <entry>A place holder for future extensions.</entry>
> > +         </row>
> > +       </tbody>
> > +      </tgroup>
> > +    </table>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    &return-value;
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +       <term><errorcode>ENOMEM</errorcode></term>
> > +       <listitem>
> > +         <para>No memory to allocate buffers for <link linkend="mmap">memory
> > +mapped</link> I/O.</para>
> > +       </listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +       <term><errorcode>EINVAL</errorcode></term>
> > +       <listitem>
> > +         <para>The buffer type (<structfield>type</structfield> field) or the
> > +requested I/O method (<structfield>memory</structfield>) is not
> > +supported.</para>
> > +       </listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +</refentry>
> > +
> 
> What happens if the driver does not agree to the provided size? EINVAL?
> 
> > +<!--
> > +Local Variables:
> > +mode: sgml
> > +sgml-parent-document: "v4l2.sgml"
> > +indent-tabs-mode: nil
> > +End:
> > +-->
> > diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > new file mode 100644
> > index 0000000..509e752
> > --- /dev/null
> > +++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
> > @@ -0,0 +1,96 @@
> > +<refentry id="vidioc-prepare-buf">
> > +  <refmeta>
> > +    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
> > +    &manvol;
> > +  </refmeta>
> > +
> > +  <refnamediv>
> > +    <refname>VIDIOC_PREPARE_BUF</refname>
> > +    <refpurpose>Prepare a buffer for I/O</refpurpose>
> > +  </refnamediv>
> > +
> > +  <refsynopsisdiv>
> > +    <funcsynopsis>
> > +      <funcprototype>
> > +       <funcdef>int <function>ioctl</function></funcdef>
> > +       <paramdef>int <parameter>fd</parameter></paramdef>
> > +       <paramdef>int <parameter>request</parameter></paramdef>
> > +       <paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
> > +      </funcprototype>
> > +    </funcsynopsis>
> > +  </refsynopsisdiv>
> > +
> > +  <refsect1>
> > +    <title>Arguments</title>
> > +
> > +    <variablelist>
> > +      <varlistentry>
> > +       <term><parameter>fd</parameter></term>
> > +       <listitem>
> > +         <para>&fd;</para>
> > +       </listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +       <term><parameter>request</parameter></term>
> > +       <listitem>
> > +         <para>VIDIOC_PREPARE_BUF</para>
> > +       </listitem>
> > +      </varlistentry>
> > +      <varlistentry>
> > +       <term><parameter>argp</parameter></term>
> > +       <listitem>
> > +         <para></para>
> > +       </listitem>
> > +      </varlistentry>
> > +    </variablelist>
> > +  </refsect1>
> > +
> > +  <refsect1>
> > +    <title>Description</title>
> > +
> > +    <para>Applications can optionally call the
> > +<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
> > +to the driver before actually enqueuing it, using the
> > +<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
> > +Such preparations may include cache invalidation or cleaning. Performing them
> > +in advance saves time during the actual I/O. In case such cache operations are
> > +not required, the application can use one of
> > +<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
> > +<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
> > +step.</para>
> > +
> 
> I'm probably forgetting something, but why would we want to do both
> PREPARE_BUF and QBUF? Why not queue in advance?
> Could you give a full sequence of ioctls how it will be used
> (including streamons, etc.)? I'm trying to picture how passing of both
> types of buffers will have to look like between vb2 and a driver.
> 
> <snip>
> 
> --
> Best regards,
> Pawel Osciak
diff mbox

Patch

diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index 227e7ac..6249d0e 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -927,6 +927,23 @@  ioctl is called.</entry>
 Applications set or clear this flag before calling the
 <constant>VIDIOC_QBUF</constant> ioctl.</entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry>
+	    <entry>0x0400</entry>
+	    <entry>Caches do not have to be invalidated for this buffer.
+Typically applications shall use this flag, if the data, captured in the buffer
+is not going to br touched by the CPU, instead the buffer will, probably, be
+passed on to a DMA-capable hardware unit for further processing or output.
+</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry>
+	    <entry>0x0800</entry>
+	    <entry>Caches do not have to be cleaned for this buffer.
+Typically applications shall use this flag for output buffers, if the data
+in this buffer has not been created by the CPU, but by some DMA-capable unit,
+in which case caches have not been used.</entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 0d05e87..06bb179 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -462,6 +462,7 @@  and discussions on the V4L mailing list.</revremark>
     &sub-close;
     &sub-ioctl;
     <!-- All ioctls go here. -->
+    &sub-create-bufs;
     &sub-cropcap;
     &sub-dbg-g-chip-ident;
     &sub-dbg-g-register;
@@ -504,6 +505,7 @@  and discussions on the V4L mailing list.</revremark>
     &sub-queryctrl;
     &sub-query-dv-preset;
     &sub-querystd;
+    &sub-prepare-buf;
     &sub-reqbufs;
     &sub-s-hw-freq-seek;
     &sub-streamon;
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
new file mode 100644
index 0000000..5f0158c
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
@@ -0,0 +1,152 @@ 
+<refentry id="vidioc-create-bufs">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_CREATE_BUFS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_CREATE_BUFS</refname>
+    <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_create_buffers *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_CREATE_BUFS</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>This ioctl is used to create buffers for <link linkend="mmap">memory
+mapped</link> or <link linkend="userp">user pointer</link>
+I/O. It can be used as an alternative to the <constant>VIDIOC_REQBUFS</constant>
+ioctl, when a tighter control over buffers is required. This ioctl can be called
+multiple times to create buffers of different sizes.
+
+    <para>To allocate device buffers applications initialize all
+fields of the <structname>v4l2_create_buffers</structname> structure.
+They set the <structfield>type</structfield> field in the
+<structname>v4l2_format</structname> structure, embedded in this
+structure, to the respective stream or buffer type.
+<structfield>count</structfield> must be set to the number of required
+buffers. <structfield>memory</structfield> specifies the required I/O
+method. Applications have two possibilities to specify the size of buffers
+to be prepared: they can either set the <structfield>size</structfield>
+field explicitly to a non-zero value, or fill in the frame format data in the
+<structfield>format</structfield> field. In the latter case buffer sizes
+will be calculated automatically by the driver. The
+<structfield>reserved</structfield> array must be zeroed. When the ioctl
+is called with a pointer to this structure the driver will attempt to allocate
+up to the requested number of buffers and store the actual number allocated
+and the starting index in the <structfield>count</structfield> and
+the <structfield>index</structfield> fields respectively.
+<structfield>count</structfield> can be smaller than the number requested.
+-ENOMEM is returned, if the driver runs out of free memory.</para>
+    <para>When the I/O method is not supported the ioctl
+returns an &EINVAL;.</para>
+
+    <table pgwide="1" frame="none" id="v4l2-create-buffers">
+      <title>struct <structname>v4l2_create_buffers</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>index</structfield></entry>
+	    <entry>The starting buffer index, returned by the driver.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>count</structfield></entry>
+	    <entry>The number of buffers requested or granted.</entry>
+	  </row>
+	  <row>
+	    <entry>&v4l2-memory;</entry>
+	    <entry><structfield>memory</structfield></entry>
+	    <entry>Applications set this field to
+<constant>V4L2_MEMORY_MMAP</constant> or
+<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>size</structfield></entry>
+	    <entry>Explicit size of buffers, being created.</entry>
+	  </row>
+	  <row>
+	    <entry>&v4l2-format;</entry>
+	    <entry><structfield>format</structfield></entry>
+	    <entry>Application has to set the <structfield>type</structfield>
+field, other fields should be used, if the application wants to allocate buffers
+for a specific frame format.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry>A place holder for future extensions.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>ENOMEM</errorcode></term>
+	<listitem>
+	  <para>No memory to allocate buffers for <link linkend="mmap">memory
+mapped</link> I/O.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The buffer type (<structfield>type</structfield> field) or the
+requested I/O method (<structfield>memory</structfield>) is not
+supported.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
new file mode 100644
index 0000000..509e752
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
@@ -0,0 +1,96 @@ 
+<refentry id="vidioc-prepare-buf">
+  <refmeta>
+    <refentrytitle>ioctl VIDIOC_PREPARE_BUF</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>VIDIOC_PREPARE_BUF</refname>
+    <refpurpose>Prepare a buffer for I/O</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>struct v4l2_buffer *<parameter>argp</parameter></paramdef>
+      </funcprototype>
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Arguments</title>
+
+    <variablelist>
+      <varlistentry>
+	<term><parameter>fd</parameter></term>
+	<listitem>
+	  <para>&fd;</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>request</parameter></term>
+	<listitem>
+	  <para>VIDIOC_PREPARE_BUF</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>Applications can optionally call the
+<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
+to the driver before actually enqueuing it, using the
+<constant>VIDIOC_QBUF</constant> ioctl, and to prepare it for future I/O.
+Such preparations may include cache invalidation or cleaning. Performing them
+in advance saves time during the actual I/O. In case such cache operations are
+not required, the application can use one of
+<constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant> and
+<constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant> flags to skip the respective
+step.</para>
+
+    <para>The <structname>v4l2_buffer</structname> structure is
+specified in <xref linkend="buffer" />.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+
+    <variablelist>
+      <varlistentry>
+	<term><errorcode>EBUSY</errorcode></term>
+	<listitem>
+	  <para>File I/O is in progress.</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><errorcode>EINVAL</errorcode></term>
+	<listitem>
+	  <para>The buffer <structfield>type</structfield> is not
+supported, or the <structfield>index</structfield> is out of bounds,
+or no buffers have been allocated yet, or the
+<structfield>userptr</structfield> or
+<structfield>length</structfield> are invalid.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 61979b7..4105f69 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -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;
+	__u32			size;		/* Explicit size, e.g., for compressed streams */
+	struct v4l2_format32	format;		/* "type" is used always, the rest if size == 0 */
+};
+
+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_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)
 {
-	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
-		put_user(kp->type, &up->type))
-		return -EFAULT;
 	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,11 @@  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_PREPARE_BUF:
 	case VIDIOC_QUERYBUF:
 	case VIDIOC_QBUF:
 	case VIDIOC_DQBUF:
@@ -959,6 +1009,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;
 
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 002ce13..7824152 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -260,6 +260,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)
 
@@ -2216,6 +2218,36 @@  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;
+		ret = check_fmt(ops, create->format.type);
+		if (ret)
+			break;
+
+		if (create->size)
+			CLEAR_AFTER_FIELD(create, count);
+
+		ret = ops->vidioc_create_bufs(file, fh, create);
+
+		dbgarg(cmd, "count=%d\n", create->count);
+		break;
+	}
+	case VIDIOC_PREPARE_BUF:
+	{
+		struct v4l2_buffer *b = arg;
+
+		if (!ops->vidioc_prepare_buf)
+			break;
+
+		ret = ops->vidioc_prepare_buf(file, fh, b);
+
+		dbgarg(cmd, "index=%d", b->index);
+		break;
+	}
 	default:
 	{
 		bool valid_prio = true;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index fca24cc..0b594c7 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -653,6 +653,9 @@  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 */
+/* Cache handling flags */
+#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE	0x0400
+#define V4L2_BUF_FLAG_NO_CACHE_CLEAN		0x0800
 
 /*
  *	O V E R L A Y   P R E V I E W
@@ -2092,6 +2095,16 @@  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;
+	__u32			size;		/* Explicit size, e.g., for compressed streams */
+	struct v4l2_format	format;		/* "type" is used always, the rest if size == 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
  *
@@ -2182,6 +2195,9 @@  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)
 
+#define VIDIOC_CREATE_BUFS	_IOWR('V', 92, struct v4l2_create_buffers)
+#define VIDIOC_PREPARE_BUF	 _IOW('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! */
 
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index dd9f1e7..4d1c74a 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -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,