天天看點

什麼是I/O記憶體?

什麼是IO記憶體

I/O記憶體也稱為Memory-Mapped I/O(MMIO), 它是指一種編址方式,不同cpu平台使用的編址方式不同,一種是“IO記憶體”方式,也叫統一編址方式,是指記憶體和外設的位址是在同一個位址空間上的,比如我們常見的ARM、MIPS等平台;還有另外一種叫獨立編址方式,是指記憶體的位址空間和外設的位址空間是分開的,比如x86平台。

Linux I/O記憶體 API

(1) IO記憶體申請

要使用某個外設前,要申請其所對應的IO記憶體,表明驅動要通路這塊區域。

//申請IO記憶體
/*
start: 該IO的位址相當與實體位址
n: 申請IO數量,必須是start起始位址連續 len個位元組
nane: 裝置名稱或者IO端口名稱,用以标記該端口被誰使用
*/
#define request_mem_region(start,n,name)\
    __request_region(&iomem_resource, (start), (n), (name), 0)
    
#define devm_request_mem_region(dev,start,n,name)\
  __devm_request_region(dev, &iomem_resource, (start), (n), (name))
     
//釋放IO記憶體
#define release_mem_region(start,n)\
    __release_region(&iomem_resource, (start), (n))

#define devm_release_mem_region(dev, start, n)\
  __devm_release_region(dev, &iomem_resource, (start), (n))      

(2)IO記憶體通路

在核心中通路IO記憶體(通常是晶片内部的各個I2C,SPI, USB等控制器的寄存器或者外部記憶體總線上的裝置)之前,需首先使用ioremap()函數将裝置所處的實體位址映射到虛拟位址上。

//将實體位址映射為虛拟位址
void __iomem *ioremap(unsigned long phys_addr, unsigned long size)
void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
         unsigned long size)
      
//申請IO記憶體并進行重映射(将實體位址映射為虛拟位址)
//它對devm_request_mem_region()和devm_ioremap()進行了封裝,内部會調用這兩個函數  
void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res)

//對裝置記憶體映射的虛拟位址進行讀寫
//讀8bit , 16bit, 32bit
#define readb(c)         ({ u8  __v = readb_relaxed(c); __iormb(); __v; })
#define readw(c)         ({ u16__v = readw_relaxed(c); __iormb(); __v; })
#define readl(c)        ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
//寫8bit , 16bit, 32bit
#define writeb(v,c)         ({ __iowmb(); writeb_relaxed(v,c); })
#define writew(v,c)         ({ __iowmb(); writew_relaxed(v,c); })
#define writel(v,c)         ({ __iowmb(); writel_relaxed(v,c); })      

驅動通路IO記憶體流程

1)調用request_mem_region()申請I/O記憶體資源。

2)将裝置寄存器的實體位址通過ioremap()映射到核心空間的虛拟位址。

3)通過readb/writeb等接口通路裝置的寄存器。

4)通路完成後,調用iounmap()函數對ioremap()映射的虛拟位址解除映射,并調用release_mem_region()函數釋放申請的I/O記憶體資源。

繼續閱讀