【Linux】基于框架编写驱动代码、驱动代码编译和测试

基于框架编写驱动代码
驱动代码编译和测试

  • ARM架构上进行Linux内核模块的交叉编译

总结

  • 内核驱动框架基本
  • 驱动测试步骤

基于框架编写驱动代码

编写一个Linux设备驱动框架需要一些基本的步骤,以及一些特定于硬件的信息。由于你提到基于PIN4,我将提供一个简单的框架,你需要根据实际硬件规格进行适当的修改。以下是一个通用的Linux设备驱动框架示例:

#include <linux/init.h>				// 包含了模块初始化和清理函数的宏定义。
#include <linux/module.h>			// 提供了Linux内核模块的基本函数和宏。
#include <linux/fs.h>				// 包含了文件系统相关的数据结构和函数。
#include <linux/cdev.h>				// 定义了字符设备相关的结构和函数。
#include <linux/device.h>			// 包含了设备类和设备的定义。
#include <linux/uaccess.h>			// 提供了用户空间和内核空间数据传输的函数。// Define driver name and device class定义驱动名称和设备类别
#define DRIVER_NAME "pin4_driver"	// 定义驱动程序名称的宏
#define CLASS_NAME "pin4_class"		// 定义设备类别名称的宏// Module information模块信息
MODULE_LICENSE("GPL");				// 指定模块的许可证(在此为GPL)
MODULE_AUTHOR("Your Name");			// 指定模块的作者
MODULE_DESCRIPTION("Linux Device Driver for PIN4");	// 指定模块的描述
MODULE_VERSION("0.1");				// 指定模块的版本号// Driver related variables驱动相关变量
static int majorNumber;						// 变量,用于存储分配给驱动程序的主设备号
static struct class* pin4Class = NULL;		// 指向表示设备类别的结构体的指针
static struct device* pin4Device = NULL;	// 指向表示设备的结构体的指针// Function prototypes函数原型 Driver function prototype declaration驱动函数原型声明
static int pin4Driver_open(struct inode*, struct file*);						// 驱动打开函数原型声明
static int pin4Driver_release(struct inode*, struct file*);						// 驱动关闭函数原型声明
static ssize_t pin4Driver_read(struct file*, char*, size_t, loff_t*);			// 驱动读取函数原型声明
static ssize_t pin4Driver_write(struct file*, const char*, size_t, loff_t*);	// 驱动写入函数原型声明// File operations structure文件操作结构 Driver operation structure驱动操作结构体
static struct file_operations fops = {.open = pin4Driver_open,			// 驱动打开函数.release = pin4Driver_release,		// 驱动关闭函数.read = pin4Driver_read,			// 驱动读取函数.write = pin4Driver_write,			// 驱动写入函数
};// Driver initialization function驱动初始化函数
static int __init pin4Driver_init(void) {// Dynamically allocate a major number动态分配主设备号majorNumber = register_chrdev(0, DRIVER_NAME, &fops);if (majorNumber < 0) {printk(KERN_ALERT "Failed to register a major number\n");return majorNumber;}// Register the device class注册设备类别pin4Class = class_create(THIS_MODULE, CLASS_NAME);if (IS_ERR(pin4Class)) {unregister_chrdev(majorNumber, DRIVER_NAME);printk(KERN_ALERT "Failed to register device class\n");return PTR_ERR(pin4Class);}// Register the device driver注册设备驱动程序pin4Device = device_create(pin4Class, NULL, MKDEV(majorNumber, 0), NULL, DRIVER_NAME);if (IS_ERR(pin4Device)) {class_destroy(pin4Class);unregister_chrdev(majorNumber, DRIVER_NAME);printk(KERN_ALERT "Failed to create the device\n");return PTR_ERR(pin4Device);}printk(KERN_INFO "PIN4 driver initialized\n");return 0;
}// Driver exit function驱动程序退出功能
static void __exit pin4Driver_exit(void) {device_destroy(pin4Class, MKDEV(majorNumber, 0));class_unregister(pin4Class);class_destroy(pin4Class);unregister_chrdev(majorNumber, DRIVER_NAME);printk(KERN_INFO "PIN4 driver exited\n");
}// Open driver打开驱动程序
static int pin4Driver_open(struct inode* inodep, struct file* filep) {printk(KERN_INFO "PIN4 driver opened\n");return 0;
}// Release driver释放驱动程序
static int pin4Driver_release(struct inode* inodep, struct file* filep) {printk(KERN_INFO "PIN4 driver closed\n");return 0;
}// Read from driver从驱动程序读取数据
static ssize_t pin4Driver_read(struct file* filep, char* buffer, size_t len, loff_t* offset) {printk(KERN_INFO "Reading from PIN4 driver\n");// Implement your read logic here在这里实现你的读取逻辑return 0;
}// Write to driver向驱动程序写入数据
static ssize_t pin4Driver_write(struct file* filep, const char* buffer, size_t len, loff_t* offset) {printk(KERN_INFO "Writing to PIN4 driver\n");// Implement your write logic here在这里实现你的写入逻辑return len;
}// Register initialization and exit functions注册初始化和退出函数
module_init(pin4Driver_init);
module_exit(pin4Driver_exit);

