<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è) > 嵌入式系統 > 設計應用 > Linux設備驅動(dòng)之I/O端口與I/O內存

Linux設備驅動(dòng)之I/O端口與I/O內存

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

3.操作IO(申請,映射,訪(fǎng)問(wèn),釋放):

盡管 I/O 在x86世界中非常流行,但是用來(lái)和設備通訊的主要機制是通過(guò)映射的寄存器和設備,兩者都稱(chēng)為I/O 內存,因為寄存器和內存之間的區別對軟件是透明的。

I/O 內存僅僅是一個(gè)類(lèi)似于RAM 的區域,處理器通過(guò)總線(xiàn)訪(fǎng)問(wèn)該區域,以實(shí)現對設備的訪(fǎng)問(wèn)。同樣,讀寫(xiě)這個(gè)區域是有邊際效應。

根據計算機體系和總線(xiàn)不同,I/O 內存可分為可以或者不可以通過(guò)頁(yè)表來(lái)存取。若通過(guò)頁(yè)表存取,內核必須先重新編排物理地址,使其對驅動(dòng)程序可見(jiàn),這就意味著(zhù)在進(jìn)行任何I/O操作之前,你必須調用ioremap;如果不需要頁(yè)表,I/O內存區域就類(lèi)似于I/O,你可以直接使用適當的I/O函數讀寫(xiě)它們。

由于邊際效應的緣故,不管是否需要 ioremap,都不鼓勵直接使用I/O內存指針,而應使用專(zhuān)門(mén)的I/O內存操作函數。這些I/O內存操作函數不僅在所有平臺上是安全,而且對直接使用指針操作 I/O 內存的情況進(jìn)行了優(yōu)化。

(1)申請I/O 內存:

I/O 內存區在使用前必須先分配。分配內存區的函數接口在定義中:

/* request_mem_region分配一個(gè)開(kāi)始于start,len字節的I/O內存區。分配成功,返回一個(gè)非NULL指針;否則返回NULL。系統當前所有I/O內存分配信息都在/proc/iomem文件中列出,你分配失敗時(shí),可以看看該文件,看誰(shuí)先占用了該內存區 */struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);

(2)映射:

在訪(fǎng)問(wèn)I/O內存之前,分配I/O內存并不是唯一要求的步驟,你還必須保證內核可存取該I/O內存。訪(fǎng)問(wèn)I/O內存并不只是簡(jiǎn)單解引用指針,在許多體系中,I/O 內存無(wú)法以這種方式直接存取。因此,還必須通過(guò)ioremap 函數設置一個(gè)映射。

/* ioremap用于將I/O內存區映射到虛擬地址。參數phys_addr為要映射的I/O內存起始地址,參數size為要映射的I/O內存的大小,返回值為被映射到的虛擬地址 */void *ioremap(unsigned long phys_addr, unsigned long size);

(3)訪(fǎng)問(wèn)IO內存:

經(jīng)過(guò) ioremap之后,就可以存取任何I/O內存地址。注意,ioremap返回的地址不可以直接解引用;相反,應當使用內核提供的訪(fǎng)問(wèn)函數。訪(fǎng)問(wèn)I/O內存的正確方式是通過(guò)一系列專(zhuān)門(mén)用于實(shí)現此目的的函數:

#include /* I/O內存讀函數。參數addr應當是從ioremap獲得的地址(可能包含一個(gè)整型偏移); 返回值是從給定I/O內存讀取到的值 */unsigned int ioread8(void *addr);unsigned int ioread16(void *addr);unsigned int ioread32(void *addr);/* I/O內存寫(xiě)函數。參數addr同I/O內存讀函數,參數value為要寫(xiě)的值 */void iowrite8(u8 value, void *addr);void iowrite16(u16 value, void *addr);void iowrite32(u32 value, void *addr);/* 以下這些函數讀和寫(xiě)一系列值到一個(gè)給定的 I/O 內存地址,從給定的buf讀或寫(xiě)count個(gè)值到給定的addr。參數count表示要讀寫(xiě)的數據個(gè)數,而不是字節大小 */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);void iowrite8_rep(void *addr, const void *buf, unsigned long count);void iowrite16_rep(void *addr, const void *buf, unsigned long count);void iowrite32_rep(void *addr,,onst void *buf,,nsigned long count);/* 需要操作一塊I/O 地址時(shí),使用下列函數(這些函數的行為類(lèi)似于它們的C庫類(lèi)似函數): */void memset_io(void *addr, u8 value, unsigned int count);void memcpy_fromio(void *dest, void *source, unsigned int count);void memcpy_toio(void *dest, void *source, unsigned int count);/* 舊的I/O內存讀寫(xiě)函數,不推薦使用 */unsigned readb(address);unsigned readw(address);unsigned readl(address); void writeb(unsigned value, address);void writew(unsigned value, address);void writel(unsigned value, address);

(4)釋放IO內存步驟:

void iounmap(void * addr); /* iounmap用于釋放不再需要的映射 */void release_mem_region(unsigned long start, unsigned long len); /* iounmap用于釋放不再需要的映射 */

4、像IO內存一樣使用

一些硬件有一個(gè)有趣的特性: 有些版本使用 I/O 端口;而有些版本則使用 I/O 內存。不管是I/O 端口還是I/O 內存,處理器見(jiàn)到的設備寄存器都是相同的,只是訪(fǎng)問(wèn)方法不同。為了統一編程接口,使驅動(dòng)程序易于編寫(xiě),2.6 內核提供了一個(gè)ioport_map函數:

/* ioport_map重新映射count個(gè)I/O端口,使它們看起來(lái)I/O內存。此后,驅動(dòng)程序可以在ioport_map返回的地址上使用ioread8和同類(lèi)函數。這樣,就可以在編程時(shí),消除了I/O 端口和I/O 內存的區別 */void *ioport_map(unsigned long port, unsigned int count);void ioport_unmap(void *addr);/* ioport_unmap用于釋放不再需要的映射 */

注意,I/O 端口在重新映射前必須使用request_region分配分配所需的I/O 端口。

5、ARM體系的IO操作接口

s3c24x0處理器使用的是I/O內存,也就是說(shuō):s3c24x0處理器使用統一編址方式,I/O寄存器和內存使用的是單一地址空間,并且讀寫(xiě)I/O寄存器和讀寫(xiě)內存的指令是相同的。所以推薦使用I/O內存的相關(guān)指令和函數。但這并不表示I/O端口的指令在s3c24x0中不可用。如果你注意過(guò)s3c24x0關(guān)于I/O方面的內核源碼,你就會(huì )發(fā)現:其實(shí)I/O端口的指令只是一個(gè)外殼,內部還是使用和I/O內存一樣的代碼。注意以下幾點(diǎn):

1)所有的讀寫(xiě)指令(I/O操作函數)所賦的地址必須都是虛擬地址,你有兩種選擇:使用內核已經(jīng)定義好的地址,如在include/asm-arm/arch-s3c2410/regs-xxx.h中定義了s3c2410處理器各外設寄存器地址(其他處理器芯片也可在類(lèi)似路徑找到內核定義好的外設寄存器的虛擬地址;另一種方法就是使用自己用ioremap映射的虛擬地址。絕對不能使用實(shí)際的物理地址,否則會(huì )因為內核無(wú)法處理地址而出現oops。



關(guān)鍵詞: Linux 設備驅動(dòng) 端口 內存

評論


相關(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>