字符设备驱动4: ioremap


#define GPIO_OFT(x) ((x) - 0x56000000)
#define GPFCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))

static int s3c24xx_leds_open(struct inode *inode, struct file *file)
{
    int minor = MINOR(inode->i_rdev); //MINOR(inode->i_cdev);

    switch(minor)
    {
        case 0: /* /dev/leds */
        {
            // 配置3引脚为输出
            GPFCON &= ~(0x3<<(4*2));
//oo00:这里GPFCON是虚拟地址,在驱动模块开始(见下面s3c24xx_leds_init)的时候,这个虚拟地址已经通过宏定义 #define GPFCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))被映射到物理地址
            GPFCON |= (1<<(4*2));
    .......
}

static struct file_operations s3c24xx_leds_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   s3c24xx_leds_open,
    .read    =    s3c24xx_leds_read,
    .write    =    s3c24xx_leds_write,
};

static int __init s3c24xx_leds_init(void)//模块入口
{
    gpio_va = ioremap(0x56000000, 0x100000); // 物理地址0x56000000, 映射区分配的大小0x100000字节

printk(DEVICE_NAME "gpio_va = %x ",gpio_va);//oo00 debug
    register_chrdev(LED_MAJOR, DEVICE_NAME, &s3c24xx_leds_fops);
    ...
    leds_class = class_create(THIS_MODULE, "leds");
    ...
    for (minor = 1; minor < 4; minor++)
    {
        leds_class_devs[minor] = class_device_create(leds_class, NULL, MKDEV(LED_MAJOR, minor), NULL, "led%d", minor);

        ..
    }
    
}

gpio_va = ioremap(0x56000000, 0x100000);//变为虚拟地址

#define GPIO_OFT(x) ((x) - 0x56000000)
#define GPFCON (*(volatile unsigned long *)(gpio_va + GPIO_OFT(0x56000050)))

 GPFCON |= (1<<(4*2));//在ioremap成功的前提下,对虚拟地址的操作作用于对应的物理地址

————————————————————————————————————

test:

insmod myleds_ou.ko
ledsgpio_va = c5400000

—————————————————————————————————————————————————————————————————————

ioremap (unsigned long offset, unsigned long size);

参考: S3C2440开发板LED驱动——ioremap 映射  http://www.linuxidc.com/Linux/2012-12/76084.htm

原文地址:https://www.cnblogs.com/mylinux/p/4010896.html