Linux 设备驱动开发思想 —— 驱动分层与驱动分离

2023-05-16

      前面我们学习I2C、USB、SD驱动时,有没有发现一个共性,就是在驱动开发时,每个驱动都分层三部分,由上到下分别是:

1、XXX 设备驱动

2、XXX 核心层

3、XXX 主机控制器驱动

      而需要我们编写的主要是设备驱动部分,主机控制器驱动部分也有少量编写,二者进行交互主要时由核心层提供的接口来实现;这样结构清晰,大大地有利于我们的驱动开发,这其中就是利用了Linux设备驱动开发中两个重要思想,下面来一一解析


一、设备驱动的分层思想

       在面向对象的程序设计中,可以为某一类相似的事物定义一个基类,而具体的事物可以继承这个基类中的函数。如果对于继承的这个事物而言,其某函数的实现与基类一致,那它就可以直接继承基类的函数;相反,它可以重载之。这种面向对象的设计思想极大地提高了代码的可重用能力,是对现实世界事物间关系的一种良好呈现。

      Linux内核完全由C语言和汇编语言写成,但是却频繁用到了面向对象的设计思想。在设备驱动方面,往往为同类的设备设计了一个框架,而框架中的核心层则实现了该设备通用的一些功能。同样的,如果具体的设备不想使用核心层的函数,它可以重载之。举个例子:

return_type core_funca(xxx_device * bottom_dev, param1_type param1, param1_type param2)
{
	if (bottom_dev->funca)
	return bottom_dev->funca(param1, param2);
	/* 核心层通用的funca代码 */
	...
}

     上述core_funca的实现中,会检查底层设备是否重载了funca(),如果重载了,就调用底层的代码,否则,直接使用通用层的。这样做的好处是,核心层的代码可以处理绝大多数该类设备的funca()对应的功能,只有少数特殊设备需要重新实现funca()

再看一个例子:

return_type core_funca(xxx_device * bottom_dev, param1_type param1, param1_type param2)
{
	/*通用的步骤代码A */
	...
	bottom_dev->funca_ops1();
	/*通用的步骤代码B */
	...
	bottom_dev->funca_ops2();
	/*通用的步骤代码C */
	...
	bottom_dev->funca_ops3();
}

    上述代码假定为了实现funca(),对于同类设备而言,操作流程一致,都要经过“通用代码A、底层ops1、通用代码B、底层ops2、通用代码C、底层ops3”这几步,分层设计明显带来的好处是,对于通用代码A、B、C,具体的底层驱动不需要再实现,而仅仅只关心其底层的操作ops1、ops2、ops3。图1明确反映了设备驱动的核心层与具体设备驱动的关系,实际上,这种分层可能只有2层(图1的a),也可能是多层的(图1的b)。


       这样的分层化设计在Linux的input、RTC、MTD、I2 C、SPI、TTY、USB等诸多设备驱动类型中屡见不鲜。


二、主机驱动和外设驱动分离思想

主机、外设驱动分离的意义

       在Linux设备驱动框架的设计中,除了有分层设计实现以外,还有分隔的思想。举一个简单的例子,假设我们要通过SPI总线访问某外设,在这个访问过程中,要通过操作CPU XXX上的SPI控制器的寄存器来达到访问SPI外设YYY的目的,最简单的方法是:

return_type xxx_write_spi_yyy(...)
{
	xxx_write_spi_host_ctrl_reg(ctrl);
	xxx_ write_spi_host_data_reg(buf);
	while(!(xxx_spi_host_status_reg()&SPI_DATA_TRANSFER_DONE));
	...
}

     如果按照这种方式来设计驱动,结果是对于任何一个SPI外设来讲,它的驱动代码都是CPU相关的。也就是说,当然用在CPU XXX上的时候,它访问XXX的SPI主机控制寄存器,当用在XXX1的时候,它访问XXX1的SPI主机控制寄存器:

return_type xxx1_write_spi_yyy(...)
{
	xxx1_write_spi_host_ctrl_reg(ctrl);
	xxx1_ write_spi_host_data_reg(buf);
	while(!(xxx1_spi_host_status_reg()&SPI_DATA_TRANSFER_DONE));
	...
}
      这显然是不能接受的,因为这意味着外设YYY用在不同的CPU XXX和XXX1上的时候需要不同的驱动。那么,我们可以用如图的思想对主机控制器驱动和外设驱动进行分离。这样的结构是, 外设a、b、c的驱动与主机控制器A、B、C的驱动不相关,主机控制器驱动不关心外设,而外设驱动也不关心主机,外设只是访问核心层的通用的API进行数据传输,主机和外设之间可以进行任意的组合


      如果我们不进行上图的主机和外设分离,外设a、b、c和主机A、B、C进行组合的时候,需要9个不同的驱动。设想一共有m个主机控制器,n个外设,分离的结果是需要m+n个驱动,不分离则需要m*n个驱动。

      Linux SPI、I2C、USB、ASoC(ALSA SoC)等子系统都典型地利用了这种分离的设计思想。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux 设备驱动开发思想 —— 驱动分层与驱动分离 的相关文章

