1# 平台驱动开发示例<a name="ZH-CN_TOPIC_0000001157064271"></a> 2 3- [概述](#section194201316174215) 4- [环境准备](#section6926133918422) 5- [开发](#section65801539470) 6 - [文件说明](#section0708184454414) 7 - [实例化驱动入口](#section85325864412) 8 - [设置相关参数](#section8155172019453) 9 - [添加控制器](#section1335374114452) 10 11- [编译及烧录](#section164824754712) 12 13## 概述<a name="section194201316174215"></a> 14 15本文档将以I2C驱动为例,介绍如何基于HDF驱动框架完成平台驱动开发。 16 17> **注意:** 18>本例仅作为平台驱动开发示例参考,开发者不可直接用于商用集成。 19 20HDF驱动框架为常用外围设备提供了标准的驱动框架,驱动开发者只需将驱动适配至HDF驱动框架,即可通过HDF驱动框架提供的接口操作外围设备。 21 22本文以I2C为例。其时序流程如[图1](#fig9596628607)所示。 23 24**图 1** I2C时序流程图<a name="fig9596628607"></a> 25 26 27## 环境准备<a name="section6926133918422"></a> 28 29环境准备具体操作请参考[标准系统基础环境搭建](../quick-start/quickstart-standard-overview.md)。 30 31> **须知:** 32>本示例针对OpenHarmony轻量系统、小型系统、标准系统都适用,本文以标准系统为例。其他系统的开发者可参考对应系统的指导文档进行环境搭建。 33 34## 开发<a name="section65801539470"></a> 35 36### 文件说明<a name="section0708184454414"></a> 37 38本例中涉及的文件及路径如下表: 39 40**表 1** 文件说明 41 42<a name="table15887645104012"></a> 43<table><thead align="left"><tr id="row198881452404"><th class="cellrowborder" align="center" valign="top" width="13.489999999999998%" id="mcps1.2.4.1.1"><p id="p158742406488"><a name="p158742406488"></a><a name="p158742406488"></a>说明</p> 44</th> 45<th class="cellrowborder" align="center" valign="top" width="68.52000000000001%" id="mcps1.2.4.1.2"><p id="p6975142717432"><a name="p6975142717432"></a><a name="p6975142717432"></a>文件路径</p> 46</th> 47<th class="cellrowborder" align="center" valign="top" width="17.990000000000002%" id="mcps1.2.4.1.3"><p id="p98891454405"><a name="p98891454405"></a><a name="p98891454405"></a>操作</p> 48</th> 49</tr> 50</thead> 51<tbody><tr id="row1088914458407"><td class="cellrowborder" align="left" valign="top" width="13.489999999999998%" headers="mcps1.2.4.1.1 "><p id="p78741540104813"><a name="p78741540104813"></a><a name="p78741540104813"></a>示例文件</p> 52</td> 53<td class="cellrowborder" align="left" valign="top" width="68.52000000000001%" headers="mcps1.2.4.1.2 "><p id="p1066541692916"><a name="p1066541692916"></a><a name="p1066541692916"></a>/drivers/adapter/khdf/linux/platform/i2c/i2c_sample.c</p> 54</td> 55<td class="cellrowborder" align="left" valign="top" width="17.990000000000002%" headers="mcps1.2.4.1.3 "><p id="p208891445144012"><a name="p208891445144012"></a><a name="p208891445144012"></a>新增文件</p> 56</td> 57</tr> 58<tr id="row1388984594013"><td class="cellrowborder" align="left" valign="top" width="13.489999999999998%" headers="mcps1.2.4.1.1 "><p id="p88741840104811"><a name="p88741840104811"></a><a name="p88741840104811"></a>设备服务文件</p> 59</td> 60<td class="cellrowborder" align="left" valign="top" width="68.52000000000001%" headers="mcps1.2.4.1.2 "><p id="p486417183298"><a name="p486417183298"></a><a name="p486417183298"></a>/drivers/adapter/khdf/linux/hcs/device_info/device_info.hcs</p> 61</td> 62<td class="cellrowborder" rowspan="3" align="left" valign="top" width="17.990000000000002%" headers="mcps1.2.4.1.3 "><p id="p128898458401"><a name="p128898458401"></a><a name="p128898458401"></a></p> 63<p id="p168904455404"><a name="p168904455404"></a><a name="p168904455404"></a>追加内容</p> 64<p id="p7890124516405"><a name="p7890124516405"></a><a name="p7890124516405"></a></p> 65</td> 66</tr> 67<tr id="row9889164513406"><td class="cellrowborder" align="left" valign="top" headers="mcps1.2.4.1.1 "><p id="p138741640124812"><a name="p138741640124812"></a><a name="p138741640124812"></a>配置参数文件</p> 68</td> 69<td class="cellrowborder" align="left" valign="top" headers="mcps1.2.4.1.2 "><p id="p26905191293"><a name="p26905191293"></a><a name="p26905191293"></a>/drivers/adapter/khdf/linux/hcs/platform/i2c_config.hcs</p> 70</td> 71</tr> 72<tr id="row1189044513404"><td class="cellrowborder" align="left" valign="top" headers="mcps1.2.4.1.1 "><p id="p1687424074814"><a name="p1687424074814"></a><a name="p1687424074814"></a>编译文件</p> 73</td> 74<td class="cellrowborder" align="left" valign="top" headers="mcps1.2.4.1.2 "><p id="p1885032192917"><a name="p1885032192917"></a><a name="p1885032192917"></a>/drivers/adapter/khdf/linux/platform/i2c/Makefile</p> 75</td> 76</tr> 77<tr id="row10890144564011"><td class="cellrowborder" align="left" valign="top" width="13.489999999999998%" headers="mcps1.2.4.1.1 "><p id="p118752040104810"><a name="p118752040104810"></a><a name="p118752040104810"></a>依赖头文件</p> 78</td> 79<td class="cellrowborder" align="left" valign="top" width="68.52000000000001%" headers="mcps1.2.4.1.2 "><p id="p15821718182916"><a name="p15821718182916"></a><a name="p15821718182916"></a>/drivers/framework/include/core/hdf_device_desc.h</p> 80</td> 81<td class="cellrowborder" rowspan="2" align="left" valign="top" width="17.990000000000002%" headers="mcps1.2.4.1.3 "><p id="p989012451401"><a name="p989012451401"></a><a name="p989012451401"></a>作为头文件引用</p> 82<p id="p1890134594014"><a name="p1890134594014"></a><a name="p1890134594014"></a></p> 83</td> 84</tr> 85<tr id="row6890164564015"><td class="cellrowborder" align="left" valign="top" headers="mcps1.2.4.1.1 "><p id="p128756401484"><a name="p128756401484"></a><a name="p128756401484"></a>核心层头文件</p> 86</td> 87<td class="cellrowborder" align="left" valign="top" headers="mcps1.2.4.1.2 "><p id="p47681122152918"><a name="p47681122152918"></a><a name="p47681122152918"></a>/drivers/framework/support/platform/include/i2c_core.h</p> 88</td> 89</tr> 90<tr id="row1499682234817"><td class="cellrowborder" align="left" valign="top" width="13.489999999999998%" headers="mcps1.2.4.1.1 "><p id="p1187513403487"><a name="p1187513403487"></a><a name="p1187513403487"></a>HCS配置入口文件</p> 91</td> 92<td class="cellrowborder" align="left" valign="top" width="68.52000000000001%" headers="mcps1.2.4.1.2 "><p id="p499818225487"><a name="p499818225487"></a><a name="p499818225487"></a>/drivers/adapter/khdf/linux/hcs/hdf.hcs</p> 93</td> 94<td class="cellrowborder" align="left" valign="top" width="17.990000000000002%" headers="mcps1.2.4.1.3 "><p id="p3998152254820"><a name="p3998152254820"></a><a name="p3998152254820"></a>HCS配置文件总入口</p> 95</td> 96</tr> 97</tbody> 98</table> 99 100> **注意:** 101>本例程涉及的文件路径均作为演示,驱动开发者应根据实际情况确定具体的源文件存放位置。 102 103### 实例化驱动入口<a name="section85325864412"></a> 104 105实例化一个HdfDriverEntry 对象作为驱动入口。驱动入口必须为HdfDriverEntry(在hdf\_device\_desc.h中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 106 107I2C驱动中没有实现Bind方法,因为I2C控制器由manager管理,而在manager中已经实现了Bind方法,因此I2C驱动中无需再绑定服务。 108 109实例化驱动入口的示例代码如下: 110 111``` 112/* 定义驱动入口的对象,必须为HdfDriverEntry(在hdf_device_desc.h中定义)类型的全局变量 */ 113struct HdfDriverEntry g_sampleI2cDriverEntry = { 114 .moduleVersion = 1, 115 .Init = SampleI2cInit, 116 .Release = SampleI2cRelease, 117 .moduleName = "demo_i2c_driver", 118}; 119/* 调用HDF_INIT将驱动入口注册到HDF框架中 */ 120HDF_INIT(g_sampleI2cDriverEntry); 121``` 122 123### 设置相关参数<a name="section8155172019453"></a> 124 125通过配置device\_info.hcs,并从HCS获取并解析设备的配置参数以确保驱动能够正确加载。 126 1271. 添加设备服务节点(必选)。 128 129 编辑device\_info.hcs,在device\_i2c :: device下添加驱动设备服务节点,示例如下: 130 131 ``` 132 root { 133 device_info { 134 match_attr = "hdf_manager"; 135 device_i2c :: device { // i2c设备节点 136 device2 :: deviceNode { // i2c驱动的DeviceNode节点 137 policy = 0; // policy字段是驱动服务发布的策略 138 priority = 55; // 驱动启动优先级 139 permission = 0644; // 驱动创建设备节点权限 140 moduleName = "demo_i2c_driver"; // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 141 serviceName = "DEMO_I2C_DRIVER"; // 驱动对外发布服务的名称,必须唯一 142 deviceMatchAttr = "demo_i2c_config"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的 143 // match_attr值相等 144 } 145 } 146 } 147 } 148 149 ``` 150 151 > **须知:** 152 >配置文件中的priority(取值范围为整数0到200)是用来表示host和驱动的优先级,不同的host内的驱动,host的priority值越小,驱动加载优先级越高;同一个host内驱动的priority值越小,加载优先级越高,驱动的priority值相同则不保证加载顺序。 153 1542. 添加配置参数(可选)。 155 156 有时驱动可能会需要私有配置信息,以确保寄存器的配置可以满足不同产品的需求。如需要私有配置信息,则可以添加一个驱动的配置文件,用来存放一些驱动的默认配置信息,HDF框架在加载驱动的时候,会将对应的配置信息获取并保存在HdfDeviceObject 中的property里面,通过Bind和Init(参考[驱动开发](../driver/driver-hdf-development.md))传递给驱动。驱动开发者可新建配置文件,并在板级驱动hdf.hcs中引用新建的配置文件,本例中直接在原有的配置文件i2c\_config.hcs内添加配置参数。 157 158 本例中编辑i2c\_config.hcs,添加配置参数: 159 160 ``` 161 root { 162 platform { 163 i2c_config_demo { 164 match_attr = "demo_i2c_config"; // 该字段的值必须和device_info.hcs中的deviceMatchAttr值一致 165 166 template i2c_controller { // 参数模板 167 bus = 0; 168 reg_pbase = 0x120b0000; 169 reg_size = 0xd1; 170 } 171 172 controller_demo_0 :: i2c_controller { // 两个I2C示例控制器 173 bus = 8; 174 } 175 controller_demo_1 :: i2c_controller { 176 bus = 9; 177 } 178 } 179 } 180 } 181 ``` 182 183 match\_attr字段必须与device\_info.hcs中的deviceMatch\_Attr保持一致,在此文件中配置驱动需要的参数,通过match\_attr可匹配至对应的驱动,该驱动即可在Bind或Init中调用DeviceResourceGetIfaceInstance\(\)函数获取这些配置参数。 184 185 若配置文件为新文件,则需要在板级配置入口文件hdf.hcs中引用该配置文件,例如: 186 187 ``` 188 #include "device_info/device_info.hcs" 189 #include "i2c/i2c_config.hcs" 190 ``` 191 192 由于本例中在原有的i2c\_config.hcs内添加配置参数,没有新建配置文件,因此无需再将i2c\_config.hcs添加至板级配置入口文件中。 193 1943. 驱动从HCS获取配置参数。 195 196 在本例中,驱动需要通过HCS获取寄存器物理基地址、寄存器大小、总线号等参数,从而对控制器进行正确配置。 197 198 ``` 199 /* 从HCS获取配置参数 */ 200 static int32_t SampleI2cReadDrs(struct SampleI2cCntlr *sampleCntlr, const struct DeviceResourceNode *node) 201 { 202 int32_t ret; 203 struct DeviceResourceIface *drsOps = NULL; 204 205 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 206 if (drsOps == NULL || drsOps->GetUint32 == NULL) { // 确保GetUint32方法可用 207 HDF_LOGE("%s: invalid drs ops fail!", __func__); 208 return HDF_FAILURE; 209 } 210 211 ret = drsOps->GetUint32(node, "reg_pbase", &sampleCntlr->regBasePhy, 0); // 从HCS读取物理基地址reg_pbase 212 if (ret != HDF_SUCCESS) { 213 HDF_LOGE("%s: read regBase fail!", __func__); 214 return ret; 215 } 216 217 ret = drsOps->GetUint16(node, "reg_size", &sampleCntlr->regSize, 0); // 从HCS读取寄存器大小reg_size 218 if (ret != HDF_SUCCESS) { 219 HDF_LOGE("%s: read regsize fail!", __func__); 220 return ret; 221 } 222 223 ret = drsOps->GetUint16(node, "bus", (uint16_t *)&sampleCntlr->bus, 0); // 从HCS读取总线号bus 224 if (ret != HDF_SUCCESS) { 225 HDF_LOGE("%s: read bus fail!", __func__); 226 return ret; 227 } 228 229 return HDF_SUCCESS; 230 } 231 ``` 232 233 234### 添加控制器<a name="section1335374114452"></a> 235 236初始化控制器硬件,并调用核心层接口完成向核心层添加、删除设备,以及钩子函数的实现等。 237 2381. 定义结构体,实现钩子函数并赋值至函数指针。 239 240 I2cMethod结构体在i2c\_core.h中定义,其中通过函数指针的方式定义了I2C需要实现的方法,transfer方法为用于传输的钩子函数,在驱动中需要做具体实现并对函数指针赋值。 241 242 示例代码如下: 243 244 ``` 245 /* 自定义设备结构体,继承父类I2cCntlr */ 246 struct SampleI2cCntlr { 247 struct I2cCntlr cntlr; 248 OsalSpinlock spin; 249 volatile unsigned char *regBase; 250 uint16_t regSize; 251 int16_t bus; 252 uint32_t regBasePhy; 253 }; 254 255 /* 消息结构体,继承父类I2cMsg */ 256 struct SampleTransferData { 257 struct I2cMsg *msgs; 258 int16_t index; 259 int16_t count; 260 }; 261 /* 钩子函数实现 */ 262 static int32_t SampleI2cTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count) 263 { 264 int32_t ret = HDF_SUCCESS; 265 struct SampleI2cCntlr *sampleCntlr = NULL; 266 struct SampleTransferData td; 267 268 if (cntlr == NULL || cntlr->priv == NULL) { 269 HDF_LOGE("SampleI2cTransfer: cntlr lor sampleCntlr is null!"); 270 return HDF_ERR_INVALID_OBJECT; 271 } 272 sampleCntlr = (struct SampleI2cCntlr *)cntlr; 273 274 if (msgs == NULL || count <= 0) { 275 HDF_LOGE("SampleI2cTransfer: err parms! count:%d", count); 276 return HDF_ERR_INVALID_PARAM; 277 } 278 td.msgs = msgs; 279 td.count = count; 280 td.index = 0; 281 282 HDF_LOGE("Successfully transmitted!"); // 表示此处传输成功 283 284 td.index = count; // 经过处理,最后实际发送msg个数等于count,返回已发送个数,此句代替已省略的处理过程 285 return (td.index > 0) ? td.index : ret; 286 } 287 /* 钩子函数赋值 */ 288 static struct I2cMethod g_method = { 289 .transfer = SampleI2cTransfer, 290 }; 291 ``` 292 2932. 编写驱动初始化函数。 294 295 本例中使用SampleI2cInit作为驱动初始化函数的函数名(函数名称可由驱动开发者确定),该函数需要在驱动入口结构体中赋值给Init,以供HDF驱动框架调用从而达到初始化驱动的目的。该函数中需要对从HCS获取的配置参数进行解析,并按照这些参数创建控制器。示例如下: 296 297 ``` 298 /* 解析参数,申请内存并创建控制器 */ 299 static int32_t SampleI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node) 300 { 301 int32_t ret; 302 struct SampleI2cCntlr *sampleCntlr = NULL; 303 (void)device; 304 305 sampleCntlr = (struct SampleI2cCntlr *)OsalMemCalloc(sizeof(*sampleCntlr)); 306 if (sampleCntlr == NULL) { 307 HDF_LOGE("%s: malloc sampleCntlr fail!", __func__); 308 return HDF_ERR_MALLOC_FAIL; 309 } 310 311 ret = SampleI2cReadDrs(sampleCntlr, node); // 从HCS获取配置参数 312 if (ret != HDF_SUCCESS) { 313 HDF_LOGE("%s: read drs fail! ret:%d", __func__, ret); 314 goto __ERR__; 315 } 316 317 sampleCntlr->regBase = OsalIoRemap(sampleCntlr->regBasePhy, sampleCntlr->regSize); 318 if (sampleCntlr->regBase == NULL) { 319 HDF_LOGE("%s: ioremap regBase fail!", __func__); 320 ret = HDF_ERR_IO; 321 goto __ERR__; 322 } 323 324 HDF_LOGE("The controller has been initialized!"); // 表示此处省略的控制器初始化操作已经成功 325 326 sampleCntlr->cntlr.priv = (void *)node; 327 sampleCntlr->cntlr.busId = sampleCntlr->bus; 328 sampleCntlr->cntlr.ops = &g_method; 329 (void)OsalSpinInit(&sampleCntlr->spin); // 初始化自旋锁 330 ret = I2cCntlrAdd(&sampleCntlr->cntlr); // 向核心层添加控制器 331 if (ret != HDF_SUCCESS) { 332 HDF_LOGE("%s: add i2c controller fail:%d!", __func__, ret); 333 goto __ERR__; 334 } 335 336 return HDF_SUCCESS; 337 __ERR__: // 错误处理 338 if (sampleCntlr != NULL) { 339 if (sampleCntlr->regBase != NULL) { 340 OsalIoUnmap((void *)sampleCntlr->regBase); // 取消地址映射 341 sampleCntlr->regBase = NULL; 342 } 343 OsalMemFree(sampleCntlr); // 释放内存 344 sampleCntlr = NULL; 345 } 346 return ret; 347 } 348 /* 驱动入口初始化函数 */ 349 static int32_t SampleI2cInit(struct HdfDeviceObject *device) 350 { 351 int32_t ret; 352 const struct DeviceResourceNode *childNode = NULL; 353 354 HDF_LOGE("%s: Enter", __func__); 355 if (device == NULL || device->property == NULL) { 356 HDF_LOGE("%s: device or property is NULL", __func__); 357 return HDF_ERR_INVALID_OBJECT; 358 } 359 360 ret = HDF_SUCCESS; 361 DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { 362 ret = SampleI2cParseAndInit(device, childNode); // 调用解析参数和创建控制器的函数 363 if (ret != HDF_SUCCESS) { 364 break; 365 } 366 } 367 return ret; 368 } 369 ``` 370 3713. 编写驱动释放函数。 372 373 本例中使用SampleI2cRelease作为驱动释放函数的函数名(函数名称可由驱动开发者确定),该函数需要在驱动入口结构体中赋值给Release,当HDF框架调用Init函数初始化驱动失败时,将调用Release释放驱动资源。该函数中需包含释放内存和删除控制器等操作。示例如下: 374 375 ``` 376 /* 删除控制器函数 */ 377 static void SampleI2cRemoveByNode(const struct DeviceResourceNode *node) 378 { 379 int32_t ret; 380 int16_t bus; 381 struct I2cCntlr *cntlr = NULL; 382 struct SampleI2cCntlr *sampleCntlr = NULL; 383 struct DeviceResourceIface *drsOps = NULL; 384 385 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 386 if (drsOps == NULL || drsOps->GetUint32 == NULL) { 387 HDF_LOGE("%s: invalid drs ops fail!", __func__); 388 return; 389 } 390 391 ret = drsOps->GetUint16(node, "bus", (uint16_t *)&bus, 0); // 从HCS获取I2C总线号 392 if (ret != HDF_SUCCESS) { 393 HDF_LOGE("%s: read bus fail!", __func__); 394 return; 395 } 396 397 cntlr = I2cCntlrGet(bus); 398 if (cntlr != NULL && cntlr->priv == node) { // 根据I2C总线号删除控制器 399 I2cCntlrPut(cntlr); 400 I2cCntlrRemove(cntlr); 401 sampleCntlr = (struct SampleI2cCntlr *)cntlr; 402 OsalIoUnmap((void *)sampleCntlr->regBase); 403 OsalMemFree(sampleCntlr); 404 } 405 return; 406 } 407 /* 释放资源 */ 408 static void SampleI2cRelease(struct HdfDeviceObject *device) 409 { 410 const struct DeviceResourceNode *childNode = NULL; 411 412 HDF_LOGI("%s: enter", __func__); 413 414 if (device == NULL || device->property == NULL) { 415 HDF_LOGE("%s: device or property is NULL", __func__); 416 return; 417 } 418 419 DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { 420 SampleI2cRemoveByNode(childNode); // 调用删除控制器函数 421 } 422 } 423 ``` 424 425 426## 编译及烧录<a name="section164824754712"></a> 427 4281. 编辑Makefile,添加源文件: 429 430 ``` 431 include drivers/hdf/khdf/platform/platform.mk 432 433 obj-y += $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/i2c_core.o \ 434 $(HDF_PLATFORM_FRAMEWORKS_ROOT)/src/i2c_if.o \ 435 ./i2c_adapter.o \ 436 ./i2c_sample.o 437 ``` 438 439 "./i2c\_sample.o"为本示例中在Makefile中追加的内容。 440 4412. 编译及烧录。 442 443 具体操作请参考[标准系统快速入门编译及烧录章节](../quick-start/quickstart-standard.md)。 444 445 446