]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - Documentation/DocBook/uio-howto.tmpl
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-omap-h63xx.git] / Documentation / DocBook / uio-howto.tmpl
index df87d1b93605ac54cf400bd7b8d44b0866d0789a..52e1b79ce0e6aaa1fabc209921966ab5a6cd7d66 100644 (file)
@@ -41,6 +41,18 @@ GPL version 2.
 </abstract>
 
 <revhistory>
+       <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>
@@ -306,6 +318,16 @@ interested in translating it, please email me
        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>
@@ -318,6 +340,54 @@ interested in translating it, please email me
 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>
 
@@ -339,12 +409,12 @@ offset = N * getpagesize();
 
 <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>
 
@@ -355,6 +425,13 @@ 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
@@ -448,6 +525,42 @@ Please do not touch the <varname>kobj</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">
@@ -497,6 +610,78 @@ to set up sysfs files for this mapping. Simply leave it alone.
        </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>
+
 </chapter>
 
 <chapter id="userspace_driver" xreflabel="Writing a driver in user space">