随机推荐

  • 基于STM32实验:uC/OS-III操作系统移植并创建多任务系统实验

    本次实验内容 xff1a 将uC OS III操作系统移植到stm32F103C8T6上 xff0c 构建至少3个任务 xff08 task xff09 xff1a 分别以1s和3s周期对LED灯进行点亮 熄灭的控制 xff1b 另外一个t
  • 初级软件测试面试题汇总

    一 请描述如何划分缺陷与错误严重性和优先级别 xff1f 给软件缺陷与错误划分严重性和优先级的通用原则 xff1a xff08 1 xff09 表示软件缺陷所造成的危害和恶劣程度 xff08 2 xff09 优先级表示修复缺陷的重要程度和次
  • selenium 安装

    火狐浏览器版本 xff1a 35 0 1 1 官网安装 Version 2 9 1 1 通过官网安装插件 xff1a https addons mozilla org en GB firefox addon selenium ide ver
  • 构造函数与析构函数执行顺序

    构造函数与析构函数执行顺序 代码 xff1a include lt iostream gt using namespace std class ABCD public ABCD int a int b int c this gt a 61
  • java.lang.NoSuchMethodException异常

    在Struts2中 xff0c 有时候会出现java lang NoSuchMethodException异常 xff0c 有可能是三种情况导致的运行异常 xff1a 第一种 xff1a Action 类的方法被定义成 private 类型
  • java.lang.IllegalArgumentException异常解决

    在maven项目中测试代码的时候 xff0c 碰到java lang IllegalArgumentException 异常 xff1a 严重 Servlet service for servlet e3 manager in contex
  • 在idea中创建一个普通工程

    第一步 xff1a File gt new gt Project 第二步 xff1a 点击next 点击 finish 即可 xff01 xff01 xff01 运行结果
  • java:获取当月最后一天

    设置时间格式 SimpleDateFormat format 61 new SimpleDateFormat 34 yyyy MM dd 34 获得实体类 Calendar ca 61 Calendar getInstance 设置最后一天
  • idea自动生成UUID和解决办法

    正常情况下 xff0c 鼠标点击类名 xff0c Alt 43 Insert键就会出现生成UUID选项 xff0c 即 xff1a 有时候Alt 43 Insert没有UUID选项 xff0c 解决办法 第一种情况 xff1a Settin
  • 页面<div>位置调整

    调整页面 lt div gt 样式 给 lt div gt lt select gt 分别起名字 xff1a div2 xff0c s1 lt div gt 代码 xff1a lt div class 61 34 div2 34 style
  • 马士兵_JAVA自学之路(为那些目标模糊的码农们)

    转载自 xff1a https blog csdn net anlidengshiwei article details 42264301 JAVA自学之路 一 学会选择 为了就业 xff0c 不少同学参加各种各样的培训 决心做软件的 xf
  • 在深度学习中Softmax交叉熵损失函数的公式求导

    以下部分基本介绍转载于点击打开链接 在深度学习NN中的output层通常是一个分类输出 xff0c 对于多分类问题我们可以采用k 二元分类器来实现 xff0c 这里我们介绍softmax softmax回归中 xff0c 我们解决的是多分类
  • 1-基于ArUco码的标记与检测

    1 简介 姿态估计 xff08 Pose estimation xff09 在 计算机视觉领域扮演着十分重要的角色 xff1a 机器人导航 增强现实以及其它 这一过程的基础是找到现实世界和图像投影之间的对应点 这通常是很困难的一步 xff0
  • 4-基于ArUco相机姿态评估

    1 简介 基于ArUco评估相机姿态 xff0c 可以使用OPENCV的外部库 xff08 opencv contrib xff09 中的aruco模块 xff0c 可以参考安装目录 xff08 库目录 xff09 xff1a opencv
  • MySQL--40道基础概念选择题及答案

    一 单选题 xff08 题数 xff1a 40 xff0c 共 40 0 分 xff09 1 在计算机系统中能够实现对数据库资源进行统一管理和控制的是 xff08 A xff09 A DBMS B DBA C DBS D DBAS 2 数据
  • 抽象类方法——子类定义getDescription方法返回对一个人的简单描述

    Person与子类的关系图 每一个 人都有一些诸如名字这样的属性 xff0c 学生与雇员都有名字属性 xff0c 因此可以将getName方法放在位于继承关系较高层的通用超类 xff08 父类 xff09 中 xff0c 现在增加一个get
  • Exynos4412 Uboot 移植(一)—— Uboot 编译流程分析

    Uboot 所用版本 u boot 2013 01 u boot 2013 01 中有上千文件 xff0c 要想了解对于某款开发板 xff0c 使用哪些文件 哪些文件首先执行 可执行文件占用内存的情况 xff0c 最好的方法就是阅读它的Ma
  • Linux USB 驱动开发(五)—— USB驱动程序开发过程简单总结

    设备驱动程序是操作系统内核和机器硬件之间的接口 xff0c 由一组函数和一些私有数据组成 xff0c 是应用程序和硬件设备之间的桥梁 在应用程序看来 xff0c 硬件设备只是一个设备文件 xff0c 应用程序可以像操作普通文件一样对硬件设备
  • 路由器开发(一)—— 路由器硬件结构及软件体系

    一 路由器的硬件构成 路由器主要由以下几个部分组成 xff1a 输入 输出接口部分 包转发或交换结构部分 xff08 switching fabric xff09 路由计算或处理部分 如图所示 图1 路由器的基本组成 输入端口是物理链路和输
  • Linux 设备驱动开发思想 —— 驱动分层与驱动分离

    前面我们学习I2C USB SD驱动时 xff0c 有没有发现一个共性 xff0c 就是在驱动开发时 xff0c 每个驱动都分层三部分 xff0c 由上到下分别是 xff1a 1 XXX 设备驱动 2 XXX 核心层 3 XXX 主机控制器