`
mmdev
  • 浏览: 12954041 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

I/O资源如何映射到内核虚拟空间

阅读更多

(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

分享到:
评论

相关推荐

    FreeBSD操作系统设计与实现

    6.1 从用户到设备的I/O映射 6.1.1 设备驱动程序 6.1.2 I/O队列 6.1.3 中断处理 6.2 字符设备 6.2.1 原始设备和物理I/O 6.2.2 面向字符的设备 6.2.3 字符设备驱动程序的入口点 6.3 磁盘设备 6.3.1 块设备驱动程序的...

    Android驱动开发权威指南

    7.4.2申请与释放I/O资源 7.4.3 I/O访问流程 7.4.4设备地址与用户空间的映射 7.5 DMA 7.5.1 DMA与Cache的一致性 7.5.2 Linux下的DMA编程 第8章Linux设备驱动中的中断 8.1 Linux中断及中断处理架构 8.2 Linux中断编程 ...

    深入解析Windows操作系统中文.part2.rar

    映射文件I/O和文件缓存 564 I/O请求包 564 针对单层驱动程序的I/O请求 569 针对分层的驱动程序的I/O请求 577 I/O完成端口 585 驱动程序检验器(Driver Verifier) 589 9.4 即插即用(PnP)管理器 590 即插即用支持的...

    LINUX编程白皮书 (全集)

    5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥 51 5.5.1 PCI-PCI桥:PCI I/O和存储地址 空间的窗口 51 5.5.2 PCI-PCI桥:PCI配置周期和PCI 总线编号 52 5.6 Linux PCI初始化 53 5.6.1 Linux内核...

    UNIX 高级教程系统技术内幕

    12.3 资源映射图分配器 12.3.1 分析 12.4 简单2 次幂空闲表 12.4.1 分析 12.5 McKusick-Karels 分配器 12.5.1 分析 12.6 伙伴系统 12.6.1 分析 12.7 SVR4 Lazy 伙伴算法 12.7.1 Lazy 合并 12.7.2 SVR4 实现细节 12.8...

    Linux编程从入门到精通

    5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥 51 5.5.1 PCI-PCI桥:PCI I/O和存储地址 空间的窗口 51 5.5.2 PCI-PCI桥:PCI配置周期和PCI 总线编号 52 5.6 Linux PCI初始化 53 5.6.1 Linux内核...

    Linux编程白皮书

    5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥 51 5.5.1 PCI-PCI桥:PCI I/O和存储地址 空间的窗口 51 5.5.2 PCI-PCI桥:PCI配置周期和PCI 总线编号 52 5.6 Linux PCI初始化 53 5.6.1 Linux内核...

    Linux编程资料

    5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥 51 5.5.1 PCI-PCI桥:PCI I/O和存储地址 空间的窗口 51 5.5.2 PCI-PCI桥:PCI配置周期和PCI 总线编号 52 5.6 Linux PCI初始化 53 5.6.1 Linux内核...

    LINUX编程白皮书

    5.5.1 PCI-PCI桥:PCI I/O和存储地址空间的窗口 51 5.5.2 PCI-PCI桥:PCI配置周期和PCI总线编号 52 5.6 Linux PCI初始化 53 5.6.1 Linux内核PCI数据结构 53 5.6.2 PCI设备驱动程序 53 5.6.3 PCI的BIOS函数 56 ...

    linux编程白皮书

    5.3 PCI的I/O和存储地址空间 51 5.4 PCI-ISA桥 51 5.5 PCI-PCI 桥 51 5.5.1 PCI-PCI桥:PCI I/O和存储地址 空间的窗口 51 5.5.2 PCI-PCI桥:PCI配置周期和PCI 总线编号 52 5.6 Linux PCI初始化 53 5.6.1 Linux内核...

    (重要)AIX command 使用总结.txt

    kmtune //HP-UX下用kmtune&gt;kernel.txt将内核参数信息导出到kernel.txt文件中配置文件为: /usr/conf/master.d/core-hpux ##操作系统 //操作系统版本 uname -a //操作系统补丁 instfix -i|grep ML //获取硬件信息 ...

    Tcl_TK编程权威指南pdf

    从安全解释器中执行i/o操作 安全基础 安全策略 第20章 safe-tk与浏览器插件 子解释器中的tk 浏览器插件 安全策略与浏览器插件 配置安全策略 第3部分 tk基础 第21章 tk的基本知识 th中的hello,world...

    RED HAT LINUX 6大全

    11.5.3 DNS将名字映射到IP地址及反 序操作 207 11.5.4 前区和反区必须保持同步 207 11.5.5 HUP信号和重启 207 11.5.6 IN-ADDR.ARPA域 207 11.5.7 主机命名方案 208 11.5.8 配置DNS客户:/etc/resolv.conf 208 ...

    Ubuntu权威指南(2/2)

    8.9.2 until循环的I/O重定向 222 8.9.3 for循环的I/O重定向 222 8.10 Here文档 223 8.11 Shell函数 227 8.12 逻辑与和逻辑或并列结构 232 8.12.1 逻辑与命令并列结构 232 8.12.2 逻辑或命令并列结构 233 8.13 Shell...

    Ubuntu权威指南(1/2)

    8.9.2 until循环的I/O重定向 222 8.9.3 for循环的I/O重定向 222 8.10 Here文档 223 8.11 Shell函数 227 8.12 逻辑与和逻辑或并列结构 232 8.12.1 逻辑与命令并列结构 232 8.12.2 逻辑或命令并列结构 233 8.13 Shell...

    Android 4游戏编程入门经典

     1.3.3 挑战赛、设备播种计划和谷歌i/o  1.4 android的功能和体系结构  1.4.1 内核  1.4.2 运行库和dalvik虚拟机  1.4.3 系统库  1.4.4 应用程序框架  1.5 软件开发工具包  1.6 开发人员社区  1.7 设备,...

Global site tag (gtag.js) - Google Analytics