埠的概念:裝置通過系統匯流排上的介面與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...