Linux驅動技術 二 訪問I O記憶體

2021-09-23 06:56:17 字數 2876 閱讀 3777

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 

intioread8(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 

intlen)  

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...