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