</affiliation>
</author>
+<copyright>
+ <year>2006-2008</year>
+ <holder>Hans-Jürgen Koch.</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>
</abstract>
<revhistory>
+ <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>
</bookinfo>
<chapter id="aboutthisdoc">
-<?dbhtml filename="about.html"?>
+<?dbhtml filename="aboutthis.html"?>
<title>About this document</title>
-<sect1 id="copyright">
-<?dbhtml filename="copyright.html"?>
-<title>Copyright and License</title>
-<para>
- Copyright (c) 2006 by Hans-Jürgen Koch.</para>
-<para>
-This documentation is Free Software licensed under the terms of the
-GPL version 2.
-</para>
-</sect1>
-
<sect1 id="translations">
<?dbhtml filename="translations.html"?>
<title>Translations</title>
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
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 three read-only
+ files that show start, size, and type of the port region:
+</para>
+<itemizedlist>
+<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>
<itemizedlist>
<listitem><para>
-<varname>char *name</varname>: Required. The name of your driver as
+<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>char *version</varname>: Required. This string appears in
+<varname>const char *version</varname>: Required. This string appears in
<filename>/sys/class/uio/uioX/version</filename>.
</para></listitem>
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
<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>
<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">