1. HDF框架概述:HDF在鸿蒙系统中的定位、核心设计思想与Linux设备模型对比

各位同学,咱们今天正式开讲HDF框架。说实话,我第一次接触HDF时,心里也犯嘀咕——这不就是鸿蒙版的设备驱动框架吗?后来深入项目才发现,事情没那么简单。

HDF的全称是Hardware Driver Foundation,翻译过来就是硬件驱动基础框架。它在鸿蒙系统里的位置,相当于Linux内核中的设备驱动模型。但你要是把它当成Linux驱动模型的简单移植,那就大错特错了。

1.1 HDF在鸿蒙系统中的定位

先看一张图,你就明白HDF到底站在哪了。

HDF在鸿蒙系统中的定位 应用层(APP / Framework) 系统服务层(System Ability / SAMgr) HDF 硬件驱动框架 驱动管理 | 设备发现 | 电源管理 | 配置解析 | 消息通信 内核层(LiteOS / Linux Kernel) 硬件层(Sensor / Display / Audio / GPIO ...) HDF 位于系统服务层与内核层之间,是硬件驱动的统一管理平台 向上提供标准驱动接口,向下屏蔽硬件差异,实现驱动与系统的解耦

从这张图你能看到,HDF夹在系统服务层和内核层之间。它不直接跟硬件打交道,而是通过内核去操作硬件。那它到底干了什么?

  • 驱动管理:驱动的加载、卸载、绑定、生命周期管理,全归它管
  • 设备发现:硬件插拔、设备枚举、资源匹配,自动完成
  • 电源管理:设备休眠唤醒、功耗控制,统一策略
  • 配置解析:用HCS配置文件描述硬件信息,不用改代码
  • 消息通信:驱动之间、驱动与用户态之间,走统一通道

说白了,HDF就是鸿蒙硬件驱动的大管家。你写驱动时,只需要关心硬件操作本身,其他杂事交给HDF。

1.2 HDF框架核心设计思想

HDF的设计思想,我总结为四个关键词。你在后面写驱动时会反复遇到它们。

设计思想 核心含义 我遇到的坑
分层解耦 驱动按功能分层,每层只做自己的事 曾经把业务逻辑写在中断里,调试到崩溃
配置驱动 硬件信息写在HCS文件,驱动代码不动 改配置比改代码快10倍,真的
统一接口 所有驱动对外暴露标准API 用户态调驱动像调函数一样简单
跨内核 同一套驱动代码,跑在LiteOS和Linux上 这个特性救了我一次项目延期

1.2.1 分层解耦

HDF把驱动拆成三层:

  • 驱动管理层:负责驱动生命周期、设备匹配、电源策略
  • 驱动服务层:提供对外接口,比如open/read/write/ioctl
  • 驱动实现层:真正操作寄存器、处理中断的地方

我在项目中遇到过一个问题:某传感器驱动里,有人把业务逻辑直接写在中断处理函数里。结果中断一多,系统直接卡死。后来按HDF的分层思想,把中断只做数据采集,业务逻辑放到工作队列里,问题就解决了。

我的习惯:写驱动前,先画分层图。哪层做什么,接口怎么传,画清楚了再动代码。这能省掉后面80%的调试时间。

1.2.2 配置驱动

HDF用HCS(HDF Configuration Source)文件来描述硬件信息。比如传感器挂在哪条I2C总线上、地址是多少、中断引脚是哪个,全写在配置文件里。

// 一个典型的HCS配置片段
root {
    sensor_config {
        board_config {
            i2c_bus = 2;        // I2C总线号
            i2c_addr = 0x76;    // 设备地址
            irq_gpio = 18;      // 中断引脚
            power_ctrl = 1;     // 电源控制使能
        }
    }
}

为什么要这么做?你想想看,如果硬件改了个引脚,传统做法要改驱动代码重新编译。有了HCS,改一下配置文件,重启就生效。我在一个项目里,光靠改配置就适配了3款不同型号的传感器,驱动代码一行没动。

1.2.3 统一接口

HDF给所有驱动定义了标准接口。不管你是I2C传感器、SPI显示屏还是GPIO按键,对外暴露的API风格都一样。

// HDF标准驱动接口
struct HdfDriverEntry g_sensorDriverEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_SENSOR",
    .Bind = SensorBind,      // 绑定服务
    .Init = SensorInit,      // 初始化
    .Release = SensorRelease // 释放资源
};

这种统一性带来的好处是——上层应用调驱动时,根本不用关心底层是什么硬件。我做过一个项目,用户态程序通过HDF接口同时操作了温度传感器、加速度计和陀螺仪,代码风格完全一致。

1.2.4 跨内核

鸿蒙支持LiteOS和Linux双内核。HDF在这两个内核上提供了同一套API。你写的驱动,只要遵循HDF规范,就能无缝切换内核。

注意:跨内核不是说代码完全不用改。底层中断处理、DMA操作这些跟内核强相关的地方,还是需要条件编译。但业务逻辑层确实可以做到一次编写、两处运行。

1.3 HDF与Linux设备模型的对比

很多同学是从Linux驱动转过来的。咱们直接对比一下,心里就有数了。

对比维度 Linux设备模型 HDF框架
设计哲学 一切皆文件,驱动通过file_operations暴露 一切皆服务,驱动通过Service发布
配置方式 Device Tree(DTS) HCS配置文件
驱动模型 platform_driver + platform_device HdfDriverEntry + HdfDeviceObject
用户态访问 open/read/write/ioctl系统调用 HDF提供的Service接口,支持IPC
电源管理 runtime PM + system suspend/resume HDF统一电源管理框架
跨内核支持 仅Linux LiteOS + Linux
热插拔 udev机制 HDF设备发现机制

我来解释几个关键差异:

  • 配置方式:Linux用DTS,HDF用HCS。语法上HCS更简洁,而且支持运行时重载。我个人觉得HCS比DTS好读多了。
  • 用户态访问:Linux驱动暴露设备节点,用户态通过系统调用访问。HDF驱动暴露Service,用户态通过IPC调用。这意味着HDF驱动天然支持跨进程访问。
  • 驱动模型:Linux的platform_driver需要手动匹配设备。HDF的HdfDriverEntry由框架自动匹配,你只需要注册就行。

一句话总结:Linux设备模型是面向文件的,HDF是面向服务的。如果你习惯Linux那套,转过来需要适应一下,但适应之后你会发现HDF在嵌入式场景下更顺手。

1.4 本章小结

咱们这一章把HDF的定位、设计思想和对比都过了一遍。核心记住三点:

  1. HDF是鸿蒙硬件驱动的统一管理平台,位于系统服务层和内核层之间
  2. 它的设计思想是分层解耦、配置驱动、统一接口、跨内核
  3. 跟Linux设备模型比,HDF更强调服务化和配置化,适合嵌入式场景