1.hello驱动

news/2026/1/21 19:58:52/文章来源:https://www.cnblogs.com/r5ett/p/19508680

1.怎么写驱动程序

  • 确定主设备号
  • 定义自己的file_operations结构体
  • 实现对应的open/read/write等函数,填入file_operations结构体
  • 把file_operations结构体告诉内核:注册驱动程序(register_chrdev(major, file_operations))
  • 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数
  • 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数(unregister_chrdev(major, file_operations))
  • 其他完善:提供设备信息,自动创建设备节点

2.写驱动程序

  • 驱动中实现open, read,write,release,APP 调用这些函数时,都打印内核信息
  • APP调用write函数时,传入的数据保存在驱动中
  • APP 调用read 函数时.把驱动中保存的数据返回给 APP
hello_drv.c
#include <linux/module.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>// 1.确定主设备号
static int major = 0; // 0表示动态分配主设备号
static char kernel_buf[1014]; // 内核缓冲区
static struct class *hello_class; // 设备类#define MIN(a, b) ((a) < (b) ? (a) : (b))// 3.实现对应的open/read/write等函数,填入file_operations结构体
static ssize_t hello_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{int err;printk("%s %s line %d", __FILE__, __FUNCTION__, __LINE__);/* 内核打印函数 */err = copy_to_user(buf, kernel_buf, MIN(size, 1024));/* 从内核空间拷贝数据到用户空间 */return MIN(size, 1024);
}static ssize_t hello_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int err;printk("%s %s line %d", __FILE__, __FUNCTION__, __LINE__);err = copy_from_user(kernel_buf, buf, MIN(size, 1024));/* 从用户空间拷贝数据到内核空间 */return MIN(size, 1024);
}static int hello_drv_open(struct inode *node, struct file *file)
{printk("%s %s line %d", __FILE__, __FUNCTION__, __LINE__);return 0;
}static int hello_drv_close(struct inode *node, struct file *file)
{printk("%s %s line %d", __FILE__, __FUNCTION__, __LINE__);return 0;
}// 2.定义自己的file_operations结构体
static struct file_operations hello_drv ={.owner   = THIS_MODULE, /* 指定模块所有者 */.open    = hello_drv_open,.read    = hello_drv_read,.write   = hello_drv_write,.release = hello_drv_close,
};// 4.把file_operations结构体告诉内核:注册驱动程序(register_chrdev(major, file_operations))z
// 5.谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数
static int __init hello_init(void)
{int err;printk("%s %s line %d", __FILE__, __FUNCTION__, __LINE__);major = register_chrdev(0, "hello", &hello_drv);/* 通过/dev/hello访问这个程序 */hello_class = class_create(THIS_MODULE, "hello_class"); /* 创建设备类 */err = PTR_ERR(hello_class);/* 判断是否创建成功 */if (IS_ERR(hello_class)){/* 创建失败 */unregister_chrdev(major, "hello");return -1;}/* device_create(类, 父设备, (主设备号,次设备号), 设备私有数据的指针, 名字) */device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");/* 创建设备节点 /dev/hello */return 0;
}// 6.有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数(unregister_chrdev(major, file_operations))
static void __exit hello_exit(void)
{printk("%s %s line %d", __FILE__, __FUNCTION__, __LINE__);device_destroy(hello_class, MKDEV(major, 0));/* 删除设备节点 /dev/hello */class_destroy(hello_class); /* 删除设备类 */ unregister_chrdev(major, "hello");
}// 7.其他完善:提供设备信息,自动创建设备节点
module_init(hello_init); /* 指定入口函数 */
module_exit(hello_exit); /* 指定出口函数 */
MODULE_LICENSE("GPL"); /* 指定模块许可证 */

3.写测试程序程序

要实现写、读功能:

./hello_drv_test r5ett  //把字符串“r5ett”发给驱动程序
./hello_drv_test        //把驱动中保存的字符串读回来
hello_drv_test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>/** ./hello_drv_test -w adc * ./hello_drv_test -r */
int main(int argc, char **argv){int fd;//* 文件描述符 */char buf[1024];/* 用户空间缓冲区 */int len;/* 实际读写的长度 *//* 1. 判断参数 */if(argc < 2){printf("Usage ./hello_drv_test -w <string>\n", argv[0]);printf("Usage ./hello_drv_test -r\n", argv[0]);return -1;}/* 2. 打开文件 */fd = open("/dev/hello", O_RDWR);/* 读写方式打开设备文件 */if(fd == -1){perror("can not open file /dev/hello failed\n");return -1;}/* 3. 读文件或写文件 */if((0 == strcmp(argv[1], "-w") && (argc ==3))){len = strlen(argv[2]) + 1;/* 包括字符串结束符 */len = len < 1024 ? len : 1024;/* 最多写1024字节 */write(fd, argv[2], len);/* 向设备文件写数据 */}else{len = read(fd, buf, 1024);/* 从设备文件读数据 */buf[len] = '\0';/* 防止没有结束符 */printf("APP read: %s\n", buf);}close(fd);/* 关闭文件 */return 0;
}

4.Makefile

