xref: /openbmc/linux/Documentation/userspace-api/media/v4l/mmap.rst (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1059b1c5bSMauro Carvalho Chehab.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
2407e84cdSMauro Carvalho Chehab.. c:namespace:: V4L
354f38fcaSMauro Carvalho Chehab
454f38fcaSMauro Carvalho Chehab.. _mmap:
554f38fcaSMauro Carvalho Chehab
654f38fcaSMauro Carvalho Chehab******************************
754f38fcaSMauro Carvalho ChehabStreaming I/O (Memory Mapping)
854f38fcaSMauro Carvalho Chehab******************************
954f38fcaSMauro Carvalho Chehab
1054f38fcaSMauro Carvalho ChehabInput and output devices support this I/O method when the
1154f38fcaSMauro Carvalho Chehab``V4L2_CAP_STREAMING`` flag in the ``capabilities`` field of struct
1254f38fcaSMauro Carvalho Chehab:c:type:`v4l2_capability` returned by the
1354f38fcaSMauro Carvalho Chehab:ref:`VIDIOC_QUERYCAP` ioctl is set. There are two
1454f38fcaSMauro Carvalho Chehabstreaming methods, to determine if the memory mapping flavor is
1554f38fcaSMauro Carvalho Chehabsupported applications must call the :ref:`VIDIOC_REQBUFS` ioctl
1654f38fcaSMauro Carvalho Chehabwith the memory type set to ``V4L2_MEMORY_MMAP``.
1754f38fcaSMauro Carvalho Chehab
1854f38fcaSMauro Carvalho ChehabStreaming is an I/O method where only pointers to buffers are exchanged
1954f38fcaSMauro Carvalho Chehabbetween application and driver, the data itself is not copied. Memory
2054f38fcaSMauro Carvalho Chehabmapping is primarily intended to map buffers in device memory into the
2154f38fcaSMauro Carvalho Chehabapplication's address space. Device memory can be for example the video
2254f38fcaSMauro Carvalho Chehabmemory on a graphics card with a video capture add-on. However, being
2354f38fcaSMauro Carvalho Chehabthe most efficient I/O method available for a long time, many other
2454f38fcaSMauro Carvalho Chehabdrivers support streaming as well, allocating buffers in DMA-able main
2554f38fcaSMauro Carvalho Chehabmemory.
2654f38fcaSMauro Carvalho Chehab
2754f38fcaSMauro Carvalho ChehabA driver can support many sets of buffers. Each set is identified by a
2854f38fcaSMauro Carvalho Chehabunique buffer type value. The sets are independent and each set can hold
2954f38fcaSMauro Carvalho Chehaba different type of data. To access different sets at the same time
3054f38fcaSMauro Carvalho Chehabdifferent file descriptors must be used. [#f1]_
3154f38fcaSMauro Carvalho Chehab
3254f38fcaSMauro Carvalho ChehabTo allocate device buffers applications call the
3354f38fcaSMauro Carvalho Chehab:ref:`VIDIOC_REQBUFS` ioctl with the desired number
3454f38fcaSMauro Carvalho Chehabof buffers and buffer type, for example ``V4L2_BUF_TYPE_VIDEO_CAPTURE``.
3554f38fcaSMauro Carvalho ChehabThis ioctl can also be used to change the number of buffers or to free
3654f38fcaSMauro Carvalho Chehabthe allocated memory, provided none of the buffers are still mapped.
3754f38fcaSMauro Carvalho Chehab
3854f38fcaSMauro Carvalho ChehabBefore applications can access the buffers they must map them into their
39407e84cdSMauro Carvalho Chehabaddress space with the :c:func:`mmap()` function. The
4054f38fcaSMauro Carvalho Chehablocation of the buffers in device memory can be determined with the
4154f38fcaSMauro Carvalho Chehab:ref:`VIDIOC_QUERYBUF` ioctl. In the single-planar
4254f38fcaSMauro Carvalho ChehabAPI case, the ``m.offset`` and ``length`` returned in a struct
4354f38fcaSMauro Carvalho Chehab:c:type:`v4l2_buffer` are passed as sixth and second
44407e84cdSMauro Carvalho Chehabparameter to the :c:func:`mmap()` function. When using the
4554f38fcaSMauro Carvalho Chehabmulti-planar API, struct :c:type:`v4l2_buffer` contains an
4654f38fcaSMauro Carvalho Chehabarray of struct :c:type:`v4l2_plane` structures, each
4754f38fcaSMauro Carvalho Chehabcontaining its own ``m.offset`` and ``length``. When using the
4854f38fcaSMauro Carvalho Chehabmulti-planar API, every plane of every buffer has to be mapped
49407e84cdSMauro Carvalho Chehabseparately, so the number of calls to :c:func:`mmap()` should
5054f38fcaSMauro Carvalho Chehabbe equal to number of buffers times number of planes in each buffer. The
5154f38fcaSMauro Carvalho Chehaboffset and length values must not be modified. Remember, the buffers are
5254f38fcaSMauro Carvalho Chehaballocated in physical memory, as opposed to virtual memory, which can be
5354f38fcaSMauro Carvalho Chehabswapped out to disk. Applications should free the buffers as soon as
54407e84cdSMauro Carvalho Chehabpossible with the :c:func:`munmap()` function.
5554f38fcaSMauro Carvalho Chehab
5654f38fcaSMauro Carvalho ChehabExample: Mapping buffers in the single-planar API
5754f38fcaSMauro Carvalho Chehab=================================================
5854f38fcaSMauro Carvalho Chehab
5954f38fcaSMauro Carvalho Chehab.. code-block:: c
6054f38fcaSMauro Carvalho Chehab
6154f38fcaSMauro Carvalho Chehab    struct v4l2_requestbuffers reqbuf;
6254f38fcaSMauro Carvalho Chehab    struct {
6354f38fcaSMauro Carvalho Chehab	void *start;
6454f38fcaSMauro Carvalho Chehab	size_t length;
6554f38fcaSMauro Carvalho Chehab    } *buffers;
6654f38fcaSMauro Carvalho Chehab    unsigned int i;
6754f38fcaSMauro Carvalho Chehab
6854f38fcaSMauro Carvalho Chehab    memset(&reqbuf, 0, sizeof(reqbuf));
6954f38fcaSMauro Carvalho Chehab    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
7054f38fcaSMauro Carvalho Chehab    reqbuf.memory = V4L2_MEMORY_MMAP;
7154f38fcaSMauro Carvalho Chehab    reqbuf.count = 20;
7254f38fcaSMauro Carvalho Chehab
7354f38fcaSMauro Carvalho Chehab    if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf)) {
7454f38fcaSMauro Carvalho Chehab	if (errno == EINVAL)
7554f38fcaSMauro Carvalho Chehab	    printf("Video capturing or mmap-streaming is not supported\\n");
7654f38fcaSMauro Carvalho Chehab	else
7754f38fcaSMauro Carvalho Chehab	    perror("VIDIOC_REQBUFS");
7854f38fcaSMauro Carvalho Chehab
7954f38fcaSMauro Carvalho Chehab	exit(EXIT_FAILURE);
8054f38fcaSMauro Carvalho Chehab    }
8154f38fcaSMauro Carvalho Chehab
8254f38fcaSMauro Carvalho Chehab    /* We want at least five buffers. */
8354f38fcaSMauro Carvalho Chehab
8454f38fcaSMauro Carvalho Chehab    if (reqbuf.count < 5) {
8554f38fcaSMauro Carvalho Chehab	/* You may need to free the buffers here. */
8654f38fcaSMauro Carvalho Chehab	printf("Not enough buffer memory\\n");
8754f38fcaSMauro Carvalho Chehab	exit(EXIT_FAILURE);
8854f38fcaSMauro Carvalho Chehab    }
8954f38fcaSMauro Carvalho Chehab
9054f38fcaSMauro Carvalho Chehab    buffers = calloc(reqbuf.count, sizeof(*buffers));
9154f38fcaSMauro Carvalho Chehab    assert(buffers != NULL);
9254f38fcaSMauro Carvalho Chehab
9354f38fcaSMauro Carvalho Chehab    for (i = 0; i < reqbuf.count; i++) {
9454f38fcaSMauro Carvalho Chehab	struct v4l2_buffer buffer;
9554f38fcaSMauro Carvalho Chehab
9654f38fcaSMauro Carvalho Chehab	memset(&buffer, 0, sizeof(buffer));
9754f38fcaSMauro Carvalho Chehab	buffer.type = reqbuf.type;
9854f38fcaSMauro Carvalho Chehab	buffer.memory = V4L2_MEMORY_MMAP;
9954f38fcaSMauro Carvalho Chehab	buffer.index = i;
10054f38fcaSMauro Carvalho Chehab
10154f38fcaSMauro Carvalho Chehab	if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buffer)) {
10254f38fcaSMauro Carvalho Chehab	    perror("VIDIOC_QUERYBUF");
10354f38fcaSMauro Carvalho Chehab	    exit(EXIT_FAILURE);
10454f38fcaSMauro Carvalho Chehab	}
10554f38fcaSMauro Carvalho Chehab
10654f38fcaSMauro Carvalho Chehab	buffers[i].length = buffer.length; /* remember for munmap() */
10754f38fcaSMauro Carvalho Chehab
10854f38fcaSMauro Carvalho Chehab	buffers[i].start = mmap(NULL, buffer.length,
10954f38fcaSMauro Carvalho Chehab		    PROT_READ | PROT_WRITE, /* recommended */
11054f38fcaSMauro Carvalho Chehab		    MAP_SHARED,             /* recommended */
11154f38fcaSMauro Carvalho Chehab		    fd, buffer.m.offset);
11254f38fcaSMauro Carvalho Chehab
11354f38fcaSMauro Carvalho Chehab	if (MAP_FAILED == buffers[i].start) {
11454f38fcaSMauro Carvalho Chehab	    /* If you do not exit here you should unmap() and free()
11554f38fcaSMauro Carvalho Chehab	       the buffers mapped so far. */
11654f38fcaSMauro Carvalho Chehab	    perror("mmap");
11754f38fcaSMauro Carvalho Chehab	    exit(EXIT_FAILURE);
11854f38fcaSMauro Carvalho Chehab	}
11954f38fcaSMauro Carvalho Chehab    }
12054f38fcaSMauro Carvalho Chehab
12154f38fcaSMauro Carvalho Chehab    /* Cleanup. */
12254f38fcaSMauro Carvalho Chehab
12354f38fcaSMauro Carvalho Chehab    for (i = 0; i < reqbuf.count; i++)
12454f38fcaSMauro Carvalho Chehab	munmap(buffers[i].start, buffers[i].length);
12554f38fcaSMauro Carvalho Chehab
12654f38fcaSMauro Carvalho ChehabExample: Mapping buffers in the multi-planar API
12754f38fcaSMauro Carvalho Chehab================================================
12854f38fcaSMauro Carvalho Chehab
12954f38fcaSMauro Carvalho Chehab.. code-block:: c
13054f38fcaSMauro Carvalho Chehab
13154f38fcaSMauro Carvalho Chehab    struct v4l2_requestbuffers reqbuf;
13254f38fcaSMauro Carvalho Chehab    /* Our current format uses 3 planes per buffer */
13354f38fcaSMauro Carvalho Chehab    #define FMT_NUM_PLANES = 3
13454f38fcaSMauro Carvalho Chehab
13554f38fcaSMauro Carvalho Chehab    struct {
13654f38fcaSMauro Carvalho Chehab	void *start[FMT_NUM_PLANES];
13754f38fcaSMauro Carvalho Chehab	size_t length[FMT_NUM_PLANES];
13854f38fcaSMauro Carvalho Chehab    } *buffers;
13954f38fcaSMauro Carvalho Chehab    unsigned int i, j;
14054f38fcaSMauro Carvalho Chehab
14154f38fcaSMauro Carvalho Chehab    memset(&reqbuf, 0, sizeof(reqbuf));
14254f38fcaSMauro Carvalho Chehab    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
14354f38fcaSMauro Carvalho Chehab    reqbuf.memory = V4L2_MEMORY_MMAP;
14454f38fcaSMauro Carvalho Chehab    reqbuf.count = 20;
14554f38fcaSMauro Carvalho Chehab
14654f38fcaSMauro Carvalho Chehab    if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
14754f38fcaSMauro Carvalho Chehab	if (errno == EINVAL)
14854f38fcaSMauro Carvalho Chehab	    printf("Video capturing or mmap-streaming is not supported\\n");
14954f38fcaSMauro Carvalho Chehab	else
15054f38fcaSMauro Carvalho Chehab	    perror("VIDIOC_REQBUFS");
15154f38fcaSMauro Carvalho Chehab
15254f38fcaSMauro Carvalho Chehab	exit(EXIT_FAILURE);
15354f38fcaSMauro Carvalho Chehab    }
15454f38fcaSMauro Carvalho Chehab
15554f38fcaSMauro Carvalho Chehab    /* We want at least five buffers. */
15654f38fcaSMauro Carvalho Chehab
15754f38fcaSMauro Carvalho Chehab    if (reqbuf.count < 5) {
15854f38fcaSMauro Carvalho Chehab	/* You may need to free the buffers here. */
15954f38fcaSMauro Carvalho Chehab	printf("Not enough buffer memory\\n");
16054f38fcaSMauro Carvalho Chehab	exit(EXIT_FAILURE);
16154f38fcaSMauro Carvalho Chehab    }
16254f38fcaSMauro Carvalho Chehab
16354f38fcaSMauro Carvalho Chehab    buffers = calloc(reqbuf.count, sizeof(*buffers));
16454f38fcaSMauro Carvalho Chehab    assert(buffers != NULL);
16554f38fcaSMauro Carvalho Chehab
16654f38fcaSMauro Carvalho Chehab    for (i = 0; i < reqbuf.count; i++) {
16754f38fcaSMauro Carvalho Chehab	struct v4l2_buffer buffer;
16854f38fcaSMauro Carvalho Chehab	struct v4l2_plane planes[FMT_NUM_PLANES];
16954f38fcaSMauro Carvalho Chehab
17054f38fcaSMauro Carvalho Chehab	memset(&buffer, 0, sizeof(buffer));
17154f38fcaSMauro Carvalho Chehab	buffer.type = reqbuf.type;
17254f38fcaSMauro Carvalho Chehab	buffer.memory = V4L2_MEMORY_MMAP;
17354f38fcaSMauro Carvalho Chehab	buffer.index = i;
17454f38fcaSMauro Carvalho Chehab	/* length in struct v4l2_buffer in multi-planar API stores the size
17554f38fcaSMauro Carvalho Chehab	 * of planes array. */
17654f38fcaSMauro Carvalho Chehab	buffer.length = FMT_NUM_PLANES;
17754f38fcaSMauro Carvalho Chehab	buffer.m.planes = planes;
17854f38fcaSMauro Carvalho Chehab
17954f38fcaSMauro Carvalho Chehab	if (ioctl(fd, VIDIOC_QUERYBUF, &buffer) < 0) {
18054f38fcaSMauro Carvalho Chehab	    perror("VIDIOC_QUERYBUF");
18154f38fcaSMauro Carvalho Chehab	    exit(EXIT_FAILURE);
18254f38fcaSMauro Carvalho Chehab	}
18354f38fcaSMauro Carvalho Chehab
18454f38fcaSMauro Carvalho Chehab	/* Every plane has to be mapped separately */
18554f38fcaSMauro Carvalho Chehab	for (j = 0; j < FMT_NUM_PLANES; j++) {
18654f38fcaSMauro Carvalho Chehab	    buffers[i].length[j] = buffer.m.planes[j].length; /* remember for munmap() */
18754f38fcaSMauro Carvalho Chehab
18854f38fcaSMauro Carvalho Chehab	    buffers[i].start[j] = mmap(NULL, buffer.m.planes[j].length,
18954f38fcaSMauro Carvalho Chehab		     PROT_READ | PROT_WRITE, /* recommended */
19054f38fcaSMauro Carvalho Chehab		     MAP_SHARED,             /* recommended */
19154f38fcaSMauro Carvalho Chehab		     fd, buffer.m.planes[j].m.offset);
19254f38fcaSMauro Carvalho Chehab
19354f38fcaSMauro Carvalho Chehab	    if (MAP_FAILED == buffers[i].start[j]) {
19454f38fcaSMauro Carvalho Chehab		/* If you do not exit here you should unmap() and free()
19554f38fcaSMauro Carvalho Chehab		   the buffers and planes mapped so far. */
19654f38fcaSMauro Carvalho Chehab		perror("mmap");
19754f38fcaSMauro Carvalho Chehab		exit(EXIT_FAILURE);
19854f38fcaSMauro Carvalho Chehab	    }
19954f38fcaSMauro Carvalho Chehab	}
20054f38fcaSMauro Carvalho Chehab    }
20154f38fcaSMauro Carvalho Chehab
20254f38fcaSMauro Carvalho Chehab    /* Cleanup. */
20354f38fcaSMauro Carvalho Chehab
20454f38fcaSMauro Carvalho Chehab    for (i = 0; i < reqbuf.count; i++)
20554f38fcaSMauro Carvalho Chehab	for (j = 0; j < FMT_NUM_PLANES; j++)
20654f38fcaSMauro Carvalho Chehab	    munmap(buffers[i].start[j], buffers[i].length[j]);
20754f38fcaSMauro Carvalho Chehab
20854f38fcaSMauro Carvalho ChehabConceptually streaming drivers maintain two buffer queues, an incoming
20954f38fcaSMauro Carvalho Chehaband an outgoing queue. They separate the synchronous capture or output
21054f38fcaSMauro Carvalho Chehaboperation locked to a video clock from the application which is subject
21154f38fcaSMauro Carvalho Chehabto random disk or network delays and preemption by other processes,
21254f38fcaSMauro Carvalho Chehabthereby reducing the probability of data loss. The queues are organized
21354f38fcaSMauro Carvalho Chehabas FIFOs, buffers will be output in the order enqueued in the incoming
21454f38fcaSMauro Carvalho ChehabFIFO, and were captured in the order dequeued from the outgoing FIFO.
21554f38fcaSMauro Carvalho Chehab
21654f38fcaSMauro Carvalho ChehabThe driver may require a minimum number of buffers enqueued at all times
21754f38fcaSMauro Carvalho Chehabto function, apart of this no limit exists on the number of buffers
21854f38fcaSMauro Carvalho Chehabapplications can enqueue in advance, or dequeue and process. They can
21954f38fcaSMauro Carvalho Chehabalso enqueue in a different order than buffers have been dequeued, and
22054f38fcaSMauro Carvalho Chehabthe driver can *fill* enqueued *empty* buffers in any order.  [#f2]_ The
22154f38fcaSMauro Carvalho Chehabindex number of a buffer (struct :c:type:`v4l2_buffer`
22254f38fcaSMauro Carvalho Chehab``index``) plays no role here, it only identifies the buffer.
22354f38fcaSMauro Carvalho Chehab
22454f38fcaSMauro Carvalho ChehabInitially all mapped buffers are in dequeued state, inaccessible by the
22554f38fcaSMauro Carvalho Chehabdriver. For capturing applications it is customary to first enqueue all
22654f38fcaSMauro Carvalho Chehabmapped buffers, then to start capturing and enter the read loop. Here
22754f38fcaSMauro Carvalho Chehabthe application waits until a filled buffer can be dequeued, and
22854f38fcaSMauro Carvalho Chehabre-enqueues the buffer when the data is no longer needed. Output
22954f38fcaSMauro Carvalho Chehabapplications fill and enqueue buffers, when enough buffers are stacked
23054f38fcaSMauro Carvalho Chehabup the output is started with :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`.
23154f38fcaSMauro Carvalho ChehabIn the write loop, when the application runs out of free buffers, it
23254f38fcaSMauro Carvalho Chehabmust wait until an empty buffer can be dequeued and reused.
23354f38fcaSMauro Carvalho Chehab
23454f38fcaSMauro Carvalho ChehabTo enqueue and dequeue a buffer applications use the
235*76a48e75SMarek Vasut:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
23654f38fcaSMauro Carvalho Chehabioctl. The status of a buffer being mapped, enqueued, full or empty can
23754f38fcaSMauro Carvalho Chehabbe determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two
23854f38fcaSMauro Carvalho Chehabmethods exist to suspend execution of the application until one or more
23954f38fcaSMauro Carvalho Chehabbuffers can be dequeued.  By default :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
24054f38fcaSMauro Carvalho Chehabblocks when no buffer is in the outgoing queue. When the ``O_NONBLOCK``
241407e84cdSMauro Carvalho Chehabflag was given to the :c:func:`open()` function,
24254f38fcaSMauro Carvalho Chehab:ref:`VIDIOC_DQBUF <VIDIOC_QBUF>` returns immediately with an ``EAGAIN``
243407e84cdSMauro Carvalho Chehaberror code when no buffer is available. The :c:func:`select()`
244407e84cdSMauro Carvalho Chehabor :c:func:`poll()` functions are always available.
24554f38fcaSMauro Carvalho Chehab
24654f38fcaSMauro Carvalho ChehabTo start and stop capturing or output applications call the
24754f38fcaSMauro Carvalho Chehab:ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>` and :ref:`VIDIOC_STREAMOFF
24854f38fcaSMauro Carvalho Chehab<VIDIOC_STREAMON>` ioctl.
24954f38fcaSMauro Carvalho Chehab
25054f38fcaSMauro Carvalho Chehab.. note:::ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>`
25154f38fcaSMauro Carvalho Chehab   removes all buffers from both queues as a side effect. Since there is
25254f38fcaSMauro Carvalho Chehab   no notion of doing anything "now" on a multitasking system, if an
25354f38fcaSMauro Carvalho Chehab   application needs to synchronize with another event it should examine
25454f38fcaSMauro Carvalho Chehab   the struct ::c:type:`v4l2_buffer` ``timestamp`` of captured
25554f38fcaSMauro Carvalho Chehab   or outputted buffers.
25654f38fcaSMauro Carvalho Chehab
25754f38fcaSMauro Carvalho ChehabDrivers implementing memory mapping I/O must support the
25854f38fcaSMauro Carvalho Chehab:ref:`VIDIOC_REQBUFS <VIDIOC_REQBUFS>`, :ref:`VIDIOC_QUERYBUF
25954f38fcaSMauro Carvalho Chehab<VIDIOC_QUERYBUF>`, :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`, :ref:`VIDIOC_DQBUF
26054f38fcaSMauro Carvalho Chehab<VIDIOC_QBUF>`, :ref:`VIDIOC_STREAMON <VIDIOC_STREAMON>`
26154f38fcaSMauro Carvalho Chehaband :ref:`VIDIOC_STREAMOFF <VIDIOC_STREAMON>` ioctls, the :ref:`mmap()
262407e84cdSMauro Carvalho Chehab<func-mmap>`, :c:func:`munmap()`, :ref:`select()
263407e84cdSMauro Carvalho Chehab<func-select>` and :c:func:`poll()` function. [#f3]_
26454f38fcaSMauro Carvalho Chehab
26554f38fcaSMauro Carvalho Chehab[capture example]
26654f38fcaSMauro Carvalho Chehab
26754f38fcaSMauro Carvalho Chehab.. [#f1]
26854f38fcaSMauro Carvalho Chehab   One could use one file descriptor and set the buffer type field
26954f38fcaSMauro Carvalho Chehab   accordingly when calling :ref:`VIDIOC_QBUF` etc.,
270407e84cdSMauro Carvalho Chehab   but it makes the :c:func:`select()` function ambiguous. We also
27154f38fcaSMauro Carvalho Chehab   like the clean approach of one file descriptor per logical stream.
27254f38fcaSMauro Carvalho Chehab   Video overlay for example is also a logical stream, although the CPU
27354f38fcaSMauro Carvalho Chehab   is not needed for continuous operation.
27454f38fcaSMauro Carvalho Chehab
27554f38fcaSMauro Carvalho Chehab.. [#f2]
27654f38fcaSMauro Carvalho Chehab   Random enqueue order permits applications processing images out of
27754f38fcaSMauro Carvalho Chehab   order (such as video codecs) to return buffers earlier, reducing the
27854f38fcaSMauro Carvalho Chehab   probability of data loss. Random fill order allows drivers to reuse
27954f38fcaSMauro Carvalho Chehab   buffers on a LIFO-basis, taking advantage of caches holding
28054f38fcaSMauro Carvalho Chehab   scatter-gather lists and the like.
28154f38fcaSMauro Carvalho Chehab
28254f38fcaSMauro Carvalho Chehab.. [#f3]
283407e84cdSMauro Carvalho Chehab   At the driver level :c:func:`select()` and :c:func:`poll()` are
284407e84cdSMauro Carvalho Chehab   the same, and :c:func:`select()` is too important to be optional.
28554f38fcaSMauro Carvalho Chehab   The rest should be evident.
286