OpenHarmony实战:硬件适配之HCS应用

一、HCS 配置管理

HCS(HDF Configuration Source)是 HDF 驱动框架的配置描述参数文件,内容以 Key-Value 为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。 HC-GEN(HDF Configuration Generator)是 HCS 配置转换工具,可以将 HDF 配置文件转换为软件可读取的文件格式。本文不涉及 HC-GEN,假设我们配置好 HCS, 利用其给定的接口可以访问对应设备节点的参数。

HCS 和硬件板卡直接相关,服务于 HDF 驱动框架。下面以一个模拟耳机插拔检测的驱动程序为例,从开发的角度逐步展开说明。

二、应用举例

第一步,找到 HDF 系统相关总入口 hdf.hcs 文件,在 audio 位置新增加 audio/analog_headset_config.hcs 参数文件,系统在加载的时候会读取该参数文件。

.\vendor\hihope\rk3568\hdf_config\khdf\hdf.hcs

#include "device_info/device_info.hcs"
......
#include "audio/audio_config.hcs"
#include "audio/codec_config.hcs"
#include "audio/dai_config.hcs"
#include "audio/dma_config.hcs"
#include "audio/dsp_config.hcs"
#include "audio/analog_headset_config.hcs" // 新增加文件
......
#include "lcd/lcd_config.hcs"

root {
    module = "rockchip,rk3568_chip";
}

第二步,新增加的文件放到对应子模块的目录下

headset_info 就是耳机插拔检测用到的硬件信息,关键是 headset_gpio

.\vendor\hihope\rk3568\hdf_config\khdf\audio\analog_headset_config.hcs
root {
    platform {
        template headset_info {
            match_attr = "";
            serviceName = "";
        }
        headset :: headset_info {
            match_attr = "analog_headset_attr";
            serviceName = "analog_headset_service";
            vendor = 0x0001;
            product = 0x0001;
            version = 0x0100;
            dev_name = "rk809_analog_headset";
            headset_gpio = 115;
            headset_gpio_flag = 0;
            mic_switch_gpio = 0;
            hp_mic_io_value = 0;
            main_mic_io_value = 1;
            headset_wakeup = 1;
            hook_gpio = 0;
            adc_controller_no = 0;
            adc_channel = 0;
            hook_down_type = 0;
        }
    }
}

第三步,这个功能需要在 audio 关键模块加载之后加载

在 device_info.hcs 中找到 audio::host 主机节点,配置好服务策略、优先级、加载策略(按时还是按需)、模块名称为驱动加载的名称,服务名称则指向 analog_headset_config.hcs 中的服务名称。模块名称错误驱动程序将不会被加载,服务名称错误则读取参数失败,可能导致驱动程序异常。
关于服务策略、优先级、加载策略在后面描述。

.\vendor\hihope\rk3568\hdf_config\khdf\device_info\device_info.hcs
audio :: host {
    hostName = "audio_host";
    priority = 110;
    device_dai :: device {
        device_primary :: deviceNode {
            policy = 1;
            priority = 50;
            preload = 0;
            permission = 0666;
            moduleName = "DAI_RK3568";
            serviceName = "dai_service";
            deviceMatchAttr = "hdf_dai_driver";
        }
        device_hdmi :: deviceNode {
            policy = 1;
            priority = 50;
            preload = 0;
            permission = 0666;
            moduleName = "DAI_RK3568";
            serviceName = "hdmi_dai_service";
            deviceMatchAttr = "hdf_hdmi_dai_driver";
        }
    }        
    ......
    // 以下为新增加部分
    device_analog_headset :: device {
        device0 :: deviceNode {
            policy = 1;
            priority = 90;
            preload = 0;
            permission = 0666;
            moduleName = "AUDIO_ANALOG_HEADSET";
            serviceName = "analog_headset_service";
            deviceMatchAttr = "analog_headset_attr";
        }
    }
}

第四步,驱动程序通过 HDF_INIT 宏,在系统启动时完成设备与服务的绑定,关键就是这个模块名称,找到这个模块名称后,进而去初始化硬件。

.\device\board\hihope\rk3568\audio_drivers\headset_monitor\src\analog_headset_core.c

/* HdfDriverEntry definitions */
struct HdfDriverEntry g_headsetDevEntry = {
    .moduleVersion = 1,
    .moduleName = "AUDIO_ANALOG_HEADSET",
    .Bind = HdfHeadsetBindDriver,
    .Init = HdfHeadsetInit,
    .Release = HdfHeadsetExit,
};
HDF_INIT(g_headsetDevEntry);

第五步,初始硬件时,务必先读取必要的 HCS 硬件信息

static int32_t HdfHeadsetInit(struct HdfDeviceObject *device)
{
    const struct DeviceResourceNode *node = NULL;
    static struct HeadsetPdata pdata;
    ......
    node = device->property;
    ret = ReadConfig(node, &pdata);   
    ......
    return HDF_SUCCESS;
}

第六步,调用 device_resource_if.h 中对外的接口函数,根据名称读取所有信息到 pdata

