Linux内核访问外设I/O资源的方式

转载 2011年07月13日 17:37:16

我们知道默认外设I/O资源是不在Linux内核空间中的(如sram或硬件接口寄存器等),若需要访问该外设I/O资源,必须先将其地址映射到内核空间中来,然后才能在内核空间中访问它。
     Linux内核访问外设I/O内存资源的方式有两种:动态映射(ioremap)和静态映射(map_desc)。
     一、动态映射(ioremap)方式
     动态映射方式是大家使用了比较多的,也比较简单。即直接通过内核提供的ioremap函数动态创建一段外设I/O内存资源到内核虚拟地址的映射表,从而可以在内核空间中访问这段I/O资源。
     Ioremap宏定义在asm/io.h内:
     #define ioremap(cookie,size)            __ioremap(cookie,size,0)
     __ioremap函数原型为(arm/mm/ioremap.c):
     void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long
     flags);
     phys_addr:要映射的起始的IO地址
     size:要映射的空间的大小
     flags:要映射的IO空间和权限有关的标志
     该函数返回映射后的内核虚拟地址(3G-4G). 接着便可以通过读写该返回的内核虚拟地址去访问之这段I/O内存资源。
     举一个简单的例子: (取自s3c2410的iis音频驱动)
     比如我们要访问s3c2410平台上的I2S寄存器, 查看datasheet 知道IIS物理地址为0x55000000,
     我们把它定义为宏S3C2410_PA_IIS,如下:
     #define S3C2410_PA_IIS     (0x55000000)
     若要在内核空间(iis驱动)中访问这段I/O寄存器(IIS)资源需要先建立到内核地址空间的映射:
     our_card->regs = ioremap(S3C2410_PA_IIS, 0x100);
     if (our_card->regs == NULL) {
     err = -ENXIO;
     goto exit_err;
     }
     创建好了之后,我们就可以通过readl(our_card->regs )或writel(value, our_card->regs)等IO接口函数去访问它。
     二、静态映射(map_desc)方式
     下面重点介绍静态映射方式即通过map_desc结构体静态创建I/O资源映射表。
     内核提供了在系统启动时通过map_desc结构体静态创建I/O资源到内核地址空间的线性映射表(即page table)的方式,这种映射表是一种一一映射的关系。程序员可以自己定义该I/O内存资源映射后的虚拟地址。创建好了静态映射表,在内核或驱动中访问该I/O资源时则无需再进行ioreamp动态映射,可以直接通过映射后的I/O虚拟地址去访问它。
     下面详细分析这种机制的原理并举例说明如何通过这种静态映射的方式访问外设I/O内存资源。
     内核提供了一个重要的结构体struct machine_desc ,这个结构体在内核移植中起到相当重要的作用,内核通过machine_desc结构体来控制系统体系架构相关部分的初始化。
     machine_desc结构体的成员包含了体系架构相关部分的几个最重要的初始化函数,包括map_io,init_irq, init_machine以及phys_io , timer成员等。
     machine_desc结构体定义如下:

 

用户可以在定义Machine_desc结构体时指定Map_io的接口函数,这里以s3c2410平台为例。
     s3c2410 machine_desc结构体定义如下:
     /* arch/arm/mach-s3c2410/Mach-smdk2410.c */
     MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
     * to SMDK2410 */
     /* Maintainer: Jonas Dietsche */
     .phys_io     = S3C2410_PA_UART,
     .io_pg_offst     = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
     .boot_params     = S3C2410_SDRAM_PA + 0x100,
     .map_io         = smdk2410_map_io,
     .init_irq     = s3c24xx_init_irq,
     .init_machine     = smdk2410_init,
     .timer         = &s3c24xx_timer,
     MACHINE_END
     如上,map_io被初始化为smdk2410_map_io。smdk2410_map_io即我们自己定义的创建静态I/O映射表的函数。在Porting内核到新开发板时,这个函数需要我们自己实现。
     (注:这个函数通常情况下可以实现得很简单,只要直接调用iotable_init创建映射表就行了,我们的板子内核就是。不过s3c2410平台这个函数实现得稍微有点复杂,主要是因为它将要创建IO映射表的资源分为了三个部分(smdk2410_iodesc, s3c_iodesc以及s3c2410_iodesc)在不同阶段分别创建。这里我们取其中一个部分进行分析,不影响对整个概念的理解。)
     S3c2410平台的smdk2410_map_io函数最终会调用到s3c2410_map_io函数。
     流程如下:s3c2410_map_io -> s3c24xx_init_io -> s3c2410_map_io
     下面分析一下s3c2410_map_io函数:
     void __init s3c2410_map_io(struct map_desc *mach_desc, int mach_size)
     {
     /* register our io-tables */
     iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc));
     ……
     }
     iotable_init内核提供,定义如下:
     /*
     * Create the architecture specific mappings
     */
     void __init iotable_init(struct map_desc *io_desc, int nr)
     {
     int i;
     for (i = 0; i   nr; i++)
     create_mapping(io_desc + i);
     }

