《linux系统内核设计与实现》-实现最简单的字符设备驱动
开发linux内核驱动需要以下4个步骤:
1 编写hello驱动代码
驱动代码如下 helloDev.c,这是一个最小、最简单的驱动,去掉了其他的不相干代码,尽量让大家能了解驱动本身。
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/slab.h>#define BUFFER_MAX (10) // buff大小
#define OK (0)
#define ERROR (-1)struct cdev *gDev; // 字符设备结构体指针
struct file_operations *gFile; // 文件操作结构体指针
dev_t devNum; // 设备号
unsigned int subDevNum = 1; // 注册设备的数量int reg_major = 232; // 主设备号
int reg_minor = 0; // 次设备号
char *buffer; // 缓冲区/*** printk 是内核中用于输出调试信息、错误信息和其他日志信息的函数。* 它将消息输出到内核日志缓冲区,这些日志可以通过 dmesg 命令查看* KERN_INFO 是一个宏:信息性消息
*/// hello_open函数:打开文件
int hello_open(struct inode *p, struct file *f)
{printk(KERN_INFO "hello_open\r\n");return 0;
}// hello_write函数
ssize_t hello_write(struct file *f, const char __user *u, size_t s, loff_t *l)
{printk(KERN_INFO "hello_write\r\n");return 0;
}// hello_read函数
ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l)
{printk(KERN_INFO "hello_read\r\n");return 0;
}int hello_init(void)
{devNum = MKDEV(reg_major, reg_minor); // 根据主次设备号,生成devNum,唯一标识设备// 把设备号注册到内核中。从devNum开始注册subDevNum个设备。if (OK == register_chrdev_region(devNum, subDevNum, "helloworld")) {printk(KERN_INFO "register_chrdev_region ok \n");} else {printk(KERN_INFO "register_chrdev_region error n");return ERROR;}printk(KERN_INFO " hello driver init \n");// 内核模块成功分配并初始化了一个字符设备结构gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);// 文件操作gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL);// 赋值。回调函数gFile->open = hello_open;gFile->read = hello_read;gFile->write = hello_write;gFile->owner = THIS_MODULE;// 建立联系:通过这两行代码,驱动程序完成了字符设备的初始化和注册,使得字符设备可以被用户进程打开、读取和写入。cdev_init(gDev, gFile); // 初始化字符设备结构体gDev,并将其与文件操作结构体gFile关联起来。cdev_add(gDev, devNum, 1); // 将初始化好的字符设备gDev 添加到内核字符设备层,使其成为一个有效的字符设备,可以被用户空间访问和操作return 0;
}// 驱动退出函数
void __exit hello_exit(void)
{printk(KERN_INFO " hello driver exit \n");cdev_del(gDev); // 删除字符设备kfree(gFile); // 释放内存kfree(gDev); // 释放内存unregister_chrdev_region(devNum, subDevNum); // 注销设备号return;
}module_init(hello_init); // 声明驱动的入口函数。执行insmod的时候调用
module_exit(hello_exit); // 声明驱动的退出函数。执行rmmod的时候调用
MODULE_LICENSE("GPL"); // 指定模块的许可证
有了驱动文件之后,还需要一个Makefile才能把驱动编译出来
2 编写makefile
ifneq ($(KERNELRELEASE),)
obj-m := helloDev.o
else
PWD := $(shell pwd) # 获取当前目录路径,并赋值给变量 PWD
# KDIR:= /lib/modules/4.4.0-31-generic/build
# KDIR:= /home/winter/linux-4.9.229
KDIR := /lib/modules/`uname -r`/build # 指定内核构建目录
all:make -C $(KDIR) M=$(PWD)
clean:rm -rf *.o *.ko *.mod.c *.symvers *.c~ *~
endif
# $(KERNELRELEASE) 是内核构建系统设置的变量,当通过内核构建系统调用此 Makefile 时,这个变量会被定义。
# -C $(KDIR):切换到内核构建目录
# M=$(PWD):指定模块源码目录为当前目录
# make -C $(KDIR) M=$(PWD):调用内核构建系统
# 这段 Makefile 通过条件分支来区分内核构建环境和用户构建环境,在用户环境中调用内核构建系统进行模块编译,并提供了清理编译生成文件的功能。
linux应用层程序在编译的时候,需要链接c运行时库和glibc库。那驱动需不需要呢?
3 编译和加载hello驱动
驱动也需要,但是驱动不能链接和使用应用层的任何lib库,驱动需要引用内核的头文件和函数。所以,编译的时候需要指定内核源码的地址。为了开发方便,也可以安装内核开发包,之后引用这个内核开发包的目录也可以。本例为:/lib/modules/4.4.0-31-generic/build
make

