driver-hdf-development.md 12.8 KB
Newer Older
A
annie_wangli 已提交
1 2 3 4 5
# Driver Development


## Driver Model

A
Annie_wang 已提交
6 7 8
The Hardware Driver Foundation (HDF) is designed upon a component-based driver model. This model enables refined driver management and streamlines driver development and deployment. In the HDF, the same type of device drivers are placed in a host. You can develop and deploy the drivers separately. One driver can have multiple nodes. 

The figure below shows the HDF driver model.
A
annie_wangli 已提交
9 10 11 12 13 14 15 16

  **Figure 1** HDF driver model

  ![](figures/hdf-driver-model.png)


## How to Development

A
Annie_wang 已提交
17
The HDF-based driver development involves driver implementation and configuration. The procedure is as follows:
A
annie_wangli 已提交
18

A
Annie_wang 已提交
19
1. Implement a driver.<br/>
A
Annie_wang 已提交
20
   Write the driver code and register the driver entry with the HDF.
A
annie_wangli 已提交
21

A
Annie_wang 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
   - Writing the driver service code 
   
     The following is an example:
   
   ```
   #include "hdf_device_desc.h"  // Header file that defines the driver development APIs provided by the HDF.
   #include "hdf_log.h"          // Header file that defines the log APIs provided by the HDF.
   
   #define HDF_LOG_TAG "sample_driver"   // Tag contained in logs. If no tag is not specified, the default HDF_TAG is used.
   
   // Bind the service interface provided by the driver to the HDF.
   int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
   {
       HDF_LOGD("Sample driver bind success");
       return 0;
   }
   
   // Initialize the driver service.
   int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
   {
       HDF_LOGD("Sample driver Init success");
       return 0;
   }
   
   // Release the driver resources.
   void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
   {
       HDF_LOGD("Sample driver release success");
       return;
   }
   ```
   
A
annie_wangli 已提交
54
   - Registering the driver entry with the HDF
A
Annie_wang 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
   
   
   ```
   // Define a driver entry object. It must be a global variable of the HdfDriverEntry type (defined in hdf_device_desc.h). 
   struct HdfDriverEntry g_sampleDriverEntry = {
       .moduleVersion = 1,
       .moduleName = "sample_driver",
       .Bind = HdfSampleDriverBind,
       .Init = HdfSampleDriverInit,
       .Release = HdfSampleDriverRelease,
   };
   
   // Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind() function and then the Init() function. If the Init() function fails to be called, the HDF will call Release() to release driver resources and exit the driver model.
   HDF_INIT(g_sampleDriverEntry);
   ```
   
A
Annie_wang 已提交
71 72
2. Build the driver.<br/>
   - LiteOS<br/>
A
annie_wangli 已提交
73 74
      Modify **makefile** and **BUILD.gn**.

A
Annie_wang 已提交
75
      - **makefile**:<br/>
A
annie_wangli 已提交
76 77 78 79 80 81
         Use the **makefile** template provided by the HDF to compile the driver code.

         
         ```
         include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk # Import the content predefined by the HDF. This operation is mandatory.
         MODULE_NAME :=    # File to be generated.
A
Annie_wang 已提交
82
         LOCAL_INCLUDE: =  # Directory of the driver header files.
A
annie_wangli 已提交
83 84 85 86 87
         LOCAL_SRCS : =     # Source code file of the driver.
         LOCAL_CFLAGS : =  # Custom compilation options.
         include $(HDF_DRIVER) # Import the makefile template to complete the compilation.
         ```

A
Annie_wang 已提交
88
         Add the path of the generated file to **hdf_lite.mk** in the **drivers/adapter/khdf/liteos** directory to link the file to the kernel image.
A
annie_wangli 已提交
89 90 91 92 93 94 95

         
         ```
         LITEOS_BASELIB += -lxxx # Static library generated by the link.
         LIB_SUBDIRS    +=         # Directory in which the driver code makefile is located.
         ```

A
Annie_wang 已提交
96
      - **BUILD.gn**:<br/>
A
annie_wangli 已提交
97 98 99 100 101 102 103 104 105 106
         Add **BUILD.gn**. The content of **BUILD.gn** is as follows:

         
         ```
         import("//build/lite/config/component/lite_component.gni")
         import("//drivers/adapter/khdf/liteos/hdf.gni")
         module_switch = defined(LOSCFG_DRIVERS_HDF_xxx)
         module_name = "xxx"
         hdf_driver(module_name) {
             sources = [
A
Annie_wang 已提交
107
                 "xxx/xxx/xxx.c", # Source code to compile.
A
annie_wangli 已提交
108
             ]
A
Annie_wang 已提交
109
             public_configs = [ ":public" ] # Head file configuration of the dependencies.
A
annie_wangli 已提交
110
         }
A
Annie_wang 已提交
111
         config("public") {# Define the head file configuration of the dependencies.
A
annie_wangli 已提交
112
             include_dirs = [
A
Annie_wang 已提交
113
             "xxx/xxx/xxx", # Directory of the dependency header files.
A
annie_wangli 已提交
114 115 116 117
             ]
         }
         ```

