嵌入式Linux应用开发-面向对象-分层-分离及总线驱动模型

news2025/4/9 10:02:53

嵌入式Linux应用开发-面向对象-分层-分离及总线驱动模型

  • 第八章 驱动设计的思想:面向对象/分层/分离
    • 8.1 面向对象
    • 8.2 分层
    • 8.3 分离
    • 8.4 写示例代码
    • 8.5 课后作业
  • 第九章 驱动进化之路:总线设备驱动模型
    • 9.1 驱动编写的 3种方法
      • 9.1.1 传统写法
      • 9.1.2 总线设备驱动模型
      • 9.1.3 设备树
    • 9.2 在 Linux中实现“分离”:Bus/Dev/Drv模型
    • 9.3 匹配规则
      • 9.3.1 最先比较:platform_device. driver_override和 platform_driver.driver.name
      • 9.3.2 然后比较:platform_device. name和 platform_driver.id_table[i].name
      • 9.3.3 最后比较:platform_device.name和 platform_driver.driver.name
      • 9.3.4 函数调用关系
    • 9.4 常用函数
      • 9.4.1 注册/反注册
      • 9.4.2 获得资源
    • 9.5 怎么写程序
      • 9.5.1 分配/设置/注册 platform_device结构体
      • 9.5.2 分配/设置/注册 platform_driver结构体
    • 9.6 课后作业

第八章 驱动设计的思想:面向对象/分层/分离

在这里插入图片描述

8.1 面向对象

字符设备驱动程序抽象出一个 file_operations结构体; 我们写的程序针对硬件部分抽象出 led_operations结构体。

8.2 分层

上下分层,比如我们前面写的 LED驱动程序就分为 2层:
① 上层实现硬件无关的操作,比如注册字符设备驱动:leddrv.c
② 下层实现硬件相关的操作,比如 board_A.c实现单板 A的 LED操作
在这里插入图片描述

8.3 分离

还能不能改进?分离。
在 board_A.c中,实现了一个 led_operations,为 LED引脚实现了初始化函数、控制函数:

static struct led_operations board_demo_led_opr = {  
.num  = 1,  
.init = board_demo_led_init,  
.ctl  = board_demo_led_ctl, 
}; 

如果硬件上更换一个引脚来控制 LED怎么办?你要去修改上面结构体中的 init、ctl函数。
实际情况是,每一款芯片它的 GPIO操作都是类似的。比如:GPIO1_3、GPIO5_4这 2个引脚接到 LED:
① GPIO1_3属于第 1组,即 GPIO1。
有方向寄存器 DIR、数据寄存器 DR等,基础地址是 addr_base_addr_gpio1。
设置为 output引脚:修改 GPIO1的 DIR寄存器的 bit3。
设置输出电平:修改 GPIO1的 DR寄存器的 bit3。

② GPIO5_4属于第 5组,即 GPIO5。
有方向寄存器 DIR、数据寄存器 DR等,基础地址是 addr_base_addr_gpio5。
设置为 output引脚:修改 GPIO5的 DIR寄存器的 bit4。
设置输出电平:修改 GPIO5的 DR寄存器的 bit4。

既然引脚操作那么有规律,并且这是跟主芯片相关的,那可以针对该芯片写出比较通用的硬件操作代码。
比如 board_A.c使用芯片 chipY,那就可以写出:chipY_gpio.c,它实现芯片 Y的 GPIO操作,适用于芯片 Y的所有 GPIO引脚。
使用时,我们只需要在 board_A_led.c中指定使用哪一个引脚即可。
程序结构如下:
在这里插入图片描述
以面向对象的思想,在 board_A_led.c中实现 led_resouce结构体,它定义“资源”──要用哪一个引脚。 在 chipY_gpio.c中仍是实现 led_operations结构体,它要写得更完善,支持所有 GPIO。

8.4 写示例代码

使用 GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\02_led_drv\03_led_drv_template_seperate 

程序仍分为上下结构:上层 leddrv.c向内核注册 file_operations结构体;下层 chip_demo_gpio.c提供 led_operations结构体来操作硬件。

下层的代码分为 2个:chip_demo_gpio.c实现通用的 GPIO操作,board_A_led.c指定使用哪个 GPIO,即“资源”。

