使用mmap在用户层访问底层硬件,基本原理是通过mmap将底层一块内存映射到用户,在LCD驱动里面应用比较多。
先看Makefile
TARGET = mmap_tool_simple
ROOTDIR = /home/flinn/bin/rootfs
CROSS_COMPILE := /home/flinn/tools/4.9.4/bin/arm-linux-gnueabi-
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
CFLAGS := -Wall -O2
OBJS := $(TARGET).o
$(TARGET): $(OBJS)
${CC} $(CFLAGS) -o $@ $^
%.o:%.c
${CC} $(CFLAGS) -c -o $@ $<
install:
sudo cp $(TARGET) $(ROOTDIR)
clean:
rm -f $(TARGET) *.o $(OBJS)
源码mmap_tool_simple.c
/*
* mmap_toos.c
*
* get register of hardware from user-space
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/errno.h>
#define DEBUG
#ifdef DEBUG
#define pr_print(...) printf(##__VA_ARGS__)
#else
#define pr_print(...)
#endif
#define reg32_read(addr) (*((volatile unsigned int *)((unsigned int)addr)))
#define reg32_write(addr, val) (*((volatile unsigned int *)((unsigned int)addr)) = (unsigned int)val)
static int rw = 0; /* 0: read, 1:write */
#define RW_LFAG_READ 0
#define RW_FLAG_WRITE 1
struct _cmd
{
unsigned int baseaddr;
unsigned int length; /* for read length */
unsigned int value; /* for write */
};
static struct _cmd cmd;
static void usage(void)
{
fprintf(stderr,
"usage : mmap_tools [cmd] [args] ... \n\n"
"options :\n"
" -r, --read open device\n"
" -w, --write close device\n"
" -h, --help show usage information.\n"
"examples :\n"
" mmap_tools -r [baseaddr] [len]\n"
" mmap_tools -w [baseaddr] [value]\n"
);
}
static int drv_parse_cmds(int argc, char **argv)
{
int i;
char *opt;
if(4 != argc)
return -1;
if(!strcmp(argv[1], "-r")){
rw = RW_LFAG_READ;
cmd.baseaddr = strtoll(argv[2], &opt, 16);
cmd.length = strtol(argv[3], &opt, 16);
}
else if(!strcmp(argv[1], "-w")) {
rw = RW_FLAG_WRITE;
cmd.baseaddr = strtoll(argv[2], &opt, 16);
cmd.value = strtol(argv[3], &opt, 16);
}
else
{
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
int ret = 0 , i;
int fd = -1;
unsigned int *map_base;
unsigned int addr;
unsigned int offset = 0;
ret = drv_parse_cmds(argc, argv);
if(ret != 0){
usage();
return -1;
}
fd = open("/dev/mem", O_RDWR);
if(fd < 0){
printf("open %s fail.\n", "/dev/mem");
return -1;
}
addr = cmd.baseaddr & ~(getpagesize() - 1);
offset = (cmd.baseaddr - addr) & 0xfffffffc; /* align 4-bytes */
unsigned int length = 1;
if(RW_LFAG_READ == rw){
length = cmd.length;
map_base = (unsigned int * )mmap(NULL, length * 4, PROT_READ, MAP_SHARED, fd, addr);
for(i = 0; i < length; i++)
{
printf("addr : %08x value : %08x\n", addr + offset + i*4, reg32_read(map_base + i*4));
}
}
else if(RW_FLAG_WRITE == rw){
unsigned int value = cmd.value;
map_base = (unsigned int * )mmap(NULL, length * 4, PROT_WRITE, MAP_SHARED, fd, addr);
reg32_write(map_base + offset , value);
}
else
{
}
munmap(map_base, length * 4);
close(fd);
return 0;
}
编译
make
make install
使用