Linux 字符设备驱动开发基础(五)—— ioremap() 函数解析
一、?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 short addr )
b --?readl()
? ? ? readl() 從內存映射的 I/O 空間上讀數據,readl 從 I/O 讀取 32 位數據 ( 4 字節 )。
?
原型:unsigned char readl (unsigned int addr )
變量 ? ?addr ?是 I/O 地址。
返回值 : 從 I/O 空間讀取的數值。
具體定義如下:
[cpp]?view plaincopy
? ? ? ? 還是拿我們寫PWM驅動的實例來解析
1、這里我們先定義了一些寄存器,這里使用的地址均是物理地址:
[cpp]?view plaincopy
2、為了使用內存映射,我們需先定義指針用來保存內存映射后的地址:
[cpp]?view plaincopy
3、使用ioremap() 函數進行內存映射,并將映射的地址賦給我們剛才定義的指針
[cpp]?view plaincopy4、得到地址后,可以調用 writel() 、readl() 函數進行相應的操作
[cpp]?view plaincopy
可以看到,這里先從相應的地址中讀取數據,修改完畢后,再利用writel函數進行數據寫入。
總結
以上是生活随笔為你收集整理的Linux 字符设备驱动开发基础(五)—— ioremap() 函数解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell脚本中怎样同时执行多个.sql
- 下一篇: Linux 下wifi 驱动开发(三)—