doc: convert UIO howto from docbook to sphinx
authorAlexander Dahl <post@lespocky.de>
Sat, 28 Jan 2017 09:45:32 +0000 (10:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 31 Jan 2017 10:12:41 +0000 (11:12 +0100)
Converted with tmplcvt. Only some tiny things needed manual fixing.

Signed-off-by: Alexander Dahl <post@lespocky.de>
Cc: Hans-Jürgen Koch <hjk@hansjkoch.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/DocBook/Makefile
Documentation/DocBook/uio-howto.tmpl [deleted file]
Documentation/driver-api/index.rst
Documentation/driver-api/uio-howto.rst [new file with mode: 0644]
MAINTAINERS

index a6eb7dcd4dd5c010fe76ac285769d9e0c5157adc..5fd8f5effd0c59b06d0dccec9bade44c8d6395a2 100644 (file)
@@ -11,7 +11,7 @@ DOCBOOKS := z8530book.xml  \
            writing_usb_driver.xml networking.xml \
            kernel-api.xml filesystems.xml lsm.xml kgdb.xml \
            gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
-           genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
+           genericirq.xml s390-drivers.xml scsi.xml \
            sh.xml regulator.xml w1.xml \
            writing_musb_glue_layer.xml iio.xml
 
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
deleted file mode 100644 (file)
index 5210f8a..0000000
+++ /dev/null
@@ -1,1112 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" []>
-
-<book id="index">
-<bookinfo>
-<title>The Userspace I/O HOWTO</title>
-
-<author>
-      <firstname>Hans-Jürgen</firstname>
-      <surname>Koch</surname>
-      <authorblurb><para>Linux developer, Linutronix</para></authorblurb>
-       <affiliation>
-       <orgname>
-               <ulink url="http://www.linutronix.de">Linutronix</ulink>
-       </orgname>
-
-       <address>
-          <email>hjk@hansjkoch.de</email>
-       </address>
-    </affiliation>
-</author>
-
-<copyright>
-       <year>2006-2008</year>
-       <holder>Hans-Jürgen Koch.</holder>
-</copyright>
-<copyright>
-       <year>2009</year>
-       <holder>Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)</holder>
-</copyright>
-
-<legalnotice>
-<para>
-This documentation is Free Software licensed under the terms of the
-GPL version 2.
-</para>
-</legalnotice>
-
-<pubdate>2006-12-11</pubdate>
-
-<abstract>
-       <para>This HOWTO describes concept and usage of Linux kernel's
-               Userspace I/O system.</para>
-</abstract>
-
-<revhistory>
-       <revision>
-       <revnumber>0.10</revnumber>
-       <date>2016-10-17</date>
-       <authorinitials>sch</authorinitials>
-       <revremark>Added generic hyperv driver
-               </revremark>
-       </revision>
-       <revision>
-       <revnumber>0.9</revnumber>
-       <date>2009-07-16</date>
-       <authorinitials>mst</authorinitials>
-       <revremark>Added generic pci driver
-               </revremark>
-       </revision>
-       <revision>
-       <revnumber>0.8</revnumber>
-       <date>2008-12-24</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>Added name attributes in mem and portio sysfs directories.
-               </revremark>
-       </revision>
-       <revision>
-       <revnumber>0.7</revnumber>
-       <date>2008-12-23</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>Added generic platform drivers and offset attribute.</revremark>
-       </revision>
-       <revision>
-       <revnumber>0.6</revnumber>
-       <date>2008-12-05</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>Added description of portio sysfs attributes.</revremark>
-       </revision>
-       <revision>
-       <revnumber>0.5</revnumber>
-       <date>2008-05-22</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>Added description of write() function.</revremark>
-       </revision>
-       <revision>
-       <revnumber>0.4</revnumber>
-       <date>2007-11-26</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>Removed section about uio_dummy.</revremark>
-       </revision>
-       <revision>
-       <revnumber>0.3</revnumber>
-       <date>2007-04-29</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>Added section about userspace drivers.</revremark>
-       </revision>
-       <revision>
-       <revnumber>0.2</revnumber>
-       <date>2007-02-13</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>Update after multiple mappings were added.</revremark>
-       </revision>
-       <revision>
-       <revnumber>0.1</revnumber>
-       <date>2006-12-11</date>
-       <authorinitials>hjk</authorinitials>
-       <revremark>First draft.</revremark>
-       </revision>
-</revhistory>
-</bookinfo>
-
-<chapter id="aboutthisdoc">
-<?dbhtml filename="aboutthis.html"?>
-<title>About this document</title>
-
-<sect1 id="translations">
-<?dbhtml filename="translations.html"?>
-<title>Translations</title>
-
-<para>If you know of any translations for this document, or you are
-interested in translating it, please email me
-<email>hjk@hansjkoch.de</email>.
-</para>
-</sect1>
-
-<sect1 id="preface">
-<title>Preface</title>
-       <para>
-       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.
-       </para>
-       <para>
-       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.
-       </para>
-       <para>
-       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:
-       </para>
-<itemizedlist>
-<listitem>
-       <para>The device has memory that can be mapped. The device can be
-       controlled completely by writing to this memory.</para>
-</listitem>
-<listitem>
-       <para>The device usually generates interrupts.</para>
-</listitem>
-<listitem>
-       <para>The device does not fit into one of the standard kernel
-       subsystems.</para>
-</listitem>
-</itemizedlist>
-</sect1>
-
-<sect1 id="thanks">
-<title>Acknowledgments</title>
-       <para>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.</para>
-</sect1>
-
-<sect1 id="feedback">
-<title>Feedback</title>
-       <para>Find something wrong with this document? (Or perhaps something
-       right?) I would love to hear from you. Please email me at
-       <email>hjk@hansjkoch.de</email>.</para>
-</sect1>
-</chapter>
-
-<chapter id="about">
-<?dbhtml filename="about.html"?>
-<title>About UIO</title>
-
-<para>If you use UIO for your card's driver, here's what you get:</para>
-
-<itemizedlist>
-<listitem>
-       <para>only one small kernel module to write and maintain.</para>
-</listitem>
-<listitem>
-       <para>develop the main part of your driver in user space,
-       with all the tools and libraries you're used to.</para>
-</listitem>
-<listitem>
-       <para>bugs in your driver won't crash the kernel.</para>
-</listitem>
-<listitem>
-       <para>updates of your driver can take place without recompiling
-       the kernel.</para>
-</listitem>
-</itemizedlist>
-
-<sect1 id="how_uio_works">
-<title>How UIO works</title>
-       <para>
-       Each UIO device is accessed through a device file and several
-       sysfs attribute files. The device file will be called
-       <filename>/dev/uio0</filename> for the first device, and
-       <filename>/dev/uio1</filename>, <filename>/dev/uio2</filename>
-       and so on for subsequent devices.
-       </para>
-
-       <para><filename>/dev/uioX</filename> is used to access the
-       address space of the card. Just use
-       <function>mmap()</function> to access registers or RAM
-       locations of your card.
-       </para>
-
-       <para>
-       Interrupts are handled by reading from
-       <filename>/dev/uioX</filename>. A blocking
-       <function>read()</function> from
-       <filename>/dev/uioX</filename> will return as soon as an
-       interrupt occurs. You can also use
-       <function>select()</function> on
-       <filename>/dev/uioX</filename> to wait for an interrupt. The
-       integer value read from <filename>/dev/uioX</filename>
-       represents the total interrupt count. You can use this number
-       to figure out if you missed some interrupts.
-       </para>
-       <para>
-       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.
-       </para>
-       <para>
-       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 <filename>/dev/uioX</filename>
-       will call the <function>irqcontrol()</function> 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
-       <function>irqcontrol()</function>, <function>write()</function> will
-       return with <varname>-ENOSYS</varname>.
-       </para>
-
-       <para>
-       To handle interrupts properly, your custom kernel module can
-       provide its own interrupt handler. It will automatically be
-       called by the built-in handler.
-       </para>
-
-       <para>
-       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
-       <function>uio_event_notify()</function>
-       from the timer's event handler.
-       </para>
-
-       <para>
-       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.
-       </para>
-
-       <para>
-       The following standard attributes are provided by the UIO
-       framework:
-       </para>
-<itemizedlist>
-<listitem>
-       <para>
-       <filename>name</filename>: The name of your device. It is
-       recommended to use the name of your kernel module for this.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>version</filename>: 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.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>event</filename>: The total number of interrupts
-       handled by the driver since the last time the device node was
-       read.
-       </para>
-</listitem>
-</itemizedlist>
-<para>
-       These attributes appear under the
-       <filename>/sys/class/uio/uioX</filename> 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.
-</para>
-<para>
-       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.
-</para>
-<para>
-       Each mapping has its own directory in sysfs, the first mapping
-       appears as <filename>/sys/class/uio/uioX/maps/map0/</filename>.
-       Subsequent mappings create directories <filename>map1/</filename>,
-       <filename>map2/</filename>, and so on. These directories will only
-       appear if the size of the mapping is not 0.
-</para>
-<para>
-       Each <filename>mapX/</filename> directory contains four read-only files
-       that show attributes of the memory:
-</para>
-<itemizedlist>
-<listitem>
-       <para>
-       <filename>name</filename>: 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.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>addr</filename>: The address of memory that can be mapped.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>size</filename>: The size, in bytes, of the memory
-       pointed to by addr.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>offset</filename>: The offset, in bytes, that has to be
-       added to the pointer returned by <function>mmap()</function> to get
-       to the actual device memory. This is important if the device's memory
-       is not page aligned. Remember that pointers returned by
-       <function>mmap()</function> are always page aligned, so it is good
-       style to always add this offset.
-       </para>
-</listitem>
-</itemizedlist>
-
-<para>
-       From userspace, the different mappings are distinguished by adjusting
-       the <varname>offset</varname> parameter of the
-       <function>mmap()</function> call. To map the memory of mapping N, you
-       have to use N times the page size as your offset:
-</para>
-<programlisting format="linespecific">
-offset = N * getpagesize();
-</programlisting>
-
-<para>
-       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
-       <function>ioperm()</function>, <function>iopl()</function>,
-       <function>inb()</function>, <function>outb()</function>, and similar
-       functions.
-</para>
-<para>
-       Since these ioport regions can not be mapped, they will not appear under
-       <filename>/sys/class/uio/uioX/maps/</filename> 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.
-</para>
-<para>
-       To address this situation, the new directory
-       <filename>/sys/class/uio/uioX/portio/</filename> 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
-       <filename>port0</filename>, <filename>port1</filename>, and so on,
-       will appear underneath
-       <filename>/sys/class/uio/uioX/portio/</filename>.
-</para>
-<para>
-       Each <filename>portX/</filename> directory contains four read-only
-       files that show name, start, size, and type of the port region:
-</para>
-<itemizedlist>
-<listitem>
-       <para>
-       <filename>name</filename>: 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.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>start</filename>: The first port of this region.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>size</filename>: The number of ports in this region.
-       </para>
-</listitem>
-<listitem>
-       <para>
-       <filename>porttype</filename>: A string describing the type of port.
-       </para>
-</listitem>
-</itemizedlist>
-
-
-</sect1>
-</chapter>
-
-<chapter id="custom_kernel_module" xreflabel="Writing your own kernel module">
-<?dbhtml filename="custom_kernel_module.html"?>
-<title>Writing your own kernel module</title>
-       <para>
-       Please have a look at <filename>uio_cif.c</filename> as an
-       example. The following paragraphs explain the different
-       sections of this file.
-       </para>
-
-<sect1 id="uio_info">
-<title>struct uio_info</title>
-       <para>
-       This structure tells the framework the details of your driver,
-       Some of the members are required, others are optional.
-       </para>
-
-<itemizedlist>
-<listitem><para>
-<varname>const char *name</varname>: Required. The name of your driver as
-it will appear in sysfs. I recommend using the name of your module for this.
-</para></listitem>
-
-<listitem><para>
-<varname>const char *version</varname>: Required. This string appears in
-<filename>/sys/class/uio/uioX/version</filename>.
-</para></listitem>
-
-<listitem><para>
-<varname>struct uio_mem mem[ MAX_UIO_MAPS ]</varname>: Required if you
-have memory that can be mapped with <function>mmap()</function>. For each
-mapping you need to fill one of the <varname>uio_mem</varname> structures.
-See the description below for details.
-</para></listitem>
-
-<listitem><para>
-<varname>struct uio_port port[ MAX_UIO_PORTS_REGIONS ]</varname>: Required
-if you want to pass information about ioports to userspace. For each port
-region you need to fill one of the <varname>uio_port</varname> structures.
-See the description below for details.
-</para></listitem>
-
-<listitem><para>
-<varname>long irq</varname>: 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
-<varname>irq</varname> to <varname>UIO_IRQ_CUSTOM</varname>.
-If you had no interrupt at all, you could set
-<varname>irq</varname> to <varname>UIO_IRQ_NONE</varname>, though this
-rarely makes sense.
-</para></listitem>
-
-<listitem><para>
-<varname>unsigned long irq_flags</varname>: Required if you've set
-<varname>irq</varname> to a hardware interrupt number. The flags given
-here will be used in the call to <function>request_irq()</function>.
-</para></listitem>
-
-<listitem><para>
-<varname>int (*mmap)(struct uio_info *info, struct vm_area_struct
-*vma)</varname>: Optional. If you need a special
-<function>mmap()</function> function, you can set it here. If this
-pointer is not NULL, your <function>mmap()</function> will be called
-instead of the built-in one.
-</para></listitem>
-
-<listitem><para>
-<varname>int (*open)(struct uio_info *info, struct inode *inode)
-</varname>: Optional. You might want to have your own
-<function>open()</function>, e.g. to enable interrupts only when your
-device is actually used.
-</para></listitem>
-
-<listitem><para>
-<varname>int (*release)(struct uio_info *info, struct inode *inode)
-</varname>: Optional. If you define your own
-<function>open()</function>, you will probably also want a custom
-<function>release()</function> function.
-</para></listitem>
-
-<listitem><para>
-<varname>int (*irqcontrol)(struct uio_info *info, s32 irq_on)
-</varname>: Optional. If you need to be able to enable or disable
-interrupts from userspace by writing to <filename>/dev/uioX</filename>,
-you can implement this function. The parameter <varname>irq_on</varname>
-will be 0 to disable interrupts and 1 to enable them.
-</para></listitem>
-</itemizedlist>
-
-<para>
-Usually, your device will have one or more memory regions that can be mapped
-to user space. For each region, you have to set up a
-<varname>struct uio_mem</varname> in the <varname>mem[]</varname> array.
-Here's a description of the fields of <varname>struct uio_mem</varname>:
-</para>
-
-<itemizedlist>
-<listitem><para>
-<varname>const char *name</varname>: Optional. Set this to help identify
-the memory region, it will show up in the corresponding sysfs node.
-</para></listitem>
-
-<listitem><para>
-<varname>int memtype</varname>: Required if the mapping is used. Set this to
-<varname>UIO_MEM_PHYS</varname> if you you have physical memory on your
-card to be mapped. Use <varname>UIO_MEM_LOGICAL</varname> for logical
-memory (e.g. allocated with <function>kmalloc()</function>). There's also
-<varname>UIO_MEM_VIRTUAL</varname> for virtual memory.
-</para></listitem>
-
-<listitem><para>
-<varname>phys_addr_t addr</varname>: Required if the mapping is used.
-Fill in the address of your memory block. This address is the one that
-appears in sysfs.
-</para></listitem>
-
-<listitem><para>
-<varname>resource_size_t size</varname>: Fill in the size of the
-memory block that <varname>addr</varname> points to. If <varname>size</varname>
-is zero, the mapping is considered unused. Note that you
-<emphasis>must</emphasis> initialize <varname>size</varname> with zero for
-all unused mappings.
-</para></listitem>
-
-<listitem><para>
-<varname>void *internal_addr</varname>: If you have to access this memory
-region from within your kernel module, you will want to map it internally by
-using something like <function>ioremap()</function>. Addresses
-returned by this function cannot be mapped to user space, so you must not
-store it in <varname>addr</varname>. Use <varname>internal_addr</varname>
-instead to remember such an address.
-</para></listitem>
-</itemizedlist>
-
-<para>
-Please do not touch the <varname>map</varname> element of
-<varname>struct uio_mem</varname>! It is used by the UIO framework
-to set up sysfs files for this mapping. Simply leave it alone.
-</para>
-
-<para>
-Sometimes, your device can have one or more port regions which can not be
-mapped to userspace. But if there are other possibilities for userspace to
-access these ports, it makes sense to make information about the ports
-available in sysfs. For each region, you have to set up a
-<varname>struct uio_port</varname> in the <varname>port[]</varname> array.
-Here's a description of the fields of <varname>struct uio_port</varname>:
-</para>
-
-<itemizedlist>
-<listitem><para>
-<varname>char *porttype</varname>: Required. Set this to one of the predefined
-constants. Use <varname>UIO_PORT_X86</varname> for the ioports found in x86
-architectures.
-</para></listitem>
-
-<listitem><para>
-<varname>unsigned long start</varname>: Required if the port region is used.
-Fill in the number of the first port of this region.
-</para></listitem>
-
-<listitem><para>
-<varname>unsigned long size</varname>: Fill in the number of ports in this
-region. If <varname>size</varname> is zero, the region is considered unused.
-Note that you <emphasis>must</emphasis> initialize <varname>size</varname>
-with zero for all unused regions.
-</para></listitem>
-</itemizedlist>
-
-<para>
-Please do not touch the <varname>portio</varname> element of
-<varname>struct uio_port</varname>! It is used internally by the UIO
-framework to set up sysfs files for this region. Simply leave it alone.
-</para>
-
-</sect1>
-
-<sect1 id="adding_irq_handler">
-<title>Adding an interrupt handler</title>
-       <para>
-       What you need to do in your interrupt handler depends on your
-       hardware and on how you want to handle it. You should try to
-       keep the amount of code in your kernel interrupt handler low.
-       If your hardware requires no action that you
-       <emphasis>have</emphasis> to perform after each interrupt,
-       then your handler can be empty.</para> <para>If, on the other
-       hand, your hardware <emphasis>needs</emphasis> some action to
-       be performed after each interrupt, then you
-       <emphasis>must</emphasis> do it in your kernel module. Note
-       that you cannot rely on the userspace part of your driver. Your
-       userspace program can terminate at any time, possibly leaving
-       your hardware in a state where proper interrupt handling is
-       still required.
-       </para>
-
-       <para>
-       There might also be applications where you want to read data
-       from your hardware at each interrupt and buffer it in a piece
-       of kernel memory you've allocated for that purpose.  With this
-       technique you could avoid loss of data if your userspace
-       program misses an interrupt.
-       </para>
-
-       <para>
-       A note on shared interrupts: Your driver should support
-       interrupt sharing whenever this is possible. It is possible if
-       and only if your driver can detect whether your hardware has
-       triggered the interrupt or not. This is usually done by looking
-       at an interrupt status register. If your driver sees that the
-       IRQ bit is actually set, it will perform its actions, and the
-       handler returns IRQ_HANDLED. If the driver detects that it was
-       not your hardware that caused the interrupt, it will do nothing
-       and return IRQ_NONE, allowing the kernel to call the next
-       possible interrupt handler.
-       </para>
-
-       <para>
-       If you decide not to support shared interrupts, your card
-       won't work in computers with no free interrupts. As this
-       frequently happens on the PC platform, you can save yourself a
-       lot of trouble by supporting interrupt sharing.
-       </para>
-</sect1>
-
-<sect1 id="using_uio_pdrv">
-<title>Using uio_pdrv for platform devices</title>
-       <para>
-       In many cases, UIO drivers for platform devices can be handled in a
-       generic way. In the same place where you define your
-       <varname>struct platform_device</varname>, you simply also implement
-       your interrupt handler and fill your
-       <varname>struct uio_info</varname>. A pointer to this
-       <varname>struct uio_info</varname> is then used as
-       <varname>platform_data</varname> for your platform device.
-       </para>
-       <para>
-       You also need to set up an array of <varname>struct resource</varname>
-       containing addresses and sizes of your memory mappings. This
-       information is passed to the driver using the
-       <varname>.resource</varname> and <varname>.num_resources</varname>
-       elements of <varname>struct platform_device</varname>.
-       </para>
-       <para>
-       You now have to set the <varname>.name</varname> element of
-       <varname>struct platform_device</varname> to
-       <varname>"uio_pdrv"</varname> to use the generic UIO platform device
-       driver. This driver will fill the <varname>mem[]</varname> array
-       according to the resources given, and register the device.
-       </para>
-       <para>
-       The advantage of this approach is that you only have to edit a file
-       you need to edit anyway. You do not have to create an extra driver.
-       </para>
-</sect1>
-
-<sect1 id="using_uio_pdrv_genirq">
-<title>Using uio_pdrv_genirq for platform devices</title>
-       <para>
-       Especially in embedded devices, you frequently find chips where the
-       irq pin is tied to its own dedicated interrupt line. In such cases,
-       where you can be really sure the interrupt is not shared, we can take
-       the concept of <varname>uio_pdrv</varname> one step further and use a
-       generic interrupt handler. That's what
-       <varname>uio_pdrv_genirq</varname> does.
-       </para>
-       <para>
-       The setup for this driver is the same as described above for
-       <varname>uio_pdrv</varname>, except that you do not implement an
-       interrupt handler. The <varname>.handler</varname> element of
-       <varname>struct uio_info</varname> must remain
-       <varname>NULL</varname>. The  <varname>.irq_flags</varname> element
-       must not contain <varname>IRQF_SHARED</varname>.
-       </para>
-       <para>
-       You will set the <varname>.name</varname> element of
-       <varname>struct platform_device</varname> to
-       <varname>"uio_pdrv_genirq"</varname> to use this driver.
-       </para>
-       <para>
-       The generic interrupt handler of <varname>uio_pdrv_genirq</varname>
-       will simply disable the interrupt line using
-       <function>disable_irq_nosync()</function>. After doing its work,
-       userspace can reenable the interrupt by writing 0x00000001 to the UIO
-       device file. The driver already implements an
-       <function>irq_control()</function> to make this possible, you must not
-       implement your own.
-       </para>
-       <para>
-       Using <varname>uio_pdrv_genirq</varname> not only saves a few lines of
-       interrupt handler code. You also do not need to know anything about
-       the chip's internal registers to create the kernel part of the driver.
-       All you need to know is the irq number of the pin the chip is
-       connected to.
-       </para>
-</sect1>
-
-<sect1 id="using-uio_dmem_genirq">
-<title>Using uio_dmem_genirq for platform devices</title>
-       <para>
-       In addition to statically allocated memory ranges, they may also be
-       a desire to use dynamically allocated regions in a user space driver.
-       In particular, being able to access memory made available through the
-       dma-mapping API, may be particularly useful.  The
-       <varname>uio_dmem_genirq</varname> driver provides a way to accomplish
-       this.
-       </para>
-       <para>
-       This driver is used in a similar manner to the
-       <varname>"uio_pdrv_genirq"</varname> driver with respect to interrupt
-       configuration and handling.
-       </para>
-       <para>
-       Set the <varname>.name</varname> element of
-       <varname>struct platform_device</varname> to
-       <varname>"uio_dmem_genirq"</varname> to use this driver.
-       </para>
-       <para>
-       When using this driver, fill in the <varname>.platform_data</varname>
-       element of <varname>struct platform_device</varname>, which is of type
-       <varname>struct uio_dmem_genirq_pdata</varname> and which contains the
-       following elements:
-       </para>
-       <itemizedlist>
-       <listitem><para><varname>struct uio_info uioinfo</varname>: The same
-       structure used as the  <varname>uio_pdrv_genirq</varname> platform
-       data</para></listitem>
-       <listitem><para><varname>unsigned int *dynamic_region_sizes</varname>:
-       Pointer to list of sizes of dynamic memory regions to be mapped into
-       user space.
-       </para></listitem>
-       <listitem><para><varname>unsigned int num_dynamic_regions</varname>:
-       Number of elements in <varname>dynamic_region_sizes</varname> array.
-       </para></listitem>
-       </itemizedlist>
-       <para>
-       The dynamic regions defined in the platform data will be appended to
-       the <varname> mem[] </varname> array after the platform device
-       resources, which implies that the total number of static and dynamic
-       memory regions cannot exceed <varname>MAX_UIO_MAPS</varname>.
-       </para>
-       <para>
-       The dynamic memory regions will be allocated when the UIO device file,
-       <varname>/dev/uioX</varname> is opened.
-       Similar to static memory resources, the memory region information for
-       dynamic regions is then visible via sysfs at
-       <varname>/sys/class/uio/uioX/maps/mapY/*</varname>.
-       The dynamic memory regions will be freed when the UIO device file is
-       closed. When no processes are holding the device file open, the address
-       returned to userspace is ~0.
-       </para>
-</sect1>
-
-</chapter>
-
-<chapter id="userspace_driver" xreflabel="Writing a driver in user space">
-<?dbhtml filename="userspace_driver.html"?>
-<title>Writing a driver in userspace</title>
-       <para>
-       Once you have a working kernel module for your hardware, you can
-       write the userspace part of your driver. You don't need any special
-       libraries, your driver can be written in any reasonable language,
-       you can use floating point numbers and so on. In short, you can
-       use all the tools and libraries you'd normally use for writing a
-       userspace application.
-       </para>
-
-<sect1 id="getting_uio_information">
-<title>Getting information about your UIO device</title>
-       <para>
-       Information about all UIO devices is available in sysfs. The
-       first thing you should do in your driver is check
-       <varname>name</varname> and <varname>version</varname> to
-       make sure your talking to the right device and that its kernel
-       driver has the version you expect.
-       </para>
-       <para>
-       You should also make sure that the memory mapping you need
-       exists and has the size you expect.
-       </para>
-       <para>
-       There is a tool called <varname>lsuio</varname> that lists
-       UIO devices and their attributes. It is available here:
-       </para>
-       <para>
-       <ulink url="http://www.osadl.org/projects/downloads/UIO/user/">
-               http://www.osadl.org/projects/downloads/UIO/user/</ulink>
-       </para>
-       <para>
-       With <varname>lsuio</varname> you can quickly check if your
-       kernel module is loaded and which attributes it exports.
-       Have a look at the manpage for details.
-       </para>
-       <para>
-       The source code of <varname>lsuio</varname> can serve as an
-       example for getting information about an UIO device.
-       The file <filename>uio_helper.c</filename> contains a lot of
-       functions you could use in your userspace driver code.
-       </para>
-</sect1>
-
-<sect1 id="mmap_device_memory">
-<title>mmap() device memory</title>
-       <para>
-       After you made sure you've got the right device with the
-       memory mappings you need, all you have to do is to call
-       <function>mmap()</function> to map the device's memory
-       to userspace.
-       </para>
-       <para>
-       The parameter <varname>offset</varname> of the
-       <function>mmap()</function> call has a special meaning
-       for UIO devices: It is used to select which mapping of
-       your device you want to map. To map the memory of
-       mapping N, you have to use N times the page size as
-       your offset:
-       </para>
-<programlisting format="linespecific">
-       offset = N * getpagesize();
-</programlisting>
-       <para>
-       N starts from zero, so if you've got only one memory
-       range to map, set <varname>offset = 0</varname>.
-       A drawback of this technique is that memory is always
-       mapped beginning with its start address.
-       </para>
-</sect1>
-
-<sect1 id="wait_for_interrupts">
-<title>Waiting for interrupts</title>
-       <para>
-       After you successfully mapped your devices memory, you
-       can access it like an ordinary array. Usually, you will
-       perform some initialization. After that, your hardware
-       starts working and will generate an interrupt as soon
-       as it's finished, has some data available, or needs your
-       attention because an error occurred.
-       </para>
-       <para>
-       <filename>/dev/uioX</filename> is a read-only file. A
-       <function>read()</function> will always block until an
-       interrupt occurs. There is only one legal value for the
-       <varname>count</varname> parameter of
-       <function>read()</function>, and that is the size of a
-       signed 32 bit integer (4). Any other value for
-       <varname>count</varname> causes <function>read()</function>
-       to fail. The signed 32 bit integer read is the interrupt
-       count of your device. If the value is one more than the value
-       you read the last time, everything is OK. If the difference
-       is greater than one, you missed interrupts.
-       </para>
-       <para>
-       You can also use <function>select()</function> on
-       <filename>/dev/uioX</filename>.
-       </para>
-</sect1>
-
-</chapter>
-
-<chapter id="uio_pci_generic" xreflabel="Using Generic driver for PCI cards">
-<?dbhtml filename="uio_pci_generic.html"?>
-<title>Generic PCI UIO driver</title>
-       <para>
-       The generic driver is a kernel module named uio_pci_generic.
-       It can work with any device compliant to PCI 2.3 (circa 2002) and
-       any compliant PCI Express device. Using this, you only need to
-        write the userspace driver, removing the need to write
-        a hardware-specific kernel module.
-       </para>
-
-<sect1 id="uio_pci_generic_binding">
-<title>Making the driver recognize the device</title>
-       <para>
-Since the driver does not declare any device ids, it will not get loaded
-automatically and will not automatically bind to any devices, you must load it
-and allocate id to the driver yourself. For example:
-       <programlisting>
- modprobe uio_pci_generic
- echo &quot;8086 10f5&quot; &gt; /sys/bus/pci/drivers/uio_pci_generic/new_id
-       </programlisting>
-       </para>
-       <para>
-If there already is a hardware specific kernel driver for your device, the
-generic driver still won't bind to it, in this case if you want to use the
-generic driver (why would you?) you'll have to manually unbind the hardware
-specific driver and bind the generic driver, like this:
-       <programlisting>
-    echo -n 0000:00:19.0 &gt; /sys/bus/pci/drivers/e1000e/unbind
-    echo -n 0000:00:19.0 &gt; /sys/bus/pci/drivers/uio_pci_generic/bind
-       </programlisting>
-       </para>
-       <para>
-You can verify that the device has been bound to the driver
-by looking for it in sysfs, for example like the following:
-       <programlisting>
-    ls -l /sys/bus/pci/devices/0000:00:19.0/driver
-       </programlisting>
-Which if successful should print
-       <programlisting>
-  .../0000:00:19.0/driver -&gt; ../../../bus/pci/drivers/uio_pci_generic
-       </programlisting>
-Note that the generic driver will not bind to old PCI 2.2 devices.
-If binding the device failed, run the following command:
-       <programlisting>
-  dmesg
-       </programlisting>
-and look in the output for failure reasons
-       </para>
-</sect1>
-
-<sect1 id="uio_pci_generic_internals">
-<title>Things to know about uio_pci_generic</title>
-       <para>
-Interrupts are handled using the Interrupt Disable bit in the PCI command
-register and Interrupt Status bit in the PCI status register.  All devices
-compliant to PCI 2.3 (circa 2002) and all compliant PCI Express devices should
-support these bits.  uio_pci_generic detects this support, and won't bind to
-devices which do not support the Interrupt Disable Bit in the command register.
-       </para>
-       <para>
-On each interrupt, uio_pci_generic sets the Interrupt Disable bit.
-This prevents the device from generating further interrupts
-until the bit is cleared. The userspace driver should clear this
-bit before blocking and waiting for more interrupts.
-       </para>
-</sect1>
-<sect1 id="uio_pci_generic_userspace">
-<title>Writing userspace driver using uio_pci_generic</title>
-       <para>
-Userspace driver can use pci sysfs interface, or the
-libpci libray that wraps it, to talk to the device and to
-re-enable interrupts by writing to the command register.
-       </para>
-</sect1>
-<sect1 id="uio_pci_generic_example">
-<title>Example code using uio_pci_generic</title>
-       <para>
-Here is some sample userspace driver code using uio_pci_generic:
-<programlisting>
-#include &lt;stdlib.h&gt;
-#include &lt;stdio.h&gt;
-#include &lt;unistd.h&gt;
-#include &lt;sys/types.h&gt;
-#include &lt;sys/stat.h&gt;
-#include &lt;fcntl.h&gt;
-#include &lt;errno.h&gt;
-
-int main()
-{
-       int uiofd;
-       int configfd;
-       int err;
-       int i;
-       unsigned icount;
-       unsigned char command_high;
-
-       uiofd = open(&quot;/dev/uio0&quot;, O_RDONLY);
-       if (uiofd &lt; 0) {
-               perror(&quot;uio open:&quot;);
-               return errno;
-       }
-       configfd = open(&quot;/sys/class/uio/uio0/device/config&quot;, O_RDWR);
-       if (configfd &lt; 0) {
-               perror(&quot;config open:&quot;);
-               return errno;
-       }
-
-       /* Read and cache command value */
-       err = pread(configfd, &amp;command_high, 1, 5);
-       if (err != 1) {
-               perror(&quot;command config read:&quot;);
-               return errno;
-       }
-       command_high &amp;= ~0x4;
-
-       for(i = 0;; ++i) {
-               /* Print out a message, for debugging. */
-               if (i == 0)
-                       fprintf(stderr, &quot;Started uio test driver.\n&quot;);
-               else
-                       fprintf(stderr, &quot;Interrupts: %d\n&quot;, icount);
-
-               /****************************************/
-               /* Here we got an interrupt from the
-                  device. Do something to it. */
-               /****************************************/
-
-               /* Re-enable interrupts. */
-               err = pwrite(configfd, &amp;command_high, 1, 5);
-               if (err != 1) {
-                       perror(&quot;config write:&quot;);
-                       break;
-               }
-
-               /* Wait for next interrupt. */
-               err = read(uiofd, &amp;icount, 4);
-               if (err != 4) {
-                       perror(&quot;uio read:&quot;);
-                       break;
-               }
-
-       }
-       return errno;
-}
-
-</programlisting>
-       </para>
-</sect1>
-
-</chapter>
-
-<chapter id="uio_hv_generic" xreflabel="Using Generic driver for Hyper-V VMBUS">
-<?dbhtml filename="uio_hv_generic.html"?>
-<title>Generic Hyper-V UIO driver</title>
-       <para>
-       The generic driver is a kernel module named uio_hv_generic.
-       It supports devices on the Hyper-V VMBus similar to uio_pci_generic
-       on PCI bus.
-       </para>
-
-<sect1 id="uio_hv_generic_binding">
-<title>Making the driver recognize the device</title>
-       <para>
-Since the driver does not declare any device GUID's, it will not get loaded
-automatically and will not automatically bind to any devices, you must load it
-and allocate id to the driver yourself. For example, to use the network device
-GUID:
-       <programlisting>
- modprobe uio_hv_generic
- echo &quot;f8615163-df3e-46c5-913f-f2d2f965ed0e&quot; &gt; /sys/bus/vmbus/drivers/uio_hv_generic/new_id
-       </programlisting>
-       </para>
-       <para>
-If there already is a hardware specific kernel driver for the device, the
-generic driver still won't bind to it, in this case if you want to use the
-generic driver (why would you?) you'll have to manually unbind the hardware
-specific driver and bind the generic driver, like this:
-       <programlisting>
-         echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 &gt; /sys/bus/vmbus/drivers/hv_netvsc/unbind
-         echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 &gt; /sys/bus/vmbus/drivers/uio_hv_generic/bind
-       </programlisting>
-       </para>
-       <para>
-You can verify that the device has been bound to the driver
-by looking for it in sysfs, for example like the following:
-       <programlisting>
-    ls -l /sys/bus/vmbus/devices/vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver
-       </programlisting>
-Which if successful should print
-       <programlisting>
-  .../vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver -&gt; ../../../bus/vmbus/drivers/uio_hv_generic
-       </programlisting>
-       </para>
-</sect1>
-
-<sect1 id="uio_hv_generic_internals">
-<title>Things to know about uio_hv_generic</title>
-       <para>
-On each interrupt, uio_hv_generic sets the Interrupt Disable bit.
-This prevents the device from generating further interrupts
-until the bit is cleared. The userspace driver should clear this
-bit before blocking and waiting for more interrupts.
-       </para>
-</sect1>
-</chapter>
-
-<appendix id="app1">
-<title>Further information</title>
-<itemizedlist>
-       <listitem><para>
-                       <ulink url="http://www.osadl.org">
-                               OSADL homepage.</ulink>
-               </para></listitem>
-       <listitem><para>
-               <ulink url="http://www.linutronix.de">
-                Linutronix homepage.</ulink>
-               </para></listitem>
-</itemizedlist>
-</appendix>
-
-</book>
index 5475a2807e7accc8241cb7aa8c15f7f09df76ef7..c5a1cd0a4ae72bf8dc23ff43635a64cc59e3b440 100644 (file)
@@ -30,6 +30,7 @@ available subsections can be seen below.
    miscellaneous
    vme
    80211/index