请注意,上述代码是一个简单的框架,它包含了初始化和清理函数、打开、释放、读和写文件操作。你需要根据实际硬件和设备规格填充相应的读写逻辑。在这个框架中,设备被创建为字符设备,并可以通过 /dev/pin4_driver 访问。

驱动代码编译和测试

在Linux内核驱动开发中,编译和测试驱动代码通常包括以下步骤:

编写 Makefile

首先,创建一个名为 Makefile 的文件,其中包含编译驱动程序的规则。以下是一个简单的示例:

obj-m += pin4_driver.oall:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modulesclean:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

编译驱动

打开终端,进入包含驱动代码的目录,并运行以下命令编译驱动:

make

如果一切顺利,将生成一个名为 pin4_driver.ko 的内核模块。

加载驱动

加载生成的内核模块:

sudo insmod pin4_driver.ko

查看日志

查看内核日志以获取有关加载过程的信息:

dmesg

卸载驱动

卸载加载的内核模块:

sudo rmmod pin4_driver

查看日志

再次查看内核日志以获取有关卸载过程的信息:

dmesg

这些步骤是通用的,但请注意,确保你的系统上已安装了构建内核模块所需的开发工具和头文件。在一些系统上,你可能需要安装 build-essentiallinux-headers 或类似的软件包。

请记住,内核模块的测试通常涉及到与硬件或模拟硬件进行交互,具体取决于你的驱动目的。如果涉及到硬件,确保你的硬件连接正确。如果驱动程序用于模拟硬件,则可能需要编写用户空间测试应用程序,通过设备文件进行交互。

以上是一个简单的示例,具体取决于你的驱动程序的复杂性和特定的需求。

ARM架构上进行Linux内核模块的交叉编译

ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules

命令是用于在ARM架构上进行Linux内核模块的交叉编译。以下是该命令的分解:

  • ARCH=arm:指定目标架构为ARM。
  • CROSS_COMPILE=arm-linux-gnueabihf-:指定ARM交叉编译器的前缀。在从不同架构进行交叉编译时,这是必需的。
  • KERNEL=kernel7:指定内核版本或源代码目录。在此情况下,设置为kernel7。根据你的实际情况,可能需要根据内核源代码的位置或目标内核版本进行调整。

该命令试图使用指定的ARM交叉编译器构建内核模块。

在运行此命令之前,请确保你的系统上安装了必要的工具链(例如arm-linux-gnueabihf-gcc等)。另外,确保你具有针对目标架构的正确内核头文件。

以下是该命令的逐步解释:

  1. ARCH=arm:将架构设置为ARM。
  2. CROSS_COMPILE=arm-linux-gnueabihf-:设置ARM的交叉编译器前缀。
  3. KERNEL=kernel7:指定内核版本或源代码目录。

然后,它调用make命令以构建内核模块(modules目标)。

在运行此命令之前,请确保你位于包含内核模块源代码的正确目录,并且在运行之前安装了必要的依赖项。如果遇到任何问题,请检查错误消息,并确保你的交叉编译环境设置正确。

总结

内核驱动框架基本

驱动代码的编写

  1. 定义和注册驱动函数: 编写驱动的核心功能,包括打开、关闭、读取和写入等函数。在文件操作结构体中注册这些函数。

内核驱动编译

  1. 拷贝到 driver/char 目录: 通常,将驱动代码放置在内核源代码树的适当位置,例如 drivers/char 目录。
  2. 修改 Makefile: 更新 Makefile 以包含新的驱动文件,确保编译器知道要编译该驱动。
  3. 使用交叉编译器编译: 使用适当的交叉编译器、架构和内核版本编译驱动。
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules

