X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=Documentation%2FDocBook%2Fuio-howto.tmpl;h=4d4ce0e61e424708a94db666e0496d7c0f3fc253;hb=90b9a32d8f441369b2f97a765d2d957b531eb653;hp=6116b93608df87246b30a845a37da3a86c1883ce;hpb=a2ab3d30005cdce45c2c7e31ad6743ad7975609a;p=safe%2Fjmp%2Flinux-2.6
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
index 6116b93..4d4ce0e 100644
--- a/Documentation/DocBook/uio-howto.tmpl
+++ b/Documentation/DocBook/uio-howto.tmpl
@@ -25,6 +25,10 @@
2006-2008
Hans-Jürgen Koch.
+
+ 2009
+ Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)
+
@@ -42,6 +46,26 @@ GPL version 2.
+ 0.9
+ 2009-07-16
+ mst
+ Added generic pci driver
+
+
+
+ 0.8
+ 2008-12-24
+ hjk
+ Added name attributes in mem and portio sysfs directories.
+
+
+
+ 0.7
+ 2008-12-23
+ hjk
+ Added generic platform drivers and offset attribute.
+
+
0.6
2008-12-05
hjk
@@ -297,12 +321,19 @@ interested in translating it, please email me
appear if the size of the mapping is not 0.
- Each mapX/ directory contains two read-only files
- that show start address and size of the memory:
+ 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.
@@ -312,6 +343,16 @@ interested in translating it, please email me
pointed to by addr.
+
+
+ offset: The offset, in bytes, that has to be
+ added to the pointer returned by 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
+ mmap() are always page aligned, so it is good
+ style to always add this offset.
+
+
@@ -350,12 +391,19 @@ offset = N * getpagesize();
/sys/class/uio/uioX/portio/.
- Each portX/ directory contains three read-only
- files that show start, size, and type of the port region:
+ 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.
@@ -393,12 +441,12 @@ offset = N * getpagesize();
-char *name: Required. The name of your driver as
+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.
-char *version: Required. This string appears in
+const char *version: Required. This string appears in
/sys/class/uio/uioX/version.
@@ -594,6 +642,78 @@ framework to set up sysfs files for this region. Simply leave it alone.
+
+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
+ 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
+ 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.
+
+
+
@@ -700,6 +820,158 @@ framework to set up sysfs files for this region. Simply leave it alone.
+
+
+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 libray 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 (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;
+}
+
+
+
+
+
+
+
Further information