+   uio-howto
 
 .. only::  subproject and html
 
diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst
new file mode 100644 (file)
index 0000000..f73d660
--- /dev/null
@@ -0,0 +1,705 @@
+=======================
+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 (*mmap)(struct uio_info *info, struct vm_area_struct *vma)``:
+   Optional. If you need a special :c:func:`mmap()`
+   function, you can set it here. If this pointer is not NULL, your
+   :c:func:`mmap()` will be called instead of the built-in one.
+
+-  ``int (*open)(struct uio_info *info, struct inode *inode)``:
+   Optional. You might want to have your own :c:func:`open()`,
+   e.g. to enable interrupts only when your device is actually used.
+
+-  ``int (*release)(struct uio_info *info, struct inode *inode)``:
+   Optional. If you define your own :c:func:`open()`, you will
+   probably also want a custom :c:func:`release()` function.
+
+-  ``int (*irqcontrol)(struct uio_info *info, s32 irq_on)``:
+   Optional. If you need to be able to enable or disable interrupts
+   from userspace by writing to ``/dev/uioX``, you can implement this
+   function. The parameter ``irq_on`` will be 0 to disable interrupts
+   and 1 to enable them.
+
+Usually, your device will have one or more memory regions that can be
+mapped to user space. For each region, you have to set up a
+``struct uio_mem`` in the ``mem[]`` array. Here's a description of the
+fields of ``struct uio_mem``:
+
+-  ``const char *name``: Optional. Set this to help identify the memory
+   region, it will show up in the corresponding sysfs node.
+
+-  ``int memtype``: Required if the mapping is used. Set this to
+   ``UIO_MEM_PHYS`` if you you have physical memory on your card to be
+   mapped. Use ``UIO_MEM_LOGICAL`` for logical memory (e.g. allocated
+   with :c:func:`kmalloc()`). There's also ``UIO_MEM_VIRTUAL`` for
+   virtual memory.
+
+-  ``phys_addr_t addr``: Required if the mapping is used. Fill in the
+   address of your memory block. This address is the one that appears in
+   sysfs.
+
+-  ``resource_size_t size``: Fill in the size of the memory block that
+   ``addr`` points to. If ``size`` is zero, the mapping is considered
+   unused. Note that you *must* initialize ``size`` with zero for all
+   unused mappings.
+
+-  ``void *internal_addr``: If you have to access this memory region
+   from within your kernel module, you will want to map it internally by
+   using something like :c:func:`ioremap()`. Addresses returned by
+   this function cannot be mapped to user space, so you must not store
+   it in ``addr``. Use ``internal_addr`` instead to remember such an
+   address.
+
+Please do not touch the ``map`` element of ``struct uio_mem``! It is
+used by the UIO framework to set up sysfs files for this mapping. Simply
+leave it alone.
+
+Sometimes, your device can have one or more port regions which can not
+be mapped to userspace. But if there are other possibilities for
+userspace to access these ports, it makes sense to make information
+about the ports available in sysfs. For each region, you have to set up
+a ``struct uio_port`` in the ``port[]`` array. Here's a description of
+the fields of ``struct uio_port``:
+
+-  ``char *porttype``: Required. Set this to one of the predefined
+   constants. Use ``UIO_PORT_X86`` for the ioports found in x86
+   architectures.
+
+-  ``unsigned long start``: Required if the port region is used. Fill in
+   the number of the first port of this region.
+
+-  ``unsigned long size``: Fill in the number of ports in this region.
+   If ``size`` is zero, the region is considered unused. Note that you
+   *must* initialize ``size`` with zero for all unused regions.
+
+Please do not touch the ``portio`` element of ``struct uio_port``! It is
+used internally by the UIO framework to set up sysfs files for this
+region. Simply leave it alone.
+
+Adding an interrupt handler
+---------------------------
+
+What you need to do in your interrupt handler depends on your hardware
+and on how you want to handle it. You should try to keep the amount of
+code in your kernel interrupt handler low. If your hardware requires no
+action that you *have* to perform after each interrupt, then your
+handler can be empty.
+
+If, on the other hand, your hardware *needs* some action to be performed
+after each interrupt, then you *must* do it in your kernel module. Note
+that you cannot rely on the userspace part of your driver. Your
+userspace program can terminate at any time, possibly leaving your
+hardware in a state where proper interrupt handling is still required.
+
+There might also be applications where you want to read data from your
+hardware at each interrupt and buffer it in a piece of kernel memory
+you've allocated for that purpose. With this technique you could avoid
+loss of data if your userspace program misses an interrupt.
+
+A note on shared interrupts: Your driver should support interrupt
+sharing whenever this is possible. It is possible if and only if your
+driver can detect whether your hardware has triggered the interrupt or
+not. This is usually done by looking at an interrupt status register. If
+your driver sees that the IRQ bit is actually set, it will perform its
+actions, and the handler returns IRQ_HANDLED. If the driver detects
+that it was not your hardware that caused the interrupt, it will do
+nothing and return IRQ_NONE, allowing the kernel to call the next
+possible interrupt handler.
+
+If you decide not to support shared interrupts, your card won't work in
+computers with no free interrupts. As this frequently happens on the PC
+platform, you can save yourself a lot of trouble by supporting interrupt
+sharing.
+
+Using uio_pdrv for platform devices
+-----------------------------------
+
+In many cases, UIO drivers for platform devices can be handled in a
+generic way. In the same place where you define your
+``struct platform_device``, you simply also implement your interrupt
+handler and fill your ``struct uio_info``. A pointer to this
+``struct uio_info`` is then used as ``platform_data`` for your platform
+device.
+
+You also need to set up an array of ``struct resource`` containing
+addresses and sizes of your memory mappings. This information is passed
+to the driver using the ``.resource`` and ``.num_resources`` elements of
+``struct platform_device``.
+
+You now have to set the ``.name`` element of ``struct platform_device``
+to ``"uio_pdrv"`` to use the generic UIO platform device driver. This
+driver will fill the ``mem[]`` array according to the resources given,
+and register the device.
+
+The advantage of this approach is that you only have to edit a file you
+need to edit anyway. You do not have to create an extra driver.
+
+Using uio_pdrv_genirq for platform devices
+------------------------------------------
+
+Especially in embedded devices, you frequently find chips where the irq
+pin is tied to its own dedicated interrupt line. In such cases, where
+you can be really sure the interrupt is not shared, we can take the
+concept of ``uio_pdrv`` one step further and use a generic interrupt
+handler. That's what ``uio_pdrv_genirq`` does.
+
+The setup for this driver is the same as described above for
+``uio_pdrv``, except that you do not implement an interrupt handler. The
+``.handler`` element of ``struct uio_info`` must remain ``NULL``. The
+``.irq_flags`` element must not contain ``IRQF_SHARED``.
+
+You will set the ``.name`` element of ``struct platform_device`` to
+``"uio_pdrv_genirq"`` to use this driver.
+
+The generic interrupt handler of ``uio_pdrv_genirq`` will simply disable
+the interrupt line using :c:func:`disable_irq_nosync()`. After
+doing its work, userspace can reenable the interrupt by writing
+0x00000001 to the UIO device file. The driver already implements an
+:c:func:`irq_control()` to make this possible, you must not
+implement your own.
+
+Using ``uio_pdrv_genirq`` not only saves a few lines of interrupt
+handler code. You also do not need to know anything about the chip's
+internal registers to create the kernel part of the driver. All you need
+to know is the irq number of the pin the chip is connected to.
+
+Using uio_dmem_genirq for platform devices
+------------------------------------------
+
+In addition to statically allocated memory ranges, they may also be a
+desire to use dynamically allocated regions in a user space driver. In
+particular, being able to access memory made available through the
+dma-mapping API, may be particularly useful. The ``uio_dmem_genirq``
+driver provides a way to accomplish this.
+
+This driver is used in a similar manner to the ``"uio_pdrv_genirq"``
+driver with respect to interrupt configuration and handling.
+
+Set the ``.name`` element of ``struct platform_device`` to
+``"uio_dmem_genirq"`` to use this driver.
+
+When using this driver, fill in the ``.platform_data`` element of
+``struct platform_device``, which is of type
+``struct uio_dmem_genirq_pdata`` and which contains the following
+elements:
+
+-  ``struct uio_info uioinfo``: The same structure used as the
+   ``uio_pdrv_genirq`` platform data
+
+-  ``unsigned int *dynamic_region_sizes``: Pointer to list of sizes of
+   dynamic memory regions to be mapped into user space.
+
+-  ``unsigned int num_dynamic_regions``: Number of elements in
+   ``dynamic_region_sizes`` array.
+
+The dynamic regions defined in the platform data will be appended to the
+`` mem[] `` array after the platform device resources, which implies
+that the total number of static and dynamic memory regions cannot exceed
+``MAX_UIO_MAPS``.
+
+The dynamic memory regions will be allocated when the UIO device file,
+``/dev/uioX`` is opened. Similar to static memory resources, the memory
+region information for dynamic regions is then visible via sysfs at
+``/sys/class/uio/uioX/maps/mapY/*``. The dynamic memory regions will be
+freed when the UIO device file is closed. When no processes are holding
+the device file open, the address returned to userspace is ~0.
+
+Writing a driver in userspace
+=============================
+
+Once you have a working kernel module for your hardware, you can write
+the userspace part of your driver. You don't need any special libraries,
+your driver can be written in any reasonable language, you can use
+floating point numbers and so on. In short, you can use all the tools
+and libraries you'd normally use for writing a userspace application.
+
+Getting information about your UIO device
+-----------------------------------------
+
+Information about all UIO devices is available in sysfs. The first thing
+you should do in your driver is check ``name`` and ``version`` to make
+sure your talking to the right device and that its kernel driver has the
+version you expect.
+
+You should also make sure that the memory mapping you need exists and
+has the size you expect.
+
+There is a tool called ``lsuio`` that lists UIO devices and their
+attributes. It is available here:
+
+http://www.osadl.org/projects/downloads/UIO/user/
+
+With ``lsuio`` you can quickly check if your kernel module is loaded and
+which attributes it exports. Have a look at the manpage for details.
+
+The source code of ``lsuio`` can serve as an example for getting
+information about an UIO device. The file ``uio_helper.c`` contains a
+lot of functions you could use in your userspace driver code.
+
+mmap() device memory
+--------------------
+
+After you made sure you've got the right device with the memory mappings
+you need, all you have to do is to call :c:func:`mmap()` to map the
+device's memory to userspace.
+
+The parameter ``offset`` of the :c:func:`mmap()` call has a special
+meaning for UIO devices: It is used to select which mapping of your
+device you want to map. To map the memory of mapping N, you have to use
+N times the page size as your offset::
+
+        offset = N * getpagesize();
+
+N starts from zero, so if you've got only one memory range to map, set
+``offset = 0``. A drawback of this technique is that memory is always
+mapped beginning with its start address.
+
+Waiting for interrupts
+----------------------
+
+After you successfully mapped your devices memory, you can access it
+like an ordinary array. Usually, you will perform some initialization.
+After that, your hardware starts working and will generate an interrupt
+as soon as it's finished, has some data available, or needs your
+attention because an error occurred.
+
+``/dev/uioX`` is a read-only file. A :c:func:`read()` will always
+block until an interrupt occurs. There is only one legal value for the
+``count`` parameter of :c:func:`read()`, and that is the size of a
+signed 32 bit integer (4). Any other value for ``count`` causes
+:c:func:`read()` to fail. The signed 32 bit integer read is the
+interrupt count of your device. If the value is one more than the value
+you read the last time, everything is OK. If the difference is greater
+than one, you missed interrupts.
+
+You can also use :c:func:`select()` on ``/dev/uioX``.
+
+Generic PCI UIO driver
+======================
+
+The generic driver is a kernel module named uio_pci_generic. It can
+work with any device compliant to PCI 2.3 (circa 2002) and any compliant
+PCI Express device. Using this, you only need to write the userspace
+driver, removing the need to write a hardware-specific kernel module.
+
+Making the driver recognize the device
+--------------------------------------
+
+Since the driver does not declare any device ids, it will not get loaded
+automatically and will not automatically bind to any devices, you must
+load it and allocate id to the driver yourself. For example::
+
+     modprobe uio_pci_generic
+     echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id
+
+If there already is a hardware specific kernel driver for your device,
+the generic driver still won't bind to it, in this case if you want to
+use the generic driver (why would you?) you'll have to manually unbind
+the hardware specific driver and bind the generic driver, like this::
+
+        echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind
+        echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind
+
+You can verify that the device has been bound to the driver by looking
+for it in sysfs, for example like the following::
+
+        ls -l /sys/bus/pci/devices/0000:00:19.0/driver
+
+Which if successful should print::
+
+      .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic
+
+Note that the generic driver will not bind to old PCI 2.2 devices. If
+binding the device failed, run the following command::
+
+      dmesg
+
+and look in the output for failure reasons.
+
+Things to know about uio_pci_generic
+------------------------------------
+
+Interrupts are handled using the Interrupt Disable bit in the PCI
+command register and Interrupt Status bit in the PCI status register.
+All devices compliant to PCI 2.3 (circa 2002) and all compliant PCI
+Express devices should support these bits. uio_pci_generic detects
+this support, and won't bind to devices which do not support the
+Interrupt Disable Bit in the command register.
+
+On each interrupt, uio_pci_generic sets the Interrupt Disable bit.
+This prevents the device from generating further interrupts until the
+bit is cleared. The userspace driver should clear this bit before
+blocking and waiting for more interrupts.
+
+Writing userspace driver using uio_pci_generic
+------------------------------------------------
+
+Userspace driver can use pci sysfs interface, or the libpci library that
+wraps it, to talk to the device and to re-enable interrupts by writing
+to the command register.
+
+Example code using uio_pci_generic
+----------------------------------
+
+Here is some sample userspace driver code using uio_pci_generic::
+
+    #include <stdlib.h>
+    #include <stdio.h>
+    #include <unistd.h>
+    #include <sys/types.h>
+    #include <sys/stat.h>
+    #include <fcntl.h>
+    #include <errno.h>
+
+    int main()
+    {
+        int uiofd;
+        int configfd;
+        int err;
+        int i;
+        unsigned icount;
+        unsigned char command_high;
+
+        uiofd = open("/dev/uio0", O_RDONLY);
+        if (uiofd < 0) {
+            perror("uio open:");
+            return errno;
+        }
+        configfd = open("/sys/class/uio/uio0/device/config", O_RDWR);
+        if (configfd < 0) {
+            perror("config open:");
+            return errno;
+        }
+
+        /* Read and cache command value */
+        err = pread(configfd, &command_high, 1, 5);
+        if (err != 1) {
+            perror("command config read:");
+            return errno;
+        }
+        command_high &= ~0x4;
+
+        for(i = 0;; ++i) {
+            /* Print out a message, for debugging. */
+            if (i == 0)
+                fprintf(stderr, "Started uio test driver.\n");
+            else
+                fprintf(stderr, "Interrupts: %d\n", icount);
+
+            /****************************************/
+            /* Here we got an interrupt from the
+               device. Do something to it. */
+            /****************************************/
+
+            /* Re-enable interrupts. */
+            err = pwrite(configfd, &command_high, 1, 5);
+            if (err != 1) {
+                perror("config write:");
+                break;
+            }
+
+            /* Wait for next interrupt. */
+            err = read(uiofd, &icount, 4);
+            if (err != 4) {
+                perror("uio read:");
+                break;
+            }
+
+        }
+        return errno;
+    }
+
+Generic Hyper-V UIO driver
+==========================
+
+The generic driver is a kernel module named uio_hv_generic. It
+supports devices on the Hyper-V VMBus similar to uio_pci_generic on
+PCI bus.
+
+Making the driver recognize the device
+--------------------------------------
+
+Since the driver does not declare any device GUID's, it will not get
+loaded automatically and will not automatically bind to any devices, you
+must load it and allocate id to the driver yourself. For example, to use
+the network device GUID::
+
+     modprobe uio_hv_generic
+     echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" > /sys/bus/vmbus/drivers/uio_hv_generic/new_id
+
+If there already is a hardware specific kernel driver for the device,
+the generic driver still won't bind to it, in this case if you want to
+use the generic driver (why would you?) you'll have to manually unbind
+the hardware specific driver and bind the generic driver, like this::
+
+          echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/hv_netvsc/unbind
+          echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 > /sys/bus/vmbus/drivers/uio_hv_generic/bind
+
+You can verify that the device has been bound to the driver by looking
+for it in sysfs, for example like the following::
+
+        ls -l /sys/bus/vmbus/devices/vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver
+
+Which if successful should print::
+
+      .../vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3/driver -> ../../../bus/vmbus/drivers/uio_hv_generic
+
+Things to know about uio_hv_generic
+-----------------------------------
+
+On each interrupt, uio_hv_generic sets the Interrupt Disable bit. This
+prevents the device from generating further interrupts until the bit is
+cleared. The userspace driver should clear this bit before blocking and
+waiting for more interrupts.
+
+Further information
+===================
+
+-  `OSADL homepage. <http://www.osadl.org>`_
+
+-  `Linutronix homepage. <http://www.linutronix.de>`_
index be8de24fd6dd80ac9916c1c4ba10d0f5fd242986..6f6efd2e706a53c8ee9a46e089b74ee71189d311 100644 (file)
@@ -12966,7 +12966,7 @@ USERSPACE I/O (UIO)
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
-F:     Documentation/DocBook/uio-howto.tmpl
+F:     Documentation/driver-api/uio-howto.rst
 F:     drivers/uio/
 F:     include/linux/uio*.h