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


## Driver Model

A
Annie_wang 已提交
6
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.
A
Annie_wang 已提交
7 8

The figure below shows the HDF driver model.
A
Annie_wang 已提交
9
 **Figure 1** HDF driver model
A
annie_wangli 已提交
10 11 12 13

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


14
## How to Develop
A
annie_wangli 已提交
15

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

A
Annie_wang 已提交
18 19
1. Implement a driver.
   
A
Annie_wang 已提交
20
   Write the driver code and register the driver entry with the HDF.
A
Annie_wang 已提交
21
   
A
Annie_wang 已提交
22 23 24
   - Writing the driver service code 
   
     The following is an example:
A
Annie_wang 已提交
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
     
      ```
      #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 已提交
53
   - Registering the driver entry with the HDF
A
Annie_wang 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67
     
      ```
      // 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 已提交
68
   
A
Annie_wang 已提交
69
2. Build the driver.
A
Annie_wang 已提交
70
   
A
Annie_wang 已提交
71
   - LiteOS
A
Annie_wang 已提交
72
   
A
Annie_wang 已提交
73
      Modify **makefile** and **BUILD.gn**.
A
Annie_wang 已提交
74
   
75
      - **Makefile**:<br/>
A
Annie_wang 已提交
76 77 78 79
   
        Use the **makefile** template provided by the HDF to compile the driver code.
   
      
A
annie_wangli 已提交
80 81 82
         ```
         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 已提交
83
         LOCAL_INCLUDE: =  # Directory of the driver header files.
A
annie_wangli 已提交
84 85
         LOCAL_SRCS : =     # Source code file of the driver.
         LOCAL_CFLAGS : =  # Custom compilation options.
A
Annie_wang 已提交
86
         include $(HDF_DRIVER) # Import the Makefile template to complete the build.
A
annie_wangli 已提交
87
         ```
A
Annie_wang 已提交
88 89 90 91
   
        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. The following is an example:
   
      
A
annie_wangli 已提交
92 93
         ```
         LITEOS_BASELIB += -lxxx # Static library generated by the link.
94
         LIB_SUBDIRS    +=         # Directory in which Makefile is located.
A
annie_wangli 已提交
95
         ```
A
Annie_wang 已提交
96 97 98 99 100 101
   
      - **BUILD.gn**:
   
        Add **BUILD.gn**. The content of **BUILD.gn** is as follows:
   
        
A
annie_wangli 已提交
102 103 104 105 106 107 108
         ```
         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 已提交
109
                 "xxx/xxx/xxx.c", # Source code to compile.
A
annie_wangli 已提交
110
             ]
A
Annie_wang 已提交
111
             public_configs = [ ":public" ] # Head file configuration of the dependencies.
A
annie_wangli 已提交
112
         }
A
Annie_wang 已提交
113
         config("public") {# Define the head file configuration of the dependencies.
A
annie_wangli 已提交
114
             include_dirs = [
A
Annie_wang 已提交
115
             "xxx/xxx/xxx", # Directory of the dependency header files.
A
annie_wangli 已提交
116 117 118
             ]
         }
         ```
A
Annie_wang 已提交
119
   
A
Annie_wang 已提交
120
         Add the **BUILD.gn** directory to **/drivers/adapter/khdf/liteos/BUILD.gn**.
A
Annie_wang 已提交
121 122
   
        
A
annie_wangli 已提交
123 124 125 126 127 128 129 130
         ```
         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 已提交
131 132
      
   - Linux
A
annie_wangli 已提交
133

A
Annie_wang 已提交
134 135
      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**.
   
A
annie_wangli 已提交
136 137 138 139 140 141
      
      ```
      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**.
A
Annie_wang 已提交
142
   
A
annie_wangli 已提交
143 144 145 146 147
      
      ```
      obj-$(CONFIG_DRIVERS_HDF)  += xxx/
      ```

148
      Add a **Makefile** to the driver directory **xxx** and add code compiling rules of the driver to the file.
A
Annie_wang 已提交
149
   
A
annie_wangli 已提交
150 151 152 153
      
      ```
      obj-y  += xxx.o
      ```
A
Annie_wang 已提交
154
   
A
Annie_wang 已提交
155
3. Configure the driver.<br/>
A
Annie_wang 已提交
156

A
Annie_wang 已提交
157
   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 已提交