编译出来的驱动文件,名称为:helloDev.ko

接下来把这个驱动加载到内核
# 清零内核日志
dmesg -c
# 执行
insmod helloDev.ko
# 再看内核日志
dmesg

# 查看驱动
lsmod

# 卸载驱动
rmmod helloDev.ko
# 再查看驱动,无

4 编写应用程序测试hello驱动test.c
/*************************************************************************> File Name: test.c> Author: Winter> Created Time: 2024年05月17日 星期五 21时03分06秒************************************************************************/#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/select.h>#define DATA_NUM (64)
int main(int argc, char *argv[])
{int fd, i;int r_len, w_len;fd_set fdset;char buf[DATA_NUM]="hello world";memset(buf,0,DATA_NUM);fd = open("/dev/hello", O_RDWR);printf("%d\r\n",fd);if(-1 == fd) {perror("open file error\r\n");return -1;} else {printf("open successe\r\n");}w_len = write(fd,buf, DATA_NUM);r_len = read(fd, buf, DATA_NUM);printf("%d %d\r\n", w_len, r_len);printf("%s\r\n",buf);return 0;
}
编译执行。因为没有/dev/hello这个设备文件,所以打开失败

需要创建设备文件
mknod
man mknod
# 名字 类型 【主设备号 次设备号】
mknod [OPTION]... NAME TYPE [MAJOR MINOR]
mknod /dev/hello c 232 0# 查看
ls -l /dev/hello# 再执行测试程序
./test

有调用日志

