driver-platform-uart-develop.md 26.7 KB
Newer Older
A
Annie_wang 已提交
1
# UART
D
duangavin123 已提交
2

A
Annie_wang 已提交
3
## Overview
D
duangavin123 已提交
4

A
Annie_wang 已提交
5
### Function
D
duangavin123 已提交
6

A
Annie_wang 已提交
7
The Universal Asynchronous Receiver/Transmitter (UART) is a universal serial data bus used for asynchronous communication. It enables bi-directional communication between devices in full-duplex mode.
D
duangavin123 已提交
8

A
Annie_wang 已提交
9
A UART is connected to other modules through two wires (as shown in Figure 1) or four wires (as shown in Figure 2).
D
duangavin123 已提交
10

A
Annie_wang 已提交
11 12 13 14
  - TX: UART transmitter. It is connected to the RX of the peer UART.
  - RX: UART receiver. It is connected to the TX of the peer UART.
  - RTS: Request to Send signal, indicating whether the local UART is ready to receive data. It is connected to the CTS of the peer UART.
  - CTS: Clear to Send signal, indicating whether the local UART is allowed to send data to the peer end. It is connected to the RTS of the peer UART.
A
Annie_wang 已提交
15

A
Annie_wang 已提交
16
**Figure 1** Two-wire UART communication
A
Annie_wang 已提交
17

A
Annie_wang 已提交
18
![image1](figures/2-wire-uart-communication.png "2-wire-uart-communication")
A
Annie_wang 已提交
19

A
Annie_wang 已提交
20
**Figure 2** Four-wire UART communication
A
Annie_wang 已提交
21

A
Annie_wang 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
 ![image2](figures/4-wire-uart-communication.png "4-wire-uart-communication")

The UART transmitter and receiver must have the same settings on particular attributes, such as the baud rate and data format (start bit, data bits, parity bit, and stop bit) before they start to communicate. A UART sends data to the peer end over the TX and receives data from the peer end over the RX. When the size of the buffer used by a UART for storing received data reaches the preset threshold, the RTS signal of the UART changes to **1** (data cannot be received), and the peer UART stops sending data to it because its CTS signal does not allow it to send data.

### Basic Concepts

- Asynchronous communication

  In asynchronous communication, data is transmitted in frames of characters or bytes. Frames are sent and received one by one through the transmission line. The transmitter and receiver have their own clocks to control data sending and receiving. The two clock sources are independent and not synchronized with each other. 

  When data is sent one character at a time, the time interval between two characters is not fixed, but the time interval between two adjacent bits in a character frame is fixed.

- Full-duplex transmission

  A duplex communication mode allows data to be transmitted in both directions at the same time. A duplex communication channel is equivalent to two simplex communication channels operating in opposite directions at the same time. In full-duplex mode, signals can be transmitted bidirectionally at the same time.

### Working Principles

In the Hardware Driver Foundation (HDF), the UART uses the independent service mode (see Figure 3) for API adaptation. In this mode, each device independently publishes a service to process external access requests. When receiving an access request, the HDF DeviceManager extracts parameters from the request to call the internal APIs of the target device. In the independent service mode, the HDF DeviceManager provides service management capabilities. However, you need to configure a node for each device, which increases memory usage.

In the independent service mode, the core layer does not publish a service for the upper layer. Therefore, a service must be published for each controller. To achieve this purpose:

- You need to implement the **Bind()** function in **HdfDriverEntry** to bind services.
- The **policy** field of **deviceNode** in the **device_info.hcs** file can be **1** or **2**, but not **0**.

The UART module is divided into the following layers:

- Interface layer: provides APIs for opening or closing a UART device, reading or writing data of the specified length, setting or obtaining the baud rate or attributes of a UART device, and setting the transmission mode.
- Core layer: provides the capabilities of adding or removing a UART controller, and managing UART devices. The core layer interacts with the adaptation layer through hook functions.
- Adaptation layer: instantiates the hook functions to implement specific features.

**Figure 3** Independent service mode

![image3](figures/independent-service-mode.png)

## Development Guidelines

