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 > **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 > **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 > **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  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 > **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 > **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  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