ARM addresses memory space and IO space uniformly, so controlling hardware by reading and writing SFR becomes controlling hardware by reading and writing corresponding SFR address. This part of the address is also known as I/O memory. In x86, I/O addresses and memory addresses are separately addressed. Such IO addresses are called I/O ports. This article only discusses IO memory access.
IO memory access process
We know that in order to manage the most important system resources and make the physical address transparent to the process, Linux uses the memory mapping mechanism, that is, if a process wants to access a physical memory address (eg.SFR address), it first maps it to a virtual address.
IO Memory Request/Return
Linux provides a set of functions for requesting and releasing the scope of IO memory. These two API s are not necessary when accessing IO memory, but it is recommended to use them. They can check whether the requested resources are available and increase the security of IO access. If available, the application succeeds and is marked as used. Other drivers will fail to apply before the process returns the resources.
The request_mem_region() macro function requests n memory addresses from memory. These addresses start at first, len is long, name is the name of the device, and successfully returns non-NULL failures to return NULL.
/** * request_mem_region - create a new busy resource region * @start: resource start address * @n: resource region size * @name: reserving caller's ID string */ struct resource * request_mem_region(resource_size_t start, resource_size_t n,const char *name)
The release_mem_region() macro function, as its name implies, returns the IO memory resources requested by request_mem_region() to the kernel so that other processes can access the IO memory as well.
/** * release_mem_region - release a previously reserved resource region * @start: resource start address * @n: resource region size */ void release_mem_region(resource_size_t start, resource_size_t n,const char *name)
IO memory mapping/de-mapping
I applied for IO resources, and then I mapped the physical address to the virtual address. The API provided by the kernel is as follows
static inline void __iomem *ioremap(unsigned long port, unsigned long size)
static inline void iounmap(volatile void __iomem *addr)
IO Memory Access API
ARM's SFR is 32 bits. After ioremap, we can actually read the acquired virtual address directly by forcing type conversion. But this method is not safe enough. If we do not read it carefully, we will misplace it. Therefore, the standard API provided by the kernel to read and write IO memory is not only more secure, but also more readable.
Read IO
unsigned int ioread8(void *addr) unsigned int ioread16(void *addr) unsigned int ioread32(void *addr)
Write IO
void iowrite8(u8 val,void *addr) void iowrite16(u8 val,void *addr) void iowrite32(u8 val,void *addr)
Read a bunch of IO memory
void ioread8_rep(void *addr,void *buf,unsigned long len) void ioread16_rep(void *addr,void *buf,unsigned long len) void ioread32_rep(void *addr,void *buf,unsigned long len)
Write a bunch of IO memory
void iowrite8_rep(void *addr,const void *buf,unsigned long len) void iowrite16_rep(void *addr,const void *buf,unsigned long len) void iowrite32_rep(void *addr,const void *buf,unsigned long len)
Copy IO memory
void memcpy_fromio(void *dest,void *source,unsigned long len) void memcpy_toio(void *dest,void *source,unsigned long len)
Setting up IO memory
void memset_io(void *addr,u8 value,unsigned int len)