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

A
Annie_wang 已提交
10
  **Figure 1** HDF driver model
A
annie_wangli 已提交
11 12 13 14

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


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

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

A
Annie_wang 已提交
19
1. Implement a driver.
A
Annie_wang 已提交
20

A
Annie_wang 已提交
21
   Write the driver code and register the driver entry with the HDF.
A
Annie_wang 已提交
22 23

   - Write the driver service code. 
A
Annie_wang 已提交
24
     
A
Annie_wang 已提交
25 26
      The following is an example:
      
A
Annie_wang 已提交
27
      ```
A
Annie_wang 已提交
28 29
      #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.
A
Annie_wang 已提交
30 31 32
      
      #define HDF_LOG_TAG "sample_driver"   // Tag contained in logs. If no tag is not specified, the default HDF_TAG is used.
      
A
Annie_wang 已提交
33
      // Bind the service APIs provided by the driver to the HDF.
A
Annie_wang 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
      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_wang 已提交
54 55
      
   - Register the driver entry with the HDF.
A
Annie_wang 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69
     
      ```
      // 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 已提交
70

A
Annie_wang 已提交
71
2. Build the driver.
A
Annie_wang 已提交
72

A
Annie_wang 已提交
73
   - LiteOS
A
Annie_wang 已提交
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

     Modify **Makefile** and **BUILD.gn** files.

     - **Makefile**:

       Use the **Makefile** template provided by the HDF to compile the driver code.

       
       ```
       include $(LITEOSTOPDIR)/../../drivers/adapter/khdf/liteos/lite.mk # (Mandatory) Import the HDF predefined content.
       MODULE_NAME :=        # File to be generated.
       LOCAL_INCLUDE: =      # Directory of the driver header files.
       LOCAL_SRCS : =        # Source code files of the driver.
       LOCAL_CFLAGS : =      # Custom build options.
       include $(HDF_DRIVER) # Import the Makefile template to complete the build.
       ```

       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:

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

     - **BUILD.gn**:

       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 = [
               "xxx/xxx/xxx.c",           # Source code to compile.
           ]
           public_configs = [ ":public" ] # Head file configuration of the dependencies.
       }
       config("public") {                 # Define the head file configuration of the dependencies.
           include_dirs = [
           "xxx/xxx/xxx",                 # Directory of dependency header files.
           ]
       }
       ```

       Add the **BUILD.gn** directory to **/drivers/adapter/khdf/liteos/BUILD.gn**.

       
       ```
       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 已提交
133
   - Linux
A
annie_wangli 已提交
134

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

A
Annie_wang 已提交
137 138 139 140
     
     ```
     source "drivers/hdf/khdf/xxx/Kconfig" # Kernel directory to which the HDF module is soft linked.
     ```
A
annie_wangli 已提交
141

A
Annie_wang 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
     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
     ```

3. Configure the driver.
A
Annie_wang 已提交
157

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

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

A
Annie_wang 已提交
162
   - (Mandatory) Set driver device information.
A
annie_wangli 已提交
163

A
Annie_wang 已提交
164
     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. 
A
Annie_wang 已提交
165

A
Annie_wang 已提交
166 167
     The following is an example:
     
A
Annie_wang 已提交
168
     
A
annie_wangli 已提交
169 170 171 172
      ```
      root {
          device_info {
              match_attr = "hdf_manager";
A
Annie_wang 已提交
173
              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 已提交
174 175
                  hostName = "";
                  priority = 100;
A
Annie_wang 已提交
176 177 178
                  uid = "";         // User ID (UID) of the 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 the 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 the user-mode process. It is left empty by default. Set this parameter based on service requirements.
A
annie_wangli 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191
                  template device {
                      template deviceNode {
                          policy = 0;
                          priority = 100;
                          preload = 0;
                          permission = 0664;
                          moduleName = "";
                          serviceName = "";
                          deviceMatchAttr = "";
                      }
                  }
              }
              sample_host :: host{
A
Annie_wang 已提交
192 193
                  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 已提交
194 195 196
                  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 已提交
197
                          policy = 1;              // Policy for publishing the driver service. For details, see Driver Service Management.
A
Annie_wang 已提交
198
                          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.
A
Annie_wang 已提交
199
                          preload = 0;             // The driver is loaded on demand. For details, see "NOTE" at the end of this document.
A
annie_wangli 已提交
200
                          permission = 0664;       // Permission for the driver to create a device node.
A
Annie_wang 已提交
201
                          moduleName = "sample_driver";      // Driver name. The value of this field must be the same as that of moduleName in the HdfDriverEntry structure.
A
Annie_wang 已提交
202
                          serviceName = "sample_service";    // Name of the service published by the driver. The service name must be unique.
A
annie_wangli 已提交
203 204 205 206 207 208 209
                          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 已提交
210 211 212 213 214 215 216 217 218 219 220 221
     
      > ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br/>
      >
      > - **uid**, **gid**, and **caps** are startup parameters for user-mode drivers only.
      >
      > - 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.
      >
      > - 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 已提交
222 223


A
Annie_wang 已提交
224
   - (Optional) Set driver private information.
A
Annie_wang 已提交
225

A
Annie_wang 已提交
226
     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 已提交
227

A
Annie_wang 已提交
228 229 230 231
     The following is an example of the driver private configuration:
     
     ```
     root {
A
annie_wangli 已提交
232 233 234
          SampleDriverConfig {
              sample_version = 1;
              sample_bus = "I2C_0";
A
Annie_wang 已提交
235
              match_attr = "sample_config"; // The value must be the same as that of deviceMatchAttr in device_info.hcs.
A
annie_wangli 已提交
236 237
          }
      }
A
Annie_wang 已提交
238 239 240 241 242 243 244 245 246 247 248 249
     ```
     
     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: 
     
     ```
     #include "device_info/device_info.hcs"
     #include "sample/sample_config.hcs"
     ```
     
     
A
Annie_wang 已提交
250

A
Annie_wang 已提交
251

A
annie_wangli 已提交
252 253


A
Annie_wang 已提交
254
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
A
annie_wangli 已提交
255
> Drivers can be loaded on demand or in sequence.
A
Annie_wang 已提交
256
> 
A
annie_wangli 已提交
257
> - On-demand loading
A
Annie_wang 已提交
258
>   
A
annie_wangli 已提交
259 260 261 262 263 264 265 266
>   ```
>   typedef enum {
>       DEVICE_PRELOAD_ENABLE = 0,
>       DEVICE_PRELOAD_ENABLE_STEP2,
>       DEVICE_PRELOAD_DISABLE,
>       DEVICE_PRELOAD_INVALID
>   } DevicePreload;
>   ```
A
Annie_wang 已提交
267
> 
A
Annie_wang 已提交
268
>   - 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 已提交
269
>
A
Annie_wang 已提交
270
>   - 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 已提交
271
>
A
Annie_wang 已提交
272
>   - If **preload** is set to **2** (**DEVICE_PRELOAD_DISABLE**), the driver service is dynamically loaded. When a user-mode process requests the driver service, the HDF attempts to dynamically load the driver if the driver service is not available. >   For more details, see [Driver Messaging Mechanism](../driver/driver-hdf-message-management.md).
A
Annie_wang 已提交
273
> 
A
Annie_wang 已提交
274 275 276
> - Sequential loading (**preload** set to **0 (DEVICE_PRELOAD_ENABLE)**)
>
>   In the configuration file, the **priority** field (ranging from 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.