OpenHarmony驱动消息机制管理

驱动消息机制管理

当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。

消息机制的功能主要有以下两种:

  • 用户态应用发送消息到驱动。

  • 用户态应用接收驱动主动上报事件。

配置管理

HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。HC-GEN(HDF Configuration Generator)是HCS配置转换工具,可以将HDF配置文件转换为软件可读取的文件格式:

  • 在弱性能环境中,转换为配置树源码或配置树宏定义,驱动可直接调用C代码或宏式APIs获取配置。

  • 在高性能环境中,转换为HCB(HDF Configuration Binary)二进制文件,驱动可使用HDF框架提供的配置解析接口获取配置。

以下是使用HCB模式的典型应用场景:

图2 配置使用流程图

HCS经过HC-GEN编译生成HCB文件,HDF驱动框架中的HCS Parser模块会从HCB文件中重建配置树,HDF驱动模块使用HCS Parser提供的配置读取接口获取配置内容。

配置语法

具体细节在此省略,后面会有些例子。

配置生成

hc-gen 是配置生成的工具,可以对HCS配置语法进行检查并把HCS源文件转化成HCB二进制文件,类似于设备树工具dtc

主要常用用法:

  • 生成.c/.h配置文件方法:

    hc-gen -o [OutputCFileName] -t [SourceHcsFileName]
  • 生成HCB配置文件方法:
hc-gen -o [OutputHcbFileName] -b [SourceHcsFileName]
  • 生成宏定义配置文件方法:
hc-gen -o [OutputMacroFileName] -m [SourceHcsFileName]
  • 反编译HCB文件为HCS方法:
hc-gen -o [OutputHcsFileName] -d [SourceHcbFileName]

平台驱动举例

适配最主要的工作就是根据具体硬件实现适配层相关的钩子函数,并配置好相应的属性文件,即hcs,大致分为以下步骤:

1.实例化驱动入口

2.配置属性文件

3.实例化UART控制器对象

4.驱动调试

统一服务模式

在统一模式下,所有的控制器都被核心层统一管理,并由核心层统一发布一个服务供接口层

比如I2C模块:

  • device_info.hcs配置参考
root {
    device_info {
        match_attr = "hdf_manager";
        device_i2c :: device {
            device0 :: deviceNode {
                policy = 2;
                priority = 50;
                permission = 0644;
                moduleName = "HDF_PLATFORM_I2C_MANAGER";
                serviceName = "HDF_PLATFORM_I2C_MANAGER";
                deviceMatchAttr = "hdf_platform_i2c_manager";
            }
            device1 :: deviceNode {
                policy = 0;                               // 等于0,不需要发布服务。
                priority = 55;                            // 驱动启动优先级。
                permission = 0644;                        // 驱动创建设备节点权限。
                moduleName = "hi35xx_i2c_driver";         //【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致。
                serviceName = "HI35XX_I2C_DRIVER";        //【必要】驱动对外发布服务的名称,必须唯一。
                deviceMatchAttr = "hisilicon_hi35xx_i2c"; //【必要】用于配置控制器私有数据,要与i2c_config.hcs中对应控制器保持一致,
                                                          // 具体的控制器信息在 i2c_config.hcs中。
            }
        }
    }
}
  • i2c_config.hcs配置参考
root {
    platform {
        i2c_config {
            match_attr = "hisilicon_hi35xx_i2c";  // 【必要】需要和device_info.hcs中的deviceMatchAttr值一致
            template i2c_controller {             // 模板公共参数,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省。
                bus = 0;                          // 【必要】i2c识别号
                reg_pbase = 0x120b0000;           // 【必要】物理基地址
                reg_size = 0xd1;                  // 【必要】寄存器位宽
                irq = 0;                          // 【可选】中断号,由控制器的中断特性决定是否需要
                freq = 400000;                    // 【可选】频率,初始化硬件控制器的可选参数
                clk = 50000000;                   // 【可选】控制器时钟,由控制器时钟的初始化流程决定是否需要
            }
            controller_0x120b0000 :: i2c_controller {
                bus = 0;
            }
            controller_0x120b1000 :: i2c_controller {
                bus = 1;
                reg_pbase = 0x120b1000;
            }
            ...
        }
    }
}

独立服务模式

