First, Ioremap () function basic concept
Almost every peripheral is carried out by the relevant registers on the read-write device, typically including control registers, status registers, and data registers, and the registers of the peripherals are usually continuously addressed. Depending on the CPU architecture, there are two ways that the CPU addresses the IO port:
A--I/O mapping mode (i/o-mapped)
Typically, such as the X86 processor specifically implements a separate address space for peripherals, called "I/O address space" or "I/O port space," the CPU accesses address units in this space through specialized I/O directives such as X86 's in and out directives.
B--Memory mapping mode (memory-mapped)
The CPU of a RISC instruction system (such as ARM, PowerPC, etc.) typically implements only one physical address space, and the peripheral I/O port becomes part of the memory. At this point, the CPU can access the peripheral I/O port as if it were accessing a memory unit without having to set up specialized peripheral I/O instructions.
However, the difference in hardware implementation is completely transparent to the software, and driver developers can treat the I/O port and peripheral memory as a "I/O Memory" resource in the memory-mapped way.
In general, when the system is running, the physical address of the peripheral's I/O memory resources is known and is determined by the hardware design. However, the CPU usually does not have a predefined virtual address range for the physical address of these known peripheral I/O memory resources, and the driver does not have access to the I/O memory resources directly through the physical address.
Instead, they must be mapped to the core virtual address space (through the page table) before accessing the I/O memory resources through the inbound instruction based on the core virtual address range obtained by the mapping.
Linux declares the function Ioremap () in the IO.h header file to map the physical address of the I/O memory resource to the core virtual address space (3GB-4GB) (here is the kernel space), and the prototype is as follows:
1. Ioremap function
IOREMAP macros are defined within Asm/io.h:
#define IOREMAP (cookie,size) __ioremap (cookie,size,0)
__ioremap function prototype is (ARM/MM/IOREMAP.C):
void __iomem * __IOREMAP (unsigned long phys_addr, size_t size, unsigned long flags);
Parameters:
PHYS_ADDR: The starting IO address to be mapped
Size: The amount of space to map
Flags: Flags about the IO space and permissions to map
The function returns the mapped kernel virtual address (3g-4g). This I/O memory resource can then be accessed by reading and writing to the returned kernel virtual address.
2. Iounmap function
The Iounmap function is used to cancel the mapping made by Ioremap () as follows:
void Iounmap (void * addr);
Second, ioremap () Correlation function Analysis
After the physical address of the I/O memory resource is mapped to a core virtual address, we can theoretically read and write the I/O memory resources as read and write Ram. To ensure cross-platform portability of drivers, we should use specific functions in Linux to access I/O memory resources rather than through pointers to the core virtual addresses .
The functions for reading and writing I/O are as follows:
A--Writel ()
Writel () writes data to the memory-mapped I/O space, writing 32-bit data (4 bytes) on the Wirtel () I/O.
Prototype:void Writel (unsigned char data, unsigned int addr)
B--READL ()
READL () reads data from the memory-mapped I/O space, Readl 32-bit data (4 bytes) from I/O.
Prototype:unsigned char readl (unsigned int addr)
It is defined as follows:
1 #defineREADB __raw_readb2 #defineREADW (addr) __le16_to_cpu (__RAW_READW (addr))3 #defineReadl (addr) __le32_to_cpu (__raw_readl (addr))4 #ifndef __raw_readb5 StaticInline U8 __raw_readb (Const volatile void__iomem *addr)6 {7 return*(Const volatileU8 __force *) addr;8 }9 #endifTen One #ifndef __RAW_READW A StaticInline U16 __RAW_READW (Const volatile void__iomem *addr) - { - return*(Const volatileU16 __force *) addr; the } - #endif - - #ifndef __raw_readl + StaticInline U32 __raw_readl (Const volatile void__iomem *addr) - { + return*(Const volatileU32 __force *) addr; A } at #endif - - #defineWriteb __raw_writeb - #defineWritew (B,ADDR) __raw_writew (__cpu_to_le16 (b), addr) - #defineWritel (B,ADDR) __raw_writel (__cpu_to_le32 (b), addr)
Linux character device driver--ioremap () function parsing