led_resource.h中定义了 led_resource结构体,用来描述 GPIO:

04 /* GPIO3_0 */ 
05 /* bit[31:16] = group */ 
06 /* bit[15:0]  = which pin */ 
07 #define GROUP(x) (x>>16) 
08 #define PIN(x)   (x&0xFFFF) 
09 #define GROUP_PIN(g,p) ((g<<16) | (p)) 
10 
11 struct led_resource { 
12      int pin; 
13 }; 
14 
15 struct led_resource *get_led_resouce(void); 
16 

board_A_led.c指定使用哪个 GPIO,它实现一个 led_resource结构体,并提供访问函数:

02 #include "led_resource.h" 
03 
04 static struct led_resource board_A_led = { 
05      .pin = GROUP_PIN(3,1), 
06 }; 
07 
08 struct led_resource *get_led_resouce(void) 
09 { 
10      return &board_A_led; 
11 } 
12 

chip_demo_gpio.c中,首先获得 board_A_led.c实现的 led_resource结构体,然后再进行其他操作,请看下面第 26行:

20 static struct led_resource *led_rsc; 
21 static int board_demo_led_init (int which) /* 初始化 LED, which-哪个 LED */ 
22 { 
23      //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which); 
24      if (!led_rsc) 
25      { 
26              led_rsc = get_led_resouce(); 
27      } 
28 ...
29}

8.5 课后作业

使用“分离”的思想,去改造前面写的 LED驱动程序:实现 led_resouce,在里面可以指定要使用哪一个 LED;改造 led_operations,让它能支持更多 GPIO。
注意:作为练习,led_operations结构体不需要写得很完善,不需要支持所有 GPIO,你可以只支持若干个 GPIO即可。

第九章 驱动进化之路:总线设备驱动模型

在这里插入图片描述

示例:
在这里插入图片描述

9.1 驱动编写的 3种方法

以 LED驱动为例:

9.1.1 传统写法

在这里插入图片描述
使用哪个引脚,怎么操作引脚,都写死在代码中。
最简单,不考虑扩展性,可以快速实现功能。 修改引脚时,需要重新编译。

9.1.2 总线设备驱动模型

在这里插入图片描述
引入 platform_device/platform_driver,将“资源”与“驱动”分离开来。
代码稍微复杂,但是易于扩展。
冗余代码太多,修改引脚时设备端的代码需要重新编译。 更换引脚时,上图中的 led_drv.c基本不用改,但是需要修改 led_dev.c

9.1.3 设备树

在这里插入图片描述
通过配置文件──设备树来定义“资源”。
代码稍微复杂,但是易于扩展。
无冗余代码,修改引脚时只需要修改 dts文件并编译得到 dtb文件,把它传给内核。
无需重新编译内核/驱动。

9.2 在 Linux中实现“分离”:Bus/Dev/Drv模型

在这里插入图片描述

9.3 匹配规则

9.3.1 最先比较:platform_device. driver_override和 platform_driver.driver.name

可以设置 platform_device的 driver_override,强制选择某个 platform_driver。

9.3.2 然后比较:platform_device. name和 platform_driver.id_table[i].name

Platform_driver.id_table是“platform_device_id”指针,表示该 drv支持若干个 device,它里面列出了各个 device的{.name, .driver_data},其中的“name”表示该 drv支持的设备的名字,driver_data是些提供给该 device的私有数据。

9.3.3 最后比较:platform_device.name和 platform_driver.driver.name

platform_driver.id_table可能为空, 这时可以根据 platform_driver.driver.name来寻找同名的 platform_device。

9.3.4 函数调用关系

platform_device_register 
platform_device_add     
	device_add         
		bus_add_device // 放入链表         
		bus_probe_device  // probe枚举设备,即找到匹配的(dev, drv)            
			device_initial_probe                 
				__device_attach                     
					bus_for_each_drv(...,__device_attach_driver,...)                         
						__device_attach_driver                             
							driver_match_device(drv, dev) // 是否匹配                             
							driver_probe_device         // 调用 drv的 probe 
platform_driver_register 
__platform_driver_register     
	driver_register         
		bus_add_driver // 放入链表             
			driver_attach(drv)                     
				bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);                         
					__driver_attach                             
						driver_match_device(drv, dev) // 是否匹配                             
						driver_probe_device         // 调用 drv的 probe 

