Differences between current version and predecessor to the previous major change of HowToIOPortProgramming.
Other diffs: Previous Revision, Previous Author, or view the Annotated Edit History
Newer page: | version 3 | Last edited on Sunday, November 28, 2004 12:49:50 am | by AristotlePagaltzis | |
Older page: | version 2 | Last edited on Friday, June 7, 2002 1:06:44 am | by perry | Revert |
@@ -1,970 +1 @@
-
-
-
-Linux I/O port programming mini-HOWTO
-
-
-
-----
-
-!!!Linux I/O port programming mini-HOWTO
-
-!!Author: Riku Saikkonen <Riku.Saikkonen@hut.fi>v3., 2000-12-13
-
-
-----
-''This HOWTO document describes programming hardware I/O ports and
-waiting for small periods of time in user-mode Linux programs running
-on the Intel x86 architecture.''
-----
-
-
-
-
-!!1. Introduction
-
-
-
-
-!!2. Using I/O ports in C programs
-
-
-*2.1 The normal method
-
-*2.2 An alternate method: /dev/port
-
-
-
-
-
-!!3. Interrupts (IRQs) and DMA access
-
-
-
-
-!!4. High-resolution timing
-
-
-*4.1 Delays
-
-*4.2 Measuring time
-
-
-
-
-
-!!5. Other programming languages
-
-
-
-
-!!6. Some useful ports
-
-
-*6.1 The parallel port
-
-*6.2 The game (joystick) port
-
-*6.3 The serial port
-
-
-
-
-
-!!7. Hints
-
-
-
-
-!!8. Troubleshooting
-
-
-
-
-!!9. Example code
-
-
-
-
-!!10. Credits
-----
-
-!!1. Introduction
-
-
-This HOWTO document describes programming hardware I/O ports and
-waiting for small periods of time in user-mode Linux programs running
-on the Intel x86 architecture. This document is a descendant of the
-very small IO-Port mini-HOWTO by the same author.
-
-
-This document is Copyright 1995-2000 Riku Saikkonen. See the
-Linux HOWTO copyright for details.
-
-
-If you have corrections or something to add, feel free to e-mail me
-(Riku.Saikkonen@hut.fi)...
-
-
-
-
-
-
-----
-
-!!2. Using I/O ports in C programs
-
-!!2.1 The normal method
-
-
-
-Routines for accessing I/O ports are in /usr/include/asm/io.h
-(or linux/include/asm-i386/io.h in the kernel source
-distribution). The routines there are inline macros, so it is enough
-to #include <asm/io.h>; you do not need any additional
-libraries.
-
-
-Because of a limitation in gcc (present in all versions I know of,
-including egcs), you ''have to'' compile any source code that uses
-these routines with optimisation turned on (gcc -O1 or higher),
-or alternatively use #define extern static before you
-#include <asm/io.h> (remember to #undef
-externafterwards).
-
-
-For debugging, you can use gcc -g -O (at least with modern
-versions of gcc), though optimisation can sometimes make the debugger
-behave a bit strangely. If this bothers you, put the routines that use
-I/O port access in a separate source file and compile only that with
-optimisation turned on.
-
-
-
-
-!Permissions
-
-
-Before you access any ports, you must give your program permission to
-do so. This is done by calling the ioperm() function (declared
-in unistd.h, and defined in the kernel) somewhere near the start
-of your program (before any I/O port accesses). The syntax is
-ioperm(from, num, turn_on), where from is the first port
-number to give access to, and num the number of consecutive ports
-to give access to. For example, ioperm(0x300, 5, 1) would give
-access to ports 0x300 through 0x304 (a total of 5 ports). The last
-argument is a Boolean value specifying whether to give access to the
-program to the ports (true (1)) or to remove access (false ()). You
-can call ioperm() multiple times to enable multiple
-non-consecutive ports. See the ioperm(2) manual page for details
-on the syntax.
-
-
-The ioperm() call requires your program to have root privileges;
-thus you need to either run it as the root user, or make it setuid
-root. You can drop the root privileges after you have called
-ioperm() to enable the ports you want to use. You are not
-required to explicitly drop your port access privileges with
-ioperm(..., ) at the end of your program; this is done
-automatically as the process exits.
-
-
-A setuid() to a non-root user does not disable the port access
-granted by ioperm(), but a fork() does (the child process
-does not get access, but the parent retains it).
-
-
-ioperm() can only give access to ports 0x000 through 0x3ff; for
-higher ports, you need to use iopl() (which gives you access to
-all ports at once). Use the level argument 3 (i.e., iopl(3)) to
-give your program access to ''all'' I/O ports (so be careful ---
-accessing the wrong ports can do all sorts of nasty things to your
-computer). Again, you need root privileges to call iopl(). See
-the iopl(2) manual page for details.
-
-
-
-
-!Accessing the ports
-
-
-
-
-
-To input a byte (8 bits) from a port, call inb(port), it returns
-the byte it got. To output a byte, call outb(value, port) (please
-note the order of the parameters). To input a word (16 bits) from
-ports x and x+1 (one byte from each to form the word, using
-the assembler instruction inw), call inw(x). To output a
-word to the two ports, use outw(value, x). If you're unsure of
-which port instructions (byte or word) to use, you probably want
-inb() and outb() --- most devices are designed for bytewise
-port access. Note that all port access instructions take at least
-about a microsecond to execute.
-
-
-The inb_p(), outb_p(), inw_p(), and outw_p()
-macros work otherwise identically to the ones above, but they do an
-additional short (about one microsecond) delay after the port access;
-you can make the delay about four microseconds with #define
-REALLY_SLOW_IO before you #include <asm/io.h>. These
-macros normally (unless you #define SLOW_IO_BY_JUMPING, which
-is probably less accurate) use a port output to port 0x80 for their
-delay, so you need to give access to port 0x80 with ioperm()
-first (outputs to port 0x80 should not affect any part of the
-system). For more versatile methods of delaying, read on.
-
-
-There are manual pages for ioperm(2), iopl(2), and the above
-macros in reasonably recent releases of the Linux manual page
-collection.
-
-
-
-
-
-
-
-!!2.2 An alternate method: /dev/port
-
-
-
-Another way to access I/O ports is to open() /dev/port (a
-character device, major number 1, minor 4) for reading and/or writing
-(the stdio f*() functions have internal buffering, so avoid
-them). Then lseek() to the appropriate byte in the file (file
-position 0 = port 0x00, file position 1 = port 0x01, and so on), and
-read() or write() a byte or word from or to it.
-
-
-Naturally, for this to work your program needs read/write access to
-/dev/port. This method is probably slower than the normal
-method above, but does not need compiler optimisation nor
-ioperm(). It doesn't need root access either, if you give a
-non-root user or group access to /dev/port --- but this is a
-very bad thing to do in terms of system security, since it is possible
-to hurt the system, perhaps even gain root access, by using
-/dev/port to access hard disks, network cards, etc. directly.
-
-
-You cannot use select(2) or poll(2) to read /dev/port,
-because the hardware does not have a facility for notifying the CPU
-when a value in an input port changes.
-
-
-
-
-
-
-----
-
-!!3. Interrupts (IRQs) and DMA access
-
-
-You cannot use IRQs or DMA directly from a user-mode process. You need
-to write a kernel driver; see
-The Linux Kernel Hacker's Guide for details and the kernel source code
-for examples.
-
-
-You can disable interrupts from within a user-mode program, though it can
-be dangerous (even kernel drivers do it for as short a time as possible).
-After calling iopl(3), you can disable interrupts simply by calling
-asm("cli");, and re-enable them with asm("sti");.
-
-
-
-
-
-
-----
-
-!!4. High-resolution timing
-
-!!4.1 Delays
-
-
-
-First of all, I should say that you cannot guarantee user-mode
-processes to have exact control of timing because of the multi-tasking
-nature of Linux. Your process might be scheduled out at any time for
-anything from about 10 milliseconds to a few seconds (on a system with
-very high load). However, for most applications using I/O ports, this
-does not really matter. To minimise this, you may want to nice your
-process to a high-priority value (see the nice(2) manual page) or
-use real-time scheduling (see below).
-
-
-If you want more precise timing than normal user-mode processes give
-you, there are some provisions for user-mode `real time' support.
-Linux 2.x kernels have soft real time support; see the manual page for
-sched_setscheduler(2) for details. There is a special kernel that
-supports hard real time; see
-http://luz.cs.nmt.edu/~rtlinux/ for more information on
-this.
-
-
-
-
-!Sleeping: sleep() and usleep()
-
-
-Now, let me start with the easier timing calls. For delays of multiple
-seconds, your best bet is probably to use sleep(). For delays of
-at least tens of milliseconds (about 10 ms seems to be the minimum
-delay), usleep() should work. These functions give the CPU to
-other processes (``sleep''), so CPU time isn't wasted. See the manual
-pages sleep(3) and usleep(3) for details.
-
-
-For delays of under about 50 milliseconds (depending on the speed of
-your processor and machine, and the system load), giving up the CPU
-takes too much time, because the Linux scheduler (for the x86
-architecture) usually takes at least about 10-30 milliseconds before
-it returns control to your process. Due to this, in small delays,
-usleep(3) usually delays somewhat more than the amount that you
-specify in the parameters, and at least about 10 ms.
-
-
-
-
-!nanosleep()
-
-
-In the 2..x series of Linux kernels, there is a new system call,
-nanosleep() (see the nanosleep(2) manual page), that allows
-you to sleep or delay for short times (a few microseconds or more).
-
-
-For delays <= 2 ms, if (and only if) your process is set to soft
-real time scheduling (using sched_setscheduler()),
-nanosleep() uses a busy loop; otherwise it sleeps, just like
-usleep().
-
-
-The busy loop uses udelay() (an internal kernel function used by
-many kernel drivers), and the length of the loop is calculated using
-the !BogoMips value (the speed of this kind of busy loop is one of the
-things that !BogoMips measures accurately). See
-/usr/include/asm/delay.h) for details on how it works.
-
-
-
-
-!Delaying with port I/O
-
-
-Another way of delaying small numbers of microseconds is port
-I/O. Inputting or outputting any byte from/to port 0x80 (see above for
-how to do it) should wait for almost exactly 1 microsecond independent
-of your processor type and speed. You can do this multiple times to
-wait a few microseconds. The port output should have no harmful side
-effects on any standard machine (and some kernel drivers use it). This
-is how {in|out}
[[bw
]_p() normally do the delay (see
-asm/io.h).
-
-
-Actually, a port I/O instruction on most ports in the -0x3ff range
-takes almost exactly 1 microsecond, so if you're, for example, using
-the parallel port directly, just do additional inb()s from that
-port to delay.
-
-
-
-
-!Delaying with assembler instructions
-
-
-If you know the processor type and clock speed of the machine the
-program will be running on, you can hard-code shorter delays by
-running certain assembler instructions (but remember, your process
-might be scheduled out at any time, so the delays might well be longer
-every now and then). For the table below, the internal processor speed
-determines the number of clock cycles taken; e.g., for a 50 MHz
-processor (e.g. 486DX-50 or 486DX2-50), one clock cycle takes
-1/50000000 seconds (=200 nanoseconds).
-
-
-
-
-
-Instruction i386 clock cycles i486 clock cycles
-xchg %bx,%bx 3 3
-nop 3 1
-or %ax,%ax 2 1
-mov %ax,%ax 2 1
-add %ax,0 2 1
-
-
-
-
-
-
-
-Clock cycles for Pentiums should be the same as for i486, except that
-on Pentium Pro/II, add %ax, 0 may take only 1/2 clock cycles. It
-can sometimes be paired with another instruction (because of
-out-of-order execution, this need not even be the very next
-instruction in the instruction stream).
-
-
-The instructions nop and xchg in the table should have no
-side effects. The rest may modify the flags register, but this
-shouldn't matter since gcc should detect it. xchg %bx, %bx is a
-safe choice for a delay instruction.
-
-
-To use these, call asm("instruction") in your
-program. The syntax of the instructions is as in the table above; if
-you want multiple instructions in a single asm() statement,
-separate them with semicolons. For example,
-asm("nop ; nop ; nop ; nop") executes four nop
-instructions, delaying for four clock cycles on i486 or Pentium
-processors (or 12 clock cycles on an i386).
-
-
-asm() is translated into inline assembler code by gcc, so there
-is no function call overhead.
-
-
-Shorter delays than one clock cycle are impossible in the Intel x86
-architecture.
-
-
-
-
-!rdtsc for Pentiums
-
-
-For Pentiums, you can get the number of clock cycles elapsed since the
-last reboot with the following C code (which executes the CPU
-instrution named RDTSC):
-
-
-
-
-----
-
-extern __inline__ unsigned long long int rdtsc()
-{
-unsigned long long int x;
-__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
-return x;
-}
-
-----
-
-
-
-You can poll this value in a busy loop to delay for as many clock
-cycles as you want.
-
-
-
-
-
-
-
-!!4.2 Measuring time
-
-
-
-For times accurate to one second, it is probably easiest to use
-time(). For more accurate times, gettimeofday() is accurate
-to about a microsecond (but see above about scheduling). For Pentiums,
-the rdtsc code fragment above is accurate to one clock cycle.
-
-
-If you want your process to get a signal after some amount of time,
-use setitimer() or alarm(). See the manual pages of the
-functions for details.
-
-
-
-
-
-
-----
-
-!!5. Other programming languages
-
-
-The description above concentrates on the C programming language. It
-should apply directly to C++ and Objective C. In assembler, you have
-to call ioperm() or iopl() as in C, but after that you can
-use the I/O port read/write instructions directly.
-
-
-In other languages, unless you can insert inline assembler or C code
-into the program or use the system calls mentioned above, it is
-probably easiest to write a simple C source file with functions for
-the I/O port accesses or delays that you need, and compile and link it
-in with the rest of your program. Or use /dev/port as described
-above.
-
-
-
-
-
-
-----
-
-!!6. Some useful ports
-
-
-Here is some programming information for common ports that can be directly
-used for general-purpose TTL (or CMOS) logic I/O.
-
-
-If you want to use these or other common ports for their intended
-purpose (e.g., to control a normal printer or modem), you should most
-likely use existing drivers (which are usually included in the kernel)
-instead of programming the ports directly as this HOWTO describes.
-This section is intended for those people who want to connect LCD
-displays, stepper motors, or other custom electronics to a PC's
-standard ports.
-
-
-If you want to control a mass-market device like a scanner (that has
-been on the market for a while), look for an existing Linux driver for
-it. The
-Hardware-HOWTO is a good place to start.
-
-
-
-http://www.hut.fi/Misc/Electronics/ is a good source for
-more information on connecting devices to computers (and on
-electronics in general).
-
-
-
-
-
-
-
-!!6.1 The parallel port
-
-
-
-The parallel port's base address (called ``BASE'' below) is 0x3bc
-for /dev/lp0, 0x378 for /dev/lp1, and 0x278 for
-/dev/lp2. If you only want to control something that acts like
-a normal printer, see the
-Printing-HOWTO.
-
-
-In addition to the standard output-only mode described below, there is
-an `extended' bidirectional mode in most parallel ports. For
-information on this and the newer ECP/EPP modes (and the IEEE 1284
-standard in general), see
-http://www.fapo.com/ and
-http://www.senet.com.au/~cpeacock/parallel.htm. Remember
-that since you cannot use IRQs or DMA in a user-mode program, you will
-probably have to write a kernel driver to use ECP/EPP; I think someone
-is writing such a driver, but I don't know the details.
-
-
-The port BASE+0 (Data port) controls the data signals of the port (D0
-to D7 for bits 0 to 7, respectively; states: 0 = low (0 V), 1 = high
-(5 V)). A write to this port latches the data on the pins. A read
-returns the data last written in standard or extended write mode, or
-the data in the pins from another device in extended read mode.
-
-
-The port BASE+1 (Status port) is read-only, and returns the state
-of the following input signals:
-
-
-*Bits 0 and 1 are reserved.
-*
-
-*Bit 2 IRQ status (not a pin, I don't know how this works)
-*
-
-*Bit 3 ERROR (1=high)
-*
-
-*Bit 4 SLCT (1=high)
-*
-
-*Bit 5 PE (1=high)
-*
-
-*Bit 6 ACK (1=high)
-*
-
-*Bit 7 -BUSY (=high)
-*
-
-
-
-The port BASE+2 (Control port) is write-only (a read returns the
-data last written), and controls the following status signals:
-
-
-*Bit 0 -STROBE (=high)
-*
-
-*Bit 1 -AUTO_FD_XT (=high)
-*
-
-*Bit 2 INIT (1=high)
-*
-
-*Bit 3 -SLCT_IN (=high)
-*
-
-*Bit 4 enables the parallel port IRQ (which occurs on the
-low-to-high transition of ACK) when set to 1.
-*
-
-*Bit 5 controls the extended mode direction (0 = write, 1 =
-read), and is completely write-only (a read returns nothing
-useful for this bit).
-*
-
-*Bits 6 and 7 are reserved.
-*
-
-
-
-Pinout (a 25-pin female D-shell connector on the port) (i=input, o=output):
-
-
-1io -STROBE, 2io D0, 3io D1, 4io D2, 5io D3, 6io D4, 7io D5, 8io D6,
-9io D7, 10i ACK, 11i -BUSY, 12i PE, 13i SLCT, 14o -AUTO_FD_XT,
-15i ERROR, 16o INIT, 17o -SLCT_IN, 18-25 Ground
-
-
-
-
-The IBM specifications say that pins 1, 14, 16, and 17 (the control
-outputs) have open collector drivers pulled to 5 V through 4.7 kiloohm
-resistors (sink 20 mA, source .55 mA, high-level output 5.0 V minus
-pullup). The rest of the pins sink 24 mA, source 15 mA, and their
-high-level output is min. 2.4 V. The low state for both is max. .5 V.
-Non-IBM parallel ports probably deviate from this standard. For more
-information on this, see
-http://www.hut.fi/Misc/Electronics/circuits/lptpower.html.
-
-
-Finally, a warning: Be careful with grounding. I've broken several
-parallel ports by connecting to them while the computer is turned
-on. It might be a good thing to use a parallel port not integrated on
-the motherboard for things like this. (You can usually get a second
-parallel port for your machine with a cheap standard `multi-I/O' card;
-just disable the ports that you don't need, and set the parallel port
-I/O address on the card to a free address. You don't need to care
-about the parallel port IRQ if you don't use it.)
-
-
-
-
-
-
-
-!!6.2 The game (joystick) port
-
-
-
-The game port is located at port addresses 0x200-0x207. If you want to
-control normal joysticks, you're probably better off using the drivers
-distributed with the Linux kernel.
-
-
-Pinout (a 15-pin female D-shell connector on the port):
-
-
-*1,8,9,15: +5 V (power)
-*
-
-*4,5,12: Ground
-*
-
-*2,7,10,14: Digital inputs BA1, BA2, BB1, and BB2, respectively
-*
-
-*3,6,11,13: ``Analog'' inputs AX, AY, BX, and BY, respectively
-*
-
-
-
-The +5 V pins seem to often be connected directly to the power lines
-in the motherboard, so they may be able to source quite a lot of
-power, depending on the motherboard, power supply and game port.
-
-
-The digital inputs are used for the buttons of the two joysticks
-(joystick A and joystick B, with two buttons each) that you can
-connect to the port. They should be normal TTL-level inputs, and you
-can read their status directly from the status port (see below). A
-real joystick returns a low (0 V) status when the button is pressed
-and a high (the 5 V from the power pins through an 1 Kohm resistor)
-status otherwise.
-
-
-The so-called analog inputs actually measure resistance. The game port
-has a quad one-shot multivibrator (a 558 chip) connected to the four
-inputs. In each input, there is a 2.2 Kohm resistor between the input
-pin and the multivibrator output, and a .01 uF timing capacitor
-between the multivibrator output and the ground. A real joystick has a
-potentiometer for each axis (X and Y), wired between +5 V and the
-appropriate input pin (AX or AY for joystick A, or BX or BY for
-joystick B).
-
-
-The multivibrator, when activated, sets its output lines high (5 V)
-and waits for each timing capacitor to reach 3.3 V before lowering the
-respective output line. Thus the high period duration of the
-multivibrator is proportional to the resistance of the potentiometer
-in the joystick (i.e., the position of the joystick in the appropriate
-axis), as follows:
-
-R = (t - 24.2) / .011,
-
-where R is the resistance (ohms) of the potentiometer and t the high
-period duration (microseconds).
-
-
-Thus, to read the analog inputs, you first activate the multivibrator
-(with a port write; see below), then poll the state of the four axes
-(with repeated port reads) until they drop from high to low state,
-measuring their high period duration. This polling uses quite a lot of
-CPU time, and on a non-realtime multitasking system like (normal
-user-mode) Linux, the result is not very accurate because you cannot
-poll the port constantly (unless you use a kernel-level driver and
-disable interrupts while polling, but this wastes even more CPU
-time). If you know that the signal is going to take a long time (tens
-of ms) to go down, you can call usleep() before polling to give CPU
-time to other processes.
-
-
-The only I/O port you need to access is port 0x201 (the other ports
-either behave identically or do nothing). Any write to this port (it
-doesn't matter what you write) activates the multivibrator. A read
-from this port returns the state of the input signals:
-
-
-*Bit : AX (status (1=high) of the multivibrator output)
-*
-
-*Bit 1: AY (status (1=high) of the multivibrator output)
-*
-
-*Bit 2: BX (status (1=high) of the multivibrator output)
-*
-
-*Bit 3: BY (status (1=high) of the multivibrator output)
-*
-
-*Bit 4: BA1 (digital input, 1=high)
-*
-
-*Bit 5: BA2 (digital input, 1=high)
-*
-
-*Bit 6: BB1 (digital input, 1=high)
-*
-
-*Bit 7: BB2 (digital input, 1=high)
-*
-
-
-
-
-
-
-
-
-!!6.3 The serial port
-
-
-
-If the device you're talking to supports something resembling RS-232,
-you should be able to use the serial port to talk to it. The Linux
-serial driver should be enough for almost all applications (you
-shouldn't have to program the serial port directly, and you'd probably
-have to write a kernel driver to do it); it is quite versatile, so
-using non-standard bps rates and so on shouldn't be a problem.
-
-
-See the termios(3) manual page, the serial driver source code
-(linux/drivers/char/serial.c), and
-http://www.easysw.com/~mike/serial/ for more
-information on programming serial ports on Unix systems.
-
-
-
-
-
-
-----
-
-!!7. Hints
-
-
-If you want good analog I/O, you can wire up ADC and/or DAC chips to
-the parallel port (hint: for power, use the game port connector or a
-spare disk drive power connector wired to outside the computer case,
-unless you have a low-power device and can use the parallel port
-itself for power, or use an external power supply), or buy an AD/DA
-card (most of the older/slower ones are controlled by I/O ports). Or,
-if you're satisfied with 1 or 2 channels, inaccuracy, and (probably)
-bad zeroing, a cheap sound card supported by the Linux sound driver
-should do (and it's quite fast).
-
-
-With accurate analog devices, improper grounding may generate errors
-in the analog inputs or outputs. If you experience something like
-this, you could try electrically isolating your device from the
-computer with optocouplers (on ''all'' signals between the computer
-and your device). Try to get power for the optocouplers from the
-computer (spare signals on the port may give enough power) to achieve
-better isolation.
-
-
-If you're looking for printed circuit board design software for Linux,
-there is a free X11 application called Pcb that should do a nice job,
-at least if you aren't doing anything very complex. It is included in
-many Linux distributions, and available in
-ftp://sunsite.unc.edu/pub/Linux/apps/circuits/ (filename
-pcb-*).
-
-
-
-
-
-
-----
-
-!!8. Troubleshooting
-
-
-
-
-; __Q1.__:
-
-I get segmentation faults when accessing ports.
-
-
-
-; __A1.__:
-
-Either your program does not have root privileges, or the
-ioperm() call failed for some other reason. Check the return
-value of ioperm(). Also, check that you're actually accessing the
-ports that you enabled with ioperm() (see Q3). If you're using
-the delaying macros (inb_p(), outb_p(), and so on), remember
-to call ioperm() to get access to port 0x80 too.
-
-
-
-; __Q2.__:
-
-I can't find the in*(), out*() functions defined
-anywhere, and gcc complains about undefined references.
-
-
-
-; __A2.__:
-
-You did not compile with optimisation turned on (-O),
-and thus gcc could not resolve the macros in asm/io.h. Or you
-did not #include <asm/io.h> at all.
-
-
-
-; __Q3.__:
-
-out*() doesn't do anything, or does something weird.
-
-
-
-; __A3.__:
-
-Check the order of the parameters; it should be
-outb(value, port), not outportb(port, value) as is common in
-MS-DOS.
-
-
-
-; __Q4.__:
-
-I want to control a standard RS-232 device/parallel
-printer/joystick...
-
-
-
-; __A4.__:
-
-You're probably better off using existing drivers (in the
-Linux kernel or an X server or somewhere else) to do it. The drivers
-are usually quite versatile, so even slightly non-standard devices
-usually work with them. See the information on standard ports above
-for pointers to documentation for them.
-
-
-
-
-
-
-
-----
-
-!!9. Example code
-
-
-Here's a piece of simple example code for I/O port access:
-
-
-
-
-----
-
-/*
-* example.c: very simple example of port I/O
-*
-* This code does nothing useful, just a port write, a pause,
-* and a port read. Compile with `gcc -O2 -o example example.c',
-* and run as root with `./example'.
-*/
-#include <stdio.h>
-#include <unistd.h>
-#include <asm/io.h>
-#define BASEPORT 0x378 /* lp1 */
-int main()
-{
-/* Get access to the ports */
-if (ioperm(BASEPORT, 3, 1)) {perror("ioperm"); exit(1);}
-/* Set the data signals (D0-7) of the port to all low () */
-outb(, BASEPORT);
-/* Sleep for a while (100 ms) */
-usleep(100000);
-/* Read from the status port (BASE+1) and display the result */
-printf("status: %d\n", inb(BASEPORT + 1));
-/* We don't need the ports anymore */
-if (ioperm(BASEPORT, 3, )) {perror("ioperm"); exit(1);}
-exit();
-}
-/* end of example.c */
-
-----
-
-
-
-
-
-
-
-----
-
-!!10. Credits
-
-
-Too many people have contributed for me to list, but thanks a lot,
-everyone. I have not replied to all the contributions that I've
-received; sorry for that, and thanks again for the help
.
-
-
-
-----
+Describe
[HowToIOPortProgramming
] here
.