一、mmap函数用法
头文件:
#include <sys/mman.h>函数:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);
参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。
参数length:代表将文件中多大的部分映射到内存。
参数prot:映射区域的保护方式。可以为以下几种方式的组合:
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不能存取
参数flags:影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。
MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
MAP_SHARED对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
参数fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。
参数offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。
返回值:
若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。
二、代码
代码结构同上篇“应用层读写i2c主设备寄存器”,预定义AUDIO_REG_BASE和MAP_SIZE的值决定内存映射的位置和大小
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#define AUDIO_REG_BASE ( 0x01C71000)
#define MAP_SIZE 0xFF
int strtol_lzh(unsigned char *ps,int flag)
{
int i=10;
int r=0;
char *pc = ps;
if(NULL==ps ) return -1;
while(*pc != '\0')
{
if((*pc >= 'a' && *pc <= 'f') ||
(*pc >= 'A' && *pc <= 'F') ||
(*pc == 'x' || *pc == 'X') )
{
i=16;
}
else if( *pc < '0' || *pc > '9')
{
return -1;
}
pc++;
}
if(flag!=0) i=flag;
pc = ps;
while(*pc != '\0')
{
r *= i;
if( *pc>='a' && *pc <= 'f')
{
r += (*pc-'a')+10;
}
else if( *pc>='A' && *pc <= 'F')
{
r += (*pc-'A')+10;
}
else if( *pc>='0' && *pc <= '9')
{
r += (*pc-'0');
}
pc++;
}
return r;
}
static int dev_fd;
int main(int argc, char **argv)
{
unsigned char reg_address =0;
unsigned int data=0;
int tmp;
dev_fd = open("/dev/mem", O_RDWR | O_NDELAY);
if (dev_fd < 0)
{
printf("open(/dev/mem) failed.");
return 0;
}
unsigned char *map_base=(unsigned char * )mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, AUDIO_REG_BASE );
if(argc==1)
{
printf("SYNCEN:%x \n", *(volatile unsigned int *)(map_base+0x00)); //读出00寄存器值
printf("MOSESET:%x \n", *(volatile unsigned int *)(map_base+0x04));
printf("HDW:%x \n", *(volatile unsigned int *)(map_base+0x08));
printf("VDW:%x \n", *(volatile unsigned int *)(map_base+0x0C));
printf("PPLN:%x \n", *(volatile unsigned int *)(map_base+0x10));
printf("LPFR:%x \n", *(volatile unsigned int *)(map_base+0x14));
printf("SPH:%x \n", *(volatile unsigned int *)(map_base+0x18));
printf("LNH:%x \n", *(volatile unsigned int *)(map_base+0x1C));
printf("SLV0:%x \n", *(volatile unsigned int *)(map_base+0x20));
printf("SLV1:%x \n", *(volatile unsigned int *)(map_base+0x24));
printf("LNV:%x \n", *(volatile unsigned int *)(map_base+0x28));
printf("CULH:%x \n", *(volatile unsigned int *)(map_base+0x2C));
printf("CULV:%x \n", *(volatile unsigned int *)(map_base+0x30));
printf("HSIZE:%x \n", *(volatile unsigned int *)(map_base+0x34));
printf("REC656IF:%x \n", *(volatile unsigned int *)(map_base+0x84));
printf("VDINT0:%x \n", *(volatile unsigned int *)(map_base+0x70));
printf("VDINT1:%x \n", *(volatile unsigned int *)(map_base+0x74));
printf("VDINT2:%x \n", *(volatile unsigned int *)(map_base+0x78));
printf("CCDCFG:%x \n", *(volatile unsigned int *)(map_base+0x88));
}
else if(argc==2|| argc > 4)
{
printf("Usage: %s [[-r regAddr] | [-w regAddr byteData]]\n", argv[0]);
}
else
{
if( strstr(argv[1],"-w") ) // write a byte only
{
if(-1 == (tmp=(unsigned short)strtol_lzh(argv[2],16)) )
{
printf(" Invalid reg_addr: %s ",argv[2]);
close(dev_fd);
return -1;
}
reg_address = (unsigned short)tmp;
if(-1 == (tmp=(unsigned int)strtol_lzh(argv[3],16)) )
{
printf(" Invalid data: %s ",argv[3]);
close(dev_fd);
return -1;
}
data = (unsigned int)tmp;
*(volatile unsigned int *)(map_base + reg_address ) = data;
printf("mode: write reg_addr: 0x%02x data: %x \n", reg_address, data);
}
if( strstr(argv[1],"-r") ) // read a byte only
{
if(-1 == (tmp=(unsigned short)strtol_lzh(argv[2],16)) )
{
printf(" Invalid reg_addr: %s ",argv[2]);
close(dev_fd);
return -1;
}
reg_address = (unsigned short)tmp;
printf("mode: read reg_addr: %3d (%02x) \n", reg_address, *(volatile unsigned int *)(map_base + reg_address ));
}
}
if(dev_fd)
close(dev_fd);
munmap(map_base,MAP_SIZE);
return 0;
}