diff options
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/DocBook/uio-howto.tmpl | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl index 8f6e3b2..4d4ce0e 100644 --- a/Documentation/DocBook/uio-howto.tmpl +++ b/Documentation/DocBook/uio-howto.tmpl @@ -25,6 +25,10 @@ <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,13 @@ 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> @@ -809,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 "8086 10f5" > /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 > /sys/bus/pci/drivers/e1000e/unbind + echo -n 0000:00:19.0 > /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 -> ../../../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 <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 (uiofd < 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; +} + +</programlisting> + </para> +</sect1> + +</chapter> + <appendix id="app1"> <title>Further information</title> <itemizedlist> |