1# HDF Driver Development Process
2
3## Overview
4
5The Hardware Driver Foundation (HDF) provides a driver development framework to implement driver loading, driver service management, driver messaging mechanism, and configuration management. It provides a component-based driver model to normalize driver development and deployment. The HDF strives to build a unified driver platform to back up a more precise and efficient environment for one-time development for multi-device deployment.
6
7### Driver Loading
8
9The HDF allows loading of the drivers that match the configured device list.
10
11### Driver Service Management
12
13The HDF supports centralized management of driver services. You can obtain a driver service by using the APIs provided by the HDF.
14
15### Driver Messaging Mechanism
16
17The HDF provides a unified driver messaging mechanism, which allows messages to be exchanged between user-mode applications and kernel-mode drivers.
18
19### Configuration Management
20
21HDF Configuration Source (HCS) provides the source code of the HDF configuration in key-value (KV) pairs. It decouples the configuration code from the driver code, thereby facilitating configuration management.
22
23### Driver Model
24
25The device model involves the following concepts:
26
27- Host: In the HDF, the device drivers of the same type are placed in a host. The host manages the startup and loading of a group of devices.  You can deploy the drivers that depend on each other to the same host, and deploy independent drivers to different hosts.
28- Device: A device corresponds to a physical device.
29- Device Node: A device node is a component of a device. A device has at least one device node. Each device node can publish a device service. Each device node corresponds to a unique driver to interact with the hardware.
30
31The following figure shows the HDF driver model.
32
33**Figure 1** HDF driver model
34
35![](figures/hdf-driver-model.png)
36
37## Driver Functions
38
39### Driver Loading
40
41The HDF implements loading of the drivers that match the configured device list. The drivers can be loaded on demand or in sequence. The **preload** field in the configuration file specifies the loading policy. The values of **preload** are as follows:
42
43```c
44typedef enum {
45    DEVICE_PRELOAD_ENABLE = 0,
46    DEVICE_PRELOAD_ENABLE_STEP2 = 1,
47    DEVICE_PRELOAD_DISABLE = 2,
48    DEVICE_PRELOAD_INVALID
49} DevicePreload;
50```
51
52#### On-Demand Loading
53
54- **0** (**DEVICE_PRELOAD_ENABLE**): loads the driver during the system boot process.
55- **1** (**DEVICE_PRELOAD_ENABLE_STEP2**): loads the driver 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**.
56- **2** (**DEVICE_PRELOAD_DISABLE**): dynamically loads the driver after the system starts. If the driver service does not exist when a user-mode process attempts to obtain the driver service [messaging mechanism](#driver-messaging-mechanism), the HDF will dynamically load the driver.
57
58#### Sequential Loading (Default)
59
60The **priority** field (ranging from 0 to 200) in the configuration file determines the loading sequence of a host and a driver. For the drivers in different hosts, the driver with a smaller host priority is loaded first. For the drivers in the same host, the driver with a smaller priority is loaded first.
61
62#### Exception Recovery (User-Mode Driver)
63
64The policies for restoring from a driver service exception are as follows:
65- If **preload** is set to **0** (**DEVICE_PRELOAD_ENABLE**) or **1** (**DEVICE_PRELOAD_ENABLE_STEP2**) for the driver service, the startup module starts the host and reloads the service.
66- If **preload** is set to **2** (**DEVICE_PRELOAD_DISABLE**), the service module needs to register an HDF service status listener. When receiving a notification on service exit, the service module calls **LoadDevice()** to reload the service.
67
68### Driver Service Management
69
70Driver services, as capability objects externally provided by HDF driver devices, are managed by the HDF in a unified manner. Driver service management involves publishing and obtaining driver services. The **policy** field in the configuration file defines the service publishing policies. The values of this field are as follows:
71
72```c
73typedef enum {
74    /* The driver does not provide services. */
75    SERVICE_POLICY_NONE = 0,
76    /* The driver publishes services only for kernel-mode processes. */
77    SERVICE_POLICY_PUBLIC = 1,
78    /* The driver publishes services for both kernel- and user-mode processes. */
79    SERVICE_POLICY_CAPACITY = 2,
80    /** The driver services are not published externally but can be subscribed to. */
81    SERVICE_POLICY_FRIENDLY = 3,
82    /* The driver private services cannot be published externally or subscribed to. */
83    SERVICE_POLICY_PRIVATE = 4,
84    /** Invalid service policy. */
85    SERVICE_POLICY_INVALID
86} ServicePolicy;
87```
88
89#### When to Use
90
91You need to implement HDF driver service management when your driver needs to provide external capabilities via APIs.
92
93#### Available APIs
94
95The following table describes the APIs for driver service management.
96
97**Table 1** APIs for driver service management
98
99| API                                                        | Description                                                        |
100| ------------------------------------------------------------ | ------------------------------------------------------------ |
101| int32_t (*Bind)(struct HdfDeviceObject *deviceObject)        | Binds a service interface to the HDF. You need to implement **Bind**.|
102| const struct HdfObject *DevSvcManagerClntGetService(const char *svcName) | Obtains a driver service.                                            |
103| int HdfDeviceSubscribeService( struct HdfDeviceObject *deviceObject, const char *serviceName, struct SubscriberCallback callback) | Subscribes to a driver service.                                            |
104
105
106### Driver Messaging Mechanism
107
108#### When to Use
109
110The HDF messaging mechanism implements interaction between the user-mode applications and kernel-mode drivers.
111
112#### Available APIs
113
114The messaging mechanism allows:
115- A user-mode application to send a message to a driver.
116- A user-mode application to receive events reported by a driver.
117
118**Table 2** APIs for the driver messaging mechanism
119
120| API                                                          | Description                                                  |
121| ------------------------------------------------------------ | ------------------------------------------------------------ |
122| struct HdfIoService *HdfIoServiceBind(const char *serviceName); | Obtains a driver service. After obtaining the driver service, the user-mode application calls **Dispatch()** in the driver service obtained to send messages to the driver. |
123| void HdfIoServiceRecycle(struct HdfIoService *service);      | Releases a driver service.                                   |
124| int HdfDeviceRegisterEventListener(struct HdfIoService *target, struct HdfDevEventlistener *listener); | Registers an event listener to receive events from the driver. |
125| int32_t HdfDeviceSendEvent(const struct HdfDeviceObject *deviceObject, uint32_t id, const struct HdfSBuf *data) | Sends an event.                                              |
126
127
128
129### Configuration Management
130
131#### HDF Configuration Overview
132
133The HCS provides the HDF configuration source code in KV pairs. It decouples the configuration code from the driver code, thereby facilitating configuration management. You can use the HDF Configuration Generator (HC-GEN) to convert an HCS configuration file into a file that can be read by the software.
134
135-   In a low-performance system on a chip (SoC), the HC-GEN tool converts an HCS configuration file into the source code or macro definitions of the configuration tree. The driver can obtain the configuration by calling the C code or macro-based APIs.
136-   In a high-performance SoC, the tool converts an HCS configuration file into an HDF configuration binary (HCB) file. The driver can obtain the configuration by calling the configuration parsing APIs provided by the HDF.
137
138The following figure illustrates the configuration management process.
139
140**Figure 2** Configuration management process
141
142![](figures/HCB-using-process.png)
143
144The HC-GEN converts the HCS into an HCB file. The HCS Parser module in the HDF rebuilds a configuration tree from the HCB file. The HDF driver obtains the configuration through the APIs provided by the HCS Parser.
145
146#### Configuration Syntax
147
148The following describes the HCS syntax.
149
150##### Keyword
151
152The following table describes the keywords used in the HCS syntax.
153
154**Table 3** Keywords used in the HCS syntax
155
156| Keyword    | Description            | Remarks                               |
157| ---------- | -------------------------- | ------------------------------------------ |
158| root       | Sets the root node.                | -                                          |
159| include    | Includes another HCS file.       | -                                          |
160| delete     | Deletes a node or an attribute.            | Applicable only to the configuration tree imported by using **include**.           |
161| template   | Defines a template node.              | -                                          |
162| match_attr | Marks the node attribute for matching.| During configuration parsing, the attribute value can be used to locate the corresponding node.|
163
164##### Basic Structs
165
166The HCS has two structs: **Attribute** and **Node**.
167
168**Attribute**
169
170**Attribute** is the minimum, independent configuration unit. The syntax is as follows:
171
172```
173  attribute_name = value;
174```
175
176-   **attribute_name** is a case-sensitive string consisting of letters, digits, and underscores (\_) and must start with a letter or underscore (_).
177-   The **value** can be in any of the following formats:
178    -   Numeric constant. The value can be a binary, octal, decimal, or hexadecimal number. For details, see [Data Types](#data-types).
179    -   String quoted by double quotation marks ("").
180    -   Node reference.
181-   An attribute key-value pair must end with a semicolon (;) and belong to a node.
182
183**Node**
184
185**Node** is a set of attributes. The syntax is as follows:
186
187```
188  node_name {
189      module = "sample";
190      ...
191  }
192```
193
194-   **node_name** is a case-sensitive string consisting of letters, digits, and underscores (\_) and must start with a letter or underscore (_).
195-   No semicolon (;) is required after the curly brace ({) or (}).
196-   The keyword **root** is used to declare the root node of a configuration table. Each configuration table must start with the root node.
197-   The root node must contain a **module** attribute. The value is a string indicating the module to which the configuration belongs.
198-   The **match_attr** attribute can be added to a node. Its value is a globally unique string. When parsing the configuration, the driver can use the value of this attribute as a parameter to call an API to locate the node that has this attribute.
199
200##### Data Types
201
202Attributes use built-in data types. You do not need to explicitly specify the data type for attribute values. Attributes support the following data types:
203
204**Integer**
205
206An integer can be in any of the following formats. The data type is assigned based on the actual data length and minimum space required.
207
208-   Binary: prefixed with **0b**. For example, **0b1010**.
209-   Octal: prefixed with **0**. For example, **0664**.
210-   Decimal: signed or unsigned, without prefix. For example, **1024** or **+1024**. Negative integers can be read only via APIs with signed numbers.
211-   Hexadecimal: prefixed with **0x**. For example, **0xff00** and **0xFF**.
212
213**String**
214
215A string is enclosed in double quotation marks ("").
216
217**Array**
218
219An array can hold either integers or strings, but not both of them. The mixed use of **uint32_t** and **uint64_t** in an integer array will cause typecasting to **uint64**. The following is an example of an integer array and a string array:
220
221```
222attr_foo = [0x01, 0x02, 0x03, 0x04];
223attr_bar = ["hello", "world"];
224```
225
226**Boolean**
227
228Boolean is a form of data with only two possible values: **true** and **false**.
229
230##### Preprocessing
231
232**include**
233
234The keyword **include** is used to import an HCS file. The syntax is as follows:
235
236```
237#include "foo.hcs"
238#include "../bar.hcs"
239```
240
241-   The file name must be enclosed in double quotation marks (""). If the file to be included is in a different directory with the target file, use a relative path. The included file must be a valid HCS file.
242-   If multiple HCS files included contain the same nodes, the same nodes will be overridden and other nodes are listed in sequence.
243
244##### Comments
245
246The following two comment formats are supported:
247
248-   Single-line comment
249
250    ```
251    // comment
252    ```
253
254-   Multi-line comment
255
256    ```
257    /*
258    comment
259    */
260    ```
261
262    >   **NOTE**
263    >
264    >   Multi-line comments cannot be nested.
265
266##### Reference Modification
267
268You can reference the content of a node to modify the content of another node. The syntax is as follows:
269
270```
271 node :& source_node
272```
273
274In this statement, the content of **node** is referenced to modify the content of **source_node**. <br>Example:
275
276```
277root {
278    module = "sample";
279    foo {
280        foo_ :& root.bar{
281            attr = "foo";
282        }
283        foo1 :& foo2 {
284            attr = 0x2;
285        }
286        foo2 {
287            attr = 0x1;
288        }
289    }
290
291    bar {
292        attr = "bar";
293    }
294}
295```
296
297The configuration tree generated is as follows:
298
299```
300root {
301    module = "sample";
302    foo {
303        foo2 {
304            attr = 0x2;
305        }
306    }
307    bar {
308        attr = "foo";
309    }
310}
311```
312
313In this example, the value of **bar.attr** is changed to **foo** by referencing **foo.foo_**, and the value of **foo.foo2.attr** is changed to **0x2** by referencing **foo.foo1**. The **foo.foo_** and **foo.foo1** nodes are used to modify the content of the target nodes, and do not exist in the configuration tree generated.
314
315-   A node of the same level can be referenced simply by using the node name. To reference a node of a different level, use the absolute path starting with **root**, and separate the node names using a period (.). **root** indicates the root node. For example, **root.foo.bar**.
316-   If multiple modifications are made to the same attribute, only one modification takes effect and a warning will be displayed for you to confirm the result.
317
318##### Node Replication
319
320You can replicate a node to define a node with similar content. The syntax is as follows:
321
322```
323 node : source_node
324```
325
326This statement replicates the attributes of the **source_node** node to define **node**. <br>Example:
327
328```
329root {
330    module = "sample";
331    foo {
332        attr_0 = 0x0;
333    }
334    bar:foo {
335        attr_1 = 0x1;
336    }
337}
338```
339
340The configuration tree generated is as follows:
341
342```
343root {
344    module = "sample";
345    foo {
346        attr_0 = 0x0;
347    }
348    bar {
349        attr_1 = 0x1;
350        attr_0 = 0x0;
351    }
352}
353```
354
355In this example, the **bar** node contains **attr_0** and **attr_1** attributes, and the modification of the **attr_0** attribute in the **bar** node does not affect the **foo** node.
356
357You do not need to specify the path of the **foo** node if **foo** and **bar** are of the same level. Otherwise, you need to specify the absolute path of **foo** by using [Reference Modification](#reference-modification).
358
359##### Delete
360
361You can use the keyword **delete** to delete unnecessary nodes or attributes from the base configuration tree imported by using the **include** keyword. The following example includes the configuration in **sample2.hcs** to **sample1.hcs** and deletes the **attribute2** attribute and the **foo_2** node. <br>Example:
362
363```
364// sample2.hcs
365root {
366    attr_1 = 0x1;
367    attr_2 = 0x2;
368    foo_2 {
369        t = 0x1;
370    }
371}
372
373// sample1.hcs
374#include "sample2.hcs"
375root {
376    attr_2 = delete;
377    foo_2 : delete {
378    }
379}
380```
381
382The configuration tree generated is as follows:
383
384```
385root {
386    attr_1 = 0x1;
387}
388```
389
390>   **NOTE**<br>
391>   The keyword **delete** cannot be used to delete nodes or attributes in the same HCS file. In an HCS file, you can directly delete unnecessary attributes.
392
393##### Attribute References
394
395You can associate an attribute and a node so that the node can be quickly located when the attribute is read during configuration parsing. The syntax is as follows:
396
397```
398 attribute = &node;
399```
400
401In this statement, the value of **attribute** is a referenced to the node. During code parsing, you can quickly locate the node based on this **attribute**. <br>Example:
402
403```
404node1 {
405    attributes;
406}
407node2 {
408    attr_1 = &root.node1;
409}
410```
411
412or
413
414```
415node2 {
416    node1 {
417        attributes;
418    }
419    attr_1 = &node1;
420}
421```
422
423##### Template
424
425The template is used to generate nodes with consistent syntax, thereby facilitating the traverse and management of nodes of the same type. If a node is defined using the keyword **template**, its child nodes inherit from the node configuration through the double colon operator (::). The child nodes can modify or add but cannot delete attributes in **template**. The attributes not defined in the child nodes will use the attributes defined in **template** as the default values. <br>Example:
426
427```
428root {
429    module = "sample";
430    template foo {
431        attr_1 = 0x1;
432        attr_2 = 0x2;
433    }
434
435    bar :: foo {
436    }
437
438    bar_1 :: foo {
439        attr_1 = 0x2;
440    }
441}
442```
443
444 The configuration tree generated is as follows:
445
446```
447root {
448    module = "sample";
449    bar {
450        attr_1 = 0x1;
451        attr_2 = 0x2;
452    }
453    bar_1 {
454        attr_1 = 0x2;
455        attr_2 = 0x2;
456    }
457}
458```
459
460In this example, the **bar** and **bar_1** nodes inherit from the **foo** node. The structure of the generated configuration tree is the same as that of the **foo** node, except that the attribute values are different.
461
462#### Configuration Generation
463
464The HC-GEN tool checks the HCS configuration syntax and converts HCS source files into HCB files.
465
466**HC-GEN**
467
468HC-GEN options:
469
470```
471Usage: hc-gen [Options] [File]
472options:
473  -o <file>   output file name, default same as input
474  -a          hcb align with four bytes
475  -b          output binary output, default enable
476  -t          output config in C language source file style
477  -m          output config in macro source file style
478  -i          output binary hex dump in C language source file style
479  -p <prefix> prefix of generated symbol name
480  -d          decompile hcb to hcs
481  -V          show verbose info
482  -v          show version
483  -h          show this help message
484```
485
486Generate a .c or .h configuration file.
487
488```
489hc-gen -o [OutputCFileName] -t [SourceHcsFileName]
490```
491
492Generate an HCB file.
493
494```
495hc-gen -o [OutputHcbFileName] -b [SourceHcsFileName]
496```
497
498Generate a macro definition file.
499
500```
501hc-gen -o [OutputMacroFileName] -m [SourceHcsFileName]
502```
503
504Decompile an HCB file to an HCS file.
505
506```
507hc-gen -o [OutputHcsFileName] -d [SourceHcbFileName]
508```
509
510## Development
511
512### When to Use
513
514During driver development, the driver cannot be loaded in the code compilation process without service management and messaging mechanism. The following describes the driver development process.
515
516### Driver Development Example
517
518The HDF-based driver development involves the following:<br>1. Implement the driver.<br>2. Write the driver build script.<br>3. Configure the driver.
519
520#### Implementing a Driver
521
522Write the driver code and register the driver entry with the HDF.
523
524-   Write the driver service code.<br>Example:
525
526    ```c
527    #include "hdf_device_desc.h"          // Include the driver development APIs provided by the HDF.
528    #include "hdf_log.h"                  // Include the log APIs provided by the HDF.
529
530    #define HDF_LOG_TAG "sample_driver"   // Define the tag contained in logs. If no tag is defined, the default HDF_TAG is used.
531
532    // Bind the service capability interface provided by the driver to the HDF.
533    int32_t HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
534    {
535        HDF_LOGD("Sample driver bind success");
536        return HDF_SUCCESS;
537    }
538
539    // Initialize the driver service.
540    int32_t HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
541    {
542        HDF_LOGD("Sample driver Init success");
543        return HDF_SUCCESS;
544    }
545
546    // Release the driver resources.
547    void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
548    {
549        HDF_LOGD("Sample driver release success");
550        return;
551    }
552    ```
553
554-   Register the driver entry with the HDF.
555
556    ```c
557    // Define a driver entry object. It must be a global variable of the HdfDriverEntry type (defined in hdf_device_desc.h).
558    struct HdfDriverEntry g_sampleDriverEntry = {
559        .moduleVersion = 1,
560        .moduleName = "sample_driver",
561        .Bind = HdfSampleDriverBind,
562        .Init = HdfSampleDriverInit,
563        .Release = HdfSampleDriverRelease,
564    };
565
566    // Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls Bind() and then Init(). If Init() fails to be called, the HDF will call Release() to release driver resources and exit the driver model.
567    HDF_INIT(g_sampleDriverEntry);
568    ```
569
570#### Writing the Driver Compilation Script
571
572- ##### LiteOS
573
574  If a LiteOS is used, you need to modify **makefile** and **BUILD.gn** files.
575
576  - **Makefile**:
577
578    Use the **makefile** template provided by the HDF to compile the driver code.
579
580    ```makefile
581    include $(LITEOSTOPDIR)/../../drivers/hdf_core/adapter/khdf/liteos/lite.mk # (Mandatory) Import the HDF predefined content.
582    MODULE_NAME :=        # File to be generated.
583    LOCAL_INCLUDE: =      # Directory of the driver header files.
584    LOCAL_SRCS : =         # Source code files of the driver.
585    LOCAL_CFLAGS : =      # Custom compiler options.
586    include $(HDF_DRIVER) # Import the Makefile template to complete the build.
587    ```
588
589    Add the path of the generated file to **hdf_lite.mk** in the **drivers/hdf_core/adapter/khdf/liteos** directory to link the file to the kernel image.
590
591    Example:
592
593    ```makefile
594    LITEOS_BASELIB += -lxxx   # Static library generated by the link.
595    LIB_SUBDIRS    +=         # Directory in which makefile is located.
596    ```
597
598  -   **BUILD.gn**:
599
600      Add the module **BUILD.gn**.
601
602      Example:
603
604      ```
605      import("//build/lite/config/component/lite_component.gni")
606      import("//drivers/hdf_core/adapter/khdf/liteos/hdf.gni")
607      module_switch = defined(LOSCFG_DRIVERS_HDF_xxx)
608      module_name = "xxx"
609      hdf_driver(module_name) {
610          sources = [
611              "xxx/xxx/xxx.c",           # Source code to compile.
612          ]
613          public_configs = [ ":public" ] # Head file configuration of the dependencies.
614      }
615      config("public") {                 # Define the head file configuration of the dependencies.
616          include_dirs = [
617              "xxx/xxx/xxx",             # Directory of dependency header files.
618          ]
619  }
620      ```
621
622      Add the **BUILD.gn** directory to **/drivers/hdf_core/adapter/khdf/liteos/BUILD.gn**.
623
624      ```
625      group("liteos") {
626          public_deps = [ ":$module_name" ]
627          deps = [
628              "xxx/xxx", # Directory of the new module BUILD.gn, /drivers/hdf_core/adapter/khdf/liteos
629          ]
630      }
631      ```
632
633-   ##### Linux
634
635    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/hdf_core/adapter/khdf/linux/Kconfig**.
636
637    ```
638    source "drivers/hdf/khdf/xxx/Kconfig" # Kernel directory to which the HDF module is soft linked.
639    ```
640
641    Add the driver directory to **drivers/hdf_core/adapter/khdf/linux/Makefile**.
642
643    ```makefile
644    obj-$(CONFIG_DRIVERS_HDF)  += xxx/
645    ```
646
647    Add a **Makefile** to the driver directory **xxx** and add code compiling rules of the driver to the **Makefile** file.
648
649    ```makefile
650    obj-y  += xxx.o
651    ```
652
653#### Configuring the Driver
654
655The HDF uses HCS as the configuration description source code. For details about the HCS, see [HDF Configuration Overview](#hdf-configuration-overview).
656
657The driver configuration consists of the driver device description defined by the HDF and the private driver configuration.
658
659- (Mandatory) Set driver device information.
660
661  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.
662
663  Example:
664
665  ```
666  root {
667      device_info {
668          match_attr = "hdf_manager";
669          template host {       // Host template. If a node (for example, sample_host) uses the default values in this template, the node fields can be omitted.
670              hostName = "";
671              priority = 100;
672              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.
673              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.
674              caps = [""]];     // Linux capabilities of the user-mode process. It is left empty by default. Set this parameter based on service requirements.
675              template device {
676                  template deviceNode {
677                      policy = 0;
678                      priority = 100;
679                      preload = 0;
680                      permission = 0664;
681                      moduleName = "";
682                      serviceName = "";
683                      deviceMatchAttr = "";
684                  }
685              }
686          }
687          sample_host :: host{
688              hostName = "host0";    // Host name. The host node is used as a container to hold a type of drivers.
689              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.
690              caps = ["DAC_OVERRIDE", "DAC_READ_SEARCH"];   // Linux capabilities of a user-mode process.
691              device_sample :: device {        // Sample device node.
692                  device0 :: deviceNode {      // DeviceNode of the sample driver.
693                      policy = 1;              // Policy for publishing the driver service. For details, see Driver Service Management.
694                      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.
695                      preload = 0;             // The value 0 means to load the driver by default during the startup of the system.
696                      permission = 0664;       // Permission for the DeviceNode created.
697                      moduleName = "sample_driver";      // Driver name. The value must be the same as that of moduleName in the HdfDriverEntry structure.
698                      serviceName = "sample_service";    // Name of the service published by the driver. The service name must be unique.
699                      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.
700                  }
701              }
702          }
703      }
704  }
705  ```
706
707  >   **NOTE**<br>
708  >
709  >   -   **uid**, **gid**, and **caps** are startup parameters for user-mode drivers only.
710  >   -   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.
711  >   -   If you need to set **uid** and **gid** to **system** or **root** due to service requirements, contact security experts for review.
712  >   -   The process UIDs are configured in **base/startup/init/services/etc/passwd**, and the process GIDs are configured in **base/startup/init/services/etc/group**. For details, see [Adding a System Service User Group]( https://gitee.com/openharmony/startup_init_lite/wikis).
713  >   -   The **caps** value is in the caps = ["xxx"] format. To configure **CAP_DAC_OVERRIDE**, set this parameter to **caps = ["DAC_OVERRIDE"]**. Do not set it to **caps = ["CAP_DAC_OVERRIDE"]**.
714  >   -   **preload** specifies the loading policy for the driver.
715
716-   (Optional) Set driver private information.
717
718    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 [Implementing a Driver](implementing-a-driver)).
719
720    Example:
721
722    ```
723    root {
724        SampleDriverConfig {
725            sample_version = 1;
726            sample_bus = "I2C_0";
727            match_attr = "sample_config"; // The value must be the same as that of deviceMatchAttr in device_info.hcs.
728        }
729}
730    ```
731
732    Add the configuration file to the **hdf.hcs** file.
733
734    Example:
735
736    ```
737    #include "device_info/device_info.hcs"
738    #include "sample/sample_config.hcs"
739    ```
740
741### Driver Messaging Mechanism Development
742
7431.  Set the **policy** field in the driver configuration information to **2** (SERVICE_POLICY_CAPACITY). For details about the policy, see [Driver Service Management](#driver-service-management).
744
745    ```
746    device_sample :: Device {
747        policy = 2;
748        ...
749    }
750    ```
751
7522.  Set permissions for the device node of the driver. By default, the **permission** field is set to **0666**. You can set it based on service requirements.
753
7543.  Implement the **Dispatch()** method of **IDeviceIoService**.
755
756    ```c
757    // Dispatch() is used to process messages sent from the user-mode application.
758    int32_t SampleDriverDispatch(struct HdfDeviceIoClient *device, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
759    {
760        HDF_LOGI("sample driver lite A dispatch");
761        return HDF_SUCCESS;
762    }
763    int32_t SampleDriverBind(struct HdfDeviceObject *device)
764    {
765        HDF_LOGI("test for lite os sample driver A Open!");
766        if (device == NULL) {
767            HDF_LOGE("test for lite os sample driver A Open failed!");
768            return HDF_FAILURE;
769        }
770        static struct ISampleDriverService sampleDriverA = {
771            .ioService.Dispatch = SampleDriverDispatch,
772            .ServiceA = SampleDriverServiceA,
773            .ServiceB = SampleDriverServiceB,
774        };
775        device->service = (struct IDeviceIoService *)(&sampleDriverA);
776        return HDF_SUCCESS;
777    }
778    ```
779
7804.  Define the cmd type in the message processing function.
781
782    ```c
783    #define SAMPLE_WRITE_READ 1 // Read and write operation 1
784    ```
785
7865.  Enable the user-mode application to obtain a service and send a message to the driver.
787
788    ```c
789    int SendMsg(const char *testMsg)
790    {
791        if (testMsg == NULL) {
792            HDF_LOGE("test msg is null");
793            return HDF_FAILURE;
794        }
795        struct HdfIoService *serv = HdfIoServiceBind("sample_driver");
796        if (serv == NULL) {
797            HDF_LOGE("fail to get service");
798            return HDF_FAILURE;
799        }
800        struct HdfSBuf *data = HdfSbufObtainDefaultSize();
801        if (data == NULL) {
802            HDF_LOGE("fail to obtain sbuf data");
803            return HDF_FAILURE;
804        }
805        struct HdfSBuf *reply = HdfSbufObtainDefaultSize();
806        if (reply == NULL) {
807            HDF_LOGE("fail to obtain sbuf reply");
808            ret = HDF_DEV_ERR_NO_MEMORY;
809            goto out;
810        }
811        if (!HdfSbufWriteString(data, testMsg)) {
812            HDF_LOGE("fail to write sbuf");
813            ret = HDF_FAILURE;
814            goto out;
815        }
816        int ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
817        if (ret != HDF_SUCCESS) {
818            HDF_LOGE("fail to send service call");
819            goto out;
820        }
821    out:
822        HdfSbufRecycle(data);
823        HdfSbbufRecycle(reply);
824        HdfIoServiceRecycle(serv);
825        return ret;
826    }
827    ```
828
8296.  Enable the user-mode process to receive messages from the driver.
830
831    1.  Implement the method for the user-mode application to process the events reported by the driver.
832
833        ```c
834        static int OnDevEventReceived(void *priv,  uint32_t id, struct HdfSBuf *data)
835        {
836            OsalTimespec time;
837            OsalGetTime(&time);
838            HDF_LOGI("%{public}s received event at %{public}llu.%{public}llu", (char *)priv, time.sec, time.usec);
839
840            const char *string = HdfSbufReadString(data);
841            if (string == NULL) {
842                HDF_LOGE("fail to read string in event data");
843                return HDF_FAILURE;
844            }
845            HDF_LOGI("%{public}s: dev event received: %{public}d %{public}s",  (char *)priv, id, string);
846            return HDF_SUCCESS;
847        }
848        ```
849
850    2.  Register the method for the user-mode application to receive messages from the driver.
851
852        ```c
853        int RegisterListen()
854        {
855            struct HdfIoService *serv = HdfIoServiceBind("sample_driver");
856            if (serv == NULL) {
857                HDF_LOGE("fail to get service");
858                return HDF_FAILURE;
859            }
860            static struct HdfDevEventlistener listener = {
861                .callBack = OnDevEventReceived,
862                .priv ="Service0"
863            };
864            if (HdfDeviceRegisterEventListener(serv, &listener) != 0) {
865                HDF_LOGE("fail to register event listener");
866                return HDF_FAILURE;
867            }
868            ......
869            HdfDeviceUnregisterEventListener(serv, &listener);
870            HdfIoServiceRecycle(serv);
871            return HDF_SUCCESS;
872        }
873        ```
874
875    3.  Enable the driver to report events.
876
877        ```c
878        int32_t SampleDriverDispatch(HdfDeviceIoClient *client, int cmdCode, struct HdfSBuf *data, struct HdfSBuf *reply)
879        {
880            ... // process api call here
881            return HdfDeviceSendEvent(client->device, cmdCode, data);
882        }
883        ```
884
885### Driver Service Management Development
886
887The development procedure is as follows:
888
889#### Defining the Services to be Published by the Driver
890
891```c
892// Define the driver service struct.
893struct ISampleDriverService {
894    struct IDeviceIoService ioService;       // The first member must be of the IDeviceIoService type.
895    int32_t (*ServiceA)(void);               // API of the first driver service.
896    int32_t (*ServiceB)(uint32_t inputCode); // API of the second driver service. You can add more as required.
897};
898
899// Implement the driver service APIs.
900int32_t SampleDriverServiceA(void)
901{
902    // You need to implement the service logic.
903    return HDF_SUCCESS;
904}
905
906int32_t SampleDriverServiceB(uint32_t inputCode)
907{
908    // You need to implement the service logic.
909    return HDF_SUCCESS;
910}
911```
912
913#### Binding Driver Services
914
915Implement the **Bind** pointer function, for example, **SampleDriverBind**, in **HdfDriverEntry** to bind the driver service to the HDF.
916
917```c
918int32_t SampleDriverBind(struct HdfDeviceObject *deviceObject)
919{
920    // deviceObject is a pointer to the device object created by the HDF for each driver. The device object holds private device data and service APIs.
921    if (deviceObject == NULL) {
922        HDF_LOGE("Sample device object is null!");
923        return HDF_FAILURE;
924    }
925    static struct ISampleDriverService sampleDriverA = {
926        .ServiceA = SampleDriverServiceA,
927        .ServiceB = SampleDriverServiceB,
928    };
929    deviceObject->service = &sampleDriverA.ioService;
930    return HDF_SUCCESS;
931}
932```
933
934#### Obtaining Driver Services
935
936The driver service can be obtained by using either of the following methods:
937
938##### Using the API provided by the HDF
939
940If the service requester clearly knows when the driver is loaded, it can obtain the driver service by using the API provided by the HDF. The following is an example:
941
942```c
943const struct ISampleDriverService *sampleService =
944        (const struct ISampleDriverService *)DevSvcManagerClntGetService("sample_driver");
945if (sampleService == NULL) {
946    return HDF_FAILURE;
947}
948sampleService->ServiceA();
949sampleService->ServiceB(5);
950```
951
952##### Using the subscription mechanism
953
954If the service requester is unaware of when the driver (in the same host) is loaded, it can use the subscription mechanism provided by the HDF to subscribe to the service. After the driver is loaded, the HDF publishes the driver service to the subscriber. The implementation is as follows:
955
956```c
957// Callback invoked to return the driver service after the subscribed driver is loaded.
958// object is the pointer to the private data of the subscriber, and service is the pointer to the subscribed service object.
959int32_t TestDriverSubCallBack(struct HdfDeviceObject *deviceObject, const struct HdfObject *service)
960{
961    const struct ISampleDriverService *sampleService =
962        (const struct ISampleDriverService *)service;
963    if (sampleService == NULL) {
964        return HDF_FAILURE;
965    }
966    sampleService->ServiceA();
967    sampleService->ServiceB(5);
968}
969// Implement the subscription process.
970int32_t TestDriverInit(struct HdfDeviceObject *deviceObject)
971{
972    if (deviceObject == NULL) {
973        HDF_LOGE("Test driver init failed, deviceObject is null!");
974        return HDF_FAILURE;
975    }
976    struct SubscriberCallback callBack;
977    callBack.deviceObject = deviceObject;
978    callBack.OnServiceConnected = TestDriverSubCallBack;
979    int32_t ret = HdfDeviceSubscribeService(deviceObject, "sample_driver", callBack);
980    if (ret != HDF_SUCCESS) {
981        HDF_LOGE("Test driver subscribe sample driver failed!");
982    }
983    return ret;
984}
985```
986
987## HDF Development Example
988
989The following is a HDF-based driver development example.
990
991### Adding the Driver Configuration
992
993Add the driver configuration to the HDF configuration file, for example, **vendor/hisilicon/xxx/hdf_config/device_info**.
994
995```
996root {
997    device_info {
998        match_attr = "hdf_manager";
999        template host {
1000            hostName = "";
1001            priority = 100;
1002            template device {
1003                template deviceNode {
1004                    policy = 0;
1005                    priority = 100;
1006                    preload = 0;
1007                    permission = 0664;
1008                    moduleName = "";
1009                    serviceName = "";
1010                    deviceMatchAttr = "";
1011                }
1012            }
1013        }
1014        sample_host :: host {
1015            hostName = "sample_host";
1016            sample_device :: device {
1017                device0 :: deviceNode {
1018                    policy = 2;
1019                    priority = 100;
1020                    preload = 1;
1021                    permission = 0664;
1022                    moduleName = "sample_driver";
1023                    serviceName = "sample_service";
1024                }
1025            }
1026        }
1027    }
1028}
1029```
1030
1031### Writing the Driver Code
1032
1033The sample driver code compiled based on the HDF framework is as follows:
1034
1035```c
1036#include <fcntl.h>
1037#include <sys/stat.h>
1038#include <sys/ioctl.h>
1039#include "hdf_log.h"
1040#include "hdf_base.h"
1041#include "hdf_device_desc.h"
1042
1043#define HDF_LOG_TAG sample_driver
1044
1045#define SAMPLE_WRITE_READ 123
1046
1047static int32_t HdfSampleDriverDispatch(
1048    struct HdfDeviceIoClient *client, int id, struct HdfSBuf *data, struct HdfSBuf *reply)
1049{
1050    HDF_LOGI("%{public}s: received cmd %{public}d", __func__, id);
1051    if (id == SAMPLE_WRITE_READ) {
1052        const char *readData = HdfSbufReadString(data);
1053        if (readData != NULL) {
1054            HDF_LOGE("%{public}s: read data is: %{public}s", __func__, readData);
1055        }
1056        if (!HdfSbufWriteInt32(reply, INT32_MAX)) {
1057            HDF_LOGE("%{public}s: reply int32 fail", __func__);
1058        }
1059        return HdfDeviceSendEvent(client->device, id, data);
1060    }
1061    return HDF_FAILURE;
1062}
1063
1064static void HdfSampleDriverRelease(struct HdfDeviceObject *deviceObject)
1065{
1066    // Release resources here
1067    return;
1068}
1069
1070static int HdfSampleDriverBind(struct HdfDeviceObject *deviceObject)
1071{
1072    if (deviceObject == NULL) {
1073        return HDF_FAILURE;
1074    }
1075    static struct IDeviceIoService testService = {
1076        .Dispatch = HdfSampleDriverDispatch,
1077    };
1078    deviceObject->service = &testService;
1079    return HDF_SUCCESS;
1080}
1081
1082static int HdfSampleDriverInit(struct HdfDeviceObject *deviceObject)
1083{
1084    if (deviceObject == NULL) {
1085        HDF_LOGE("%{public}s::ptr is null!", __func__);
1086        return HDF_FAILURE;
1087    }
1088    HDF_LOGI("Sample driver Init success");
1089    return HDF_SUCCESS;
1090}
1091
1092static struct HdfDriverEntry g_sampleDriverEntry = {
1093    .moduleVersion = 1,
1094    .moduleName = "sample_driver",
1095    .Bind = HdfSampleDriverBind,
1096    .Init = HdfSampleDriverInit,
1097    .Release = HdfSampleDriverRelease,
1098};
1099
1100HDF_INIT(g_sampleDriverEntry);
1101```
1102
1103### Implementing Interaction Between the Application and the Driver
1104
1105Write the code for interaction between the user-mode application and the driver. Place the code in the **drivers/hdf_core/adapter/uhdf** directory for compilation. For details about **BUILD.gn**, see **drivers/hdf_core/framework/sample/platform/uart/dev/BUILD.gn**.
1106
1107```c
1108#include <fcntl.h>
1109#include <sys/stat.h>
1110#include <sys/ioctl.h>
1111#include <unistd.h>
1112#include "hdf_log.h"
1113#include "hdf_sbuf.h"
1114#include "hdf_io_service_if.h"
1115
1116#define HDF_LOG_TAG sample_test
1117#define SAMPLE_SERVICE_NAME "sample_service"
1118
1119#define SAMPLE_WRITE_READ 123
1120
1121int g_replyFlag = 0;
1122
1123static int OnDevEventReceived(void *priv,  uint32_t id, struct HdfSBuf *data)
1124{
1125    const char *string = HdfSbufReadString(data);
1126    if (string == NULL) {
1127        HDF_LOGE("fail to read string in event data");
1128        g_replyFlag = 1;
1129        return HDF_FAILURE;
1130    }
1131    HDF_LOGI("%{public}s: dev event received: %{public}u %{public}s",  (char *)priv, id, string);
1132    g_replyFlag = 1;
1133    return HDF_SUCCESS;
1134}
1135
1136static int SendEvent(struct HdfIoService *serv, char *eventData)
1137{
1138    int ret = 0;
1139    struct HdfSBuf *data = HdfSbufObtainDefaultSize();
1140    if (data == NULL) {
1141        HDF_LOGE("fail to obtain sbuf data");
1142        return 1;
1143    }
1144
1145    struct HdfSBuf *reply = HdfSbufObtainDefaultSize();
1146    if (reply == NULL) {
1147        HDF_LOGE("fail to obtain sbuf reply");
1148        ret = HDF_DEV_ERR_NO_MEMORY;
1149        goto out;
1150    }
1151
1152    if (!HdfSbufWriteString(data, eventData)) {
1153        HDF_LOGE("fail to write sbuf");
1154        ret = HDF_FAILURE;
1155        goto out;
1156    }
1157
1158    ret = serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply);
1159    if (ret != HDF_SUCCESS) {
1160        HDF_LOGE("fail to send service call");
1161        goto out;
1162    }
1163
1164    int replyData = 0;
1165    if (!HdfSbufReadInt32(reply, &replyData)) {
1166        HDF_LOGE("fail to get service call reply");
1167        ret = HDF_ERR_INVALID_OBJECT;
1168        goto out;
1169    }
1170    HDF_LOGI("Get reply is: %{public}d", replyData);
1171out:
1172    HdfSbufRecycle(data);
1173    HdfSbufRecycle(reply);
1174    return ret;
1175}
1176
1177int main()
1178{
1179    char *sendData = "default event info";
1180    struct HdfIoService *serv = HdfIoServiceBind(SAMPLE_SERVICE_NAME);
1181    if (serv == NULL) {
1182        HDF_LOGE("fail to get service %s", SAMPLE_SERVICE_NAME);
1183        return HDF_FAILURE;
1184    }
1185
1186    static struct HdfDevEventlistener listener = {
1187        .callBack = OnDevEventReceived,
1188        .priv ="Service0"
1189    };
1190
1191    if (HdfDeviceRegisterEventListener(serv, &listener) != HDF_SUCCESS) {
1192        HDF_LOGE("fail to register event listener");
1193        return HDF_FAILURE;
1194    }
1195    if (SendEvent(serv, sendData)) {
1196        HDF_LOGE("fail to send event");
1197        return HDF_FAILURE;
1198    }
1199
1200    while (g_replyFlag == 0) {
1201        sleep(1);
1202    }
1203
1204    if (HdfDeviceUnregisterEventListener(serv, &listener)) {
1205        HDF_LOGE("fail to  unregister listener");
1206        return HDF_FAILURE;
1207    }
1208
1209    HdfIoServiceRecycle(serv);
1210    return HDF_SUCCESS;
1211}
1212```
1213
1214>   **NOTE**
1215>
1216>   The user-mode application uses the message sending API of the HDF, and the compilation of the user-mode application depends on the dynamic libraries **hdf_core** and **osal** provided by the HDF. Therefore, you need to add the following dependencies to the .gn file:
1217>
1218>   deps = [
1219>
1220>   ​        "//drivers/hdf_core/adapter/uhdf/manager:hdf_core",
1221>
1222>   ​        "//drivers/hdf_core/adapter/uhdf/posix:hdf_posix_osal",
1223>
1224>   ]
1225