独立服务模式下,核心层不会统一发布一个服务供上层使用,因此这种模式下驱动要为每个控制器发布一个服务,具体表现为:

  • 驱动适配者需要实现HdfDriverEntry的Bind钩子函数以绑定服务。
  • device_info.hcs文件中deviceNode的policy字段为1或2,不能为0。

    比如UART模块:

  • device_info.hcs 配置参考:
    root {
        device_info {
            match_attr = "hdf_manager";
            platform :: host {
                hostName = "platform_host";
                priority = 50;
                device_uart :: device {
                    device0 :: deviceNode {
                        policy = 1;                                   // 驱动服务发布的策略,policy大于等于1(用户态可见为2,仅内核态可见为1)。
                        priority = 40;                                // 驱动启动优先级
                        permission = 0644;                            // 驱动创建设备节点权限
                        moduleName = "HDF_PLATFORM_UART";             // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致。
                        serviceName = "HDF_PLATFORM_UART_0";          // 驱动对外发布服务的名称,必须唯一,必须要按照HDF_PLATFORM_UART_X的格式,X为UART控制器编号。
                        deviceMatchAttr = "hisilicon_hi35xx_uart_0";  // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值一致。
                    }
                    device1 :: deviceNode {
                      policy = 2;
                      permission = 0644;
                      priority = 40;
                      moduleName = "HDF_PLATFORM_UART"; 
                      serviceName = "HDF_PLATFORM_UART_1";
                      deviceMatchAttr = "hisilicon_hi35xx_uart_1";
                    }
                    ......                                            // 如果存在多个UART设备时【必须】添加节点,否则不用
                }
            }
        }
    }
  • uart_config.hcs 配置参考:
    root {
        platform {
            template uart_controller {                   // 配置模板,如果下面节点使用时继承该模板,则节点中未声明的字段会使用该模板中的默认值
                match_attr = "";
                num = 0;                                 // 【必要】端口号
                baudrate = 115200;                       // 【必要】波特率,数值可按需填写
                fifoRxEn = 1;                            // 【必要】使能接收FIFO
                fifoTxEn = 1;                            // 【必要】使能发送FIFO
                flags = 4;                               // 【必要】标志信号
                regPbase = 0x120a0000;                   // 【必要】地址映射需要
                interrupt = 38;                          // 【必要】中断号
                iomemCount = 0x48;                       // 【必要】地址映射需要
            }
            controller_0x120a0000 :: uart_controller {
                match_attr = "hisilicon_hi35xx_uart_0";  // 【必要】必须和device_info.hcs中对应的设备的deviceMatchAttr值一致
            }
            controller_0x120a1000 :: uart_controller {
                num = 1;
                baudrate = 9600;
                regPbase = 0x120a1000;
                interrupt = 39;
                match_attr = "hisilicon_hi35xx_uart_1";
            }
            ......               // 如果存在多个UART设备时【必须】添加节点,否则不用
        }
    }

    统一服务模式相较独立模式,可以节省资源,方便管理

    外设驱动举例

    这里列举一个稍微简单点的Light驱动模型,Light驱动模型为上层Light硬件服务层提供稳定的灯控制能力接口,包括获取灯类型、配置点灯模式、配置灯闪烁效果、点灯、熄灯等。Light驱动模型流程:

    以标准系统RK3568为例,介绍Light模块驱动加载及运行流程:

  1. Device Manager从device_info.hcs配置文件中读取Light设备管理配置信息。
  2. Device Manager从light_config.hcs配置文件中读取Light数据配置信息。
  3. HCS Parser解析Light设备管理配置信息,加载对应的Light Host,并控制Host完成驱动的加载。
  4. Light Proxy获取到Light HDI接口服务实例后,通过IPC(Inter-Process Communication)调用到Light Stub。
  5. Light Stub主要处理与IPC相关的业务逻辑,完成参数反序列化后调用Light Controller。
  6. Light Controller中是HDI接口的真正实现,通过IPC调用Light抽象驱动接口,进一步操作Light硬件设备。

思考总结

  • HDF最核心几大块:配置管理,驱动管理,对外服务,消息机制
  • 对外接口侧重于服务,消息,而不是设备节点,这个是很大的一个转变

那么要想成为一名鸿蒙高级开发,以上知识点是必须要掌握的,除此之外,还需要掌握一些鸿蒙应用开发相关的一些技术,需要我们共同去探索。

为了节省大家一些查找的时间,这边联合几位行业大佬,为大家准备了一份《OpenHarmony4.0&Next》的学习导图从入门到进阶再到南北向开发实战的一整套完整体系,想要学习了解更多鸿蒙开发的相关知识可以借鉴:《做鸿蒙应用开发到底学习些啥?》

除了上面整理的思维导图以外,这里还特别整理的一份《鸿蒙 (Harmony OS)开发学习手册》给大家进行参考学习:

一、入门必看

1. 应用开发导读(ArkTS)

2. ……

二、HarmonyOS 概念

1. 系统定义

2. 技术架构

3. 技术特性

4. 系统安全

5........

三、如何快速入门?《鸿蒙基础入门开发宝典!》

1. 基本概念

2. 构建第一个ArkTS应用

3. 构建第一个JS应用

4. ……

四、开发基础知识

1. 应用基础知识

2. 配置文件

3. 应用数据管理

4. 应用安全管理

5. 应用隐私保护

6. 三方应用调用管控机制

7. 资源分类与访问

8. 学习ArkTS语言

9. ……

五、基于ArkTS 开发

1. Ability开发

2. UI开发

3. 公共事件与通知

4. 窗口管理

5. 媒体

6. 安全

7. 网络与链接

8. 电话服务

9. 数据管理

10. 后台任务(Background Task)管理

11. 设备管理

12. 设备使用信息统计

13. DFX

14. 国际化开发

15. 折叠屏系列

16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙开发学习指南》