Message ID | Pine.LNX.4.64.1106271710490.9394@axis700.grange (mailing list archive) |
---|---|
State | RFC |
Headers | show |
Hi, Guennadi! Many thanks for the patch! On Mon, Jun 27, 2011 at 05:17:03PM +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> > --- > > 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/v4l2.xml | 2 + > .../DocBook/media/v4l/vidioc-create-bufs.xml | 153 ++++++++++++++++++++ > .../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 + > 7 files changed, 361 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/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml > index a7fd76d..10fe7c7 100644 > --- a/Documentation/DocBook/media/v4l/v4l2.xml > +++ b/Documentation/DocBook/media/v4l/v4l2.xml > @@ -453,6 +453,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; > @@ -495,6 +496,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..3003530 > --- /dev/null > +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml > @@ -0,0 +1,153 @@ > +<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, or fill in the frame format data in the ... explicitly -> to non-zero value... ? > +<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 > +the requested number of buffers and it stores the actual number > +allocated and the starting index in the <structfield>count</structfield> and > +the <structfield>index</structfield> fields respectively. REQBUFS documentation does not mention that the buffer indices would be limited to VIDEO_MAX_FRAME but they actually are (I think). Do you think we could mention that the buffer indices obtained by CREATE_BUFS are _not_ limited to that number, for the reasons I pointed to at an earlier review round of this patch? Even if the actual implementation would be limited to VIDEO_MAX_FRAME for now the applications wouldn't start assuming that. > +<structfield>count</structfield> can be smaller than the number requested, > +even zero, when the driver runs out of free memory. A larger number is also As -ENOMEM is a valid error code I don't think there's use for returning count == 0. > +possible when the driver requires more buffers to function correctly.</para> I'm not sure if I still like the idea of telling the user that n buffers are required for streaming by creating that many buffer objects. The user may also create more buffers and use them for streaming instead of the ones the driver created at the first call. > + <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>[2]</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> A stupid question: don't we want to do actual allocation in PREPARE_BUF instead? Or is this a policy issue rather than something that results from an actual memory allocation failure? > + </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..9532d28 > --- /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, 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> The flags should be documented as part of struct v4l2_buffer documentation as they are specific to the structure field rather than the ioctl. Wouldn't they be valid for QBUF and DQBUF as well --- actually they are more important there IMO. PREPARE_BUF only needs to be called right after CREATE_BUFS (or REQBUFS); otherwise it has no effect, or does it? This should also thus define the default cache behaviour for QBUF and DQBUF. > + <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 7c26947..6fcc7e0 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 */ > @@ -675,6 +709,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext > #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) > #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_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) > @@ -693,6 +729,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar > struct v4l2_input v2i; > struct v4l2_standard v2s; > struct v4l2_ext_controls v2ecs; > + struct v4l2_create_buffers v2crt; > unsigned long vx; > int vi; > } karg; > @@ -722,6 +759,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) { > @@ -746,6 +785,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: > @@ -818,6 +863,11 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar > err = put_v4l2_framebuffer32(&karg.v2fb, up); > break; > > + case VIDIOC_CREATE_BUFS: > + err = put_v4l2_create32(&karg.v2crt, up); > + break; > + > + case VIDIOC_PREPARE_BUF: > case VIDIOC_G_FMT: > case VIDIOC_S_FMT: > case VIDIOC_TRY_FMT: > @@ -922,6 +972,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) > case VIDIOC_DQEVENT: > 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 213ba7d..40b8d96 100644 > --- a/drivers/media/video/v4l2-ioctl.c > +++ b/drivers/media/video/v4l2-ioctl.c > @@ -259,6 +259,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) > > @@ -2184,6 +2186,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 8a4c309..8807462 100644 > --- a/include/linux/videodev2.h > +++ b/include/linux/videodev2.h > @@ -643,6 +643,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 > @@ -1852,6 +1855,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[4]; I think we should have more reserved fields. What about 8 at least? It doesn't matter much as long as we keep this under 256 bytes (struct v4l2_format is 204 bytes). Also the number of reserved fields is different from the documentation above. > +}; > + > /* > * 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 > * > @@ -1942,6 +1955,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 > Cheers,
Hi Sakari On Mon, 27 Jun 2011, Sakari Ailus wrote: > Hi, Guennadi! > > Many thanks for the patch! > > On Mon, Jun 27, 2011 at 05:17:03PM +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> > > --- > > > > 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/v4l2.xml | 2 + > > .../DocBook/media/v4l/vidioc-create-bufs.xml | 153 ++++++++++++++++++++ > > .../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 + > > 7 files changed, 361 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/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml > > index a7fd76d..10fe7c7 100644 > > --- a/Documentation/DocBook/media/v4l/v4l2.xml > > +++ b/Documentation/DocBook/media/v4l/v4l2.xml > > @@ -453,6 +453,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; > > @@ -495,6 +496,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..3003530 > > --- /dev/null > > +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml > > @@ -0,0 +1,153 @@ > > +<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, or fill in the frame format data in the > > ... explicitly -> to non-zero value... ? > > > +<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 > > +the requested number of buffers and it stores the actual number > > +allocated and the starting index in the <structfield>count</structfield> and > > +the <structfield>index</structfield> fields respectively. > > REQBUFS documentation does not mention that the buffer indices would be > limited to VIDEO_MAX_FRAME but they actually are (I think). Do you think we > could mention that the buffer indices obtained by CREATE_BUFS are _not_ > limited to that number, for the reasons I pointed to at an earlier review > round of this patch? > > Even if the actual implementation would be limited to VIDEO_MAX_FRAME for > now the applications wouldn't start assuming that. Don't know, why should an application assume anything, that is not in the spec? We certainly can add this here, but I just don't see the point, sorry. > > +<structfield>count</structfield> can be smaller than the number requested, > > +even zero, when the driver runs out of free memory. A larger number is also > > As -ENOMEM is a valid error code I don't think there's use for returning > count == 0. yes, as you guess, it is copied from REQBUFS. I was wondering too, why not just rely on the respective error code. But it says it _can_ be, so, again, it's not very important. > > +possible when the driver requires more buffers to function correctly.</para> > > I'm not sure if I still like the idea of telling the user that n buffers are > required for streaming by creating that many buffer objects. The user may > also create more buffers and use them for streaming instead of the ones the > driver created at the first call. TBH, I don't understand this behaviour either. It is not that important how many buffers the user has allocated, it is important, how many buffers are queued during streaming. An underrun situation, when an application has enough buffers allocated, but failed to QBUF them quickly enough, seems perfectly possible to me and should be handled by all drivers, right? So, I tend to agree, that a more logical behaviour would be to fail the STREAMON ioctl() if not enough buffers are queued, and handle and underruns at run-time accordingly. So, would everyone agree, if we prohibit drivers from allocating more buffers, than the uesr has requested? So, an application, relying on this and requesting 1 buffer to get a minimum suitable number of them wouldn't work? I don't think we shall change this for REQBUFS, but for CREATE_BUFS we can do this. > > + <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>[2]</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> > > A stupid question: don't we want to do actual allocation in PREPARE_BUF > instead? Or is this a policy issue rather than something that results from > an actual memory allocation failure? No, don't think so. We want buffers to exist after a call to CREATE_BUFS, also, see below. > > + </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..9532d28 > > --- /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, 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> > > The flags should be documented as part of struct v4l2_buffer documentation > as they are specific to the structure field rather than the ioctl. Wouldn't > they be valid for QBUF and DQBUF as well --- actually they are more > important there IMO. Ok, will move. > PREPARE_BUF only needs to be called right after CREATE_BUFS (or REQBUFS); > otherwise it has no effect, or does it? No. You do PREPARE_BUF every time, when you're done processing the buffer contents and want to prepare it for use with a future QBUF. Say, you start your camera in preview mode, at that time you use your small buffers, meanwhile you submit your big snapshot buffers with PREPARE_BUF to the kernel. Then, when you need to take a still shot, you STREAMOFF, S_FMT, QBUF your big buffers, STREAMON, DQBUF, STREAMOFF, S_FMT, QBUF your small buffers for preview again, STREAMON, process your still image, then PREPARE_BUF your big buffers again for the next still shot, etc. > This should also thus define the > default cache behaviour for QBUF and DQBUF. Hm, didn't you suggest, that it is possible, that an application will want to invalidate caches on some buffers and skip others? And since we only have flags to skip the cache operation and not to enforce it, how would you disable that flag again? I think, it should stay explicit per buffer per submission. As for the use of these flags with QBUF, I don't see any reasons why this shouldn't be allowed. Seems a good idea to me, thanks. > > + <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 7c26947..6fcc7e0 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 */ > > @@ -675,6 +709,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext > > #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) > > #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_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) > > @@ -693,6 +729,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar > > struct v4l2_input v2i; > > struct v4l2_standard v2s; > > struct v4l2_ext_controls v2ecs; > > + struct v4l2_create_buffers v2crt; > > unsigned long vx; > > int vi; > > } karg; > > @@ -722,6 +759,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) { > > @@ -746,6 +785,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: > > @@ -818,6 +863,11 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar > > err = put_v4l2_framebuffer32(&karg.v2fb, up); > > break; > > > > + case VIDIOC_CREATE_BUFS: > > + err = put_v4l2_create32(&karg.v2crt, up); > > + break; > > + > > + case VIDIOC_PREPARE_BUF: > > case VIDIOC_G_FMT: > > case VIDIOC_S_FMT: > > case VIDIOC_TRY_FMT: > > @@ -922,6 +972,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) > > case VIDIOC_DQEVENT: > > 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 213ba7d..40b8d96 100644 > > --- a/drivers/media/video/v4l2-ioctl.c > > +++ b/drivers/media/video/v4l2-ioctl.c > > @@ -259,6 +259,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) > > > > @@ -2184,6 +2186,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 8a4c309..8807462 100644 > > --- a/include/linux/videodev2.h > > +++ b/include/linux/videodev2.h > > @@ -643,6 +643,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 > > @@ -1852,6 +1855,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[4]; > > I think we should have more reserved fields. What about 8 at least? > > It doesn't matter much as long as we keep this under 256 bytes (struct > v4l2_format is 204 bytes). Also the number of reserved fields is different > from the documentation above. Shall I say, that I don't care?:-) Shall I put 800 reserved words there? I wouldn't even be offended, if Mauro changed this value to any other he sees fit best here. > > +}; > > + > > /* > > * 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 > > * > > @@ -1942,6 +1955,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 > > > > Cheers, > > -- > Sakari Ailus > sakari.ailus@iki.fi 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
Hi, Guennadi! Guennadi Liakhovetski wrote: > Hi Sakari > > On Mon, 27 Jun 2011, Sakari Ailus wrote: > >> Hi, Guennadi! >> >> Many thanks for the patch! >> >> On Mon, Jun 27, 2011 at 05:17:03PM +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> >>> --- >>> >>> 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/v4l2.xml | 2 + >>> .../DocBook/media/v4l/vidioc-create-bufs.xml | 153 ++++++++++++++++++++ >>> .../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 + >>> 7 files changed, 361 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/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml >>> index a7fd76d..10fe7c7 100644 >>> --- a/Documentation/DocBook/media/v4l/v4l2.xml >>> +++ b/Documentation/DocBook/media/v4l/v4l2.xml >>> @@ -453,6 +453,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; >>> @@ -495,6 +496,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..3003530 >>> --- /dev/null >>> +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml >>> @@ -0,0 +1,153 @@ >>> +<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, or fill in the frame format data in the >> >> ... explicitly -> to non-zero value... ? >> >>> +<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 >>> +the requested number of buffers and it stores the actual number >>> +allocated and the starting index in the <structfield>count</structfield> and >>> +the <structfield>index</structfield> fields respectively. >> >> REQBUFS documentation does not mention that the buffer indices would be >> limited to VIDEO_MAX_FRAME but they actually are (I think). Do you think we >> could mention that the buffer indices obtained by CREATE_BUFS are _not_ >> limited to that number, for the reasons I pointed to at an earlier review >> round of this patch? >> >> Even if the actual implementation would be limited to VIDEO_MAX_FRAME for >> now the applications wouldn't start assuming that. > > Don't know, why should an application assume anything, that is not in the > spec? We certainly can add this here, but I just don't see the point, > sorry. If there never has been an assumption that buffer indices are limited to VIDEO_MAX_FRAME, there is no problem. Perhaps it has been the implementation (videobuf and videobuf2 and many drivers) which have been doing this? >>> +<structfield>count</structfield> can be smaller than the number requested, >>> +even zero, when the driver runs out of free memory. A larger number is also >> >> As -ENOMEM is a valid error code I don't think there's use for returning >> count == 0. > > yes, as you guess, it is copied from REQBUFS. I was wondering too, why not > just rely on the respective error code. But it says it _can_ be, so, > again, it's not very important. REQBUFS may have count == 0 because that's a way to release the allocated buffers. We don't support freeing buffers using CREATE_BUFS. >>> +possible when the driver requires more buffers to function correctly.</para> >> >> I'm not sure if I still like the idea of telling the user that n buffers are >> required for streaming by creating that many buffer objects. The user may >> also create more buffers and use them for streaming instead of the ones the >> driver created at the first call. > > TBH, I don't understand this behaviour either. It is not that important > how many buffers the user has allocated, it is important, how many buffers > are queued during streaming. An underrun situation, when an application > has enough buffers allocated, but failed to QBUF them quickly enough, > seems perfectly possible to me and should be handled by all drivers, > right? I agree. > So, I tend to agree, that a more logical behaviour would be to fail the > STREAMON ioctl() if not enough buffers are queued, and handle and > underruns at run-time accordingly. So, would everyone agree, if we > prohibit drivers from allocating more buffers, than the uesr has > requested? So, an application, relying on this and requesting 1 buffer to > get a minimum suitable number of them wouldn't work? I agree. Returning a proper error code in VIDIOC_STREAMON is what I would also use for this. > I don't think we shall change this for REQBUFS, but for CREATE_BUFS we can > do this. Agreed. >>> + <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>[2]</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> >> >> A stupid question: don't we want to do actual allocation in PREPARE_BUF >> instead? Or is this a policy issue rather than something that results from >> an actual memory allocation failure? > > No, don't think so. We want buffers to exist after a call to CREATE_BUFS, > also, see below. Please ignore that comment. I missed it already mentioned the MMAP buffer type. >>> + </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..9532d28 >>> --- /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, 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> >> >> The flags should be documented as part of struct v4l2_buffer documentation >> as they are specific to the structure field rather than the ioctl. Wouldn't >> they be valid for QBUF and DQBUF as well --- actually they are more >> important there IMO. > > Ok, will move. > >> PREPARE_BUF only needs to be called right after CREATE_BUFS (or REQBUFS); >> otherwise it has no effect, or does it? > > No. You do PREPARE_BUF every time, when you're done processing the buffer > contents and want to prepare it for use with a future QBUF. Say, you start > your camera in preview mode, at that time you use your small buffers, > meanwhile you submit your big snapshot buffers with PREPARE_BUF to the > kernel. Then, when you need to take a still shot, you STREAMOFF, S_FMT, > QBUF your big buffers, STREAMON, DQBUF, STREAMOFF, S_FMT, QBUF your small > buffers for preview again, STREAMON, process your still image, then > PREPARE_BUF your big buffers again for the next still shot, etc. Right. I missed the cache handling part of the PREPARE_BUF ioctl. Of course it must be called before every QBUF to get any advantage of it. I think you could add "using QBUF IOCTL" after "actually enqueueing it" to make the name of the IOCTL explicit. >> This should also thus define the >> default cache behaviour for QBUF and DQBUF. > > Hm, didn't you suggest, that it is possible, that an application will want > to invalidate caches on some buffers and skip others? And since we only > have flags to skip the cache operation and not to enforce it, how would > you disable that flag again? I think, it should stay explicit per buffer > per submission. > > As for the use of these flags with QBUF, I don't see any reasons why this > shouldn't be allowed. Seems a good idea to me, thanks. The flags are to be used for QBUF as well then. Good. If the user gave these flags to PREPARE_BUF, QBUF likely shouldn't do cache operations even if the flags are not passed since the job is already done. No change needed for documentation, but videobuf2. The same flag could be used for this in vb2_buffer.v4l2_buf. Are any of these flags valid in DQBUF? Probably theoretically the INVALIDATE is, but I'm not sure whether it is necessary to define right now. The actual implementation may well be flushing the whole cache and doing that would be only necessary once when the buffer passes through the driver. The pinning of the buffer to system memory, possible mapping to IOMMU etc. would take place in the first PREPARE_BUF, I guess? Compared to these, the cache invalidation is insignificant, but the non-cache related operations only needs to be done on the first PREPARE_BUF call. Do you think some of this should be mentioned in the documentation? >>> + <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 7c26947..6fcc7e0 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 */ >>> @@ -675,6 +709,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext >>> #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) >>> #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_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) >>> @@ -693,6 +729,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar >>> struct v4l2_input v2i; >>> struct v4l2_standard v2s; >>> struct v4l2_ext_controls v2ecs; >>> + struct v4l2_create_buffers v2crt; >>> unsigned long vx; >>> int vi; >>> } karg; >>> @@ -722,6 +759,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) { >>> @@ -746,6 +785,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: >>> @@ -818,6 +863,11 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar >>> err = put_v4l2_framebuffer32(&karg.v2fb, up); >>> break; >>> >>> + case VIDIOC_CREATE_BUFS: >>> + err = put_v4l2_create32(&karg.v2crt, up); >>> + break; >>> + >>> + case VIDIOC_PREPARE_BUF: >>> case VIDIOC_G_FMT: >>> case VIDIOC_S_FMT: >>> case VIDIOC_TRY_FMT: >>> @@ -922,6 +972,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) >>> case VIDIOC_DQEVENT: >>> 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 213ba7d..40b8d96 100644 >>> --- a/drivers/media/video/v4l2-ioctl.c >>> +++ b/drivers/media/video/v4l2-ioctl.c >>> @@ -259,6 +259,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) >>> >>> @@ -2184,6 +2186,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 8a4c309..8807462 100644 >>> --- a/include/linux/videodev2.h >>> +++ b/include/linux/videodev2.h >>> @@ -643,6 +643,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 >>> @@ -1852,6 +1855,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[4]; >> >> I think we should have more reserved fields. What about 8 at least? >> >> It doesn't matter much as long as we keep this under 256 bytes (struct >> v4l2_format is 204 bytes). Also the number of reserved fields is different >> from the documentation above. > > Shall I say, that I don't care?:-) Shall I put 800 reserved words there? I > wouldn't even be offended, if Mauro changed this value to any other he > sees fit best here. Would you use eight if I ask nicely? :-) I have never seen a case where additional reserved fields have posed any issue but there are real examples of the opposite, and we're hitting these every now and then. In the worst case there needs to be a new ioctl just because of this. I can start listing IOCTLs if you wish. >>> +}; >>> + >>> /* >>> * 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 >>> * >>> @@ -1942,6 +1955,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 >>> >> >> Cheers, >> >> -- >> Sakari Ailus >> sakari.ailus@iki.fi > > Thanks > Guennadi > --- > Guennadi Liakhovetski, Ph.D. > Freelance Open-Source Software Developer > http://www.open-technology.de/ Kind regards,
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index a7fd76d..10fe7c7 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -453,6 +453,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; @@ -495,6 +496,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..3003530 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml @@ -0,0 +1,153 @@ +<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, 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 +the requested number of buffers and it stores 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, +even zero, when the driver runs out of free memory. A larger number is also +possible when the driver requires more buffers to function correctly.</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>[2]</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..9532d28 --- /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, 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 7c26947..6fcc7e0 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 */ @@ -675,6 +709,8 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32) #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_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) @@ -693,6 +729,7 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar struct v4l2_input v2i; struct v4l2_standard v2s; struct v4l2_ext_controls v2ecs; + struct v4l2_create_buffers v2crt; unsigned long vx; int vi; } karg; @@ -722,6 +759,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) { @@ -746,6 +785,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: @@ -818,6 +863,11 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar err = put_v4l2_framebuffer32(&karg.v2fb, up); break; + case VIDIOC_CREATE_BUFS: + err = put_v4l2_create32(&karg.v2crt, up); + break; + + case VIDIOC_PREPARE_BUF: case VIDIOC_G_FMT: case VIDIOC_S_FMT: case VIDIOC_TRY_FMT: @@ -922,6 +972,8 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_DQEVENT: 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 213ba7d..40b8d96 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -259,6 +259,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) @@ -2184,6 +2186,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 8a4c309..8807462 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -643,6 +643,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 @@ -1852,6 +1855,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[4]; +}; + /* * 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 * @@ -1942,6 +1955,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,
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> --- 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/v4l2.xml | 2 + .../DocBook/media/v4l/vidioc-create-bufs.xml | 153 ++++++++++++++++++++ .../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 + 7 files changed, 361 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