3.4 manage I/O port resources
We all know that the x86 processor using I/O ing implements a separate address space for the peripherals, that is, the "I/O space" (I/O
Or "I/O port space". Its size is 64 KB (0x0000-0xffff ). Linux implements the concept of "I/O port space" on all platforms it supports.
Because I/O space is very small, even if the peripheral bus has a separate I/O port space, not all peripherals place their I/O Ports (registers) maps to "I/O port space.
For example, most PCI cards map their I/O ports or peripheral memory to the CPU's Ram physical address space through memory ing. The old ISA cartoon often maps its I/O port to I
/O port space.
Linux is based on
The concept of Region
Memory-mapped.
3.4.1 definition of the resource Root Node
Linux defines the global variables ioport_resource and iomem_resource in the kernel/resource. c file to describe
The entire I/O port space in the I/O ing mode and the I/O memory resource space (including I/O port and peripheral memory) based on the memory ing mode ). It is defined as follows:
Struct resource ioport_resource =
{"PCI Io", 0x0000, io_space_limit, ioresource_io };
Struct resource iomem_resource =
{"PCI mem", 0x00000000, 0 xffffffff, ioresource_mem
};
Here there is a change in kernel 2.6.32. The end of iomem_resource is changed from 0xffffffff to-1, which is more reasonable. You can refer to this URL http://www.spinics.net/lists/linux-pci/msg09857.html (the iomem_resource Map reflects the available physical address space. we statically initialize the end to-1, I. E ., 0xffffffff_ffffff, but of course we can only use as much as the CPU can address .)
Here, the macro io_space_limit represents the size of the entire I/O space, for x86 platforms, it is 0 xFFFF (defined in the include/asm-i386/IO. h header file ). Here I will write another sentence. For the ARM platform, taking S3C2410 as an example, io_space_limit is 0 xffffffff, because for the ARM platform, it uses the memory ing method.
Obviously, the size of I/O memory is 4 GB.
3.4.2 operations on the I/O port Space
I/O-based
Region's operation function _ xxx_region (). Linux defines three pairs of I/O port space in the header file include/Linux/ioport. h.
Macro of the row operation: ① request_region () Macro, requesting allocation of the specified range of I/O port resources in the I/O port space. ② Check_region () Macro, check I
Whether the specified I/O port resource in the/O port space is occupied. ③ Release_region () macro to release the specified I/O port resources in the I/O port space. The definition of these three macros is as follows:
Below:
# Define request_region (START, N, name)
_ Request_region (& ioport_resource, (start), (n), (name ))
# Define check_region (START, n)
_ Check_region (& ioport_resource, (start), (n ))
# Define release_region (START, n)
_ Release_region (& ioport_resource, (start), (n ))
The macro parameter start specifies the starting physical address of the I/O port Resource (physical address in the I/O port space), and the macro parameter n specifies the size of the I/O port resource.
3.4.3 operations on I/O memory resources
I/O-based
Region operation function _ xxx_region (), Linux in the header file include/Linux/ioport. h defines three macros that operate on the I/O memory resources: ① request_mem_region () Macro, and requests the allocation of the specified I/O memory resources. ② Check _
Mem_region () macro to check whether the specified I/O memory resources are occupied. ③ Release _
Mem_region () macro to release specified I/O memory resources. The three macros are defined as follows:
# Define request_mem_region (START, N, name)
_ Request_region (& iomem_resource, (start), (n ),
(Name ))
# Define check_mem_region (START, n)
_ Check_region (& iomem_resource, (start), (n ))
# Define release_mem_region (START, n)
_ Release_region (& iomem_resource, (start), (n ))
Here, the start parameter is the starting physical address of the I/O memory resource (the physical address in the CPU's Ram physical address space), and the parameter n specifies the size of the I/O memory resource.
3.4.4 support for/proc/ioports and/proc/iomem
Linux defines two macros in the ioport. h header file:
Get_ioport_list () and get_iomem_list () are used to implement the/proc/ioports file and/proc/iomem file respectively. It is defined as follows:
# Define get_ioport_list (BUF)
Get_resource_list (& ioport_resource, Buf, page_size)
# Define get_mem_list (BUF) get_resource_list (& iomem_resource,
Buf, page_size)
2.6.32 removed these two functions. I still don't know how to implement support for/proc/ioports and/proc/iomem. Please advise.
3.5 Access the I/O port Space
After the driver requests port resources in the I/O port space, it can read and write these I/O ports through the CPU Io designation. When reading and writing I/O Ports, note that most platforms distinguish between 8-bit, 16-bit, and 32-bit ports, that is, the width of the I/O port.
Linux defines a series of macro functions for reading and writing different I/O Ports in the include/ASM/IO. h header file (for the i386 platform is include/asm-i386/IO. h. As follows:
(1) read and write 8-bit I/O Ports
Unsigned char INB (unsigned port );
Void outb (unsigned char value, unsigned port );
The port parameter specifies the port address in the I/O port space. On most platforms (such as x86), it is unsigned.
Short Type, while others are unsigned.
Int type. Obviously, the port address type is determined by the size of the I/O port space.
(2) read and write 16-bit I/O Ports
Unsigned short inw (unsigned port );
Void outw (unsigned short value, unsigned port );
(3) read and write 32-bit I/O Ports
Unsigned int INL (unsigned port );
Void outl (unsigned int value, unsigned port );
3.5.1 string operation on the I/O port
In addition to these single-shot I/O operations, some CPUs also support sequential read/write operations on an I/O port, that is, a series of bytes, characters, or 32-bit integers are read or written to a single I/O port.
Instruction ). The speed of such commands is obviously much faster than using loops to implement the same function.
Linux also defines the string I/O read/write function in the IO. h file:
(1) 8-bit string I/O operations
Void InSb (unsigned port, void * ADDR, unsigned long
Count );
Void outsb (unsigned port, void * ADDR, unsigned long
Count );
(2) string I/O operations with a 16-Bit Width
Void insw (unsigned port, void * ADDR, unsigned long
Count );
Void outsw (unsigned port, void * ADDR, unsigned long
Count );
(3) 32-bit string I/O operations
Void insl (unsigned port, void * ADDR, unsigned long
Count );
Void outsl (unsigned port, void * ADDR, unsigned long
Count );
3.5.2 pausing I/O
On Some platforms (such as x86), for slow peripherals on older bus (such as ISA), if the CPU reads and writes its I/O Ports too fast, then the data may be lost.
Image. The solution to this problem is to insert a small latency between two consecutive I/O operations to wait for the slow peripherals. This is the so-called "pausing
I/O ".
For pausing
I/O, Linux also defines its I/O Read and Write Functions in the IO. h header file, and all of them are named after xxx_p, such as inb_p () and outb_p. Next we will take out_p () as an example for analysis.
Expand the macro definition _ out (B, "B" char) in Io. h and you can get the following definition:
Extern inline void outb (unsigned char value, unsigned short port)
{
_ ASM _ volatile _ ("outb %" "B" "0, %" W "" 1"
: "A" (value), "nd" (port ));
}
Extern inline void outb_p (unsigned char value, unsigned short port)
{
_ ASM _ volatile _ ("outb %" "B" "0, %" W "" 1"
_ Full_slow_down_io
: "A" (value), "nd" (port ));
}
We can see that macro _ full_slown_down_io is inserted in the implementation of the outb_p () function to achieve small latency. Macro _ full_slown_down_io is defined at the beginning of the header file IO. h:
# Ifdef slow_io_by_jumping
# DEFINE _ slow_down_io"
JMP 1f
1: JMP 1f
1 :"
# Else
# DEFINE _ slow_down_io"
Outb % Al, $0x80"
# Endif
# Ifdef really_slow_io
# DEFINE _ full_slow_down_io _ slow_down_io
_ Slow_down_io
# Else
# DEFINE _ full_slow_down_io _ slow_down_io
# Endif
Apparently, __full_slow_down_io is one or four _ slow_down_io (determined based on whether the macro really_slow_io is defined
), While macro _ slow_down_io is defined as meaningless jump statements or write operations on port 0x80 (based on whether macro slow_io_by_jumping is defined
).