分享

struct resource,struct platform_device和驱动的关系?

 Archangel 2007-08-11

还是对照代码解释一下.我的这部分代码如下:
static struct map_desc smdk2410_iodesc[] __initdata = {
/* Map the ethernet controller CS8900A */
{/* VRAM*/
.virtual=  vSMDK2410_ETH_IO,
.pfn= __phys_to_pfn(pSMDK2410_ETH_IO),
.length= SZ_1M,
.type= MT_DEVICE
},
};
这样的定义,无非是希望系统将 pSMDK2410_ETH_IO这个物理地址给映射到虚地址vSMDK2410_ETH_IO上,占用可操作的长度是1M.

接下来在我的CS8900的驱动里就能利用这个转换后的地址操作我的CS8900了。例如一下的代码:
dev->base_addr = vSMDK2410_ETH_IO + 0x300;
dev->irq = SMDK2410_ETH_IRQ;

if ((result = check_mem_region (dev->base_addr, 0xfff))) {
printk (KERN_ERR "%s: can‘t get I/O port address 0x%lx\n",dev->name,dev->base_addr);
return (result);
}

request_mem_region (dev->base_addr, 0xff, dev->name);

这里直接就可以使用vSMDK2410_ETH_IO 这个事先定义好的地址进行操作了,后面的几个语句无非的检查和对齐这个地址资源什么的。

而用smdk2410_devices定义的资源,需要在驱动代码中动态向系统申请映射,并返回一个可操作的虚地址才能操作的。例如以下的代码:
host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!host->mem) {
printk(KERN_ERR PFX "failed to get io memory region resouce.\n");
ret = -ENOENT;
goto probe_free_host;
}

host->mem = request_mem_region(host->mem->start,
RESSIZE(host->mem), pdev->name);

if (!host->mem) {
printk(KERN_ERR PFX "failed to request io memory region.\n");
ret = -ENOENT;
goto probe_free_host;
}

host->base = ioremap(host->mem->start, RESSIZE(host->mem));
if (host->base == 0) {
printk(KERN_ERR PFX "failed to ioremap() io memory region.\n");
ret = -EINVAL;
goto probe_free_mem_region;
}

其中platform_get_resource是得到物理的IO或者寄存器的物理地址.
然 后用request_mem_region申请一块区域,最后用host->base = ioremap(host->mem->start, RESSIZE(host->mem));将可操作的虚地址返回给驱动,驱动用这个转换后的地址就可以操作硬件的寄存器什么的了...这里面的物理 和需地址的转化是怎样的。自己有兴趣自己了解.

[这个贴子最后由cefanty在 2006/08/25 10:45am 第 1 次编辑]


首先你需要为SOC的各个功能部分定义他的一些资源.例如可用于访问的寄存器地址.中断号,DMA什 么的。然后将这些资源(resource) 作为 platform 的dev .通过platform_add_devices函数将你定义的paltform_device变量注册到系统的dev里面.。或者你可以象我这样将你需 要的驱动添加:
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_bl,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
&s3c_device_sdi,
&s3c_device_adc,
&s3c_device_nand,
&s3c_device_usbgadget,
&s3c_device_ts,
&s3c_device_buttons,
&s3c_device_rtc,
&s3c_device_spi0,
&s3c_device_timer1,//add by cefanty for battery charging
};
这样你的硬件的信息和资源就会注册到系统中.

说了半天,这回该说这有什么用了。
你编写的驱动或者移植别人的驱动,一般在驱动里有这样的代码,例如:
static struct platform_driver s3c2410sdi_driver =
{
.probe          = s3c2410sdi_probe,
.remove         = s3c2410sdi_remove,
.suspend= s3c2410mci_suspend,
.resume= s3c2410mci_resume,
.driver={
.name= "s3c2410-sdi",
.bus    = &platform_bus_type,
.owner= THIS_MODULE,
},
};

看到 .name= "s3c2410-sdi",这条关键的语句没有??,它和我在上面注册的&s3c_device_sdi,里的device的名称是一致的.我这里展开我的s3c_device_sdi,的内容
:
/* SDI */

static struct resource s3c_sdi_resource[] = {
[0] = {
.start = S3C2410_PA_SDI,
.end   = S3C2410_PA_SDI + S3C24XX_SZ_SDI - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_SDI,
.end   = IRQ_SDI,
.flags = IORESOURCE_IRQ,
},
[2] = {
.start = 3,
.end  = 3,
.flags = IORESOURCE_DMA,
}
};

struct platform_device s3c_device_sdi = {
.name  = "s3c2410-sdi",
.id  = -1,
.num_resources  = ARRAY_SIZE(s3c_sdi_resource),
.resource  = s3c_sdi_resource,
};

在驱动程序里的init代码大致如下:
static int __init s3c2410sdi_init(void)
{
return platform_driver_register(&s3c2410sdi_driver);
}
用platform_driver_register 向系统注册这个驱动程序.而这个函数会在s3c2410sdi_driver的信息里提取name为搜索内容,搜索系统注册的device中有没有这个 platform_device。 如果有注册,那么接着会执行platform_driver 里probe函数.在这里显然是s3c2410sdi_probe函数  在probe函数里,用的最多和刚才platform_device有关的语句是platform_get_resource,这条语句用于获取 platform_device里的resource资料.例如映射的IO地址,中断等.剩下等得就是ioremap,和 request_irq等的事情了


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多