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