FEATURED · 精选文章

第二十章 字符设备驱动开发

发布时间 / 2026/8/24 21:39:24
来源 / 创域科博编辑部
栏目 / 资讯中心
第二十章 字符设备驱动开发 1问题原因缺少 C/C 扩展最常见没有安装微软官方C/C扩展命令不会出现文件夹处于【受限模式】截图顶部明显提示未信任文件夹部分命令被隐藏输入命令不全、大小写问题完整命令是C/C: Edit Configurations (JSON)VSCode 版本过旧✅ 分步解决第 1 步信任文件夹先处理截图顶部警告点击顶部蓝色文字管理 → 信任此文件夹受限模式下C/C 的配置命令会直接隐藏这是你当前首要问题第 2 步安装 C/C 官方扩展左侧扩展栏四个方块图标搜索C/C作者Microsoftms-vscode.cpptools点击安装安装完成后重启 VSCode。modprobe chrdevbase 报错disagrees about version of symbol module_layout报错disagrees about version of symbol module_layout编译 ko 所用内核源码 ≠ 开发板当前运行内核的原始编译源码虽然版本号同为 5.4.31但是.config、Module.symvers、CRC 校验不一致重中之重.config配置文件必须和板子固件原始编译配置一模一样板子固件编译时间Thu Jan 12 15:16:06 CST 2023你现在用的imx_v7_defconfig不一定等于固件当年使用的配置正点原子固件包内一般附带固件配套.config复制到内核源码根目录覆盖任意配置差异SMP、PREEMPT、MODVERSIONS都会直接导致 vermagic / CRC 不匹配modprobe chrdevbase.ko 与 modprobe chrdevbase 的区别这两个命令在 Linux 内核模块加载中有着本质区别理解它们对于解决模块加载失败至关重要。modprobe chrdevbase.ko这是一个错误的用法。modprobe命令设计用于加载位于标准模块目录如/lib/modules/$(uname -r)/中的模块它通过模块名而不是带.ko后缀的文件名在模块依赖关系数据库modules.dep中查找并加载模块及其依赖。直接指定.ko文件路径不是modprobe的标准用法通常会导致命令失败或行为不符合预期。modprobe chrdevbase这是正确的标准用法。它指示系统加载名为chrdevbase的模块。系统会在/lib/modules/$(uname -r)/modules.dep文件中查找chrdevbase.ko的实际路径。检查并加载chrdevbase所依赖的其他模块如果有。执行模块的初始化函数将模块插入到运行中的内核。前提是该模块已通过make modules_install正确安装到了标准模块目录并且生成了正确的依赖文件。对于驱动开发调试的实际情况在开发过程中我们通常在源码目录下编译出.ko文件但并未将其安装到系统标准目录。此时应该使用insmod chrdevbase.ko命令。insmod是“插入模块”的意思它不处理模块依赖直接加载指定的.ko文件。这是开发阶段加载自定义驱动模块最常用、最直接的方法。总结与选择开发/测试阶段在编译目录下使用insmod chrdevbase.ko。生产/部署阶段将模块安装到系统后使用modprobe chrdevbase。避免使用modprobe chrdevbase.ko非标准用法。因此如果你在开发板尝试加载自己编译的chrdevbase.ko时遇到disagrees about version of symbol module_layout错误根本原因在于内核版本不匹配如前文所述与使用modprobe还是insmod无关。但使用正确的命令insmod可以避免因命令使用不当而产生的额外困惑。.config 覆盖源码根目录完整编译内核make xxx modules -j4生成 Module.symvers编译驱动模块Makefile 指向这套配套源码拷贝新 ko 到开发板modprobe正常加载 Makefile 标准模板确认你当前 Makefile 是否完整KERNELDIR : /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31 CURRENT_PATH : $(shell pwd) obj-m : chrdevbase.o build: make -C $(KERNELDIR) M$(CURRENT_PATH) ARCHarm CROSS_COMPILEarm-linux-gnueabihf- modules clean: make -C $(KERNELDIR) M$(CURRENT_PATH) clean虚拟机strings chrdevbase.ko | grep vermagic开发板cat /proc/version虚拟机strings chrdevbase.ko | grep vermagic开发板cat /proc/version最终重新5.4.31 编译 将tm32mp157d-atk.dtb uImage 挂在 tftpmodprobe chrdevbase.ko modprobe chrdevbase 什么区别modprobe chrdevbasevsmodprobe chrdevbase.ko标准规范modprobe 后面跟【模块名】不带 .kochrdevbase 带.kochrdevbase.ko属于非常规写法行为不一样1. modprobe chrdevbase标准写法教程推荐去modules.depdepmod 生成的依赖表查找chrdevbase这个模块读取依赖自动加载它依赖的其他内核模块加载成功后lsmod里面模块名称就是chrdevbase卸载配套modprobe -r chrdevbase同样不带后缀2. modprobe chrdevbase.ko带后缀不规范modprobe 会把chrdevbase.ko 整体当成模块名去 modules.dep 查找如果 modules.dep 里没有名为chrdevbase.ko的条目大概率直接报错module xxx.ko not found in modules.dep部分新版 kmod 兼容处理识别成文件名直接加载 ko不再自动处理完整依赖行为接近 insmod你这次碰巧加载成功属于兼容特例不具备通用性换环境很容易报错 结合你截图里现象解释modprobe chrdevbase.ko [ 450.473140] chrdevbase init! # 加载成功兼容模式 modprobe chrdevbase # 无打印因为模块已经加载过了 lsmod 能看到 chrdevbase第二次执行modprobe chrdevbase没有打印chrdevbase init!模块一旦加载成功再次 modprobe 不会重复执行入口函数不会再次打印 init卸载后rmmod chrdevbase再 modprobe 才会重新打印 init 补充区分三条命令modprobe chrdevbase✅ 标准查 modules.dep自动加载依赖modprobe chrdevbase.ko❌ 非标准尝试按文件名加载依赖处理失效极易报错insmod chrdevbase.ko直接指定 ko 文件加载完全不解析依赖⚠️ 额外提示你截图里的警告module verification failed: signature and/or required key missing - tainting kernel含义你的内核开启模块签名校验但 ko 没有签名驱动依然可以加载只是内核标记为tainted被污染不影响实验学习正式产品需要处理签名。✅ 开发实验推荐固定用法# 加载 modprobe chrdevbase # 卸载 modprobe -r chrdevbase输入“lsmod”命令即可查看当前系统中存在的模块[rootATK-stm32mp1]:/lib/modules/5.4.31$ modprobe chrdevbase [ 1583.815287] chrdevbase init! [rootATK-stm32mp1]:/lib/modules/5.4.31$ lsmod Module Size Used by Tainted: G chrdevbase 16384 0 [rootATK-stm32mp1]:/lib/modules/5.4.31$当前系统只有“chrdevbase”这一个模块。输入如下命令查看当前 系统中有没有 chrdevbase 这个设备cat /proc/devices当前系统存在 chrdevbase 这个设备主设备号为 200跟我们设置的主设备号一致。创建设备节点文件 驱动加载成功需要在/dev 目录下创建一个与之对应的设备节点文件应用程序就是通过操 作这个设备节点文件来完成对具体设备的操作。输入如下命令创建/dev/chrdevbase 这个设备节 点文件[rootATK-stm32mp1]:/lib/modules/5.4.31$ mknod /dev/chrdevbase c 200 0 [rootATK-stm32mp1]:/lib/modules/5.4.31$其中“mknod”是创建节点命令“/dev/chrdevbase”是要创建的节点文件“c”表示这是个 字符设备“200”是设备的主设备号“0”是设备的次设备号。创建完成以后就会存在 /dev/chrdevbase 这个文件可以使用“ls /dev/chrdevbase -l”命令查看[rootATK-stm32mp1]:/lib/modules/5.4.31$ ls /dev/chrdevbase -l crw-r--r-- 1 root root 200, 0 Feb 21 17:20 /dev/chrdevbase [rootATK-stm32mp1]:/lib/modules/5.4.31$如果 chrdevbaseAPP 想要读写 chrdevbase 设备直接对/dev/chrdevbase 进行读写操作即可。 相当于/dev/chrdevbase 这个文件是 chrdevbase 设备在用户空间中的实现。前面一直说 Linux 下 一切皆文件包括设备也是文件。chrdevbase 设备操作测试[rootATK-stm32mp1]:/lib/modules/5.4.31$ ./chrdevbaseApp /dev/chrdevbase 1 [ 2231.625077] kernel senddata ok! read data:kernel data! [rootATK-stm32mp1]:/lib/modules/5.4.31$[rootATK-stm32mp1]:/lib/modules/5.4.31$ ./chrdevbaseApp /dev/chrdevbase 2 [ 2265.073573] kernel recevdata:usr data! [rootATK-stm32mp1]:/lib/modules/5.4.31$chrdevbase_read 函数输出的信息因为 chrdevbaseAPP 使用 read 函数从 chrdevbase 设备读取数 据因此 chrdevbase_read 函数就会执行。chrdevbase_read 函数向 chrdevbaseAPP 发送“kernel data!”数据chrdevbaseAPP 接收到以后就打印出来“read data:kernel data!”就是 chrdevbaseAPP 打印出来的接收到的数据。说明对 chrdevbase 的读操作正常接下来测试对 chrdevbase 设备的 写操作输入如下命令 ./chrdevbaseApp /dev/chrdevbase 2[rootATK-stm32mp1]:/lib/modules/5.4.31$ ./chrdevbaseApp /dev/chrdevbase 2 [ 2265.073573] kernel recevdata:usr data! [rootATK-stm32mp1]:/lib/modules/5.4.31$只有一行“kernel recevdata:usr data!”这个是驱动程序中的 chrdevbase_write 函数输出的。 chrdevbaseAPP 使用 write 函数向 chrdevbase 设备写入数据“usr data!”。chrdevbase_write 函数接 收到以后将其打印出来。说明对 chrdevbase 的写操作正常既然读写都没问题说明我们编写 的 chrdevbase 驱动是没有问题的如果不再使用某个设备的话可以将其驱动卸载掉比如输入如下命令卸载掉 chrdevbase 这 个设备 rmmod chrdevbase[rootATK-stm32mp1]:/home/user/getnfs/rootfs$ cd 5.4.31/ [rootATK-stm32mp1]:/home/user/getnfs/rootfs/5.4.31$ ls [rootATK-stm32mp1]:/home/user/getnfs/rootfs/5.4.31$ rmmod chrdevbase [ 5094.423605] chrdevbase exit! [rootATK-stm32mp1]:/home/user/getnfs/rootfs/5.4.31$ lsmod Module Size Used by Tainted: G [rootATK-stm32mp1]:/home/user/getnfs/rootfs/5.4.31$至此chrdevbase 这个设备的整个驱动就验证完成了驱动工作正常。本章我们详细的讲 解了字符设备驱动的开发步骤并且以一个虚拟的 chrdevbase 设备为例带领大家完成了第一 个字符设备驱动的开发掌握了字符设备驱动的开发框架以及测试方法rm: 无法删除/home/user/linux/Drivers/Linux_Drivers/01chrdebbase/Module.symvers: 权限不够报错原因rm: 无法删除 Module.symvers: 权限不够Module.symvers文件之前大概率是用sudo/root权限生成的现在普通user用户执行make clean没有删除权限。✅ 方案 1推荐手动清理进入驱动目录执行sudo rm -f *.o *.ko *.mod.c Module.symvers modules.order .*.cmd make clean✅ 方案 2 直接 sudo 执行 cleansudo make clean⚠️ 注意不建议长期用 sudo 编译驱动容易后续所有文件权限全部变成 root反复权限报错清理完之后编译最好还是普通 user 用户make✅ 方案 3 修复整个文件夹所有者根治权限问题把驱动目录全部改成当前 user 拥有以后不会再报权限不足sudo chown -R user:user /home/user/linux/Drivers/Linux_Drivers/01chrdebbase make clean 顺带检查你的 Makefile 小优化不报错写法可以简化适配原子教程你现在的 Makefile 可以精简成标准模板功能一致KERNELDIR ? /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31 PWD : $(shell pwd) obj-m chrdevbase.o all: make -C $(KERNELDIR) M$(PWD) modules clean: make -C $(KERNELDIR) M$(PWD) clean❗ 补充提醒编译驱动make不要加 sudo一旦 sudo make生成文件归属 root下次 clean 必报权限不足确认linux-5.4.31内核源码已经提前完整编译过make modules否则 ko 依然会版本不匹配清理完成后直接make生成新的 chrdevbase.ko 传到开发板测试即可如果你需要我还可以告诉你如何查看文件归属ls -l Module.symvers确认是不是 root 权限。问题分析权限问题ls -l看到所有文件所有者都是root root普通user用户无法正常删除编译产物make clean会权限报错。编译报错多个目标匹配是 Makefile 写法问题 旧编译文件残留共同引发。目录里遗留了root 创建的隐藏依赖文件.chrdevbase.o.d普通 user 用户无法覆盖写入编译临时文件。make -C /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31 M/home/user/linux/Drivers/Linux_Drivers/01chrdebbase modules make[1]: 进入目录“/home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31” CC [M] /home/user/linux/Drivers/Linux_Drivers/01chrdebbase/chrdevbase.o /home/user/linux/Drivers/Linux_Drivers/01chrdebbase/chrdevbase.c:147:2: 致命错误 打开依赖文件 /home/user/linux/Drivers/Linux_Drivers/01chrdebbase/.chrdevbase.o.d权限不够 147 | MODULE_INFO(intree, Y); | ^~~~~~~~~~~ 编译中断。 scripts/Makefile.build:265: recipe for target /home/user/linux/Drivers/Linux_Drivers/01chrdebbase/chrdevbase.o failed make[2]: *** [/home/user/linux/Drivers/Linux_Drivers/01chrdebbase/chrdevbase.o] Error 1 Makefile:1692: recipe for target /home/user/linux/Drivers/Linux_Drivers/01chrdebbase failed make[1]: *** [/home/user/linux/Drivers/Linux_Drivers/01chrdebbase] Error 2 make[1]: 离开目录“/home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31” Makefile:8: recipe for target kernel_modules failed make: *** [kernel_modules] Error 2 useruser-virtual-machine:~/linux/Drivers/Linux_Drivers/01chrdebbase$ sudo chown -R user:user /home/user/linux/Drivers/Linux_Drivers/01chrdebbase useruser-virtual-machine:~/linux/Drivers/Linux_Drivers/01chrdebbase$ make make -C /home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31 M/home/user/linux/Drivers/Linux_Drivers/01chrdebbase modules make[1]: 进入目录“/home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31” CC [M] /home/user/linux/Drivers/Linux_Drivers/01chrdebbase/chrdevbase.o Building modules, stage 2. MODPOST 1 modules CC [M] /home/user/linux/Drivers/Linux_Drivers/01chrdebbase/chrdevbase.mod.o LD [M] /home/user/linux/Drivers/Linux_Drivers/01chrdebbase/chrdevbase.ko make[1]: 离开目录“/home/user/linux/atk-mp1/linux/my_linux/linux-5.4.31” useruser-virtual-machine:~/linux/Drivers/Linux_Drivers/01chrdebbase$编译APParm-none-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseAppuseruser-virtual-machine:~/linux/Drivers/Linux_Drivers/01chrdebbase$ arm-none-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseApp useruser-virtual-machine:~/linux/Drivers/Linux_Drivers/01chrdebbase$ la chrdevbaseApp chrdevbase.c .chrdevbase.ko.cmd chrdevbase.mod.c chrdevbase.mod.o chrdevbase.o Makefile Module.symvers chrdevbaseApp.c chrdevbase.ko chrdevbase.mod .chrdevbase.mod.cmd .chrdevbase.mod.o.cmd .chrdevbase.o.cmd modules.order useruser-virtual-machine:~/linux/Drivers/Linux_Drivers/01chrdebbase$nfs 挂载路径没有文件showmount -e 查看nfs 共享路径useruser-virtual-machine:~/linux/Drivers/Linux_Drivers/01chrdebbase$ cd /home/user/linux/nfs/rootfs/lib/modules/5.4.31/ useruser-virtual-machine:~/linux/nfs/rootfs/lib/modules/5.4.31$ ls aaaa chrdevbaseApp chrdevbase.ko useruser-virtual-machine:~/linux/nfs/rootfs/lib/modules/5.4.31$ ls aaaa chrdevbaseApp chrdevbase.ko useruser-virtual-machine:~/linux/nfs/rootfs/lib/modules/5.4.31$ touch bbb useruser-virtual-machine:~/linux/nfs/rootfs/lib/modules/5.4.31$ showmount -e Export list for user-virtual-machine: /home/user/linux/nfs * useruser-virtual-machine:~/linux/nfs/rootfs/lib/modules/5.4.31$[rootATK-stm32mp1]:/home/user/getnfs/rootfs/lib/modules/5.4.31$ cd /lib/modules /5.4.31/ [rootATK-stm32mp1]:/lib/modules/5.4.31$ ls aaaa chrdevbaseApp modules.dep chrdevbase.ko modules.alias modules.symbols [rootATK-stm32mp1]:/lib/modules/5.4.31$ rm -f * [rootATK-stm32mp1]:/lib/modules/5.4.31$ ls [rootATK-stm32mp1]:/lib/modules/5.4.31$ cp /home/user/getnfs/rootfs/lib/module s/5.4.31/* ./ [rootATK-stm32mp1]:/lib/modules/5.4.31$ ls aaaa bbb chrdevbase.ko chrdevbaseApp [rootATK-stm32mp1]:/lib/modules/5.4.31$ depmod [rootATK-stm32mp1]:/lib/modules/5.4.31$ modprobe chrdevbase [rootATK-stm32mp1]:/lib/modules/5.4.31$ ls aaaa chrdevbase.ko modules.alias modules.symbols bbb chrdevbaseApp modules.dep [rootATK-stm32mp1]:/lib/modules/5.4.31$ lsmod Module Size Used by Tainted: G chrdevbase 16384 0 [rootATK-stm32mp1]:/lib/modules/5.4.31$ cat /proc/devices Character devices: 1 mem 2 pty 3 ttyp 4 /dev/vc/0 4 tty 5 /dev/tty 5 /dev/console 5 /dev/ptmx 5 ttyRPMSG 7 vcs 10 misc 13 input 21 sg 29 fb 89 i2c 90 mtd 108 ppp 116 alsa 128 ptm 136 pts 153 spi 166 ttyACM 180 usb 188 ttyUSB 189 usb_device 200 chrdevbase 216 rfcomm 226 drm 242 rpmb 243 ttyGS 244 ttyUSI 245 ttySTM 246 bsg 247 watchdog 248 tee 249 iio 250 ptp 251 pps 252 cec 253 rtc 254 gpiochip Block devices: 1 ramdisk 7 loop 8 sd 11 sr 31 mtdblock 65 sd 66 sd 67 sd 68 sd 69 sd 70 sd 71 sd 128 sd 129 sd 130 sd 131 sd 132 sd 133 sd 134 sd 135 sd 179 mmc 254 virtblk 259 blkext [rootATK-stm32mp1]:/lib/modules/5.4.31$ mknod /dev/chrdevbase c 200 0 [rootATK-stm32mp1]:/lib/modules/5.4.31$ ls /dev/chrdevbase -l crw-r--r-- 1 root root 200, 0 Feb 21 19:18 /dev/chrdevbase [rootATK-stm32mp1]:/lib/modules/5.4.31$ ./chrdevbaseApp /dev/chrdevbase 1 [ 8857.040525] chrdevbase init! [ 8957.094541] chrdevbase open! [ 8957.098927] kernel senddata ok! read data:kernel data! [rootATK-stm32mp1]:/lib/modules/5.4.31$ ./chrdevbaseApp /dev/chrdevbase 2 [ 8974.459888] chrdevbase open! [ 8974.461390] kernel recevdata:usr data! write data:usr data! [rootATK-stm32mp1]:/lib/modules/5.4.31$ rmmod chrdevbase [ 9001.674865] chrdevbase exit! [rootATK-stm32mp1]:/lib/modules/5.4.31$
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