在不少平台,包括嵌入式的,如jz4730,pxa-166等都把CPU可访问的整个物理地址空间(逻辑地址空间)映射到用户空间去.其和用户交互的设备节点就是/dev/mem.用户空间通过这个设备节点可以直接访问整个CPU可访的物理地址空间(逻辑地址空间).这里的映射,从宏观来讲,是一种"中介",一种"逻辑转换".
如果我们因为某种特殊需求需要在用户空间编写程序的话(现在有很多用户空间的驱动,如libusb,libiic等),不修改内核却又想追求效率,可以优先考虑一下内存映射的方式--借用/dev/mem.一般来说,把CPU的逻辑地址遇到到用户空间由CPU厂家做好的,也就是说为我们建议好VMA页表.我们只需要把mmap到用户空间,通过数据手册的目标寄存器地址值作偏移量就可以在用户空间直接操作寄存器了.
比如,某一CPU的GPIO的基地址为0xD401_9000.通过mmap映射/dev/mem,把0xD401_9000作偏移量即可操作到GPIO的基地址.示意代码如下:
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#define SPICS (119)
#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
#define GPIO_REG(x) (*((volatile unsigned int *)(GPIO_REGS_VIRT + (x))))
#define GPIO_REG_BASE (0xD4019000)
#define NR_BUILTIN_GPIO (128)
#define GPIO_bit(gpio) (1 << ((gpio) & 0x1f))
#define GPLR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x00)
#define GPDR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x0c)
#define GPSR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x18)
#define GPCR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x24)
#define GSDR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x54)
#define GCDR(x) GPIO_REG(BANK_OFF((x) >> 5) + 0x60)
static inline void gpio_direction_output(unsigned gpio, int value)
{
if (gpio < NR_BUILTIN_GPIO) {
GSDR(gpio) = GPIO_bit(gpio);
if (value)
GPSR(gpio) = GPIO_bit(gpio);
else
GPCR(gpio) = GPIO_bit(gpio);
} else
printf("Invalid GPIO pin %u\n", gpio);
}
int main(int argc, char *argv[])
{
unsigned char *gpiobase = NULL;
int mem_fd = -1;
gpio_direction_output(SPICS,1);
}