<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > [ARM筆記](méi)設備IO端口和IO內存的訪(fǎng)問(wèn)

[ARM筆記](méi)設備IO端口和IO內存的訪(fǎng)問(wèn)

作者: 時(shí)間:2016-12-05 來(lái)源:網(wǎng)絡(luò ) 收藏

  設備通常會(huì )提供一組寄存器來(lái)用于控制設備、讀寫(xiě)設備和獲取設備狀態(tài),即控制寄存器、數據寄存器和狀態(tài)寄存器。這些寄存器可能位于IO空間,也可能位于內存空間。當位于IO空間時(shí),通常被稱(chēng)為IO端口,位于內存空間時(shí),對應的內存空間成為IO內存。

本文引用地址:http://dyxdggzs.com/article/201612/341120.htm

  1.  IO端口和IO內存訪(fǎng)問(wèn)接口

  1.1 IO端口

  在設備驅動(dòng)中,應使用內核提供的函數來(lái)訪(fǎng)問(wèn)定位于IO空間的端口,這些函數包括如下幾種:

  (1)讀寫(xiě)字節端口(8位寬)

  unsigned inb(unsigned port);

  void outb(unsigned char byte , unsigned port);

  (2)讀寫(xiě)字端口(16位寬)

  unsigned inw(unsigned port);

  void outw(unsigned char byte , unsigned port);

  (3)讀寫(xiě)長(cháng)字端口(32位寬)

  unsigned inl(unsigned port);

  void outl(unsigned char byte , unsigned port);

  (4)讀寫(xiě)一串字

  void insw(unsigned port , void *addr , unsigned long count);

  void outsw(unsigned port , void *addr , unsigned long count);

  (5)讀寫(xiě)一串長(cháng)字

  void insl(unsigned port , void *addr , unsigned long count);

  void outsl(unsigned port , void *addr , unsigned long count);

  上述各函數中IO端口號port的類(lèi)型高度依賴(lài)于具體的硬件平臺,因此,只是寫(xiě)出了unsigned。

  1.2 IO內存

  在內核中訪(fǎng)問(wèn)IO內存之前,需首先使用ioremap()函數將設備所處的物理地址映射到虛擬地址。ioremap的原型如下:

  void *ioremap(unsigned long offset , unsigned long size);

  ioremap()與vmalloc()類(lèi)似,也需要建立新的頁(yè)表,但是它并不進(jìn)行vmalloc()中所執行的內存分配行為。ioremap()返回一個(gè)特殊的虛擬地址,該地址可用來(lái)存取特定的物理地址范圍。通過(guò)ioremap()獲得的虛擬地址應該被iounmap()函數釋放,其原型為:

  void iounmap(void *addr);

  在設備的物理地址被映射到虛擬地址之后,盡管可以直接通過(guò)指針訪(fǎng)問(wèn)這些地址,但是可以使用Linux內核的如下一組函數來(lái)完成設備內存映射的虛擬地址的讀寫(xiě),這些函數如下所示。

  (1)讀IO內存

  unsigned int ioread8(void *addr);

  unsigned int ioread16(void *addr);

  unsigned int ioread32(void *addr);

  與上述函數對應的較早版本的函數為(這些函數在Linux2.6中仍然被支持):

  unsigned readb(address);

  unsigned readw(address);

  unsigned readl(address);

  (2)寫(xiě)IO內存

  void iowrite8(u8 value , void *addr);

  void iowrite16(u16 value , void *addr);

  void iowrite32(u32 value , void *addr);

  與上述函數對應的較早版本的函數為(這些函數在Linux2.6中仍然被支持):

  unsigned writeb(address);

  unsigned writew(address);

  unsigned writel(address);

  (3)讀一串IO內存

  void ioread8_rep(void *addr , void *buf , unsigned long count);

  void ioread16_rep(void *addr , void *buf , unsigned long count);

  void ioread32_rep(void *addr , void *buf , unsigned long count);

  (4)寫(xiě)一串IO內存

  void iowrite8_rep(void *addr , void *buf , unsigned long count);

  void iowrite16_rep(void *addr , void *buf , unsigned long count);

  void iowrite32_rep(void *addr , void *buf , unsigned long count);

  (5)復制IO內存

  void memcpy_fromio(void *dest , void *source , unsigned int count);

  void memcpy_toio(void *dest , void *source , unsigned int count);

  (6)設置IO內存

  void memset_io(void *addr , u8 value , unsigned int count);

  1.3 把IO端口映射到內存空間

  void *ioport_map(unsigned long port , unsigned int count);

  通過(guò)這個(gè)函數,可以把port開(kāi)始的count個(gè)連續的IO端口重映射為一段“內存空間”。然后就可以在其返回的地址上像訪(fǎng)問(wèn)IO內存一樣訪(fǎng)問(wèn)這些IO端口。當不再需要這種映射時(shí),需要調用下面的函數來(lái)撤銷(xiāo)。

  void ioport_unmap(void *addr);

  實(shí)際上,分析ioport_map()的源代碼可發(fā)現,映射到內存空間行為實(shí)際上是給開(kāi)發(fā)人員制造的一個(gè)“假象”,并沒(méi)有映射到內核虛擬地址,僅僅是為了讓工程師可使用統一的IO內存訪(fǎng)問(wèn)接口訪(fǎng)問(wèn)IO端口。

  2. 申請與釋放設備IO端口和IO內存

  2.1 IO端口申請

  Linux內核提供了一組函數用于申請和釋放IO端口。

  struct resource *request_region(resource_size_t start, resource_size_t n, const char *name);

  這個(gè)函數向內核申請了n個(gè)端口,這些端口從first開(kāi)始,name參數為設備的名稱(chēng)。如果分配成功返回非NULL,失敗,則返回NULL。

  當用request_region()申請的IO端口使用完成后,應當使用release_region()函數將它們還給系統,這個(gè)函數的原型如下:

  void release_region(resource_size_t start , resource_size_t n);

  2.2 IO內存申請

  Linux內核提供了一組函數用于申請和釋放IO內存的范圍。

  struct resource *request_mem_region(resource_size_t start, resource_size_t n, const char *name, const char *name);

  這個(gè)函數向內核申請n個(gè)內存地址,這些地址從first開(kāi)始,name參數為設備的名稱(chēng)。如果分配成功返回值是非NULL,如果失敗,返回NULL。

  當用request_mem_region()申請的IO內存使用完成后,應當使用release_region()函數將它們還給系統,這個(gè)函數的原型如下:

  void release_region(resource_size_t start , resource_size_t n);

  上述request_region()和release_mem_region()都不是必須的,但建議使用。其任務(wù)是檢查申請的資源是否可用,如果可用則申請成功,并標志為已經(jīng)使用,其他驅動(dòng)想再次申請該資源就會(huì )失敗。

  查看內核源碼可知,request_region()和request_mem_region()調用的函數是一樣的,只是傳入參數的不同。

  #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))

  #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))

  3. 設備IO端口和IO內存訪(fǎng)問(wèn)流程

  IO端口訪(fǎng)問(wèn)的一種途徑是直接使用IO端口操作函數:在設備打開(kāi)或驅動(dòng)模塊被加載時(shí)申請IO端口區域,之后使用inb()、outb()等進(jìn)行端口訪(fǎng)問(wèn),最后,在設備關(guān)閉或驅動(dòng)被卸載時(shí)釋放IO端口范圍。

  ___________________________

  | |

  | request_region() | 在設備驅動(dòng)模塊加載或open()函數中進(jìn)行

  |__________________________ |

  |

  ___________________________

  | |

  | inb()、outb()等 | 在設備驅動(dòng)初始化、write()、read()、iotcl()等函數中進(jìn)行

  |__________________________ |

  |

  ___________________________

  | |

  | release_region()等 | 在設備驅動(dòng)模塊卸載或release()函數中進(jìn)行

  |__________________________ |

  IO端口的訪(fǎng)問(wèn)流程(不映射到內存空間)

  IO端口訪(fǎng)問(wèn)的另一種途徑是將IO端口映射為內存進(jìn)行訪(fǎng)問(wèn):在設備打開(kāi)或驅動(dòng)模塊被加載時(shí),申請IO端口區域并使用ioport_map()映射到內存,之后使用IO內存的函數進(jìn)行端口訪(fǎng)問(wèn),最后,在設備關(guān)閉或驅動(dòng)被卸載時(shí)釋放IO端口并釋放映射。整個(gè)流程如下圖所示:

  ___________________________

  | |

  | request_region()等 | 

  |__________________________ | 

  |  在設備驅動(dòng)模塊加載或open()函數中進(jìn)行

  ___________________________ /

  | | /

  | ioport_map()等 |

  |__________________________ |

  |

  ___________________________

  | |

  | ioread8、ioread16、 | 在設備驅動(dòng)初始化、write()、read()、ioctl等函數中調用

  | ioread32、iowrite8等 |

  |__________________________ |

  |

  ___________________________

  | |

  | ioport_unmap() |

  |__________________________ | 

  | 

  ___________________________ /在設備驅動(dòng)卸載或release()函數中調用

  | | /

  | release_region() | /

  |__________________________ |

  IO端口的訪(fǎng)問(wèn)流程(映射到內存空間)

  ___________________________________

  | |

  | request_mem_region()等 | 

  |__________________________________ | 

  |  在設備驅動(dòng)模塊加載或open()函數中進(jìn)行

  __________________________________ /

  | | /

  | ioremap()等 |/

  |__________________________________|

  |

  ___________________________

  | |

  | ioread8、ioread16、 | 在設備驅動(dòng)初始化、write()、read()、ioctl等函數中調用

  | ioread32、iowrite8等 |

  |__________________________ |

  |

  ______________________________

  | |

  | iounmap() | 

  |_____________________________ | 

  | 

  ______________________________ /在設備驅動(dòng)卸載或release()函數中調用

  | | /

  | release_mem_region() | /

  |______________________________|



關(guān)鍵詞: ARM Linux

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>