9.4 常用函数

这些函数可查看内核源码:drivers/base/platform.c,根据函数名即可知道其含义。 下面摘取常用的几个函数。

9.4.1 注册/反注册

platform_device_register/ platform_device_unregister 
platform_driver_register/ platform_driver_unregister 
platform_add_devices // 注册多个 device 

9.4.2 获得资源

返回该 dev中某类型(type)资源中的第几个(num):

struct resource *platform_get_resource(struct platform_device *dev,unsigned int type,unsigned int num)

返回该 dev所用的第几个(num)中断:

int platform_get_irq(struct platform_device *dev,unsigned int num)

通过名字(name)返回该 dev的某类型(type)资源:

struct resource *platform_get_resource byname(struct platform_device *dev,unsigned int type,const char *name)

通过名字(name)返回该 dev的中断号:

int platform_get_irq_byname(struct platform_device *dev,unsigned char *name)

9.5 怎么写程序

9.5.1 分配/设置/注册 platform_device结构体

在里面定义所用资源,指定设备名字。

9.5.2 分配/设置/注册 platform_driver结构体

在其中的 probe函数里,分配/设置/注册 file_operations结构体, 并从 platform_device中确实所用硬件资源。 指定 platform_driver的名字。

9.6 课后作业

在内核源码中搜索 platform_device_register可以得到很多驱动,选择一个作为例子:
① 确定它的名字
② 根据它的名字找到对应的 platform_driver
③ 进入 platform_device_register/platform_driver_register内部,分析 dev和 drv的匹配过程

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

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

相关文章

进阶指针(三)--- qsort函数(快速排序)的使用和(用冒泡排序)模拟实现

✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;进阶C语言 &#x1f388;推荐相关博文&#xff1a;进阶C语言&#xff08;一&#xff09;、进阶C语言&#xff08;二&#xff09; 进阶指针&#xff08;三&#xff09; 8.回调函数&#xff08;下&#x…

​中秋团圆季《乡村振兴战略下传统村落文化旅游设计》许少辉八月新著

​中秋团圆季《乡村振兴战略下传统村落文化旅游设计》许少辉八月新著 ​中秋团圆季《乡村振兴战略下传统村落文化旅游设计》许少辉八月新著

手动实现BERT

本文重点介绍了如何从零训练一个BERT模型的过程&#xff0c;包括整体上BERT模型架构、数据集如何做预处理、MASK替换策略、训练模型和保存、加载模型和测试等。 一.BERT架构   BERT设计初衷是作为一个通用的backbone&#xff0c;然后在下游接入各种任务&#xff0c;包括翻译…

Azure Arc 概要:功能、管理和应用场景详解,AZ900 考点示例

文章目录 本文大纲一、什么是 Azure Arc二、使用 Azure Arc 可以做什么操作三、使用 Azure Arc 可以管理什么资源3.1 如何使用Azure Arc与服务器? 四、Azure Arc 支持的主要场景五、在 AZ900 中的考点示例5.1 示例题 15.2 示例题 2 本文大纲 本文思维导图概述的主要内容&…

【C/C++】C/C++面试八股

C/C面试八股 C和C语言的区别简单介绍一下三大特性多态的实现原理虚函数的构成原理虚函数的调用原理虚表指针在什么地方进行初始化的&#xff1f;构造函数为什么不能是虚函数虚函数和纯虚函数的区别抽象类类对象的对象模型内存对齐是什么&#xff1f;为什么要内存对齐static关键…

嵌入式Linux应用开发-第十章LED模板总线设备驱动模型

嵌入式Linux应用开发-第十章LED模板总线设备驱动模型 第十章 LED模板驱动程序的改造&#xff1a;总线设备驱动模型10.1 原来的框架10.2 要实现的框架10.3 写代码10.3.1 注意事项10.3.2 实现 platform_device结构体10.3.3 实现 platform_driver结构体 10.4 课后作业 第十章 LED模…

CCF CSP认证 历年题目自练Day13