#include "device_resource_if.h"
static int32_t ReadConfig(const struct DeviceResourceNode *node, struct HeadsetPdata *pdata)
{
    int32_t ret;
    int32_t temp;
    struct DeviceResourceIface *parser = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
    ret = parser->GetString(node, "dev_name", &pdata->devName, NULL);  
    ret = parser->GetUint32(node, "headset_gpio", &pdata->hsGpio, 0);   
    ret = parser->GetUint32(node, "headset_gpio_flag", &pdata->hsGpioFlag, OF_GPIO_ACTIVE_LOW); 
    ret = ReadHookModeConfig(parser, node, pdata); 
    (void)ReadMicConfig(parser, node, pdata);
    ret = parser->GetUint32(node, "headset_wakeup", &temp, 0); 
    return HDF_SUCCESS;
}

第七步,驱动编写完成后,需要就近修改 Makefile 中要编译的驱动源文件

.\device\board\hihope\rk3568\audio_drivers\Makefile

obj-$(CONFIG_DRIVERS_HDF_AUDIO_ANA_HEADSET) += \
        headset_monitor/src/analog_headset_base.o \
        headset_monitor/src/analog_headset_core.o \
        headset_monitor/src/analog_headset_gpio.o \
        headset_monitor/src/analog_headset_adc.o

ccflags-$(CONFIG_DRIVERS_HDF_AUDIO_ANA_HEADSET) += \
        -I$(srctree)/$(KHDF_FRAMEWORK_ROOT_DIR)/model/input/driver \
        -I$(srctree)/drivers/hdf/evdev \
        -I$(srctree)/$(KHDF_AUDIO_RK3568_INC_DIR)/headset_monitor/include

第八步,这个属于通用功能,板卡支持与否,需要在 Kconfig 文件配置 CONFIG_DRIVERS_HDF_AUDIO_ANA_HEADSET 来决定是否编译以上文件。

三、 device_resource_if.h 接口定义

在驱动实现中,使用 device_resource_if.h 中定义的接口对配置进行查询和读取,所在目录.\drivers\hdf_core\interfaces\inner_api\utils\device_resource_if.h。常用 API 介绍如下:

四、HDF 关键点说明

HDF(Hardware Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理、驱动消息机制和配置管理。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。

4.1. HDF 驱动模型

HDF 框架将一类设备驱动放在同一个 Host 里面,开发者也可以将 Host 中的驱动功能分层独立开发和部署,支持一个驱动多个 Node,HDF 驱动模型如下图所示:

开发者应当将同一类的设备放在同一个 Host 里面,在新增设备时,检查是否已经存在同类型的 Host。如果已存在 Host,则将 Device 配置在此 Host 中,禁止重复配置 Host。一个驱动设备应该只属于一类驱动类型,因此也禁止将同一个 Device 配置在不同 Host 当中。

4.2. 发布策略

驱动服务必须按照业务规则设置对外发布的策略,禁止设置不必要的发布策略。驱动服务是 HDF 驱动设备对外提供能力的对象,由 HDF 框架统一管理。HDF 框架定义了驱动对外发布服务的策略,是由配置文件中的 policy 字段来控制,policy 字段的取值范围以及含义如下:

typedef enum {
    /* 驱动不提供服务 */
    SERVICE_POLICY_NONE = 0,
    /* 驱动对内核态发布服务 */
    SERVICE_POLICY_PUBLIC = 1,
    /* 驱动对内核态和用户态都发布服务 */
    SERVICE_POLICY_CAPACITY = 2,
    /* 驱动服务不对外发布服务,但可以被订阅 */
    SERVICE_POLICY_FRIENDLY = 3,
    /* 驱动私有服务不对外发布服务,也不能被订阅 */
    SERVICE_POLICY_PRIVATE = 4,
    /* 错误的服务策略 */
    SERVICE_POLICY_INVALID
} ServicePolicy;

因此,驱动服务应该按照业务规则来设置发布策略,禁止设置不必要的发布策略,如内核态驱动设置用户态的发布策略。

4.3. 加载时机

HDF 驱动加载包括按需加载和按序加载。
按需加载:HDF 框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载。
按序加载:HDF 框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。

五、总结

HDF 框架结构庞杂,意义深远,值得每个底层开发者不断探索和改善。HCS 仅仅是其中一个功能点,此文旨在抛砖引玉,深层了解还需要阅读专业文档和源码。

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(HarmonyOS NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

相关推荐

  1. 应用数据库还是数据库应用

    2024-04-02 08:42:01       41 阅读
  2. Flutter 屏幕相对尺寸

    2024-04-02 08:42:01       24 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-02 08:42:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-02 08:42:01       18 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-02 08:42:01       17 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-02 08:42:01       20 阅读

热门阅读

  1. 如何重置woocommerce,如何批量删除woocommerce产品

    2024-04-02 08:42:01       12 阅读
  2. StarRocks部署

    2024-04-02 08:42:01       11 阅读
  3. WPF —— 动画

    2024-04-02 08:42:01       13 阅读
  4. react 父子组件的渲染机制 | 优化手段

    2024-04-02 08:42:01       14 阅读
  5. leetcode76最后一个测试用例无法通过

    2024-04-02 08:42:01       13 阅读
  6. SeLinux安全上下文文件

    2024-04-02 08:42:01       13 阅读
  7. C语言函数如何将数组元素作为实参?

    2024-04-02 08:42:01       15 阅读
  8. InitializingBean是什么以及如何使用?

    2024-04-02 08:42:01       15 阅读
  9. Sentinel 的QPS限流和Redis流量风控

    2024-04-02 08:42:01       13 阅读