Commit 6970f299 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

doc-rst: mmap: Add ioctl cross references

There are lots of ioctls mentioned there that aren't cross-referenced.

Convert the const to cross references. That makes it visually
better, and improves navigation along the document.

While here, remove bad whitespaces.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 5c591aa1
...@@ -58,8 +58,8 @@ possible with the :ref:`munmap() <func-munmap>` function. ...@@ -58,8 +58,8 @@ possible with the :ref:`munmap() <func-munmap>` function.
struct v4l2_requestbuffers reqbuf; struct v4l2_requestbuffers reqbuf;
struct { struct {
void *start; void *start;
size_t length; size_t length;
} *buffers; } *buffers;
unsigned int i; unsigned int i;
...@@ -69,57 +69,57 @@ possible with the :ref:`munmap() <func-munmap>` function. ...@@ -69,57 +69,57 @@ possible with the :ref:`munmap() <func-munmap>` function.
reqbuf.count = 20; reqbuf.count = 20;
if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) { if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
if (errno == EINVAL) if (errno == EINVAL)
printf("Video capturing or mmap-streaming is not supported\\n"); printf("Video capturing or mmap-streaming is not supported\\n");
else else
perror("VIDIOC_REQBUFS"); perror("VIDIOC_REQBUFS");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* We want at least five buffers. */ /* We want at least five buffers. */
if (reqbuf.count < 5) { if (reqbuf.count < 5) {
/* You may need to free the buffers here. */ /* You may need to free the buffers here. */
printf("Not enough buffer memory\\n"); printf("Not enough buffer memory\\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
buffers = calloc(reqbuf.count, sizeof(*buffers)); buffers = calloc(reqbuf.count, sizeof(*buffers));
assert(buffers != NULL); assert(buffers != NULL);
for (i = 0; i < reqbuf.count; i++) { for (i = 0; i < reqbuf.count; i++) {
struct v4l2_buffer buffer; struct v4l2_buffer buffer;
memset(&buffer, 0, sizeof(buffer)); memset(&buffer, 0, sizeof(buffer));
buffer.type = reqbuf.type; buffer.type = reqbuf.type;
buffer.memory = V4L2_MEMORY_MMAP; buffer.memory = V4L2_MEMORY_MMAP;
buffer.index = i; buffer.index = i;
if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) { if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
perror("VIDIOC_QUERYBUF"); perror("VIDIOC_QUERYBUF");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
buffers[i].length = buffer.length; /* remember for munmap() */ buffers[i].length = buffer.length; /* remember for munmap() */
buffers[i].start = mmap(NULL, buffer.length, buffers[i].start = mmap(NULL, buffer.length,
PROT_READ | PROT_WRITE, /* recommended */ PROT_READ | PROT_WRITE, /* recommended */
MAP_SHARED, /* recommended */ MAP_SHARED, /* recommended */
fd, buffer.m.offset); fd, buffer.m.offset);
if (MAP_FAILED == buffers[i].start) { if (MAP_FAILED == buffers[i].start) {
/* If you do not exit here you should unmap() and free() /* If you do not exit here you should unmap() and free()
the buffers mapped so far. */ the buffers mapped so far. */
perror("mmap"); perror("mmap");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
/* Cleanup. */ /* Cleanup. */
for (i = 0; i < reqbuf.count; i++) for (i = 0; i < reqbuf.count; i++)
munmap(buffers[i].start, buffers[i].length); munmap(buffers[i].start, buffers[i].length);
.. code-block:: c .. code-block:: c
...@@ -130,8 +130,8 @@ possible with the :ref:`munmap() <func-munmap>` function. ...@@ -130,8 +130,8 @@ possible with the :ref:`munmap() <func-munmap>` function.
#define FMT_NUM_PLANES = 3 #define FMT_NUM_PLANES = 3
struct { struct {
void *start[FMT_NUM_PLANES]; void *start[FMT_NUM_PLANES];
size_t length[FMT_NUM_PLANES]; size_t length[FMT_NUM_PLANES];
} *buffers; } *buffers;
unsigned int i, j; unsigned int i, j;
...@@ -141,66 +141,66 @@ possible with the :ref:`munmap() <func-munmap>` function. ...@@ -141,66 +141,66 @@ possible with the :ref:`munmap() <func-munmap>` function.
reqbuf.count = 20; reqbuf.count = 20;
if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) { if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
if (errno == EINVAL) if (errno == EINVAL)
printf("Video capturing or mmap-streaming is not supported\\n"); printf("Video capturing or mmap-streaming is not supported\\n");
else else
perror("VIDIOC_REQBUFS"); perror("VIDIOC_REQBUFS");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* We want at least five buffers. */ /* We want at least five buffers. */
if (reqbuf.count < 5) { if (reqbuf.count < 5) {
/* You may need to free the buffers here. */ /* You may need to free the buffers here. */
printf("Not enough buffer memory\\n"); printf("Not enough buffer memory\\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
buffers = calloc(reqbuf.count, sizeof(*buffers)); buffers = calloc(reqbuf.count, sizeof(*buffers));
assert(buffers != NULL); assert(buffers != NULL);
for (i = 0; i < reqbuf.count; i++) { for (i = 0; i < reqbuf.count; i++) {
struct v4l2_buffer buffer; struct v4l2_buffer buffer;
struct v4l2_plane planes[FMT_NUM_PLANES]; struct v4l2_plane planes[FMT_NUM_PLANES];
memset(&buffer, 0, sizeof(buffer)); memset(&buffer, 0, sizeof(buffer));
buffer.type = reqbuf.type; buffer.type = reqbuf.type;
buffer.memory = V4L2_MEMORY_MMAP; buffer.memory = V4L2_MEMORY_MMAP;
buffer.index = i; buffer.index = i;
/* length in struct v4l2_buffer in multi-planar API stores the size /* length in struct v4l2_buffer in multi-planar API stores the size
* of planes array. */ * of planes array. */
buffer.length = FMT_NUM_PLANES; buffer.length = FMT_NUM_PLANES;
buffer.m.planes = planes; buffer.m.planes = planes;
if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) { if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) {
perror("VIDIOC_QUERYBUF"); perror("VIDIOC_QUERYBUF");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Every plane has to be mapped separately */ /* Every plane has to be mapped separately */
for (j = 0; j < FMT_NUM_PLANES; j++) { for (j = 0; j < FMT_NUM_PLANES; j++) {
buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */ buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length, buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
PROT_READ | PROT_WRITE, /* recommended */ PROT_READ | PROT_WRITE, /* recommended */
MAP_SHARED, /* recommended */ MAP_SHARED, /* recommended */
fd, buffer.m.planes[j].m.offset); fd, buffer.m.planes[j].m.offset);
if (MAP_FAILED == buffers[i].start[j]) { if (MAP_FAILED == buffers[i].start[j]) {
/* If you do not exit here you should unmap() and free() /* If you do not exit here you should unmap() and free()
the buffers and planes mapped so far. */ the buffers and planes mapped so far. */
perror("mmap"); perror("mmap");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
} }
/* Cleanup. */ /* Cleanup. */
for (i = 0; i < reqbuf.count; i++) for (i = 0; i < reqbuf.count; i++)
for (j = 0; j < FMT_NUM_PLANES; j++) for (j = 0; j < FMT_NUM_PLANES; j++)
munmap(buffers[i].start[j], buffers[i].length[j]); munmap(buffers[i].start[j], buffers[i].length[j]);
Conceptually streaming drivers maintain two buffer queues, an incoming Conceptually streaming drivers maintain two buffer queues, an incoming
and an outgoing queue. They separate the synchronous capture or output and an outgoing queue. They separate the synchronous capture or output
...@@ -224,37 +224,38 @@ mapped buffers, then to start capturing and enter the read loop. Here ...@@ -224,37 +224,38 @@ mapped buffers, then to start capturing and enter the read loop. Here
the application waits until a filled buffer can be dequeued, and the application waits until a filled buffer can be dequeued, and
re-enqueues the buffer when the data is no longer needed. Output re-enqueues the buffer when the data is no longer needed. Output
applications fill and enqueue buffers, when enough buffers are stacked applications fill and enqueue buffers, when enough buffers are stacked
up the output is started with ``VIDIOC_STREAMON``. In the write loop, up the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.
when the application runs out of free buffers, it must wait until an In the write loop, when the application runs out of free buffers, it
empty buffer can be dequeued and reused. must wait until an empty buffer can be dequeued and reused.
To enqueue and dequeue a buffer applications use the To enqueue and dequeue a buffer applications use the :ref:`VIDIOC_QBUF`
:ref:`VIDIOC_QBUF` and and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. The status of a buffer
:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` ioctl. The status of a buffer being being mapped, enqueued, full or empty can be determined at any time
mapped, enqueued, full or empty can be determined at any time using the using the :ref:`VIDIOC_QUERYBUF` ioctl. Two methods exist to suspend
:ref:`VIDIOC_QUERYBUF` ioctl. Two methods exist to execution of the application until one or more buffers can be dequeued.
suspend execution of the application until one or more buffers can be By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` blocks when no buffer is
dequeued. By default ``VIDIOC_DQBUF`` blocks when no buffer is in the in the outgoing queue. When the ``O_NONBLOCK`` flag was given to the
outgoing queue. When the ``O_NONBLOCK`` flag was given to the :ref:`open() <func-open>` function, :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
:ref:`open() <func-open>` function, ``VIDIOC_DQBUF`` returns returns immediately with an ``EAGAIN`` error code when no buffer is
immediately with an ``EAGAIN`` error code when no buffer is available. The available. The :ref:`select() <func-select>` or :ref:`poll()
:ref:`select() <func-select>` or :ref:`poll() <func-poll>` functions <func-poll>` functions are always available.
are always available.
To start and stop capturing or output applications call the To start and stop capturing or output applications call the
:ref:`VIDIOC_STREAMON` and :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF
:ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctl. Note <VIDIOC_STREAMON>` ioctl. Note :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`
``VIDIOC_STREAMOFF`` removes all buffers from both queues as a side removes all buffers from both queues as a side effect. Since there is
effect. Since there is no notion of doing anything "now" on a no notion of doing anything "now" on a multitasking system, if an
multitasking system, if an application needs to synchronize with another application needs to synchronize with another event it should examine
event it should examine the struct :ref:`v4l2_buffer <v4l2-buffer>` the struct ::ref:`v4l2_buffer <v4l2-buffer>` ``timestamp`` of captured
``timestamp`` of captured or outputted buffers. or outputted buffers.
Drivers implementing memory mapping I/O must support the Drivers implementing memory mapping I/O must support the
``VIDIOC_REQBUFS``, ``VIDIOC_QUERYBUF``, ``VIDIOC_QBUF``, :ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF
``VIDIOC_DQBUF``, ``VIDIOC_STREAMON`` and ``VIDIOC_STREAMOFF`` ioctl, <VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF
the :ref:`mmap() <func-mmap>`, :ref:`munmap() <func-munmap>`, :ref:`select() <func-select>` and <VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
:ref:`poll() <func-poll>` function. [3]_ and :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()
<func-mmap>`, :ref:`munmap() <func-munmap>`, :ref:`select()
<func-select>` and :ref:`poll() <func-poll>` function. [3]_
[capture example] [capture example]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment