新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > [ARM筆記]設備IO端口和IO內存的訪問

        [ARM筆記]設備IO端口和IO內存的訪問

        作者: 時間:2016-12-05 來源:網絡 收藏

          設備通常會提供一組寄存器來用于控制設備、讀寫設備和獲取設備狀態,即控制寄存器、數據寄存器和狀態寄存器。這些寄存器可能位于IO空間,也可能位于內存空間。當位于IO空間時,通常被稱為IO端口,位于內存空間時,對應的內存空間成為IO內存。

        本文引用地址:http://www.104case.com/article/201612/341120.htm

          1.  IO端口和IO內存訪問接口

          1.1 IO端口

          在設備驅動中,應使用內核提供的函數來訪問定位于IO空間的端口,這些函數包括如下幾種:

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

          unsigned inb(unsigned port);

          void outb(unsigned char byte , unsigned port);

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

          unsigned inw(unsigned port);

          void outw(unsigned char byte , unsigned port);

          (3)讀寫長字端口(32位寬)

          unsigned inl(unsigned port);

          void outl(unsigned char byte , unsigned port);

          (4)讀寫一串字

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

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

          (5)讀寫一串長字

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

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

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

          1.2 IO內存

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

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

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

          void iounmap(void *addr);

          在設備的物理地址被映射到虛擬地址之后,盡管可以直接通過指針訪問這些地址,但是可以使用Linux內核的如下一組函數來完成設備內存映射的虛擬地址的讀寫,這些函數如下所示。

          (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)寫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)寫一串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);

          通過這個函數,可以把port開始的count個連續的IO端口重映射為一段“內存空間”。然后就可以在其返回的地址上像訪問IO內存一樣訪問這些IO端口。當不再需要這種映射時,需要調用下面的函數來撤銷。

          void ioport_unmap(void *addr);

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

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

          2.1 IO端口申請

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

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

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

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

          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);

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

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

          void release_region(resource_size_t start , resource_size_t n);

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

          查看內核源碼可知,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內存訪問流程

          IO端口訪問的一種途徑是直接使用IO端口操作函數:在設備打開或驅動模塊被加載時申請IO端口區域,之后使用inb()、outb()等進行端口訪問,最后,在設備關閉或驅動被卸載時釋放IO端口范圍。

          ___________________________

          | |

          | request_region() | 在設備驅動模塊加載或open()函數中進行

          |__________________________ |

          |

          ___________________________

          | |

          | inb()、outb()等 | 在設備驅動初始化、write()、read()、iotcl()等函數中進行

          |__________________________ |

          |

          ___________________________

          | |

          | release_region()等 | 在設備驅動模塊卸載或release()函數中進行

          |__________________________ |

          IO端口的訪問流程(不映射到內存空間)

          IO端口訪問的另一種途徑是將IO端口映射為內存進行訪問:在設備打開或驅動模塊被加載時,申請IO端口區域并使用ioport_map()映射到內存,之后使用IO內存的函數進行端口訪問,最后,在設備關閉或驅動被卸載時釋放IO端口并釋放映射。整個流程如下圖所示:

          ___________________________

          | |

          | request_region()等 | 

          |__________________________ | 

          |  在設備驅動模塊加載或open()函數中進行

          ___________________________ /

          | | /

          | ioport_map()等 |

          |__________________________ |

          |

          ___________________________

          | |

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

          | ioread32、iowrite8等 |

          |__________________________ |

          |

          ___________________________

          | |

          | ioport_unmap() |

          |__________________________ | 

          | 

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

          | | /

          | release_region() | /

          |__________________________ |

          IO端口的訪問流程(映射到內存空間)

          ___________________________________

          | |

          | request_mem_region()等 | 

          |__________________________________ | 

          |  在設備驅動模塊加載或open()函數中進行

          __________________________________ /

          | | /

          | ioremap()等 |/

          |__________________________________|

          |

          ___________________________

          | |

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

          | ioread32、iowrite8等 |

          |__________________________ |

          |

          ______________________________

          | |

          | iounmap() | 

          |_____________________________ | 

          | 

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

          | | /

          | release_mem_region() | /

          |______________________________|



        關鍵詞: ARM Linux

        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 泸定县| 吉木萨尔县| 革吉县| 孝感市| 凌源市| 兴化市| 湖南省| 临邑县| 孝感市| 五原县| 工布江达县| 崇明县| 柏乡县| 尖扎县| 景洪市| 西丰县| 石门县| 中卫市| 富锦市| 柘荣县| 丰台区| 通江县| 湟中县| 迁西县| 辽阳县| 明溪县| 铜鼓县| 泰兴市| 上杭县| 同江市| 富川| 关岭| 宕昌县| 双流县| 烟台市| 五家渠市| 成都市| 扬州市| 麻栗坡县| 额济纳旗| 宜宾县|