### When to Use

The UART module is widely used to implement low-speed serial communication between devices, for example, output the printing information. It can also connect to a variety of external GPS and Bluetooth devices. Before using your UART devices with OpenHarmony, you need to perform UART driver adaptation.

### Available APIs

To enable the upper layer to successfully operate the PWM controller by calling the UART APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/uart/uart_core.h** for the core layer. You need to implement these hook functions at the adaptation layer and hook them to implement the interaction between the interface layer and the core layer.

**UartHostMethod**:

```c
D
duangavin123 已提交
70
struct UartHostMethod {
A
Annie_wang 已提交
71 72 73 74 75 76 77 78 79 80
    int32_t (*Init)(struct UartHost *host);
    int32_t (*Deinit)(struct UartHost *host);
    int32_t (*Read)(struct UartHost *host, uint8_t *data, uint32_t size);
    int32_t (*Write)(struct UartHost *host, uint8_t *data, uint32_t size);
    int32_t (*GetBaud)(struct UartHost *host, uint32_t *baudRate);
    int32_t (*SetBaud)(struct UartHost *host, uint32_t baudRate);
    int32_t (*GetAttribute)(struct UartHost *host, struct UartAttribute *attribute);
    int32_t (*SetAttribute)(struct UartHost *host, struct UartAttribute *attribute);
    int32_t (*SetTransMode)(struct UartHost *host, enum UartTransMode mode);
    int32_t (*pollEvent)(struct UartHost *host, void *filep, void *table);
D
duangavin123 已提交
81 82 83
};
```

A
Annie_wang 已提交
84
**Table 1** Hook functions in UartHostMethod
A
Annie_wang 已提交
85

A
Annie_wang 已提交
86
| Function| Input Parameter| Output Parameter| Return Value| Description|
A
Annie_wang 已提交
87
| -------- | -------- | -------- | -------- | -------- |
A
Annie_wang 已提交
88 89
| Init | **host**: structure pointer to the UART controller at the core layer.| –| HDF_STATUS| Initializes a UART device.|
| Deinit | **host**: structure pointer to the UART controller at the core layer.| –| HDF_STATUS| Deinitializes a UART device.|
A
Annie_wang 已提交
90 91 92 93 94 95 96 97
| Read | **host**: structure pointer to the UART controller at the core layer.<br>**size**: size of the data to read, which is of the uint32_t type.| **data**: pointer to the data read, which is of the uint8_t type. | HDF_STATUS| Reads data.|
| Write | **host**: structure pointer to the UART controller at the core layer.<br>**data**: pointer to the data to write, which is of the uint8_t type.<br>**size**: size of the data to write, which is of the uint32_t type.| –| HDF_STATUS| Writes data.|
| SetBaud | **host**: structure pointer to the UART controller at the core layer.<br>**baudRate**: baud rate to set, which is of the uint32_t type.| –| HDF_STATUS| Sets the baud rate.|
| GetBaud | **host**: structure pointer to the UART controller at the core layer.| **baudRate**: pointer to the baud rate obtained, which is of the uint32_t type.| HDF_STATUS| Obtains the baud rate.|
| GetAttribute | **host**: structure pointer to the UART controller at the core layer.| **attribute**: structure pointer to the attributes obtained. For details, see **UartAttribute** in **uart_if.h**.| HDF_STATUS| Obtains UART attributes.|
| SetAttribute | **host**: structure pointer to the UART controller at the core layer.<br>**attribute**: structure pointer to the attributes to set.| –| HDF_STATUS| Sets UART attributes.|
| SetTransMode | **host**: structure pointer to the UART controller at the core layer.<br>**mode**: transmission mode to set. For details, see **UartTransMode** in **uart_if.h**.| –| HDF_STATUS| Sets the UART transmission mode.|
| PollEvent | **host**: structure pointer to the UART controller at the core layer.<br>**filep**: void pointer to a file.<br>**table**: void pointer to the poll_table.| –| HDF_STATUS| Polls for the pending events.|
A
Annie_wang 已提交
98

