ARM是對記憶體空間和IO空間統一編址的,所以,通過讀寫SFR來控制硬體也就變成了通過讀寫相應的SFR地址來控制硬體。這部分地址也被稱為 I/O記憶體 。x86中對I/O地址和記憶體地址是分開編址的,這樣的IO地址被稱為 I/O埠 。本文只討論IO記憶體的訪問 IO記憶體訪問流程 我們知道,為了管理最重要的 ...
ARM是對記憶體空間和IO空間統一編址的,所以,通過讀寫SFR來控制硬體也就變成了通過讀寫相應的SFR地址來控制硬體。這部分地址也被稱為I/O記憶體。x86中對I/O地址和記憶體地址是分開編址的,這樣的IO地址被稱為I/O埠。本文只討論IO記憶體的訪問
IO記憶體訪問流程
我們知道,為了管理最重要的系統資源並讓物理地址對進程透明,Linux使用了記憶體映射機制,就是一個進程如果想訪問一個物理記憶體地址(eg.SFR地址),那麼首先就是將其映射成虛擬地址。
IO記憶體申請/歸還
Linux提供一組函數用於申請和釋放IO記憶體的範圍,這兩個API在訪問IO記憶體的時候並不是必須的,但是建議使用,他們可以檢查申請的資源是否可用,增加IO訪問的安全性,如果可用則申請成功,並標誌為已用,其他驅動想在這個進程歸還資源前申請就會失敗。
request_mem_region()巨集函數向記憶體申請n個記憶體地址,這些地址從first開始,len長,name表示設備的名稱,成功返回非NULL失敗返回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)
release_mem_region()巨集函數顧名思義就是將request_mem_region()申請的IO記憶體資源歸還給內核以便其他進程也可以訪問該IO記憶體。
/**
* 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記憶體映射/去映射
申請了IO資源,接下來就是進行物理地址到虛擬地址的映射。內核提供的API如下
static inline void __iomem *ioremap(unsigned long port, unsigned long size)
static inline void iounmap(volatile void __iomem *addr)
IO記憶體訪問API
ARM的SFR是32bit的,我們在經過了ioremap之後其實就可以直接通過強制類型轉換來讀取獲取的虛擬地址,但是這種方法不夠安全,一不小心就會讀錯位,為此,內核同樣提供的標準的API來讀寫IO記憶體,不但代碼的安全性更高,可讀性也得到了改善。
讀IO
unsigned int ioread8(void *addr)
unsigned int ioread16(void *addr)
unsigned int ioread32(void *addr)
寫IO
void iowrite8(u8 val,void *addr)
void iowrite16(u8 val,void *addr)
void iowrite32(u8 val,void *addr)
讀一串IO記憶體
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)
寫一串IO記憶體
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)
複製IO記憶體
void memcpy_fromio(void *dest,void *source,unsigned long len)
void memcpy_toio(void *dest,void *source,unsigned long len)
設置IO記憶體
void memset_io(void *addr,u8 value,unsigned int len)