diff --git a/en/device-dev/driver/driver-platform-pin-develop.md b/en/device-dev/driver/driver-platform-pin-develop.md new file mode 100644 index 0000000000000000000000000000000000000000..e85936af7dff542a8a4a695d34bd3823b3b66ec8 --- /dev/null +++ b/en/device-dev/driver/driver-platform-pin-develop.md @@ -0,0 +1,312 @@ +# Pin + + +## Overview + +The pin module controls the states and functionalities of system pins. In the Hardware Driver Foundation (HDF), the pin module uses the service-free mode for API adaptation. The service-free mode applies to 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. + +Figure 1 Service-free mode +![image1](figures/service-free-mode.png "service-free-mode") + +## Available APIs + +**PinCntlrMethod**: + +```c +struct PinCntlrMethod { + int32_t (*SetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType pullType); + int32_t (*GetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType *pullType); + int32_t (*SetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t strength); + int32_t (*GetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t *strength); + int32_t (*SetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char *funcName); + int32_t (*GetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char **funcName); +}; +``` + +**Table 1** APIs for the members in the PinCntlrMethod structure + +| API | Input Parameter | Return Value| Description| +| ------------ | ------------------------------------------- | ------ | ---- | +| SetPinPull | **cntlr**: structure pointer to the pin controller at the core layer.
**index**: pin index, which is a uint32_t variable.
**pullType**: pull type of the pin. It is an enum constant.|HDF_STATUS|Sets the pull type of a pin.| +| GetPinPull | **cntlr**: structure pointer to the pin controller at the core layer.
**index**: pin index, which is a uint32_t variable.
**pullType**: pointer to the pull type of the pin.| HDF_STATUS| Obtains the pull type of a pin.| +| SetPinStrength | **cntlr**: structure pointer to the pin controller at the core layer.
**index**: pin index, which is a uint32_t variable.
**strength**: pull strength of the pin. It is a uint32_t variable.| HDF_STATUS| Sets the pull strength of a pin.| +| GetPinStrength | **cntlr**: structure pointer to the pin controller at the core layer.
**index**: pin index, which is a uint32_t variable.
**strength**: pointer to the pull strength of the pin.| HDF_STATUS| Obtains the pull strength of a pin.| +| SetPinFunc | **cntlr**: structure pointer to the pin controller at the core layer.
**index**: pin index, which is a uint32_t variable.
**funcName**: char pointer to the pin functionality.| HDF_STATUS| Sets the pin functionality.| +| GetPinFunc | **cntlr**: structure pointer to the pin controller at the core layer.
**index**: pin index, which is a uint32_t variable.
**funcName**: char double pointer to the pin functionality.| HDF_STATUS| Obtains the pin functionalities.| + +## How to Develop + +The pin 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 **pin_config.hcs** file. + +3. Instantiate the pin controller object. + + - Initialize the **PinCntlr** object. + + - Instantiate **PinCntlrMethod** in the **PinCntlr** object. + + >![](../public_sys-resources/icon-note.gif) **NOTE** + >For details, see [Available APIs](#section2_PINDevelop). + +4. Debug the driver. + + - (Optional) Verify basic functionalities of new drivers. For example, verify the information returned when the driver is loaded and whether data is successfully transmitted. + +## Development Example + +The following uses **pin_hi35xx.c** as an example to present the content to be provided by the vendor to implement device functionalities. + +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 the driver. If **Init** fails to be called, the HDF calls **Release** to release driver resources and exit. + + Pin driver entry reference: + + ```c + static struct HdfDriverEntry g_hi35xxPinDriverEntry = { + .moduleVersion = 1, + .Bind = Hi35xxPinBind, + .Init = Hi35xxPinInit, + .Release = Hi35xxPinRelease, + .moduleName = "hi35xx_pin_driver",// (Mandatory) The value must be the same as that of moduleName in the .hcs file. + }; + // Call HDF_INIT to register the driver entry with the HDF. + HDF_INIT(g_hi35xxPinDriverEntry); + ``` + +2. Add **deviceNode** to the **device\_info.hcs** file, and set the device attributes in the **pin\_config.hcs** file. 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 **PinCntlr** members at the core layer. + + >![](../public_sys-resources/icon-note.gif) **NOTE** + >If there are multiple devices, add the **deviceNode** information to the **device\_info** file and add the corresponding device attributes to the **pin\_config** file. + + - **device\_info.hcs** reference: + + ```c + root { + device_info { + platform :: host { + hostName = "platform_host"; + priority = 50; + device_pin :: device { + device0:: deviceNode { // Set an HDF device node for each pin controller. + policy = 0; // 2: visible in user mode; 1: visible in kernel mode; 0: no service required. + priority = 10; // Driver startup priority. + permission = 0644; // Permission to create device nodes for the driver. + /* (Mandatory) Driver name, which must be the same as the moduleName in the driver entry. */ + moduleName = "hi35xx_Pin_driver"; + /* (Mandatory) Set the controller private data, which must be same as that in Pin_config.hcs. */ + deviceMatchAttr = "hisilicon_hi35xx_Pin_0"; + } + device1 :: deviceNode { + policy = 0; + priority = 10; + permission = 0644; + moduleName = "hi35xx_Pin_driver"; + deviceMatchAttr = "hisilicon_hi35xx_Pin_1"; + } + ... + } + } + } + } + ``` + + - **Pin\_config.hcs** reference: + + ```c + root { + platform { + Pin_config_hi35xx { + template Pin_controller { // (Mandatory) Template configuration. In the template, you can configure the common parameters shared by device nodes. + number = 0; // (Mandatory) Controller ID. + regStartBasePhy = 0; // (Mandatory) Start physical base address of the register. + regSize = 0; // (Mandatory) Register bit width. + PinCount = 0; // (Mandatory) Number of pins. + match_attr = ""; + template Pin_desc { + PinName = ""; // (Mandatory) Pin name. + init = 0; // (Mandatory) Default value of the register. + F0 = ""; // (Mandatory) Functionality 0. + F1 = ""; // Functionality 1. + F2 = ""; // Functionality 2. + F3 = ""; // Functionality 3. + F4 = ""; // Functionality 4. + F5 = ""; // Functionality 5. + } + } + controller_0 :: Pin_controller { + number = 0; + regStartBasePhy = 0x10FF0000; + regSize = 0x48; + PinCount = 18; + match_attr = "hisilicon_hi35xx_Pin_0"; + T1 :: Pin_desc { + PinName = "T1"; + init = 0x0600; + F0 = "EMMC_CLK"; + F1 = "SFC_CLK"; + F2 = "SFC_BOOT_MODE"; + } + ... + } + ...// Each pin controller corresponds to a controller node. If there are multiple pin controllers, add the corresponding controller nodes one by one. + } + } + } + ``` + +3. Initialize the **PinCntlr** object at the core layer, including initializing the vendor custom structure (passing parameters and data), instantiating **PinCntlrMethod** (used to call underlying functions of the driver) in **PinCntlr**, and implementing the **HdfDriverEntry** member functions (**Bind**, **Init**, and **Release**). + + - Initializing the vendor custom structure + + The **PinCntlr** structure holds parameters and data for the driver. The HDF obtains the values in **pin\_config.hcs** using **DeviceResourceIface**. + + ```c + // PinCntlr is the controller structure at the core layer. Its members are assigned with values by using the Init function. + struct PinCntlr { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + struct PinCntlrMethod *method; + struct DListHead node; + OsalSPinlock sPin; + uint16_t number; + uint16_t PinCount; + struct PinDesc *Pins; + void *priv; + }; + + struct PinDesc { + const char *PinName; // Pointer to the pin name. + void *priv; + }; + ``` + + - Instantiating **PinCntlrMethod** (other members are initialized by **Init**) + + ```c + // Example of Pin_hi35xx.c: Instantiate the hook. + static struct PinCntlrMethod g_method = { + .SetPinPull = Hi35xxPinSetPull, + .GetPinPull = Hi35xxPinGetPull, + .SetPinStrength = Hi35xxPinSetStrength, + .GetPinStrength = Hi35xxPinGetStrength, + .SetPinFunc = Hi35xxPinSetFunc, + .GetPinFunc = Hi35xxPinGetFunc, + }; + ``` + + - Init function + + Input parameters: + + **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration. + + Return value: + + **HDF\_STATUS** (The following table lists some states. For more details, see **HDF\_STATUS** in **/drivers/framework/include/utils/hdf\_base.h**.) + + **Table 2** HDF\_STATUS + + + + + + + + + + + + + + + + + + + + + + + + +