A
Annie_wang 已提交
99
### How to Develop
A
annie_wangli 已提交
100

A
Annie_wang 已提交
101
The UART module adaptation procedure is as follows:
A
annie_wangli 已提交
102

A
Annie_wang 已提交
103 104 105
1. Instantiate the driver entry.
2. Configure attribute files.
3. Instantiate the UART controller object.
A
Annie_wang 已提交
106 107
4. Debug the driver.

A
Annie_wang 已提交
108
### Example
A
Annie_wang 已提交
109

A
Annie_wang 已提交
110
The following uses the **//device_soc_hisilicon/common/platform/uart/uart_hi35xx.c** driver of the Hi3516D V300 development board as an example to describe the UART driver adaptation.
A
Annie_wang 已提交
111

A
Annie_wang 已提交
112 113
1. Instantiate the driver entry.

A
Annie_wang 已提交
114 115
   The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **hdf_device_desc.h**), and the value of **moduleName** must be the same as that in **device_info.hcs**. In the HDF, the start address of each **HdfDriverEntry** object of all loaded drivers is collected to form a segment address space similar to an array for the upper layer to invoke.
   Generally, the HDF calls **Bind()** and then **Init()** to load a driver. If **Init()** fails to be called, the HDF calls **Release()** to release driver resources and exit.
A
Annie_wang 已提交
116

A
Annie_wang 已提交
117
   UART driver entry example:
A
Annie_wang 已提交
118 119

   ```c
A
Annie_wang 已提交
120 121
   struct HdfDriverEntry g_hdfUartDevice = {
       .moduleVersion = 1,
A
Annie_wang 已提交
122 123 124 125
       .moduleName = "HDF_PLATFORM_UART",   // (Mandatory) The value must be the same as that of moduleName in the .hcs file.
       .Bind = HdfUartDeviceBind,           // See the Bind function.
       .Init = HdfUartDeviceInit,           // See the Init function.
       .Release = HdfUartDeviceRelease,     // See the Release function.
A
Annie_wang 已提交
126
   };
A
Annie_wang 已提交
127
   HDF_INIT(g_hdfUartDevice);               // Call HDF_INIT to register the driver entry with the HDF.
A
Annie_wang 已提交
128 129
   ```

A
Annie_wang 已提交
130
2. Configure attribute files.
A
Annie_wang 已提交
131

A
Annie_wang 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
   Add the deviceNode information to the **device_info.hcs** file. The deviceNode information is related to the driver entry registration. The following example uses two UART controllers as an example. If there are more UART controllers, add the deviceNode information to the **device_info.hcs** file for each controller. The device attribute values configured in **uart_config.hcs** are closely related to default values or value ranges of the **UartHost** members at the core layer.

   - **device_info.hcs** example:

      Add the deviceNode information to the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file.

      ```c
      root {
          device_info {
              match_attr = "hdf_manager";
              platform :: host {
                  hostName = "platform_host";
                  priority = 50;
                  device_uart :: device {
                      device0 :: deviceNode {
                          policy = 1;                                 // The value 1 means to publish services only to the kernel-mode processes.
                          priority = 40;                              // Driver startup priority.
                          permission = 0644;                          // Permission for the device node created.
                          moduleName = "HDF_PLATFORM_UART";           // Driver name, which must be the same as moduleName in the HdfDriverEntry structure.
                          serviceName = "HDF_PLATFORM_UART_0";        // Unique name of the service published by the driver. The name is in the HDF_PLATFORM_UART_X format. X indicates the UART controller number.
                          deviceMatchAttr = "hisilicon_hi35xx_uart_0";// Keyword for matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver.
                      }
                      device1 :: deviceNode {
                        policy = 2;                                   // The value 2 means to publish services for both kernel- and user-mode processes.
                        permission = 0644;
                        priority = 40;
                        moduleName = "HDF_PLATFORM_UART"; 
                        serviceName = "HDF_PLATFORM_UART_1";
                        deviceMatchAttr = "hisilicon_hi35xx_uart_1";
                      }
                      ...
                  }
              }
          }
      }
      ```

   - **uart_config.hcs** example

      Configure the device attributes in the **//device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/uart/uart_config.hcs** file. The parameters are as follows:

      ```c
      root {
          platform {
              template uart_controller {                   // Template configuration. If the template is used to configure device node information, the default values in the template will be used for the fields that are not declared for the node.
                  match_attr = "";
                  num = 0;                                 // (Mandatory) Port number.
                  baudrate = 115200;                       // (Mandatory) Baud rate.
                  fifoRxEn = 1;                            // (Mandatory) Enable RX FIFO.
                  fifoTxEn = 1;                            // (Mandatory) Enable TX FIFO.
                  flags = 4;                               // (Mandatory) flag signal.
                  regPbase = 0x120a0000;                   // (Mandatory) Register physical base address used for address mapping.
                  interrupt = 38;                          // (Mandatory) Interrupt number.
                  iomemCount = 0x48;                       // (Mandatory) Used for address mapping.
              }
              controller_0x120a0000 :: uart_controller {
                  match_attr = "hisilicon_hi35xx_uart_0";  // (Mandatory) The value must be the same as that of deviceMatchAttr of the device in device_info.hcs.
              }
              controller_0x120a1000 :: uart_controller {
                  num = 1;
                  baudrate = 9600;
                  regPbase = 0x120a1000;
                  interrupt = 39;
                  match_attr = "hisilicon_hi35xx_uart_1";
              }
              ...                                          // Add node information for more UART devices.
          }
      }
      ```

      After the **uart_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.

      ```c
      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/uart/uart_config.hcs" // Relative path of the file.
A
Annie_wang 已提交
206
      ```
