# OpenHarmony HDF驱动编程规范 ## å‰è¨€ ### 目的 OpenHarmonyçš„ç›®æ ‡æ˜¯é¢å‘全场景ã€å…¨è¿žæŽ¥ã€å…¨æ™ºèƒ½æ—¶ä»£ï¼ŒåŸºäºŽå¼€æºçš„æ–¹å¼ï¼Œæå»ºä¸€ä¸ªæ™ºèƒ½ç»ˆç«¯è®¾å¤‡æ“作系统的框架和平å°ï¼Œä¿ƒè¿›ä¸‡ç‰©äº’è”产业的ç¹è£å‘展。具有“硬件互助,资æºå…±äº«â€ã€â€œä¸€æ¬¡å¼€å‘,多端部署â€ã€â€œç»Ÿä¸€OS,弹性部署â€çš„æŠ€æœ¯ç‰¹æ€§ã€‚ HDF(Hardware Driver Foundation)驱动框架,为开å‘者æä¾›é©±åŠ¨æ¡†æž¶èƒ½åŠ›ï¼ŒåŒ…æ‹¬é©±åŠ¨åŠ è½½ã€é©±åЍæœåŠ¡ç®¡ç†å’Œé©±åŠ¨æ¶ˆæ¯æœºåˆ¶ã€‚旨在构建统一的驱动架构平å°ï¼Œä¸ºå¼€å‘者æä¾›æ›´ç²¾å‡†ã€æ›´é«˜æ•ˆçš„å¼€å‘环境,力求åšåˆ°ä¸€æ¬¡å¼€å‘,多系统部署。 å› æ¤ï¼Œå¯¹åŸºäºŽHDF实现的OpenHarmony驱动代ç éœ€è¦æœ‰ä¸€å®šçš„编程规约,以满足驱动代ç 的“一次开å‘ï¼Œå¤šç«¯éƒ¨ç½²â€æŠ€æœ¯ç‰¹æ€§ã€‚æœ¬æ–‡ä»¥æ¤ä¸ºåˆè¡·ï¼Œç»“åˆOpenHarmonyå’ŒHDF的特点,拟定了相关编程规约,用于指导驱动代ç 的开å‘ç¼–ç ,æå‡ä»£ç 的规范性åŠå¯ç§»æ¤æ€§ï¼Œä¾›å¼€å‘者å‚考。 ## 编程规范 ### 总则 #### ã€è§„则】OpenHarmony的驱动程åºï¼Œåº”当使用HDF框架æä¾›çš„能力实现 ã€è¯´æ˜Žã€‘HDF驱动框架æä¾›äº†é©±åŠ¨åŠ è½½ã€é©±åЍæœåŠ¡ç®¡ç†å’Œé©±åŠ¨æ¶ˆæ¯æœºåˆ¶ï¼ŒåŒæ—¶è¿˜æä¾›äº†æ“作系统抽象层(OSAL, Operating System Abstraction Layer)å’Œå¹³å°æŠ½è±¡å±‚(PAL, Platform Abstraction Layer)æ¥ä¿è¯é©±åŠ¨ç¨‹åºçš„跨系统跨平å°éƒ¨ç½²çš„特性。除æ¤ä¹‹å¤–,HDFæä¾›äº†é©±åŠ¨æ¨¡åž‹çš„æŠ½è±¡ã€å…¬å…±å·¥å…·ã€å¤–围器件框架ç‰èƒ½åŠ›ã€‚å¼€å‘者应该基于HDFæä¾›çš„这些能力开å‘驱动,从而ä¿è¯é©±åŠ¨ç¨‹åºå¯ä»¥åœ¨å„ç§å½¢æ€çš„OpenHarmony上进行部署。 #### ã€è§„则】开å‘者应当éµå¾ªæ¤è§„èŒƒè¦æ±‚,开å‘èƒ½å¤ŸåŒæ—¶æ»¡è¶³å†…æ ¸æ€å’Œç”¨æˆ·æ€çš„驱动 ã€è¯´æ˜Žã€‘å†…æ ¸æ€é©±åŠ¨ä¸Žç”¨æˆ·æ€é©±åŠ¨å¤©ç„¶å˜åœ¨ç€å·®å¼‚,两ç§å½¢æ€é€‚用的场景也ä¸å°½ç›¸åŒã€‚å¼€å‘者在业务设计和开å‘的时候应当éµå¾ªæ¤è§„范,使用HDFæä¾›çš„OSALã€PALç‰ç‰¹æ€§æ¥å±è”½å½¢æ€çš„差异,æ¥ä¿è¯å¼€å‘çš„é©±åŠ¨åŒæ—¶æ»¡è¶³å†…æ ¸æ€å’Œç”¨æˆ·æ€ã€‚ #### ã€å»ºè®®ã€‘使用HDF框架时,编译脚本应当包å«drivers/framework/includeç›®å½•ï¼Œè€Œä¸æ˜¯å模å—目录 ã€è¯´æ˜Žã€‘drivers/framework/include目录是HDFå¯¹å¤–æš´éœ²çš„å¤´æ–‡ä»¶æ ¹ç›®å½•ï¼Œæ¤ç›®å½•䏋颿Œ‰ç…§åŠŸèƒ½åˆ’åˆ†ä¸ºæ ¸å¿ƒæ¡†æž¶ã€OSALå’ŒPALç‰å¤šä¸ªå模å—目录。在使用对应头文件时,建议编译脚本包å«åˆ°drivers/framework/includeç›®å½•ï¼Œè¿™æ ·åœ¨ä»£ç ä¸è¿›è¡Œå¼•用时,å¯ä»¥é¿å…é‡å¤åŒ…å«ï¼Œä¹Ÿä¾¿äºŽåŒºåˆ†å¯¹åº”忍¡å—,达到驱动范围内的统一。 ã€æ ·ä¾‹ã€‘ ```gn config("xxxx_private_config") { include_dirs = [ "//drivers/framework/include", "//drivers/framework/include/core", # ä¸å»ºè®® ] } ``` ```c #include <core/hdf_device_desc.h> #include <hdf_device_desc.h> // ä¸å»ºè®® ``` ### HDFæ ¸å¿ƒæ¡†æž¶ #### ã€è§„则】应当按照驱动入å£å¯¹è±¡HdfDriverEntryä¸çš„èŒè´£å®šä¹‰æ¥å®žçްBindã€Initå’ŒRelease方法,é¿å…èŒè´£ä¸å•一引入问题 ã€è¯´æ˜Žã€‘HdfDriverEntry对象是HDF驱动的入å£ï¼Œå…¶ä¸çš„ä¸‰ä¸ªæ–¹æ³•æŒ‡é’ˆå‡æœ‰å„自的èŒè´£ï¼Œå¼€å‘者需按照方法èŒè´£æ¥å®žçŽ°å¯¹åº”å‡½æ•°ã€‚ ```c struct HdfDriverEntry g_sampleDriverEntry = { .moduleVersion = 1, .moduleName = "sample_driver", .Bind = SampleDriverBind, // èŒè´£ï¼šç»‘定驱动对外æä¾›çš„æœåŠ¡æŽ¥å£åˆ°HDF .Init = SampleDriverInit, // èŒè´£ï¼šåˆå§‹åŒ–驱动自身的业务 .Release = SampleDriverRelease, // èŒè´£ï¼šé‡Šæ”¾é©±åŠ¨èµ„æºï¼Œå‘生异常时也会调用 }; HDF_INIT(g_sampleDriverEntry); ``` #### ã€è§„则】驱动æœåŠ¡çš„ç»“æž„å®šä¹‰ï¼Œé¦–ä¸ªæˆå‘˜å¿…须是IDeviceIoService类型 ã€è¯´æ˜Žã€‘HDF框架内部实现约æŸï¼Œé©±åŠ¨å®šä¹‰çš„æœåŠ¡æŽ¥å£ï¼Œé¦–个æˆå‘˜å¿…须是IDeviceIoService类型。 ã€æ ·ä¾‹ã€‘ ```c struct ISampleDriverService { struct IDeviceIoService ioService; // 首个æˆå‘˜å¿…须是IDeviceIoService类型 int32_t (*FunctionA)(void); // 驱动的第一个æœåŠ¡æŽ¥å£ int32_t (*FunctionB)(uint32_t inputCode); // 驱动的第二个æœåŠ¡æŽ¥å£ï¼Œå¯ä»¥ä¾æ¬¡å¾€ä¸‹ç´¯åŠ }; ``` ã€æ ·ä¾‹ã€‘ ```c struct ISampleDriverService { struct IDeviceIoService ioService; // 首个æˆå‘˜å¿…须是IDeviceIoService类型 void *instance; // 也å¯ä»¥å°è£…æœåŠ¡å®žä¾‹ï¼Œåœ¨å®žä¾‹ä¸æä¾›æœåŠ¡æŽ¥å£ }; ``` #### ã€è§„则】在HdfDriverEntryçš„Bind方法ä¸ï¼Œå¿…须完æˆå…¨éƒ¨é©±åЍæœåŠ¡æŽ¥å£çš„ç»‘å®šï¼Œç¦æ¢å°†æœåŠ¡æŽ¥å£æœªå®šä¹‰æˆ–定义为空 ã€è¯´æ˜Žã€‘驱动定义的æœåŠ¡æŽ¥å£ï¼Œå‡æ˜¯å¯¹å¤–暴露的,如果未定义或定义为空,å¯èƒ½ä¼šå¯¼è‡´å¤–部调用时产生异常,从而é™ä½Žé©±åŠ¨çš„å¯é 性。 ã€æ ·ä¾‹ã€‘ ```c int32_t SampleDriverBind(struct HdfDeviceObject *deviceObject) { static struct ISampleDriverService sampleDriver = { .FunctionA = SampleDriverServiceA, .FunctionB = NULL, // ç¦æ¢å®šä¹‰ä¸ºç©º }; // å°†ioService与HDF创建的设备对象进行绑定 deviceObject->service = &sampleDriver.ioService; return HDF_SUCCESS; } ``` #### ã€å»ºè®®ã€‘在HdfDriverEntryçš„Init方法ä¸ï¼Œåº”当调用HdfDeviceSetClass接å£ï¼Œå¯¹é©±åŠ¨çš„ç±»åž‹è¿›è¡Œå®šä¹‰ ã€è¯´æ˜Žã€‘驱动的类型å¯ä»¥ç”¨äºŽå½’类当å‰è®¾å¤‡çš„驱动程åºï¼Œä¹Ÿå¯ä»¥ç”¨æ¥æŸ¥è¯¢å½“å‰è®¾å¤‡çš„驱动能力。为了便于åŽç»é©±åŠ¨çš„ç»Ÿä¸€ç®¡ç†ï¼Œå»ºè®®é€šè¿‡HdfDeviceSetClassæŽ¥å£æ¥è®¾ç½®å½“å‰é©±åŠ¨çš„ç±»åž‹ã€‚ ã€æ ·ä¾‹ã€‘ ```c int32_t SampleDriverInit(struct HdfDeviceObject *deviceObject) { // 设置驱动的类型为DISPLAY if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_DISPLAY)) { HDF_LOGE("HdfDeviceSetClass failed"); return HDF_FAILURE; } return HDF_SUCCESS; } ``` ### HCSé…置规范 HCS(HDF Configuration Source)是HDF驱动框架的é…ç½®æè¿°æºç ,内容以Key-Value为主è¦å½¢å¼ã€‚它实现了é…置代ç 与驱动代ç 解耦,便于开å‘者进行é…置管ç†ã€‚ 驱动é…置包å«ä¸¤éƒ¨åˆ†ï¼ŒHDF框架定义的驱动设备æè¿°å’Œé©±åŠ¨çš„ç§æœ‰é…置信æ¯ã€‚ **设备æè¿°ä¿¡æ¯** HDFæ¡†æž¶åŠ è½½é©±åŠ¨æ‰€éœ€è¦çš„ä¿¡æ¯æ¥æºäºŽHDF框架定义的驱动设备æè¿°ï¼Œå› æ¤åŸºäºŽHDF框架开å‘的驱动必须è¦åœ¨HDF框架定义的device_info.hcsé…ç½®æ–‡ä»¶ä¸æ·»åŠ å¯¹åº”çš„è®¾å¤‡æè¿°ã€‚ #### ã€è§„则】在进行驱动设备é…置之å‰ï¼Œåº”当明确驱动所属的硬件和部署形æ€ï¼Œè§„划需è¦é…置的目录和文件 ã€è¯´æ˜Žã€‘在OpenHarmonyæºç çš„vendor目录下,按照芯片厂商ã€å¼€å‘æ¿ã€é…置的目录进行规划,HDF驱动的é…ç½®ä½äºŽhdf_configç›®å½•ä¸‹ã€‚æ ¹æ®ç¡¬ä»¶è§„æ ¼ï¼Œæ¤hdf_configç›®å½•ä¸‹å˜æ”¾å†…æ ¸æ€é…ç½®ä¿¡æ¯æˆ–è€…åˆ†åˆ«å†…æ ¸æ€å’Œç”¨æˆ·æ€çš„é…置信æ¯ã€‚å¼€å‘è€…åº”å½“æ ¹æ®é©±åŠ¨æ‰€å±žçš„ç¡¬ä»¶å’Œéƒ¨ç½²å½¢æ€ï¼Œç¡®å®šåœ¨å“ªä¸€ä¸ªç›®å½•下进行é…置。 ã€æ ·ä¾‹ã€‘ ```bash $openharmony_src_root/vendor/hisilicon/hispark_taurus/hdf_config # å†…æ ¸æ€é…ç½®æ–‡ä»¶ç›®å½•ï¼Œæ— ç”¨æˆ·æ€ $openharmony_src_root/vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf # å†…æ ¸æ€é…置文件目录 $openharmony_src_root/vendor/hisilicon/hispark_taurus_standard/hdf_config/uhdf # 用户æ€é…置文件目录 $openharmony_src_root/vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/device_info/device_info.hcs # å†…æ ¸æ€é©±åŠ¨è®¾å¤‡æè¿°é…置文件 $openharmony_src_root/vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/lcd/lcd_config.hcs # å†…æ ¸æ€é©±åŠ¨ç§æœ‰é…置文件 ``` #### ã€è§„则】驱动设备在é…置时,应当充分使用已有的é…置信æ¯ï¼Œç»§æ‰¿å·²æœ‰çš„é…ç½®æ¨¡æ¿ ã€è¯´æ˜Žã€‘在HDF框架定义的device_info.hcsé…置文件ä¸ï¼Œå·²ç»é…置好了hostã€deviceå’ŒdeviceNode的模æ¿ï¼Œå¼€å‘者在é…置驱动设备时,应该充分利用已有é…置信æ¯å’ŒHCS的继承特性,å‡å°‘é‡å¤çš„é…置工作é‡ã€‚ ã€æ ·ä¾‹ã€‘ ``` root { device_info { match_attr = "hdf_manager"; template host { // hostæ¨¡æ¿ hostName = ""; priority = 100; // hostå¯åŠ¨ä¼˜å…ˆçº§ï¼ˆ0-200),值越大优先级越低,建议默认é…100,优先级相åŒåˆ™ä¸ä¿è¯hostçš„åŠ è½½é¡ºåº template device { // deviceæ¨¡æ¿ template deviceNode { // deviceNodeæ¨¡æ¿ policy = 0; // policyå—æ®µæ˜¯é©±åЍæœåŠ¡å‘布的ç–ç•¥ priority = 100; // 驱动å¯åŠ¨ä¼˜å…ˆçº§ï¼ˆ0-200),值越大优先级越低,建议默认é…100,优先级相åŒåˆ™ä¸ä¿è¯deviceçš„åŠ è½½é¡ºåº preload = 0; // é©±åŠ¨æŒ‰éœ€åŠ è½½å—æ®µ permission = 0664; // 驱动创建设备节点æƒé™ moduleName = ""; serviceName = ""; deviceMatchAttr = ""; } } } // 继承模æ¿çš„节点如果使用模æ¿ä¸çš„é»˜è®¤å€¼ï¼Œåˆ™èŠ‚ç‚¹å—æ®µå¯ä»¥ç¼ºçœ sample_host :: host { // sample_host继承了hostæ¨¡æ¿ hostName = "host0"; // hostå称,host节点是用æ¥å˜æ”¾æŸä¸€ç±»é©±åŠ¨çš„å®¹å™¨ device_sample :: device { // device_sample继承了deviceæ¨¡æ¿ device0 :: deviceNode { // device0继承了deviceNodeæ¨¡æ¿ policy = 1; // 覆写了模æ¿ä¸çš„policy值 moduleName = "sample_driver"; // 驱动åç§°ï¼Œè¯¥å—æ®µçš„值必须和驱动入å£ç»“构的moduleName值一致 serviceName = "sample_service"; // 驱动对外å‘布æœåŠ¡çš„å称,必须唯一 deviceMatchAttr = "sample_config"; // é©±åŠ¨ç§æœ‰æ•°æ®åŒ¹é…的关键å—ï¼Œå¿…é¡»å’Œé©±åŠ¨ç§æœ‰æ•°æ®é…置表ä¸çš„match_attrå€¼ç›¸ç‰ } } } } } ``` #### ã€è§„则】驱动模型的设计和归类应当满足业务需è¦å’Œæ—¢å®šç±»åž‹ï¼Œç¦æ¢é‡å¤é…ç½®Hostå’ŒDevice ã€è¯´æ˜Žã€‘HDF框架将一类设备驱动放在åŒä¸€ä¸ªHost里é¢ï¼Œå¼€å‘者也å¯ä»¥å°†Hostä¸çš„驱动功能分层独立开å‘和部署,支æŒä¸€ä¸ªé©±åŠ¨å¤šä¸ªNode,HDF驱动模型如下图所示:  å¼€å‘者应当将åŒä¸€ç±»çš„设备放在åŒä¸€ä¸ªHost里é¢ï¼Œåœ¨æ–°å¢žè®¾å¤‡æ—¶ï¼Œæ£€æŸ¥æ˜¯å¦å·²ç»å˜åœ¨åŒç±»åž‹çš„Host。如果已å˜åœ¨Host,则将Deviceé…置在æ¤Hostä¸ï¼Œç¦æ¢é‡å¤é…ç½®Host。一个驱动设备应该åªå±žäºŽä¸€ç±»é©±åŠ¨ç±»åž‹ï¼Œå› æ¤ä¹Ÿç¦æ¢å°†åŒä¸€ä¸ªDeviceé…置在ä¸åŒHost当ä¸ã€‚ #### ã€è§„则】驱动æœåŠ¡å¿…é¡»æŒ‰ç…§ä¸šåŠ¡è§„åˆ™è®¾ç½®å¯¹å¤–å‘布的ç–ç•¥ï¼Œç¦æ¢è®¾ç½®ä¸å¿…è¦çš„å‘布ç–ç•¥ ã€è¯´æ˜Žã€‘驱动æœåŠ¡æ˜¯HDF驱动设备对外æä¾›èƒ½åŠ›çš„å¯¹è±¡ï¼Œç”±HDF框架统一管ç†ã€‚HDF框架定义了驱动对外å‘布æœåŠ¡çš„ç–略,是由é…置文件ä¸çš„policyå—æ®µæ¥æŽ§åˆ¶ï¼Œpolicyå—æ®µçš„å–值范围以åŠå«ä¹‰å¦‚下: ```c 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; ``` å› æ¤ï¼Œé©±åЍæœåŠ¡åº”è¯¥æŒ‰ç…§ä¸šåŠ¡è§„åˆ™æ¥è®¾ç½®å‘布ç–ç•¥ï¼Œç¦æ¢è®¾ç½®ä¸å¿…è¦çš„å‘布ç–ç•¥ï¼Œå¦‚å†…æ ¸æ€é©±åŠ¨è®¾ç½®ç”¨æˆ·æ€çš„å‘布ç–略。 ã€æ ·ä¾‹ã€‘ ``` root { device_info { sample_host { sample_device { device0 { policy = 1; // é©±åŠ¨å¯¹å†…æ ¸æ€å‘布æœåŠ¡ ... } } } } } ``` #### ã€è§„则】驱动创建设备节点æƒé™å¿…须与驱动的å‘å¸ƒè§„åˆ™äº’ç›¸åŒ¹é… ã€è¯´æ˜Žã€‘在HDF框架定义的device_info.hcsé…置文件ä¸ï¼Œpermission为驱动创建的设备节点æƒé™å—æ®µã€‚è¯¥å—æ®µçš„å–值使用Unix文件æƒé™çš„å…«è¿›åˆ¶æ•°å—æ¨¡å¼æ¥è¡¨ç¤ºï¼Œé•¿åº¦ä¸º4ä½ï¼Œä¾‹å¦‚0644。permissionå—æ®µä»…在驱动æœåŠ¡å¯¹ç”¨æˆ·æ€å‘布æœåŠ¡æ—¶ï¼ˆå³policy = 2)æ‰ä¼šç”Ÿæ•ˆã€‚ å¼€å‘者应当ä¿è¯é©±åЍæœåŠ¡çš„å‘布ç–略与设备节点的æƒé™äº’相匹é…,å¦åˆ™å¯èƒ½ä¼šå¯¼è‡´é©±åЍæœåŠ¡æ— æ³•è®¿é—®æˆ–è®¾å¤‡èŠ‚ç‚¹çš„æƒé™è¢«æ”¾å¤§ã€‚ ã€æ ·ä¾‹ã€‘ ``` root { device_info { sample_host { sample_device { device0 { policy = 2; // é©±åŠ¨å¯¹å†…æ ¸æ€å’Œç”¨æˆ·æ€éƒ½å‘布æœåŠ¡ permission = 0640; // 建议值 ... } } } } } ``` ã€å例】 ``` root { device_info { sample_host { sample_device { device0 { policy = 2; // é©±åŠ¨å¯¹å†…æ ¸æ€å’Œç”¨æˆ·æ€éƒ½å‘布æœåŠ¡ permission = 0777; // æƒé™è¿‡å¤§ ... } } } } } ``` ã€å例】 ``` root { device_info { sample_host { sample_device { device0 { policy = 1; // é©±åŠ¨å¯¹å†…æ ¸æ€å‘布æœåŠ¡ï¼Œä¸ä¼šåˆ›å»ºè®¾å¤‡èŠ‚ç‚¹ permission = 0640; // 冗余é…ç½® ... } } } } } ``` #### ã€è§„åˆ™ã€‘åº”å½“æ ¹æ®ä¸šåŠ¡è¦æ±‚é…ç½®æ˜¯å¦æŒ‰éœ€åŠ è½½ ã€è¯´æ˜Žã€‘在HDF框架定义的device_info.hcsé…置文件ä¸ï¼Œpreloadä¸ºé©±åŠ¨æŒ‰éœ€åŠ è½½å—æ®µï¼Œå–值的范围è§å¦‚下枚举: ```c typedef enum { /* 系统å¯åŠ¨æ—¶é»˜è®¤åŠ è½½ */ DEVICE_PRELOAD_ENABLE = 0, /* 当系统支æŒå¿«å¯æ—¶ï¼Œåˆ™åœ¨å¿«å¯å®ŒæˆåŽå†åŠ è½½ï¼›å¦‚æžœç³»ç»Ÿä¸æ”¯æŒå¿«å¯ï¼Œä¸ŽDEVICE_PRELOAD_ENABLEå«ä¹‰ç›¸åŒ */ DEVICE_PRELOAD_ENABLE_STEP2, /* 系统å¯åŠ¨æ—¶é»˜è®¤ä¸åŠ è½½ï¼Œå½“ä½¿ç”¨æ—¶HDF框架会å°è¯•动æ€åŠ è½½ */ DEVICE_PRELOAD_DISABLE, /* æ— æ•ˆå€¼ */ DEVICE_PRELOAD_INVALID } DevicePreload; ``` å¼€å‘è€…åº”å½“æ ¹æ®é©±åŠ¨çš„ä¸šåŠ¡è¦æ±‚,将preloadå—æ®µé…置为相应的值,从而HDF框架å¯ä»¥æŒ‰ç…§preloadè§„åˆ™è¿›è¡Œé©±åŠ¨çš„åŠ è½½ã€‚ ã€æ ·ä¾‹ã€‘ ``` root { device_info { sample_host { sample_device { device0 { preload = 2; // ä½¿ç”¨æ—¶æŒ‰éœ€åŠ è½½ ... } } } } } ``` #### ã€å»ºè®®ã€‘当preloadå—æ®µé…ç½®ä¸ºé»˜è®¤åŠ è½½æ—¶ï¼Œåº”å½“æ ¹æ®ä¸šåŠ¡è¦æ±‚é…置按åºåŠ è½½çš„ä¼˜å…ˆçº§ ã€è¯´æ˜Žã€‘在HDF框架定义的device_info.hcsé…置文件ä¸ï¼Œpriorityå—æ®µï¼ˆå–值范围为整数0到200)是用æ¥è¡¨ç¤ºHost和驱动的优先级。ä¸åŒçš„Host内的驱动,Hostçš„priority值越å°ï¼Œé©±åŠ¨åŠ è½½ä¼˜å…ˆçº§è¶Šé«˜ï¼›åŒä¸€ä¸ªHost内驱动的priority值越å°ï¼ŒåŠ è½½ä¼˜å…ˆçº§è¶Šé«˜ã€‚priorityå—æ®µçš„默认值为100,当未é…ç½®æˆ–å—æ®µå€¼ç›¸åŒæ—¶ï¼ŒHDF框架将ä¸ä¿è¯é©±åŠ¨çš„åŠ è½½é¡ºåºã€‚å¼€å‘è€…åº”å½“æ ¹æ®ä¸šåŠ¡åœºæ™¯çš„è¦æ±‚,é…ç½®priorityå—æ®µï¼Œä¿è¯å„个驱动的å¯åŠ¨é¡ºåºã€‚ ã€æ ·ä¾‹ã€‘ ``` root { device_info { sample_host0 { priority = 100; sample_device { device0 { preload = 0; // é»˜è®¤åŠ è½½ priority = 100; // HDFä¿è¯åœ¨device1之å‰åŠ è½½ ... } device1 { preload = 0; // é»˜è®¤åŠ è½½ priority = 200; // HDFä¿è¯åœ¨device0之åŽåŠ è½½ ... } } } sample_host1 { priority = 100; // 由于与sample_host0的优先级相åŒï¼ŒHDFå°†ä¸ä¿è¯åŠ è½½é¡ºåº ... } } } ``` **é©±åŠ¨ç§æœ‰é…置信æ¯** å¦‚æžœé©±åŠ¨æœ‰ç§æœ‰é…置,则å¯ä»¥æ·»åŠ ä¸€ä¸ªé©±åŠ¨çš„é…置文件,用æ¥å¡«å†™ä¸€äº›é©±åŠ¨çš„é»˜è®¤é…置信æ¯ï¼ŒHDFæ¡†æž¶åœ¨åŠ è½½é©±åŠ¨çš„æ—¶å€™ï¼Œä¼šå°†å¯¹åº”çš„é…置信æ¯èŽ·å–å¹¶ä¿å˜åœ¨HdfDeviceObjectä¸çš„property里é¢ï¼Œé€šè¿‡Bindå’ŒInitä¼ é€’ç»™é©±åŠ¨ã€‚ #### ã€è§„åˆ™ã€‘é©±åŠ¨ç§æœ‰é…置文件应当按照器件类型或者模å—进行目录划分,并放置在相应的目录下 ã€è¯´æ˜Žã€‘å¼€å‘è€…åº”å½“å¯¹é©±åŠ¨çš„ç§æœ‰é…置文件进行åˆç†çš„ç›®å½•è§„åˆ’ï¼Œç¦æ¢å°†ç§æœ‰é…置文件放置在é…ç½®çš„æ ¹ç›®å½•ä¸‹ã€‚ ã€æ ·ä¾‹ã€‘ ```bash $openharmony_src_root/vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/sample/sample_config.hcs # æ£ç¡®ï¼Œå°†ç§æœ‰é…置文件放置在了sample目录下 $openharmony_src_root/vendor/hisilicon/hispark_taurus_standard/hdf_config/khdf/sample_config.hcs # é”™è¯¯ï¼Œå°†ç§æœ‰é…置文件放置在了é…ç½®æ ¹ç›®å½•ä¸‹ ``` #### ã€è§„åˆ™ã€‘åº”å½“å°†é©±åŠ¨ç§æœ‰é…置文件包å«åˆ°hdf_configé…置目录下的hdf.hcsæ–‡ä»¶ä¸ ã€è¯´æ˜Žã€‘hdf.hcs文件是é…置信æ¯çš„æ±‡æ€»æ–‡ä»¶ï¼Œåœ¨HDF编译和è¿è¡Œæ—¶ï¼Œå°†ä¼šè§£æžæ¤æ–‡ä»¶ä¸çš„å†…å®¹ï¼ŒåŠ è½½é©±åŠ¨çš„ç§æœ‰é…置信æ¯åˆ°é©±åŠ¨çš„è®¾å¤‡èŠ‚ç‚¹ä¸ã€‚å¼€å‘者应当ä¿è¯hdf.hcs文件ä¸åŒ…å«äº†é©±åŠ¨çš„ç§æœ‰é…置文件,从而ä¿è¯é©±åŠ¨èƒ½å¤Ÿæ£ç¡®åˆå§‹åŒ–。 ã€æ ·ä¾‹ã€‘ ```c #include "device_info/device_info.hcs" #include "sample/sample_config.hcs" // 包å«é©±åŠ¨ç§æœ‰é…置文件 root { module = "hisilicon,hi35xx_chip"; } ``` #### ã€è§„åˆ™ã€‘é©±åŠ¨ç§æœ‰é…置信æ¯ä¸çš„matchAttrå—æ®µå€¼ï¼Œå¿…须与device_info.hcsä¸é…置的deviceMatchAttrå—æ®µå€¼ä¸€è‡´ ã€è¯´æ˜Žã€‘HDF框架会通过match_attrå—æ®µçš„值,æ¥ä¸Žé©±åŠ¨è®¾å¤‡è¿›è¡Œå…³è”。如果é…ç½®é”™è¯¯ï¼Œå°†å¯¼è‡´ç§æœ‰é…ç½®ä¿¡æ¯æ— 法获å–。 ã€æ ·ä¾‹ã€‘ ``` root { sample_config { ... match_attr = "sample_config"; // è¯¥å—æ®µçš„值必须和device_info.hcsä¸çš„deviceMatchAttr值一致 } } ``` #### ã€è§„åˆ™ã€‘é©±åŠ¨ç§æœ‰é…置信æ¯ä¸çš„å—æ®µåï¼Œä½¿ç”¨ä¸‹åˆ’çº¿å‘½åæ³• ã€è¯´æ˜Žã€‘由于C/C++è¯è¨€ç¼–程指导的命åè§„åˆ™è¦æ±‚ï¼Œé©±åŠ¨çš„ç§æœ‰é…置信æ¯ä¸çš„å—æ®µåï¼Œåº”å½“ä½¿ç”¨ä¸‹åˆ’çº¿å‘½åæ³•ã€‚è¿™æ ·ï¼Œåœ¨å®žçŽ°ä»£ç ä¸å¯¹ç§æœ‰é…置数æ®ç»“构进行定义时,å¯ä»¥æ»¡è¶³å‘½å规则,也便于代ç å’Œé…置文件的统一管ç†ã€‚ ã€æ ·ä¾‹ã€‘ ``` root { sample_config { sample_version = 1; // 使用下划线命å sample_bus = "I2C_0"; match_attr = "sample_config"; } } ``` ### HCSå® é©±åŠ¨çš„ç§æœ‰é…置信æ¯ä¼šè¢«åŠ è½½åˆ°HdfDeviceObjectä¸çš„propertyä¸ï¼Œå› æ¤ä¼šå 用一定的内å˜ç©ºé—´ï¼Œè¿™åœ¨è½»é‡å’Œå°åž‹ç³»ç»Ÿä¸å¸¦æ¥çš„缺点尤为明显。为了å‡å°‘ç§æœ‰é…置信æ¯çš„内å˜å 用,HDF框架æä¾›äº†HCSå®ï¼Œæ¥è§£æžé©±åŠ¨çš„ç§æœ‰é…置信æ¯ã€‚ #### ã€è§„åˆ™ã€‘åœ¨å†…å˜æ•感或跨系统类型的驱动场景下,应当使用HCS宿¥è§£æžé©±åŠ¨çš„ç§æœ‰é…ç½®ä¿¡æ¯ ã€è¯´æ˜Žã€‘å¼€å‘è€…åº”å½“æ˜Žç¡®é©±åŠ¨çš„ä½¿ç”¨åœºæ™¯ï¼Œå¦‚æžœå¯¹å†…å˜æ•感或者需è¦è·¨è½»é‡ã€å°åž‹å’Œæ ‡å‡†ç³»ç»Ÿä½¿ç”¨ï¼Œåº”当使用HCS宿¥è§£æžé©±åŠ¨çš„ç§æœ‰é…置信æ¯ï¼Œä»Žè€Œä¿è¯é©±åŠ¨çš„æ€§èƒ½å’Œå¯ç§»æ¤æ€§ã€‚ ã€æ ·ä¾‹ã€‘ ```c #include <utils/hcs_macro.h> #define SAMPLE_CONFIG_NODE HCS_NODE(HCS_ROOT, sample_config) ASSERT_EQ(HCS_PROP(SAMPLE_CONFIG_NODE, sampleVersion), 1); ASSERT_EQ(HCS_PROP(SAMPLE_CONFIG_NODE, sample_bus), "I2C_0"); ASSERT_EQ(HCS_PROP(SAMPLE_CONFIG_NODE, match_attr), "sample_config"); ``` ### HDF工具 #### ã€è§„则】在使用HdfSbuf进行数æ®é€šä¿¡æ—¶ï¼Œåº”å½“æ˜Žç¡®é€šä¿¡çš„åœºæ™¯ï¼Œå¹¶æ ¹æ®ç›¸åº”场景确定创建的HdfSbuf类型 ã€è¯´æ˜Žã€‘HdfSbuf是HDF进行数æ®ä¼ 输时的数æ®ç»“构,æ¤ç»“æž„æ ¹æ®é€šä¿¡çš„场景区分为ä¸åŒçš„类型,定义在hdf_sbuf.h头文件的枚举ä¸ï¼š ```c enum HdfSbufType { SBUF_RAW = 0, /* SBUF used for communication between the user space and the kernel space */ SBUF_IPC, /* SBUF used for inter-process communication (IPC) */ SBUF_IPC_HW, /* Reserved for extension */ SBUF_TYPE_MAX, /* Maximum value of the SBUF type */ }; ``` å¼€å‘者在进行数æ®é€šä¿¡æ—¶ï¼Œåº”当明确是跨用户æ€å’Œå†…æ ¸æ€é€šä¿¡åœºæ™¯ï¼Œè¿˜æ˜¯ç”¨æˆ·æ€çš„进程间通信,从而创建相应的HdfSbuf。 ã€æ ·ä¾‹ã€‘ ```c void SampleDispatchBetweenUserAndKernel() { int32_t ret; /* 跨用户æ€å’Œå†…æ ¸æ€è¿›è¡Œé€šä¿¡çš„场景 */ struct HdfSBuf *data = HdfSBufTypedObtain(SBUF_RAW); ... ret = sample->dispatcher->Dispatch(&sample->object, CMD_SAMPLE_DISPATCH, data, NULL); ... HdfSBufRecycle(data); } ``` ã€æ ·ä¾‹ã€‘ ```c++ void SampleDispatchIpc() { /* 跨进程进行通信的场景 */ struct HdfSBuf *data = HdfSBufTypedObtain(SBUF_IPC); ... int ret = sample->dispatcher->Dispatch(sample, CMD_SAMPLE_DISPATCH, data, nullptr); ... HdfSBufRecycle(data); } ``` #### ã€è§„则】在使用HDFçš„æ—¥å¿—æ‰“å°æ—¶ï¼Œåº”当明确定义HDF_LOG_TAG日志打å°çš„æ ‡ç¾ ã€è¯´æ˜Žã€‘HDF框架æä¾›äº†ä¸€å¥—日志打å°å·¥å…·hdf_log.h,开å‘者å¯ä»¥ç›´æŽ¥ä½¿ç”¨HDF的日志打å°è¿›è¡Œé©±åЍè¿è¡Œæ—¥å¿—的输出。HDF_LOG_TAGå®çš„作用是定义日志打å°çš„æ ‡ç¾ï¼Œå¼€å‘è€…å¿…é¡»åœ¨æ‰“å°æ—¥å¿—å‰è¿›è¡Œå®šä¹‰ã€‚ ã€æ ·ä¾‹ã€‘ ```c #include <hdf_log.h> #define HDF_LOG_TAG sample_driver // å®šä¹‰æ—¥å¿—çš„æ ‡ç¾ int32_t SampleDriverInit(struct HdfDeviceObject *deviceObject) { HDF_LOGI("sample driver is initialized"); // 使用HDFæ—¥å¿—å·¥å…·æ‰“å°æ—¥å¿— return HDF_SUCCESS; } ``` #### ã€è§„则】应当对HDF框架方法的返回值进行有效判æ–,并使用HDFæä¾›çš„错误ç ã€è¯´æ˜Žã€‘HDF框架æä¾›çš„æ–¹æ³•有明确的错误ç 返回值,开å‘者在使用时应当进行判æ–ï¼Œè€Œä¸æ˜¯é€‰æ‹©å¿½ç•¥ã€‚对应的返回值为hdf_base.h头文件ä¸çš„错误ç ,开å‘者在使用HDF或实现自定义方法时,应当统一使用HDFæä¾›çš„错误ç 。 ã€æ ·ä¾‹ã€‘ ```c int32_t SampleDriverInit(struct HdfDeviceObject *deviceObject) { int32_t ret; // 判æ–è®¾å¤‡ç±»åž‹è®¾ç½®æ˜¯å¦æˆåŠŸ if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_DISPLAY)) { HDF_LOGE("HdfDeviceSetClass failed"); return HDF_FAILURE; } ret = InitDiver(); // 自定义方法使用HDF的错误ç if (ret != HDF_SUCCESS) { HDF_LOGE("init driver is failed"); return ret; } return HDF_SUCCESS; } ``` ### OSAL框架 HDF OSAL框架å±è”½äº†OpenHarmonyå„个系统类型之间的接å£å·®å¼‚,对外æä¾›ç»Ÿä¸€çš„OS接å£ï¼ŒåŒ…括内å˜ç®¡ç†ã€çº¿ç¨‹ã€äº’斥体ã€è‡ªæ—‹é”ã€ä¿¡å·é‡ã€å®šæ—¶å™¨ã€æ–‡ä»¶ã€ä¸æ–ã€æ—¶é—´ã€åŽŸåã€å›ºä»¶ã€I/Oæ“作模å—。 #### ã€è§„则】跨轻é‡ã€å°åž‹å’Œæ ‡å‡†ç³»ç»Ÿç±»åž‹çš„驱动,必须通过OSAL框架æ¥ä½¿ç”¨æ“ä½œç³»ç»ŸæŽ¥å£ ã€è¯´æ˜Žã€‘OSALå±è”½äº†OS接å£ä¹‹é—´çš„差异,开å‘者应当基于OSALæ¥æ“作OS的接å£ï¼Œä¿è¯é©±åŠ¨èƒ½å¤Ÿè·¨ç³»ç»Ÿç±»åž‹è¿è¡Œã€‚ ã€æ ·ä¾‹ã€‘ ```c #include <osal/osal_mem.h> #include <util/hdf_log.h> struct DevHandle *SampleInit(void) { struct DevHandle *handle = (struct DevHandle *)OsalMemCalloc(sizeof(struct DevHandle)); if (handle == NULL) { HDF_LOGE("OsalMemCalloc handle failed"); return NULL; } return handle; } ``` ã€æ ·ä¾‹ã€‘ ```c #include <osal/osal_time.h> void SampleSleep(uint32_t timeMs) { OsalMSleep(timeMs); } ``` ### PAL框架 HDF PAL框架对平å°ç±»é©±åŠ¨è¿›è¡Œäº†æŠ½è±¡ï¼Œå¹¶å¯¹å¤–æä¾›ç»Ÿä¸€çš„æ“ä½œæŽ¥å£ï¼ŒåŒ…括GPIOã€I2Cã€SPIã€UARTã€RTCã€SDIOã€EMMCã€DSIã€PWMã€WATCHDOGç‰æ¨¡å—。 #### ã€è§„则】跨轻é‡ã€å°åž‹å’Œæ ‡å‡†ç³»ç»Ÿç±»åž‹çš„驱动,必须通过PAL框架æ¥ä½¿ç”¨å¹³å°é©±åЍ ã€è¯´æ˜Žã€‘PALå±è”½äº†ä¸åŒç³»ç»Ÿç±»åž‹ä¹‹é—´çš„å¹³å°é©±åŠ¨æŽ¥å£å·®å¼‚,开å‘者应当基于PALæ¥æ“作这些接å£ï¼Œä¿è¯é©±åŠ¨èƒ½å¤Ÿè·¨ç³»ç»Ÿç±»åž‹è¿è¡Œã€‚ ã€æ ·ä¾‹ã€‘ ```c #include <platform/gpio_if.h> #include <util/hdf_log.h> #include <osal/osal_irq.h> #include <osal/osal_time.h> static uint32_t g_irqCnt; /* GPIO䏿–æœåŠ¡æ ·ä¾‹å‡½æ•° */ static int32_t SampleGpioIrqHandler(uint16_t gpio, void *data) { HDF_LOGE("%s: irq triggered, on gpio:%u, data=%p", __func__, gpio, data); g_irqCnt++; // å¦‚æžœä¸æ–æœåŠ¡å‡½æ•°è§¦å‘æ‰§è¡Œï¼Œåˆ™å°†å…¨å±€ä¸æ–è®¡æ•°åŠ 1 return GpioDisableIrq(gpio); } /* GPIOæ ·ä¾‹å‡½æ•° */ static int32_t SampleGpioIrqEdge(void) { int32_t ret; uint16_t valRead; uint16_t mode; uint16_t gpio = 83; // 待测试的GPIOç®¡è„šå· uint32_t timeout; /* 将管脚方å‘设置为输出 */ ret = GpioSetDir(gpio, GPIO_DIR_OUT); ... /* ç¦æ¢è¯¥ç®¡è„šä¸æ– */ ret = GpioDisableIrq(gpio); ... /* ä¸ºç®¡è„šè®¾ç½®ä¸æ–æœåŠ¡å‡½æ•°ï¼Œè§¦å‘æ¨¡å¼ä¸ºä¸Šå‡æ²¿å’Œä¸‹é™æ²¿å…±åŒè§¦å‘ */ mode = OSAL_IRQF_TRIGGER_RISING | OSAL_IRQF_TRIGGER_FALLING; ret = GpioSetIrq(gpio, mode, SampleGpioIrqHandler, NULL); ... /* 使能æ¤ç®¡è„šä¸æ– */ ret = GpioEnableIrq(gpio); ... g_irqCnt = 0; // 清除全局计数器 timeout = 0; // ç‰å¾…时间清零 /* ç‰å¾…æ¤ç®¡è„šä¸æ–æœåŠ¡å‡½æ•°è§¦å‘,ç‰å¾…超时时间为1000毫秒 */ while (g_irqCnt <= 0 && timeout < 1000) { ret = GpioRead(gpio, &valRead); ... ret = GpioWrite(gpio, (valRead == GPIO_VAL_LOW) ? GPIO_VAL_HIGH : GPIO_VAL_LOW); ... OsalMDelay(200); // ç‰å¾…䏿–è§¦å‘ timeout += 200; } ret = GpioUnSetIrq(gpio); ... return (g_irqCnt > 0) ? HDF_SUCCESS : HDF_FAILURE; } ```