I/O资源如何映射到内核虚拟空间
2008-07-24 14:13
369 查看
(1) 系统启动初始化时iotable_init() ----------------------------- MACHINE_START(AT91SAM9261EK, "ATMEL AT91SAM9261") ············································ .map_io = at91sam9261_map_io, ············································ MACHINE_END -------------------------------------- void __init at91sam9261_map_io(void) { iotable_init(at91sam9261_io_desc, ARRAY_SIZE(at91sam9261_io_desc)); } -------------------------------------- /* * System peripheral registers mapped at virtual address. */ static struct map_desc at91sam9261_io_desc[] __initdata = { { .virtual = AT91C_VA_BASE_SYS, .pfn = __phys_to_pfn(AT91C_BASE_AIC), .length = SZ_4K, .type = MT_DEVICE }, { .virtual = AT91C_VA_BASE_EBI, .pfn = __phys_to_pfn(AT91C_BASE_EBI), .length = SZ_4K, .type = MT_DEVICE }, ·············································· }; <./linux/include/asm-arm/map.h>----------------------- struct map_desc { unsigned long virtual; unsigned long pfn; unsigned long length; unsigned int type; //标志位:domain、read、write、cache、buffer }; #define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT) #define __pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) -------------------------------------- iotable_init()函数<./arch/arm/mm/mm-armv.c>循环调用create_mapping()函数完成IO的虚拟地址到物理地址的映射。 (2) 系统启动后,在驱动中ioremap() -------------------------------------- static struct platform_device *smdk2410_devices[] __initdata = { &s3c_device_usb, //片上的各个设备 &s3c_device_lcd, //下面以s3c_device_lcd为例 &s3c_device_wdt, &s3c_device_i2c, &s3c_device_iis, }; -------------------------------------- struct platform_device s3c_device_lcd = { .name = "s3c2410-lcd", //此处设备的命名应和相应驱动程序命名一致以实现driver bind .id = -1, //-1表示不支持同类多个设备 .num_resources = ARRAY_SIZE(s3c_lcd_resource), .resource = s3c_lcd_resource, .dev = { .dma_mask = &s3c_device_lcd_dmamask, .coherent_dma_mask = 0xffffffffUL } }; ------------------------------------- /* LCD Controller */ static struct resource s3c_lcd_resource[] = { //LCD的两个资源 [0] = { .start = S3C2410_PA_LCD, .end = S3C2410_PA_LCD + S3C2410_SZ_LCD, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_LCD, .end = IRQ_LCD, .flags = IORESOURCE_IRQ, } }; ------------------------------------ /* -------Resource type -------- */ #define IORESOURCE_IO 0x00000100 #define IORESOURCE_MEM 0x00000200 #define IORESOURCE_IRQ 0x00000400 #define IORESOURCE_DMA 0x00000800 ------------------------------------ -----s3c_device_lcd的resource中硬件地址--------------- #define S3C2410_LCDREG(x) (x) /* LCD control registers */ #define S3C2410_LCDCON1 S3C2410_LCDREG(0x00) #define S3C2410_LCDCON2 S3C2410_LCDREG(0x04) #define S3C2410_LCDCON3 S3C2410_LCDREG(0x08) #define S3C2410_LCDCON4 S3C2410_LCDREG(0x0C) #define S3C2410_LCDCON5 S3C2410_LCDREG(0x10) /* LCD controller */ #define S3C2410_PA_LCD (0x4D000000) #define S3C24XX_SZ_LCD SZ_1M ----------------------------------- /** * platform_device_register - add a platform-level device * @pdev: platform device we're adding * */ int platform_device_register(struct platform_device * pdev) { device_initialize(&pdev->dev); //初始化设备结构 return platform_device_add(pdev); //添加一个片上的设备到设备层 } ------------------------------------------ /** * platform_device_add - add a platform device to device hierarchy * @pdev: platform device we're adding * * This is part 2 of platform_device_register(), though may be called * separately _iff_ pdev was allocated by platform_device_alloc(). */ int platform_device_add(struct platform_device *pdev) { int i, ret = 0; if (!pdev) return -EINVAL; if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); /* 若支持同类多个设备,则用pdev->name和pdev->id在总线上标识该设备 */ else strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); /* 否则,用pdev->name(即"s3c2410-lcd")在总线上标识该设备 */ for (i = 0; i < pdev->num_resources; i++) { /* 遍历资源数,并为各自在总线地址空间请求分配 */ struct resource *p, *r = &pdev->resource[i]; if (r->name == NULL) r->name = pdev->dev.bus_id; p = r->parent; if (!p) { if (r->flags & IORESOURCE_MEM) p = &iomem_resource; /* LCD寄存器地址作为IO内存资源分配 */ ---------------- struct resource iomem_resource = { .name = "PCI mem", .start = 0UL, .end = ~0UL, .flags = IORESOURCE_MEM, }; ---------------- else if (r->flags & IORESOURCE_IO) p = &ioport_resource; } if (p && insert_resource(p, r)) { /* 将LCD寄存器地址插入到IO内存空间 */ printk(KERN_ERR "%s: failed to claim resource %d/n", pdev->dev.bus_id, i); ret = -EBUSY; goto failed; } } pr_debug("Registering platform device '%s'. Parent at %s/n", pdev->dev.bus_id, pdev->dev.parent->bus_id); ret = device_add(&pdev->dev); if (ret == 0) return ret; failed: while (--i >= 0) if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO)) release_resource(&pdev->resource[i]); return ret; } ----------------------------------------- static struct platform_driver s3c2410fb_driver = { .probe = s3c2410fb_probe, .remove = s3c2410fb_remove, .suspend = s3c2410fb_suspend, .resume = s3c2410fb_resume, .driver = { .name = "s3c2410-lcd", .owner = THIS_MODULE, }, }; platform_driver_register(&s3c2410fb_driver)-----> driver_register(&drv->driver)-----> bus_add_driver(drv)-----> driver_attach(drv)-----> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)-----> __driver_attach(struct device * dev, void * data)-----> driver_probe_device(drv, dev)-----> really_probe(dev, drv)-----> 在really_probe()中: 为设备指派管理该设备的驱动:dev->driver = drv 调用s3c2410fb_probe()初始化设备:drv->probe(dev) --------------------------------- static int __init s3c2410fb_probe(struct platform_device *pdev) { ····························· res = platform_get_resource(pdev, IORESOURCE_MEM, 0); /* 取得LCD控制寄存器的物理地址 */ size = (res->end - res->start)+1; info->mem = request_mem_region(res->start, size, pdev->name); /* 个人理解:设备注册时已经分配区域,驱动这里应该不是必须的*/ info->io = ioremap(res->start, size); /* 此时驱动便可以用指针info->io 读写LCD控制寄存器了 */ /* eg: readl(info->io + S3C2410_LCDCON1) */ ···························· } -------------------------------- 以下是AT91SAM9261EK的IOMEM: root@ebd9261:~# cat /proc/iomem 00500000-005fffff : usb-ohci.0 00500000-005fffff : ohci_hcd 00600000-00600fff : sidsa-lcdc.0 //支持同类多个设备,在驱动中未分配I/O内存区域 20000000-23ffffff : System RAM 20022000-20225e47 : Kernel text 20226000-2028da23 : Kernel data 30000000-30000003 : dm9000.0 30000000-30000003 : dm9000 30000044-300000ff : dm9000.0 30000044-300000ff : dm9000 fffa4000-fffa7fff : at91_udc //不支持同类多个设备,在驱动中也分配I/O内存区域 fffa4000-fffa7fff : at91_udc fffb0000-fffb3fff : usart.1 fffb4000-fffb7fff : usart.2 fffc8000-fffcbfff : spi.0 fffff200-fffff3ff : usart.0 |
相关文章推荐
- [转载]I/O资源如何映射到内核虚拟空间
- I/O资源如何映射到内核虚拟空间
- I/O资源如何映射到内核虚拟空间
- Unix v6中对虚拟地址映射到物理地址以及在内核态如何访问用户空间的u值
- 从MDL(把应用层的地址空间映射到系统内核空间)得到系统虚拟空间地址
- Linux如何映射物理内存到内核空间
- Linux如何映射物理内存到内核空间
- Linux虚拟地址空间如何分布?
- 对于内核输入系统驱动(例如keypad, sensor, touch panel),内核如何发送事件给用户空间
- 如何用ftp上传静态网站到虚拟空间
- Linux的内核空间和用户空间是如何划分的(以32位系统为例)?
- Linux系统调用详解(如何从用户空间进入内核空间)
- ANDROID开发中资源文件和资源ID是如何映射的
- Linux内核访问外设I/O资源的方式(设备物理地址和设备虚拟地址),静态映射和动态映射
- 用户空间的虚拟地址如何转换得到实际的物理地址
- 关于虚拟空间IIS无法配置rails的映射
- 进程虚拟地址空间中的虚拟内存区域(vma)---可执行程序与虚拟地址空间的映射关系
- android里面,资源文件和资源ID之间的映射是如何工作的?
- 从赵炯老师的文章中截图linux0.11 内核在线性空间和虚拟空间分布