3.6 access to I/O memory resources
Although I/O port space was once widely used on the X86 platform, it is very small, so most modern bus devices use the memory ing method (memory-mapped ).
Maps its I/O Ports (I/O registers) and peripheral memory. Memory ing-based I/O Ports (I/O registers) and peripheral memory can be referred to as "I/O memory" Resources (I/O
Memory ). Because the hardware implementation differences between the two are completely transparent to the software, the driver developers can regard the memory ing I/O port and the peripheral memory as "I
/O memory "resource.
From the previous sections, we know that I/O memory resources are stored in a single physical address space in the CPU, that is, it is in the same physical address space as the system Ram. Therefore, I/O memory resources can be accessed through the CPU access command.
Generally, when the system is running, the physical address of the peripheral I/O memory resources is known, which can be allocated at startup through the system firmware (such as BIOS, or through the hardware connection of the device.
(Hardwired. For example, the physical address of the PCI Card's I/O memory resources is
The BIOS is allocated and written to the bar in the configuration space of the PCI Card. The physical addresses of the I/O memory resources of the ISA card are mapped to the 640kb-1mb range through hardware connections. However
The CPU generally does not reserve the virtual address range for the physical addresses of these known peripheral I/O memory resources, because they are known after the system is started (in a sense dynamic ),
Instead of directly accessing I/O memory resources through physical addresses, you must map them to the core virtual address space (through the page table ), then, according to the core virtual address range obtained by the ing
Access these I/O memory resources.
3.6.1 ing I/O memory resources
Linux declares the ioremap () function in the IO. h header file to map the physical address of the I/O memory resource to the core virtual address space (3 GB-4 GB), as follows:
Void * ioremap (unsigned long phys_addr, unsigned long size,
Unsigned long flags );
Void iounmap (void * ADDR );
The function is used to cancel the Iing made by ioremap (). The ADDR parameter is a pointer to the core virtual address. Both functions are implemented in the mm/ioremap. c file. For specific implementation, refer to "Situational Analysis.
3.6.2 read/write I/O memory resources
After ing the physical address of the I/O memory resources into the core virtual address, theoretically we can directly read and write the I/O memory resources like the read/write Ram. However
The memory and system memory have different access processing. Therefore, to ensure cross-platform compatibility, Linux implements a series of functions for reading and writing I/O memory resources, these functions have different implementations on different platforms.
However, on the X86 platform, there is no difference between read/write I/O memory and read/write Ram. As shown below (include/asm-i386/IO. h ):
# Define readb (ADDR) (* (volatile unsigned char *)
_ Io_virt (ADDR ))
# Define readw (ADDR) (* (volatile unsigned short *)
_ Io_virt (ADDR ))
# Define readl (ADDR) (* (volatile unsigned int *)
_ Io_virt (ADDR ))
# Define writeb (B, ADDR) (* (volatile unsigned char *) _ io_virt (ADDR)
= (B ))
# Define writew (B, ADDR) (* (volatile unsigned short *)
_ Io_virt (ADDR) = (B ))
# Define writel (B, ADDR) (* (volatile unsigned int *) _ io_virt (ADDR)
= (B ))
# Define memset_io (a, B, c) memset (_ io_virt (a), (B), (c ))
# Define memcpy_fromio (a, B, c) memcpy (a) ,__ io_virt (B), (c ))
# Define memcpy_toio (a, B, c) memcpy (_ io_virt (a), (B), (c ))
In the preceding definition, macro _ io_virt () only checks whether the virtual address ADDR is a virtual address in the core space. The implementation of this macro in Kernel 2.4.0 is temporary. The specific implementation functions are in the arch/i386/lib/iodebug. c file.
Obviously, there is no difference between accessing I/O memory resources on the X86 platform and accessing the system's primary Memory RAM. However, to ensure the cross-platform portability of the driver, we should use the above function to access the I/O memory resources, instead of accessing it by pointing to the core virtual address.