1# UART 2 3 4## Overview 5 6In the Hardware Driver Foundation (HDF), the Universal Asynchronous Receiver/Transmitter (UART) uses the independent service mode 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. 7 8 **Figure 1** Independent service mode 9 10  11 12 13## Available APIs 14 15**UartHostMethod**: 16 17 18``` 19struct UartHostMethod { 20 int32_t (*Init)(struct UartHost *host); 21 int32_t (*Deinit)(struct UartHost *host); 22 int32_t (*Read)(struct UartHost *host, uint8_t *data, uint32_t size); 23 int32_t (*Write)(struct UartHost *host, uint8_t *data, uint32_t size); 24 int32_t (*GetBaud)(struct UartHost *host, uint32_t *baudRate); 25 int32_t (*SetBaud)(struct UartHost *host, uint32_t baudRate); 26 int32_t (*GetAttribute)(struct UartHost *host, struct UartAttribute *attribute); 27 int32_t (*SetAttribute)(struct UartHost *host, struct UartAttribute *attribute); 28 int32_t (*SetTransMode)(struct UartHost *host, enum UartTransMode mode); 29 int32_t (*pollEvent)(struct UartHost *host, void *filep, void *table); 30}; 31``` 32 33 **Table 1** Description of the callback functions in UartHostMethod 34 35| Function| Input Parameter| Output Parameter| Return Value| Description| 36| -------- | -------- | -------- | -------- | -------- | 37| Init | **host**: structure pointer to the UART controller at the core layer.| –| HDF_STATUS| Initializes a UART device.| 38| Deinit | **host**: structure pointer to the UART controller at the core layer.| –| HDF_STATUS| Deinitializes a UART device.| 39| Read | **host**: structure pointer to the UART controller at the core layer.<br>**size**: data size, which is of the uint32_t type.| **data**: pointer to the data read. The value is of the uint8_t type. | HDF_STATUS| Reads data.| 40| Write | **host**: structure pointer to the UART controller at the core layer.<br>**data**: pointer to the data to write. The value is of the uint8_t type.<br>**size**: data size, which is of the uint32_t type. | –| HDF_STATUS| Writes data.| 41| SetBaud | **host**: structure pointer to the UART controller at the core layer.<br>**baudRate**: pointer to the baud rate to set. The value is of the uint32_t type. | –| HDF_STATUS| Sets the baud rate.| 42| GetBaud | **host**: structure pointer to the UART controller at the core layer.| **baudRate**: pointer to the baud rate obtained. The value is of the uint32_t type. | HDF_STATUS| Obtains the current baud rate.| 43| GetAttribute | **host**: structure pointer to the UART controller at the core layer.| **attribute**: structure pointer to the attribute obtained. For details, see **UartAttribute** in **uart_if.h**. | HDF_STATUS| Obtains UART attributes.| 44| SetAttribute | **host**: structure pointer to the UART controller at the core layer.<br>**attribute**: structure pointer to the attribute to set. | –| HDF_STATUS| Sets UART attributes.| 45| SetTransMode | **host**: structure pointer to the UART controller at the core layer.<br>**mode**: transfer mode to set. For details, see **UartTransMode** in **uart_if.h**.| –| HDF_STATUS| Sets the UART transfer mode.| 46| PollEvent | **host**: structure pointer to the UART controller at the core layer.<br>**filep**: void pointer to a file.<br>**table**: void pointer to poll_table.| –| HDF_STATUS| Polls for pending events.| 47 48 49## How to Develop 50 51The UART module adaptation involves the following steps: 52 531. Instantiate the driver entry. 54 - Instantiate the **HdfDriverEntry** structure. 55 - Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF. 56 572. Configure attribute files. 58 - Add the **deviceNode** information to the **device_info.hcs** file. 59 - (Optional) Add the **uart_config.hcs** file. 60 613. Instantiate the UART controller object. 62 - Initialize **UartHost**. 63 - Instantiate **UartHostMethod** in the **UartHost** object. 64 >  **NOTE**<br> 65 > For details about the functions in **UartHostMethod**, see [Available APIs](#available-apis). 66 674. Debug the driver. 68 69 (Optional) For new drivers, verify the basic functions, such as the UART status control and response to interrupts. 70 71 72## Development Example 73 74The following uses **uart_hi35xx.c** as an example to present the information required for implementing device functions. 75 761. Instantiate the driver entry. 77 78 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**. 79 80 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. 81 82 Generally, the HDF calls the **Bind** function and then the **Init** function to load a driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit. 83 84 UART driver entry example: 85 86 ``` 87 struct HdfDriverEntry g_hdfUartDevice = { 88 .moduleVersion = 1, 89 .moduleName = "HDF_PLATFORM_UART", // (Mandatory) The value must be the same as that in the .hcs file. 90 .Bind = HdfUartDeviceBind, // See the Bind function. 91 .Init = HdfUartDeviceInit, // See the Init function. 92 .Release = HdfUartDeviceRelease, //See the Release function. 93 }; 94 // Call HDF_INIT to register the driver entry with the HDF. 95 HDF_INIT(g_hdfUartDevice); 96 ``` 97 982. Add the **deviceNode** information to the **device_info.hcs** file and configure the device attributes in the **uart_config.hcs** file. 99 100 The **deviceNode** information is related to registration of the driver entry. The device attribute values are closely related to the default values or value ranges of the **UartHost** members at the core layer. 101 102 In this example, there is only one UART controller. If there are multiple UART controllers, you need to add the **deviceNode** information to the **device_info** file and add the corresponding device attributes to the **uart_config** file for each controller. 103 104 - **device_info.hcs** configuration example: 105 106 107 ``` 108 root { 109 device_info { 110 match_attr = "hdf_manager"; 111 platform :: host { 112 hostName = "platform_host"; 113 priority = 50; 114 device_uart :: device { 115 device0 :: deviceNode { 116 policy = 1; // The driver publishes services only for kernel-mode processes. 117 priority = 40; // Driver startup priority. 118 permission = 0644; // Permission for the driver to create a device node. 119 moduleName = "HDF_PLATFORM_UART"; // Driver name, which must be the same as moduleName in the HdfDriverEntry structure. 120 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. 121 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. 122 } 123 device1 :: deviceNode { 124 policy = 2; // The driver publishes services for both kernel- and user-mode processes. 125 permission = 0644; 126 priority = 40; 127 moduleName = "HDF_PLATFORM_UART"; 128 serviceName = "HDF_PLATFORM_UART_1"; 129 deviceMatchAttr = "hisilicon_hi35xx_uart_1"; 130 } 131 ... 132 } 133 } 134 } 135 } 136 ``` 137 138 - **uart_config.hcs** configuration example 139 140 141 ``` 142 root { 143 platform { 144 template uart_controller { // Template configuration. In the template, you can configure the common parameters shared by device nodes. 145 match_attr = ""; 146 num = 0; // (Mandatory) Device number. 147 baudrate = 115200; // (Mandatory) Baud rate. Set the value based on service requirements. 148 fifoRxEn = 1; // (Mandatory) Enable FIFOs to be received. 149 fifoTxEn = 1; // (Mandatory) Enable FIFOs to be transferred. 150 flags = 4; // (Mandatory) Flag signal. 151 regPbase = 0x120a0000; // (Mandatory) Used for address mapping. 152 interrupt = 38; // (Mandatory) Interrupt number. 153 iomemCount = 0x48; // (Mandatory) Used for address mapping. 154 } 155 controller_0x120a0000 :: uart_controller { 156 match_attr = "hisilicon_hi35xx_uart_0";// (Mandatory) The value must be the same as that of deviceMatchAttr of the corresponding device in device_info.hcs. 157 } 158 controller_0x120a1000 :: uart_controller { 159 num = 1; 160 baudrate = 9600; 161 regPbase = 0x120a1000; 162 interrupt = 39; 163 match_attr = "hisilicon_hi35xx_uart_1"; 164 } 165 ... 166 //(Optional) Add more controller data. The node information must have been added in the device_info.hcs file. 167 } 168 } 169 ``` 170 1713. 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). 172 173 - Defining a custom structure 174 175 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 device number, to the **UartHost** object at the core layer. 176 177 178 ``` 179 struct UartPl011Port { // Interface structure 180 int32_t enable; 181 unsigned long physBase; // Physical address 182 uint32_t irqNum; // Interrupt number 183 uint32_t defaultBaudrate; // Default baud rate 184 uint32_t flags; // Flags related to the following three macros 185 #define PL011_FLG_IRQ_REQUESTED (1 << 0) 186 #define PL011_FLG_DMA_RX_REQUESTED (1 << 1) 187 #define PL011_FLG_DMA_TX_REQUESTED (1 << 2) 188 struct UartDmaTransfer *rxUdt; // DMA transfer 189 struct UartDriverData *udd; // The data structure is defined as follows: 190 }; 191 struct UartDriverData { // Structure related to data transfer 192 uint32_t num; 193 uint32_t baudrate; // Baud rate (configurable) 194 struct UartAttribute attr; // Attributes, such as the data bit and stop bit, related to data transfer. 195 struct UartTransfer *rxTransfer; // Buffer (FIFO structure) 196 wait_queue_head_t wait; // Queuing signal related to conditional variables 197 int32_t count; // Data count 198 int32_t state; // UART controller state 199 #define UART_STATE_NOT_OPENED 0 200 #define UART_STATE_OPENING 1 201 #define UART_STATE_USEABLE 2 202 #define UART_STATE_SUSPENDED 3 203 uint32_t flags; // Status flags 204 #define UART_FLG_DMA_RX (1 << 0) 205 #define UART_FLG_DMA_TX (1 << 1) 206 #define UART_FLG_RD_BLOCK (1 << 2) 207 RecvNotify recv; // Pointer to the function that receives serial port data. 208 struct UartOps *ops; // Custom function pointer structure. For details, see device/hisilicon/drivers/uart/uart_pl011.c. 209 void *private; // It stores the pointer to the start address of UartPl011Port for easy invocation. 210 }; 211 212 // UartHost is the controller structure at the core layer. The Init function assigns values to the members of UartHost. 213 struct UartHost { 214 struct IDeviceIoService service; 215 struct HdfDeviceObject *device; 216 uint32_t num; 217 OsalAtomic atom; 218 void *priv; // It stores the pointer to the start address of the vendor's custom structure for easy invocation. 219 struct UartHostMethod *method; // Hook at the core layer. You need to implement and instantiate its member functions. 220 }; 221 ``` 222 223 - Instantiating **UartHostMethod** in **UartHost** (other members are initialized by **Bind**) 224 225 226 ``` 227 // Example in uart_hi35xx.c: instantiate the hook. 228 struct UartHostMethod g_uartHostMethod = { 229 .Init = Hi35xxInit, 230 .Deinit = Hi35xxDeinit, 231 .Read = Hi35xxRead, 232 .Write = Hi35xxWrite, 233 .SetBaud = Hi35xxSetBaud, 234 .GetBaud = Hi35xxGetBaud, 235 .SetAttribute = Hi35xxSetAttribute, 236 .GetAttribute = Hi35xxGetAttribute, 237 .SetTransMode = Hi35xxSetTransMode, 238 .pollEvent = Hi35xxPollEvent, 239 }; 240 ``` 241 242 - **Bind** function 243 244 **Input parameter**: 245 246 **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information. 247 248 **Return value**: 249 250 **HDF_STATUS**<br/>The table below describes some status. For more information, see **HDF_STATUS** in the **/drivers/framework/include/utils/hdf_base.h** file. 251 252 **Table 2** Description of HDF_STATUS 253 254 | Status| Description| 255 | -------- | -------- | 256 | HDF_ERR_INVALID_OBJECT | Invalid controller object.| 257 | HDF_ERR_MALLOC_FAIL | Failed to allocate memory.| 258 | HDF_ERR_INVALID_PARAM | Invalid parameter.| 259 | HDF_ERR_IO | I/O error.| 260 | HDF_SUCCESS | Initialization successful.| 261 | HDF_FAILURE | Initialization failed.| 262 263 **Function description**: 264 265 Initializes the custom structure object and **UartHost**. 266 267 268 ``` 269 //uart_hi35xx.c 270 static int32_t HdfUartDeviceBind(struct HdfDeviceObject *device) 271 { 272 ... 273 return (UartHostCreate(device) == NULL)? HDF_FAILURE: HDF_SUCCESS;// (Mandatory) Call UartHostCreate. 274 } 275 // Description of UartHostCreate() in uart_core.c 276 struct UartHost *UartHostCreate(struct HdfDeviceObject *device) 277 { 278 struct UartHost *host = NULL; // Create UartHost. 279 ... 280 host = (struct UartHost *)OsalMemCalloc(sizeof(*host));// Allocate memory. 281 ... 282 host->device = device; // (Mandatory) Prerequisites for conversion between HdfDeviceObject and UartHost. 283 device->service = &(host->service; // (Mandatory) Prerequisites for conversion between HdfDeviceObject and UartHost. 284 host->device->service->Dispatch = UartIoDispatch; // Assign values to Dispatch of service. 285 OsalAtomicSet(&host->atom, 0); // Initialize or set the atomic services. 286 host->priv = NULL; 287 host->method = NULL; 288 return host; 289 } 290 ``` 291 292 - **Init** function 293 294 **Input parameter**: 295 296 **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information. 297 298 **Return value**: 299 300 **HDF_STATUS** 301 302 **Function description**: 303 304 Initializes the custom structure object and **UartHost**, calls the **artAddDev** function at the core layer, and connects to the VFS. 305 306 307 ``` 308 int32_t HdfUartDeviceInit(struct HdfDeviceObject *device) 309 { 310 int32_t ret; 311 struct UartHost *host = NULL; 312 HDF_LOGI("%s: entry", __func__); 313 ... 314 host = UartHostFromDevice(device);// Forcibly convert to UartHost by using service. The values are assigned by Bind(). 315 ... 316 ret = Hi35xxAttach(host, device); // Initialize the UartHost object. 317 ... 318 host->method = &g_uartHostMethod; // Attach the UartHostMethod instance. 319 return ret; 320 } 321 // Initialize UartHost. 322 static int32_t Hi35xxAttach(struct UartHost *host, struct HdfDeviceObject *device) 323 { 324 int32_t ret; 325 // udd and port are customized structure objects. Implement the related functions as required. 326 struct UartDriverData *udd = NULL; 327 struct UartPl011Port *port = NULL; 328 ... 329 // Steps 1 to 7 instantiate and assign values to the udd object, and then assign values to UartHost. 330 udd = (struct UartDriverData *)OsalMemCalloc(sizeof(*udd));// Step 1 331 ... 332 port = (struct UartPl011Port *)OsalMemCalloc(sizeof(struct UartPl011Port));// Step 2 333 ... 334 udd->ops = Pl011GetOps(); // Step 3 Hook the functions for starting or stopping a device, setting attributes, and sending data. 335 udd->recv = PL011UartRecvNotify;// Step 4 Hook the data receiving notification function (conditional lock mechanism). 336 udd->count = 0; // Step 5 337 port->udd = udd; // Step 6 Enable conversion between UartPl011Port and UartDriverData. 338 ret = UartGetConfigFromHcs(port, device->property);// Pass the attributes of HdfDeviceObject to the custom structure. 339 // The sample code is as follows: 340 ... 341 udd->private = port; // Step 7 342 343 host->priv = udd; // (Mandatory) Enable conversion between UartHost and UartDriverData. 344 host->num = udd->num; // (Mandatory) UART device number 345 UartAddDev(host); // (Mandatory) Function (in uart_dev.c) 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. 346 return HDF_SUCCESS; 347 } 348 349 static int32_t UartGetConfigFromHcs(struct UartPl011Port *port, const struct DeviceResourceNode *node) 350 { 351 uint32_t tmp, regPbase, iomemCount; 352 struct UartDriverData *udd = port->udd; 353 struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); 354 ... 355 // Extract the values based on the request and assign the values to the custom structure. 356 if (iface->GetUint32(node, "num", &udd->num, 0) != HDF_SUCCESS) { 357 HDF_LOGE("%s: read busNum fail", __func__); 358 return HDF_FAILURE; 359 } 360 ... 361 return 0; 362 } 363 ``` 364 - **Release** function 365 366 **Input parameter**: 367 368 **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs information. 369 370 **Return value**: 371 372 No value is returned. 373 374 **Function description**: 375 376 Releases the memory and deletes the controller. This function assigns values to the **Release** API in the driver entry structure. When the HDF fails to call the **Init** function to initialize the driver, the **Release** function can be called to release driver resources. 377 378 >  **NOTE** 379 > 380 > All forced conversion operations for obtaining the corresponding object can be successful only when **Init()** has the corresponding value assignment operations. 381 382 383 ``` 384 void HdfUartDeviceRelease(struct HdfDeviceObject *device) 385 { 386 struct UartHost *host = NULL; 387 ... 388 host = UartHostFromDevice(device); // Forcibly convert HdfDeviceObject to UartHost by using service. For details about the value assignment, see the Bind function. 389 ... 390 if (host->priv != NULL) { 391 Hi35xxDetach(host); // Customized memory release function. 392 } 393 UartHostDestroy(host); // Call the function of the core layer to release the host. 394 } 395 396 static void Hi35xxDetach(struct UartHost *host) 397 { 398 struct UartDriverData *udd = NULL; 399 struct UartPl011Port *port = NULL; 400 ... 401 udd = host->priv; // The conversion from UartHost to UartDriverData is involved. 402 ... 403 UartRemoveDev (host); // Remove the VFS. 404 port = udd->private; // The conversion from UartDriverData to UartPl011Port is involved. 405 if (port != NULL) { 406 if (port->physBase != 0) { 407 OsalIoUnmap((void *)port->physBase);// Unmap addresses. 408 } 409 OsalMemFree(port); 410 udd->private = NULL; 411 } 412 OsalMemFree (udd); // Release UartDriverData. 413 host->priv = NULL; 414 } 415 ``` 416