A
Annie_wang 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222

3. Instantiate the UART controller object.

   Initialize the **UartHost** object at the core layer, including defining a custom structure (to pass parameters and data) and implementing the **HdfDriverEntry** member functions (**Bind**, **Init** and **Release**) to instantiate **UartHostMethod** in **UartHost** (so that the underlying driver functions can be called).

   - Define a custom structure.

      To the driver, the custom structure holds parameters and data. The **DeviceResourceIface** method provided by the HDF reads the values in the **uart_config.hcs** file to initialize the members in the custom structure and passes important parameters, such as the UART port number, to the object at the core layer.

      ```c
      struct UartPl011Port {                       // Pin description structure customized.
          int32_t enable;
          unsigned long physBase;                  // Physical base address.
          uint32_t irqNum;                         // IRQ number.
          uint32_t defaultBaudrate;                // Default baud rate.
          uint32_t flags;                          // Flag signals related to the following three macros.
A
Annie_wang 已提交
223 224 225
      #define PL011_FLG_IRQ_REQUESTED    (1 << 0)
      #define PL011_FLG_DMA_RX_REQUESTED (1 << 1)
      #define PL011_FLG_DMA_TX_REQUESTED (1 << 2)
A
Annie_wang 已提交
226 227
          struct UartDmaTransfer *rxUdt;           // DMA transfer.
          struct UartDriverData *udd;
A
Annie_wang 已提交
228
      };
A
Annie_wang 已提交
229 230 231 232 233 234 235 236
      struct UartDriverData {                      // Structure related to data transfer
          uint32_t num;                            // Port number.
          uint32_t baudrate;                       // Baud rate (configurable).
          struct UartAttribute attr;               // Attributes, such as the data bits and stop bit of the data to transfer.
          struct UartTransfer *rxTransfer;         // Buffer structure (FIFO structure)
          wait_queue_head_t wait;                  // Queuing signal related to conditional variables
          int32_t count;                           // Data count.
          int32_t state;                           // UART controller state.
A
Annie_wang 已提交
237 238 239 240
      #define UART_STATE_NOT_OPENED 0
      #define UART_STATE_OPENING    1
      #define UART_STATE_USEABLE    2
      #define UART_STATE_SUSPENDED  3
A
Annie_wang 已提交
241
          uint32_t flags;                          // Status flags.
A
Annie_wang 已提交
242 243 244
      #define UART_FLG_DMA_RX       (1 << 0)
      #define UART_FLG_DMA_TX       (1 << 1)
      #define UART_FLG_RD_BLOCK     (1 << 2)
A
Annie_wang 已提交
245 246 247
          RecvNotify recv;                         // Pointer to the function that receives serial port data.
          struct UartOps *ops;                     // Custom function pointer structure.
          void *private;                           // Private data.
A
Annie_wang 已提交
248 249 250 251
      };
      
      // UartHost is the controller structure at the core layer. The Init function assigns values to the members of UartHost.
      struct UartHost {
A
Annie_wang 已提交
252 253 254 255 256 257
          struct IDeviceIoService service;         // Driver service.
          struct HdfDeviceObject *device;          // Driver device object.
          uint32_t num;                            // Port number.
          OsalAtomic atom;                         // Atomic quantity.
          void *priv;                              // Private data.
          struct UartHostMethod *method;           // Callback functions.
A
Annie_wang 已提交
258 259
      };
      ```