Linux内核访问外设I O资源的方式

首先介绍一下I/O端口和I/O内存。 1. I/O端口:当一个寄存器或内存位于I/O空间时,称其为I/O端口。 2. I/O内存:当一个寄存器或内存位于内存空间时,称其为I/O内存。 再来看一下...
  • a8039974
  • a8039974
  • 2014年04月20日 23:36
  • 714

I/O端口与I/O内存 对外设访问方式

从CPU连出来一把线:数据总线、地址总线、控制总线,这把线上挂着N个接口,有相同的,有不同的,名字叫做存储器接口、中断控制接口、DMA接口、并行接口、串行接口、AD接口……一个设备要想接入,就用自己的...
  • YuZhiHui_No1
  • YuZhiHui_No1
  • 2015年07月19日 00:36
  • 2181

Linux内核访问外设I/O资源

关于Linux内核访问外设I/O资源的方式,dongas的博文说的很好了,转过来做个备份,地址:http://blog.chinaunix.net/space.php?uid=20643761&do=...
  • zhangjun03402
  • zhangjun03402
  • 2011年09月14日 17:32
  • 423

Linux内核访问外设I/O的方式

原文:http://www.embeddedlinux.org.cn/html/yingjianqudong/201008/31-843.html 我们知道默认外设I/O资源是不在Linux...
  • nashouat
  • nashouat
  • 2013年05月19日 22:55
  • 462

外设I/O资源的访问方式

们知道默认外设I/O资源是不在Linux内核空间中的(如sram或硬件接口寄存器等),若需要访问该外设I/O资源,必须先将其地址映射到内核空间中来,然后才能在内核空间中访问它。 ...
  • farsight2009
  • farsight2009
  • 2011年03月10日 15:06
  • 668

访问外设I/O资源的方式

访问外设I/O资源的方式   我们知道默认外设I/O资源是不在Linux内核空间中的(如sram或硬件接口寄存器等),若需要访问该外设I/O资源,必须先将其地址映射到内核空间中...
  • bingfeng1210
  • bingfeng1210
  • 2011年08月22日 16:20
  • 374

Linux内核与驱动开发学习总结:内核访问外设IO.map_desc和ioremap(七)

默认外设I/O资源不在Linux内核空间中的,如sram或硬件接口寄存器等),若需要访问该外设I/O资源,必须先将其地址映射到内核空间中来,然后才能在内核空间中访问它。Linux内核访问外设I/O方式...
  • fenggui
  • fenggui
  • 2015年06月07日 12:02
  • 649

Linux内核访问外设I/O资源的方式(转)

Linux内核访问外设I/O资源的方式(转)3/15/2009 1:27:34 PMhttp://www.diybl.com/course/6_system/linux/Linuxjs/200888/...
  • gracioushe
  • gracioushe
  • 2010年09月30日 10:57
  • 707

Linux内核访问外设I/O资源的方式

 Linux内核访问外设I/O资源的方式我们知道默认外设I/O资源是不在Linux内核空间中的(如sram或硬件接口寄存器等),若需要访问该外设I/O资源,必须先将其地址映射到内核空间中来,然后才能在...
  • againyuan
  • againyuan
  • 2008年11月20日 10:44
  • 721

【转】Linux内核访问外设I/O资源的方式

  • lgqzero
  • lgqzero
  • 2009年09月04日 14:27
  • 58
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux内核访问外设I/O资源的方式
举报原因:
原因补充:

(最多只允许输入30个字)