当前位置: 首页 > 科技观察

HDF驱动开发流程分析

时间:2023-03-13 06:19:52 科技观察

了解更多开源请访问:开源基础软件社区https://ost.51cto.com前言在上一节中,我们通过DevEcoDeviceTool生成了一个标准的HDF框架。接下来,我们将使用生成的模板深入研究HDF驱动开发。本次使用Hi3516DV300开发板,搭建LiteOS内核和Linux内核两个版本为例,深入了解HDF驱动开发过程,对比Linux内核和LiteOS内核HDF驱动的异同发展。参考文章HDF开发过程可以参考下面的文章。驱动开发。示例代码由DevEcoDeviceTool生成。代码和结构比较规范。你可以参考下面的文章。DevEcoDeviceTool:一键生成HDF框架!前提准备本测试示例使用OpenHarmony3.1版本完整代码下配置的两个工程,一个是LiteOS内核的小系统,一个是Linux内核的小系统,HDF框架参考前面生成文章。生成的文件包括BUILD.gn、Kconfig、MakeFile、hcs、c/c++编译、驱动代码等,点击跳转到对应文件。Linux内核与LiteOS内核存在一些差异,主要体现在驱动编译上。HDF驱动开发步骤基于HDF框架的驱动开发主要分为三个部分:驱动实现、驱动编译和驱动配置。1.驱动实现驱动实现包括驱动业务代码实现和驱动入口注册。具体写法如下:#include"hdf_device_desc.h"//HDF框架驱动开发相关能力的头文件#include"hdf_log.h"//HDF框架提供的日志接口头文件#defineHDF_LOG_TAG"sample_driver"//打印日志包含的标签,如果没有定义,使用默认的HDF_TAG标签。//驱动对外提供的服务能力,将相关服务接口绑定到HDF框架。int32_tHdfSampleDriverBind(structHdfDeviceObject*deviceObject){HDF_LOGD("示例驱动绑定成功");return0;}//驱动自身业务初始化的接口int32_tHdfSampleDriverInit(structHdfDeviceObject*deviceObject){HDF_LOGD("SampledriverInit;success")return0;}//驱动资源释放接口voidHdfSampleDriverRelease(structHdfDeviceObject*deviceObject){HDF_LOGD("示例驱动发布成功");return;}驱动程序条目已注册到HDF框架。//定义驱动入口的对象必须是HdfDriverEntry类型的全局变量(在hdf_device_desc.h中定义)。structHdfDriverEntryg_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);工具生成的驱动代码位置在drivers/framework/model。我们通过DevecoDeviceToolgeneration添加了一个LiteOS测试驱动程序(hello_liteos)和一个Linux内核测试驱动程序(hello_linux)。自动生成驱动业务代码和将驱动入口注册到HDF框架的模板。为了区分后面两个内核的驱动实现结果,我修改了驱动的初始化Init函数。Liteos内核驱动程序实现打印“HelloLiteOS”日志。Linux内核的驱动打印“HelloLinux”日志,但实际测试结果显示Liteos内核的Hilog有问题,显示缓冲区已满。尝试增加buffer也解决不了,于是加入了Liteos内核驱动实现让绿色LED等常亮,Linux内核的驱动可以让红外灯常亮来区分。查询原理图可知:绿色LED为GPIO2_3引脚,转换后的引脚数为2×8+3=19。(Hi3516组GPIO包含8个管脚),输出高电平点亮。红外LED为GPIO,为GPIO5_1引脚,换算成引脚数为5×8+1=41,输出高电平点亮。这样,我们就可以修改我们的驱动代码了。注意需要包含#include"gpio_if.h"头文件来控制GPIO。修改后的代码如下。//初始化驱动程序service.staticint32_tHdfHelloLiteosDriverInit(structHdfDeviceObject*deviceObject){HDF_LOGI("HelloLiteOS");GpioSetDir(19,GPIO_DIR_OUT);//设置管脚为输出GpioWrite(19,GPIO_VAL_HIGH);//输出高电平,绿色LED在return0;}//初始化驱动服务.staticint32_tHdfHelloLinuxDriverInit(structHdfDeviceObject*deviceObject){HDF_LOGI("你好Linux");GpioSetDir(41,GPIO_DIR_OUT);//引脚设置为输出GpioWrite(41,GPIO_VAL_HIGH);//输出高电平,红外灯亮返回0;}二、驱动编译创建驱动代码后,必须加入OpenHarmony构建系统,LiteOS内核和Linux内核的编译配置过程会有所不同。LiteOS内核驱动编译涉及到Makefile和BUILD.gn修改:可以看到在drivers/adapter/khdf/liteos/model中增加了hello_liteos目录用来存放驱动编译规则代码,新增了BUILD.gn和Makefile文件,Kconfig在目录下创建的File文件不参与驱动编译,暂不考虑。MakeFile驱动代码的编译必须使用HDF框架提供的Makefile模板进行编译。在新建的MakeFile文件中创建如下代码生成编译结构文件,即生成MODULE_NAME对应的静态库。包含$(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk#导入hdf预定义内容HELLO_LITEOS_ROOT_DIR=$(LITEOSTOPDIR)/../../drivers/framework/model/hello_liteosifeq((LOSCFG_DRIVERS_HDF_HELLO_LITEOS),y)MODULE_NAME:=hdf_hello_liteos_driver#生成的结果文件LOCAL_INCLUDE:=$(HELLO_LITEOS_ROOT_DIR)/../../../../../third_party/FreeBSD/sys/dev/evdev#thisDriver'sheader文件目录LOCAL_SRCS+=$(HELLO_LITEOS_ROOT_DIR)/driver/hello_liteos_driver.c#驱动源码文件endifinclude$(HDF_DRIVER)#导入Makefile模板完成编译,编译结果在drivers/adapter/khdf/liteos/hdf_lite。mk文件链接到内核映像。ifeq($(LOSCFG_DRIVERS_HDF_HELLO_LITEOS),y)LITEOS_BASELIB+=-lhdf_hello_liteos_driver#链接生成静态库LIB_SUBDIRS+=$(LITEOS_DRIVERS_HDF)/model/hello_liteos#驱动代码Makefile目录endif编译过程关系如下:BUILD.gn部分:newAddmoduleBUILD.gn代码如下:import("//drivers/adapter/khdf/liteos/hdf.gni")module_switch=defined(LOSCFG_DRIVERS_HDF_HELLO_LITEOS)module_name="hdf_hello_liteos_driver"#modulenamehdf_driver(module_name){FRAMEWORKS_HELLO_LITEOS"/model/hello_liteos"#模块要编译的源代码文件sources=["$FRAMEWORKS_HELLO_LITEOS_ROOT/driver/hello_liteos_driver.c"]#依赖头文件目录include_dirs=["//third_party/FreeBSD/sys/dev/evdev/"]}将新模块的BUILD.gn所在目录添加到/drivers/adapter/khdf/liteos/BUILD.gn:由于生成的代码在model模块下,所以model已经添加编译到/drivers/适配器/khdf/liteos/BUILd.gn,所以我们只需要在model层下的BUILD.gn下添加模块,即在drivers/adapter/khdf/liteos/model/BUILD.gn中的modules中添加hello_liteos模块。import("//drivers/adapter/khdf/liteos/hdf.gni")module_group("model"){modules=["audio","bus/usb","display","input","hello_liteos",//添加模块"misc/dsoftbus","misc/light","misc/vibrator","network/ethernet","network/wifi","sensor","storage","usb/device","usb/host",]}用下图来表示它们的编译依赖关系可能会更清楚。Linux内核驱动编译可以在drivers/adapter/khdf/linux/model目录下找到。新建一个hello_linux文件夹,用于存放驱动编译规则代码,并在该目录下新建一个MakeFile文件,用于编译驱动配置。Makefile部分,Makefile文件中的模块代码编译规则代码如下:\$(HELLO_LINUX_ROOT_DIR)/hello_linux_driver.o##编译hello_linux_driver.o文件ccflags-y+=-I$(srctree)/drivers/hdf/framework/include/core\-I$(srctree)/drivers/hdf/framework/核心/通用/包含/主机\-I$(srctree)/drivers/hdf/framework/include/utils\-I$(srctree)/drivers/hdf/framework/include/osal\-I$(srctree)/drivers/hdf/framework/ability/sbuf/include\-I$(srctree)/drivers/hdf/framework/include/platform\-I$(srctree)/drivers/hdf/framework/include/config\-I$(srctree)/drivers/hdf/framework/core/host/include\-I$(srctree)/drivers/hdf/framework/core/shared/include\-I$(srctree)/drivers/hdf/framework/utils/include\-I$(srctree)/drivers/hdf/khdf/osal/includeccflags-y+=-I$(srctree)/bounds_checking_function/include\-I$(srctree)/drivers/hdf/evdev添加模块目录到drivers/adapter/khdf/linux/Makefile:obj-$(CONFIG_DRIVERS_HDF)+=manager/obj-$(CONFIG_DRIVERS_HDF_PLATFORM)+=平台/obj-$(CONFIG_DRIVERS_HDF_DISP)+=模型/显示/obj-$(CONFIG_DRIVERS_HDF_INPUT)+=模型/输入/obj-$(CONFIG_DRIVERS_HDF_WIFI)+=模型/网络/wifi/obj-$(CONFIG_DRIVERS_HDF_USB_PNP_NOTIFY)+=model/usb/host/obj-$(CONFIG_DRIVERS_HDF_USB_F_GENERIC)+=model/usb/device/obj-$(CONFIG_DRIVERS_HDF_SENSOR)+=model/sensor/obj-$(CONFIG_DRIVERS_HDF_STORAGE/model)+=对象-$(CONFIG_DRIVERS_HDF_BT)+=model/network/bluetooth/obj-$(CONFIG_DRIVERS_HDF_LIGHT)+=model/misc/light/obj-$(CONFIG_DRIVERS_HDF_VIBRATOR)+=model/misc/vibrator/obj-$(CONFIG_DRIVERS_HDF_AUDIO)+=模型/audio/obj-$(CONFIG_DRIVERS_HDF_DSOFTBUS)+=model/misc/dsoftbus/obj-$(CONFIG_DRIVERS_HDF_HELLO_LINUX)+=model/hello_linux/#新添加模块dir编译过程的关系ectory如下:Kconfig(optional)如果需要定义模块控制宏,也可以可以配置Kconfig,在工具生成的文件中可以找到Kconfig可视化配置文件。该功能基于Kconfiglib和Kconfig实现,方便用户对OpenHarmony产品子系统组件进行个性化配置。基于Kconfig的可视化配置功能具有以下优点:可以直观、全面地展示软件的组件选项。可靠性强,如Linux-kernel、buildroot等知名软件均采用Kconfig进行可视化配置。目前这个功能对我用处不大,也没有深入研究。对HDF驱动的编译配置没有影响,不需要配置。如果你有兴趣,可以看看下面的指南进行学习。编译构建Kconfig可视化配置指南。3、驱动配置驱动设备描述HDF框架加载驱动所需的信息来自于HDF框架定义的驱动设备描述,所以在vendor/hisilicon/hispark_taurus(_linux)/hdf_config/device_info下添加单独的驱动设备描述/device_info.hcs,模板如下:sample_host::host{hostName="host0";//主机名,主机节点是用来存放某类驱动的容器。优先级=100;//主机启动优先级(0-200),值越大优先级越低,建议默认配置100,相同优先级不保证主机的加载顺序。caps=["DAC_OVERRIDE","DAC_READ_SEARCH"];//用户态处理Linux能力配置。device_sample::device{//样本设备节点device0::deviceNode{//样本驱动的DeviceNode节点policy=1;//policy字段是驱动服务发布的策略,在驱动服务管理章节有详细介绍。优先级=100;//驱动启动优先级(0-200),值越大优先级越低。建议默认设置为100。如果优先级相同,则无法保证设备的加载顺序。预载=0;//驱动按需加载字段,本章末尾有详细介绍。许可=0664;//为驱动创建设备节点的权限moduleName="sample_driver";//驱动名称,该字段的值必须与驱动入口结构的moduleName值一致。serviceName="sample_service";//驱动发布的服务名称必须是唯一的。deviceMatchAttr="sample_config";//驱动私有数据匹配的关键字必须等于驱动私有数据配置表中的match_attr值。DevEcoDeviceTool为我们生成了如下配置,可以根据需要修改:Driver私有配置信息(可选)从上图中我们可以看到deviceMatchAttr为空,没有为我们生成私有配置信息。如果驱动有私有配置,可以添加一个驱动配置文件,填写一些驱动默认配置信息。HDF框架在加载驱动时,会获取相应的配置信息保存在HdfDeviceObject的属性中,通过Bind和Init传递给驱动。驱动配置信息示例如下:root{SampleDriverConfig{sample_version=1;样本总线=“I2C_0”;match_attr="sample_config";//该字段的值必须与device_info.hcs中的deviceMatchAttr值一致}}配置信息定义完成后,需要在板级配置入口文件hdf.hcs中添加该配置文件(目录位于在vendor/hisilicon/hispark_taurus(_linux)/hdf_config/hdf.hcs),这里就不做配置了,下次尝试添加用户态业务代码再演示,示例如下。#include"device_info/device_info.hcs"#include"sample/sample_config.hcs"这样一来,两个核心工程分别编译、烧录、运行。结果如下:LinuxKernel:LiteOSKernel:了解更多开源请访问:开源基础软件社区https://ost.51cto.com。