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

  • 相关阅读:
    【转】ubuntu 13.04 普通用户丢失sudo权限后的恢复办法
    #流水账# Mac上用Virtualbox安装//配置虚拟机Ubuntu
    #小知识# 网页内容居中的办法
    无法正常访问FTP服务(Windows 7 + VirtualBox + Ubuntu + vsftpd)
    【转】WordPress上传主题出错:无法创建目录
    判断是PC端还是移动端
    公告滚动
    vs code 汉化 自动保存 插件
    手机端的适配
    css 常见属性
  • 原文地址:https://www.cnblogs.com/ZQQH/p/8630649.html
Copyright © 2011-2022 走看看