核心中有很多資源,但屬于IO資源的有:
#define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800
本文我主要研究IORESOURCE_IO IORESOURCE_MEM,及位址空間的管理,涉及的檔案隻有kernel/resource.c.
這兩種資源本質上都是一段位址空間. 隻是類型不一樣
IORESOURCE_IO 指的是IO位址空間,這個空間從kernel程式設計上來看,隻能通過專門的接口函數才能通路.硬體層面上,cpu需要用特殊指令才能通路或需要用特殊通路方式才能通路,不能直接用指針來尋址.在PC機上,其指的就是PCI/CPU IO address space.在嵌入式中,基本上沒有io address space.
IORESOURCE_MEM 指的是屬于外設或者用于和裝置通訊的支援直接尋址的位址空間.PC機上,主機闆上北橋上連的記憶體都是交給kernel直接管理,或者都是用于軟體執行,是以這部分記憶體不屬于IORESOURCE_MEM, IORESOURCE_MEM主要是指PCI裝置的 memory address space. 但在嵌入式上, 主機闆上的sdram一般是裝置與cpu共享的. 故交給kernel直接管理的記憶體隻是一部分.餘下的記憶體以及寄存器空間都作為IORESOURCE_MEM來管理.
隻是以需要管理,是因為像PCI總路線裝置的這些位址空間是裝置向系統申請的,故是可配置的,并且裝置并身可能熱插撥或更換,故其變成一種可配置設定的資源. 故核心用算法來管理配置設定與釋放操作,防止沖突和便于查詢維護.但實際PC中,BIOS一般會做配置設定操作,核心需要是把配置設定結果添加進來,故提供了注冊(或者叫做添加)接口. 在嵌入式系統中,外設的位址也通常是固定的,隻需要添加即可.
這兩種資源,核心采用同樣的管理算法--二叉樹.相當于核心維護兩個獨立的二叉樹. 按位址基位址與位址長度範圍作為管理資料.可以添加,配置設定,釋放節點.配置設定過程中可以避
免空間沖突,添加時可以識别空間沖突.根節點在kernel/resource.c中以全局變量方式定義.根節點用于限制位址空間的範圍.
主要接口:
int insert_resource(struct resource *parent, struct resource *new)
int adjust_resource(struct resource *res, unsigned long start, unsigned long size)
int allocate_resource(struct resource *root, struct resource *new,
unsigned long size,
unsigned long min, unsigned long max,
unsigned long align,
void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data)
int release_resource(struct resource *old)
int request_resource(struct resource *root, struct resource *new)
上面的接口對上述4種資源類型都有效,對于IORESOURCE_IO 和 IORESOURCE_MEM這兩種資源,使用這兩個接口更為友善
request_region(start,n,name)
release_region(start,n)
io space
request_mem_region(start,n,name)
release_mem_region(start,n)
mem space
在 /proc 檔案系統中,ioports和iomem分别顯示系統目前這兩種資源.
嵌入式裝置的外設一般先作為platform device添加到platform bus上,其主要目的就是向系統注冊資源,在platform_add_devices時做,
如:
static struct resource wdt_resource[] = {
[0] = {
.start = 0xFFC00008,
.end = 0xFFC00010,
.flags = IORESOURCE_MEM,
}
};
struct platform_device wdt_device = {
.name = "wdt",
.id = -1,
.num_resources = ARRAY_SIZE(wdt_resource),
.resource = wdt_resource,
};
platform_add_devices(wdt_device,1);
故如已知裝置的實體位址,并不一定需要request_mem_region,因為這個操作并沒有涉及到任何硬體,與軟體通路也沒有任何關系..但一般還是推薦做.
I/O port 通路流程( 不用mem模拟方式):
request_region() #在裝置驅動子產品加載或opn() 函數中進行,實體i/o port位址由pci bios子產品配置設定
inb(),outb()等 #在裝置驅動初始化,write(),red(),ioctl() 等函數中進行
relase_region #在裝置驅動子產品解除安裝或release() 函數中進行
I/O port 通路流程( 用mem模拟方式):
request_region()
ioport_map #在裝置驅動子產品加載或opn() 函數中進行,實體i/o port位址由pci bios子產品配置設定
ioread8,iowrite8等 #在裝置驅動初始化,write(),red(),ioctl() 等函數中進行
ioport_unmap()
relase_region #在裝置驅動子產品解除安裝或release() 函數中進行
request_mem_region
ioremap #在裝置驅動子產品加載或opn() 函數中進行,實體i/o port位址由pci bios子產品配置設定
ioread8,iowrite8等 #在裝置驅動初始化,write(),red(),ioctl() 等函數中進行
iounmap()
relase_region #在裝置驅動子產品解除安裝或release() 函數中進行