Makefile
#定义内核源码路径
KERN_DIR = /home/book/100ask_imx6ull-sdk/Linux-4.9.88#定义默认目标
#编译内核模块
#-C表示切换到指定目录执行make
#M='pwd': M是内核Makefile识别的参数,意思是编译完内核自身的东西后,回到当前目录
#modules:告诉内核Makefile执行“编译模块”的目标
#最终会把当前目录下的hello_drv.c编译成hello_drv.ko
#$(CROSS_COMPILE);这是交叉编译工具链的前缀,比如imx6ull的arm-linux-gnueabihf-
#需要你在执行make前先export这个变量,否则会用主机的gcc编译,生成的程序无法在开发板运行
all:make -C $(KERN_DIR) M=$(shell pwd) modules $(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c#定义清理目标
#调用内核Makefile清理当前目录的模块编译文件,比如.ko、.o、.mod.c等
#删除编译模块时生成的modules.order文件,内核编译的辅助文件s
clean:make -C $(KERN_DIR) M=$(shell pwd) modules cleanrm -rf modules.orderrm -f hello_drv_test#指定要编译的模块文件
#obj-m告诉内核Makefile“要把hello_drv.o编译成可加载模块
#把当前目录的hello_drv.c编译成hello_drv.ko
obj-m += hello_drv.o
make 构建
make clean 清理

5.运行

首先在虚拟机上配置交叉编译工具链

export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin

然后make生成hello_drv.ko和hello_drv_test
用adb将这两个文件发给开发板adb push hello_drv.ko hello_drv_test 目的地址
在开发板上insmod hello_drv.ko加载内核模块
然后可以通过lsmod列出当前已加载到内核中的所有可加载模块

ls /dev/hello -l 看有没有设备节点
crw------- 1 root root 240, 0 Jan  1 00:34 /dev/hello
./hello_drv_test -w 13245 写12345
./hello_drv_test -r 读
APP read: 13245 结果

最后rmmod hello_drv卸载内核模块
dmesg查看打印信息(内容比较多,比如下图)
image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1196108.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025冬 超级无敌挂分大王

11.12 分层测试~ 开 T1,MST 板题?写了一下,最后用大法师求根到点的边权和。炸。瞎改了一堆。炸炸炸。 无语,滚去 T2。怎么是类 CSPS T1,瞎猜了个基于优先队列的贪心,因为不会写堆所以改写线段树,胡写了一下,大…

文科核心期刊发表指南:AI助力高效投稿

8大文科论文查重工具核心对比 排名 工具名称 查重准确率 数据库规模 特色功能 适用场景 1 Aicheck 98% 10亿文献 AI降重、AIGC检测 初稿查重与修改 2 Aibiye 96% 8亿文献 智能改写、格式调整 终稿精细优化 3 秒篇 95% 6亿文献 一键生成降重报告 快速查…

Agentic-KGR:多智能体强化学习驱动的知识图谱本体渐进式扩展技术

Agentic-KGR是一种通过多轮强化学习驱动的多智能体交互实现知识图谱本体渐进式自进化的技术框架。该框架遵循"提取→暂存→更新→奖励计算→晋升"的闭环流程&#xff0c;依赖LLM的知识发现能力和反馈闭环机制。系统通过多尺度提示压缩、Neo4j数据库管理、分层决策机制…

教师必看!国内发成绩小程序大盘点

教师必看!国内发成绩小程序大盘点引言:成绩发布痛点与小程序崛起 每到期中期末考试结束,便是老师们的 “成绩发布攻坚战”。传统的成绩发布方式,简直是问题百出。手动录入成绩,那密密麻麻的数字,一不留神就可能输…

瞬维智能:房产获客的精准革命,让每一份投入都开出确定的花

在房产行业摸爬滚打的人&#xff0c;都曾经历过这样的时刻&#xff1a;深夜对着电脑屏幕&#xff0c;反复修改房源文案却始终触不到那个“对的人”&#xff1b;或是花费大量人力物力制作的内容&#xff0c;最终却石沉大海&#xff0c;连个水花都没溅起。 瞬维智能的AI获客智能体…

学Simulink--电机控制架构与算法实现​场景示例:基于Simulink的电机电流环PI参数整定仿真

目录 手把手教你学Simulink 一、引言:为什么“调不好PI”会让高性能电机变成“抖动机器”? 二、核心原理:电流环的“等效传递函数”建模 1. 电流环简化模型(d/q轴解耦后) 2. 数字控制系统中的关键延迟 3. 电流环闭环结构 三、应用场景:伺服驱动器中的高性能电流环设…

稀土合金回收利用:资源闭环新路径,产业盈利与环保双赢

稀土被誉为“现代工业的维生素”,稀土合金更是新能源、航空航天、高端制造领域的核心材料,不可或缺。但原生稀土储量有限、开采污染大,随着全球稀土需求激增,稀土合金回收利用已成为缓解资源缺口、践行双碳目标、提…

P6822 [PA 2012 Finals] Tax 题解

题目大意 可恶,我们老师竟然把紫题放到了模拟赛里。 题目传送门 原题中题意说的很清楚了。 思路 转化问题 首先先新建两条边,使原题点到点的问题转化成边到边的问题。 可以连接一条从 \(0\) 到 \(1\),长度为 \(0\) …

基于Springboot+Vue的校园二手书交易系统(源码+lw+部署文档+讲解等)

课题介绍 本课题针对校园内二手书流转不畅、交易信息分散、供需对接低效、交易安全缺乏保障等痛点&#xff0c;设计并实现基于SpringbootVue的校园二手书交易系统&#xff0c;构建集图书发布、检索匹配、在线沟通、交易履约于一体的数字化校园交易平台。系统以MySQL为数据存储核…

UVA1464 Traffic Real Time Query System 题解

UVA1464 Traffic Real Time Query System 题解 题目大意 题目传送门 给出一张 \(n\) 个点,\(m\) 条边的无向连通图,问从第 \(s\) 条边到第 \(t\) 号边必须经过多少点。题目有多组数据。 思路 转换问题 这道题类似于 …

基于Springboot+Vue的校园家教信息平台的设计开发(源码+lw+部署文档+讲解等)

课题介绍 本课题针对校园内家教供需信息不对称、对接效率低、资质审核缺失、服务质量难保障等痛点&#xff0c;设计并开发基于SpringbootVue的校园家教信息平台&#xff0c;构建集家教信息发布、资质审核、供需匹配、服务跟踪于一体的数字化校园服务平台。系统以MySQL为数据存储…

基于C++的《Head First设计模式》笔记——模式合作

目录 一.专栏简介 二.模式合作 三.与鸭子重聚 1.创建一个Quackable接口 2.鸭子实现Quackable 3.模拟器 四.加上鹅 五.鹅适配器 六.模拟器中加入鹅 七.叫声的统计 八.模拟器加入装饰者 九.工厂生产鸭子 十.模拟器使用工厂 十一.创建一群鸭子 十二.修改模拟器 十三…

B4172 学习计划 题解

B4172 学习计划 题解 思路 可以将收益式子换一下,设 \(c_i\) 为 \(a_i\) 被分到的段的编号,那收益式子变成 \(\sum_{i=1}^n a_i \times b_{c_i}\)。 很显然的 dp, 设 \(f_{i,j}\) 为将 \(a\) 的前 \(i\) 个数分成 \(…

解码AI生态新范式,擘画智能未来新图景

2月23日&#xff0c;以“模塑全球 无限可能”为主题的2025全球开发者先锋大会在上海徐汇圆满落幕。这场汇聚全球智慧的行业盛会&#xff0c;以空前的行业影响力构建起覆盖产学研用全链条的生态体系&#xff0c;成为引领人工智能开源创新与垂类应用落地的风向标。瞬维智能CEO哲西…

基于Springboot+Vue的校园设备维护报修系统(源码+lw+部署文档+讲解等)

课题介绍 本课题针对校园内设备故障报修流程繁琐、响应滞后、维修进度难追踪、设备台账管理混乱等痛点&#xff0c;设计并开发基于SpringbootVue的校园设备维护报修系统&#xff0c;构建集报修提交、工单分配、维修跟踪、设备台账管理于一体的数字化校园服务平台。系统以MySQL为…

基于Springboot+Vue的校园闲置物品交易系统(源码+lw+部署文档+讲解等)

课题介绍本课题针对校园内闲置物品流转不畅、交易信息分散、供需匹配低效、线下交易安全性不足等痛点&#xff0c;设计并开发基于SpringbootVue的校园闲置物品交易系统&#xff0c;构建集物品发布、检索匹配、在线沟通、交易履约于一体的数字化校园交易平台。系统以MySQL为数据…

学术写作利器:主流论文工具功能对比与实战场景解析

工具核心特点速览 工具名称 核心优势 适用场景 数据支撑 aibiye 全流程覆盖降重优化 从开题到答辩的一站式需求 支持20万字长文逻辑连贯 aicheck 院校规范适配模板化输出 国内本硕博论文框架搭建 覆盖90%高校格式要求 秒篇 3分钟文献综述生成 紧急补文献章节 知…

瞬维智能CEO刘哲先生受邀参加2025年火山引擎FORCE原动力大会

2025年12月18日-19日&#xff0c;火山引擎FORCE原动力大会在上海世博中心盛大启幕。本次大会以“AI原生赋能&#xff0c;开源共筑生态”为核心主题&#xff0c;汇聚了火山引擎总裁谭待、火山引擎智能算法负责人吴迪、比亚迪集团高级副总裁杨冬生及扣子负责人乔屿等全球AI领域顶…

完整教程:【华为云DevUI开发实战】

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

基于Springboot+Vue的物品租赁管理系统(源码+lw+部署文档+讲解等)

课题介绍本课题针对物品租赁行业租赁流程繁琐、物品状态难追踪、押金核算复杂、租赁数据零散等痛点&#xff0c;设计并实现基于SpringbootVue的物品租赁管理系统&#xff0c;构建集物品管理、租赁交易、押金管控、数据统计于一体的数字化租赁运营平台。系统以MySQL为数据存储核…