一、 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 )
引用https://www.cnblogs.com/kazuki/p/9341414.html