Merge branch 'kdb-merge' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel...
[safe/jmp/linux-2.6] / Documentation / DocBook / uio-howto.tmpl
index 6116b93..4d4ce0e 100644 (file)
        <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>
@@ -42,6 +46,26 @@ GPL version 2.
 
 <revhistory>
        <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>
@@ -297,12 +321,19 @@ interested in translating it, please email me
        appear if the size of the mapping is not 0.
 </para>
 <para>
-       Each <filename>mapX/</filename> directory contains two read-only files
-       that show start address and size of the memory:
+       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>
@@ -312,6 +343,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>
@@ -350,12 +391,19 @@ offset = N * getpagesize();
        <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:
+       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>
@@ -393,12 +441,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>
 
@@ -594,6 +642,78 @@ framework to set up sysfs files for this region. 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">
@@ -700,6 +820,158 @@ framework to set up sysfs files for this region. Simply leave it alone.
 
 </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 (uiofd &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>
+
 <appendix id="app1">
 <title>Further information</title>
 <itemizedlist>