关于ioremap,request_mem_region(转)

来源:互联网 发布:年轻人不愿生了知乎 编辑:程序博客网 时间:2024/06/03 16:03
 

文章内容来自:http://blog.csdn.net/fudan_abc/archive/2007/10/04/1811451.aspx

 

以我们家Intel为代表的i386系列处理器中,内存和外部IO是独立编址独立寻址的,于是有一个地址空间叫做内存空间,另有一个地址空间叫做I/O空间.也就是说,从处理器的角度来说,i386提供了一些单独的指令用来访问I/O空间.换言之,访问I/O空间和访问普通的内存得使用不同的指令.而在一些玩嵌入式的处理器中,比如PowerPC,他们家就只使用一个空间,那就是内存空间,那像这种情况,外设的I/O端口的物理地址就被映射到内存地址空间中,这就是传说中的Memory-mapped,内存映射.而我们家那种情况,外设的I/O端口的物理地址就被映射到I/O地址空间中,这就是传说中的I/O-mapped,I/O映射.


要使用I/O内存首先要申请,然后要映射,而要使用I/O端口首先要申请,或者叫请求,对于I/O端口的请求意思是让内核知道你要访问这个端口,这样内核知道了以后它就不会再让别人也访问这个端口了.毕竟这个世界僧多粥少啊.申请I/O端口的函数是request_region,这个函数来自include/linux/ioport.h,


/* Convenience shorthand with allocation */

#define request_region(start,n,name)    __request_region(&ioport_resource, (start), (n), (name))

#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))

#define rename_region(region, newname) do { (region)->name = (newname); } while (0)

extern struct resource * __request_region(struct resource *,

                                         resource_size_t start,

                                         resource_size_t n, const char *name);


这里我们看到的那个request_mem_region是申请I/O内存用的.申请了之后,还需要使用ioremap或者ioremap_nocache函数来映射 .对于request_region,三个参数start,n,name表示你想使用从start开始的sizenI/O port资源,name自然就是你的名字了.


这两个函数在内核的驱动中几乎都会出现,例如ohci-at91.c里面的probe函数:

 

view plaincopy to clipboardprint?
  1. hcd->rsrc_start = pdev->resource[0].start;  
  2.     hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;  
  3.     if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {  
  4.         pr_debug("request_mem_region failed/n");  
  5.         retval = -EBUSY;  
  6.         goto err1;  
  7.     }  
  8.     hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);  
  9.     if (!hcd->regs) {  
  10.         pr_debug("ioremap failed/n");  
  11.         retval = -EIO;  
  12.         goto err2;  
  13.     }  

hcd->rsrc_start = pdev->resource[0].start; hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { pr_debug("request_mem_region failed/n"); retval = -EBUSY; goto err1; } hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { pr_debug("ioremap failed/n"); retval = -EIO; goto err2; }

 

这样的好处是寄存器访问方式比较好看,只要加个偏移地址就可以了。

不过我有时候又不太喜欢用。因为这两句话说到底是为了访问寄存器用的。相当于获得寄存器虚拟地址。但是我们在初始化的时候虚拟地址就已经映射过了,所以我喜欢直接操作寄存器的虚拟地址。