概述
最近HarmonyOS 2.0Beta出来了,大家伙看了界面,很多人说这不就是Android,尤其是头条上一些人;大家都知道Android是基于Linux内核开发的,HarmonyOS是全新微内核(官方说法,具体啥意思不做探究),下面我们就拿linux驱动和HarmonyOS驱动做个对比,看看到底是不是套用!
驱动概述
HarmonyOS Driver Foundation
HDF(HarmonyOS Driver Foundation)驱动框架,为驱动开发者提供驱动框架能力,包括驱动加载、驱动服务管理和驱动消息机制。旨在构建统一的驱动架构平台,为驱动开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
概念性的东西,看不出啥来
驱动加载
HDF驱动加载包括按需加载和按序加载。
- 按需加载HDF框架支持驱动在系统启动过程中默认加载,或者在系统启动之后动态加载。
- 按序加载HDF框架支持驱动在系统启动的过程中按照驱动的优先级进行加载。
linux中也可以动态加载驱动模块,也可以设置优先级
驱动服务管理
HDF框架可以集中管理驱动服务,开发者可直接通过HDF框架对外提供的能力接口获取驱动相关的服务。
驱动消息机制
HDF框架提供统一的驱动消息机制,支持用户态应用向内核态驱动发送消息,也支持内核态驱动向用户态应用发送消息。
驱动模型介绍
HDF框架以组件化的驱动模型作为核心设计思路,为开发者提供更精细化的驱动管理,让驱动开发和部署更加规范。HDF框架将一类设备驱动放在同一个host里面,开发者也可以将驱动功能分层独立开发和部署,支持一个驱动多个node,HDF框架管理驱动模型如下图所示:
上面这些概念分别都可以在linux中找到对应的概念或者说法
概念上看不出来,下面我们就看具体代码
驱动开发步骤示例
基于HDF框架进行驱动的开发主要分为两个部分,驱动实现和驱动配置,详细开发流程如下所示:
- 驱动实现
驱动实现包含驱动业务代码和驱动入口注册,具体写法如下: 驱动业务代码
#include "hdf_device_desc.h" // HDF框架对驱动开放相关能力接口的头文件#include "hdf_log.h" // HDF 框架提供的日志接口头文件 #define HDF_LOG_TAG sample_driver // 打印日志所包含的标签,如果不定义则用默认定义的HDF_TAG标签 //驱动对外提供的服务能力,将相关的服务接口绑定到HDF框架int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject){ HDF_LOGD("Sample driver bind success"); return 0;} // 驱动自身业务初始的接口int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject){ HDF_LOGD("Sample driver Init success"); return 0;} // 驱动资源释放的接口void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject){ HDF_LOGD("Sample driver release success"); return;}
首先说代码风格,linux代码是这种“hdf_sample_driver_release”小写加下划线的风格,Harmony是驼峰式写法。
驱动入口注册到HDF框架
// 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量struct HdfDriverEntry g_sampleDriverEntry = { .moduleVersion = 1, .moduleName = "sample_driver", .Bind = HdfSampleDriverBind, .Init = HdfSampleDriverInit, .Release = HdfSampleDriverRelease,}; // 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。HDF_INIT(g_sampleDriverEntry);
这个注册跟下面这个linux驱动还是有些相似的,虽说条条大路通罗马,但路先让别人走了,我们再走,不能算抄袭。
// linux内核任意摘取的驱动static struct i2c_driver bd2802_i2c_driver = {.driver= {.name= "BD2802",.pm= &bd2802_pm,},.probe= bd2802_probe,.remove= bd2802_remove,.id_table= bd2802_id,};module_i2c_driver(bd2802_i2c_driver);
- 驱动编译
编译都是采用的Makefile,这个没啥好说的。
- 驱动代码的编译必须要使用HDF框架提供的Makefile模板进行编译。
include $(LITEOSTOPDIR)/../../drivers/hdf/lite/lite.mk #导入hdf预定义内容,必需MODULE_NAME := #生成的结果文件LOCAL_INCLUDE := #本驱动的头文件目录LOCAL_SRCS := #本驱动的源代码文件LOCAL_CFLAGS := #自定义的编译选项include $(HDF_DRIVER) #导入模板makefile完成编译
编译结果文件链接到内核镜像,添加到vendor目录下的hdf_vendor.mk里面,示例如下:
LITEOS_BASELIB += -lxxx #链接生成的静态库LIB_SUBDIRS += #驱动代码Makefile的目录
3.驱动配置
HDF使用HCS作为配置描述源码,HCS详细介绍参考配置管理介绍。
驱动配置包含两部分,HDF框架定义的驱动设备描述和驱动的私有配置信息,具体写法如下:
- 驱动设备描述(必选)HDF框架加载驱动所需要的信息来源于HDF框架定义的驱动设备描述,因此基于HDF框架开发的驱动必须要在HDF框架定义的device_info.hcs配置文件中添加对应的设备描述,驱动的设备描述填写如下所示:
root { device_info { match_attr = "hdf_manager"; template host { // host模板,继承该模板的节点(如下sample_host)如果使用模板中的默认值,则节点字段可以缺省 hostName = ""; priority = 100; template device { template deviceNode { policy = 0; priority = 100; preload = 0; permission = 0664; moduleName = ""; serviceName = ""; deviceMatchAttr = ""; } } } sample_host :: host{ hostName = "host0"; // host名称,host节点是用来存放某一类驱动的容器 priority = 100; // host启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证host的加载顺序 device_sample :: device { // sample设备节点 device0 :: deviceNode { // sample驱动的DeviceNode节点 policy = 1; // policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍 priority = 100; // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序 preload = 0; // 驱动按需加载字段,在本章节最后的说明有详细介绍 permission = 0664; // 驱动创建设备节点权限 moduleName = "sample_driver"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 serviceName = "sample_service"; // 驱动对外发布服务的名称,必须唯一 deviceMatchAttr = "sample_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 } } } }}
下面这个是任意摘录自linux源码
dw-apb-gpio@2000 {compatible = "snps,dw-apb-gpio";reg = < 0x2000 0x80 >;#address-cells = <1>;#size-cells = <0>;ictl_intc: gpio-controller@0 {compatible = "snps,dw-apb-gpio-port";gpio-controller;#gpio-cells = <2>;snps,nr-gpios = <30>;reg = <0>;interrupt-controller;#interrupt-cells = <2>;interrupt-parent = ;interrupts = <25>;};};
无论是概念思路还是代码风格都跟Linux的设备树(DeviceTree)似乎异曲同工;虽说条条大路通罗马,但路先让别人走了,我们再走,不能算抄袭。
驱动私有配置信息(可选)
如果驱动有私有配置,则可以添加一个驱动的配置文件,用来填写一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考驱动开发)传递给驱动,驱动的配置信息示例如下:
root { SampleDriverConfig { sample_version = 1; sample_bus = "I2C_0"; match_attr = "sample_config"; //该字段的值必须和device_info.hcs中的deviceMatchAttr值一致 }}
>linux设备树中似乎没这个概念
配置信息定义之后,需要将该配置文件添加到板级配置入口文件hdf.hcs(这一块可以通过HarmonyOS驱动子系统在DevEco集成驱动开发套件工具一键式配置,具体使用方法参考驱动开发套件中的介绍),示例如下:
#include "device_info/device_info.hcs"#include "sample/sample_config.hcs"
驱动服务管理
驱动服务是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;
这个地方,嗯,似乎LINUX没有这个概念,更像IOT中的一些通信协议比如MQTT中的一些概念,放在操作系统中是比较新的概念,就像华为说的物联网操作系统。
使用场景
当驱动以接口的形式对外提供能力时,可以使用HDF框架的驱动服务管理能力。
接口说明
针对驱动服务管理功能,HDF框架开放了以下接口供开发者调用,如下表所示:
开发步骤
驱动服务管理的开发包括驱动服务的编写、绑定、获取或者订阅,详细步骤如下。
- 驱动服务发布
驱动服务结构的定义struct ISampleDriverService { struct IDeviceIoService ioService; // 服务结构的首个成员必须是IDeviceIoService类型的成员 int32_t (*ServiceA)(void); // 驱动的第一个服务接口 int32_t (*ServiceB)(uint32_t inputCode); // 驱动的第二个服务接口,有多个可以依次往下累加}; 驱动服务接口的实现int32_t SampleDriverServiceA(void){ // 驱动开发者实现业务逻辑 return 0;} int32_t SampleDriverServiceB(uint32_t inputCode){ // 驱动开发者实现业务逻辑 return 0;}
驱动服务绑定到HDF框架中,实现HdfDriverEntry中的Bind指针函数。
int32_t SampleDriverBind(struct HdfDeviceObject *deviceObject){ // deviceObject为HDF框架给每一个驱动创建的设备对象,用来保存设备相关的私有数据和服务接口 if (deviceObject == NULL) { HDF_LOGE("Sample device object is null!"); return -1; } static struct ISampleDriverService sampleDriverA = { .ServiceA = SampleDriverServiceA, .ServiceB = SampleDriverServiceB, }; deviceObject->service = &sampleDriverA.ioService; return 0;}
驱动服务获取。
驱动服务的获取有两种方式,HDF框架提供接口直接获取和HDF框架提供订阅机制获取。
- 通过HDF接口直接获取当明确驱动已经加载完成时,获取该驱动的服务可以通过HDF框架提供的能力接口直接获取,如下所示:
const struct ISampleDriverService *sampleService = (const struct ISampleDriverService *)DevSvcManagerClntGetService("sample_driver");if (sampleService == NULL) { return -1;}sampleService->ServiceA();sampleService->ServiceB(5);
通过HDF提供的订阅机制获取
当对驱动(同一个host)加载的时机不感知时,可以通过HDF框架提供的订阅机制来订阅该驱动,当该驱动加载完成时,HDF框架会将被订阅的驱动服务发布给订阅者,实现方式如下所示:
// 订阅回调函数的编写,当被订阅的驱动加载完成后,HDF框架会将被订阅驱动的服务发布给订阅者,通过这个回调函数给订阅者使用// object为订阅者的私有数据,service为被订阅的服务对象int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service){ const struct ISampleDriverService *sampleService = (const struct ISampleDriverService *)service; if (sampleService == NULL) { return -1; } sampleService->ServiceA(); sampleService->ServiceB(5);}// 订阅过程的实现int32_t TestDriverInit(struct HdfDeviceObject *deviceObject){ if (deviceObject == NULL) { HDF_LOGE("Test driver init failed, deviceObject is null!"); return -1; } struct SubscriberCallback callBack; callBack.deviceObject = deviceObject; callBack.OnServiceConnected = TestDriverSubCallBack; int32_t ret = HdfDeviceSubscribeService(deviceObject, "sample_driver", callBack); if (ret != 0) { HDF_LOGE("Test driver subscribe sample driver failed!"); } return ret;}
驱动消息机制管理
使用场景
当用户态应用和内核态驱动需要交互时,可以使用HDF框架的消息机制来实现。
接口说明
消息机制的功能主要有以下两种:
- 用户态应用发送消息到驱动。
- 用户态应用接收驱动主动上报事件。
开发步骤
- 将驱动配置信息中服务策略policy字段设置为2(SERVICE_POLICY_CAPACITY,参考policy定义)。
device_sample :: Device { policy = 2; ...}
- 配置驱动信息中的服务设备节点权限(permission字段)是框架给驱动创建设备节点的权限,默认是0666,驱动开发者根据驱动的实际使用场景配置驱动设备节点的权限。
- 在服务实现过程中,实现服务基类成员IDeviceIoService中的Dispatch方法。
// Dispatch是用来处理用户态发下来的消息int32_t SampleDriverDispatch(struct HdfDeviceObject *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply){ HDF_LOGE("sample driver lite A dispatch"); return 0;}int32_t SampleDriverBind(struct HdfDeviceObject *device){ HDF_LOGE("test for lite os sample driver A Open!"); if (device == NULL) { HDF_LOGE("test for lite os sample driver A Open failed!"); return -1; } static struct ISampleDriverService sampleDriverA = { .ioService.Dispatch = SampleDriverDispatch, .ServiceA = SampleDriverServiceA, .ServiceB = SampleDriverServiceB, }; device->service = (struct IDeviceIoService *)(&sampleDriverA); return 0;}
- 驱动定义消息处理函数中的cmd类型。
#define SAMPLE_WRITE_READ 1 // 读写操作码1
- 用户态获取服务接口并发送消息到驱动。
int SendMsg(const char *testMsg){ if (testMsg == NULL) { HDF_LOGE("test msg is null"); return -1; } struct HdfIoService *serv = HdfIoServiceBind("sample_driver", 0); if (serv == NULL) { HDF_LOGE("fail to get service"); return -1; } struct HdfSBuf *data = HdfSBufObtainDefaultSize(); if (data == NULL) { HDF_LOGE("fail to obtain sbuf data"); return -1; } struct HdfSBuf *reply = HdfSBufObtainDefaultSize(); if (reply == NULL) { HDF_LOGE("fail to obtain sbuf reply"); ret = HDF_DEV_ERR_NO_MEMORY; goto out; } if (!HdfSbufWriteString(data, testMsg)) { HDF_LOGE("fail to write sbuf"); ret = HDF_FAILURE; goto out; } int ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply); if (ret != HDF_SUCCESS) { HDF_LOGE("fail to send service call"); goto out; }out: HdfSBufRecycle(data); HdfSBufRecycle(reply); HdfIoServiceRecycle(serv); return ret;}
- 用户态接收该驱动上报的消息。
a.用户态编写驱动上报消息的处理函数。
static int OnDevEventReceived(void *priv, uint32_t id, struct HdfSBuf *data){ OsalTimespec time; OsalGetTime(&time); HDF_LOGE("%s received event at %llu.%llu", (char *)priv, time.sec, time.usec); const char *string = HdfSbufReadString(data); if (string == NULL) { HDF_LOGE("fail to read string in event data"); return -1; } HDF_LOGE("%s: dev event received: %d %s", (char *)priv, id, string); return 0;}
b.用户态注册接收驱动上报消息的操作方法。
int RegisterListen(){ struct HdfIoService *serv = HdfIoServiceBind("sample_driver", 0); if (serv == NULL) { HDF_LOGE("fail to get service"); return -1; } static struct HdfDevEventlistener listener = { .callBack = OnDevEventReceived, .priv ="Service0" }; if (HdfDeviceRegisterEventListener(serv, &listener) != 0) { HDF_LOGE("fail to register event listener"); return -1; } ...... HdfDeviceUnregisterEventListener(serv, &listener); HdfIoServiceRecycle(serv); return 0;}
c.驱动上报事件
int32_t SampleDriverDispatch(struct HdfDeviceObject *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply){ ... // process api call here return HdfDeviceSendEvent(deviceObject, cmdCode, data);}
从驱动的服务管理、消息机制管理可以看出跟Linux驱动是截然不同的。
至于配置管理和Linux驱动中的设备树极为相似,以及内核中的shell、adb、api接口的名字相似等,我觉得这个说明不了什么,毕竟linux几十年了,有些比较先进的理念,我们采用了不能说我们就套用了。还是那句话,条条大路通罗马,人家选择一条好的路先走了,我们不能为了避嫌故意选择一条差的路吧。你们说呢?
最后
以上就是强健樱桃为你收集整理的android usb device host 切换_从Harmony驱动架构来看是不是套用Android驱动概述HarmonyOS Driver Foundation驱动加载驱动服务管理驱动消息机制驱动模型介绍驱动开发步骤示例驱动服务管理使用场景接口说明开发步骤驱动消息机制管理使用场景接口说明开发步骤的全部内容,希望文章能够帮你解决android usb device host 切换_从Harmony驱动架构来看是不是套用Android驱动概述HarmonyOS Driver Foundation驱动加载驱动服务管理驱动消息机制驱动模型介绍驱动开发步骤示例驱动服务管理使用场景接口说明开发步骤驱动消息机制管理使用场景接口说明开发步骤所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复