还是对照代码解释一下.我的这部分代码如下: 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等的事情了
|