
解决disagrees about version of symbol device_create-CSDN博客这两条报错是两个独立的问题需要分开处理Unknown symbol device_create (err -22)内核符号版本不匹配。模块编译用的内核源码和你开发板上实际运行的内核版本不一致导致 device_create 这个符号的 CRC 校验值对不上内核拒绝加载模块。module verification failed: signature and/or required key missing内核开启了模块签名校验你的模块没签名或签名密钥不对。这个通常只是警告不影响模块功能但会污染内核tainted。核心解决思路让编译环境和运行内核完全一致根本原因你编译 .ko 时用的内核源码版本 ≠ 开发板正在运行的内核版本。具体来说是 Module.symvers 里的符号 CRC 值和当前内核不一致。[rootATK-stm32mp1]:/lib/modules/5.4.31$ uname -r5.4.31[rootATK-stm32mp1]:/lib/modules/5.4.31$ cat /proc/versionLinux version 5.4.31(useruser-virtual-machine) (gcc version 9.2.1 20191025 (GNU Toolchain for the A-profile Architecture 9.2-2019.12 (arm-9.10))) #1 SMP PREEMPT Sat Aug 22 14:48:05 CST 2026[rootATK-stm32mp1]:/lib/modules/5.4.31$根本原因分析Linux 内核启用了 CONFIG_MODVERSIONS 机制。每个导出的内核符号如 device_create, device_destroy都有一个唯一的 CRC 校验值。编译时驱动模块引用了某个版本的 device_create并记录了当时的 CRC 值。加载时内核检查模块记录的 CRC 值是否与当前运行内核中该符号的 CRC 值一致。结果如果不一致通常是因为编译用的内核源码版本/配置与运行内核不同内核报错 disagrees about version of symbol 并拒绝加载。重新编译内核校验 vermagic最重要的核对手段虚拟机看 ko 的 vermagicmodinfo newchrled.ko开发板看当前运行内核 vermagiccat /proc/version两处 vermagic 字符串必须一字不差空格、编译时间、版本串全部要相同。只要有一处不一样就一定报 err‑22。关键信息提取虚拟机 ko 的 vermagic5.4.31 SMP preempt mod_unload modversions ARMv7 p2v8开发板/proc/versionLinux version 5.4.31 (useruser-virtual‑machine) ... #1 SMP PREEMPT Sun Aug 30 11:26:04 CST 2026✅vermagic 核心字段 SMP、preempt、mod_unload、modversions 完全一致。版本串本身没问题不是 vermagic 字符串不匹配。 ❗那为什么还报disagrees about version of symbolinsmod 同样报disagrees about version of symbol device_create err‑22insmod直接加载还报错彻底排除 modprobe/depmod 问题。本质编译 ko 时没有获取到内核device_create等函数的 CRC 校验值。vermagic 字符串虽然匹配但函数 CRC 不匹配。解决disagrees about version of symbol device_create-CSDN博客disagrees about version of symbol device_create驱动加载报错的解决办法-CSDN博客解决disagrees about version of symbol device_create-CSDN博客useruser-virtual-machine:~/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/boot/dts$ cp stm32mp157c-ed1.dts stm32mp157d-atk.dts useruser-virtual-machine:~/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/boot/dts$ cp stm32mp15xx-edx.dtsi stm32mp157d-atk.dtsi复制文件useruser-virtual-machine:~/linux/alientek_linux/arch/arm/boot/dts$ cp stm32mp157d-atk.dts /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/boot/dts/stm32mp157d-atk.dts useruser-virtual-machine:~/linux/alientek_linux/arch/arm/boot/dts$ cp stm32mp157d-atk.dtsi /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31/arch/arm/boot/dts/stm32mp157d-atk.dtsi编译 stm32mp157d-atk.dts 设备树 最 后 我 们 肯 定 要 编 译 stm32mp157d-atk.dts 得 到 对 应 的 .dtb 文 件 打 开 arch/arm/boot/dts/Makefile到“dtb-$(CONFIG_ARCH_STM32)”配置项在此配置项中加入 “stm32mp157d-atk.dtb”注意不是拼写错误 dts 里写的是stm32mpl57d‑atk.dtsi字母是小写 L (L) 实际文件名stm32mp157d‑atk.dtsi是数字1stm32mp157d是数字 1不是字母 l (L)。DTC 设备树编译器区分大小写、区分数字与字母所以找不到文件。定位文件路径dts 文件路径arch/arm/boot/dts/stm32mp157d‑atk.dts大概率问题中文空格 / 不可见特殊字符你 dts 文件第 14 行的#include stm32mp157d‑atk.dtsi里面的短横线不是普通英文减号-而是复制过来的全角符号、长破折号肉眼看着像横杠但 DTC 识别文件名失败。修复步骤打开stm32mp157d‑atk.dts定位到第 14 行把整行删掉手动手敲一遍不要复制粘贴#include stm32mp157d-atk.dtsi关键点 关闭内核验证# CONFIG_MODULE_SRCVERSION_ALL is not set #CONFIG_MODULE_SIGy # CONFIG_MODULE_SIG_FORCE is not set #CONFIG_MODULE_SIG_ALLy # CONFIG_MODULE_SIG_SHA1 is not set # CONFIG_MODULE_SIG_SHA224 is not set #CONFIG_MODULE_SIG_SHA256y # CONFIG_MODULE_SIG_SHA384 is not set # CONFIG_MODULE_SIG_SHA512 is not set #CONFIG_MODULE_SIG_HASHsha256 # CONFIG_MODULE_COMPRESS is not setCONFIG_MODVERSIONS符号 CRC 版本校验disagrees about version of symbolerr‑22另外我们也可以直接在 Linux 的图形化配置界面上关闭掉内核模块验证输入如下命令 打开 Linux 内核图形化配置界面 make menuconfig 配置路径如下 - Enable loadable module support (MODULES [y]) -Module signature verification 取消对“Module signature verification”选项的选中如图 17.3.3.2 所示bbb chrdevbaseApp led.ko newchrled.ko[rootATK-stm32mp1]:/lib/modules/5.4.31$ depmod[rootATK-stm32mp1]:/lib/modules/5.4.31$ modprobe newchrled[ 281.530903] newchrled: version magic 5.4.31 SMP preempt mod_unload modversions ARMv7 p2v8 should be 5.4.31 SMP preempt mod_unload ARMv7 p2v8 [ 281.548903] newchrled: version magic 5.4.31 SMP preempt mod_unload modversions ARMv7 p2v8 should be 5.4.31 SMP preempt mod_unload ARMv7 p2v8 modprobe: cant load module newchrled (newchrled.ko): inval原因 : KERNELDIR : /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31 驱动要重新编译useruser-virtual-machine:/mnt/hgfs/sharefile/02、Linux驱动例程/test/03newchr$ ls ledApp Makefile Module.symvers newchrled.ko newchrled.mod.c newchrled.o ledApp.c modules.order newchrled.c newchrled.mod newchrled.mod.o useruser-virtual-machine:/mnt/hgfs/sharefile/02、Linux驱动例程/test/03newchr$ rm ledApp useruser-virtual-machine:/mnt/hgfs/sharefile/02、Linux驱动例程/test/03newchr$ arm-none-linux-gnueabihf-gcc ledApp.c -o ledApp useruser-virtual-machine:/mnt/hgfs/sharefile/02、Linux驱动例程/test/03newchr$ cp ledApp /home/user/linux/nfs/rootfs/lib/modules/5.4.31/ useruser-virtual-machine:/mnt/hgfs/sharefile/02、Linux驱动例程/test/03newchr$ cat Makefile KERNELDIR : /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31 CURRENT_PATH : $(shell pwd) obj-m : newchrled.o build: kernel_modules kernel_modules: $(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) modules clean: $(MAKE) -C $(KERNELDIR) M$(CURRENT_PATH) clean useruser-virtual-machine:/mnt/hgfs/sharefile/02、Linux驱动例程/test/03newchr$cp newchrled.ko /home/user/linux/nfs/rootfs/lib/modules/5.4.31/arm-none-linux-gnueabihf-gcc ledApp.c -o ledAppcp ledApp /home/user/linux/nfs/rootfs/lib/modules/5.4.31/板子串口 nfs 挂载[rootATK-stm32mp1]:/home/user$ mount -t nfs -o nolock,nfsvers3 192.168.1.100:/ home/user/linux/nfs getnfs/[rootATK-stm32mp1]:/home/user/getnfs/rootfs/lib/modules/5.4.31$ cp newchrled.ko ledApp /lib/modules/5.4.31/ [rootATK-stm32mp1]:/home/user/getnfs/rootfs/lib/modules/5.4.31$ LS -sh: LS: not found [rootATK-stm32mp1]:/home/user/getnfs/rootfs/lib/modules/5.4.31$ cd /lib/module s/5.4.31/ [rootATK-stm32mp1]:/lib/modules/5.4.31$ ls aaaa chrdevbaseApp ledApp modules.symbols bbb led modules.alias newchrled.ko chrdevbase.ko led.ko modules.dep [rootATK-stm32mp1]:/lib/modules/5.4.31$ rm -f modules.* [rootATK-stm32mp1]:/lib/modules/5.4.31$ mpmode -sh: mpmode: not found [rootATK-stm32mp1]:/lib/modules/5.4.31$ depmod [rootATK-stm32mp1]:/lib/modules/5.4.31$ modprobe newchrled [ 759.805639] newcheled major241,minor0 [rootATK-stm32mp1]:/lib/modules/5.4.31$可以看出申请到的主设备号为 241次设备号为 0。驱动加载成功以后会自 动在/dev 目录下创建设备节点文件/dev/newchrdev输入如下命令查看/dev/newchrdev 这个设备 节点文件是否存在 ls /dev/newchrled -l[rootATK-stm32mp1]:/lib/modules/5.4.31$ lsmod Module Size Used by Tainted: G newchrled 16384 0 [rootATK-stm32mp1]:/lib/modules/5.4.31$ ls /dev/newchrled -l crw-rw---- 1 root root 241, 0 Jan 1 00:12 /dev/newchrled [rootATK-stm32mp1]:/lib/modules/5.4.31$/dev/newchrled 这个设备文件存在而且主设备号为 241此设 备号为 0说明设备节点文件创建成功。 驱动节点创建成功以后就可以使用 ledApp 软件来测试驱动是否工作正常输入如下命令打 开 LED 灯 ./ledApp /dev/newchrled 1 //打开 LED 灯[rootATK-stm32mp1]:/lib/modules/5.4.31$ ./ledApp /dev/newchrled 1 灯在闪无法控制[rootATK-stm32mp1]:/lib/modules/5.4.31$ ./ledApp /dev/newchrled 0[rootATK-stm32mp1]:/lib/modules/5.4.31$关闭心跳闪烁执行echo none /sys/class/leds/sys-led/trigger查看当前触发器状态cat /sys/class/leds/sys-led/trigger正常会看到[heartbeat] none timer gpio‑default‑on这样代表当前是 heartbeat 心跳模式。永久关闭设备树修改打开stm32mp157d‑atk.dtsi找到sys‑led节点sys_led: sys‑led { gpios gpioi 0 GPIO_ACTIVE_HIGH; linux,default‑trigger heartbeat; };把linux,default‑trigger heartbeat;删掉或者改成nonelinux,default‑trigger none;重新编译 dtbs更新开发板 dtb开机就不会自动心跳闪烁。小结板子 LED 子系统节点名字叫sys‑led不是 red临时关闭echo none /sys/class/leds/sys‑led/trigger永久关闭修改设备树的linux,default‑trigger不影响你自己写的newchrled字符驱动两套独立。执行完上面 echo 命令看看板子红灯是不是立刻停止闪烁。。如果要卸载驱动的话输入如下命rmmod newchrled现象echo none /sys/class/leds/sys‑led/trigger关闭了内核 LED 子系统对 PI0 引脚的占用现在执行./ledApp /dev/newchrled 1LED 不亮0也没反应核心原因内核 gpio‑leds 驱动sys‑led一旦加载会占有该 GPIOPI0就算把 trigger 改成 none驱动仍然持有 GPIO你的字符驱动不能复用这个引脚两套驱动抢同一个 GPIO 引脚后打开的驱动操作 GPIO 无效。验证思路卸载内核 led 驱动模块释放 PI0 引脚rmmod gpio_leds再运行你的应用./ledApp /dev/newchrled 1#include linux/types.h #include linux/kernel.h #include linux/delay.h #include linux/ide.h #include linux/init.h #include linux/module.h #include linux/errno.h #include linux/gpio.h #include linux/cdev.h #include linux/device.h #include asm/mach/map.h #include asm/uaccess.h #include asm/io.h /*************************************************************** Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved. 文件名 : newchrled.c 作者 : 正点原子 版本 : V1.0 描述 : LED 驱动文件。 其他 : 无 论坛 : [www.openedv.com](https://www.openedv.com) 日志 : 初版 V1.0 2020/11/24 正点原子团队创建 ***************************************************************/ #define NEWCHARLED_CNT 1 /* 设备号个数 */ #define NEWCHRLED_NAME newchrled /* 名字 */ #define LEDOFF 0 /*关灯 */ #define LEDON 1 /*开灯 */ /* 寄存器物理地址 */ #define PERIPH_BASE (0x40000000) #define MPU_AHB4_PERIPH_BASE (PERIPH_BASE 0x10000000) #define RCC_BASE (MPU_AHB4_PERIPH_BASE 0x0000) #define RCC_MP_AHB4ENSETR (RCC_BASE 0XA28) #define GPIOI_BASE (MPU_AHB4_PERIPH_BASE 0xA000) #define GPIOI_MODER (GPIOI_BASE 0x0000) #define GPIOI_OTYPER (GPIOI_BASE 0x0004) #define GPIOI_OSPEEDR (GPIOI_BASE 0x0008) #define GPIOI_PUPDR (GPIOI_BASE 0x000C) #define GPIOI_BSRR (GPIOI_BASE 0x0018) /* 映射后的寄存器虚拟地址指针 */ static void __iomem *MPU_AHB4_PERIPH_RCC_PI; static void __iomem *GPIOI_MODER_PI; static void __iomem *GPIOI_OTYPER_PI; static void __iomem *GPIOI_OSPEEDR_PI; static void __iomem *GPIOI_PUPDR_PI; static void __iomem *GPIOI_BSRR_PI; /* newchrled 设备结构体 */ struct newchrled_dev { dev_t devid; // 设备号 struct cdev cdev; /* cdev */ struct class *class; /* 类 */ struct device *device; /* 设备 */ int major; /* 主设备号 */ int minor; /* 次设备号 */ }; struct newchrled_dev newchrled; /* led 设备 */ /* * description : LED 打开 / 关闭 * param - sta : LEDON (0) 打开 LEDLEDOFF (1) 关闭 LED * return : 无 */ void led_switch (u8 sta) { u32 val0; if (staLEDON){ valreadl (GPIOI_BSRR_PI); val |(116); writel (val,GPIOI_BSRR_PI); } else if (staLEDOFF) { val readl (GPIOI_BSRR_PI); val|(10); writel (val,GPIOI_BSRR_PI); } } /* * description : 取消映射 * return : 无 */ void led_unmap (void) { iounmap (MPU_AHB4_PERIPH_RCC_PI); iounmap (GPIOI_MODER_PI); iounmap (GPIOI_OTYPER_PI); iounmap (GPIOI_OSPEEDR_PI); iounmap (GPIOI_PUPDR_PI); iounmap (GPIOI_BSRR_PI); } /* inode : 传递给驱动的 inode file : 设备文件 file 结构体有个 private_data return : 0 成功 1: 失败 */ static int led_open(struct inode *inode ,struct file *filp) { filp-private_datanewchrled; return 0; } /* 从设备中读数据 filp: 要打开的设备文件 buff: 返回给用户空间的数据缓冲区 cnt: 要读取的数据长度 offt: 相对文件首地址的偏移 */ static ssize_t led_read(struct file *filp,char __user *buf,size_t cnt,loff_t *offt) { return 0 ; } /*** * 向设备写入数据 * filp : 设备文件表示打开的文件描述 * buf: 要给设备写入的数据 * cnt: 要写入的数据长度 * offt: 相对于文件首地址的偏移 * return: 写入的字节数负数表示写入失败 * * * */ static ssize_t led_write (struct file *flip,const char __user *buf,size_t cnt,loff_t *offt) { int retvalue; unsigned char databuf [1]; unsigned char ledstat; retvaluecopy_from_user (databuf,buf,cnt); if (retvalue0){ printk (kernel write failed!\n\r); return -EFAULT; } ledstatdatabuf [0];// 获取状态值 if (ledstatLEDON){ led_switch (LEDON);// 打开 LED 灯 } else if (ledstatLEDOFF){ led_switch (LEDOFF);// 关闭 LED 灯 } return 0 ; } /*** * * 关闭、释放设备 * 要关闭的设备文件文件描述 * 0 成功 其他失败 */ static int led_release (struct inode *inode,struct file *filp) { return 0; } /* 设备操作函数 */ static struct file_operations newchrled_fops{ .ownerTHIS_MODULE, .openled_open, .readled_read, .writeled_write, .releaseled_release, }; /*** * * 驱动出口函数 * */ static int __init led_init(void) { u32 val 0; int ret; /* 初始化 LED */ /* 1、寄存器地址映射 */ MPU_AHB4_PERIPH_RCC_PI ioremap(RCC_MP_AHB4ENSETR, 4); GPIOI_MODER_PI ioremap(GPIOI_MODER, 4); GPIOI_OTYPER_PI ioremap(GPIOI_OTYPER, 4); GPIOI_OSPEEDR_PI ioremap(GPIOI_OSPEEDR, 4); GPIOI_PUPDR_PI ioremap(GPIOI_PUPDR, 4); GPIOI_BSRR_PI ioremap(GPIOI_BSRR, 4); /* 2、使能 PI 时钟 */ val readl (MPU_AHB4_PERIPH_RCC_PI); // 清空以前设置 val~(0x18);// 1000000 0100 0000 val|(0x18); // 设置新值 writel (val,MPU_AHB4_PERIPH_RCC_PI); // 3. 设置 PI0 通用的输出模式 valreadl (GPIOI_MODER_PI); val~(0x30);//bit0:1 清零 11 val|(0x10); //bit0:1 设置 01 writel (val,GPIOI_MODER_PI); // 4. 设置为 PI0 为高速 valreadl (GPIOI_OSPEEDR_PI); val ~(0x30);//bit0:1 清零 val |(0x20);//bir0:1 设置为 10 writel (val,GPIOI_OSPEEDR_PI); // 5. 设置为 PI0 为上拉 valreadl (GPIOI_PUPDR_PI); val ~(0x30);//bit0:1 清零 val |(0x10);//bir0:1 设置为 10 writel (val,GPIOI_PUPDR_PI); /* 6、默认关闭 LED */ val readl(GPIOI_BSRR_PI); val | (0x1 0); writel(val, GPIOI_BSRR_PI); /* 注册字符设备驱动 */ /* 1、创建设备号 */ if (newchrled.major) { /* 定义了设备号 */ newchrled.devid MKDEV (newchrled.major, 0); ret register_chrdev_region(newchrled.devid, NEWCHARLED_CNT,NEWCHRLED_NAME); if(ret 0) { pr_err(cannot register %s char driver[ret%d]\n,NEWCHRLED_NAME, NEWCHARLED_CNT); goto fail_map; } } else { retalloc_chrdev_region (newchrled.devid, 0, NEWCHARLED_CNT,NEWCHRLED_NAME);/* 申请设备号 */ if (ret0){ pr_err(%s Couldnt alloc_chrdev_region, ret%d\r\n,NEWCHRLED_NAME, ret); goto fail_map; } newchrled.major MAJOR(newchrled.devid); /* 获取主设备号 */ newchrled.minor MINOR(newchrled.devid); /* 获取次设备号 */ } printk (newcheled major% d,minor% d\r\n,newchrled.major,newchrled.minor); /* 2、初始化 cdev */ newchrled.cdev.owner THIS_MODULE; cdev_init(newchrled.cdev,newchrled_fops); /* 3、添加一个 cdev */ ret cdev_add (newchrled.cdev, newchrled.devid, NEWCHARLED_CNT); if (ret 0) goto del_unregister; /* 4、创建类 */ newchrled.class class_create (THIS_MODULE, NEWCHRLED_NAME); if (IS_ERR (newchrled.class)){ goto del_cdev; } /* 5、创建设备 */ newchrled.device device_create (newchrled.class, NULL, newchrled.devid, NULL, NEWCHRLED_NAME); if (IS_ERR (newchrled.device)) { goto destroy_class; } return 0; destroy_class: class_destroy(newchrled.class); del_cdev: cdev_del(newchrled.cdev); del_unregister: unregister_chrdev_region(newchrled.devid,NEWCHARLED_CNT); fail_map: led_unmap(); return -EIO; } /* * description : 驱动出口函数 * param : 无 * return : 无 */ static void __exit led_exit (void) { // 取消映射 led_unmap (); /* 注销字符设备驱动 */ cdev_del(newchrled.cdev);/* 删除 cdev */ unregister_chrdev_region(newchrled.devid, NEWCHARLED_CNT); /* 注销设备号 */ device_destroy (newchrled.class, newchrled.devid); class_destroy (newchrled.class); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE(GPL); MODULE_AUTHOR(ALIENTEK); MODULE_INFO(intree, Y);不改 DTS改用 PI1