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

1、XXX 设备驱动

2、XXX 核心层

3、XXX 主机控制器驱动

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

一、设备驱动的分层思想

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

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

[cpp] view plaincopy
  1. return_type core_funca(xxx_device * bottom_dev, param1_type param1, param1_type param2)
  2. {
  3. if (bottom_dev->funca)
  4. return bottom_dev->funca(param1, param2);
  5. /* 核心层通用的funca代码 */
  6. ...
  7. }

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

再看一个例子:

[cpp] view plaincopy
  1. return_type core_funca(xxx_device * bottom_dev, param1_type param1, param1_type param2)
  2. {
  3. /*通用的步骤代码A */
  4. ...
  5. bottom_dev->funca_ops1();
  6. /*通用的步骤代码B */
  7. ...
  8. bottom_dev->funca_ops2();
  9. /*通用的步骤代码C */
  10. ...
  11. bottom_dev->funca_ops3();
  12. }

上述代码假定为了实现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的目的,最简单的方法是:

[cpp] view plaincopy
  1. return_type xxx_write_spi_yyy(...)
  2. {
  3. xxx_write_spi_host_ctrl_reg(ctrl);
  4. xxx_ write_spi_host_data_reg(buf);
  5. while(!(xxx_spi_host_status_reg()&SPI_DATA_TRANSFER_DONE));
  6. ...
  7. }

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

[cpp] view plaincopy
  1. return_type xxx1_write_spi_yyy(...)
  2. {
  3. xxx1_write_spi_host_ctrl_reg(ctrl);
  4. xxx1_ write_spi_host_data_reg(buf);
  5. while(!(xxx1_spi_host_status_reg()&SPI_DATA_TRANSFER_DONE));
  6. ...
  7. }

这显然是不能接受的,因为这意味着外设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)等子系统都典型地利用了这种分离的设计思想。

Linux 设备驱动开发思想 —— 驱动分层与驱动分离相关推荐

  1. 嵌入式Linux设备驱动程序:在运行时读取驱动程序状态

    嵌入式Linux设备驱动程序:在运行时读取驱动程序状态 Embedded Linux device drivers: Reading driver state at runtime 在运行时了解驱动程 ...

  2. 32驱动_轻松掌握pinctrl子系统驱动开发——一个虚拟pinctrl dev驱动开发

    这周主要对pinctrl子系统进行分析,该分析的基本上已经分析完成,唯一没有细说的估计就是gpio与pinctrl之间的关联了.本章即是pinctrl子系统分析的最后一章,本章我们主要实现一个虚拟的p ...

  3. 《精通Linux设备驱动程序开发》——1.5 Linux发行版

    本节书摘来自异步社区<精通Linux设备驱动程序开发>一书中的第1章,第1.5节,作者:[印]Sreekrishnan Venkateswaran(斯里克里斯汉 温卡特斯瓦兰)著,更多章节 ...

  4. 《精通Linux设备驱动程序开发》——1.7 编译内核

    本节书摘来自异步社区<精通Linux设备驱动程序开发>一书中的第1章,第1.7节,作者:[印]Sreekrishnan Venkateswaran(斯里克里斯汉 温卡特斯瓦兰)著,更多章节 ...

  5. 驱动开发:配置Visual Studio驱动开发环境

    在正式开始驱动开发之前,需要自行搭建驱动开发的必要环境,首先我们需要安装Visual Studio 2013这款功能强大的程序开发工具,在课件内请双击ISO文件并运行内部的vs_ultimate.ex ...

  6. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED驱动框架--面向对象、分层设计思想

    文章目录 前言 1.LED驱动程序框架 1.1.对于LED驱动,我们想要什么样的接口? 1.2.LED驱动要怎么写,才能支持多个板子?分层写 1.3.程序分析 驱动程序 应用程序 Makefile 1 ...

  7. 嵌入式Linux设备驱动程序开发指南14(Linux设备驱动使用DMA)——读书笔记

    Linux设备驱动使用DMA 十四.Linux设备驱动使用DMA 14.1 简介 14.2 缓存一致性 14.3 DMA控制器接口 14.4 流式DMA模块 14.4.1 sdma_sam_m2m.c ...

  8. linux主设备编号从0到多少,Linux驱动开发之主设备号找驱动,次设备号找设备

    一.引言 很久前接触linux驱动就知道主设备号找驱动,次设备号找设备.这句到底怎么理解呢,如何在驱动中实现呢,在介绍该实现之前先看下内核中主次设备号的管理: 二.Linux内核主次设备号的管理 Li ...

  9. Linux驱动开发之主设备号找驱动,次设备号找设备

    原创作品,转载时请务必以超链接形式标明文章原始出处:http://blog.csdn.net/gqb666/article/details/8805179,作者:gqb666 一.引言   最近成都地 ...

最新文章

  1. 转:在 .NET 中实现异步回调访问数据库
  2. 传统网站性能优化的三种手段
  3. 英文论文中i.e.,e.g.,etc.的正确用法
  4. excel2010设置列宽为像素_vba:如何设置excel图表的宽度和高度(以像素为单位)?...
  5. table row设置cell的html,css中display设置为table、table-row、table-cell后的作用及其注意点...
  6. c#图片处理之:在图片上打上文字
  7. 煤矿行业设备管理系统
  8. 视频码率,帧率和分辨率的联系与差别
  9. 《OSPF和IS-IS详解》一2.4 理解内部BGP
  10. 设计模式之GOF23原型模式01
  11. 单片机的现状即发展前景
  12. java实现复制文件目录及文件到指定路径下
  13. iOS性能优化的几个方向
  14. PHP8与PHP7计算性能对比
  15. 力扣刷题篇——摩尔投票算法
  16. Ain_电脑所有乱码文字集
  17. 内存不能为“read” “written”的解决方法
  18. SMDS:交换式多兆位数据服务--网络大典
  19. android vitamio 缓存,Android如何集成Vitamio
  20. Scrapy Spider中间件,你学会了吗?本篇博客有一案例

热门文章

  1. java获取classpath以外的路径
  2. 解决SQL命令行回退的问题
  3. ADempiere 360LTS 地址(Address)的中国格式定制
  4. 流程制造项目中关于销售订单数量与实际产生数量不同时的解决方案
  5. 江民杀毒软件KV网络版反病毒整体解决方案──金融行业
  6. 233. 数字 1 的个数
  7. 乐高ev3涉及到的一些赛事_使您成为英雄的前五名开发者技能(提示:涉及LEGO)
  8. 计算机工程师分级_这些是每个计算机工程师都应该知道的数字
  9. sphinx 项目根目录_如何使用Sphinx工具记录Django项目
  10. aws lambda_四处奔走:初学者遇到AWS Lambda