The analog-to-digital converter \(ADC\) is a device that converts analog signals into digital signals. In the Hardware Driver Foundation \(HDF\) framework, the ADC module uses the unified service mode for API adaptation. In this mode, a device service is used as the ADC manager to handle external access requests in a unified manner, which is reflected in the configuration file. The unified service mode applies to the scenario where there are many device objects of the same type, for example, when the ADC has more than 10 controllers. If the independent service mode is used, more device nodes need to be configured and memory resources will be consumed by services.
**Figure 1** Unified service mode<aname="fig14423182615525"></a>
>For details, see [AdcMethod](#section1618135285210) and [Table 1](#table1943202316536).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether the signal collection is successful.
>For details, see [AdcMethod](#section1618135285210) and [Table 1](#table1943202316536).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether the signal collection is successful.
## Development Example<a name="section1745221471165048"></a>
The following uses **adc\_hi35xx.c** as an example to present the contents that need to be provided by the vendor to implement device functions.
In the Hardware Driver Foundation \(HDF\) framework, the general-purpose input/output \(GPIO\) module uses the service-free mode for API adaptation. The service-free mode applies to the devices that do not provide user-mode APIs or the OS system that does not distinguish the user mode and the kernel mode. In the service-free mode, **DevHandle**\(a void pointer\) directly points to the kernel-mode address of the device object.
- The High-Definition Multimedia Interface (HDMI) is an audio/video transmission protocol released by Hitachi, Panasonic, Philips, Silicon Image, Sony, Thomson, Toshiba.
- The HDMI works in master/slave mode and usually has a source and a sink.
- The HDMI APIs provide a set of common functions for HDMI transmission, including:
- Opening and closing an HDMI controller.
- Starting and stopping HDMI transmission.
- Setting audio, video, and High Dynamic Range (HDR) attributes, color depth, and AV mute.
- Reading the raw Extended Display Identification Data (EDID) from a sink.
- Registering and unregistering a callback for HDMI hot plug detect.
-[Figure 1](#fig1) shows the HDMI physical connection.
<tdclass="cellrowborder"valign="top"width="53.339999999999996%">Reads the raw EDID from a sink.</p>
</td>
</tr>
<tr><tdclass="cellrowborder"bgcolor="#ffffff"rowspan="2"valign="top"width="18.63%"><p>Registering or unregistering a callback for HDMI hot plug detect</p>
The High-Definition Multimedia Interface (HDMI) is an audio/video transmission protocol released by Hitachi, Panasonic, Philips, SiliconImage, Sony, Thomson and Toshiba. It is used to transmit audio or video data from an audio or video source device, such as a DVD player or STB, to a sink device, such as a TV or monitor. The transmission process complies with the Transition Minimized Differential Signaling (TMDS) protocol.
In the HDF, the HDMI module uses the independent service mode for API adaptation. In this mode, each device independently publishes a device service to process external access requests. After receiving an access request, the device manager extracts the parameters in the request to call the internal method of the target device. In the independent service mode, the service management capabilities of the HDFDeviceManager can be directly used. However, you need to configure a node for each device, which increases the memory usage.
**Figure 1** Independent service mode<aname="fig1"></a>

## How to Develop<a name="2"></a>
The HDMI module adaptation involves the following steps:
1. Instantiate the driver entry.
- Instantiate the **HdfDriverEntry** structure.
- Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF.
2. Configure attribute files.
- Add the **deviceNode** information to the **device_info.hcs** file.
- (Optional) Add the **hdmi_config.hcs** file.
3. Instantiate the HDMI controller object.
- Initialize **HdmiCntlr**.
- Instantiate **HdmiCntlrOps** in **HdmiCntlr**. For details, see the following description of **HdmiCntlrOps**.
| hardWareInit | **cntlr**: structure pointer to an HDMI controller at the core layer.| –| –| Initializes HDMI hardware.|
| hardWareStatusGet | **cntlr**: structure pointer to an HDMI controller at the core layer. <br/>| **status**: HDMI hardware status.| –| Obtains the HDMI hardware status.|
| controllerReset | **cntlr**: structure pointer to an HDMI controller at the core layer.| –| –| Resets an HDMI controller.|
| hotPlugStateGet | **cntlr**: structure pointer to an HDMI controller at the core layer.| -| **bool**: HDMI hot-plug status.| Obtains the HDMI hot-plug status.|
| hotPlugInterruptStateGet | **cntlr**: structure pointer to an HDMI controller at the core layer.| –| **bool**: HDMI hot-plug interrupt status.| Obtains the HDMI hot-plug interrupt status.|
| lowPowerSet | **cntlr**: structure pointer to an HDMI controller at the core layer.<br/>**enable**: whether low power consumption is enabled.| –| –| Enables or disables low power consumption.|
| tmdsModeSet | **cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**mode**: TMDS mode.| –| –| Set the TMDS mode.|
|tmdsConfigSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**mode**: TMDS mode parameters.|–|HDF_STATUS|Sets TMDS parameters.|
|infoFrameEnable|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**infoFrameType**: packet type. <br/>**enable**: whether infoFrame is enabled.|–|–|Enables or disables infoFrame.|
|infoFrameSend|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**infoFrameType**: packet type. <br/>**data**: infoFrame data. <br/>**len**: data length.|–|HDF_STATUS|Sends an infoFrame.|
|cecMsgSend|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**msg**: Consumer Electronics Control (CEC) message.|–|HDF_STATUS|Sends a CEC message.|
|audioPathEnable|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**enable**: whether the audio path is enabled.|–|–|Enables or disables the audio path.|
|audioPathSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**config**: audio path configuration.|–|–|Sets the audio path.|
|phyOutputEnable|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**enable**: whether the physical layer output is enabled.|–|–|Enables or disables the physical layer output.|
|phyOutputSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**cfg**: physical layer configuration.|–|–|Sets the physical layer information.|
|blackDataSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**enable**: whether the black screen is enabled.|–|–|Sets the black screen.|
|videoMuteEnable|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**enable**: whether the video mute feature is enabled.|–|–|Enables or disables the video mute feature.|
|videoPathSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**attr**: configuration.|–|–|Sets the video path.|
|audioMuteEnable|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**enable**: whether the audio mute feature is enabled.|–|–|Enables or disables the audio mute feature.|
|avmuteSet|**cntlr**: structure pointer to an HDMI controller at the core layer.<br/>**enable**: whether the AV mute feature is enabled.|–|–|Enables or disables the AV mute feature.|
|ddcTransfer|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**ddcCfg**: DDC configuration.|**ddcCfg**: DDC configuration.|HDF_STATUS|Reads and writes data through the display data channel (DDC).|
|scdcSourceScrambleGet|**cntlr**: structure pointer to an HDMI controller at the core layer.|–|Scrambling status of the source.|Obtains the scrambling status of the source.|
|scdcSourceScrambleSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**enable**: whether scrambling is enabled for the source.|–|HDF_STATUS|Enables or disable scrambling for the source.|
|frlEnable|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**enable**: whether fixed rate link (FRL) is enabled.|–|HDF_STATUS|Enables or disables the FRL.|
|audioNctsSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**cfg**: N/CTS configuration.|–|HDF_STATUS|Sets the audio N/CTS information.|
|frlTrainingConfigSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**cfg**: FRL training configuration.|–|–|Sets FRL training information.|
|frlTrainingStart|**cntlr**: structure pointer to an HDMI controller at the core layer.|–|–|Starts FRL training.|
|frlGetTriningRslt|**cntlr**: structure pointer to an HDMI controller at the core layer.|**rslt**: FRL training result.|–|Obtains the FRL training result.|
|hdcpRegInit|**cntlr**: structure pointer to an HDMI controller at the core layer.|–|–|Initializes registers related to the High-bandwidth Digital Content Protection (HDCP) process.|
|hdcpGenerateAksvAndAn|**cntlr**: structure pointer to an HDMI controller at the core layer.|–|HDF_STATUS|Generates the **Aksv** and **An** in the HDCP process.|
|hdcpOptReg|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**type**: operation type. <br/>**data**: register data. <br/>**len**: data length.|**data**: register data.|HDF_STATUS|Reads or writes the registers in the HDCP process.|
|hdrTimerSet|**cntlr**: structure pointer to an HDMI controller at the core layer. <br/>**config**: timer configuration.|–|–|Sets the HDR-related timer.|
## Development Example<a name="3"></a>
1. Instantiate the driver entry. 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 are collected to form a segment address space similar to an array for the upper layer to invoke.
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.
HDMI driver entry reference:
```c
struct HdfDriverEntry g_hdmiDriverEntry = {
.moduleVersion = 1,
.Bind = HdmiAdapterBind,
.Init = HdmiAdapterInit,
.Release = HdmiAdapterRelease,
.moduleName = "adapter_hdmi_driver",// (mandatory) The value must be the same as that in the .hcs file.
};
HDF_INIT(g_hdmiDriverEntry); // Call HDF_INIT to register the driver entry with the HDF.
```
2. Add **deviceNode** to the **device_info.hcs** file, and configure the device attributes in the **hdmi_config.hcs** file. The **deviceNode** information is related to registration of the driver entry. The device attribute values are closely related to the driver implementation and the default values or restriction ranges of the **HdmiCntlr** members at the core layer.
Configure HDMI controller information from the second node. This node specifies a type of HDMI controllers rather than a specific HDMI controller. In this example, there is only one HDMI controller. If there are multiple HDMI controllers, you need to add the **deviceNode** information to the **device_info** file and add the corresponding device attributes to the **hdmi_config** file.
- **device_info.hcs** configuration reference
```c
root {
platform :: host {
device_hdmi :: device {
device0 :: deviceNode {
policy = 2; // The value 2 means to publish a service.
priority = 20; // Driver startup priority.
permission = 0644; // Permission to create device nodes for the driver.
serviceName = "HDF_PLATFORM_HDMI_0"; // (Mandatory) Unique name of the service published by the driver.
moduleName = "hdmi_driver"; // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
deviceMatchAttr = "adapter_hdmi_driver"; // (Mandatory) Controller private data, which must be same as that of the corresponding controller in hdmi_config.hcs.
} // The specific controller information is in hdmi_config.hcs.
}
}
}
```
- **hdmi_config.hcs** configuration reference
```c
root {
platform {
hdmi_config {
template hdmi_controller { // Template configuration. In the template, you can configure the common parameters shared by service nodes.
match_attr = ""; // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
index = 0; // (Mandatory) HDMI controller number.
regBasePhy = 0x10100000; // (Mandatory) Physical base address of the register.
regSize = 0xd1; // (Mandatory) Register bit width.
3. Initialize the **HdmiCntlr** object at the core layer, including initializing the vendor custom structure (transferring parameters and data) and instantiating the **HdmiCntlrOps** (used to call the underlying functions of the driver). The **HdfDriverEntry** member functions (**Bind**, **Init**, and **Release**) must be implemented in this step.
> To the driver, the custom structure carries parameters and data. The values in the **hdmi_config.hcs** file are read by the HDF, and structure members are initialized by **DeviceResourceIface**. Some important values (such as the device number and bus number) are also passed to the **HdmiCntlr** object of the core layer.
```c
struct HdmiAdapterHost {
struct HdmiCntlr *cntlr; // (Mandatory) Control object of the core layer. The details are as follows:
volatile unsigned char *regBase;// (Mandatory) Register base address.
uint32_t regBasePhy // (Mandatory) Physical base address of the register.
uint32_t regSize; // (Mandatory) Register bit width.
uint32_t irqNum; // (Mandatory) IRQ number.
};
/* HdmiCntlr is the controller structure at the core layer. Its members are assigned with values by using the Init function. */
struct HdmiCntlr {
struct IDeviceIoService service;
struct HdfDeviceObject *hdfDevObj;
struct PlatformDevice device;
struct OsalMutex mutex;
struct PlatformQueue *msgQueue;
struct HdmiCntlrCap cap;
struct HdmiAttr attr;
struct HdmiCntlrOps *ops;
uint32_t deviceIndex;
uint32_t state; // Controller status.
enum HdmiTmdsModeType tmdsMode;
struct HdmiDevice *hdmi;
struct HdmiInfoframe infoframe;
struct HdmiScdc *scdc;
struct HdmiDdc ddc;
struct HdmiFrl *frl;
struct HdmiHdcp *hdcp;
struct HdmiCec *cec;
struct HdmiEvent event;
struct HdmiHdr *hdr;
void *priv;
};
```
- **(Important)** Instantiate the callback structure **HdmiCntlrOps** in **HdmiCntlr**.
> **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
>
> **Return value**
> **HDF_STATUS** (The following table lists some states. For more details, see **HDF_STATUS** definition in the **/drivers/framework/include/utils/hdf_base.h file**.)
> Initializes the custom structure object **HdmiAdapterHost** and **HdmiCntlr**, and calls the **HdmiCntlrAdd** function to add the HDMI controller to the core layer.
>
> The **HdmiCntlr**, **HdmiAdapterHost**, and **HdfDeviceObject** assign values with each other so that other functions can be converted successfully.
> **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
>
> **Return value**
> –
>
> **Function description:**
> Releases the memory and deletes the controller. This function assigns a value 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.
cntlr = (struct MmcCntlr *)obj->service;// Forcibly convert HdfDeviceObject to HdmiCntlr by using service. For details about the value assignment, see the Bind function.
...
HimciDeleteHost((struct HimciAdapterHost *)cntlr->priv);// Memory release function customized by the vendor. A forced conversion from HdmiCntlr to HimciAdapterHost is involved in the process.
}
```
> All forced conversion operations for obtaining the corresponding object can be successful only when the **Init** function has the corresponding value assignment operations.
>For details, see [I2cMethod and I2cLockMethod](#section1683458184518) and [Table 1](#table10549174014611).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether data is successfully transmitted.
### I2cMethod and I2cLockMethod<a name="section1683458184518"></a>
>For details, see [I2cMethod and I2cLockMethod](#section1683458184518) and [Table 1](#table10549174014611).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether data is successfully transmitted.
## Development Example<a name="section1773332551114257"></a>
The following uses **i2c\_hi35xx.c** as an example to present the contents that need to be provided by the vendor to implement device functions.
The Improved Inter-Integrated Circuit (I3C) is a simple and cost-efficient bidirectional 2-wire synchronous serial bus protocol developed by the Mobile Industry Processor Interface (MIPI) Alliance.
I3C is backward compatible with legacy Inter-Integrated Circuit (I2C) devices. Moreover, it provides the in-band interrupt (IBI) function and supports hot-join of I3C devices. This eliminates the need for adding an extra interrupt line to implement interrupts in I2C.
The I2C device, I3C slave device, and I3C secondary master device can coexist on the I3C bus.
The I3C APIs provide a set of common functions for I3C transfer, including:
- Opening and closing an I3C controller.
- Obtaining and setting I3C controller parameters.
- Performing customized I3C message transfer by using a message array.
- Requesting and releasing an IBI.
[Figure 1](#fig1) shows the I3C physical connection.
<tdclass="cellrowborder"valign="top"width="50%"><p>Transmission mode, where the value 0 indicates the I2C mode, 1 indicates the I3C mode, and 2 indicates transmission of the Common Command Code (CCC).
The I3C messages are of the I3cMsg type. Each message structure indicates a read or write operation. A message array is used to perform multiple read or write operations.
```c
int32_tret;
uint8_twbuff[2]={0x12,0x13};
uint8_trbuff[2]={0};
structI3cMsgmsgs[2];/* Custom message array for transfer. */
msgs[0].buf=wbuff;/* Data to write */
msgs[0].len=2;/* Length of the data to write. */
msgs[0].addr=0x3F;/* Address of the device to which the data is written. */
msgs[0].flags=0;/* Transfer flag. An write operation is performed by default. */
msgs[1].buf=rbuff;/* Data to read */
msgs[1].len=2;/* Length of the data to read. */
msgs[1].addr=0x3F;/* Address of the device from which the data is read. */
msgs[1].flags=I3C_FLAG_READ/* I3C_FLAG_READ is set. */
>- The device address in the **I3cMsg** structure does not contain the read/write flag bit. The read/write information is passed by the read/write control bit in the member variable **flags**.
>- The **I3cTransfer()** function does not limit the number of message structures or the length of data in each message structure. The I3C controller determines these two parameters.
>- Using **I3cTransfer()** may cause the system to sleep. Do not call it in the interrupt context.
### Obtaining the I3C Controller Configuration<a name="section7"></a>
I3cClose(i3cHandle);/* Close an I3C controller. */
```
## Example<a name="section12"></a>
This following example shows how to use I3C APIs to manage an I3C device on a Hi3516D V300 development board.
Because the Hi3516D V300 SoC has no I3C controller, this example describes how to perform simple transfer operations on a virtual driver on a Hi3516D V300. The basic information is as follows:
- SoC: Hi3516D V300
- Virtual: The I3C address is 0x3f, and the register bit width is 1 byte.
- The virtual I3C devices are connected to virtual I3C controllers 18 and 19.
Perform simple I3C transfer to test whether the I3C channels are normal.
The sample code is as follows:
```c
#include "i3c_if.h" /* Header file for I3C standard APIs */
#include "i3c_ccc.h" /* Header file for I3C CCCs */
#include "hdf_log.h" /* Header file for log APIs */
##include "osal_io.h" /* Header file for I/O read and write APIs */
##include "osal_time.h" /* Header file for delay and sleep APIs */
/* Define a device structure to hold information. */
structTestI3cDevice{
uint16_tbusNum;/* I3C bus number */
uint16_taddr;/* I3C device address */
uint16_tregLen;/* Register bit width */
DevHandlei3cHandle;/* I3C controller handle */
};
/* Use I3cTransfer to encapsulate a register read/write helper function. Use flag to indicate a read or write operation. */
The Improved Inter-Integrated Circuit (I3C) is a simple and cost-efficient bidirectional 2-wire synchronous serial bus protocol developed by the Mobile Industry Processor Interface (MIPI) Alliance. In the Hardware Driver Foundation (HDF), the I3C module uses the unified service mode for API adaptation. In this mode, a device service is used as the I3C manager to handle external access requests in a unified manner, which is reflected in the configuration file. The unified service mode applies to the scenario where there are many device objects of the same type, for example, when the I3C has more than 10 controllers. If the independent service mode is used, more device nodes need to be configured and memory resources will be consumed by services.

## How to Develop<a name="2"></a>
The I3C module adaptation involves the following steps:
1. Instantiate the driver entry.
- Instantiate the **HdfDriverEntry** structure.
- Call **HDF_INIT** to register the **HdfDriverEntry** instance with the HDF.
2. Configure attribute files.
- Add the **deviceNode** information to the **device_info.hcs** file.
- (Optional) Add the **i3c_config.hcs** file.
3.**Instantiate the I3C controller object.**
- Initialize **I3cCntlr**.
- Instantiate **I3cMethod** in **I3cCntlr**. For details, see the following description of **I3cMethod**.
4. Register an interrupt handler.
Registers an interrupt handler for the controller to implement the device hot-join and in-band interrupt (IBI) features.
|sendCccCmd|**cntlr**: structure pointer to an I3C controller at the core layer. <br> **ccc**: pointer to the input common command code (CCC) structure.|**ccc**: pointer to the output CCC structure.|HDF_STATUS|Sends a CCC.|
|Transfer |**cntlr**: structure pointer to an I3C controller at the core layer. <br>**msgs**: structure pointer to user messages. <br>**count**: number of messages, which is of the int16_t type.|**msgs**: structure pointer to user messages.|HDF_STATUS|Transfers user messages in I3C mode.|
|i2cTransfer |**cntlr**: structure pointer to an I3C controller at the core layer. <br>**msgs**: structure pointer to user messages. <br>**count**: number of messages, which is of the int16_t type.|**msgs**: structure pointer to user messages.|HDF_STATUS|Transfers user messages in I2C mode.|
|setConfig|**cntlr**: structure pointer to an I3C controller at the core layer. <br>**config**: controller configuration parameters.|–|HDF_STATUS|Configures an I3C controller.|
|getConfig|**cntlr**: structure pointer to an I3C controller at the core layer.|**config**: controller configuration parameters.|HDF_STATUS|Obtains the configuration of an I3C controller.|
|requestIbi|**device**: structure pointer to an I3C device at the core layer.|–|HDF_STATUS|Requests an IBI for an I3C device.|
|freeIbi|**device**: structure pointer to an I3C device at the core layer.|–|HDF_STATUS|Releases the IBI for an I3C device.|
## Development Example<a name="3"></a>
1. Instantiate the driver entry. 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 are collected to form a segment address space similar to an array for the upper layer to invoke.
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.
I3C driver entry reference
> The I3C module may be connected with multiple controllers. Therefore, in the HDF, a manager object is created for the I3C, and a manager service is published to handle external access requests in a unified manner. Before a controller is opened, the manager service is obtained first. Then, the manager service locates the target controller based on the specified parameters.
>
> The core layer implements the driver of the I3C manager service. **Vendors do not need to care about the implementation. When **Init()** is implemented, the **I3cCntlrAdd()** function at the core layer needs to be called to implement related features.**
.moduleName = "virtual_i3c_driver",// (Mandatory) The value must be the same as that in the .hcs file.
};
HDF_INIT(g_virtualI3cDriverEntry); // Call HDF_INIT to register the driver entry with the HDF.
/* Driver entry of the i3c_core.c manager service at the core layer */
struct HdfDriverEntry g_i3cManagerEntry = {
.moduleVersion = 1,
.Init = I3cManagerInit,
.Release = I3cManagerRelease,
.moduleName = "HDF_PLATFORM_I3C_MANAGER",// Correspond to device0 in the device_info file.
};
HDF_INIT(g_i3cManagerEntry);
```
2. Add **deviceNode** to the **device_info.hcs** file, and configure the device attributes in the **i3c_config.hcs** file. The **deviceNode** information is related to registration of the driver entry. The device attribute values are closely related to the driver implementation and the default values or restriction ranges of the **I3cCntlr** members at the core layer.
In the unified service mode, the first device node in the **device_info** file must be the I3C manager. The I3C manager parameters must be set as follows:
|Member|Value|
|-|-|
|moduleName |HDF_PLATFORM_I3C_MANAGER|
|serviceName|- (reserved)|
|policy|0|
|cntlrMatchAttr| - (reserved)|
Configure I3C controller information from the second node. This node specifies a type of I3C controllers rather than a specific I3C controller. In this example, there is only one I3C controller. If there are multiple I3C controllers, you need to add the **deviceNode** information to the **device_info** file and add the corresponding device attributes to the **i3c_config** file.
- **device_info.hcs** configuration reference
```c
root {
device_i3c :: device {
device0 :: deviceNode {
policy = 0;
priority = 52;
permission = 0644;
serviceName = "HDF_PLATFORM_I3C_MANAGER";
moduleName = "HDF_PLATFORM_I3C_MANAGER";
}
}
i3c_virtual :: deviceNode {
policy = 0; // The value 0 indicates that no service is published.
priority = 56; // Driver startup priority.
permission = 0644; // Permission to create device nodes for the driver.
moduleName = "virtual_i3c_driver"; // (Mandatory) Driver name, which must be the same as moduleName in the driver entry.
serviceName = "VIRTUAL_I3C_DRIVER"; // (Mandatory) Unique name of the service published by the driver.
deviceMatchAttr = "virtual_i3c"; // (Mandatory) Controller private data, which must be same as that of the corresponding controller in i3c_config.hcs.
} // The specific controller information is in i3c_config.hcs.
}
```
- i3c_config.hcs configuration reference
```c
root {
platform {
i3c_config {
match_attr = "virtual_i3c"; // (Mandatory) The value must be the same as that of deviceMatchAttr in device_info.hcs.
template i3c_controller { // Template configuration. In the template, you can configure the common parameters shared by service nodes.
busId = 0; // (Mandatory) I3C bus number.
busMode = 0x0; // Bus mode. Which can be 0x0 (pure), 0x1 (mixed-fast), 0x2 (mixed-limited), or 0x3 (mixed-slow).
regBasePhy = 0x120b0000; // (Mandatory) Physical base address.
regSize = 0xd1; // (Mandatory) Register bit width.
3. Initialize the **I3cCntlr** object at the core layer, including initializing the vendor custom structure (transferring parameters and data) and instantiating **I3cMethod** (used to call the underlying functions of the driver) in **I3cCntlr**.
The **HdfDriverEntry** member functions (**Bind**, **Init**, and **Release**) must be implemented in this step.
- Custom structure reference
> To the driver, the custom structure carries parameters and data. The values in the **i3c_config.hcs** file are read by the HDF, and the structure members are initialized through **DeviceResourceIface**. Some important values, such as the device number and bus number, are also passed to the **I3cCntlr** object at the core layer.
```c
struct VirtualI3cCntlr {
struct AdcDevice device;// (Mandatory) Control object at the core layer. For details, see the following description of **I3cCntlr**.
volatile unsigned char *regBase;// (Mandatory) Register base address.
uint32_t regBasePhy; // (Mandatory) Physical base address of the register.
uint32_t regSize; // (Mandatory) Bit width of the register.
uint16_t busId; // (Mandatory) Device number.
uint16_t busMode;
uint16_t IrqNum;
uint32_t i3cMaxRate;
uint32_t i3cRate;
uint32_t i2cFmRate;
uint32_t i2cFmPlusRate;
};
/* I3cCntlr is the controller structure at the core layer. Its members are assigned with values by using the Init function.
> **(Important)** The following shows instantiation of the **I3cCntlr** member callback structure **I3cMethod**. This example does not provide the instantiation of the **I3cLockMethod** callback structure. For details, see the I2C driver development. Other members are initialized in the **Init** function.
- **Init function**
> **Input parameter**:
> **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
>
> **Return value**
> **HDF_STATUS** (The following table lists some states. For more details, see **HDF_STATUS** definition in the **/drivers/framework/include/utils/hdf_base.h file**.)
virtual->cntlr.ops = &g_method; // (Mandatory) Connect to the I3cMethod instance.
(void)OsalSpinInit(&virtual->spin);
ret = I3cCntlrAdd(&virtual->cntlr); // (Mandatory) Call this function to add the controller to the core layer. If a success signal is returned, the driver is completely connected to the core layer of the platform.
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: add i3c controller failed! ret = %d", __func__, ret);
(void)OsalSpinDestroy(&virtual->spin);
goto __ERR__;
}
return HDF_SUCCESS;
__ERR__: // If the controller fails to be added, deinitialize related functions.
> **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration file information.
>
> **Return value**
> None.
>
> **Function description:**
> Releases the memory and deletes the controller. This function assigns a value 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. All forcible conversion operations for obtaining the corresponding object can be successful only when the **Init** function has the corresponding value assignment operations.
if (drsOps == NULL || drsOps->GetUint32 == NULL) {
HDF_LOGE("%s: invalid drs ops fail!", __func__);
return;
}
ret = drsOps->GetUint16(node, "busId", (uint16_t *)&busId, 0);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: read busId fail!", __func__);
return;
}
...
/* Call the I3cCntlrGet function to obtain the I3cCntlr object through the cntlrNum of the device, and call the I3cCntlrRemove function to release the I3cCntlr object. */
cntlr = I3cCntlrGet(busId);
if (cntlr != NULL && cntlr->priv == node) {
I3cCntlrPut(cntlr);
I3cCntlrRemove(cntlr); // (Mandatory) Remove the I3cCntlr object from the manager driver.
virtual = (struct VirtualI3cCntlr *)cntlr; // (Mandatory) Obtain the custom object through a forcible conversion and perform the release operation.
VirtualI3cRemoveByNode(childNode); // See the description of VirtualI3cRemoveByNode for more details.
}
}
```
4. Implement the interrupt handler. The interrupt handler helps implement operations such as hot-join and IBI based on the address of the interrupt generated.
/* (Mandatory) Obtain the address where the interrupt is generated. Use the CHECK_RESERVED_ADDR macro to determine whether the address is the reserved address of the I3C. */
ibiAddr = VirtualI3cGetIbiAddr();
if (CHECK_RESERVED_ADDR(ibiAddr) == I3C_ADDR_RESERVED) {
-[Sending/Receiving the Pointer to a Command](#section199401342173415)
-[Releasing the MIPI DSI Device Handle](#section161011610357)
-[Usage Example](#section17470126123520)
## Overview<a name="section16806142183217"></a>
- The Display Serial Interface \(DSI\) is a specification stipulated by the Mobile Industry Processor Interface \(MIPI\) Alliance, aiming to reduce the cost of display controllers in a mobile device. It defines a serial bus and communication protocol among the host, the source of image data, and the target device. In this way, the DSI can send pixel data or commands to peripherals \(usually LCDs or similar display devices\) in serial mode, or reads information such as status and pixel from the peripherals.
>For details, see [MipiDsiCntlrMethod](#section10711202141617) and [Table 1](#table218771071713).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether data is successfully transmitted.
>For details, see [MipiDsiCntlrMethod](#section10711202141617) and [Table 1](#table218771071713).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether data is successfully transmitted.
## Development Example<a name="section1167576616161538"></a>
The following uses **mipi\_tx\_hi35xx.c** as an example to present the contents that need to be provided by the vendor to implement device functions.
In the Hardware Driver Foundation \(HDF\) framework, the MultiMedia Card \(MMC\) uses the independent service mode for API adaptation. In this mode, each device independently publishes a device service to handle external access requests. After receiving an access request from an API, the device manager extracts the parameters in the request to call the internal method of the target device. In the independent service mode, the service management capabilities of the HDFDeviceManager can be directly used. However, you need to configure a device node for each device, which increases the memory usage.
...
...
@@ -13,31 +7,9 @@ In the Hardware Driver Foundation \(HDF\) framework, the MultiMedia Card \(MMC\)
**Figure 1** Independent service mode<aname="fig19517114132810"></a>
>For details, see [MmcCntlrOps](#section6203107192915) and [Table 1](#table99129433019).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the mount operation and whether the device starts successfully.
## Available APIs<a name="section752964871810"></a>
>For details, see [MmcCntlrOps](#section6203107192915) and [Table 1](#table99129433019).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the mount operation and whether the device starts successfully.
## Development Example<a name="section1220893490162704"></a>
The following uses **himci.c** as an example to present the contents that need to be provided by the vendor to implement device functions.
Pulse width modulation (PWM) is a method used to digitally encode analog signal levels and convert them into pulses. It can be used for motor control and backlight brightness adjustment.
In the Hardware Driver Foundation \(HDF\) framework, the Pulse Width Modulator \(PWM\) uses the independent service mode for API adaptation. In this mode, each device independently publishes a device service to handle external access requests. After receiving an access request from an API, the device manager extracts the parameters in the request to call the internal method of the target device. In the independent service mode, the service management capabilities of the HDF Device Manager can be directly used. However, you need to configure a device node for each device, which increases the memory usage.
...
...
@@ -13,31 +7,9 @@ In the Hardware Driver Foundation \(HDF\) framework, the Pulse Width Modulator \
**Figure 1** Independent service mode<aname="fig983655084219"></a>
The real-time clock \(RTC\) driver provides precise real time for the operating system \(OS\). If the OS is powered off, the RTC driver continues to keep track of the system time using an external battery.
-[Disabling the SDIO Device](#section15379324143611)
-[Releasing the Exclusively Claimed Host](#section536018263713)
-[Closing an SDIO Controller](#section4752739183716)
-[Usage Example](#section376910122382)
## Overview<a name="section1155271783811"></a>
- Secure Digital Input/Output \(SDIO\) is a peripheral interface evolved from the Secure Digital \(SD\) memory card interface. The SDIO interface is compatible with SD memory cards and can be connected to devices that support the SDIO interface.
-[Setting the UART Transmission Mode](#section72713435918)
-[Writing Data of a Specified Length into a UART Device](#section128001736155919)
-[Reading Data of a Specified Length from a UART Device](#section92851601604)
-[Destroying the UART Device Handle](#section1477410521406)
-[Usage Example](#section35404241311)
## Overview<a name="section833012453535"></a>
- 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.
-[Obtaining the Watchdog Status](#section786624341011)
-[Setting the Timeout Duration](#section182386137111)
-[Obtaining the Timeout Duration](#section1883310371114)
-[Starting a Watchdog](#section82501405123)
-[Feeding a Watchdog](#section3547530101211)
-[Stopping a Watchdog](#section944595841217)
-[Closing a Watchdog](#section96561824121311)
-[Usage Example](#section1724514523135)
## Overview<a name="section14918241977"></a>
A watchdog, also called a watchdog timer, is a hardware timing device. If an error occurs in the main program of the system and fails to reset the watchdog timer, the watchdog timer sends a reset signal to restore the system to a normal state.
>For details, see [WatchdogMethod](#section220331929) and [Table 1](#table1370451732).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether the watchdog timer is successfully set.
### WatchdogMethod<a name="section220331929"></a>
WatchdogMethod
```
struct WatchdogMethod {
...
...
@@ -137,6 +110,31 @@ struct WatchdogMethod {
</tbody>
</table>
## How to Develop<a name="section477974542160117"></a>
The Watchdog module adaptation involves the following steps:
1. Instantiate the driver entry.
- Instantiate the **HdfDriverEntry** structure.
- Call **HDF\_INIT** to register the **HdfDriverEntry** instance with the HDF framework.
2. Configure attribute files.
- Add the **deviceNode** information to the **device\_info.hcs** file.
-\(Optional\) Add the **watchdog\_config.hcs** file.
3. Instantiate the Watchdog controller object.
- Initialize **WatchdogCntlr**.
- Instantiate **WatchdogMethod** in the **WatchdogCntlr** object.
>For details, see [WatchdogMethod](#section220331929) and [Table 1](#table1370451732).
4. Debug the driver.
-\(Optional\) For new drivers, verify basic functions, for example, verify the information returned after the connect operation and whether the watchdog timer is successfully set.
## Development Example<a name="section1832270347160117"></a>
The following uses **watchdog\_hi35xx.c** as an example to present the contents that need to be provided by the vendor to implement device functions.