|
還是對照代碼解釋一下.我的這部分代碼如下: 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 }, }; 這樣的定義,無非是希望系統(tǒng)將 pSMDK2410_ETH_IO這個(gè)物理地址給映射到虛地址vSMDK2410_ETH_IO上,占用可操作的長度是1M.
接下來在我的CS8900的驅(qū)動(dòng)里就能利用這個(gè)轉(zhuǎn)換后的地址操作我的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 這個(gè)事先定義好的地址進(jìn)行操作了,后面的幾個(gè)語句無非的檢查和對齊這個(gè)地址資源什么的。
而用smdk2410_devices定義的資源,需要在驅(qū)動(dòng)代碼中動(dòng)態(tài)向系統(tǒng)申請映射,并返回一個(gè)可操作的虛地址才能操作的。例如以下的代碼: 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申請一塊區(qū)域,最后用host->base =
ioremap(host->mem->start,
RESSIZE(host->mem));將可操作的虛地址返回給驅(qū)動(dòng),驅(qū)動(dòng)用這個(gè)轉(zhuǎn)換后的地址就可以操作硬件的寄存器什么的了...這里面的物理
和需地址的轉(zhuǎn)化是怎樣的。自己有興趣自己了解.
[這個(gè)貼子最后由cefanty在 2006/08/25 10:45am 第 1 次編輯]
首先你需要為SOC的各個(gè)功能部分定義他的一些資源.例如可用于訪問的寄存器地址.中斷號,DMA什
么的。然后將這些資源(resource) 作為 platform 的dev
.通過platform_add_devices函數(shù)將你定義的paltform_device變量注冊到系統(tǒng)的dev里面.?;蛘吣憧梢韵笪疫@樣將你需
要的驅(qū)動(dòng)添加: 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 }; 這樣你的硬件的信息和資源就會(huì)注冊到系統(tǒng)中.
說了半天,這回該說這有什么用了。 你編寫的驅(qū)動(dòng)或者移植別人的驅(qū)動(dòng),一般在驅(qū)動(dòng)里有這樣的代碼,例如: 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",這條關(guān)鍵的語句沒有??,它和我在上面注冊的&s3c_device_sdi,里的device的名稱是一致的.我這里展開我的s3c_device_sdi,的內(nèi)容 : /* 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, };
在驅(qū)動(dòng)程序里的init代碼大致如下: static int __init s3c2410sdi_init(void) { return platform_driver_register(&s3c2410sdi_driver); } 用platform_driver_register
向系統(tǒng)注冊這個(gè)驅(qū)動(dòng)程序.而這個(gè)函數(shù)會(huì)在s3c2410sdi_driver的信息里提取name為搜索內(nèi)容,搜索系統(tǒng)注冊的device中有沒有這個(gè)
platform_device。 如果有注冊,那么接著會(huì)執(zhí)行platform_driver
里probe函數(shù).在這里顯然是s3c2410sdi_probe函數(shù)
在probe函數(shù)里,用的最多和剛才platform_device有關(guān)的語句是platform_get_resource,這條語句用于獲取
platform_device里的resource資料.例如映射的IO地址,中斷等.剩下等得就是ioremap,和
request_irq等的事情了
|