码迷,mamicode.com
首页 > 其他好文 > 详细

访问I/O内存和I/O端口设备

时间:2015-08-04 22:53:31      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:linux驱动   io映射   

        前面为了写pwm驱动,仔细研究了下I/O内存和I/O端口设备的区别,以及访问方式。不过,其实也没必要纠结这个了,因为现在绝大部分设备都使用I/O内存映射的。


I/O独立编址和I/O统一编址

        首先有两个概念:I/O独立编址和I/O统一编址;记住这两种编址方式都是由CPU架构决定的。

        I/O独立编址:应该只有X86处理器才是I/O独立编址,其他的处理器基本都是统一编址了。所谓的I/O独立编址就是处理器上的所有物理地址(如果开启了MMU则为所有虚拟地址)都分配给总线和内存(可以理解为内存条上)。而 不 分配地址给外设,外设有自己的一套编址方式。所以有内存空间和I/O空间的叫法;

        I/O统一编址:就是在分配地址时会留一部分地址给外设用。


内存空间和I/O空间

        每种外设都是通过读写寄存器进行控制的,大部分外设都有几个寄存器,不管是在内存地址空间还是在I/O地址空间,这些寄存器的访问地址都是连续的。在硬件层,内存区域和I/O区域没有概念上的区别:他们都是通过向地址总线和控制总线发送电平信号进行访问,再通过数据总线读写数据;

        技术分享

        上面简单的图说明了内存区域(memory)和I/O区域(I/O),他们都是通过地址总线(address)、控制总线(controller)、数据总线(data)发送信号来控制外设的。还有些处理器为I/O空间读写提供了独立的总线(上图是I/O空间没有独立的总线,和内存区域共用总线);


I/O端口映射和内存映射

        I/O端口映射:这是在I/O独立编址处理器上映射的,把I/O端口映射到I/O空间,然后通过特殊指令去访问该空间的数据。系统会专门定义一些特殊指令来访问I/O空间:in、out;而系统也为这些指令封装成一些简单的函数:inb()、inw()、outb()、outw()。。。等;

        内存映射:这是在统一编址的处理器上操作的。把外设寄存器和内存映射到系统的内存中,外设内存映射到系统内存中有点不一样,可以看看PCI设备,后期会分析下。


对外设的访问操作

        端口映射访问:

        头文件:#include <linux/ioport.h>

        struct  resource  *request_region(unsigned long first, unsigned long n, const char* name);

        向内核注册需要使用的接口,first 使用端口的起始地址;n 注册n个端口;name 设备名称;可以从/proc/ioports中查看到端口分配的情况;

        不再使用该I/O端口:void  release_region(unsigned long start,  unsigned long n);

       #######################################################################################################

        对端口的访问不能向内存那样使用一样的访问方式,硬件把8位、16位、32位端口区分开来;

        头文件:  #include<asm/io.h>

        unsigned inb(unsigned port);  =====  void outb(unsigned char byte, unsigned port);

        unsigned inw(unsigned port); =====   void outw(unsinged short word, unsigned port);


        内存映射访问:

        头文件:#include<linux/ioport.h>

        struct resource*  request_mem_region(unsigned long start, unsigned long len, char *name);表示从start开始分配len个字节长的内存区域。I/O内存分配情况可以从/proc/iomem中得到;

        void  release_mem_region(unsigned long start, unsigned long len);释放接口;

        ######################################################################################################

        注册完后,接下来就是映射到内存中和访问该段内存了。其实有的系统支持直接访问注册时得到的内存地址,但是这样不安全,也不利用代码移植,所以有些系统干脆就直接报错来阻止这种访问方式;

        映射到内存中,通过下面函数:

        void *ioremap(unsigned long phys_addr, unsigned long size);这个函数就是把虚拟地址和物理地址映射起来,一般会动用页表。这个后面linux内核内存会分析下。这里不一样的就是ioremap映射的物理地址不是系统的,而是外设的。释放映射:void iounmap(void *addr);

       访问函数:

        unsigned int ioread8(void *addr);

        unsigned int ioread16(void *addr);

      
        转载地址:http://blog.csdn.net/yuzhihui_no1/article/details/47111647

        如果有理解不正确的地方,欢迎指正!!


版权声明:本文为博主原创文章,未经博主允许不得转载。

访问I/O内存和I/O端口设备

标签:linux驱动   io映射   

原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/47111647

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!