驱动测试步骤

  1. 内核驱动装载: 使用 insmod 命令加载驱动模块。
    sudo insmod your_driver.ko
    
  2. 内核驱动卸载: 使用 rmmod 命令卸载已加载的驱动模块。
    sudo rmmod your_driver
    
  3. 查看内核模块: 使用 lsmod 命令查看已加载的内核模块。
    lsmod
    
  4. 验证步骤:
    • 装载驱动: 使用 insmod 加载驱动模块。
    • 生成设备节点: 驱动加载后,系统可能会自动生成设备节点(例如 /dev/PIN4)。
    • 设置访问权限: 使用 sudo chmod 666 /dev/PIN4 添加访问权限。
    • 运行测试程序: 编写一个测试程序,调用驱动程序的功能。
    • 查看内核日志: 使用 dmesg 命令查看内核的打印信息,以便验证驱动的行为。

通过这些步骤,你可以加载、卸载和测试你的内核驱动程序,确保其正确性和稳定性。

内核的printk是内核态的printf

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

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

相关文章

JavaScript基础篇

目录 1.初始JavaScript 2.Js数据类型 2.1强制转换类型 1.转换为String类型 2.转换为Number类型 3.转换为 Boolean 4.转义符 2.2运算符 2.3分支结构 1.初始JavaScript <!-- 1. 文件引入 --> <!--<script src"./js/index.js"></script>-…

JVM-7-经典垃圾收集器

Serial收集器 这个收集器是一个单线程工作的收集器&#xff0c;但它的“单线程”的意义并不仅仅是说明它只会使用一个处理器或一条收集线程去完成垃圾收集工作&#xff0c;更重要的是强调在它进行垃圾收集时&#xff0c;必须暂停其他所有工作线程&#xff0c;直到它收集结束。…

普冉(PUYA)单片机开发笔记 [完结篇]:使用体会

失败的移植&#xff1a;FreeRTOS 当使用了 PY32F003 的各种接口和功能后&#xff0c;手痒痒想把 FreeRTOS 也搬到这个 MCU 上&#xff0c;参考 STM32 和 GD32 对 FreeRTOS 的移植步骤&#xff0c;把 FreeRTOS v202212.00 版本的源码搬到了 Keil 工程中&#xff0c;编译倒是通过…

sql服务无法启动 请键入net helpmsg 3534

然后 如果是管理员权限打开命令行输入操作的话 先清空 MySQL 下的 data 文件夹&#xff0c;然后确保系统环境变量中已经配置了 mysql 的 bin 目录到Path中&#xff0c;然后执行 sc delete mysql 得到 [SC] DeleteService 成功 后&#xff08;也可能不会有返回信息&#xff…

Oracle 中ROW_NUMBER() OVER()函数用法详解

select * from ( select t.data maxdata, datatime,s.xlmc,ROW_NUMBER() OVER (PARTITION BY s.xlmc ORDER BY datatime) AS rn from HISTORY_FH_ONEDAY t, CURRENT_FH_XL s where t.code s.code ) c where c.rn1

VSCode 常用的快捷键和技巧系列(2)

一、如何让VSCode工程树显示图标 第一步&#xff1a;安装 快捷键 CtrlP &#xff0c;输入 ext install vscode-icons &#xff0c;然后点击安装插件 第二步&#xff1a;配置 安装成功后&#xff0c;点击Reload重新加载。 然后配置&#xff0c;当前图标使用VsCode-Icons Go…

2023-12-18 AndroidR RK356X 新增一个分区,这个分区可写入读取,恢复出厂后数据也不会被删除。

一、整个过程需要修改的内容,不多解释,直接看源码吧 read the fuck code。 diff --git a/bootable/recovery/install/include/install/wipe_data.h b/bootable/recovery/install/include/install/wipe_data.h old mode 100644 new mode 100755 index c177f59274..6e1987d990…

nginx学习--2023-12-18

一 proxy_pass的作用 格式很简单&#xff1a; proxy_pass URL; proxy_pass http://www.xxx.com/; proxy_pass http://192.168.200.101:8080/uri; proxy_pass unix:/tmp/www.sock; 二 proxy_pass的注意案例 案例描述&#xff1a; 假设 nginx服务器的域名为&#xff1a;www.xxx…

喜报|亚数荣获“2023物联网场景应用品牌企业”奖项

