歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

IO管理二IORESOURCE_IO和IORESOURCE_MEM

內核中有很多資源,但屬於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() 函數中進行

Copyright © Linux教程網 All Rights Reserved