• 设备驱动 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 *,发现还是没有效果,所以我放弃了,等待以后的再来解答这个问题。

  • 相关阅读:
    hdfs fsck命令查看HDFS文件对应的文件块信息(Block)和位置信息(Locations)
    更高的压缩比,更好的性能–使用ORC文件格式优化Hive
    InfluxDB基本概念和操作
    InfluxDB部署
    Zookeeper运维小结--CancelledKeyException
    Zookeeper源码编译为Eclipse工程(win7下Ant编译)
    ZooKeeper Observers解决节点过多时写性能下降问题
    ZooKeeper日志与快照文件简单分析
    ZooKeeper Administrator's Guide A Guide to Deployment and Administration(吃别人嚼过的馍没意思,直接看官网资料)
    ZOOKEEPER解惑
  • 原文地址:https://www.cnblogs.com/ZQQH/p/8630649.html
Copyright © 2020-2023  润新知