核心中與驅動相關的記憶體操作之十三(/dev/mem)
阿新 • • 發佈:2019-01-28
在不少平臺,包括嵌入式的,如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); }