123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730 |
- =======================
- The Userspace I/O HOWTO
- =======================
- :Author: Hans-Jürgen Koch Linux developer, Linutronix
- :Date: 2006-12-11
- About this document
- ===================
- Translations
- If you know of any translations for this document, or you are interested
- in translating it, please email me hjk@hansjkoch.de.
- Preface
- For many types of devices, creating a Linux kernel driver is overkill.
- All that is really needed is some way to handle an interrupt and provide
- access to the memory space of the device. The logic of controlling the
- device does not necessarily have to be within the kernel, as the device
- does not need to take advantage of any of other resources that the
- kernel provides. One such common class of devices that are like this are
- for industrial I/O cards.
- To address this situation, the userspace I/O system (UIO) was designed.
- For typical industrial I/O cards, only a very small kernel module is
- needed. The main part of the driver will run in user space. This
- simplifies development and reduces the risk of serious bugs within a
- kernel module.
- Please note that UIO is not an universal driver interface. Devices that
- are already handled well by other kernel subsystems (like networking or
- serial or USB) are no candidates for an UIO driver. Hardware that is
- ideally suited for an UIO driver fulfills all of the following:
- - The device has memory that can be mapped. The device can be
- controlled completely by writing to this memory.
- - The device usually generates interrupts.
- - The device does not fit into one of the standard kernel subsystems.
- Acknowledgments
- I'd like to thank Thomas Gleixner and Benedikt Spranger of Linutronix,
- who have not only written most of the UIO code, but also helped greatly
- writing this HOWTO by giving me all kinds of background information.
- Feedback
- Find something wrong with this document? (Or perhaps something right?) I
- would love to hear from you. Please email me at hjk@hansjkoch.de.
- About UIO
- =========
- If you use UIO for your card's driver, here's what you get:
- - only one small kernel module to write and maintain.
- - develop the main part of your driver in user space, with all the
- tools and libraries you're used to.
- - bugs in your driver won't crash the kernel.
- - updates of your driver can take place without recompiling the kernel.
- How UIO works
- Each UIO device is accessed through a device file and several sysfs
- attribute files. The device file will be called ``/dev/uio0`` for the
- first device, and ``/dev/uio1``, ``/dev/uio2`` and so on for subsequent
- devices.
- ``/dev/uioX`` is used to access the address space of the card. Just use
- :c:func:`mmap()` to access registers or RAM locations of your card.
- Interrupts are handled by reading from ``/dev/uioX``. A blocking
- :c:func:`read()` from ``/dev/uioX`` will return as soon as an
- interrupt occurs. You can also use :c:func:`select()` on
- ``/dev/uioX`` to wait for an interrupt. The integer value read from
- ``/dev/uioX`` represents the total interrupt count. You can use this
- number to figure out if you missed some interrupts.
- For some hardware that has more than one interrupt source internally,
- but not separate IRQ mask and status registers, there might be
- situations where userspace cannot determine what the interrupt source
- was if the kernel handler disables them by writing to the chip's IRQ
- register. In such a case, the kernel has to disable the IRQ completely
- to leave the chip's register untouched. Now the userspace part can
- determine the cause of the interrupt, but it cannot re-enable
- interrupts. Another cornercase is chips where re-enabling interrupts is
- a read-modify-write operation to a combined IRQ status/acknowledge
- register. This would be racy if a new interrupt occurred simultaneously.
- To address these problems, UIO also implements a write() function. It is
- normally not used and can be ignored for hardware that has only a single
- interrupt source or has separate IRQ mask and status registers. If you
- need it, however, a write to ``/dev/uioX`` will call the
- :c:func:`irqcontrol()` function implemented by the driver. You have
- to write a 32-bit value that is usually either 0 or 1 to disable or
- enable interrupts. If a driver does not implement
- :c:func:`irqcontrol()`, :c:func:`write()` will return with
- ``-ENOSYS``.
- To handle interrupts properly, your custom kernel module can provide its
- own interrupt handler. It will automatically be called by the built-in
- handler.
- For cards that don't generate interrupts but need to be polled, there is
- the possibility to set up a timer that triggers the interrupt handler at
- configurable time intervals. This interrupt simulation is done by
- calling :c:func:`uio_event_notify()` from the timer's event
- handler.
- Each driver provides attributes that are used to read or write
- variables. These attributes are accessible through sysfs files. A custom
- kernel driver module can add its own attributes to the device owned by
- the uio driver, but not added to the UIO device itself at this time.
- This might change in the future if it would be found to be useful.
- The following standard attributes are provided by the UIO framework:
- - ``name``: The name of your device. It is recommended to use the name
- of your kernel module for this.
- - ``version``: A version string defined by your driver. This allows the
- user space part of your driver to deal with different versions of the
- kernel module.
- - ``event``: The total number of interrupts handled by the driver since
- the last time the device node was read.
- These attributes appear under the ``/sys/class/uio/uioX`` directory.
- Please note that this directory might be a symlink, and not a real
- directory. Any userspace code that accesses it must be able to handle
- this.
- Each UIO device can make one or more memory regions available for memory
- mapping. This is necessary because some industrial I/O cards require
- access to more than one PCI memory region in a driver.
- Each mapping has its own directory in sysfs, the first mapping appears
- as ``/sys/class/uio/uioX/maps/map0/``. Subsequent mappings create
- directories ``map1/``, ``map2/``, and so on. These directories will only
- appear if the size of the mapping is not 0.
- Each ``mapX/`` directory contains four read-only files that show
- attributes of the memory:
- - ``name``: A string identifier for this mapping. This is optional, the
- string can be empty. Drivers can set this to make it easier for
- userspace to find the correct mapping.
- - ``addr``: The address of memory that can be mapped.
- - ``size``: The size, in bytes, of the memory pointed to by addr.
- - ``offset``: The offset, in bytes, that has to be added to the pointer
- returned by :c:func:`mmap()` to get to the actual device memory.
- This is important if the device's memory is not page aligned.
- Remember that pointers returned by :c:func:`mmap()` are always
- page aligned, so it is good style to always add this offset.
- From userspace, the different mappings are distinguished by adjusting
- the ``offset`` parameter of the :c:func:`mmap()` call. To map the
- memory of mapping N, you have to use N times the page size as your
- offset::
- offset = N * getpagesize();
- Sometimes there is hardware with memory-like regions that can not be
- mapped with the technique described here, but there are still ways to
- access them from userspace. The most common example are x86 ioports. On
- x86 systems, userspace can access these ioports using
- :c:func:`ioperm()`, :c:func:`iopl()`, :c:func:`inb()`,
- :c:func:`outb()`, and similar functions.
- Since these ioport regions can not be mapped, they will not appear under
- ``/sys/class/uio/uioX/maps/`` like the normal memory described above.
- Without information about the port regions a hardware has to offer, it
- becomes difficult for the userspace part of the driver to find out which
- ports belong to which UIO device.
- To address this situation, the new directory
- ``/sys/class/uio/uioX/portio/`` was added. It only exists if the driver
- wants to pass information about one or more port regions to userspace.
- If that is the case, subdirectories named ``port0``, ``port1``, and so
- on, will appear underneath ``/sys/class/uio/uioX/portio/``.
- Each ``portX/`` directory contains four read-only files that show name,
- start, size, and type of the port region:
- - ``name``: A string identifier for this port region. The string is
- optional and can be empty. Drivers can set it to make it easier for
- userspace to find a certain port region.
- - ``start``: The first port of this region.
- - ``size``: The number of ports in this region.
- - ``porttype``: A string describing the type of port.
- Writing your own kernel module
- ==============================
- Please have a look at ``uio_cif.c`` as an example. The following
- paragraphs explain the different sections of this file.
- struct uio_info
- This structure tells the framework the details of your driver, Some of
- the members are required, others are optional.
- - ``const char *name``: Required. The name of your driver as it will
- appear in sysfs. I recommend using the name of your module for this.
- - ``const char *version``: Required. This string appears in
- ``/sys/class/uio/uioX/version``.
- - ``struct uio_mem mem[ MAX_UIO_MAPS ]``: Required if you have memory
- that can be mapped with :c:func:`mmap()`. For each mapping you
- need to fill one of the ``uio_mem`` structures. See the description
- below for details.
- - ``struct uio_port port[ MAX_UIO_PORTS_REGIONS ]``: Required if you
- want to pass information about ioports to userspace. For each port
- region you need to fill one of the ``uio_port`` structures. See the
- description below for details.
- - ``long irq``: Required. If your hardware generates an interrupt, it's
- your modules task to determine the irq number during initialization.
- If you don't have a hardware generated interrupt but want to trigger
- the interrupt handler in some other way, set ``irq`` to
- ``UIO_IRQ_CUSTOM``. If you had no interrupt at all, you could set
- ``irq`` to ``UIO_IRQ_NONE``, though this rarely makes sense.
- - ``unsigned long irq_flags``: Required if you've set ``irq`` to a
- hardware interrupt number. The flags given here will be used in the
- call to :c:func:`request_irq()`.
- - ``int
|