State

+

Description

+

HDF_ERR_INVALID_OBJECT

+

Invalid controller object

+

HDF_ERR_MALLOC_FAIL

+

Failed to allocate memory

+

HDF_ERR_INVALID_PARAM

+

Invalid parameter

+

HDF_ERR_IO

+

I/O error

+

HDF_SUCCESS

+

Initialization successful

+

HDF_FAILURE

+

Initialization failed

+
+ + Function description: + Initializes the custom structure and **PinCntlr** members, and connects to the pin controller by calling the **PinCntlrAdd** function at the core layer. + + ```c + static int32_t Hi35xxPinInit(struct HdfDeviceObject *device) + { + ... + struct Hi35xxPinCntlr *hi35xx = NULL; + ... + ret = Hi35xxPinCntlrInit(device, hi35xx); // Obtain .hcs information. + ... + DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { + ret = Hi35xxPinParsePinNode(childNode, hi35xx, index); // (Mandatory) The implementation is as follows: + ... + } + + hi35xx->cntlr.method = &g_method; // Instantiate OPS. + ret = PinCntlrAdd(&hi35xx->cntlr); // Connect to the controller. + ... + } + + static int32_t Hi35xxPinParsePinNode(const struct DeviceResourceNode *node, + struct Hi35xxPinCntlr *hi35xx, + int32_t index) + { + ... + hi35xx->cntlr.Pins[index].PinName = hi35xx->desc[index].PinName; // Instantiate PinName. + hi35xx->cntlr.Pins[index].priv = (void *)node; // Instantiate nodes. + ... + } + + + - Release function + + Input parameters: + + **HdfDeviceObject**, an interface parameter exposed by the driver, contains the .hcs configuration. + + Return value: + + – + + Function description: + + Releases memory and deletes the controller. This function assigns a value to the **Release** API 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. + + ```c + static void Hi35xxPinRelease(struct HdfDeviceObject *device) + { + struct PinCntlr *cntlr = NULL; + ... + PinCntlrRemove(cntlr);// (Mandatory) Call the function at the core layer to release pin controller devices and services. + ... + } + ```