1e41f4b71Sopenharmony_ci# DAC 
2e41f4b71Sopenharmony_ci
3e41f4b71Sopenharmony_ci## Overview
4e41f4b71Sopenharmony_ci
5e41f4b71Sopenharmony_ci### DAC
6e41f4b71Sopenharmony_ci
7e41f4b71Sopenharmony_ciA digit-to-analog converter (DAC) is a device that converts a digital signal into an analog signal in electronics.
8e41f4b71Sopenharmony_ci
9e41f4b71Sopenharmony_ciThe DAC module supports development of digital-to-analog conversion. The DAC devices can be used to:
10e41f4b71Sopenharmony_ci
11e41f4b71Sopenharmony_ci- Provide the output channel for the process control computer system and connect to the executor to implement automatic control of the production process.
12e41f4b71Sopenharmony_ci- Serve as an important module in the analog-to-digital converter using feedback technologies.
13e41f4b71Sopenharmony_ci
14e41f4b71Sopenharmony_ci### Basic Concepts
15e41f4b71Sopenharmony_ci
16e41f4b71Sopenharmony_ci- Resolution
17e41f4b71Sopenharmony_ci
18e41f4b71Sopenharmony_ci  The number of binary bits that can be converted by a DAC. A greater number of bits indicates a higher resolution.
19e41f4b71Sopenharmony_ci
20e41f4b71Sopenharmony_ci- Conversion precision
21e41f4b71Sopenharmony_ci
22e41f4b71Sopenharmony_ci  Difference between the actual output value of the DAC and the theoretical value when the maximum value is added to the input end. The conversion precision of a DAC converter varies depending on the structure of the chip integrated on the DAC and the interface circuit configuration. The ideal conversion precision value should be as small as possible. To achieve optimal DAC conversion precision, the DAC must have high resolution. In addition, errors in the devices or power supply of the interface circuits will affect the conversion precision. When the error exceeds a certain degree, a DAC conversion error will be caused.
23e41f4b71Sopenharmony_ci
24e41f4b71Sopenharmony_ci- Conversion speed
25e41f4b71Sopenharmony_ci
26e41f4b71Sopenharmony_ci  The conversion speed is determined by the setup time. The setup time is the period from the time the input suddenly changes from all 0s to all 1s to the time the output voltage remains within the FSR ± ½LSB (or FSR ± x%FSR). It is the maximum response time of the DAC, and hence used to measure the conversion speed.
27e41f4b71Sopenharmony_ci
28e41f4b71Sopenharmony_ci  - The full scale range (FSR) is the maximum range of the output signal amplitude of a DAC. Different DACs have different FSRs, which can be limited by positive and negative currents or voltages.
29e41f4b71Sopenharmony_ci
30e41f4b71Sopenharmony_ci  - The least significant byte (LSB) refers to bit 0 (the least significant bit) in a binary number.
31e41f4b71Sopenharmony_ci
32e41f4b71Sopenharmony_ci### Working Principles
33e41f4b71Sopenharmony_ci
34e41f4b71Sopenharmony_ciIn the Hardware Driver Foundation (HDF), the DAC module uses the unified service mode for API adaptation. In this mode, a device service is used as the DAC manager to handle access requests from the devices of the same type in a unified manner. The unified service mode applies to the scenario where there are many device objects of the same type. If the independent service mode is used in this case, more device nodes need to be configured and more memory resources will be consumed. The DAC module uses the unified service mode, as shown in Figure 1.
35e41f4b71Sopenharmony_ci
36e41f4b71Sopenharmony_ciThe DAC module is divided into the following layers:
37e41f4b71Sopenharmony_ci- Interface layer: provides the capabilities of opening and closing a device and writing data.
38e41f4b71Sopenharmony_ci- Core layer: provides the capabilities of binding, initializing, and releasing devices.
39e41f4b71Sopenharmony_ci- Adaptation layer: implements hardware-related functions, such as controller initialization.
40e41f4b71Sopenharmony_ci
41e41f4b71Sopenharmony_ciIn the unified service mode, the core layer manages all controllers in a unified manner and publishes a service for the interface layer. That is, the driver does not need to publish a service for each controller.
42e41f4b71Sopenharmony_ci
43e41f4b71Sopenharmony_ci>![](../public_sys-resources/icon-note.gif) **NOTE**<br/>The core layer can call the APIs of the interface layer and uses hooks to call APIs of the adaptation layer. In this way, the adaptation layer can indirectly call the APIs of the interface layer, but the interface layer cannot call the APIs of the adaptation layer.
44e41f4b71Sopenharmony_ci
45e41f4b71Sopenharmony_ci**Figure 1** Unified service mode 
46e41f4b71Sopenharmony_ci
47e41f4b71Sopenharmony_ci![](figures/unified-service-mode.png "DAC unified service mode")
48e41f4b71Sopenharmony_ci
49e41f4b71Sopenharmony_ci### Constraints
50e41f4b71Sopenharmony_ci
51e41f4b71Sopenharmony_ciThe DAC module supports only the kernel (LiteOS-A) for mini and small systems.
52e41f4b71Sopenharmony_ci
53e41f4b71Sopenharmony_ci## Development Guidelines
54e41f4b71Sopenharmony_ci
55e41f4b71Sopenharmony_ci### When to Use
56e41f4b71Sopenharmony_ci
57e41f4b71Sopenharmony_ciThe DAC module is used for digital-to-analog conversion, audio output, and motor control. The DAC driver is used when the digital signals input by the DAC module are converted into analog signals to output. Before using DAC devices with OpenHarmony, you need to adapt the DAC driver to OpenHarmony. The following describes how to do it.
58e41f4b71Sopenharmony_ci
59e41f4b71Sopenharmony_ci### Available APIs
60e41f4b71Sopenharmony_ci
61e41f4b71Sopenharmony_ciTo enable the upper layer to successfully operate the hardware by calling the DAC APIs, hook functions are defined in **//drivers/hdf_core/framework/support/platform/include/dac/dac_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.
62e41f4b71Sopenharmony_ci
63e41f4b71Sopenharmony_ciDefinitions of **DacMethod** and **DacLockMethod**:
64e41f4b71Sopenharmony_ci
65e41f4b71Sopenharmony_ci```c++
66e41f4b71Sopenharmony_cistruct DacMethod {
67e41f4b71Sopenharmony_ci    /* Hook used to write data. */
68e41f4b71Sopenharmony_ci    int32_t (*write)(struct DacDevice *device, uint32_t channel, uint32_t val);
69e41f4b71Sopenharmony_ci    /* Hook used to start a DAC device. */
70e41f4b71Sopenharmony_ci    int32_t (*start)(struct DacDevice *device);
71e41f4b71Sopenharmony_ci    /* Hook used to stop a DAC device. */
72e41f4b71Sopenharmony_ci    int32_t (*stop)(struct DacDevice *device);
73e41f4b71Sopenharmony_ci};
74e41f4b71Sopenharmony_ci
75e41f4b71Sopenharmony_cistruct DacLockMethod {
76e41f4b71Sopenharmony_ci    int32_t (*lock)(struct DacDevice *device);
77e41f4b71Sopenharmony_ci    void (*unlock)(struct DacDevice *device);
78e41f4b71Sopenharmony_ci};
79e41f4b71Sopenharmony_ci```
80e41f4b71Sopenharmony_ciAt the adaptation layer, **DacMethod** must be implemented, and **DacLockMethod** can be implemented based on service requirements. The core layer provides the default **DacLockMethod**, in which a spinlock is used to protect the critical section.
81e41f4b71Sopenharmony_ci
82e41f4b71Sopenharmony_ci```c
83e41f4b71Sopenharmony_cistatic int32_t DacDeviceLockDefault(struct DacDevice *device)
84e41f4b71Sopenharmony_ci{
85e41f4b71Sopenharmony_ci    if (device == NULL) {
86e41f4b71Sopenharmony_ci        HDF_LOGE("%s: device is null", __func__);
87e41f4b71Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
88e41f4b71Sopenharmony_ci    }
89e41f4b71Sopenharmony_ci    return OsalSpinLock(&device->spin);
90e41f4b71Sopenharmony_ci}
91e41f4b71Sopenharmony_ci
92e41f4b71Sopenharmony_cistatic void DacDeviceUnlockDefault(struct DacDevice *device)
93e41f4b71Sopenharmony_ci{
94e41f4b71Sopenharmony_ci    if (device == NULL) {
95e41f4b71Sopenharmony_ci        HDF_LOGE("%s: device is null", __func__);
96e41f4b71Sopenharmony_ci        return;
97e41f4b71Sopenharmony_ci    }
98e41f4b71Sopenharmony_ci    (void)OsalSpinUnlock(&device->spin);
99e41f4b71Sopenharmony_ci}
100e41f4b71Sopenharmony_ci
101e41f4b71Sopenharmony_cistatic const struct DacLockMethod g_dacLockOpsDefault = {
102e41f4b71Sopenharmony_ci    .lock = DacDeviceLockDefault,
103e41f4b71Sopenharmony_ci    .unlock = DacDeviceUnlockDefault,
104e41f4b71Sopenharmony_ci};
105e41f4b71Sopenharmony_ci```
106e41f4b71Sopenharmony_ci
107e41f4b71Sopenharmony_ciIf spinlock cannot be used, you can use another type of lock to implement **DacLockMethod**. The implemented **DacLockMethod** will replace the default **DacLockMethod**.
108e41f4b71Sopenharmony_ci
109e41f4b71Sopenharmony_ci**Table 1** Hook functions in **DacMethod**
110e41f4b71Sopenharmony_ci
111e41f4b71Sopenharmony_ci| Function| Input Parameter                                                        | Output Parameter| Return Value            | Description          |
112e41f4b71Sopenharmony_ci| -------- | ------------------------------------------------------------ | ---- | ------------------ | -------------- |
113e41f4b71Sopenharmony_ci| write    | **device**: structure pointer to the DAC controller at the core layer.<br>**channel**: channel ID, which is of the uint32_t type.<br>**val**: data to write, which is of the uint32_t type.| -  | HDF_STATUS| Writes the target digit-to-analog (DA) value.|
114e41f4b71Sopenharmony_ci| start    | **device**: structure pointer to the DAC controller at the core layer.                       | -  | HDF_STATUS| Starts a DAC device.   |
115e41f4b71Sopenharmony_ci| stop     | **device**: structure pointer to the DAC controller at the core layer.                       | -  | HDF_STATUS| Stops a DAC device.   |
116e41f4b71Sopenharmony_ci
117e41f4b71Sopenharmony_ci**Table 2** Functions in **DacLockMethod**
118e41f4b71Sopenharmony_ci
119e41f4b71Sopenharmony_ci| Function| Input Parameter| Output Parameter| Return Value| Description|
120e41f4b71Sopenharmony_ci| -------- | -------- | -------- | -------- | -------- |
121e41f4b71Sopenharmony_ci| lock | **device**: structure pointer to the DAC device object at the core layer.| -| HDF_STATUS| Acquires the critical section lock.|
122e41f4b71Sopenharmony_ci| unlock | **device**: structure pointer to the DAC device object at the core layer.| -| HDF_STATUS| Releases the critical section lock.|
123e41f4b71Sopenharmony_ci
124e41f4b71Sopenharmony_ci
125e41f4b71Sopenharmony_ci### How to Develop
126e41f4b71Sopenharmony_ci
127e41f4b71Sopenharmony_ciThe DAC module adaptation procedure is as follows:
128e41f4b71Sopenharmony_ci
129e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
130e41f4b71Sopenharmony_ci2. Configure attribute files.
131e41f4b71Sopenharmony_ci3. Instantiate the core layer APIs.
132e41f4b71Sopenharmony_ci4. Debug the driver.
133e41f4b71Sopenharmony_ci
134e41f4b71Sopenharmony_ci### Example
135e41f4b71Sopenharmony_ci
136e41f4b71Sopenharmony_ciThe following uses the Hi3516D V300 driver **//device/soc/hisilicon/common/platform/dac/dac_hi35xx.c** as an example to describe how to perform the DAC driver adaptation.
137e41f4b71Sopenharmony_ci
138e41f4b71Sopenharmony_ci1. Instantiate the driver entry.
139e41f4b71Sopenharmony_ci
140e41f4b71Sopenharmony_ci    The driver entry must be a global variable of the **HdfDriverEntry** type (defined in **hdf_device_desc.h**), and the module name must be the same as that in **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/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.
141e41f4b71Sopenharmony_ci
142e41f4b71Sopenharmony_ci    Generally, the HDF calls **Init()** to load the driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit.
143e41f4b71Sopenharmony_ci
144e41f4b71Sopenharmony_ci    ```c++
145e41f4b71Sopenharmony_ci    static struct HdfDriverEntry g_dacDriverEntry = {
146e41f4b71Sopenharmony_ci        .moduleVersion = 1,
147e41f4b71Sopenharmony_ci        .Init = VirtualDacInit,
148e41f4b71Sopenharmony_ci        .Release = VirtualDacRelease,
149e41f4b71Sopenharmony_ci        .moduleName = "virtual_dac_driver",// (Mandatory) The value must be the same as that in the .hcs file.
150e41f4b71Sopenharmony_ci    };
151e41f4b71Sopenharmony_ci    HDF_INIT(g_dacDriverEntry);             // Call HDF_INIT to register the driver entry with the HDF.
152e41f4b71Sopenharmony_ci    ```
153e41f4b71Sopenharmony_ci
154e41f4b71Sopenharmony_ci2. Configure attribute files.
155e41f4b71Sopenharmony_ci
156e41f4b71Sopenharmony_ci   - Add the **//vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs** file.
157e41f4b71Sopenharmony_ci
158e41f4b71Sopenharmony_ci     The device attribute values are closely related to the driver implementation and the default values or value ranges of the **DacDevice** members at the core layer, for example, the number of device channels and the maximum transmission speed.
159e41f4b71Sopenharmony_ci
160e41f4b71Sopenharmony_ci     In the unified service mode, the first device node in the **device_info.hcs** file must be the DAC manager. The parameters must be set as follows:
161e41f4b71Sopenharmony_ci
162e41f4b71Sopenharmony_ci     | Parameter          | Value                                                                 |
163e41f4b71Sopenharmony_ci     | --------------- | ------------------------------------------------------------------- |
164e41f4b71Sopenharmony_ci     | policy          | **0**, which indicates that no service is published.                                               |
165e41f4b71Sopenharmony_ci     | priority        | Driver startup priority. The value range is 0 to 200. A larger value indicates a lower priority. For the drivers with the same priority, the device loads them randomly.|
166e41f4b71Sopenharmony_ci     | permission      | Driver permission.                                                            |
167e41f4b71Sopenharmony_ci     | moduleName      | **HDF_PLATFORM_DAC_MANAGER**                                      |
168e41f4b71Sopenharmony_ci     | serviceName     | **HDF_PLATFORM_DAC_MANAGER**                                      |
169e41f4b71Sopenharmony_ci     | deviceMatchAttr | Reserved.                                                      |
170e41f4b71Sopenharmony_ci
171e41f4b71Sopenharmony_ci     Configure DAC controller information from the second node. This node specifies a type of DAC controllers rather than a specific DAC controller. In this example, there is only one DAC device. If there are multiple DAC devices, add the **deviceNode** information to the **device_info.hcs** file and add the corresponding device attributes to the **dac_config.hcs** file for each device.
172e41f4b71Sopenharmony_ci
173e41f4b71Sopenharmony_ci     **device_info.hcs** example:
174e41f4b71Sopenharmony_ci
175e41f4b71Sopenharmony_ci        ```hcs
176e41f4b71Sopenharmony_ci        root {
177e41f4b71Sopenharmony_ci            device_dac :: device {
178e41f4b71Sopenharmony_ci                /* device0 is the DAC manager. */
179e41f4b71Sopenharmony_ci                device0 :: deviceNode {
180e41f4b71Sopenharmony_ci                    policy = 0;
181e41f4b71Sopenharmony_ci                    priority = 52;
182e41f4b71Sopenharmony_ci                    permission = 0644;
183e41f4b71Sopenharmony_ci                    serviceName = "HDF_PLATFORM_DAC_MANAGER";
184e41f4b71Sopenharmony_ci                    moduleName = "HDF_PLATFORM_DAC_MANAGER";
185e41f4b71Sopenharmony_ci                }
186e41f4b71Sopenharmony_ci            }
187e41f4b71Sopenharmony_ci            /* dac_virtual is a DAC controller. */
188e41f4b71Sopenharmony_ci            dac_virtual :: deviceNode {
189e41f4b71Sopenharmony_ci                policy = 0;
190e41f4b71Sopenharmony_ci                priority = 56;
191e41f4b71Sopenharmony_ci                permission = 0644;
192e41f4b71Sopenharmony_ci                moduleName = "virtual_dac_driver";        // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
193e41f4b71Sopenharmony_ci                serviceName = "VIRTUAL_DAC_DRIVER";       // (Mandatory) Unique name of the service published by the driver.
194e41f4b71Sopenharmony_ci                deviceMatchAttr = "virtual_dac";          // (Mandatory) Controller private data, which must be same as that of the controller in dac_config.hcs.
195e41f4b71Sopenharmony_ci                }                                          
196e41f4b71Sopenharmony_ci        }
197e41f4b71Sopenharmony_ci        ```
198e41f4b71Sopenharmony_ci
199e41f4b71Sopenharmony_ci    - Configure the **dac_test_config.hcs** file.
200e41f4b71Sopenharmony_ci
201e41f4b71Sopenharmony_ci      Add a file to the directory of a product to configure driver parameters. For example, add the **vendor/hisilicon/hispark_taurus/hdf_config/hdf_test/dac_test_config.hcs** file for the hispark_taurus development board. 
202e41f4b71Sopenharmony_ci
203e41f4b71Sopenharmony_ci      The configuration parameters are as follows:
204e41f4b71Sopenharmony_ci
205e41f4b71Sopenharmony_ci        ```hcs
206e41f4b71Sopenharmony_ci        root {
207e41f4b71Sopenharmony_ci            platform {
208e41f4b71Sopenharmony_ci            dac_config {
209e41f4b71Sopenharmony_ci                    match_attr = "virtual_dac"; // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.   
210e41f4b71Sopenharmony_ci                    template dac_device {
211e41f4b71Sopenharmony_ci                        deviceNum = 0;          // Device number.    
212e41f4b71Sopenharmony_ci                        validChannel = 0x1; // Valid channel 1.
213e41f4b71Sopenharmony_ci                        rate = 20000; // Transmission speed.
214e41f4b71Sopenharmony_ci                    }
215e41f4b71Sopenharmony_ci                    device_0 :: dac_device {
216e41f4b71Sopenharmony_ci                        deviceNum = 0;          // Device number.
217e41f4b71Sopenharmony_ci                        validChannel = 0x2; // Valid channel 2.
218e41f4b71Sopenharmony_ci                    }
219e41f4b71Sopenharmony_ci                }
220e41f4b71Sopenharmony_ci            }
221e41f4b71Sopenharmony_ci        }
222e41f4b71Sopenharmony_ci        ```
223e41f4b71Sopenharmony_ci
224e41f4b71Sopenharmony_ci      After the **dac_config.hcs** file is configured, include the file in the **hdf.hcs** file. Otherwise, the configuration file cannot take effect.
225e41f4b71Sopenharmony_ci
226e41f4b71Sopenharmony_ci      For example, if the path of **dac_config.hcs** is **device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/dac/dac_config.hcs**, add the following statement to **hdf.hcs** of the product:
227e41f4b71Sopenharmony_ci
228e41f4b71Sopenharmony_ci        ```c
229e41f4b71Sopenharmony_ci      #include "../../../../device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/dac/dac_config.hcs" // Relative path of the file.
230e41f4b71Sopenharmony_ci        ```
231e41f4b71Sopenharmony_ci
232e41f4b71Sopenharmony_ci3. Instantiate the core layer APIs.
233e41f4b71Sopenharmony_ci
234e41f4b71Sopenharmony_ci    - Initialize the **DacDevice** object.
235e41f4b71Sopenharmony_ci
236e41f4b71Sopenharmony_ci        Initialize **DacDevice** in the **VirtualDacParseAndInit** function.
237e41f4b71Sopenharmony_ci
238e41f4b71Sopenharmony_ci        ```c++
239e41f4b71Sopenharmony_ci        /* Custom structure of the virtual driver. */
240e41f4b71Sopenharmony_ci        struct VirtualDacDevice {
241e41f4b71Sopenharmony_ci        /* DAC device structure. */
242e41f4b71Sopenharmony_ci            struct DacDevice device;
243e41f4b71Sopenharmony_ci            /* DAC device number. */
244e41f4b71Sopenharmony_ci            uint32_t deviceNum;
245e41f4b71Sopenharmony_ci            /* Valid channel. */ 
246e41f4b71Sopenharmony_ci            uint32_t validChannel;
247e41f4b71Sopenharmony_ci            /* DAC rate. */
248e41f4b71Sopenharmony_ci            uint32_t rate;
249e41f4b71Sopenharmony_ci        };
250e41f4b71Sopenharmony_ci        /* Parse and initialize the **DacDevice** object of the core layer. */
251e41f4b71Sopenharmony_ci        static int32_t VirtualDacParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
252e41f4b71Sopenharmony_ci        {
253e41f4b71Sopenharmony_ci            /* Define the return values. */
254e41f4b71Sopenharmony_ci            int32_t ret;
255e41f4b71Sopenharmony_ci            /* Pointer to the virtual DAC device. */
256e41f4b71Sopenharmony_ci            struct VirtualDacDevice *virtual = NULL;
257e41f4b71Sopenharmony_ci            (void)device;
258e41f4b71Sopenharmony_ci            /* Allocate space for this pointer. */
259e41f4b71Sopenharmony_ci            virtual = (struct VirtualDacDevice *)OsalMemCalloc(sizeof(*virtual));
260e41f4b71Sopenharmony_ci        if (virtual == NULL) {
261e41f4b71Sopenharmony_ci            /* If the value is null, return an error code. */
262e41f4b71Sopenharmony_ci            HDF_LOGE("%s: Malloc virtual fail!", __func__);
263e41f4b71Sopenharmony_ci            return HDF_ERR_MALLOC_FAIL;
264e41f4b71Sopenharmony_ci        }
265e41f4b71Sopenharmony_ci        /* Read the attribute file. */
266e41f4b71Sopenharmony_ci        ret = VirtualDacReadDrs(virtual, node);
267e41f4b71Sopenharmony_ci        if (ret != HDF_SUCCESS) {
268e41f4b71Sopenharmony_ci            /* Failed to read the file. */
269e41f4b71Sopenharmony_ci            HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
270e41f4b71Sopenharmony_ci            /* Release the space for the virtual DAC device. */
271e41f4b71Sopenharmony_ci            OsalMemFree(virtual);
272e41f4b71Sopenharmony_ci            /* Set the pointer to 0. */
273e41f4b71Sopenharmony_ci            virtual = NULL;
274e41f4b71Sopenharmony_ci            return ret;
275e41f4b71Sopenharmony_ci        }
276e41f4b71Sopenharmony_ci        /* Initialize the pointer to the virtual DAC device. */
277e41f4b71Sopenharmony_ci        VirtualDacDeviceInit(virtual);
278e41f4b71Sopenharmony_ci        /* Initialize the priv object in DacDevice. */
279e41f4b71Sopenharmony_ci        virtual->device.priv = (void *)node;
280e41f4b71Sopenharmony_ci        /* Initialize the devNum object in DacDevice. */
281e41f4b71Sopenharmony_ci        virtual->device.devNum = virtual->deviceNum;
282e41f4b71Sopenharmony_ci        /* Initialize the ops object in DacDevice. */
283e41f4b71Sopenharmony_ci        virtual->device.ops = &g_method;
284e41f4b71Sopenharmony_ci        /* Add a DAC device. */
285e41f4b71Sopenharmony_ci        ret = DacDeviceAdd(&virtual->device);
286e41f4b71Sopenharmony_ci        if (ret != HDF_SUCCESS) {
287e41f4b71Sopenharmony_ci            /* Failed to add the device. */
288e41f4b71Sopenharmony_ci            HDF_LOGE("%s: add Dac controller failed! ret = %d", __func__, ret);
289e41f4b71Sopenharmony_ci            /* Release the space for the virtual DAC device. */
290e41f4b71Sopenharmony_ci            OsalMemFree(virtual);
291e41f4b71Sopenharmony_ci            /* Set this pointer to null. */
292e41f4b71Sopenharmony_ci            virtual = NULL;
293e41f4b71Sopenharmony_ci            return ret;
294e41f4b71Sopenharmony_ci        }
295e41f4b71Sopenharmony_ci        
296e41f4b71Sopenharmony_ci        return HDF_SUCCESS;
297e41f4b71Sopenharmony_ci           }
298e41f4b71Sopenharmony_ci        ```
299e41f4b71Sopenharmony_ci
300e41f4b71Sopenharmony_ci        
301e41f4b71Sopenharmony_ci
302e41f4b71Sopenharmony_ci    - Define a custom structure. 
303e41f4b71Sopenharmony_ci
304e41f4b71Sopenharmony_ci        The custom structure holds parameters and data for the driver. Define the custom structure based on the function parameters of the device. The **DacTestReadConfig()** provided by the HDF reads the values in the **dac_config.hcs** file, and **DeviceResourceIface()** initializes the custom structure and passes some important parameters, such as the device number and bus number, to the **DacDevice** object at the core layer.
305e41f4b71Sopenharmony_ci
306e41f4b71Sopenharmony_ci        ```c++
307e41f4b71Sopenharmony_ci        struct VirtualDacDevice {
308e41f4b71Sopenharmony_ci              struct DacDevice device;// (Mandatory) Control object at the core layer. For details, see the description below.
309e41f4b71Sopenharmony_ci              uint32_t deviceNum;      // (Mandatory) Device number.
310e41f4b71Sopenharmony_ci              uint32_t validChannel;   // (Mandatory) Valid channel.
311e41f4b71Sopenharmony_ci              uint32_t rate;           // (Mandatory) Sampling rate.
312e41f4b71Sopenharmony_ci          };
313e41f4b71Sopenharmony_ci          
314e41f4b71Sopenharmony_ci          /* DacDevice is the core layer controller structure. The Init() function assigns values to the members of DacDevice. */
315e41f4b71Sopenharmony_ci          struct DacDevice {
316e41f4b71Sopenharmony_ci              const struct DacMethod *ops;
317e41f4b71Sopenharmony_ci              OsalSpinlock spin;      // Spinlock.
318e41f4b71Sopenharmony_ci              uint32_t devNum; // Device number.
319e41f4b71Sopenharmony_ci              uint32_t chanNum; // Device channel number.
320e41f4b71Sopenharmony_ci              const struct DacLockMethod *lockOps;
321e41f4b71Sopenharmony_ci              void *priv;
322e41f4b71Sopenharmony_ci          };
323e41f4b71Sopenharmony_ci        ```
324e41f4b71Sopenharmony_ci
325e41f4b71Sopenharmony_ci        
326e41f4b71Sopenharmony_ci
327e41f4b71Sopenharmony_ci    - Instantiate **DacDevice** in **DacMethod**.
328e41f4b71Sopenharmony_ci
329e41f4b71Sopenharmony_ci        The **VirtualDacWrite**, **VirtualDacStop**, and **VirtualDacStart** functions are instantiated in **dac_virtual.c**.
330e41f4b71Sopenharmony_ci
331e41f4b71Sopenharmony_ci        ```c++
332e41f4b71Sopenharmony_ci        static const struct DacMethod g_method = {
333e41f4b71Sopenharmony_ci            .write = VirtualDacWrite, // Write data to a DAC device. 
334e41f4b71Sopenharmony_ci            .stop = VirtualDacStop, // Stop a DAC device.
335e41f4b71Sopenharmony_ci            .start = VirtualDacStart, // Start a DAC device.
336e41f4b71Sopenharmony_ci        };
337e41f4b71Sopenharmony_ci        ```
338e41f4b71Sopenharmony_ci
339e41f4b71Sopenharmony_ci        >![](../public_sys-resources/icon-note.gif) **NOTE**<br>For details about **DacMethod**, see [Available APIs](#available-apis).
340e41f4b71Sopenharmony_ci
341e41f4b71Sopenharmony_ci    
342e41f4b71Sopenharmony_ci
343e41f4b71Sopenharmony_ci    - Implement the **Init** function.
344e41f4b71Sopenharmony_ci
345e41f4b71Sopenharmony_ci        Input parameter:
346e41f4b71Sopenharmony_ci
347e41f4b71Sopenharmony_ci        **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
348e41f4b71Sopenharmony_ci
349e41f4b71Sopenharmony_ci        Return value:
350e41f4b71Sopenharmony_ci
351e41f4b71Sopenharmony_ci        **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.
352e41f4b71Sopenharmony_ci
353e41f4b71Sopenharmony_ci        | Status                 | Description                |
354e41f4b71Sopenharmony_ci        | ---------------------- | -------------------------- |
355e41f4b71Sopenharmony_ci        | HDF_ERR_INVALID_OBJECT | Invalid controller object. |
356e41f4b71Sopenharmony_ci        | HDF_ERR_INVALID_PARAM  | Invalid parameter.         |
357e41f4b71Sopenharmony_ci        | HDF_ERR_MALLOC_FAIL    | Failed to allocate memory. |
358e41f4b71Sopenharmony_ci        | HDF_ERR_IO             | I/O error.                 |
359e41f4b71Sopenharmony_ci        | HDF_SUCCESS            | Transmission successful.   |
360e41f4b71Sopenharmony_ci        | HDF_FAILURE            | Transmission failed.       |
361e41f4b71Sopenharmony_ci
362e41f4b71Sopenharmony_ci        
363e41f4b71Sopenharmony_ci
364e41f4b71Sopenharmony_ci        Function description:
365e41f4b71Sopenharmony_ci
366e41f4b71Sopenharmony_ci        Initializes the custom structure object and **DacDevice**, and calls the **DacDeviceAdd** function at the core layer.
367e41f4b71Sopenharmony_ci
368e41f4b71Sopenharmony_ci        ```c++
369e41f4b71Sopenharmony_ci          static int32_t VirtualDacParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)
370e41f4b71Sopenharmony_ci            {
371e41f4b71Sopenharmony_ci                /* Define the return values. */
372e41f4b71Sopenharmony_ci                int32_t ret;
373e41f4b71Sopenharmony_ci                /* Pointer to the VirtualDacDevice structure. */
374e41f4b71Sopenharmony_ci                struct VirtualDacDevice *virtual = NULL;
375e41f4b71Sopenharmony_ci                (void)device;
376e41f4b71Sopenharmony_ci                /* Allocate memory of the specified size. */
377e41f4b71Sopenharmony_ci                virtual = (struct VirtualDacDevice *)OsalMemCalloc(sizeof(*virtual));
378e41f4b71Sopenharmony_ci                if (virtual == NULL) {
379e41f4b71Sopenharmony_ci                    /* Failed to allocate memory. */
380e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: Malloc virtual fail!", __func__);
381e41f4b71Sopenharmony_ci                    return HDF_ERR_MALLOC_FAIL;
382e41f4b71Sopenharmony_ci                }
383e41f4b71Sopenharmony_ci                /* Read the node parameters in the HCS. The function definition is as follows. */
384e41f4b71Sopenharmony_ci                ret = VirtualDacReadDrs(virtual, node);
385e41f4b71Sopenharmony_ci                if (ret != HDF_SUCCESS) {
386e41f4b71Sopenharmony_ci                    /* Failed to read the node data. */
387e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: Read drs fail! ret:%d", __func__, ret);
388e41f4b71Sopenharmony_ci                    goto __ERR__;
389e41f4b71Sopenharmony_ci                }
390e41f4b71Sopenharmony_ci                /* Initialize the DAC device pointer. */
391e41f4b71Sopenharmony_ci                VirtualDacDeviceInit(virtual);
392e41f4b71Sopenharmony_ci                /* Pass in the private data of the node. */
393e41f4b71Sopenharmony_ci                virtual->device.priv = (void *)node;
394e41f4b71Sopenharmony_ci                /* Pass in the device number. */
395e41f4b71Sopenharmony_ci                virtual->device.devNum = virtual->deviceNum;
396e41f4b71Sopenharmony_ci                /* Pass in the method. */
397e41f4b71Sopenharmony_ci                virtual->device.ops = &g_method;
398e41f4b71Sopenharmony_ci                /* Add a DAC device. */
399e41f4b71Sopenharmony_ci                ret = DacDeviceAdd(&virtual->device);
400e41f4b71Sopenharmony_ci                if (ret != HDF_SUCCESS) {
401e41f4b71Sopenharmony_ci                    /* Failed to add the DAC device. */
402e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: add Dac controller failed! ret = %d", __func__, ret);
403e41f4b71Sopenharmony_ci                    goto __ERR__;
404e41f4b71Sopenharmony_ci                }
405e41f4b71Sopenharmony_ci                /* The DAC device is added successfully. */
406e41f4b71Sopenharmony_ci                return HDF_SUCCESS;
407e41f4b71Sopenharmony_ci            __ERR__:
408e41f4b71Sopenharmony_ci                /* If the pointer is null */
409e41f4b71Sopenharmony_ci                if (virtual != NULL) {
410e41f4b71Sopenharmony_ci                    / Release the memory. */
411e41f4b71Sopenharmony_ci                    OsalMemFree(virtual);
412e41f4b71Sopenharmony_ci                    /* Set this pointer to null. */
413e41f4b71Sopenharmony_ci                    virtual = NULL;
414e41f4b71Sopenharmony_ci                }
415e41f4b71Sopenharmony_ci            
416e41f4b71Sopenharmony_ci                return ret;
417e41f4b71Sopenharmony_ci            }
418e41f4b71Sopenharmony_ci            
419e41f4b71Sopenharmony_ci            static int32_t VirtualDacInit(struct HdfDeviceObject *device)
420e41f4b71Sopenharmony_ci            {
421e41f4b71Sopenharmony_ci                /* Define return values. */
422e41f4b71Sopenharmony_ci                int32_t ret;
423e41f4b71Sopenharmony_ci                /* Child node of the device structure. */
424e41f4b71Sopenharmony_ci                const struct DeviceResourceNode *childNode = NULL;
425e41f4b71Sopenharmony_ci                /* Check the input parameter pointer. */
426e41f4b71Sopenharmony_ci                if (device == NULL || device->property == NULL) {
427e41f4b71Sopenharmony_ci                    /* The input parameter pointer is null. */
428e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: device or property is NULL", __func__);
429e41f4b71Sopenharmony_ci                    return HDF_ERR_INVALID_OBJECT;
430e41f4b71Sopenharmony_ci                }
431e41f4b71Sopenharmony_ci                /* The input parameter pointer is not null. */
432e41f4b71Sopenharmony_ci                ret = HDF_SUCCESS;
433e41f4b71Sopenharmony_ci                DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
434e41f4b71Sopenharmony_ci                    /* Parse the child node. */
435e41f4b71Sopenharmony_ci                    ret = VirtualDacParseAndInit(device, childNode);
436e41f4b71Sopenharmony_ci                    if (ret != HDF_SUCCESS) {
437e41f4b71Sopenharmony_ci                        /* Failed to parse the child node. */
438e41f4b71Sopenharmony_ci                        break;
439e41f4b71Sopenharmony_ci                    }
440e41f4b71Sopenharmony_ci                }
441e41f4b71Sopenharmony_ci                /* The child node is parsed. */
442e41f4b71Sopenharmony_ci                return ret;
443e41f4b71Sopenharmony_ci            }
444e41f4b71Sopenharmony_ci            
445e41f4b71Sopenharmony_ci            static int32_t VirtualDacReadDrs(struct VirtualDacDevice *virtual, const struct DeviceResourceNode *node)
446e41f4b71Sopenharmony_ci            {
447e41f4b71Sopenharmony_ci                struct DeviceResourceIface *drsOps = NULL;
448e41f4b71Sopenharmony_ci            
449e41f4b71Sopenharmony_ci                /* Obtain the drsOps method. */
450e41f4b71Sopenharmony_ci                drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
451e41f4b71Sopenharmony_ci                if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint16 == NULL) {
452e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: Invalid drs ops fail!", __func__);
453e41f4b71Sopenharmony_ci                    return HDF_FAILURE;
454e41f4b71Sopenharmony_ci                }
455e41f4b71Sopenharmony_ci                /* Read the configuration parameters in sequence and fill them in the structure. */
456e41f4b71Sopenharmony_ci                if (drsOps->GetUint32(node, "deviceNum", &virtual->deviceNum, 0) != HDF_SUCCESS) {
457e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: Read deviceNum fail!", __func__);
458e41f4b71Sopenharmony_ci                    return HDF_ERR_IO;
459e41f4b71Sopenharmony_ci                }
460e41f4b71Sopenharmony_ci                if (drsOps->GetUint32(node, "validChannel", &virtual->validChannel, 0) != HDF_SUCCESS) {
461e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: Read validChannel fail!", __func__);
462e41f4b71Sopenharmony_ci                    return HDF_ERR_IO;
463e41f4b71Sopenharmony_ci                }
464e41f4b71Sopenharmony_ci                if (drsOps->GetUint32(node, "rate", &virtual->rate, 0) != HDF_SUCCESS) {
465e41f4b71Sopenharmony_ci                    HDF_LOGE("%s: Read rate fail!", __func__);
466e41f4b71Sopenharmony_ci                    return HDF_ERR_IO;
467e41f4b71Sopenharmony_ci                }
468e41f4b71Sopenharmony_ci                return HDF_SUCCESS;
469e41f4b71Sopenharmony_ci            }
470e41f4b71Sopenharmony_ci        ```
471e41f4b71Sopenharmony_ci
472e41f4b71Sopenharmony_ci          
473e41f4b71Sopenharmony_ci
474e41f4b71Sopenharmony_ci    - Implement the **Release** function.
475e41f4b71Sopenharmony_ci
476e41f4b71Sopenharmony_ci      Input parameter:
477e41f4b71Sopenharmony_ci
478e41f4b71Sopenharmony_ci      **HdfDeviceObject**, an interface parameter provided by the driver, contains the .hcs information.
479e41f4b71Sopenharmony_ci
480e41f4b71Sopenharmony_ci      Return value:
481e41f4b71Sopenharmony_ci
482e41f4b71Sopenharmony_ci      No value is returned.
483e41f4b71Sopenharmony_ci
484e41f4b71Sopenharmony_ci      Function description:
485e41f4b71Sopenharmony_ci
486e41f4b71Sopenharmony_ci      Releases the memory and deletes the controller. This function assigns values to the **Release** function in the driver entry structure. If the HDF fails to call the **Init** function to initialize the driver, the **Release** function can be called to release driver resources.
487e41f4b71Sopenharmony_ci
488e41f4b71Sopenharmony_ci       >![](../public_sys-resources/icon-note.gif) **NOTE** <br>
489e41f4b71Sopenharmony_ci       >
490e41f4b71Sopenharmony_ci       >All forced conversion operations for obtaining the corresponding object can be successful only when **Init()** has the corresponding value assignment operations.
491e41f4b71Sopenharmony_ci
492e41f4b71Sopenharmony_ci       
493e41f4b71Sopenharmony_ci
494e41f4b71Sopenharmony_ci      ```c++
495e41f4b71Sopenharmony_ci       static void VirtualDacRemoveByNode(const struct DeviceResourceNode *node)
496e41f4b71Sopenharmony_ci           {
497e41f4b71Sopenharmony_ci               /* Define return values. */
498e41f4b71Sopenharmony_ci               int32_t ret;
499e41f4b71Sopenharmony_ci               /*Define the DAC device number. */
500e41f4b71Sopenharmony_ci               int16_t devNum;
501e41f4b71Sopenharmony_ci               /* Pointer to the DacDevice structure. */
502e41f4b71Sopenharmony_ci               struct DacDevice *device = NULL;
503e41f4b71Sopenharmony_ci               // Pointer to the VirtualDacDevice structure. */
504e41f4b71Sopenharmony_ci               struct VirtualDacDevice *virtual = NULL;
505e41f4b71Sopenharmony_ci               /* Pointer to the DeviceResourceIface structure. */
506e41f4b71Sopenharmony_ci               struct DeviceResourceIface *drsOps = NULL;
507e41f4b71Sopenharmony_ci               /* Obtain device resources through the instance entry. */
508e41f4b71Sopenharmony_ci               drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
509e41f4b71Sopenharmony_ci               /* Check the input parameter pointer. */
510e41f4b71Sopenharmony_ci               if (drsOps == NULL || drsOps->GetUint32 == NULL) {
511e41f4b71Sopenharmony_ci                   /* The pointer is null. */
512e41f4b71Sopenharmony_ci                   HDF_LOGE("%s: invalid drs ops fail!", __func__);
513e41f4b71Sopenharmony_ci                   return;
514e41f4b71Sopenharmony_ci               }
515e41f4b71Sopenharmony_ci               /* Obtain data of the devNum node. */
516e41f4b71Sopenharmony_ci               ret = drsOps->GetUint16(node, "devNum", (uint16_t *)&devNum, 0);
517e41f4b71Sopenharmony_ci               if (ret != HDF_SUCCESS) {
518e41f4b71Sopenharmony_ci                   /* The information fails to be obtained. */
519e41f4b71Sopenharmony_ci                   HDF_LOGE("%s: read devNum fail!", __func__);
520e41f4b71Sopenharmony_ci                   return;
521e41f4b71Sopenharmony_ci               }
522e41f4b71Sopenharmony_ci               /* Obtain the DAC device number. */
523e41f4b71Sopenharmony_ci               device = DacDeviceGet(devNum);
524e41f4b71Sopenharmony_ci               /* Check whether the DAC device number and data are null. */
525e41f4b71Sopenharmony_ci               if (device != NULL && device->priv == node) {
526e41f4b71Sopenharmony_ci                   /* Release the DAC device number if the device data is null. */
527e41f4b71Sopenharmony_ci                   DacDevicePut(device);
528e41f4b71Sopenharmony_ci                   /* Remove the DAC device number. */
529e41f4b71Sopenharmony_ci                   DacDeviceRemove(device);
530e41f4b71Sopenharmony_ci                   virtual = (struct VirtualDacDevice *)device;
531e41f4b71Sopenharmony_ci                   /* Release the virtual pointer. */
532e41f4b71Sopenharmony_ci                   OsalMemFree(virtual);
533e41f4b71Sopenharmony_ci               }
534e41f4b71Sopenharmony_ci               return;
535e41f4b71Sopenharmony_ci           }
536e41f4b71Sopenharmony_ci           
537e41f4b71Sopenharmony_ci           static void VirtualDacRelease(struct HdfDeviceObject *device)
538e41f4b71Sopenharmony_ci           {
539e41f4b71Sopenharmony_ci               /* Define the child node structure pointer to the DeviceResourceNode. */
540e41f4b71Sopenharmony_ci               const struct DeviceResourceNode *childNode = NULL;
541e41f4b71Sopenharmony_ci               /* Check whether the input parameter pointer is null. */
542e41f4b71Sopenharmony_ci               if (device == NULL || device->property == NULL) {
543e41f4b71Sopenharmony_ci                   /* The input parameter pointer is null. */
544e41f4b71Sopenharmony_ci                   HDF_LOGE("%s: device or property is NULL", __func__);
545e41f4b71Sopenharmony_ci                   return;
546e41f4b71Sopenharmony_ci               }
547e41f4b71Sopenharmony_ci               
548e41f4b71Sopenharmony_ci               DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {
549e41f4b71Sopenharmony_ci                   /* Remove the DAC by node. */
550e41f4b71Sopenharmony_ci                   VirtualDacRemoveByNode(childNode);
551e41f4b71Sopenharmony_ci               }
552e41f4b71Sopenharmony_ci           }
553e41f4b71Sopenharmony_ci      ```
554e41f4b71Sopenharmony_ci
555e41f4b71Sopenharmony_ci        
556e41f4b71Sopenharmony_ci
557e41f4b71Sopenharmony_ci
558e41f4b71Sopenharmony_ci4. Debug the driver.
559e41f4b71Sopenharmony_ci
560e41f4b71Sopenharmony_ci   (Optional) Verify the basic functions of the new driver, for example, check whether the test cases are successful after the driver is loaded.
561