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如下
staticinline void __iomem *ioremap(unsigned long port, unsigned long
size
)
staticinline void iounmap(volatile void __iomem *addr)
io記憶體訪問api
arm的sfr是32bit的,我們在經過了ioremap之後其實就可以直接通過強制型別轉換來讀取獲取的虛擬位址,但是這種方法不夠安全,一不小心就會讀錯位,為此,核心同樣提供的標準的api來讀寫io記憶體,不但**的安全性更高,可讀性也得到了改善。
讀io
unsignedintioread8(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,unsignedintlen)
Linux 驅動分類 與訪問技術
驅動開發概述 1.驅動分類 1.1 常規分析法 1.1.1 字元裝置 字元裝置是一種按位元組來訪問的裝置,字元驅動則負責驅動字元裝置,這樣的驅動通常實現open,close,read和write 系統呼叫。例 串列埠,led,按鍵。1.1.2 塊裝置 在大部分的unix系統中,塊裝置定義為 以塊 通...
Linux字元驅動 IO模型
實現方法 一 手動實現 定義乙個等待佇列頭,並初始化等待佇列頭 wait queue head t wq init waitqueue head wq 定義乙個等待佇列項,新增等待佇列項到等待佇列 declare waitqueue r wait,current r wait表示等待佇列項的名稱,c...
Linux 記憶體與I O訪問
linux 記憶體分類 由於複雜的記憶體管理功能,記憶體的概念也相對複雜,有常規記憶體,高階記憶體,虛擬位址,邏輯位址,匯流排位址,實體地址,i o記憶體,裝置記憶體,預留記憶體等。高階處理器一般會提供mmu 記憶體管理單元 mmu具有虛擬位址和實體地址轉換,記憶體訪問許可權保護等功能,為了理解mm...