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