A
Annie_wang 已提交
260

A
Annie_wang 已提交
261
   - Instantiate **UartHostMethod** in **UartHost**.
A
Annie_wang 已提交
262

A
Annie_wang 已提交
263 264
      ```c
      // Instantiate the hook functions in uart_hi35xx.c.
A
Annie_wang 已提交
265
      struct UartHostMethod g_uartHostMethod = {
A
Annie_wang 已提交
266 267 268 269 270 271 272 273 274 275
          .Init = Hi35xxInit,                     // Initialize the device.
          .Deinit = Hi35xxDeinit,                 // Deinitialize the device.
          .Read = Hi35xxRead,                     // Receive data.
          .Write = Hi35xxWrite,                   // Write data.
          .SetBaud = Hi35xxSetBaud,               // Set the baud rate.
          .GetBaud = Hi35xxGetBaud,               // Obtain the baud rate.
          .SetAttribute = Hi35xxSetAttribute,     // Set device attributes.
          .GetAttribute = Hi35xxGetAttribute,     //Obtain device attributes.
          .SetTransMode = Hi35xxSetTransMode,     // Set the transmission mode.
          .pollEvent = Hi35xxPollEvent,           // Polling for pending events.
A
Annie_wang 已提交
276 277 278
      };
      ```

A
Annie_wang 已提交
279
   - Implement the **Bind** function.
A
Annie_wang 已提交
280

A
Annie_wang 已提交
281
      Input parameter:
A
Annie_wang 已提交
282

A
Annie_wang 已提交
283
      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
A
annie_wangli 已提交
284

A
Annie_wang 已提交
285
      Return value:
A
annie_wangli 已提交
286

A
Annie_wang 已提交
287 288 289
      **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **//drivers/hdf_core/framework/include/utils/hdf_base.h** file.

      **Table 2** HDF_STATUS
A
annie_wangli 已提交
290

A
Annie_wang 已提交
291
      | Status| Description|
A
Annie_wang 已提交
292
      | -------- | -------- |
A
Annie_wang 已提交
293 294 295 296 297 298
      | HDF_ERR_INVALID_OBJECT | Invalid controller object.|
      | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.|
      | HDF_ERR_INVALID_PARAM | Invalid parameter.|
      | HDF_ERR_IO | I/O error.|
      | HDF_SUCCESS | Initialization successful.|
      | HDF_FAILURE | Initialization failed.|
A
Annie_wang 已提交
299

A
Annie_wang 已提交
300
      Function description:
A
Annie_wang 已提交
301 302 303

      Initializes the custom structure object and **UartHost**.

