如何为devmemon MT7620n使用mmap

How to use mmap for devmemon MT7620n

我正在尝试通过寄存器设置访问 MT7620n 的 GPIO。到目前为止,我可以使用 /sys/class/gpio/... 访问它们,但这对我来说还不够快。

在第 84 页的 MT7620 编程指南中,您可以看到 GPIO 基地址为 0x10000600,单个寄存器的偏移量为 4 字节。

MT7620 Programming Guide

类似于: devmem 0x10000600 来自 shell 的工作绝对正常,但我无法从 c 程序内部访问它。

这是我的代码:

#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address
#define GPIO_BLOCK 4

volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
int  m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
    printf("ERROR open\n");
    return -1;
}
gpiochip_0_Address = (unsigned long*)mmap(NULL, GPIO_BLOCK, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, GPIOCHIP_0_ADDDRESS);

close(m_mfd);

if(gpiochip_0_Address == MAP_FAILED)
{
    printf("mmap() failed at phsical address:%d %s\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
    return -2;
}

return 0;
}

我得到的输出是:

mmap() failed at phsical address:268436992 Invalid argument

我需要注意什么?我必须先让内存可访问吗?我是 运行 root。

谢谢

编辑

Peter Cordes 说得对,非常感谢。

这是我的最终解决方案,如果有人发现错误,请告诉我 ;)

#define GPIOCHIP_0_ADDDRESS 0x10000600 // base address

volatile unsigned long *gpiochip_0_Address;
int gpioSetup()
{
const size_t pagesize = sysconf(_SC_PAGE_SIZE);
unsigned long gpiochip_pageAddress = GPIOCHIP_0_ADDDRESS & ~(pagesize-1); //get the closest page-sized-address
const unsigned long gpiochip_0_offset = GPIOCHIP_0_ADDDRESS - gpiochip_pageAddress;  //calculate the offset between the physical address and the page-sized-address

int  m_mfd;
if ((m_mfd = open("/dev/mem", O_RDWR)) < 0)
{
    printf("ERROR open\n");
    return -1;
}
page_virtual_start_Address = (unsigned long*)mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, m_mfd, gpiochip_pageAddress);


close(m_mfd);

if(page_virtual_start_Address == MAP_FAILED)
{
    printf("ERROR mmap\n");
    printf("mmap() failed at phsical address:%d %d\n", GPIOCHIP_0_ADDDRESS, strerror(errno));
    return -2;
}

gpiochip_0_Address = page_virtual_start_Address + (gpiochip_0_offset/sizeof(long));


return 0;
}

mmap 的文件偏移量参数必须是页面对齐的,这就是 one of the documented reasons mmap 失败并返回 EINVAL 的原因。

0x10000600 不是 4k 的倍数,甚至不是 1k 的倍数,所以这几乎肯定是您的问题。我认为任何系统的页面都不会小到 512B。

映射包含所需地址的整个页面,并访问该页面内偏移量处的 MMIO 寄存器。

要么对其进行硬编码,要么执行类似 GPIOCHIP_0_ADDDRESS & ~(page_size-1) 的操作以将地址向下舍入到页对齐边界。您应该能够做一些事情,将页面大小作为编译时常量,这样它仍然可以高效编译。