• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Developing a Driver<a name="EN-US_TOPIC_0000001174350613"></a>
2
3-   [Introduction to Driver](#s8efc1952ebfe4d1ea717182e108c29bb)
4-   [Building Source Code and Burning Images](#section660016185110)
5-   [Running an Image](#section333215226219)
6-   [Follow-up Learning](#section9712145420182)
7
8This section describes how to develop a driver on the board, including introduction, compilation, burning, and running of the driver.
9
10## Introduction to Driver<a name="s8efc1952ebfe4d1ea717182e108c29bb"></a>
11
12The following operations take a HDF-based UART driver as an example to show how to add configuration files, code the driver, and compile the code for interactions between the user-space applications and the driver. The driver source code is stored in the  **vendor/huawei/hdf/sample**  directory.
13
141.  Add Configurations.
15
16    Add driver configurations to the HDF driver configuration file \(for example,  **device/hisilicon/hi3516dv300/sdk\_liteos/config/uart/uart\_config.hcs**\).
17
18    ```
19    root {
20        platform {
21            uart_sample {
22                num = 5;            // UART device number
23                base = 0x120a0000;  // Base address of the UART register
24                irqNum = 38;
25                baudrate = 115200;
26                uartClk = 24000000;
27                wlen = 0x60;
28                parity = 0;
29                stopBit = 0;
30                match_attr = "sample_uart_5";
31            }
32        }
33    }
34    ```
35
36    Add the device node information to the HDF device configuration file \(for example,  **vendor/hisilicon/ipcamera\_hi3516dv300\_liteos/config/device\_info/device\_info.hcs**\)
37
38    ```
39    root {
40        device_info {
41            platform :: host {
42                hostName = "platform_host";
43                priority = 50;
44                device_uart :: device {
45                    device5 :: deviceNode {
46                        policy = 2;
47                        priority = 10;
48                        permission = 0660;
49                        moduleName = "UART_SAMPLE";
50                        serviceName = "HDF_PLATFORM_UART_5";
51                        deviceMatchAttr = "sample_uart_5";
52                    }
53                }
54            }
55        }
56    }
57    ```
58
59    >![](../public_sys-resources/icon-note.gif) **NOTE:**
60    >The configuration files are in the same path as the source code of the UART driver. You need to manually add the files to the path of the Hi3516D V300 development board.
61
622.  Register a UART driver entry.
63
64    Register the  **HdfDriverEntry**  of the UART driver with the HDF.
65
66    ```
67    // Bind the UART driver interface to the HDF.
68    static int32_t SampleUartDriverBind(struct HdfDeviceObject *device)
69    {
70        struct UartHost *uartHost = NULL;
71
72        if (device == NULL) {
73            return HDF_ERR_INVALID_OBJECT;
74        }
75        HDF_LOGI("Enter %s:", __func__);
76
77        uartHost = UartHostCreate(device);
78        if (uartHost == NULL) {
79            HDF_LOGE("%s: UartHostCreate failed", __func__);
80            return HDF_FAILURE;
81        }
82        uartHost->service.Dispatch = SampleDispatch;
83        return HDF_SUCCESS;
84    }
85
86    // Obtain configuration information from the HCS of the UART driver.
87    static uint32_t GetUartDeviceResource(
88        struct UartDevice *device, const struct DeviceResourceNode *resourceNode)
89    {
90        struct UartResource *resource = &device->resource;
91        struct DeviceResourceIface *dri = NULL;
92        dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
93        if (dri == NULL || dri->GetUint32 == NULL) {
94            HDF_LOGE("DeviceResourceIface is invalid");
95            return HDF_FAILURE;
96        }
97
98        if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) {
99            HDF_LOGE("uart config read num fail");
100            return HDF_FAILURE;
101        }
102        if (dri->GetUint32(resourceNode, "base", &resource->base, 0) != HDF_SUCCESS) {
103            HDF_LOGE("uart config read base fail");
104            return HDF_FAILURE;
105        }
106        resource->physBase = (unsigned long)OsalIoRemap(resource->base, 0x48);
107        if (resource->physBase == 0) {
108            HDF_LOGE("uart config fail to remap physBase");
109            return HDF_FAILURE;
110        }
111        if (dri->GetUint32(resourceNode, "irqNum", &resource->irqNum, 0) != HDF_SUCCESS) {
112            HDF_LOGE("uart config read irqNum fail");
113            return HDF_FAILURE;
114        }
115        if (dri->GetUint32(resourceNode, "baudrate", &resource->baudrate, 0) != HDF_SUCCESS) {
116            HDF_LOGE("uart config read baudrate fail");
117            return HDF_FAILURE;
118        }
119        if (dri->GetUint32(resourceNode, "wlen", &resource->wlen, 0) != HDF_SUCCESS) {
120            HDF_LOGE("uart config read wlen fail");
121            return HDF_FAILURE;
122        }
123        if (dri->GetUint32(resourceNode, "parity", &resource->parity, 0) != HDF_SUCCESS) {
124            HDF_LOGE("uart config read parity fail");
125            return HDF_FAILURE;
126        }
127        if (dri->GetUint32(resourceNode, "stopBit", &resource->stopBit, 0) != HDF_SUCCESS) {
128            HDF_LOGE("uart config read stopBit fail");
129            return HDF_FAILURE;
130        }
131        if (dri->GetUint32(resourceNode, "uartClk", &resource->uartClk, 0) != HDF_SUCCESS) {
132            HDF_LOGE("uart config read uartClk fail");
133            return HDF_FAILURE;
134        }
135        return HDF_SUCCESS;
136    }
137
138    // Attach the configuration and interface of the UART driver to the HDF.
139    static int32_t AttachUartDevice(struct UartHost *host, struct HdfDeviceObject *device)
140    {
141        int32_t ret;
142        struct UartDevice *uartDevice = NULL;
143        if (device->property == NULL) {
144            HDF_LOGE("%s: property is NULL", __func__);
145            return HDF_FAILURE;
146        }
147        uartDevice = (struct UartDevice *)OsalMemCalloc(sizeof(struct UartDevice));
148        if (uartDevice == NULL) {
149            HDF_LOGE("%s: OsalMemCalloc uartDevice error", __func__);
150            return HDF_ERR_MALLOC_FAIL;
151        }
152        ret = GetUartDeviceResource(uartDevice, device->property);
153        if (ret != HDF_SUCCESS) {
154            (void)OsalMemFree(uartDevice);
155            return HDF_FAILURE;
156        }
157        host->num = uartDevice->resource.num;
158        host->priv = uartDevice;
159        AddUartDevice(host);
160        return InitUartDevice(uartDevice);
161    }
162
163    // Initialize the UART driver.
164    static int32_t SampleUartDriverInit(struct HdfDeviceObject *device)
165    {
166        int32_t ret;
167        struct UartHost *host = NULL;
168
169        if (device == NULL) {
170            HDF_LOGE("%s: device is NULL", __func__);
171            return HDF_ERR_INVALID_OBJECT;
172        }
173        HDF_LOGI("Enter %s:", __func__);
174        host = UartHostFromDevice(device);
175        if (host == NULL) {
176            HDF_LOGE("%s: host is NULL", __func__);
177            return HDF_FAILURE;
178        }
179        ret = AttachUartDevice(host, device);
180        if (ret != HDF_SUCCESS) {
181            HDF_LOGE("%s: attach error", __func__);
182            return HDF_FAILURE;
183        }
184        host->method = &g_sampleUartHostMethod;
185        return ret;
186    }
187
188    static void DeinitUartDevice(struct UartDevice *device)
189    {
190        struct UartRegisterMap *regMap = (struct UartRegisterMap *)device->resource.physBase;
191        /* Wait for the UART to enter the idle state. */
192        while (UartPl011IsBusy(regMap));
193        UartPl011ResetRegisters(regMap);
194        uart_clk_cfg(0, false);
195        OsalIoUnmap((void *)device->resource.physBase);
196        device->state = UART_DEVICE_UNINITIALIZED;
197    }
198
199    // Detach and release the UART driver.
200    static void DetachUartDevice(struct UartHost *host)
201    {
202        struct UartDevice *uartDevice = NULL;
203
204        if (host->priv == NULL) {
205            HDF_LOGE("%s: invalid parameter", __func__);
206            return;
207        }
208        uartDevice = host->priv;
209        DeinitUartDevice(uartDevice);
210        (void)OsalMemFree(uartDevice);
211        host->priv = NULL;
212    }
213
214    // Release the UART driver.
215    static void SampleUartDriverRelease(struct HdfDeviceObject *device)
216    {
217        struct UartHost *host = NULL;
218        HDF_LOGI("Enter %s:", __func__);
219
220        if (device == NULL) {
221            HDF_LOGE("%s: device is NULL", __func__);
222            return;
223        }
224        host = UartHostFromDevice(device);
225        if (host == NULL) {
226            HDF_LOGE("%s: host is NULL", __func__);
227            return;
228        }
229        if (host->priv != NULL) {
230            DetachUartDevice(host);
231        }
232        UartHostDestroy(host);
233    }
234
235    struct HdfDriverEntry g_sampleUartDriverEntry = {
236        .moduleVersion = 1,
237        .moduleName = "UART_SAMPLE",
238        .Bind = SampleUartDriverBind,
239        .Init = SampleUartDriverInit,
240        .Release = SampleUartDriverRelease,
241    };
242
243    HDF_INIT(g_sampleUartDriverEntry);
244    ```
245
2463.  Register a UART driver interface.
247
248    Implement the UART driver interface using the template  **UartHostMethod**  provided by the HDF.
249
250    ```
251    static int32_t SampleUartHostInit(struct UartHost *host)
252    {
253        HDF_LOGI("%s: Enter", __func__);
254        if (host == NULL) {
255            HDF_LOGE("%s: invalid parameter", __func__);
256            return HDF_ERR_INVALID_PARAM;
257        }
258        return HDF_SUCCESS;
259    }
260
261    static int32_t SampleUartHostDeinit(struct UartHost *host)
262    {
263        HDF_LOGI("%s: Enter", __func__);
264        if (host == NULL) {
265            HDF_LOGE("%s: invalid parameter", __func__);
266            return HDF_ERR_INVALID_PARAM;
267        }
268        return HDF_SUCCESS;
269    }
270
271    // Write data into the UART device.
272    static int32_t SampleUartHostWrite(struct UartHost *host, uint8_t *data, uint32_t size)
273    {
274        HDF_LOGI("%s: Enter", __func__);
275        uint32_t idx;
276        struct UartRegisterMap *regMap = NULL;
277        struct UartDevice *device = NULL;
278
279        if (host == NULL || data == NULL || size == 0) {
280            HDF_LOGE("%s: invalid parameter", __func__);
281            return HDF_ERR_INVALID_PARAM;
282        }
283        device = (struct UartDevice *)host->priv;
284        if (device == NULL) {
285            HDF_LOGE("%s: device is NULL", __func__);
286            return HDF_ERR_INVALID_PARAM;
287        }
288        regMap = (struct UartRegisterMap *)device->resource.physBase;
289        for (idx = 0; idx < size; idx++) {
290            UartPl011Write(regMap, data[idx]);
291        }
292        return HDF_SUCCESS;
293    }
294
295    // Set the baud rate for the UART device.
296    static int32_t SampleUartHostSetBaud(struct UartHost *host, uint32_t baudRate)
297    {
298        HDF_LOGI("%s: Enter", __func__);
299        struct UartDevice *device = NULL;
300        struct UartRegisterMap *regMap = NULL;
301        UartPl011Error err;
302
303        if (host == NULL) {
304            HDF_LOGE("%s: invalid parameter", __func__);
305            return HDF_ERR_INVALID_PARAM;
306        }
307        device = (struct UartDevice *)host->priv;
308        if (device == NULL) {
309            HDF_LOGE("%s: device is NULL", __func__);
310            return HDF_ERR_INVALID_PARAM;
311        }
312        regMap = (struct UartRegisterMap *)device->resource.physBase;
313        if (device->state != UART_DEVICE_INITIALIZED) {
314            return UART_PL011_ERR_NOT_INIT;
315        }
316        if (baudRate == 0) {
317            return UART_PL011_ERR_INVALID_BAUD;
318        }
319        err = UartPl011SetBaudrate(regMap, device->uartClk, baudRate);
320        if (err == UART_PL011_ERR_NONE) {
321            device->baudrate = baudRate;
322        }
323        return err;
324    }
325
326    // Obtain the baud rate of the UART device.
327    static int32_t SampleUartHostGetBaud(struct UartHost *host, uint32_t *baudRate)
328    {
329        HDF_LOGI("%s: Enter", __func__);
330        struct UartDevice *device = NULL;
331
332        if (host == NULL) {
333            HDF_LOGE("%s: invalid parameter", __func__);
334            return HDF_ERR_INVALID_PARAM;
335        }
336        device = (struct UartDevice *)host->priv;
337        if (device == NULL) {
338            HDF_LOGE("%s: device is NULL", __func__);
339            return HDF_ERR_INVALID_PARAM;
340        }
341        *baudRate = device->baudrate;
342        return HDF_SUCCESS;
343    }
344
345    // Bind the UART device using HdfUartSampleInit.
346    struct UartHostMethod g_sampleUartHostMethod = {
347        .Init = SampleUartHostInit,
348        .Deinit = SampleUartHostDeinit,
349        .Read = NULL,
350        .Write = SampleUartHostWrite,
351        .SetBaud = SampleUartHostSetBaud,
352        .GetBaud = SampleUartHostGetBaud,
353        .SetAttribute = NULL,
354        .GetAttribute = NULL,
355        .SetTransMode = NULL,
356    };
357    ```
358
359    Add the sample module of the UART driver to the compilation script  **device/hisilicon/drivers/lite.mk**.
360
361    ```
362    LITEOS_BASELIB += -lhdf_uart_sample
363    LIB_SUBDIRS    += $(LITEOS_SOURCE_ROOT)/vendor/huawei/hdf/sample/platform/uart
364    ```
365
3664.  Implement the code for interaction between the user-space applications and driver.
367
368    Create the  **/dev/uartdev-5**  node after the UART driver is initialized successfully. The following example shows how to interact with the UART driver through the node.
369
370    ```
371    #include <stdlib.h>
372    #include <unistd.h>
373    #include <fcntl.h>
374    #include "hdf_log.h"
375
376    #define HDF_LOG_TAG "hello_uart"
377    #define INFO_SIZE 16
378
379    int main(void)
380    {
381        int ret;
382        int fd;
383        const char info[INFO_SIZE] = {" HELLO UART! "};
384
385        fd = open("/dev/uartdev-5", O_RDWR);
386        if (fd < 0) {
387            HDF_LOGE("hello_uart uartdev-5 open failed %d", fd);
388            return -1;
389        }
390        ret = write(fd, info, INFO_SIZE);
391        if (ret != 0) {
392            HDF_LOGE("hello_uart write uartdev-5 ret is %d", ret);
393        }
394        ret = close(fd);
395        if (ret != 0) {
396            HDF_LOGE("hello_uart uartdev-5 close failed %d", fd);
397            return -1;
398        }
399        return ret;
400    }
401    ```
402
403    Add the  **hello\_uart\_sample**  component to  **targets**  of the  **hdf\_hi3516dv300\_liteos\_a**  component in the  **build/lite/components/drivers.json**  file.
404
405    ```
406    {
407      "components": [
408        {
409          "component": "hdf_hi3516dv300_liteos_a",
410          ...
411          "targets": [
412            "//vendor/huawei/hdf/sample/platform/uart:hello_uart_sample"
413          ]
414        }
415      ]
416    }
417    ```
418
419    >![](../public_sys-resources/icon-note.gif) **NOTE:**
420    >Preceding code snippets are for reference only. You can view the complete sample code in  **vendor/huawei/hdf/sample.**
421    >The sample code is not automatically compiled by default. You can add it to the compilation script.
422
423
424## Building Source Code and Burning Images<a name="section660016185110"></a>
425
426Perform the  [building](quickstart-lite-steps-hi3516-running.md#section1077671315253)  and  [burning](quickstart-lite-steps-hi3516-running.md#section1347011412201)  as instructed in  **Running a Hello OHOS Program**.
427
428## Running an Image<a name="section333215226219"></a>
429
4301.  Connect to a serial port.
431
432    >![](../public_sys-resources/icon-notice.gif) **NOTICE:**
433    >If the connection fails, rectify the fault by referring to  [FAQs](quickstart-lite-steps-hi3516-faqs.md#section14871149155911).
434
435    **Figure  1**  Serial port connection<a name="fig124315964718"></a>
436    ![](figure/serial-port-connection-5.png "serial-port-connection-5")
437
438    1.  Click  **Monitor**  to enable the serial port.
439    2.  Press  **Enter**  repeatedly until  **hisilicon**  displays.
440    3.  Go to step  [2](quickstart-lite-steps-hi3516-running.md#l5b42e79a33ea4d35982b78a22913b0b1)  if the board is started for the first time or the startup parameters need to be modified; go to step  [3](quickstart-lite-steps-hi3516-running.md#ld26f18828aa44c36bfa36be150e60e49)  otherwise.
441
4422.  \(Mandatory when the board is started for the first time\) Modify the  **bootcmd**  and  **bootargs**  parameters of U-Boot. You need to perform this step only once if the parameters need not to be modified during the operation. The board automatically starts after it is reset.
443
444    >![](../public_sys-resources/icon-notice.gif) **NOTICE:**
445    >The default waiting time in the U-Boot is 2s. You can press  **Enter**  to interrupt the waiting and run the  **reset**  command to restart the system after "hisilicon" is displayed.
446
447    **Table  1**  Parameters of the U-Boot
448
449    <a name="en-us_topic_0000001151888681_table1323441103813"></a>
450    <table><thead align="left"><tr id="en-us_topic_0000001151888681_row1423410183818"><th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.1"><p id="en-us_topic_0000001151888681_p623461163818"><a name="en-us_topic_0000001151888681_p623461163818"></a><a name="en-us_topic_0000001151888681_p623461163818"></a>Command</p>
451    </th>
452    <th class="cellrowborder" valign="top" width="50%" id="mcps1.2.3.1.2"><p id="en-us_topic_0000001151888681_p42341014388"><a name="en-us_topic_0000001151888681_p42341014388"></a><a name="en-us_topic_0000001151888681_p42341014388"></a>Description</p>
453    </th>
454    </tr>
455    </thead>
456    <tbody><tr id="en-us_topic_0000001151888681_row1623471113817"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="en-us_topic_0000001151888681_p102341719385"><a name="en-us_topic_0000001151888681_p102341719385"></a><a name="en-us_topic_0000001151888681_p102341719385"></a>setenv bootcmd "mmc read 0x0 0x80000000 0x800 0x4800; go 0x80000000";</p>
457    </td>
458    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="en-us_topic_0000001151888681_p92347120389"><a name="en-us_topic_0000001151888681_p92347120389"></a><a name="en-us_topic_0000001151888681_p92347120389"></a>Run this command to read content that has a size of 0x4800 (9 MB) and a start address of 0x800 (1 MB) to the memory address 0x80000000. The file size must be the same as that of the <strong id="b881982511127"><a name="b881982511127"></a><a name="b881982511127"></a>OHOS_Image.bin</strong> file in the IDE.</p>
459    </td>
460    </tr>
461    <tr id="en-us_topic_0000001151888681_row12234912381"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="en-us_topic_0000001151888681_p172306219392"><a name="en-us_topic_0000001151888681_p172306219392"></a><a name="en-us_topic_0000001151888681_p172306219392"></a>setenv bootargs "console=ttyAMA0,115200n8 root=emmc fstype=vfat rootaddr=10M rootsize=20M rw";</p>
462    </td>
463    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="en-us_topic_0000001151888681_p13489329396"><a name="en-us_topic_0000001151888681_p13489329396"></a><a name="en-us_topic_0000001151888681_p13489329396"></a>Run this command to set the output mode to serial port output, baud rate to <strong id="b433815011512"><a name="b433815011512"></a><a name="b433815011512"></a>115200</strong>, data bit to <strong id="b1933919018155"><a name="b1933919018155"></a><a name="b1933919018155"></a>8</strong>, <strong id="b433912010151"><a name="b433912010151"></a><a name="b433912010151"></a>rootfs</strong> to be mounted to the <strong id="b83409014151"><a name="b83409014151"></a><a name="b83409014151"></a>emmc</strong> component, and file system type to <strong id="b133418081511"><a name="b133418081511"></a><a name="b133418081511"></a>vfat</strong>.</p>
464    <p id="en-us_topic_0000001151888681_p12481832163913"><a name="en-us_topic_0000001151888681_p12481832163913"></a><a name="en-us_topic_0000001151888681_p12481832163913"></a><strong id="b1641214193158"><a name="b1641214193158"></a><a name="b1641214193158"></a>rootaddr=10M rootsize=20M rw</strong> indicates the start address and size of the <strong id="b1441320198151"><a name="b1441320198151"></a><a name="b1441320198151"></a>rootfs.img</strong> file to be burnt, respectively. The file size must be the same as that of the <strong id="b15414219161513"><a name="b15414219161513"></a><a name="b15414219161513"></a>rootfs.img</strong> file in the IDE.</p>
465    </td>
466    </tr>
467    <tr id="en-us_topic_0000001151888681_row18234161153820"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="en-us_topic_0000001151888681_p823417118386"><a name="en-us_topic_0000001151888681_p823417118386"></a><a name="en-us_topic_0000001151888681_p823417118386"></a>saveenv</p>
468    </td>
469    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="en-us_topic_0000001151888681_p32341616389"><a name="en-us_topic_0000001151888681_p32341616389"></a><a name="en-us_topic_0000001151888681_p32341616389"></a><strong id="b8139162216169"><a name="b8139162216169"></a><a name="b8139162216169"></a>saveenv</strong> means to save the current configuration.</p>
470    </td>
471    </tr>
472    <tr id="en-us_topic_0000001151888681_row192345113811"><td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.1 "><p id="en-us_topic_0000001151888681_p7235111183819"><a name="en-us_topic_0000001151888681_p7235111183819"></a><a name="en-us_topic_0000001151888681_p7235111183819"></a>reset</p>
473    </td>
474    <td class="cellrowborder" valign="top" width="50%" headers="mcps1.2.3.1.2 "><p id="en-us_topic_0000001151888681_p123781411114016"><a name="en-us_topic_0000001151888681_p123781411114016"></a><a name="en-us_topic_0000001151888681_p123781411114016"></a><strong id="b760219545018"><a name="b760219545018"></a><a name="b760219545018"></a>reset</strong> means to reset the board.</p>
475    </td>
476    </tr>
477    </tbody>
478    </table>
479
480    >![](../public_sys-resources/icon-notice.gif) **NOTICE:**
481    >**go 0x80000000**  is optional. It indicates that the command is fixed in the startup parameters by default and the board automatically starts after it is reset. If you want to manually start the board, press  **Enter**  in the countdown phase of the U-Boot startup to interrupt the automatic startup.
482
4833.  Run the  **reset**  command and press  **Enter**  to restart the board. After the board is restarted,  **OHOS**  is displayed when you press  **Enter**.
484
485    **Figure  2**  System startup<a name="fig14618415485"></a>
486    ![](figure/system-startup-6.png "system-startup-6")
487
4884.  In the root directory, run the  **./bin/hello\_uart**  command line to execute the demo program. The compilation result is shown in the following example.
489
490    ```
491    OHOS # ./bin/hello_uart
492    OHOS #  HELLO UART!
493    ```
494
495
496## Follow-up Learning<a name="section9712145420182"></a>
497
498Congratulations! You have finished all steps! You are advised to go on learning how to develop  [Cameras with a Screen](../guide/device-iotcamera.md).
499
500