A
Annie_wang 已提交
304
      ```c
A
Annie_wang 已提交
305 306 307 308
      //uart_hi35xx.c
      static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device)
      {
          ...
A
Annie_wang 已提交
309
          return (UartHostCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS; // (Mandatory) Call UartHostCreate.
A
Annie_wang 已提交
310
      }
A
Annie_wang 已提交
311

A
Annie_wang 已提交
312 313 314
      // Description of UartHostCreate() in uart_core.c
      struct UartHost *UartHostCreate(struct HdfDeviceObject *device)
      {
A
Annie_wang 已提交
315 316 317
          struct UartHost *host = NULL                                         // Create UartHost.
          ...                                                                  
          host = (struct UartHost *)OsalMemCalloc(sizeof(*host));              // Allocate memory.
A
Annie_wang 已提交
318
          ...
A
Annie_wang 已提交
319 320 321 322
          host->device = device;                                               // (Mandatory) Prerequisites for conversion between HdfDeviceObject and UartHost.
          device->service = &(host->service);                                  // (Mandatory) Prerequisites for conversion between HdfDeviceObject and UartHost.
          host->device->service->Dispatch = UartIoDispatch;                    // Assign values to Dispatch() of service.
          OsalAtomicSet(&host->atom, 0);                                       // Initialize or set the atomic service.
A
Annie_wang 已提交
323 324 325 326 327 328
          host->priv = NULL;
          host->method = NULL;
          return host;
      }
      ```

A
Annie_wang 已提交
329
   - Implement the **Init** function.
A
Annie_wang 已提交
330

A
Annie_wang 已提交
331
      Input parameter:
A
Annie_wang 已提交
332

A
Annie_wang 已提交
333
      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.
A
Annie_wang 已提交
334

A
Annie_wang 已提交
335
      Return value:
A
Annie_wang 已提交
336

A
Annie_wang 已提交
337
      HDF_STATUS
A
Annie_wang 已提交
338

A
Annie_wang 已提交
339
      Function description:
A
Annie_wang 已提交
340

A
Annie_wang 已提交
341
      Initialize the custom structure and **UartHost**, calls **UartAddDev()** at the core layer to add the UART controller, and accesses the VFS.
A
Annie_wang 已提交
342

A
Annie_wang 已提交
343
      ```c
A
Annie_wang 已提交
344 345 346 347 348 349
      int32_t HdfUartDeviceInit(struct HdfDeviceObject *device)
      {
          int32_t ret;
          struct UartHost *host = NULL;
          HDF_LOGI("%s: entry", __func__);
          ...
A
Annie_wang 已提交
350 351 352 353 354
          host = UartHostFromDevice(device);                                           // Forcibly convert to UartHost by using service. The values are assigned by Bind().
          ...                                    
          ret = Hi35xxAttach(host, device);                                            // Initialize the UartHost object.
          ...                                    
          host->method = &g_uartHostMethod;                                            // Attach the UartHostMethod instance.
A
Annie_wang 已提交
355 356 357 358 359 360
          return ret;
      }
      // Initialize UartHost.
      static int32_t Hi35xxAttach(struct UartHost *host, struct HdfDeviceObject *device)
      {
          int32_t ret;
A
Annie_wang 已提交
361
          struct UartDriverData *udd = NULL;                                           // udd and port are custom structure objects. You can implement features as required.
A
Annie_wang 已提交
362 363
          struct UartPl011Port *port = NULL;
          ...
A
Annie_wang 已提交
364 365
          // Steps 1 to 7 assign values to the udd object and then UartHost.
          udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd));                  // Step 1
A
Annie_wang 已提交
366
          ...
A
Annie_wang 已提交
367
          port = (struct UartPl011Port *)OsalMemCalloc(sizeof(struct UartPl011Port));  // Step 2
A
Annie_wang 已提交
368
          ...
A
Annie_wang 已提交
369 370 371 372 373
          udd->ops = Pl011GetOps();                                                    // Step 3 Hook the functions for opening or closing a device, setting device attributes, and sending data.
          udd->recv = PL011UartRecvNotify;                                             // Step 4 Hook the data receiving notification function (conditional lock mechanism).
          udd->count = 0;                                                              // Step 5.
          port->udd = udd;                                                             // Step 6 Prerequisites for conversion between UartPl011Port and UartDriverData.
          ret = UartGetConfigFromHcs(port, device->property);                          // Pass the attributes of HdfDeviceObject to the custom structure to perform related operations. The sample code is as follows:
A
Annie_wang 已提交
374
          ...
A
Annie_wang 已提交
375 376 377 378
          udd->private = port;                                                         // Step 7
          host->priv = udd;                                                            // (Mandatory) Prerequisites for conversion between UartHost and UartDriverData.
          host->num = udd->num;                                                        // (Mandatory) UART device number.
          UartAddDev(host);                                                            // (Mandatory) Function in uart_dev.c at the core layer used to register a character device node to the VFS so that the UART can be accessed through the virtual file node in user mode. 
A
Annie_wang 已提交
379 380 381 382 383 384 385 386 387
          return HDF_SUCCESS;
      }
      
      static int32_t UartGetConfigFromHcs(struct UartPl011Port *port, const struct DeviceResourceNode *node)
      {
          uint32_t tmp, regPbase, iomemCount;
          struct UartDriverData *udd = port->udd;
          struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 
          ...
A
Annie_wang 已提交
388
          // Extract the values based on the request and assign the values to the custom structures.
A
Annie_wang 已提交
389 390 391 392 393 394 395 396 397
          if (iface->GetUint32(node, "num", &udd->num, 0) != HDF_SUCCESS) {
              HDF_LOGE("%s: read busNum fail", __func__);
              return HDF_FAILURE;
          }
          ...
          return 0;
          }
      ```

