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() 函数中进行

static int sbsa_uart_probe(struct platform_device *pdev) { struct uart_amba_port *uap; struct resource *r; int portnr, ret; int baudrate; /* * Check the mandatory baud rate parameter in the DT node early * so that we can easily exit with the error. */ if (pdev->dev.of_node) { struct device_node *np = pdev->dev.of_node; ret = of_property_read_u32(np, "current-speed", &baudrate); if (ret) return ret; } else { baudrate = 115200; } portnr = pl011_find_free_port(); if (portnr < 0) return portnr; uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), GFP_KERNEL); if (!uap) return -ENOMEM; ret = platform_get_irq(pdev, 0); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "cannot obtain irq\n"); return ret; } uap->port.irq = ret; #ifdef CONFIG_ACPI_SPCR_TABLE if (qdf2400_e44_present) { dev_info(&pdev->dev, "working around QDF2400 SoC erratum 44\n"); uap->vendor = &vendor_qdt_qdf2400_e44; } else #endif uap->vendor = &vendor_sbsa; uap->reg_offset = uap->vendor->reg_offset; uap->fifosize = 32; uap->port.iotype = uap->vendor->access_32b ? UPIO_MEM32 : UPIO_MEM; uap->port.ops = &sbsa_uart_pops; uap->fixed_baud = baudrate; snprintf(uap->type, sizeof(uap->type), "SBSA"); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); ret = pl011_setup_port(&pdev->dev, uap, r, portnr); if (ret) return ret; platform_set_drvdata(pdev, uap); return pl011_register_port(uap); }linux内核uart驱动在设备注册时,使用acpi表定义的波特率来初始化串口,请根据我的要求和上述代码,在代码中添加这一功能
06-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值