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