6.4 设备驱动程序

L36

学习目标

文件抽象、文件系统层次;嵌入式常有 FlashFS/LittleFS(本课原理+规划)。

  • 按名访问、持久性。
  • 教学可选 RAMFS 后续扩展。
  • RAMFS 的数据在 SRAM 里,掉电就没了;适合日志、配置草稿,不适合当唯一的长期仓库。
  • 最小接口通常是 create、open/close、read/write、list;下面是文件控制块和一块连续或分块的内存池。
  • 它可以挂在字符设备或后续 Flash 抽象前面,先把「文件」这个词用起来。
  • 缓冲平滑速度差。
  • 本课串口暂可无复杂缓冲。
  • 官方用 HCS;本课用表。

原理 · 深入理解

6.4 设备驱动程序

本节概览:先建立「设备驱动程序」的框架,再依次展开下列小节。

  1. 设备驱动程序概述
  2. 设备驱动程序的处理过程
  3. 对I/O设备的控制方式

6.4.1 设备驱动程序概述

驱动程序是实现在与设备无关软件和设备控制器之间通信和转换的程序,将抽象I/O请求转换成具体I/O操作后传送给控制器,并把控制器中记录的设备状态和I/O操作完成情况及时反映给请求I/O的进程。

驱动程序与设备控制器及I/O设备的硬件特性紧密相关,不同类型设备应配置不同驱动程序,但可为相同的多个终端设置一个终端驱动程序。

驱动程序与I/O设备采用的I/O控制方式紧密相关,常用控制方式是中断驱动和DMA方式。

驱动程序与硬件紧密相关,其中一部分必须用汇编语言书写,目前很多驱动程序的基本部分已固化在ROM中。

  1. 驱动程序应允许可重入,一个正在运行的驱动程序常会在一次调用完成前被再次调用

接收由与设备无关软件发来的命令和参数,将命令中的抽象要求转换为与设备相关的低层操作序列。

检查用户I/O请求的合法性,了解I/O设备工作状态,传递与I/O设备操作有关的参数,设置设备工作方式。

发出I/O命令:设备空闲则立即启动I/O设备完成指定操作;设备忙碌则将请求块挂在设备队列上等待。

及时响应设备控制器发来的中断请求,根据中断类型调用相应中断处理程序进行处理。

不同操作系统采用的设备处理方式不完全相同,可将设备处理方式分为三类。

  1. 为每一类设备设置一个进程,专门执行这类设备的I/O操作
  2. 在整个系统中设置一个I/O进程,专门执行系统中所有各类设备的I/O操作
  3. 不设置专门的设备处理进程,只为各类设备设置相应的设备驱动程序,供用户或系统进程调用

6.4.2 设备驱动程序的处理过程

设备驱动程序的主要任务是启动指定设备,完成上层指定的I/O工作。启动前应先完成必要的准备工作,如检测设备状态是否为忙等,所有准备工作完成后才向设备控制器发送启动命令。

处理流程如下:

  1. 将抽象要求转换为具体要求
  2. 对服务请求进行校验
  3. 检查设备的状态
  4. 传送必要的参数
  5. 启动I/O设备
图6-12 状态寄存器中的格式 完成 1/0 1/0 1/0
图6-12 状态寄存器中的格式

6.4.3 对I/O设备的控制方式

DMA方式比中断方式显著减少了CPU的干预,已由以字(节)为单位减少到以数据块为单位,但CPU每发出一条I/O指令也只能读(或写)一个连续的数据块。当需要一次读多个数据块且分别传送到不同内存区域时,需要CPU发出多条I/O指令及多次中断处理。

I/O通道方式是DMA方式的发展,可进一步减少CPU的干预,把对一个数据块的读(写)为单位的干预,减少为对一组数据块的读(写)及有关控制和管理工作为单位的干预。

直接存储器访问(DMA)方式的特点如下:

  1. 数据传输的基本单位是数据块
  2. 所传送的数据从设备直接送入内存,或者相反
  3. 仅在传送一个或多个数据块的开始和结束时才需CPU干预,整块数据的传送在控制器控制下完成
图6-13 程序I/O和中断驱动方式的流程 轮询 vs 中断
图6-13 程序I/O和中断驱动方式的流程

当前对I/O设备的控制广泛采用中断可编程I/O方式。某进程要启动I/O设备工作时,CPU向相应设备控制器发出一条I/O命令,然后立即返回继续执行原任务,此时CPU与I/O设备并行操作。

