日期:2014-05-16  浏览次数:21035 次

ioremap内存映射 始终不能访问内存 求解
ioremap内存映射,修改了数次,还是不能正常访问寄存器,基本问题是可以加载模块,但是只要lsmod就会出现段错误
unable to handle kernel paging request at virtual address 7fXXXXXX
望高手指教!!!
C/C++ code

#include <asm/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>
#include <linux/gpio.h>

static int led_major;
static void *base;
#define LED_CONTROLLER_BASE 0x56000050
#define led_all_off    0
#define led_all_on    1
#define DEVICE_NAME    "zx_led"
#define LED_CON (*(volatile u32*)(LED_CONTROLLER_BASE))
#define LED_DAT (*(volatile u32*)(LED_CONTROLLER_BASE + 4))
#define LED_UP    (*(volatile u32*)(LED_CONTROLLER_BASE + 8))
#define LED_MEM_LEN    0x0c
static int led_open(struct inode *inode,struct file *file)
{
    printk("the led driver is open\n");
    return 0;
}
static int led_close(struct inode *inode,struct file *file)
{
    printk("the led driver is close\n");
    return 0;
}
static int led_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
    switch(cmd)
    {
    case led_all_off: 
    //iowrite16(0x00,base + 0x04);
    iowrite16((ioread16(base + 0x04)&0xff)|0x0,base + 0x04);
    break;
    case led_all_on:
    iowrite16(0x0f00,base + 0x04);
    iowrite16((ioread16(base + 0x04)&0xff)|0xff00,base + 0x04);
    break;
    default:
    return -EINVAL;
    }
    return 0;
}

static struct file_operations led_fops =
{
    .owner    =     THIS_MODULE,
    .open    =    led_open,
    .ioctl    =    led_ioctl,
    .release=    led_close,
};

static struct class *led_class;
static int led_init(void)
{
    printk("led initialize\n");
    led_major = register_chrdev(0, DEVICE_NAME, &led_fops);
    if(led_major < 0)
    {
        printk("can't creat led_major\n");
        return led_major;
    }
    printk("register zhengxu_led Driver OK! Major = %d\n", led_major);
    led_class = class_create(THIS_MODULE,DEVICE_NAME);
    if(IS_ERR(led_class))
    {
        printk("led_class create is failed\n");
        return -1;
    }
    printk("class_create is ok\n");
    device_create(led_class, NULL, MKDEV(led_major, 0), NULL, DEVICE_NAME);
    printk("initialize is sucessful\n");
    request_mem_region(LED_CONTROLLER_BASE,LED_MEM_LEN,"zx_led");
    base=ioremap_nocache(LED_CONTROLLER_BASE,LED_MEM_LEN);
    printk("%lx\n",base);
    printk("ioremap is sucessful\n");
    if(base < 0)
    {
        printk("ioremap is failed\n");
    }
//    iowrite16(0xff00,base);
    iowrite16((ioread16(base)&0xff00)|0x00ff,base);
//    iowrite16(0xff00,base + 0x08);
    iowrite16((ioread16(base + 0x08)&0xff)|0xff00,base + 0x08);
    return 0;
}
void led_exit(void)
{
    unregister_chrdev(led_major,DEVICE_NAME);
    device_destroy(led_class,MKDEV(led_major,0));
    class_destroy(led_class);
    iounmap(base);
    release_mem_region(LED_CONTROLLER_BASE,LED_MEM_LEN);
}

module_init(led_init);
module_exit(led_exit);
MODULE_AUTHOR("zhengxu");
MODULE_LICENSE("GPL");




------解决方案--------------------
是可以用ioremap去映射物理内存的,不过base的类型好像是 void __iomem *啊!还有啊,最好多用printk打印程序执行到哪儿出问题了,我一般直接用ioremap。
可以这样定义后就可以直接读值和写值,就把它当做一个变量就可以了。不过你也可以直接搞成结构体类型也成。
#define ADCCON (*(volatile unsigned long *)(base_addr + 0x00))