一、 ioremap() 函數基礎概念 幾乎每一種外設都是通過讀寫設備上的相關寄存器來進行的,通常包括控制寄存器、狀態寄存器和數據寄存器三大類,外設的寄存器通常被連續地編址。根據CPU體繫結構的不同,CPU對IO埠的編址方式有兩種: a -- I/O 映射方式(I/O-mapped) 典型地,如X ...
一、 ioremap() 函數基礎概念
幾乎每一種外設都是通過讀寫設備上的相關寄存器來進行的,通常包括控制寄存器、狀態寄存器和數據寄存器三大類,外設的寄存器通常被連續地編址。根據CPU體繫結構的不同,CPU對IO埠的編址方式有兩種:
a -- I/O 映射方式(I/O-mapped)
典型地,如X86處理器為外設專門實現了一個單獨的地址空間,稱為"I/O地址空間"或者"I/O埠空間",CPU通過專門的I/O指令(如X86的IN和OUT指令)來訪問這一空間中的地址單元。
b -- 記憶體映射方式(Memory-mapped)
RISC指令系統的CPU(如ARM、PowerPC等)通常只實現一個物理地址空間,外設I/O埠成為記憶體的一部分。此時,CPU可以象訪問一個記憶體單元那樣訪問外設I/O埠,而不需要設立專門的外設I/O指令。
但是,這兩者在硬體實現上的差異對於軟體來說是完全透明的,驅動程式開發人員可以將記憶體映射方式的I/O埠和外設記憶體統一看作是"I/O記憶體"資源。
一般來說,在系統運行時,外設的I/O記憶體資源的物理地址是已知的,由硬體的設計決定。但是CPU通常並沒有為這些已知的外設I/O記憶體資源的物理地址預定義虛擬地址範圍,驅動程式並不能直接通過物理地址訪問I/O記憶體資源,
而必須將它們映射到核心虛地址空間內(通過頁表),然後才能根據映射所得到的核心虛地址範圍,通過訪內指令訪問這些I/O記憶體資源。
Linux在io.h頭文件中聲明瞭函數ioremap(),用來將I/O記憶體資源的物理地址映射到核心虛地址空間(3GB-4GB)中(這裡是內核空間),原型如下:
1、ioremap函數
ioremap巨集定義在asm/io.h內:
#define ioremap(cookie,size) __ioremap(cookie,size,0)
__ioremap函數原型為(arm/mm/ioremap.c):
void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);
參數:
phys_addr:要映射的起始的IO地址
size:要映射的空間的大小
flags:要映射的IO空間和許可權有關的標誌
該函數返回映射後的內核虛擬地址(3G-4G). 接著便可以通過讀寫該返回的內核虛擬地址去訪問之這段I/O記憶體資源。
2、iounmap函數
iounmap函數用於取消ioremap()所做的映射,原型如下:
void iounmap(void * addr);
二、 ioremap() 相關函數解析
在將I/O記憶體資源的物理地址映射成核心虛地址後,理論上講我們就可以象讀寫RAM那樣直接讀寫I/O記憶體資源了。為了保證驅動程式的跨平臺的可移植性,我們應該使用Linux中特定的函數來訪問I/O記憶體資源,而不應該通過指向核心虛地址的指針來訪問。
讀寫I/O的函數如下所示:
a -- writel()
writel()往記憶體映射的 I/O 空間上寫數據,wirtel() I/O 上寫入 32 位數據 (4位元組)。
原型:void writel (unsigned char data , unsigned int addr )
b -- readl()
readl() 從記憶體映射的 I/O 空間上讀數據,readl 從 I/O 讀取 32 位數據 ( 4 位元組 )。
原型:unsigned char readl (unsigned int addr )
具體定義如下:
1 #define readb __raw_readb 2 #define readw(addr) __le16_to_cpu(__raw_readw(addr)) 3 #define readl(addr) __le32_to_cpu(__raw_readl(addr)) 4 #ifndef __raw_readb 5 static inline u8 __raw_readb(const volatile void __iomem *addr) 6 { 7 return *(const volatile u8 __force *) addr; 8 } 9 #endif 10 11 #ifndef __raw_readw 12 static inline u16 __raw_readw(const volatile void __iomem *addr) 13 { 14 return *(const volatile u16 __force *) addr; 15 } 16 #endif 17 18 #ifndef __raw_readl 19 static inline u32 __raw_readl(const volatile void __iomem *addr) 20 { 21 return *(const volatile u32 __force *) addr; 22 } 23 #endif 24 25 #define writeb __raw_writeb 26 #define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr) 27 #define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)