设备驱动 ioremap 无效不起作用 iowrite32 无效。解决方法

1.问题出现

 我编写了一个简单的内核驱动模块。在模块初始化时点亮led,模块退出时关闭led。但是我执行这个模块的时候,led一直没有反应

以下是源码:ledq.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>

#define BADDR 0x01c20800
#define PB_CFG1_OFF 0x24 //PB组IO口的功能配置寄存器1对基地址偏移为0x24
#define PB_DATA_OFF 0x34 //PB组IO口的数据寄存器对基地址偏移为0x34

static int *vaddr;

static int __init myled_init(void)
{
    vaddr = ioremap(BADDR, SZ_4K);//映射到物理地址
    //配置io口为输出模式   //先左移16位取反得 FFFF0FFF 相与 再或上 0x1<<16  ioread32就是调用readl
    iowrite32((ioread32(vaddr + PB_CFG1_OFF) & ~(7 << 16)) | (1 << 16), vaddr + PB_CFG1_OFF); //PB4 设定out
    iowrite32((ioread32(vaddr + PB_CFG1_OFF) & ~(7 << 20)) | (1 << 20), vaddr + PB_CFG1_OFF); //PB5 设定out

    iowrite32(ioread32(vaddr + PB_DATA_OFF) & (~(1 << 4)), vaddr + PB_DATA_OFF); //置低开灯
    iowrite32(ioread32(vaddr + PB_DATA_OFF) & (~(1 << 5)), vaddr + PB_DATA_OFF); //置低开灯

    printk("myled_init ...
");
    return 0;
}

static void __exit myled_exit(void)
{
    printk("myled_exit ...
");
    iowrite32(ioread32(vaddr + PB_DATA_OFF) | (1 << 4), vaddr + PB_DATA_OFF); //置高关灯
    iowrite32(ioread32(vaddr + PB_DATA_OFF) | (1 << 5), vaddr + PB_DATA_OFF); //置高关灯
    // iowrite32(ioread32(PB_DAT) | (0x1<<5),PBdat);
    iounmap(vaddr);
}

module_init(myled_init);
module_exit(myled_exit);

MODULE_LICENSE("GPL");

2.问题解决

 经过各种不同的尝试,我发现一个非常蛋疼的问题:ioremap的返回值不能赋值给int型!这就会导致一系列我不懂的问题,可以工作的源码如下

ledq.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>

#define BADDR 0x01c20800
#define PB_CFG1_OFF 0x24 //PB组IO口的功能配置寄存器1对基地址偏移为0x24
#define PB_DATA_OFF 0x34 //PB组IO口的数据寄存器对基地址偏移为0x34

//static int *vaddr; //不可用
//int *vaddr; // 不可用
//unsigned int *vaddr;//不可用

uint8_t *vaddr;//可用

static int __init myled_init(void)
{
    vaddr = ioremap(BADDR, SZ_4K);//映射到物理地址
    //配置io口为输出模式   //先左移16位取反得 FFFF0FFF 相与 再或上 0x1<<16  ioread32就是调用readl
    iowrite32((ioread32(vaddr + PB_CFG1_OFF) & ~(7 << 16)) | (1 << 16), vaddr + PB_CFG1_OFF); //PB4 设定out
    iowrite32((ioread32(vaddr + PB_CFG1_OFF) & ~(7 << 20)) | (1 << 20), vaddr + PB_CFG1_OFF); //PB5 设定out

    iowrite32(ioread32(vaddr + PB_DATA_OFF) & (~(1 << 4)), vaddr + PB_DATA_OFF); //置低开灯
    iowrite32(ioread32(vaddr + PB_DATA_OFF) & (~(1 << 5)), vaddr + PB_DATA_OFF); //置低开灯

    printk("myled_init ...
");
    return 0;
}

static void __exit myled_exit(void)
{
    printk("myled_exit ...
");
    iowrite32(ioread32(vaddr + PB_DATA_OFF) | (1 << 4), vaddr + PB_DATA_OFF); //置高关灯
    iowrite32(ioread32(vaddr + PB_DATA_OFF) | (1 << 5), vaddr + PB_DATA_OFF); //置高关灯
    // iowrite32(ioread32(PB_DAT) | (0x1<<5),PBdat);
    iounmap(vaddr);
}

module_init(myled_init);
module_exit(myled_exit);

MODULE_LICENSE("GPL");

红色高亮即为关键语句。

3.问题思索

  那么我能想到肯定是复制给了不同类型的vaddr会导致ioread时他所读取到的值发生改变,或者iowrite的地址发生改变,导致了模块没有正常工作。

首先我先查看ioremap函数

void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
void *ioremap(unsigned long phys_addr, unsigned long size)

返回类型void *, 但是尝试了强制转换为int *,发现还是没有效果,所以我放弃了,等待以后的再来解答这个问题。

原文地址:https://www.cnblogs.com/ZQQH/p/8630649.html