ioremap,iowrite,ioread,request_mem_region
一。I/O使用前准备工作
首先要搞清楚一个概念,就是I/O memory是什么。Memory-mapped I/O uses the same address space to address both memory and I/O devices. 意味着,寻址I/O的寄存器和内存(memory)是公用内存中的地址的。所以,在cpu发出寻址指令时,可能是寻找物理的RAM也可能指向IO设备。因此,在内存中要保留一部分内存以供IO硬件所使用。
I/O内存的区域需要再使用前进行分配,因此涉及到函数struct resource *request_mem_region(unsigned long start, unsigned long len,char *name);
是将一块分配从start的地址开始的len Bytes的区域。成功返回non-null指针。
释放空间使用void release_mem_region(unsigned long start, unsigned long len);
在使用前,分配I/O memory并不是唯一需要的步骤,我们需要确认内核能使用I/o memory。因此需要先通过ioremap进行寻址。此函数设计目的就是讲虚拟地址分配给I/o memory的区域。其返回值不应该直接通过取值符*进行使用,而应该通过内核的引用函数进行操作。void *ioremap(unsigned long phys_addr, unsigned long size);
2。I/O的调用
调用其实是通过对返回地址(其实就是寄存器)输出或读取值。
读取: unsigned int ioread8(void *addr);unsigned int ioread16(void *addr);unsigned int ioread32(void *addr);
输出: void iowrite8(u8 value, void *addr); void iowrite16(u16 value, void *addr); void iowrite32(u32 value, void *addr);
还有块操作的 :void ioread8_rep(void *addr, void *buf, unsigned long count);等等。
实验1:不使用分配函数,看是否能进行IO访问。
因此,对于ARM寄存器,如gpio要用到的DATA_REG数据寄存器,物理地址为0x41200000和三态寄存器TRP_PHA,物理地址为0x41200004,可以分配一个连续的空间。内存每个地址对应一个Byte,因为Arm寄存器为32bit即0x41200000-0x41200003都为DATA_REG,接下去为三态寄存器,ioremap可以直接从初始地址分配8个bytes。也就是
unsigned long io_base_addr=ioremap(0x41200000,8);
实验2,对指定io口寻址,查看对应寄存器的值是否改变。
参考:http://www.makelinux.net/ldd3/chp-9-sect-4
https://en.wikipedia.org/wiki/Memory-mapped_I/O