虽然中断驱动I/O比程序I/O方式更有效,但它仍以字(节)为单位进行I/O,每当完成一个字(节)的I/O时控制器便要向CPU请求一次中断。

I/O控制方式的发展始终贯穿一个宗旨:尽量减少主机对I/O控制的干预,把主机从繁杂的I/O控制事务中解脱出来,更多地去完成数据处理任务。

轮询可编程I/O方式:处理机向控制器发出I/O指令启动输入设备时,同时把状态寄存器中的忙/闲标志busy置为1,然后不断循环测试busy(称为轮询)。

当busy=1时表示输入机尚未输完一个字(符),处理机继续测试该标志,直至busy=0,表明输入机已将数据送入控制器的数据寄存器。处理机将数据寄存器中的数据取出送入内存指定单元,完成一个字(符)的I/O,再启动读下一个数据并置busy=1。

DMA 控制器由三部分组成:主机与 DMA 控制器的接口、DMA 控制器与块设备的接口、I/O 控制逻辑。

  1. 命令/状态寄存器 CR
  2. 内存地址寄存器 MAR
  3. 数据寄存器 DR
  4. 数据计数器 DC
图6-14 DMA控制器的组成 地址寄存器 字计数 控制逻辑 成块搬内存,少打扰 CPU
图6-14 DMA控制器的组成

DMA 工作过程:CPU 从磁盘读入数据块时,向磁盘控制器发送读命令送入 CR,将数据在内存的起始目标地址送入 MAR,要读入的数据量送入 DC,然后 CPU 继续执行其他任务,由 DMA 控制器直接完成数据传送。

图6-15 DMA方式的工作流程图 CPU 设地址和计数 DMA 成块搬 计数到 0 中断 CPU
图6-15 DMA方式的工作流程图

I/O 通道控制方式的引入:DMA 方式已将 CPU 干预减少到以数据块为单位,但每条 I/O 指令只能读写一个连续数据块。当需要一次读写多个数据块且传送到不同内存区域时,需 CPU 分别发多条指令。

I/O 通道方式是 DMA 的发展,进一步减少 CPU 干预,把对一个数据块的干预减少为对一组数据块及有关控制和管理的干预。

程序控制 I/O vs DMA PIO:CPU 逐字节搬 CPU 控制器 每字节一次中断/查询 DMA:通道自己搬 CPU DMA 完成中断 内存 ⇄ 设备

通道程序:通道通过执行通道程序与设备控制器共同实现对 I/O 设备的控制。通道程序由一系列通道指令(通道命令)构成。

一个由六条通道指令构成的简单通道程序,功能是将内存中不同地址的数据写成多个记录。

  1. 通道指令包含:操作码
  2. 内存地址

做 · 实验

  • 根据「学习目标」列出 3 个关键词,对照原理段落解释给自己听。
  • 写出 RAMFS 的最小 API 列表与数据结构草图。
  • 填写外设→module→service 表;交互动画预览寻道。
  • 编译 HDF UART 实验,确认输出能表明走了服务而不是纯裸机路径。
  • 对照裸机串口实验的日志,列出多出来的标识或调用层次。
  • 烧录 08-hdf-uart,串口有课程标识行。

打开工作台

设备驱动程序

io-buffering

fs-acl

用控件单步操作;日志区记下每一步发生了什么。

代码导读

本课在工作台编译烧录。先读 user 实验入口,再对照 kernel / HDF 中被调用的函数,不要一上来改链接脚本。

总结与提升

  • 能说出文件相对「裸扇区」的好处。
  • 能用自己的话复述学习目标,并指出概念与板上实验的对应。
  • 设计稿含 create/read/write/list。
  • 能说明双缓冲的好处。
  • 能区分 moduleName 与 serviceName。
  • 能举出嵌入式简化保护的一种做法。
  • 能解释路径名解析步骤。
  • 映射表含 uart0、gpio,并预留 tft/rgb。
  • 能默写 Bind/Init/Release 职责。
  • 串口输出稳定,并能说明访问路径经过 HDF。
  • 按下/松开有 HDF 日志。

延伸思考

  • 配置参数用文件还是 Kconfig?
  • 如果把本节机制拿到 Linux 或完整 OpenHarmony 上,会多出哪些硬件假设?
  • RAMFS 与消息队列谁更适合「临时日志」?
  • RGB 帧缓冲算哪类缓冲?

← 本阶段封面 · 课程列表