#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