CCF CSP认证 历年题目自练Day13 题目一 试题编号&#xff1a; 201612-1 试题名称&#xff1a; 中间数 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 问题描述   在一个整数序列a1, a2, …, an中&#xff0c;如果存在某个数&#xff0c;大…

web:[极客大挑战 2019]BabySQL

题目 点进页面显示如下 查看源代码 先尝试一下万能密码 没用&#xff0c;or被过滤了 试着双写看看 回显一串&#xff0c;也不是flag 先查询列数尝试一下&#xff0c;把union select过滤了&#xff0c;使用双写 构造payload /check.php?usernameadmin&password1 %27 ununi…

基于Java的医院住院管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统功能具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域…

ShowDoc部署与应用:文档管理的最佳实践

在项目开发和协作中&#xff0c;文档管理扮演着至关重要的角色。ShowDoc作为一款卓越的开源文档管理工具&#xff0c;不仅提供强大的文档管理功能&#xff0c;还具备简单易用的协作和部署特性。我们的项目团队最初选择了ShowDoc作为文档管理工具&#xff0c;用以促进前后端协作…

【超分:光谱响应函数】

Spectral Response Function-Guided Deep Optimization-Driven Network for Spectral Super-Resolution &#xff08;光谱响应函数引导的深度优化驱动网络光谱超分辨&#xff09; 高光谱图像&#xff08;HSI&#xff09;是许多研究工作的关键。光谱超分辨率&#xff08;SSR&a…

mysql面试题5:索引、主键、唯一索引、联合索引的区别?什么情况下设置了索引但无法使用?并且举例说明

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:说一说索引、主键、唯一索引、联合索引的区别? 索引、主键、唯一索引和联合索引是数据库中常用的索引类型,它们有以下区别: 索引:索引是一种数…

时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解

时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现SSA-VMD麻雀算法优化变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 SSA-VMD麻雀搜索算法SSA优化VMD变分模态分解 可直接运行 分解效果好…

JavaScript Web APIs第二天笔记

Web APIs - 第2天 学会通过为DOM注册事件来实现可交互的网页特效。 能够判断函数运行的环境并确字 this 所指代的对象理解事件的作用&#xff0c;知道应用事件的 3 个步骤 学习会为 DOM 注册事件&#xff0c;实现简单可交互的网页特交。 事件 事件是编程语言中的术语&#xff…

笔试强训Day7

T1&#xff1a;合法括号序列判断 链接&#xff1a;合法括号序列判断__牛客网 给定一个字符串A和其长度n&#xff0c;请返回一个bool值代表它是否为一个合法的括号串&#xff08;只能由括号组成&#xff09;。 经典括号匹配问题&#xff0c;考察栈的使用 #include<iostre…

freertos中函数调用和启动第一个任务(栈相关!!!!!!)

本内容仅就一些较难理解的点讲解&#xff0c;请结合其它文章实用 在函数调用时&#xff0c;m3的处理器使用r0-r3共四个寄存器传参&#xff0c;其余的使用栈传参。 但是&#xff0c;如果传入的参数是全局变量&#xff0c;则不需传参&#xff0c;因为全局变量在函数内部是可见的…

YOLO训练心得

文件框架 通过简单的模型训练&#xff0c;对于YOLO的理解更加透彻了。 detect.py文件 如上图所示&#xff0c;weights表示权重。source表示识别图像的位置。 train.py文件 如上图所示&#xff0c;weights是权重&#xff0c;我们通常使用YOLO提供的训练权重进行训练。data是训…

ADworld reverse wp easyre-153

逆向分析 做逆向题先查壳, 就像做pwn先checksec一样 用PEid查不出来, 用Exeinfo PE可以查出ELF文件的壳 用工具直接脱upx壳, kali自带的工具或者手动安装一个windows的upx工具 脱壳之后拖入IDA32 int __cdecl main(int argc, const char **argv, const char **envp) {int …

SLAM从入门到精通(amcl定位使用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 学习slam&#xff0c;一般就是所谓的边定位、边制图的知识。然而在实际生产过程中&#xff0c;比如扫地机器人、agv、巡检机器人、农业机器人&…

Sentinel学习——sentinel的使用,引入依赖和配置 对消费者进行流控 对生产者进行熔断降级

前言 Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 本篇博客介绍sentinel的使用&#x…