如何从内核空间驱动程序访问--- i / o端口

时间:2013-06-07 11:26:11

标签: linux-kernel linux-device-driver

我可以使用user space上的mmap系统调用访问/dev/mem中的i / o端口

#define BCM2708_PERI_BASE       0x20000000
#define GPIO_PADS               (BCM2708_PERI_BASE + 0x100000)
#define CLOCK_BASE              (BCM2708_PERI_BASE + 0x101000)
#define GPIO_BASE               (BCM2708_PERI_BASE + 0x200000)
#define GPIO_PWM                (BCM2708_PERI_BASE + 0x20C000)


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdint.h>

static volatile uint32_t *gpio;

int main(int argc, char **argv)
{
        int fd ;

        //Obtain handle to physical memory
        if ((fd = open ("/dev/mem", O_RDWR | O_SYNC) ) < 0) {
                printf("Unable to open /dev/mem: %s\n", strerror(errno));
                return -1;
        }


        //map a page of memory to gpio at offset 0x20200000 which is where GPIO goodnessstarts
        gpio = (uint32_t *)mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x20200000);

        if ((int32_t)gpio < 0){
                printf("Mmap failed: %s\n", strerror(errno));
                return -1;
        }

        //set gpio17 as an output
        //increment the pointer to 0x20200004
        //set the value through a little bit twiddling where we only modify the bits 21-23 in the register
        *(gpio + 1) = (*(gpio + 1) & ~(7 << 21)) | (1 << 21);

        //toggle gpio17 every second
        while(1){
                //set the pin high
                //increment the pointer to 0x2020001C
                *(gpio + 7) = 1 << 17;

                //sleep
                sleep(1);

                //set the pin to low
                //increment the pointer to 0x20200028
                *(gpio + 10) = 1 << 17;

                sleep(1);
        }
}

地图仅适用于用户空间。现在,我如何在kernel space设备驱动程序?

中访问相同的i / o端口

1 个答案:

答案 0 :(得分:3)

ex的每个模块:GPIO模块都有自己的存储器映射,即处理器技术参考手册中指定的物理地址。首先,您需要使用check_mem_region检查是否正在使用内存区域。如果使用request_mem_region对该内存区域进行空闲请求访问,则使用ioremapioremap_nocache(将总线内存映射到CPU空间)映射GPIO模块,这会返回一个void指针。返回的地址不能保证可以直接用作虚拟地址;它只能由ioread*|iowrite*|read*|write*等函数使用。使用ioread8|16|32/iowrite8|16|32函数从/向I / O端口读取或写入。最后,您需要iounmap取消映射内存,然后需要使用release_mem_region释放内存区域。通常在内核空间中,大多数时候不需要检查和请求内存区域。您只需要使用ioremapioremap_nocache将总线内存映射到CPU空间,并使用iounmap取消映射。