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

嵌入式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.mzph.cn/news/90955.shtml

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

相关文章

BUUCTF reverse wp 21 - 30

[ACTF新生赛2020]rome 无壳, 直接拖进IDA32 y键把v2改成char[49], n键重命名为iuput int func() {int result; // eaxint v1[4]; // [esp14h] [ebp-44h]char input[49]; // [esp24h] [ebp-34h] BYREFstrcpy(&input[23], "Qsw3sj_lz4_Ujwl");printf("Please…

《Upload-Labs》01. Pass 1~13

Upload-Labs 索引前言Pass-01题解 Pass-02题解总结 Pass-03题解总结 Pass-04题解 Pass-05题解总结 Pass-06题解总结 Pass-07题解总结 Pass-08题解总结 Pass-09题解 Pass-10题解 Pass-11题解 Pass-12题解总结 Pass-13题解 靶场部署在 VMware - Win7。 靶场地址&#xff1a;https…

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

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

FreeRTOS入门教程(任务优先级,Tick)

文章目录 前言一、什么是任务优先级二、FreeRTOS如何分辨出优先级最高可运行的任务三、FreeRTOS中的时钟节拍Tick四、什么是时间片五、相同优先级任务怎么进行切换六、任务优先级实验七、修改任务优先级总结 前言 本篇文章将带大家学习FreeRTOS中的任务优先级&#xff0c;并且…

GPT-4科研实践:数据可视化、统计分析、编程、机器学习数据挖掘、数据预处理、代码优化、科研方法论

查看原文>>>GPT4科研实践技术与AI绘图 GPT对于每个科研人员已经成为不可或缺的辅助工具&#xff0c;不同的研究领域和项目具有不同的需求。例如在科研编程、绘图领域&#xff1a;1、编程建议和示例代码: 无论你使用的编程语言是Python、R、MATLAB还是其他语言&#x…

【SSL】用Certbot生成免费HTTPS证书

1. 实验背景 服务器&#xff1a;CentOS7.x 示例域名&#xff1a; www.example.com 域名对应的web站点目录&#xff1a; /usr/local/openresty/nginx/html 2. 安装docker # yum -y install yum-utils# yum-config-manager --add-repo https://download.docker.com/linux/ce…

web:[极客大挑战 2019]LoveSQL

题目 打开页面显示如下 查看源代码&#xff0c;查到一个check.php&#xff0c;还是get传参 尝试账号密码输入 题目名为sql&#xff0c;用万能密码 1or 11# 或 admin or 11 给了一段乱码&#xff0c;也不是flag 查看字段数 /check.php?usernameadmin order by 3%23&pass…

Word | 简单可操作的快捷公式编号、右对齐和引用方法

1. 问题描述 在理工科论文的写作中&#xff0c;涉及到大量的公式输入&#xff0c;我们希望能够按照章节为公式进行编号&#xff0c;并且实现公式居中&#xff0c;编号右对齐的效果。网上有各种各样的方法来实现&#xff0c;操作繁琐和简单的混在一起&#xff0c;让没有接触过公…

Redis学习笔记(常用数据类型,发布订阅,事务和锁机制,持久化,集群,雪崩,缓存击穿,分布式锁)

一、NoSQL数据库简介 解决扩展性问题&#xff0c;如果需要对功能进行改变&#xff08;比如增删功能&#xff09;&#xff0c;用框架有一定的规范要求&#xff0c;无形中解决了扩展性问题。 Redis是一种典型的NoSQL数据库。 NoSQL的基础作用&#xff1a; 1. nginx负载均衡反向…

Armv9读取cache内容:Direct access to internal memory

10 访问cache Cortex-A720核心提供一种机制,通过IMPLEMENTATION DEFINED系统寄存器可以读取L1缓存、L2缓存和Translation Lookaside Buffer(TLB)。当缓存数据与系统内存数据之间的一致性异常时,您可以使用此机制来调查任何问题。 只有在EL3中才可以访问内部内存(cache)。…

排序:最佳归并树(优化外部排序中对磁盘的读写次数)

1.归并树的性质 每个初始归并段对应一个叶子结点&#xff0c;把归并段的块数作为叶子的权值归并树的WPL树中所有叶结点的带权路径长度之和归并过程中的磁盘I/O次数归并树的WPL*2 如下图&#xff1a; 每个初始归并段看作一个叶子结点&#xff0c;归并段的长度作为结点权值&a…

C/C++进程线程超详细详解

目录 前言 一、进程基础 1.进程概念 2.进程特征 3.进程状态&#xff08;如图清晰可见&#xff09; 4&#xff0c;进程的标识 实例代码如下&#xff1a; 5.进程的种类 实例shell脚本程序如下: 二、进程API 1.创建子进程 实例代码如下&#xff1a; 2.exec函数族 函数…

Socket网络编程练习题四:客户端上传文件(多线程版)

题目 想要服务器不停止&#xff0c;能接收很多客户上传的图片&#xff1f; 解决方案 可以使用循环或者多线程 但是循环不合理&#xff0c;最优解法是&#xff08;循环多线程&#xff09;改写 代码实战 客户端代码 package com.heima;import java.io.*; import java.net.S…

深度学习算法在工业视觉落地的思考

0.废话 距离上次的栈板识别的思考已经过去3个月&#xff0c;中间根据客户的需求和自己的思考&#xff0c;对软件又重新做了调整。但是整体上还是不满意。 0.1 老生常谈的工业视觉落地架构 对于软件架构&#xff0c;我实在没有太多的参考。没办法&#xff0c;公司根本不关心软…

使用华为eNSP组网试验⑵-通过端口地址进行静态路由

有了网络模拟器可以对很多网络应用场景进行模拟&#xff0c;既方便学习又有利于实际的网络实施。 之前因为没有用过&#xff0c;用过了才知道eNSP的好处。但是与思科模拟器不同&#xff0c;连接是自动连接&#xff0c;不能确定端口&#xff0c;比如使用指定的光纤端口或者RJ45的…

CSS详细基础(六)边框样式

本期是CSS基础的最后一篇~ 目录 一.border属性 二.边框属性复合写法 三.CSS修改表格标签 四.内边距属性 五.外边距属性 六.其他杂例 1.盒子元素水平居中 2.清除网页内外元素边距 3.外边距的合并与塌陷 4.padding不会撑大盒子的情况 七.综合案例——新浪导航栏仿真 …

QT按钮介绍

目录 按钮基类 QAbstractButton QPushButton QToolButton QRadioButton QCheckBox 按钮基类 QAbstractButton 这是按钮的基类&#xff0c;它是继承QWidget类 它可对当前的图标&#xff0c;标题等进行设置。 它有自己的一些信号与槽函数&#xff1a; /* 当按钮被激活时(即…

Chrome(谷歌浏览器)如何关闭搜索栏历史记录

目录 问题描述解决方法插件解决&#xff08;亲测有效&#xff09;自带设置解决步骤首先打开 地址 输入&#xff1a;chrome://flags关闭浏览器&#xff0c;重新打开Chrome 发现 已经正常 问题描述 Chrome是大家熟知的浏览器&#xff0c;但是搜索栏的历史记录如何自己一条条的删…

asp.net core mvc 文件上传,下载,预览

//文件上传用到了IformFile接口 1.1文件上传视图 <form action"/stu/upload" method"post" enctype"multipart/form-data"><input type"file" name"img" /><input type"submit" value"上传&…

国庆day1

发送数据 #include<myhead.h>//消息结构体 typedef struct {long msgtype; //消息类型char data[1024]; //消息正文 }Msg_ds;#define SIZE sizeof(Msg_ds)-sizeof(long) //正文大小 int main(int argc, const char *argv[]) {//1、创建key值key_t ke…