12月5日至6日&#xff0c;以“物联中国 数智雄安”为主题的“千企雄安行&#xff1a;2023物联网产业品牌大会”在雄安新区举办。 大会由雄安新区管理委员会、中关村发展集团股份有限公司、物联中国团体组织联席会主办&#xff0c;雄安新区投资促进服务中心、北京物联网智能技术…

2023.12.16力扣每日一题

2023.12.16 题目来源我的题解方法一 线段树&#xff08;借鉴官方题解评论区 知白守黑&#xff09; 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2276 我的题解 方法一 线段树&#xff08;借鉴官方题解评论区 知白守黑&#xff09; 用一棵平衡二叉搜索树维护插入的区间…

开发语言:ArkTS

简介 ArkTS是华为为鸿蒙操作系统&#xff08;HarmonyOS&#xff09;开发的一种应用开发语言。这种语言在TypeScript&#xff08;简称TS&#xff09;的基础上进行了扩展&#xff0c;以更好地适应鸿蒙系统的特点和开发需求。ArkTS不仅继承了TS的所有特性&#xff0c;而且还对TS的…

Elasticsearch之ik中文分词篇

Elasticsearch之ik中文分词篇 ik分词器插件ik分词器安装ik分词模式es ik分词测试 ik分词器插件 es在7.3版本已经支持中文分词&#xff0c;由于中文分词只能支持到单个字进行分词&#xff0c;不够灵活与适配我们平常使用习惯&#xff0c;所以有很多对应中文分词出现&#xff0c…

【LeetCode刷题】-- 229.多数元素II

229.多数元素II 方法&#xff1a;使用哈希表 class Solution {public List<Integer> majorityElement(int[] nums) {HashMap<Integer,Integer> map new HashMap<>();for(int i 0;i< nums.length;i){map.put(nums[i],map.getOrDefault(nums[i],0) 1);}…

拾[10],局部可变形匹配,函数CreateLocalDeformableModel/FindLocalDeformableModel

函数CreateLocalDeformableModel 函数功能 创建局部的可变形匹配模板 C模式 LIntExport void CreateLocalDeformableModel( const HObject& Template, const HTuple& NumLevels, const HTuple& AngleStart, const HTuple& AngleExtent, const HTuple&a…

【K8S基础】-k8s的核心概念pod

一、Pod 是什么 1.1 Pod 的定义和概念 在Kubernetes中&#xff0c;Pod是创建或部署的最小/最简单的基本单位。一个Pod代表着集群上正在运行的一个进程&#xff0c;它封装了一个或多个应用容器&#xff0c;并且提供了一些共享资源&#xff0c;如网络和存储&#xff0c;每个Pod…

c语言:判断闰年|练习题

一、题目 输入一个年份&#xff0c;判断该年份是否闰年 二、解题思路 闰年的判断方法 【】普通闰年&#xff1a; 公历年份是4的倍数&#xff0c;且不是100的倍数 【】世纪闰年&#xff1a; 公历年份是整百数的年份&#xff0c;需是400的倍数 三、代码图片【带注释】 四、源代码…

Rabbitmq 死信取消超时订单

本文使用的版本 otp_win64_25.0rabbitmq-server-3.11.26rabbitmq插件 rabbitmq_delayed_message_exchange-3.11.1 pom.xml文件 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> …

Quartz如何获取当前执行的Trigger如何注册多个Trigger到Job中,如何自定义的 Trigger 类

如何获取当前执行的Trigger import org.quartz.*; import org.quartz.impl.StdSchedulerFactory;public class TriggerNameExample {public static void main(String[] args) throws SchedulerException {// 创建调度器Scheduler scheduler StdSchedulerFactory.getDefaultSc…

数组去重及去除指定值,每一个对象添加属性值

1、数组去重ES6写法 Set() // 数组去重 let arr [1,2,4,6,3,2,6,7,7,2,9,0,1,5] arr [...new Set(arr)] console.log(arr); 2、数组去除指定值 filter() // 数组去除指定值 let arr [1,2,4,6,3,2,6,7,7,2,9,0,1,5] const num 7 arr arr.filter(item>item!num) cons…

详解YOLOv5网络结构/数据集获取/环境搭建/训练/推理/验证/导出/部署

一、本文介绍 本文给大家带来的教程是利用YOLOv5训练自己的数据集&#xff0c;以及有关YOLOv5的网络结构讲解/数据集获取/环境搭建/训练/推理/验证/导出/部署相关的教程&#xff0c;同时通过示例的方式让大家来了解具体的操作流程&#xff0c;过程中还分享给大家一些好用的资源…