內核中有很多資源,但屬於IO資源的有:
#define IORESOURCE_IO 0x00000100 /* Resource type */
#defineIORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800
本文我主要研究IORESOURCE_IOIORESOURCE_MEM,及地址空間的管理,涉及的文件只有kernel/resource.c.
這兩種資源本質上都是一段地址空間. 只是類型不一樣
IORESOURCE_IO指的是IO地址空間,這個空間從kernel編程上來看,只能通過專門的接口函數才能訪問.硬件層面上,cpu需要用特殊指令才能訪問或需要用特殊訪問方式才能訪問,不能直接用指針來尋址.在PC機上,其指的就是PCI/CPU
IO addressspace.在嵌入式中,基本上沒有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, structresource *new)
int adjust_resource(struct resource *res, unsignedlong start, unsigned long size)
int allocate_resource(struct resource *root, structresource *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, structresource *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添加到platformbus上,其主要目的就是向系統注冊資源,在platform_add_devices時做,
如:
/* Watchdog timer parameters */
static struct resource wdt_resource[] = {
/* Watchdog timeronly needs a register address */
[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() 函數中進行