I O埠與I O記憶體

2022-09-17 06:30:11 字數 4516 閱讀 4769

埠的概念:裝置通過系統匯流排上的介面與cpu相連,介面電路中含有多種暫存器,cpu向裝置讀寫資料實際上是向介面上的暫存器讀寫資料,這些暫存器稱為i/o埠。乙個介面通常包含控制埠,資料埠,狀態埠。

對於x86平台,實體地址就是匯流排位址。

linux中,程序中的4gb虛擬記憶體分為使用者空間和核心空間,使用者空間0-3gb,剩下的1gb為核心空間。程式設計師只能使用虛擬位址,系統中的每個程序都有自己的私有使用者空間(0-3gb),這個空間對其他程序時不可見的。

埠編址方式:

對外設的讀寫都是通過讀寫介面上的暫存器來完成的。埠的編址方式有兩種:統一編址和獨立編址

linux將記憶體對映方式和i/o對映方式的i/o埠通稱為i/o區域,無論採用那種編址方式都需要先申請i/o區域

pc架構一共有65536個8bit的i/o埠,組成64ki/o位址

空間,編號從0~0xffff。連續兩個8bit的端

口可以組成乙個16bit的埠,連續4個組成乙個32bit的埠。

i/o位址空間和cpu的實體地址空間是兩個不同的概念,例如i/o位址空間為64k,乙個32bit的cpu實體地址空間是4g

。i/o埠的操作:

申請i/o埠:

/*request_region告訴核心:要使用first開始的n個埠。引數name為裝置名。

如果分配成功返回值是非null;否則無法使用需要的埠

(/proc/ioports包含了系統當前所有埠的分配資訊,

若request_region分配失敗時,可以檢視該檔案,看誰先用了你要的埠)

*/struct resource *request_region(unsigned long first, unsigned long n, const

char *name);

訪問i/o埠:

linux 核心標頭檔案(體系依賴的標頭檔案) 定義了下列內聯函式來訪問i/o埠

/*inb/outb:讀/寫位元組埠(8位寬)。有些體系將port引數定義為unsigned long;而有些平台則將它定義為unsigned short。inb的返回型別也是依賴體系的

*/unsigned inb(unsigned port);

void outb(unsigned char

byte, unsigned port)

/*inw/outw:讀/寫字埠(16位寬)

*/unsigned inw(unsigned port);

void outw(unsigned short word, unsigned port);

/*inl/outl:讀/寫32位埠。longword也是依賴體系的,有的體系為unsigned long;而有的為unsigned int

*/unsigned inl(unsigned port);

void outl(unsigned longword, unsigned port);

釋放i/o埠:

/*用完i/o埠後(可能在模組解除安裝時),應當呼叫release_region將i/o埠返還給系統。引數start和n應與之前傳遞給request_region一致

*/void release_region(unsigned long start, unsigned long n);

i/o記憶體的操作:

根據計算機體系和匯流排不同,i/o 記憶體可分為可以或者不可以通過頁表來訪問。

若通過頁表訪問,核心必須先重新編排實體地址,使其對驅動程式可見,這就意味著在進行任何i/o操作之前,你必 須呼叫ioremap;

如果不需要頁表,i/o記憶體區域就類似於i/o埠,你可以直接使用適當的i/o函式讀寫它們。

申請i/o記憶體:

i/o 記憶體區在使用前必須先分配。分配記憶體區的函式介面在中定

/*request_mem_region 分配乙個始於start ,len位元組的i/o記憶體

分配成功,返回乙個非null指標,失敗則放回null

系統當前所有i/o記憶體分配資訊都在/proc/iomem檔案中列出,你分配失敗時,可以看看該檔案,看誰先占用了該記憶體區

*/struct resource *request_mem_region(unsigned long start, unsigned long len, char *name);

對映:在訪問i/o記憶體之前,分配i/o記憶體並不是唯一要求的步驟,你還必須保證核心可訪問該i/o記憶體。

訪問i/o記憶體並不只是簡單解引用指標,在許多體系中,i/o 記憶體無法以這種方式直接訪問。

因此,還必須通過ioremap 函式設定乙個對映。

/*ioremap用於將i/o記憶體區對映到虛擬位址。引數phys_addr為要對映的i/o記憶體起始位址,引數size為要對映的i/o記憶體的大小,返回值為被對映到的虛擬位址

*/void *ioremap(unsigned long phys_addr, unsigned long size);

i/o記憶體訪問:

經過 ioremap之後,裝置驅動就可以訪問任何i/o記憶體位址。

ioremap返回的位址不可以直接解引用,應當使用核心提供的訪問函式。

訪問i/o記憶體的正確方式是通過一系列專門用於實現此目的的函式:

#include

/*i/o記憶體讀函式。引數addr應當是從ioremap獲得的位址(可能包含乙個整型偏移); 返回值是從給定i/o記憶體讀取到的值

*/unsigned int ioread8(void *addr);

unsigned int ioread16(void *addr);

unsigned int ioread32(void *addr)

/*i/o記憶體寫函式。引數addr同i/o記憶體讀函式,引數value為要寫的值

*/void iowrite8(u8 value, void *addr);

void iowrite16(u16 value, void *addr);

void iowrite32(u32 value, void *addr);

/*以下這些函式讀和寫一系列值到乙個給定的 i/o 記憶體位址,從給定的buf讀或寫count個值到給定的addr。引數count表示要讀寫的資料個數,而不是位元組大小

*/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 位址時,使用下列函式(這些函式的行為類似於它們的c庫類似函式):

*/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記憶體讀寫函式,不推薦使用

*/unsigned readb(address);

unsigned readw(address);

unsigned readl(address);

void writeb(unsigned value, address);

void writew(unsigned value, address);

void writel(unsigned value, address);

i/o記憶體釋放:

void iounmap(void * addr); /*

iounmap用於釋放不再需要的對映

*/void release_mem_region(unsigned long start, unsigned long len); /*

iounmap用於釋放不再需要的對映 */

像i/o記憶體一樣使用i/o埠

/*ioport_map重新對映count個i/o埠,使它們看起來i/o記憶體。

此後,驅動程式可以在ioport_map返回的位址上使用ioread8和同類函式

這樣,就可以在程式設計時,消除了i/o 埠和i/o 記憶體的區別

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

void ioport_unmap(void *addr);/*

ioport_unmap用於釋放不再需要的對映

*/

I O埠和I O記憶體

每種外設都通過讀寫暫存器進行控制,大部分外設都有幾個暫存器,不管在記憶體位址空間還是在i o位址空間,這些暫存器的訪問位址是連續的。在硬體層,記憶體區域和io區域沒有概念上的區別 他們都通過向位址匯流排和控制匯流排傳送電平訊號進行訪問,再通過資料匯流排讀寫資料。儘管硬體暫存器和記憶體非常相似,但程式...

Linux I O埠與I O記憶體

一 io埠訪問 1 直接使用io埠操作函式 1 在裝置開啟或驅動模組被載入時申請io埠區域,之後使用inb outb 等進行埠訪問,最後在裝置關閉或驅動被解除安裝時釋放io埠範圍。流程如下 2 struct resource request region unsigned long first,un...

IO埠與記憶體空間

1 關於io與記憶體空間 在x86處理器中存在著i o空間的概念,i o空間是相對於記憶體空間而言的,它通過特定的指令in out來訪問。埠號標識了外設的暫存器位址。intel語法的in out指令格式為 in 累加器,out 累加器 目前,大多數嵌入式微控制器如arm powerpc等中並不提供i...