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

news/2024/7/21 10:25:09 标签: linux, harmonyos, 鸿蒙, android, 鸿蒙系统, OpenHarmony, 华为

一、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多媒体技术

  • 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学习资料

总结

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


http://www.niftyadmin.cn/n/5465113.html

相关文章

力扣热题100_链表_142_环形链表 II

文章目录 题目链接解题思路解题代码 题目链接 142. 环形链表 II 给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中…

linux自动化运维之ansible实战

ansible基础介绍 优点 - 相比于saltatack和puppet,没有客户端,更轻量级 - 只是一个工具,可以很容易实现分布式拓展 - 更强的远程执行命令 特点 - 模块化 - 支持自定义模块,可以用任何语言编写模块 - 基于python语言实现 - 部署简单…

蓝桥杯速成5-AD/DA模数转换

一、原理图 上图可知该芯片使用的是iic时序,而不是51单片机的xpt2046时序,iic我们都很熟悉了吧 并且大赛还提供了我们iic底层驱动代码 左上角有AIN0-4四个转换输入通道,和AOUT一个输出通道,由控制字节选择 地址字节:0x…

Linux shell编程学习笔记45:uname命令-获取Linux系统信息

0 前言 linux 有多个发行版本,不同的版本都有自己的版本号。 如何知道自己使用的Linux的系统信息呢? 使用uname命令、hostnamectl命令,或者通过查看/proc/version文件来了解这些信息。 我们先看看uname命令。 1 uname 命令的功能和格式 …

用 Wireshark 解码 H.264

H264,你不知道的小技巧-腾讯云开发者社区-腾讯云 这篇文章写的非常好 这里仅做几点补充 init.lua内容: -- Set enable_lua to false to disable Lua support. enable_lua trueif not enable_lua thenreturn end-- If false and Wireshark was start…

用python,将有道词典中的生词导入扇贝单词

我试过有道词典和扇贝单词,个人感觉扇贝单词记忆功能非常好用,但是扇贝单词没有pc版,而有道在这方面就做的很好。博主平时都是用有道查生词,那有没有办法将有道词典中的生词导入扇贝中呢?下面的过程看上去很复杂&#…

【C语言】InfiniBand内核驱动_mlx4_ib_post_send

一、注释 以下是_mlx4_ib_post_send函数的注释,该函数用于处理InfiniBand工作请求(WRs)的发送过程: static int _mlx4_ib_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,const struct ib_send_wr **bad_wr, bool …

宝塔 docker 安装 rabbitmq

点击宝塔目录docker 拉取镜像 docker pull rabbitmq:management创建rabbitmq容器 docker run -d --name rabbit -e RABBITMQ_DEFAULT_USERadmin -e RABBITMQ_DEFAULT_PASSadmin -p 15672:15672 -p 5672:5672 -p 25672:25672 -p 61613:61613 -p 1883:1883 rabbitmq:managemen…