A
Annie_wang 已提交
118
         Add the **BUILD.gn** directory to **/drivers/adapter/khdf/liteos/BUILD.gn**.
A
annie_wangli 已提交
119 120 121 122 123 124 125 126 127 128

         
         ```
         group("liteos") {
                public_deps = [ ":$module_name" ]
                    deps = [
                       "xxx/xxx", # Directory where the BUILD.gn of the driver is located. It is a relative path to /drivers/adapter/khdf/liteos.
                   ]
         }
         ```
A
Annie_wang 已提交
129
   - Linux<br/>
A
annie_wangli 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
      To define the driver control macro, add the **Kconfig** file to the driver directory **xxx** and add the path of the **Kconfig** file to **drivers/adapter/khdf/linux/Kconfig**.

      
      ```
      source "drivers/hdf/khdf/xxx/Kconfig" # Kernel directory to which the HDF module is soft linked.
      ```

      Add the driver directory to **drivers/adapter/khdf/linux/Makefile**.

      
      ```
      obj-$(CONFIG_DRIVERS_HDF)  += xxx/
      ```

      Add a **Makefile** to the driver directory **xxx** and add code compiling rules of the driver to the **Makefile** file.

      
      ```
      obj-y  += xxx.o
      ```

A
Annie_wang 已提交
151
3. Configure the driver.<br/>
A
Annie_wang 已提交
152
   The HDF Configuration Source (HCS) contains the source code of HDF configuration. For details about the HCS, see [Configuration Management](../driver/driver-hdf-manage.md).
A
annie_wangli 已提交
153 154 155

   The driver configuration consists of the driver device description defined by the HDF and the private driver configuration.

A
Annie_wang 已提交
156
   - (Mandatory) Setting the driver device description<br/>
A
Annie_wang 已提交
157
      The HDF loads a driver based on the driver device description defined by the HDF. Therefore, the driver device description must be added to the **device_info.hcs** file defined by the HDF. The following is an example:
A
annie_wangli 已提交
158 159 160 161 162 163

      
      ```
      root {
          device_info {
              match_attr = "hdf_manager";
A
Annie_wang 已提交
164
              template host {       // Host template. If a node (for example, sample_host) uses the default values in this template, the node fields can be omitted.
A
annie_wangli 已提交
165 166
                  hostName = "";
                  priority = 100;
A
Annie_wang 已提交
167 168 169
                  uid = "";        // User ID (UID) of a user-mode process. It is left empty by default. If you do not set the value, this parameter will be set to the value of hostName, which indicates a common user.
                  gid = "";        // Group ID (GID) of a user-mode process. It is left empty by default. If you do not set the value, this parameter will be set to the value of hostName, which indicates a common user group.
                  caps = [""]];     // Linux capabilities of a user-mode process. It is left empty by default. Set this parameter based on service requirements.
A
annie_wangli 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182
                  template device {
                      template deviceNode {
                          policy = 0;
                          priority = 100;
                          preload = 0;
                          permission = 0664;
                          moduleName = "";
                          serviceName = "";
                          deviceMatchAttr = "";
                      }
                  }
              }
              sample_host :: host{
A
Annie_wang 已提交
183 184
                  hostName = "host0";    // Host name. The host node is used as a container to hold a type of drivers.
                  priority = 100;        // Host startup priority (0-200). A smaller value indicates a higher priority. The default value 100 is recommended. The hosts with the same priority start based on the time when the priority was configured. The host configured first starts first.
A
annie_wangli 已提交
185 186 187
                  caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"];   // Linux capabilities of the user-mode process.
                  device_sample :: device {        // Sample device node.
                      device0 :: deviceNode {      // DeviceNode of the sample driver.
A
Annie_wang 已提交
188
                          policy = 1;             // Policy for providing the driver service. For details, see Driver Service Management.
A
Annie_wang 已提交
189 190
                          priority = 100;          // Driver startup priority (0-200). A smaller value indicates a higher priority. The default value 100 is recommended. The drivers with the same priority start based on the time when the priority was configured. The driver configured first starts first.
                          preload = 0;            // The loading mode of the driver is on-demand loading. For details, see "NOTE" at the end of this document.
A
annie_wangli 已提交
191
                          permission = 0664;       // Permission for the driver to create a device node.
A
Annie_wang 已提交
192
                          moduleName = "sample_driver"; // Driver name. The value must be the same as that of moduleName in the HdfDriverEntry structure.
A
Annie_wang 已提交
193
                          serviceName = "sample_service";    // Name of the service provided by the driver. The service name must be unique.
A
annie_wangli 已提交
194 195 196 197 198 199 200
                          deviceMatchAttr = "sample_config"; // Keyword for matching the private data of the driver. The value must be the same as that of match_attr in the private data configuration table of the driver.
                      }
                  }
              }
          }
      }
      ```