158 159 160

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

A
Annie_wang 已提交
161
   - (Mandatory) Setting the driver device description<br/>
A
annie_wangli 已提交
162

A
Annie_wang 已提交
163 164 165
     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 已提交
166 167 168 169
      ```
      root {
          device_info {
              match_attr = "hdf_manager";
A
Annie_wang 已提交
170
              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 已提交
171 172
                  hostName = "";
                  priority = 100;
A
Annie_wang 已提交
173 174 175
                  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 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188
                  template device {
                      template deviceNode {
                          policy = 0;
                          priority = 100;
                          preload = 0;
                          permission = 0664;
                          moduleName = "";
                          serviceName = "";
                          deviceMatchAttr = "";
                      }
                  }
              }
              sample_host :: host{
A
Annie_wang 已提交
189 190
                  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 已提交
191 192 193
                  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 已提交
194
                          policy = 1;             // Policy for publishing the driver service. For details, see Driver Service Management.
A
Annie_wang 已提交
195 196
                          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 已提交
197
                          permission = 0664;       // Permission for the driver to create a device node.
A
Annie_wang 已提交
198 199
                          moduleName = "sample_driver"; // Driver name. The value of this field must be the same as that of moduleName in the HdfDriverEntry structure.
                          serviceName = "sample_service";    // Name of the service published by the driver. The service name must be unique.
A
annie_wangli 已提交
200 201 202 203 204 205 206
                          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 已提交
207
      ![icon-note.gif](../public_sys-resources/icon-note.gif) **NOTE**<br>
A
annie_wangli 已提交
208

A
Annie_wang 已提交
209
      - **uid**, **gid**, and **caps** are startup parameters for user-mode drivers only.
A
Annie_wang 已提交
210

A
annie_wangli 已提交
211
      - 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 已提交
212

A
Annie_wang 已提交
213
      - If you need to set **uid** and **gid** to **system** or **root** due to service requirements, contact security experts for review.
A
Annie_wang 已提交
214

A
Annie_wang 已提交
215
      - 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).
A
annie_wangli 已提交
216

A
Annie_wang 已提交
217
      - 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 已提交
218

A
Annie_wang 已提交
219
   - (Optional) Setting driver private information<br/>
A
Annie_wang 已提交
220

A
Annie_wang 已提交
221
      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_wang 已提交
222

A
Annie_wang 已提交
223 224
      The following is an example of the driver private configuration:
      
A
annie_wangli 已提交
225 226 227 228 229
      ```
      root {
          SampleDriverConfig {
              sample_version = 1;
              sample_bus = "I2C_0";
A
Annie_wang 已提交
230
              match_attr = "sample_config"; // The value must be the same as that of deviceMatchAttr in device_info.hcs.
A
annie_wangli 已提交
231 232 233 234
          }
      }
      ```

A
Annie_wang 已提交
235
      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.) 
A
Annie_wang 已提交
236

A
Annie_wang 已提交
237 238
      The following is an example:
      
A
annie_wangli 已提交
239 240 241 242 243 244
      ```
      #include "device_info/device_info.hcs"
      #include "sample/sample_config.hcs"
      ```


A
Annie_wang 已提交
245
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br/>
A
annie_wangli 已提交
246
> Drivers can be loaded on demand or in sequence.
A
Annie_wang 已提交
247
> 
A
annie_wangli 已提交
248
> - On-demand loading
A
Annie_wang 已提交
249
>     
A
annie_wangli 已提交
250 251 252 253 254 255 256 257
>   ```
>   typedef enum {
>       DEVICE_PRELOAD_ENABLE = 0,
>       DEVICE_PRELOAD_ENABLE_STEP2,
>       DEVICE_PRELOAD_DISABLE,
>       DEVICE_PRELOAD_INVALID
>   } DevicePreload;
>   ```
A
Annie_wang 已提交
258
> 
A
Annie_wang 已提交
259
>   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 已提交
260
>
A
Annie_wang 已提交
261
>   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 已提交
262
>
A
Annie_wang 已提交
263
>   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_wang 已提交
264
> 
A
Annie_wang 已提交
265
> - Sequential loading (**preload** set to **0 (DEVICE_PRELOAD_ENABLE)**)<br/>
A
Annie_wang 已提交
266
>   In the configuration file, the **priority** field (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.