嵌入式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.rhkb.cn/news/144637.html

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

相关文章

QT信号槽

目录 信号槽的概念 按钮的常用信号 自定义槽函数 自定义信号函数 自定义槽和信号注意的事项 信号与槽的拓展 lambda表达式 信号槽的概念 信号槽是Qt框架引以为豪的机制之一。所谓信号槽&#xff0c;实际就是观察者模式。当某个事件发生之后&#xff0c;比如&#xff0c…

布隆过滤器Bloom Filter

本章代码gitee仓库&#xff1a;布隆过滤器 文章目录 0. 前言1. 布隆过滤器的概念2. 布隆过滤器的实现2.1 哈希函数2.2 插入和判断 3. 布隆过滤器的删除4. 布隆过滤器的误判 0. 前言 我们在玩某款游戏的时候&#xff0c;刚注册的话&#xff0c;我们需要取一个昵称&#xff0c;这…

【Java】复制数组的四种方式

1. System.arraycopy() 用来将一个数组的&#xff08;一部分&#xff09;内容复制到另一个数组里面去。 定义&#xff1a; void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);例&#xff1a; int[] arr1 { 1, 2, 3, 4, 5 }; int[] arr2 new…

CSS详细基础(四)显示模式

本帖开始介绍CSS中更复杂的内容 目录 一.显示模式 1.行内元素 2.块级元素 3.行内块元素 二.背景样式 一.显示模式 顾名思义&#xff0c;在CSS中&#xff0c;元素主要有3种显示模式&#xff1a;行内元素、块级元素、行内块元素~ 所谓块级元素&#xff0c;指的是该元素在…

ROS2 从头开始​​:第6部分 - ROS2 中的 DDS,用于可靠的机器人通信

一、说明 在这篇文章中,我们将重点关注 ROS 2的通信栈DDS,其中这是介于管理节点通信与控制节点通信环节,是上位机决策体系与下位机的控制体系实现指令-执行-反馈的关键实现机制。 二、ROS工程的概念框架 现代机器人系统非常复杂,因为需要集成各种类型的传感器、执行器和其…

Vue封装全局SVG组件

1.SVG图标配置 1.安装插件 npm install vite-plugin-svg-icons -D 2.Vite.config.ts中配置 import { createSvgIconsPlugin } from vite-plugin-svg-icons import path from path export default () > {return {plugins: [createSvgIconsPlugin({// Specify the icon fo…

JavaScript高阶班之ES6 → ES11(八)

JavaScript高阶班之ES6 → ES11 1、ES6新特性1.1、let 关键字1.2、const关键字1.3、变量的解构赋值1.3.1、数组的解构赋值1.3.2、对象的解构赋值 1.4、模板字符串1.5、简化对象写法1.6、箭头函数1.7、函数参数默认值1.8、rest参数1.9、spread扩展运算符1.9.1、数组合并1.9.2、数…

PYQT制作动态时钟

所有代码&#xff1a; import sys from PyQt5.QtCore import Qt, QTimer, QRect from PyQt5.QtGui import QPixmap, QTransform, QPainter, QImage from PyQt5.QtWidgets import QApplication, QLabel from PyQt5 import uic import newdef adder():global iglobal angle_s, a…

大数据Flink(八十八):Interval Join(时间区间 Join)

文章目录 Interval Join&#xff08;时间区间 Join&#xff09; Interval Join&#xff08;时间区间 Join&#xff09; Interval Join 定义&#xff08;支持 Batch\Streaming&#xff09;&#xff1a;Interval Join 在离线的概念中是没有的。Interval Join 可以让一条流去 Jo…

UE4 Cesium 与ultra dynamic sky插件天气融合

晴天&#xff1a; 雨天&#xff1a; 雨天湿度&#xff1a; 小雪&#xff1a; 中雪&#xff1a; 找到该路径这个材质&#xff1a; 双击点开&#xff1a; 将Wet_Weather_Effects与Snow_Weather_Effects复制下来&#xff0c;包括参数节点 找到该路径这个材质&#xff0c;双击点开&…

Docker配置镜像加速器

1.登录阿里云 阿里云-计算&#xff0c;为了无法计算的价值 (aliyun.com) 2.容器 说明&#xff1a;找到产品下的容器 3.容器镜像服务ACR 4.点击控制台 5. 点击镜像加速器 6.操作文档

35 LRU缓存

LRU缓存 题解1 双map&#xff08;差2个testcases&#xff09;题解2 哈希表双向链表&#xff08;参考&#xff09;题解3 STL:listunordered_map 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正…

ThreeJS-3D教学四-光源

three模拟的真实3D环境&#xff0c;一个非常炫酷的功能便是对光源的操控&#xff0c;之前教学一中已经简单的描述了多种光源&#xff0c;这次咱们就详细的讲下一些最常见的光源&#xff1a; AmbientLight 该灯光在全局范围内平等地照亮场景中的所有对象。 该灯光不能用于投射阴…

k8s部署gin-vue-admin框架、gitlab-ci、jenkins pipeline 、CICD

测试环境使用的jenkins 正式环境使用的gitlab-ci 测试环境 创建yaml文件 apiVersion: v1 kind: ConfigMap metadata:name: dtk-go-tiktok-admin-configlabels:app.kubernetes.io/name: dtk-go-tiktok-adminapp.kubernetes.io/business: infrastructureapp.kubernetes.io/run…

Windows系统利用cpolar内网穿透搭建Zblog博客网站并实现公网访问内网!

文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网站制作网页是绕…

What is a UDP Flood Attack?

用户数据报协议 &#xff08;UDP&#xff09; 是计算机网络中使用的无连接、不可靠的协议。它在互联网协议 &#xff08;IP&#xff09; 的传输层上运行&#xff0c;并提供跨网络的快速、高效的数据传输。与TCP&#xff08;其更可靠的对应物&#xff09;不同&#xff0c;UDP不提…

GitHub配置SSH key

GitHub配置SSH key Git配置信息并生成密钥 设置用户名和密码 设置用户名 git config --global user.name "用户名" 设置邮箱 git confir --global user.email "邮箱" 生成密钥 ssh-keygen -t rsa -C "邮箱" 查看密钥 到密钥所保存的位置 复…

ubuntu与win之间共享文件夹

ubuntu上设置共享文件夹 第一步&#xff1a;点击【设置】或【虚拟机弹窗下面的【设置】选项】 第二步&#xff1a;进入【虚拟机设置】页面&#xff0c;点击【选项】如下图所示 第三步&#xff1a;启用共享文件&#xff1a;点击【总是启用】第四步&#xff1a;添加共享文件&…

uni-app:canvas-绘制图形4(获取画布宽高,根据画布宽高进行图形绘制)

效果 代码 var width ; var height ; const query uni.createSelectorQuery(); //获取宽度 query.select(#firstCanvas).fields({ size: true }, (res) > { width res.width; height res.height; }).exec(); console.log(宽度width); console.log(高…

国庆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…