#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\n",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