A
Annie_wang 已提交
201
      ![icon-note.gif](../public_sys-resources/icon-note.gif) **NOTE**<br>
A
annie_wangli 已提交
202

A
Annie_wang 已提交
203
      - **uid**, **gid**, and **caps** are startup parameters for user-mode drivers only.
A
annie_wangli 已提交
204
      - According to the principle of least privilege for processes, **uid** and **gid** do not need to be configured for service modules. In the preceding example, **uid** and **gid** are left empty (granted with the common user rights) for sample_host.
A
Annie_wang 已提交
205 206 207
      - If you need to set **uid** and **gid** to **system** or **root** due to service requirements, contact security experts for review.
      - The process UIDs are configured in **base/startup/init_lite/services/etc/passwd**, and the process GIDs are configured in **base/startup/init_lite/services/etc/group**. For details, see [Adding a System Service User Group]( https://gitee.com/openharmony/startup_init_lite/wikis).
      - If CAP_DAC_OVERRIDE needs to be configured for a service module, enter **caps = ["DAC_OVERRIDE"]** instead of **caps = ["CAP_DAC_OVERRIDE"]**.
A
annie_wangli 已提交
208 209 210

      

A
Annie_wang 已提交
211
   - (Optional) Setting driver private information<br/>
A
Annie_wang 已提交
212
      If the driver has private configuration, add a driver configuration file to set default driver configuration. When loading the driver, the HDF obtains and saves the driver private information in **property** of **HdfDeviceObject**, and passes the information to the driver using **Bind()** and **Init()** (see step 1). 
A
annie_wangli 已提交
213
   
A
Annie_wang 已提交
214 215
      The following is an example of the driver private configuration:
      
A
annie_wangli 已提交
216 217 218 219 220 221
      
      ```
      root {
          SampleDriverConfig {
              sample_version = 1;
              sample_bus = "I2C_0";
A
Annie_wang 已提交
222
              match_attr = "sample_config"; // The value must be the same as that of deviceMatchAttr in device_info.hcs.
A
annie_wangli 已提交
223 224 225 226
          }
      }
      ```

A
Annie_wang 已提交
227 228 229 230
      After the configuration, add the configuration file to the board-level configuration entry file **hdf.hcs**. (You can use DevEco to perform one-click configuration. For details, see the description about the driver development suite.) 
      
      The following is an example:
      
A
annie_wangli 已提交
231 232 233 234 235 236 237
      
      ```
      #include "device_info/device_info.hcs"
      #include "sample/sample_config.hcs"
      ```


A
Annie_wang 已提交
238
> ![icon-note.gif](../public_sys-resources/icon-note.gif) **NOTE**<br>
A
annie_wangli 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251
> Drivers can be loaded on demand or in sequence.
>
> - On-demand loading
>
>   ```
>   typedef enum {
>       DEVICE_PRELOAD_ENABLE = 0,
>       DEVICE_PRELOAD_ENABLE_STEP2,
>       DEVICE_PRELOAD_DISABLE,
>       DEVICE_PRELOAD_INVALID
>   } DevicePreload;
>   ```
>
A
Annie_wang 已提交
252
>   If **preload** in the configuration file is set to **0 (DEVICE_PRELOAD_ENABLE)**, the driver is loaded by default during the system boot process. 
A
annie_wangli 已提交
253
>
A
Annie_wang 已提交
254
>   If **preload** is set to **1 (DEVICE_PRELOAD_ENABLE_STEP2)**, the driver is loaded after a quick start is complete. If the system does not support quick start, the value **1** has the same meaning as **DEVICE_PRELOAD_ENABLE**. 
A
annie_wangli 已提交
255
>
A
Annie_wang 已提交
256
>   If **preload** is set to **2 (DEVICE_PRELOAD_DISABLE)** , the driver is dynamically loaded instead of being loaded during the system boot process. When a user-mode process requests the driver service, the HDF attempts to dynamically load the driver if the driver service does not exist.  For more details, see [Driver Messaging Mechanism](driver-hdf-message-management.md).
A
annie_wangli 已提交
257
>
A
Annie_wang 已提交
258
> - Sequential loading (**preload** set to **0 (DEVICE_PRELOAD_ENABLE)**)<br/>
A
Annie_wang 已提交
259
>   In the configuration file, the **priority** fields (value range: 0 to 200) determines the loading sequence of a host and a driver. For drivers in different hosts, a smaller host priority value indicates a higher driver loading priority; for drivers in the same host, a smaller driver priority value indicates a higher driver loading priority.