A
Annie_wang 已提交
398
   - Implement the **Release** function.
A
Annie_wang 已提交
399

A
Annie_wang 已提交
400
      Input parameter:
A
Annie_wang 已提交
401

A
Annie_wang 已提交
402 403 404
      **HdfDeviceObject**, a device object created by the HDF for each driver, holds device-related private data and service APIs.

      Return value:
A
Annie_wang 已提交
405 406 407

      No value is returned.

A
Annie_wang 已提交
408
      Function description:
A
Annie_wang 已提交
409

A
Annie_wang 已提交
410
      Releases the memory and deletes the controller. This function assigns values to **Release()** in the driver entry structure. When the HDF fails to call **Init()** to initialize the driver, **Release()** is called to release driver resources.
A
Annie_wang 已提交
411

A
Annie_wang 已提交
412 413 414
      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
      > All forced conversion operations for obtaining the corresponding object can be successful only when **Init()** has the corresponding value assignment operations.

A
Annie_wang 已提交
415
      ```c
A
Annie_wang 已提交
416 417 418 419
      void HdfUartDeviceRelease(struct HdfDeviceObject *device)
      {
          struct UartHost *host = NULL;
          ...
A
Annie_wang 已提交
420 421 422 423 424 425
          host = UartHostFromDevice(device);           // Forcible conversion from HdfDeviceObject to UartHost through the service member. For details about the value assignment, see the Bind function.
          ...                                          
          if (host->priv != NULL) {                    
              Hi35xxDetach(host);                      // Customized memory release function. For details, see the following.
          }                                            
          UartHostDestroy(host);                       // Call the core layer function to release the host.
A
Annie_wang 已提交
426 427 428 429 430 431 432
      }
      
      static void Hi35xxDetach(struct UartHost *host)
      {
          struct UartDriverData *udd = NULL;
          struct UartPl011Port *port = NULL;
          ...
A
Annie_wang 已提交
433 434 435 436 437 438 439
          udd = host->priv;                            // The conversion from UartHost to UartDriverData is involved.
          ...                                          
          UartRemoveDev (host);                        // Remove the VFS.
          port = udd->private;                         // The conversion from UartDriverData to UartPl011Port is involved.
          if (port != NULL) {                          
              if (port->physBase != 0) {               
                  OsalIoUnmap((void *)port->physBase); // Unmap addresses.
A
Annie_wang 已提交
440 441 442 443
              }
              OsalMemFree(port);
              udd->private = NULL;
          }
A
Annie_wang 已提交
444
          OsalMemFree (udd);                           // Release UartDriverData.
A
Annie_wang 已提交
445 446 447
          host->priv = NULL;
      }
      ```
A
Annie_wang 已提交
448 449 450 451

4. Debug the driver.

   (Optional) For new drivers, verify basic functions, for example, check the information returned after the driver is attached and whether data is successfully transmitted.