/dev/mem,通过mmap可以将物理地址映射到用户空间的虚拟地址上,在用户空间完成对设备寄存器的操作,/dev/mem是物理内存的全映像,可以用来访问物理内存,一般用法是open("/dev/mem",O_RDWR|O_SYNC),接着就可以用mmap来访问物理内存以及外设的IO资源,这就是实现用户空间驱动的一种方法。
关于mmap原理
映射就是建立一种一一对应关系,在这里主要是指硬盘上文件的位置与进程逻辑地址空间 中一块大小相同的区域之间的一一对应
这种对应关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在的。在内存映射的过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上被放入了内存,具体到代码,就是建立并初始化了相关的数据结构(struct address_space),这个过程由系统调用mmap()实现,所以建立内存映射的效率很高。
int pli_init()
{
if(pliFd > 0)
return 1;
pliFd = open(MEM_PATH,O_RDWR|O_SYNC);
if(pliFd < 0)
{
printf("pli_init failed!\r\n");
return -1;
}
baseIOVirAddress = mmap((void *)NULL, REGS_RANG_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, pliFd,INTER_REGS_BASE);
if(baseIOVirAddress == MAP_FAILED) {
printf("Unable to mmap \r\n");
return -1;
}
printf("pli_init success Base 0x%x!\r\n",INTER_REGS_BASE);
return pliFd;
}
int* pli_getIOAddress( int addr)
{
volatile void* targetIOVirAddress = NULL;
if(baseIOVirAddress == NULL)
return NULL;
targetIOVirAddress = baseIOVirAddress + addr;
return (int*)targetIOVirAddress;
}
/*
* 设置GPIOX 接口复用功能
* port: 0~9 A~J GPIO类型
* portPin: 0~15 GPIOX对应引脚
* mode: 0x00: 普通IO口功能 0xXX 复用功能 其他: 普通IO口功能
*/
int setMPPMode(unsigned char port,unsigned int portPin,unsigned char mode)
{
volatile unsigned int *baseRegAddr = NULL;
unsigned char pin = portPin;
if(pin < 8)
{
pin *= 4;
baseRegAddr =(volatile unsigned int *) pli_getIOAddress(SYS_REG_BASE_ADDR+0x70+port*8);
}
else
{
pin = (pin-8)*4;
baseRegAddr = (volatile unsigned int *)pli_getIOAddress(SYS_REG_BASE_ADDR+0x70+port*8+4);
}
*baseRegAddr &= ~(0xf << (pin)); //先设置为通用IO模式
*baseRegAddr |= (mode << (pin)); //这个决定复用还是通用
//设置IO模式
//printf("port %d portPin %d setMPPMode 0x%x = 0x%x\r\n",port,portPin,(SYS_REG_BASE_ADDR+0x70+port*8),*baseRegAddr);
return 1;
}
/*
* 设置通用GPIO的方向
* port: 0~9 A~J GPIO类型
* portPin: 0~15 GPIOX对应引脚
* isOut : 1 is output,0 is input
********/
int setGPIODir(unsigned char port,unsigned int GPIOPin,unsigned char isOut)
{
volatile unsigned int *baseRegAddr = NULL;
if(isOut > 0)
isOut = 1;
else
isOut = 0;
baseRegAddr = pli_getIOAddress(GPIO_BASE_ADDR+0x40*port);//DIR
//printf("Before 0x%x\r\n",(*baseRegAddr));
//对应位置零后,再置为想要的
*baseRegAddr = ((*baseRegAddr) & (~(1 << GPIOPin))) | (isOut << GPIOPin);//setDIR
//printf("port %d portPin %d setMPPMode 0x%x = 0x%x\r\n",port,GPIOPin,(GPIO_BASE_ADDR+0x40*port),*baseRegAddr);
//printf("port %d portPin %d setMPPMode 0x%x = 0x%x\r\n",port,GPIOPin,(GPIO_BASE_ADDR+0x40*port+0x20),*baseRegAddr);
return 1;
}