这个返回值是驱动部分对应的返回值
5 一些命令
dmesg -c # 清零内核日志
insmod helloDev.ko # 插入(加载)Linux内核模块的命令
dmesg # dmesg 命令用于查看和管理 Linux 内核的环形缓冲区中的消息
lsmod # 查看驱动
rmmod helloDev.ko # 卸载驱动# 创建设备文件:名字 类型 【主设备号 次设备号】
mknod [OPTION]... NAME TYPE [MAJOR MINOR]
mknod /dev/hello c 232 0
相关文章:
《linux系统内核设计与实现》-实现最简单的字符设备驱动
开发linux内核驱动需要以下4个步骤: 1 编写hello驱动代码 驱动代码如下 helloDev.c,这是一个最小、最简单的驱动,去掉了其他的不相干代码,尽量让大家能了解驱动本身。 #include <linux/module.h> #include <linux/mod…...
【MotionCap】pycharm 远程在wsl2 ubuntu20.04中root的miniconda3环境
pycharm wsl2 链接到pycharmsbin 都能看到内容,/root 下内容赋予了zhangbin 所有,pycharm还是看不到/root 下内容。sudo 安装了miniconda3 引发了这些问题 由于是在 root 用户安装的miniconda3 所以安装路径在/root/miniconda3 里 这导致了环境也是root用户的,会触发告警 WA…...
[BJDCTF 2nd]简单注入
sqlsqlsqlsqlsql又来喽 过滤了单双引号,等于符号,还有select等,但是这里没有二次注入 。扫描发现hint.txt 看出题人的意思是,得到密码即可获得flag。 select * from users where username$_POST["username"] and passw…...
java项目的一些功能(完善登录功能、注册接口参数校验、完善分页查询、完善日期格式、更新文章分类和添加文章分类的分组校验、自定义校验、文件上传 )
目录 完善登录功能 注册接口参数校验 完善分页查询 完善日期格式 更新文章分类和添加文章分类的分组校验 编辑 自定义校验 文件上传 完善登录功能 对前端传过来的明文密码进行md5加密处理 password DigestUtils.md5DigestAsHex(password.getBytes()); 这样既可 注…...
Mac安装AndroidStudio连接手机 客户端测试
参考文档:https://www.cnblogs.com/andy0816/p/17097760.html 环境依赖 需要java 1.8 java安装 略 下载Android Studio 地址 下载 Android Studio 和应用工具 - Android 开发者 | Android Developers 本机对应的包进行下载 安装过程 https://www.cnblogs.c…...
Git 完整的提交规范教程
约定式提交规范 本文中的关键词 “必须(MUST)”、“禁止(MUST NOT)”、“必要(REQUIRED)”、“应当(SHALL)”、“不应当(SHALL NOT)”、“应该(S…...
【TB作品】51单片机 Proteus仿真 00001仿真实物PID电机调速系统
实验报告:Proteus 仿真 PID 电机调速系统 一、实验背景 PID(比例-积分-微分)控制器广泛应用于工业控制系统中,用于调节各种物理变量。本实验的目的是通过 Proteus 仿真软件设计并实现一个 PID 电机调速系统,以控制直…...
【LInux】从动态库的加载深入理解页表机制
💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤 📃个人主页 :阿然成长日记 …...
IDEA与通义灵码的智能编程之旅
1 概述 本文主要介绍在IDEA中如何安装和使用通义灵码来助力软件编程,从而提高编程效率,创造更大的个人同企业价值。 2 安装通义灵码 2.1 打开IDEA插件市场 点击IDEA的设置按钮,下拉选择Plugins,如下: 2.2 搜索通义灵码 在搜索框中输入“通义灵码”,如下: 2.3 安…...
多表查询sql
概述:项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,分为三种: 一对多多对多一对一 一、多表关系 一对多 案例:部门与…...
移动端UI风格营造舒适氛围
移动端UI风格营造舒适氛围...
摸鱼大数据——Spark SQL——DataFrame详解一
1.DataFrame基本介绍 DataFrame表示的是一个二维的表。二维表,必然存在行、列等表结构描述信息表结构描述信息(元数据Schema): StructType对象字段: StructField对象,可以描述字段名称、字段数据类型、是否可以为空行: Row对象列: Column对象ÿ…...
【Java探索之旅】初识多态_概念_实现条件
文章目录 📑前言一、多态1.1 概念1.2 多态的实现条件 🌤️全篇总结 📑前言 多态作为面向对象编程中的重要概念,为我们提供了一种灵活而强大的编程方式。通过多态,同一种操作可以应用于不同的对象,并根据对象…...
[Day 26] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
數據科學與AI的整合應用 數據科學(Data Science)和人工智能(AI)在現代技術世界中扮演著至關重要的角色。兩者的整合應用能夠為企業和研究人員提供強大的工具,以更好地理解、預測和解決各種複雜的問題。本文將深入探討…...
算法 —— 滑动窗口
目录 长度最小的子数组 无重复字符的最长子串 最大连续1的个数 将x减到0的最小操作数 找到字符串中所有字母异位词 最小覆盖子串 长度最小的子数组 sum比target小就进窗口,sum比target大就出窗口,由于数组是正数,所以相加会使sum变大&…...
【设计模式】工厂模式(定义 | 特点 | Demo入门讲解)
文章目录 定义简单工厂模式案例 | 代码Phone顶层接口设计Meizu品牌类Xiaomi品牌类PhoneFactory工厂类Customer 消费者类 工厂方法模式案例 | 代码PhoneFactory工厂类 Java高级特性---工厂模式与反射的高阶玩法方案:反射工厂模式 总结 其实工厂模式就是用一个代理类帮…...
Linux之计划和日志
计划任务 计划任务概念解析 在Linux操作系统中,除了用户即时执行的命令操作以外,还可以配置在指定的时间、指定的日期执行预先计划好的系统管理任务(如定期备份、定期采集监测数据)。通过安装at和crontabs这两个系统服务实现一次性、周期性计划任务的功能,并分别通过at、…...
C++ 多态篇
文章目录 1. 多态的概念和实现1.1 概念1.2 实现1.2.1 协变1.2.2 析构函数1.2.3 子类虚函数不加virtual 2. C11 final和override3.1 final3.2 override 3. 函数重载、重写与隐藏4. 多态的原理5. 抽象类6.单继承和多继承的虚表6.1 单继承6.2 多继承 7. 菱形继承的虚表(了解)7.1 菱…...
【LVGL-SquareLine Studio】
LVGL-SquareLine Studio ■ SquareLine Studio-官网下载地址■ SquareLine Studio-参考博客■ SquareLine Studio-安装■ SquareLine Studio-汉化■ SquareLine Studio-■ SquareLine Studio-■ SquareLine Studio-■ SquareLine Studio-■ SquareLine Studio- ■ SquareLine S…...
mysqli 与mysql 区别和联系, 举例说明
mysqli是一种PHP的扩展,用于与MySQL数据库进行交互。它提供了一套面向对象的接口,可以更方便地操作数据库。MySQL是一种关系型数据库管理系统,用于存储和管理数据。 区别: mysqli是MySQL的扩展,而不是单独的数据库管…...
OpenClaw日志分析技能:千问3.5-27B自动排查错误信息
OpenClaw日志分析技能:千问3.5-27B自动排查错误信息 1. 为什么需要自动化日志分析 作为一名长期与代码打交道的开发者,我每天至少有30%的时间花在查看日志上。从服务器报错到应用崩溃,从性能瓶颈到数据异常,日志就像系统的"…...
新手福音:零基础在快马平台创建你的第一个口播智能体
今天想和大家分享一个特别适合编程新手的实战项目——在InsCode(快马)平台上创建一个旗博士口播智能体。这个项目不需要任何后端知识,用最基础的HTML和JavaScript就能实现,而且能让你直观感受到AI应用的开发流程。 项目整体思路 这个口播智能体的核心功能…...
Instructions完全指南:快速创建iOS应用引导教程的终极解决方案
Instructions完全指南:快速创建iOS应用引导教程的终极解决方案 【免费下载链接】Instructions Create walkthroughs and guided tours (coach marks) in a simple way, with Swift. 项目地址: https://gitcode.com/gh_mirrors/in/Instructions Instructions是…...
从湖科大计网笔记出发,聊聊我当年学网络时踩过的那些坑(附避坑指南)
从湖科大计网笔记出发:一位工程师的避坑实战指南 1. 那些年我掉进的TCP/IP陷阱 第一次接触TCP三次握手时,我天真地以为这就像打电话的"喂-喂-好"那么简单。直到期末考试时被问到"为什么不能两次握手?",我才意…...
移动设备上实现实时人物移除的终极优化指南
移动设备上实现实时人物移除的终极优化指南 【免费下载链接】Real-Time-Person-Removal Removing people from complex backgrounds in real time using TensorFlow.js in the web browser 项目地址: https://gitcode.com/gh_mirrors/re/Real-Time-Person-Removal Real-…...
RMBG-2.0(BiRefNet)开源抠图工具落地实操:Streamlit双列界面零门槛上手
RMBG-2.0(BiRefNet)开源抠图工具落地实操:Streamlit双列界面零门槛上手 想给产品换个背景,却不会用复杂的PS?想快速处理一批图片素材,又担心在线工具泄露隐私?今天,我们就来聊聊一个…...
python pygame实现贪食蛇
文章目录步骤2、创建snake.py,然后运行即可操作方式解读很简单的一个例子,开启小游戏制作大门。步骤 1、安装依赖 pip install pygame2、创建snake.py,然后运行即可 代码: import pygame import time import random# --- 1. 初…...
XUnity.AutoTranslator实用指南:高效实现Unity游戏实时翻译
XUnity.AutoTranslator实用指南:高效实现Unity游戏实时翻译 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 在全球化游戏市场中,语言障碍常常成为玩家体验优质游戏的最大阻碍。XUn…...
Infect工具完整教程:快速掌握Android设备病毒传播技术
Infect工具完整教程:快速掌握Android设备病毒传播技术 【免费下载链接】infect Infect Any Android Device With Virus From Link In Termux 项目地址: https://gitcode.com/gh_mirrors/in/infect Infect是一款基于Bash的Android病毒传播工具,专为…...
忍者像素绘卷基础教程:3步完成‘火之意志’提示词→像素绘卷生成
忍者像素绘卷基础教程:3步完成火之意志提示词→像素绘卷生成 1. 认识忍者像素绘卷 忍者像素绘卷是一款基于Z-Image-Turbo深度优化的图像生成工具,它将传统忍者文化与16-Bit复古游戏美学完美结合。不同于常见的暗色调像素艺术,这款工具采用了…...
