Accessing I/O ports

When porting code that accesses hardware, the x86 architecture has a set of instructions that manipulate a separate address space called the I/O address space. This address space is completely separate from the memory address space. On non-x86 platforms (PPC, etc.), such an address space doesn't exist — all devices are mapped into memory.

In order to keep code portable, we've defined a number of functions that isolate this behavior. By including the file <hw/inout.h>, you get the following functions:

in8()
Reads an 8-bit value.
in16(), inbe16(), inle16()
Reads a 16-bit value.
in32(), inbe32(), inle32()
Reads a 32-bit value.
in8s()
Reads a number of 8-bit values.
in16s()
Reads a number of 16-bit values.
in32s()
Reads a number of 32-bit values.
out8()
Writes a 8-bit value.
out16(), outbe16(), outle16()
Writes a 16-bit value.
out32(), outbe32(), outle32()
Writes a 32-bit value.
out8s()
Writes a number of 8-bit values.
out16s()
Writes a number of 16-bit values.
out32s()
Writes a number of 32-bit values.

On the x86 architecture, these functions perform the machine instructions in, out, rep ins*, and rep outs*. On non-x86 architectures, they dereference the supplied address (the addr parameter) and perform memory accesses.

The bottom line is that code written for the x86 will be portable to MIPS and PPC. Consider the following fragment:

iir = in8 (baseport);
if (iir & 0x01) {
    return;
}

On an x86 platform, this will perform IN AL, DX, whereas on a MIPS or PPC, it will dereference the 8-bit value stored at location baseport.

Note that the calling process must use mmap_device_io() to access the device's I/O registers.