• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# USB
2
3## Introduction
4
5### Function Overview
6
7The universal serial bus (USB) consists of a USB host and multiple USB devices. The USB host implement data transfer and port management in the USB bus, and the USB device can connect to various peripherals. Therefore, USB driver development is divided into USB host driver development and USB device driver development.
8
9The USB module of OpenHarmony supports the development of USB services, provides USB-related functions, provides interfaces to read and write USB device data of third-party function drivers in user mode, creates and deletes USB devices, obtains notification events, enables or disables event listening, implements non-isochronous and isochronous data transfer over USB pipes, and sets custom USB attributes.
10
11The USB DriverDevelop Kit (DDK) is the USB driver development kit provided by the Framework of the OpenHarmony Driver Foundation (HDF). This kit consists of the USB Host DDK and USB Device DDK. It supports the development of USB device drivers based on the user mode and provides rich USB driver development capabilities that help you to efficiently develop USB drivers.
12
13### Basic Concepts
14
15- Pipe
16
17  A pipe is a model for data transfer between the USB host and a device endpoint. Once a USB device is powered on, a pipe, that is, the default control pipe, is established. The USB host obtains the description, configuration, and status of the USB device through the pipe, and configures the device as requested. Pipes and endpoints are associated and share the same attributes, such as the supported transfer type, maximum packet length, and data transfer direction.
18
19- Endpoint
20
21  The minimum unit that transfers and receives data in a USB device. It supports unidirectional or bidirectional data transfer. One USB device may include several endpoints, and different endpoints are distinguished by endpoint numbers and directions. Different endpoints can support different data transfer types, access intervals, and maximum packet sizes. All endpoints except endpoint 0 support data transfer in only one direction. Endpoint 0 is a special endpoint that supports bidirectional control transfer.
22
23- Interface
24
25  The application implements device control and data transfer through exchanging data with the device. Because a pipe supports only one data transfer type, multiple pipes are usually required to complete data exchange in this process. A collection of pipes that are used together to control a device is called an interface.
26
27- Descriptor
28
29  A data structure used to describe device attributes. The first byte indicates the descriptor size (number of bytes), and the second byte indicates the descriptor type.
30
31### Working Principles
32
33#### USB Host DDK
34
35The USB Host DDK provides the capability of developing USB drivers on the host. Based on functions, APIs of the USB Host DDK are classified into three types: DDK initialization, **interface** object operation, and **request** object operation.
36
37  **Figure 1** USB host driver model
38
39  ![](figures/USB_host_driver_model.png "USB host driver model")
40
41- The USB Interface Pool module manages USB interfaces. It applies for and reclaims USB interface objects, which are used to record device port information and resources. The module manages USB interfaces by USB port. In addition, it provides USB DDK APIs to read and write USB data.
42
43- The USB Protocol Layer module provides USB protocol encapsulation, translates and parses device I/O and control commands based on the USB protocol, manages device descriptors, and matches descriptors based on the enum information reported by the USB device. This module creates the corresponding USB interface objects and adds them to the USB Interface Pool module for management.
44
45- The Device I/O Manager module manages USB I/O requests and provides synchronous and asynchronous I/O management mechanisms. For the asynchronous I/O management mechanism, the module records the asynchronous I/O requests and processes the requests to be sent through the APIs provided by the Raw API Library module. After receiving the processing result from the USB controller, the I/O request receiving thread parses the processing result and reports it to the upper-layer caller.
46
47- The Raw API Library module abstracts underlying OS capabilities, defines unified OS capability APIs, and provides the USB RAW APIs needed to implement more complex driver functions.
48
49- The OS Adapter module encapsulates operations related to platforms (Linux and LiteOS). It compiles encapsulation APIs depending on the configuration of the specific platform. On the Linux platform, all USB FS access operations are encapsulated in this module. On the LiteOS platform, all device access operations based on the FreeBSD USB framework are encapsulated in this module.
50
51- The PNP Notify module dynamically monitors USB status changes. This module updates the device information when a device is added or removed. Meanwhile, it reports all USB device information to the PNP Notify Manager module on the UHDF side through the KHDF to load or uninstall third-party function drivers.
52
53#### USB Device DDK
54
55The USB Device DDK provides the capability of developing USB drivers on the device side. For example, with the dynamic registration and deregistration capabilities, you can dynamically add and combine USB ports based on the actual requirement; with the dynamic instantiation capability, you can create device instances and transmission channels based on dynamically delivered device, configuration, interface, and endpoint descriptors. In addition, the following functions are supported: sending and receiving data in user mode, isolating multiple logical devices from each other on a physical device, and accessing different logical devices from different application processes at the same time.
56
57  **Figure 2** USB device driver model
58
59  ![](figures/USB_device_driver_model.png "USB device driver model")
60
61- The SDK IF module divides USB devices logically by device, interface, and pipe, and encapsulates functions including configuration management, device management, and I/O management. This module also provides APIs for device driver development, such as creating and obtaining devices, receiving events, and sending and receiving data.
62
63- The Configuration Manager module parses the .hcs file for the USB descriptor information, which will be used for creating USB devices. In addition, the module provides operations such as reading, creating, deleting, and modifying custom USB attributes.
64
65- The Device Manager module parses USB descriptor information and creates USB devices accordingly. It also provides functions such as adding or deleting USB devices, obtaining USB device status, and obtaining USB device interface information.
66
67- The IO Manager module reads and writes data, including common events and data read and write events. It supports data read and write in synchronous and asynchronous modes.
68
69- The Adapter IF module encapsulates device node operations of composite device configuration drivers and common function drivers to provide unified device management APIs for the upper layer.
70
71- The Adapter module is provided by the composite device configuration driver and common function driver.
72
73## Development Guidelines
74
75The USB driver development in kernel mode is complex. Therefore, you need to have a deep understanding of the USB protocol. The USB DDK is introduced to help you to develop USB drivers in user mode more conveniently.
76
77### When to Use
78
79The USB Host DDK comes with two modes, namely, common mode and expert mode. In common mode, you can directly read and write USB data by using USB DDK APIs without knowing details about data transfer at the bottom layer. In expert mode, you can use USB RAW APIs to directly access the USB channel interfaces provided by the OS platform to implement more complex functions. The USB Device DDk provides functions such as USB device management, interface definition, and USB data request.
80
81### Available APIs
82
83The following table lists the APIs related to USB host driver development (common mode). For details about the API definitions, see the [source code](https://gitee.com/openharmony/drivers_peripheral/blob/master/usb/interfaces/ddk/host/usb_ddk_interface.h).
84
85  **Table 1** APIs for USB host driver development (common mode)
86
87| API| Description|
88| -------- | -------- |
89| int32_t UsbInitHostSdk(struct UsbSession \*\*session); | Initializes the USB host driver DDK.|
90| const&nbsp;struct&nbsp;UsbInterface&nbsp;\*UsbClaimInterface(const<br>struct&nbsp;UsbSession&nbsp;\*session,&nbsp;uint8_t&nbsp;busNum,&nbsp;uint8_t<br>usbAddr,&nbsp;uint8_t&nbsp;interfaceIndex); | Obtains a USB interface.|
91| UsbInterfaceHandle&nbsp;\*UsbOpenInterface(const&nbsp;struct<br>UsbInterface&nbsp;\*interfaceObj); | Opens a USB interface.|
92| int32_t&nbsp;UsbGetPipeInfo(const&nbsp;UsbInterfaceHandle<br>\*interfaceHandle,&nbsp;uint8_t&nbsp;settingIndex,&nbsp;uint8_t&nbsp;pipeId,<br>struct&nbsp;UsbPipeInfo&nbsp;\*pipeInfo); | Obtains USB pipe information.|
93| struct&nbsp;UsbRequest&nbsp;\*UsbAllocRequest(const<br>UsbInterfaceHandle&nbsp;\*interfaceHandle,&nbsp;int32_t&nbsp;isoPackets<br>,&nbsp;int32_t&nbsp;length); | Allocates a request object.|
94| int32_t&nbsp;UsbFillRequest(const&nbsp;struct&nbsp;UsbRequest<br>\*request,&nbsp;const&nbsp;UsbInterfaceHandle&nbsp;\*interfaceHandle,<br>const&nbsp;struct&nbsp;UsbRequestParams&nbsp;\*params); | Fills in a request.|
95| int32_t&nbsp;UsbSubmitRequestSync(const&nbsp;struct&nbsp;UsbRequest<br>\*request); | Sends a synchronous request.|
96
97The following table lists the APIs related to USB host driver development (expert mode). For details about the API definitions, see the [source code](https://gitee.com/openharmony/drivers_peripheral/blob/master/usb/interfaces/ddk/host/usb_raw_api.h).
98
99  **Table 2** APIs for USB host driver development (expert mode)
100
101| API| Description|
102| -------- | -------- |
103| int32_t&nbsp;UsbRawInit(struct&nbsp;UsbSession&nbsp;\*\*session); | Initializes the USB raw APIs.|
104| UsbRawHandle&nbsp;\*UsbRawOpenDevice(const&nbsp;struct<br>UsbSession&nbsp;\*session,&nbsp;uint8_t&nbsp;busNum,&nbsp;uint8_t<br>usbAddr); | Opens a USB device.|
105| int32_t&nbsp;UsbRawSendControlRequest(const&nbsp;struct<br>UsbRawRequest&nbsp;\*request,&nbsp;const&nbsp;UsbRawHandle<br>\*devHandle,&nbsp;const&nbsp;struct&nbsp;UsbControlRequestData<br>\*requestData); | Performs a control transfer synchronously.|
106| int32_t&nbsp;UsbRawSendBulkRequest(const&nbsp;struct<br>UsbRawRequest&nbsp;\*request,&nbsp;const&nbsp;UsbRawHandle<br>\*devHandle,&nbsp;const&nbsp;struct&nbsp;UsbRequestData<br>\*requestData); | Performs a bulk transfer synchronously.|
107| int32_t&nbsp;UsbRawSendInterruptRequest(const&nbsp;struct<br>UsbRawRequest&nbsp;\*request,&nbsp;const&nbsp;UsbRawHandle<br>\*devHandle,&nbsp;const&nbsp;struct&nbsp;UsbRequestData<br>\*requestData); | Performs an interrupt transfer synchronously.|
108| int32_t&nbsp;UsbRawGetConfigDescriptor(const&nbsp;UsbRawDevice<br>\*rawDev,&nbsp;uint8_t&nbsp;configIndex,&nbsp;struct<br>UsbRawConfigDescriptor&nbsp;\*\*config); | Obtains the configuration descriptor of a device.|
109| int32_t&nbsp;UsbRawFillInterruptRequest(const&nbsp;struct&nbsp;UsbRawRequest<br>\*request,&nbsp;const&nbsp;UsbRawHandle&nbsp;\*devHandle,&nbsp;const&nbsp;struct<br>UsbRawFillRequestData&nbsp;\*fillData); | Fills in an interrupt transfer request.|
110| int32_t&nbsp;UsbRawFillIsoRequest(const&nbsp;struct&nbsp;UsbRawRequest<br>\*request,&nbsp;const&nbsp;UsbRawHandle&nbsp;\*devHandle,&nbsp;const&nbsp;struct<br>UsbRawFillRequestData&nbsp;\*fillData); | Fills in an isochronous transfer request.|
111| int32_t&nbsp;UsbRawSubmitRequest(const&nbsp;struct&nbsp;UsbRawRequest<br>\*request); | Submits a transfer request.|
112| int32_t&nbsp;UsbRawCancelRequest(const&nbsp;struct&nbsp;UsbRawRequest<br>\*request); | Cancels a transfer request.|
113| int32_t&nbsp;UsbRawHandleRequests(const&nbsp;UsbRawHandle<br>\*devHandle); | Handles a transfer request event.|
114
115The following table lists the APIs for USB device management on the device side. For details about the API definitions, see the [source code](https://gitee.com/openharmony/drivers_peripheral/blob/master/usb/interfaces/ddk/device/usbfn_device.h).
116
117  **Table 3** APIs for USB device management on the device side
118
119| API| Description|
120| -------- | -------- |
121| const&nbsp;struct&nbsp;UsbFnDevice&nbsp;\*UsbFnCreateDevice(const<br>char&nbsp;\*udcName,&nbsp;const&nbsp;struct&nbsp;UsbFnDescriptorData<br>\*descriptor); | Creates a USB device.|
122| int32_t&nbsp;UsbFnRemoveDevice(struct&nbsp;UsbFnDevice<br>\*fnDevice); | Deletes a USB device.|
123| const&nbsp;struct&nbsp;UsbFnDevice&nbsp;\*UsbFnGetDevice(const&nbsp;char<br>\*udcName); | Obtains a USB device.|
124
125The following table lists the APIs for USB interface definition on the device side. For details about the API definitions, see the [source code](https://gitee.com/openharmony/drivers_peripheral/blob/master/usb/interfaces/ddk/device/usbfn_interface.h).
126
127  **Table 4** APIs for USB interface definition on the device side
128
129| API| Description|
130| -------- | -------- |
131| int32_t&nbsp;UsbFnStartRecvInterfaceEvent(struct<br>UsbFnInterface&nbsp;\*interface,&nbsp;uint32_t&nbsp;eventMask,<br>UsbFnEventCallback&nbsp;callback,&nbsp;void&nbsp;\*context); | Starts receiving events.|
132| int32_t&nbsp;UsbFnStopRecvInterfaceEvent(struct<br>UsbFnInterface&nbsp;\*interface); | Stops receiving events.|
133| UsbFnInterfaceHandle&nbsp;UsbFnOpenInterface(struct&nbsp;UsbFnInterface&nbsp;\*interface); | Opens an interface.|
134| int32_t&nbsp;UsbFnCloseInterface(UsbFnInterfaceHandle&nbsp;handle); | Closes an interface.|
135| int32_t&nbsp;UsbFnGetInterfacePipeInfo(struct&nbsp;UsbFnInterface<br>\*interface,&nbsp;uint8_t&nbsp;pipeId,&nbsp;struct&nbsp;UsbFnPipeInfo&nbsp;\*info); | Obtains pipe information.|
136| int32_t&nbsp;UsbFnSetInterfaceProp(const&nbsp;struct&nbsp;UsbFnInterface<br>\*interface,&nbsp;const&nbsp;char&nbsp;\*name,&nbsp;const&nbsp;char&nbsp;\*value); | Sets custom properties.|
137
138The following table lists the APIs for USB data request on the device side. For details about the API definitions, see the [source code](https://gitee.com/openharmony/drivers_peripheral/blob/master/usb/interfaces/ddk/device/usbfn_request.h).
139
140  **Table 5** APIs for USB data request on the device side
141
142| API| Description|
143| -------- | -------- |
144| struct&nbsp;UsbFnRequest<br>\*UsbFnAllocCtrlRequest(UsbFnInterfaceHandle&nbsp;handle,<br>uint32_t&nbsp;len); | Allocates a control transfer request.|
145| struct&nbsp;UsbFnRequest&nbsp;\*UsbFnAllocRequest(UsbFnInterfaceHandle&nbsp;handle,<br>uint8_t&nbsp;pipe,&nbsp;uint32_t&nbsp;len); | Allocates a data request.|
146| int32_t&nbsp;UsbFnFreeRequest(struct&nbsp;UsbFnRequest&nbsp;\*req); | Releases a request.|
147| int32_t&nbsp;UsbFnSubmitRequestAsync(struct&nbsp;UsbFnRequest<br>\*req); | Sends an asynchronous request.|
148| int32_t&nbsp;UsbFnSubmitRequestSync(struct&nbsp;UsbFnRequest<br>\*req,&nbsp;uint32_t&nbsp;timeout); | Sends a synchronous request.|
149| int32_t&nbsp;UsbFnCancelRequest(struct&nbsp;UsbFnRequest&nbsp;\*req); | Cancels a request.|
150
151
152### How to Develop
153
154USB drivers are developed based on the Hardware Driver Foundation (HDF), platform, and Operating System Abstraction Layer (OSAL) APIs. A unified driver model is provided for USB devices, irrespective of the operating system and chip architecture. This section uses the serial port as an example to describe how to develop USB host and USB device drivers.
155
156#### Developing Driver Using Host DDK APIs
157
1581. Configure USB host driver information in the .hcs file of private device data.
159
160    ```cpp
161    root {
162        module = "usb_pnp_device";
163        usb_pnp_config {
164            match_attr = "usb_pnp_match";
165            usb_pnp_device_id = "UsbPnpDeviceId";
166            UsbPnpDeviceId {
167                idTableList = [
168                    "host_acm_table"
169                ];
170                host_acm_table {
171                    // Driver module name, which must be the same as the value of moduleName in the driver entry structure.
172                    moduleName = "usbhost_acm";
173                    // Service name of the driver, which must be unique.
174                    serviceName = "usbhost_acm_pnp_service";
175                    // Keyword for matching private driver data.
176                    deviceMatchAttr = "usbhost_acm_pnp_matchAttr";
177                    // Data length starting from this field, in bytes.
178                    length = 21;
179                    // USB driver matching rule: vendorId+productId+interfaceSubClass+interfaceProtocol+interfaceNumber.
180                    matchFlag = 0x0303;
181                    // Vendor ID.
182                    vendorId = 0x12D1;
183                    // Product ID.
184                    productId = 0x5000;
185                    // The least significant 16 bits of the device sequence number.
186                    bcdDeviceLow = 0x0000;
187                    // The most significant 16 bits of the device sequence number.
188                    bcdDeviceHigh = 0x0000;
189                    // Device class code allocated by the USB.
190                    deviceClass = 0;
191                    // Child class code allocated by the USB.
192                    deviceSubClass = 0;
193                    // Device protocol code allocated by the USB.
194                    deviceProtocol = 0;
195                    // Interface type. You can enter multiple types as needed.
196                    interfaceClass = [0];
197                    // Interface subtype. You can enter multiple subtypes as needed.
198                    interfaceSubClass = [2, 0];
199                    // Protocol that the interface complies with. You can enter multiple protocols as needed.
200                    interfaceProtocol = [1, 2];
201                    // Interface number. You can enter multiple interface numbers as needed.
202                    interfaceNumber = [2, 3];
203                }
204            }
205        }
206    }
207    ```
208
2092. Initialize the USB host driver DDK.
210
211    ```cpp
212    int32_t UsbInitHostSdk(struct UsbSession **session);
213    ```
214
2153. Obtain the **UsbInterface** object after initialization.
216
217    ```cpp
218    const struct UsbInterface *UsbClaimInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex);
219    ```
220
2214. Open the **UsbInterface** object to obtain the **UsbInterfaceHandle** object.
222
223    ```cpp
224    UsbInterfaceHandle *UsbOpenInterface(const struct UsbInterface *interfaceObj);
225    ```
226
2275. Obtain pipe information of the specified **pipeIndex** based on the **UsbInterfaceHandle** object.
228
229    ```cpp
230    int32_t UsbGetPipeInfo(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, uint8_t pipeId, struct UsbPipeInfo *pipeInfo);
231    ```
232
2336. Pre-allocate an I/O request for the **UsbInterfaceHandle** object.
234
235    ```cpp
236    struct UsbRequest *UsbAllocRequest(const UsbInterfaceHandle *interfaceHandle, int32_t isoPackets, int32_t length);
237    ```
238
2397. Fill in the I/O request based on the input parameters.
240
241    ```cpp
242    int32_t UsbFillRequest(const struct UsbRequest *request, const UsbInterfaceHandle *interfaceHandle, const struct UsbRequestParams *params);
243    ```
244
2458. Submit the I/O request in synchronous or asynchronous mode.
246
247    ```cpp
248    int32_t UsbSubmitRequestSync(const struct UsbRequest *request); // Send a synchronous I/O request.
249    int32_t UsbSubmitRequestAsync(const struct UsbRequest *request); // Send an asynchronous I/O request.
250    ```
251
252#### Developing Driver Using Host Raw APIs
253
2541. Configure USB host driver information in the .hcs file of private device data. For details, see step 1 in the previous section.
255
2562. Initialize the host raw data, open the USB device, obtain the descriptor, and then obtain interface and endpoint information based on the descriptor.
257
258    ```cpp
259    int32_t UsbRawInit(struct UsbSession **session);
260    ```
261
2623. Open the USB device.
263
264    ```cpp
265    UsbRawHandle *UsbRawOpenDevice(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr);
266    ```
267
2684. Obtain the device descriptor, and obtain the interface and endpoint information based on the descriptor.
269
270    ```cpp
271    int32_t UsbRawGetConfigDescriptor(const UsbRawDevice *rawDev, uint8_t configIndex, struct UsbRawConfigDescriptor **config);
272    ```
273
2745. Allocate a request and fill in the request based on the transfer type.
275
276    ```cpp
277    int32_t UsbRawFillBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData); // Populate the request for bulk transfer.
278    int32_t UsbRawFillControlSetup(const unsigned char *setup, const struct UsbControlRequestData *requestData);
279    int32_t UsbRawFillControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData); // Populate the request for control transfer.
280    int32_t UsbRawFillInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData); // Populate the request for interrupt transfer.
281    int32_t UsbRawFillIsoRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData); // Populate the request for isochronous transfer.
282    ```
283
2846. Submit the I/O request in synchronous or asynchronous mode.
285
286    ```cpp
287    int32_t UsbRawSendControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbControlRequestData *requestData); // Send a synchronous request for control transfer.
288    int32_t UsbRawSendBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData); // Send a synchronous request for bulk transfer.
289    int32_t UsbRawSendInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData); // Send a synchronous request for interrupt transfer.
290    int32_t UsbRawSubmitRequest(const struct UsbRawRequest *request); // Send an asynchronous I/O request.
291    ```
292
293#### Developing Driver Using Device DDK APIs
294
2951. Construct a descriptor in the device function code.
296
297    ```cpp
298    static struct UsbFnFunction g_acmFunction = { // Function descriptor
299        .enable         = true,
300        .funcName       = "f_generic.a",
301        .strings        = g_acmStrings,
302        .fsDescriptors  = g_acmFsFunction,
303        .hsDescriptors  = g_acmHsFunction,
304        .ssDescriptors  = g_acmSsFunction,
305        .sspDescriptors = NULL,
306    };
307    struct UsbFnFunction *g_functions[] = {
308    #ifdef CDC_ECM
309        &g_ecmFunction,
310    #endif
311    #ifdef CDC_ACM
312        &g_acmFunction,
313    #endif
314    NULL
315    };
316    static struct UsbFnConfiguration g_masterConfig = { // Configuration descriptor
317        .configurationValue = 1,
318        .iConfiguration     = USB_FUNC_CONFIG_IDX,
319        .attributes         = USB_CFG_BUS_POWERED,
320        .maxPower           = POWER,
321        .functions          = g_functions,
322    };
323    static struct UsbFnConfiguration *g_configs[] = {
324        &g_masterConfig,
325        NULL,
326    };
327    static struct UsbDeviceDescriptor g_cdcMasterDeviceDesc = { // Device descriptor
328        .bLength            = sizeof(g_cdcMasterDeviceDesc),
329        .bDescriptorType    = USB_DDK_DT_DEVICE,
330        .bcdUSB             = CpuToLe16(BCD_USB),
331        .bDeviceClass       = 0,
332        .bDeviceSubClass    = 0,
333        .bDeviceProtocol    = 0,
334        .bMaxPacketSize0    = USB_MAX_PACKET_SIZE,
335        .idVendor           = CpuToLe16(DEVICE_VENDOR_ID),
336        .idProduct          = CpuToLe16(DEVICE_PRODUCT_ID),
337        .bcdDevice          = CpuToLe16(DEVICE_VERSION),
338        .iManufacturer      = USB_FUNC_MANUFACTURER_IDX,
339        .iProduct           = USB_FUNC_PRODUCT_IDX,
340        .iSerialNumber      = USB_FUNC_SERIAL_IDX,
341        .bNumConfigurations = 1,
342    };
343    static struct UsbFnDeviceDesc g_masterFuncDevice = { // Descriptor entry
344        .deviceDesc    = &g_cdcMasterDeviceDesc,
345        .deviceStrings = g_devStrings,
346        .configs       = g_configs,
347    };
348    ```
349
3502. Create a USB device. Call **UsbFnDeviceCreate** and pass in the UDC controller and **UsbFnDescriptorData** structure to create a USB device.
351
352    ```cpp
353    if (useHcs == 0) { // Descriptor written in the code.
354        descData.type        = USBFN_DESC_DATA_TYPE_DESC;
355        descData.descriptor = &g_acmFuncDevice;
356    } else {             // Descriptor compiled by using the .hcs file.
357        descData.type         = USBFN_DESC_DATA_TYPE_PROP;
358        descData.property    = acm->device->property;
359    }
360    // Create a USB device.
361    fnDev = (struct UsbFnDevice *) UsbFnCreateDevice(acm->udcName, &descData);
362    ```
363
3643. Call **UsbFnGetInterface** to obtain a **UsbInterface** object, and call **UsbFnGetInterfacePipeInfo** to obtain the USB pipe information.
365
366    ```cpp
367    // Obtain an interface.
368    fnIface = (struct UsbFnInterface *)UsbFnGetInterface(fnDev, i);
369    // Obtain the pipe information.
370    UsbFnGetInterfacePipeInfo(fnIface, i, &pipeInfo);
371    // Obtain a handle.
372    handle = UsbFnOpenInterface(fnIface);
373    // Obtain a control (EP0) request.
374    req = UsbFnAllocCtrlRequest(acm->ctrlIface.handle,
375                sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));
376    // Obtain the request.
377    req = UsbFnAllocCtrlRequest(acm->ctrlIface.handle,
378                sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));
379    ```
380
3814. Call **UsbFnStartRecvInterfaceEvent** to receive events, and call **UsbFnEventCallback** to respond to the events.
382
383    ```cpp
384    // Start receiving events.
385    ret = UsbFnStartRecvInterfaceEvent(acm->ctrlIface.fn, 0xff, UsbAcmEventCallback, acm);
386    // Process the event in the callback.
387    static void UsbAcmEventCallback(struct UsbFnEvent *event)
388    {
389        struct UsbAcmDevice *acm = NULL;
390        if (event == NULL || event->context == NULL) {
391            HDF_LOGE("%s: event is null", __func__);
392            return;
393        }
394
395        acm = (struct UsbAcmDevice *)event->context;
396        switch (event->type) {
397            case USBFN_STATE_BIND:
398                HDF_LOGI("%s: receive bind event", __func__);
399                break;
400            case USBFN_STATE_UNBIND:
401                HDF_LOGI("%s: receive unbind event", __func__);
402                break;
403            case USBFN_STATE_ENABLE:
404                HDF_LOGI("%s: receive enable event", __func__);
405                AcmEnable(acm);
406                break;
407            case USBFN_STATE_DISABLE:
408                HDF_LOGI("%s: receive disable event", __func__);
409                AcmDisable(acm);
410                acm->enableEvtCnt = 0;
411                break;
412            case USBFN_STATE_SETUP:
413                HDF_LOGI("%s: receive setup event", __func__);
414                if (event->setup != NULL) {
415                    AcmSetup(acm, event->setup);
416                }
417                break;
418            case USBFN_STATE_SUSPEND:
419                HDF_LOGI("%s: receive suspend event", __func__);
420                AcmSuspend(acm);
421                break;
422            case USBFN_STATE_RESUME:
423                HDF_LOGI("%s: receive resume event", __func__);
424                AcmResume(acm);
425                break;
426            default:
427                break;
428        }
429    }
430    ```
431
4325. Send and receive data in synchronously or asynchronously.
433
434    ```cpp
435    notify = (struct UsbCdcNotification *)req->buf;
436    ...
437    if (memcpy_s((void *)(notify + 1), length, data, length) != EOK) {
438        return HDF_FAILURE;
439    }
440    ret = UsbFnSubmitRequestAsync(req); // Send data asynchronously.
441    ```
442
443### Development Example
444
445The following example helps you better understand the development of the USB serial port driver.
446
447#### Developing Driver Using Host DDK APIs
448
449```cpp
450#include "usb_serial.h"
451#include "hdf_base.h"
452#include "hdf_log.h"
453#include "osal_mem.h"
454#include "osal_time.h"
455#include "securec.h"
456#include "usb_ddk_interface.h"
457#include "hdf_usb_pnp_manage.h"
458
459#define HDF_LOG_TAG USB_HOST_ACM
460#define STR_LEN     512
461
462static struct UsbRequest *g_syncRequest = NULL; // Define a USB request.
463static struct UsbRequest *g_ctrlCmdRequest = NULL;
464static bool g_acmReleaseFlag = false;
465static uint8_t *g_acmReadBuffer = NULL;
466...
467static int32_t SerialCtrlMsg(struct AcmDevice *acm, uint8_t request,
468    uint16_t value, void *buf, uint16_t len)
469{
470    int32_t ret;
471    uint16_t index = acm->intPipe->interfaceId;
472    struct UsbControlParams controlParams;
473    struct UsbRequestParams params; // Define a UsbRequestParams object.
474    if (acm == NULL || buf == NULL) {
475        return HDF_ERR_IO;
476    }
477    if (acm->ctrlReq == NULL) {
478        // Pre-allocate the IO Request object to be sent to UsbInterfaceHandle.
479        acm->ctrlReq = UsbAllocRequest(acm->ctrDevHandle, 0, len);
480        if (acm->ctrlReq == NULL) {
481            return HDF_ERR_IO;
482        }
483    }
484
485    controlParams.request = request;
486    controlParams.target = USB_REQUEST_TARGET_INTERFACE; // Interface object
487    controlParams.reqType = USB_REQUEST_TYPE_CLASS; // Request type
488    controlParams.direction = USB_REQUEST_DIR_TO_DEVICE; // Data transfer from the host to the device
489    controlParams.value = value;
490    controlParams.index = index;
491    controlParams.data = buf;
492    controlParams.size = len;
493
494    params.interfaceId = USB_CTRL_INTERFACE_ID; // Define the default ID of the USB control interface.
495    params.pipeAddress = acm->ctrPipe->pipeAddress;
496    params.pipeId = acm->ctrPipe->pipeId;
497    params.requestType = USB_REQUEST_PARAMS_CTRL_TYPE; // Control type.
498    params.timeout = USB_CTRL_SET_TIMEOUT; // Set the timeout interval.
499    params.ctrlReq = UsbControlSetUp(&controlParams);
500    // Fill in the pre-allocated I/O request based on UsbRequestParams.
501    ret = UsbFillRequest(acm->ctrlReq, acm->ctrDevHandle, &params);
502    if (ret != HDF_SUCCESS) {
503        return ret;
504    }
505    // Send an I/O request synchronously.
506    ret = UsbSubmitRequestSync(acm->ctrlReq);
507    if (ret != HDF_SUCCESS) {
508        return ret;
509    }
510    if (!acm->ctrlReq->compInfo.status) {
511        HDF_LOGE("%s status=%d ", __func__, acm->ctrlReq->compInfo.status);
512    }
513    return HDF_SUCCESS;
514}
515...
516static struct UsbInterface *GetUsbInterfaceById(const struct AcmDevice *acm,
517    uint8_t interfaceIndex)
518{
519    struct UsbInterface *tmpIf = NULL;
520    // Obtain a UsbInterface object.
521    tmpIf = (struct UsbInterface *)UsbClaimInterface(acm->session, acm->busNum, acm->devAddr, interfaceIndex);
522    return tmpIf;
523}
524...
525static struct UsbPipeInfo *EnumePipe(const struct AcmDevice *acm,
526    uint8_t interfaceIndex, UsbPipeType pipeType, UsbPipeDirection pipeDirection)
527{
528    uint8_t i;
529    int32_t ret;
530    struct UsbInterfaceInfo *info = NULL; // Define a UsbInterfaceInfo object.
531    UsbInterfaceHandle *interfaceHandle = NULL; // Define a USB interface operation handle (that is, the void * type).
532    if (pipeType == USB_PIPE_TYPE_CONTROL)
533    {
534        info = &acm->ctrIface->info;
535        interfaceHandle = acm->ctrDevHandle;
536    }
537    else
538    {
539        info = &acm->iface[interfaceIndex]->info;
540        // Obtain the device handle based on interfaceIndex.
541        interfaceHandle = InterfaceIdToHandle(acm, info->interfaceIndex);
542    }
543
544    for (i = 0;  i <= info->pipeNum; i++) {
545        struct UsbPipeInfo p;
546        // Obtain the pipeInfo object whose index is i.
547        ret = UsbGetPipeInfo(interfaceHandle, info->curAltSetting, i, &p);
548        if (ret < 0) {
549            continue;
550        }
551        if ((p.pipeDirection == pipeDirection) && (p.pipeType == pipeType)) {
552            struct UsbPipeInfo *pi = OsalMemCalloc(sizeof(*pi)); // Allocate and initialize the memory.
553            if (pi == NULL) {
554                return NULL;
555            }
556            p.interfaceId = info->interfaceIndex;
557            *pi = p;
558            return pi;
559        }
560    }
561    return NULL;
562}
563
564static struct UsbPipeInfo *GetPipe(const struct AcmDevice *acm,
565    UsbPipeType pipeType, UsbPipeDirection pipeDirection)
566{
567    uint8_t i;
568    if (acm == NULL) {
569        return NULL;
570    }
571    for (i = 0; i < acm->interfaceCnt; i++) {
572        struct UsbPipeInfo *p = NULL;
573        if (!acm->iface[i]) {
574            continue;
575        }
576        // Obtain pipe information of the control pipe.
577        p = EnumePipe(acm, i, pipeType, pipeDirection);
578        if (p == NULL) {
579            continue;
580        }
581        return p;
582    }
583    return NULL;
584}
585
586/* HdfDriverEntry implementations */
587static int32_t UsbSerialDriverBind(struct HdfDeviceObject *device)
588{
589    struct UsbPnpNotifyServiceInfo *info = NULL;
590    errno_t err;
591    struct AcmDevice *acm = NULL;
592    if (device == NULL) {
593        return HDF_ERR_INVALID_OBJECT;
594    }
595    acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*acm));
596    if (acm == NULL) {
597        return HDF_FAILURE;
598    }
599    // Initialize the mutex. &acm->lock indicates the pointer pointing to the mutex.
600    if (OsalMutexInit(&acm->lock) != HDF_SUCCESS) {
601        goto error;
602    }
603    info = (struct UsbPnpNotifyServiceInfo *)device->priv;
604    if (info != NULL) {
605        acm->busNum = info->busNum;
606        acm->devAddr = info->devNum;
607        acm->interfaceCnt = info->interfaceLength;
608        err = memcpy_s((void *)(acm->interfaceIndex), USB_MAX_INTERFACES,
609              (const void*)info->interfaceNumber, info->interfaceLength);
610        if (err != EOK) {
611            goto lock_error;
612        }
613    } else {
614        goto lock_error;
615    }
616    acm->device  = device;
617    device->service = &(acm->service);
618    acm->device->service->Dispatch = UsbSerialDeviceDispatch;
619    return HDF_SUCCESS;
620
621lock_error:
622    if (OsalMutexDestroy(&acm->lock)) {
623        HDF_LOGE("%s:%d OsalMutexDestroy failed", __func__, __LINE__);
624    }
625error:
626    OsalMemFree(acm);
627    acm = NULL;
628    return HDF_FAILURE;
629}
630...
631static int32_t AcmAllocReadRequests(struct AcmDevice *acm)
632{
633    int32_t ret;
634    struct UsbRequestParams readParams;
635    for (int32_t i = 0; i < ACM_NR; i++) {
636        // Allocate the readReq I/O request to be sent.
637        acm->readReq[i] = UsbAllocRequest(InterfaceIdToHandle(acm, acm->dataInPipe->interfaceId), 0, acm->readSize);
638        if (!acm->readReq[i]) {
639            goto error;
640        }
641        readParams.userData = (void *)acm;
642        readParams.pipeAddress = acm->dataInPipe->pipeAddress;
643        readParams.pipeId = acm->dataInPipe->pipeId;
644        readParams.interfaceId = acm->dataInPipe->interfaceId;
645        readParams.callback = AcmReadBulk;
646        readParams.requestType = USB_REQUEST_PARAMS_DATA_TYPE; /* Data type */
647        readParams.timeout = USB_CTRL_SET_TIMEOUT;
648        readParams.dataReq.numIsoPackets = 0;
649        readParams.dataReq.direction = (acm->dataInPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & 0x1;
650        readParams.dataReq.length = acm->readSize;
651        // Fill in the readReq IO Request object to be sent based on readParams.
652        ret = UsbFillRequest(acm->readReq[i], InterfaceIdToHandle(acm, acm->dataInPipe->interfaceId), &readParams);
653        if (ret != HDF_SUCCESS) {
654            goto error;
655        }
656    }
657    return HDF_SUCCESS;
658
659error:
660    AcmFreeReadRequests(acm);
661    return HDF_ERR_MALLOC_FAIL;
662}
663
664static int32_t AcmAllocNotifyRequest(struct AcmDevice *acm)
665{
666    int32_t ret;
667    struct UsbRequestParams intParams = {};
668    // Allocate the interrupt I/O request to be sent.
669    acm->notifyReq = UsbAllocRequest(InterfaceIdToHandle(acm, acm->intPipe->interfaceId), 0, acm->intSize);
670    if (!acm->notifyReq) {
671        return HDF_ERR_MALLOC_FAIL;
672    }
673    intParams.userData = (void *)acm;
674    intParams.pipeAddress = acm->intPipe->pipeAddress;
675    intParams.pipeId = acm->intPipe->pipeId;
676    intParams.interfaceId = acm->intPipe->interfaceId;
677    intParams.callback = AcmCtrlIrq;
678    intParams.requestType = USB_REQUEST_PARAMS_DATA_TYPE;
679    intParams.timeout = USB_CTRL_SET_TIMEOUT;
680    intParams.dataReq.numIsoPackets = 0;
681    intParams.dataReq.direction = (acm->intPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & DIRECTION_MASK;
682    intParams.dataReq.length = acm->intSize;
683    // Fill in the interrupt I/O request.
684    ret = UsbFillRequest(acm->notifyReq, InterfaceIdToHandle(acm, acm->intPipe->interfaceId), &intParams);
685    if (ret != HDF_SUCCESS) {
686        goto error;
687    }
688    return HDF_SUCCESS;
689
690error:
691    AcmFreeNotifyRequest(acm);
692    return ret;
693}
694
695static void AcmReleaseInterfaces(struct AcmDevice *acm)
696{
697    for (int32_t i = 0; i < acm->interfaceCnt; i++) {
698        if (acm->iface[i]) {
699            // Release a USB interface object.
700            UsbReleaseInterface(acm->iface[i]);
701            acm->iface[i] = NULL;
702        }
703    }
704    if (acm->ctrIface) {
705        UsbReleaseInterface(acm->ctrIface);
706        acm->ctrIface = NULL;
707    }
708}
709
710static int32_t AcmClaimInterfaces(struct AcmDevice *acm)
711{
712    for (int32_t i = 0; i < acm->interfaceCnt; i++) {
713        // Obtain a UsbInterface object.
714        acm->iface[i] = GetUsbInterfaceById((const struct AcmDevice *)acm, acm->interfaceIndex[i]);
715        if (acm->iface[i] == NULL) {
716            goto error;
717        }
718    }
719
720    // Obtain the UsbInterface object corresponding to the control interface.
721    acm->ctrIface = GetUsbInterfaceById((const struct AcmDevice *)acm, USB_CTRL_INTERFACE_ID);
722    if (acm->ctrIface == NULL) {
723        goto error;
724    }
725
726    return HDF_SUCCESS;
727
728 error:
729    // Release the UsbInterface object cyclically based on acm->interfaceCnt.
730    AcmReleaseInterfaces(acm);
731    return HDF_FAILURE;
732}
733
734static void AcmCloseInterfaces(struct AcmDevice *acm)
735{
736    for (int32_t i = 0; i < acm->interfaceCnt; i++) {
737        if (acm->devHandle[i]) {
738            // Close a USB device object.
739            UsbCloseInterface(acm->devHandle[i]);
740            acm->devHandle[i] = NULL;
741        }
742    }
743    if (acm->ctrDevHandle) {
744        UsbCloseInterface(acm->ctrDevHandle);
745        acm->ctrDevHandle = NULL;
746    }
747}
748
749static int32_t AcmOpenInterfaces(struct AcmDevice *acm)
750{
751    for (int32_t i = 0; i < acm->interfaceCnt; i++) {
752        if (acm->iface[i]) {
753            // Open the UsbInterface object obtained.
754            acm->devHandle[i] = UsbOpenInterface(acm->iface[i]);
755            if (acm->devHandle[i] == NULL) {
756                goto error;
757            }
758        }
759    }
760    acm->ctrDevHandle = UsbOpenInterface(acm->ctrIface);
761    if (acm->ctrDevHandle == NULL) {
762        goto error;
763    }
764
765    return HDF_SUCCESS;
766
767error:
768    // Disable all UsbInterface objects.
769    AcmCloseInterfaces(acm);
770    return HDF_FAILURE;
771}
772
773static int32_t AcmGetPipes(struct AcmDevice *acm)
774{
775    // Obtain pipe information of dataInPipe.
776    acm->dataInPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_IN);
777    if (acm->dataInPipe == NULL) {
778        goto error;
779    }
780
781    // Obtain pipe information of dataOutPipe.
782    acm->dataOutPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_OUT);
783    if (acm->dataOutPipe == NULL) {
784        goto error;
785    }
786
787    // Obtain pipe information of the control pipe.
788    acm->ctrPipe = EnumePipe(acm, acm->ctrIface->info.interfaceIndex, USB_PIPE_TYPE_CONTROL, USB_PIPE_DIRECTION_OUT);
789    if (acm->ctrPipe == NULL) {
790        goto error;
791    }
792
793    //Obtain pipe information of the interrupt pipe.
794    acm->intPipe = GetPipe(acm, USB_PIPE_TYPE_INTERRUPT, USB_PIPE_DIRECTION_IN);
795    if (acm->intPipe == NULL) {
796        goto error;
797    }
798
799    acm->readSize  = acm->dataInPipe->maxPacketSize;
800    acm->writeSize = acm->dataOutPipe->maxPacketSize;
801    acm->ctrlSize  = acm->ctrPipe->maxPacketSize;
802    acm->intSize   = acm->intPipe->maxPacketSize;
803    return HDF_SUCCESS;
804
805error:
806    // Release all pipe information on the device.
807    AcmFreePipes(acm);
808    return HDF_FAILURE;
809}
810
811static void AcmFreeRequests(struct AcmDevice *acm)
812{
813    if (g_syncRequest != NULL) {
814        UsbFreeRequest(g_syncRequest);
815        g_syncRequest = NULL;
816    }
817    AcmFreeReadRequests(acm);
818    AcmFreeNotifyRequest(acm);
819    AcmFreeWriteRequests(acm);
820    AcmWriteBufFree(acm);
821}
822
823static int32_t AcmAllocRequests(struct AcmDevice *acm)
824{
825    int32_t ret;
826
827    if (AcmWriteBufAlloc(acm) < 0) {
828        return HDF_ERR_MALLOC_FAIL;
829    }
830
831    for (int32_t i = 0; i < ACM_NW; i++) {
832        struct AcmWb *snd = &(acm->wb[i]);
833        // Allocate the I/O request to be sent.
834        snd->request = UsbAllocRequest(InterfaceIdToHandle(acm, acm->dataOutPipe->interfaceId), 0, acm->writeSize);
835        snd->instance = acm;
836        if (snd->request == NULL) {
837            goto error_alloc_write_req;
838        }
839    }
840
841    ret = AcmAllocNotifyRequest(acm); // Allocate and fill in the interrupt I/O request.
842    if (ret != HDF_SUCCESS) {
843        goto error_alloc_int_req;
844    }
845
846    ret = AcmAllocReadRequests(acm);    // Allocate and fill in the readReq I/O request.
847    if (ret) {
848        goto error_alloc_read_req;
849    }
850
851    return HDF_SUCCESS;
852
853error_alloc_read_req:
854    AcmFreeNotifyRequest(acm);
855error_alloc_int_req:
856    AcmFreeWriteRequests(acm);
857error_alloc_write_req:
858    AcmWriteBufFree(acm);
859    return HDF_FAILURE;
860}
861
862static int32_t AcmInit(struct AcmDevice *acm)
863{
864    int32_t ret;
865    struct UsbSession *session = NULL;
866
867    if (acm->initFlag == true) {
868        return HDF_SUCCESS;
869    }
870
871    // Initialize the USB Host DDK.
872    ret = UsbInitHostSdk(NULL);
873    if (ret != HDF_SUCCESS) {
874        return HDF_ERR_IO;
875    }
876    acm->session = session;
877
878    // Obtain UsbInterface objects based on acm->interfaceIndex[i].
879    ret = AcmClaimInterfaces(acm);
880    if (ret != HDF_SUCCESS) {
881        goto error_claim_interfaces;
882    }
883
884    // Open UsbInterface objects based on acm->iface[i].
885    ret = AcmOpenInterfaces(acm);
886    if (ret != HDF_SUCCESS) {
887        goto error_open_interfaces;
888    }
889
890    // Obtain the pointer to the pipe information.
891    ret = AcmGetPipes(acm);
892    if (ret != HDF_SUCCESS) {
893        goto error_get_pipes;
894    }
895
896    ret = AcmAllocRequests(acm);
897    if (ret != HDF_SUCCESS) {
898        goto error_alloc_reqs;
899    }
900
901    acm->lineCoding.dwDTERate = CpuToLe32(DATARATE); // Convert to little-endian data.
902    acm->lineCoding.bCharFormat = CHARFORMAT; // 8
903    acm->lineCoding.bParityType = USB_CDC_NO_PARITY;
904    acm->lineCoding.bDataBits = USB_CDC_1_STOP_BITS;
905    acm->initFlag = true;
906    return HDF_SUCCESS;
907
908error_alloc_reqs:
909    AcmFreePipes(acm);
910error_get_pipes:
911    // Disable all UsbInterface objects.
912    AcmCloseInterfaces(acm);
913error_open_interfaces:
914    // Release all UsbInterface objects.
915    AcmReleaseInterfaces(acm);
916error_claim_interfaces:
917    // Exit the USB DDK on the host. acm->session indicates the pointer pointing to the session context.
918    UsbExitHostSdk(acm->session);
919    acm->session = NULL;
920    return ret;
921}
922
923static void AcmRelease(struct AcmDevice *acm)
924{
925    if (acm->initFlag == false) {
926        return;
927    }
928
929    AcmFreeRequests(acm);
930    AcmFreePipes(acm);
931    AcmCloseInterfaces(acm);
932    AcmReleaseInterfaces(acm);
933    // Exit the USB DDK on the host.
934    UsbExitHostSdk(acm->session);
935    acm->session = NULL;
936    acm->initFlag = false;
937}
938
939static int32_t UsbSerialDriverInit(struct HdfDeviceObject *device)
940{
941    int32_t ret;
942    struct AcmDevice *acm = NULL;
943
944    if (device == NULL) {
945        return HDF_ERR_INVALID_OBJECT;
946    }
947    acm = (struct AcmDevice *)device->service;
948    // Initialize the mutex. &acm->readLock indicates the pointer pointing to the mutex.
949    OsalMutexInit(&acm->readLock);
950    OsalMutexInit(&acm->writeLock);
951    HDF_LOGD("%s:%d busNum=%d,devAddr=%d", __func__, __LINE__, acm->busNum, acm->devAddr);
952
953    // Allocate space for the USB serial port device information and assign a value.
954    ret = UsbSerialDeviceAlloc(acm);
955    if (ret != HDF_SUCCESS) {
956        HDF_LOGE("%s: Serial Device alloc failed", __func__);
957    }
958
959    acm->initFlag = false;
960    g_acmReleaseFlag = false;
961    return ret;
962}
963
964static void UsbSerialDriverRelease(struct HdfDeviceObject *device)
965{
966    struct AcmDevice *acm = NULL;
967
968    if (device == NULL) {
969        return;
970    }
971    acm = (struct AcmDevice *)device->service;
972    if (acm == NULL) {
973        return;
974    }
975
976    g_acmReleaseFlag = true;
977
978    if (acm->initFlag == true) {
979        AcmRelease(acm);
980    }
981    // Release the USB serial port device information.
982    UsbSeriaDevicelFree(acm);
983    // Release the mutex.
984    OsalMutexDestroy(&acm->writeLock);
985    OsalMutexDestroy(&acm->readLock);
986    OsalMutexDestroy(&acm->lock);
987    OsalMemFree(acm);
988    acm = NULL;
989}
990
991// Perform Bind, Init, and Release operations on the driver.
992struct HdfDriverEntry g_usbSerialDriverEntry = {
993    .moduleVersion = 1,
994    .moduleName    = "usbhost_acm",    // Driver module name, which must be the same as that configured in the .hcs file.
995    .Bind          = UsbSerialDriverBind,
996    .Init          = UsbSerialDriverInit,
997    .Release       = UsbSerialDriverRelease,
998};
999HDF_INIT(g_usbSerialDriverEntry); // Driver entry.
1000```
1001
1002#### Developing Driver Using Host Raw APIs
1003
1004```cpp
1005root {
1006    module = "usb_pnp_device";
1007    usb_pnp_config {
1008        match_attr = "usb_pnp_match";
1009        usb_pnp_device_id = "UsbPnpDeviceId";
1010        UsbPnpDeviceId {
1011            idTableList = [
1012                "host_acm_rawapi_table"
1013            ];
1014            host_acm_rawapi_table {    // Driver mapping table information.
1015                // Driver module name, which must be the same as the value of moduleName in the driver entry structure.
1016                moduleName = "usbhost_acm_rawapi";
1017                // Service name of the driver, which must be unique.
1018                serviceName = "usbhost_acm_rawapi_service";
1019                // Keyword for matching private driver data.
1020                deviceMatchAttr = "usbhost_acm_rawapi_matchAttr";
1021                // Data length starting from this field, in bytes.
1022                length = 21;
1023                // USB driver matching rule: vendorId+productId+interfaceSubClass+interfaceProtocol+interfaceNumber.
1024                matchFlag = 0x0303;
1025                // Vendor ID.
1026                vendorId = 0x12D1;
1027                // Product ID.
1028                productId = 0x5000;
1029                // The least significant 16 bits of the device sequence number.
1030                bcdDeviceLow = 0x0000;
1031                // The most significant 16 bits of the device sequence number.
1032                bcdDeviceHigh = 0x0000;
1033                // Device class code allocated by the USB.
1034                deviceClass = 0;
1035                // Child class code allocated by the USB.
1036                deviceSubClass = 0;
1037                // Device protocol code allocated by the USB.
1038                deviceProtocol = 0;
1039                // Interface type. You can enter multiple types as needed.
1040                interfaceClass = [0];
1041                // Interface subtype. You can enter multiple subtypes as needed.
1042                interfaceSubClass = [2, 0];
1043                // Protocol that the interface complies with. You can enter multiple protocols as needed.
1044                interfaceProtocol = [1, 2];
1045                // Interface number. You can enter multiple interface numbers as needed.
1046                interfaceNumber = [2, 3];
1047            }
1048        }
1049    }
1050}
1051```
1052
1053```cpp
1054#include "usb_serial_rawapi.h"
1055#include <unistd.h>
1056#include "osal_mem.h"
1057#include "osal_time.h"
1058#include "securec.h"
1059#include "hdf_base.h"
1060#include "hdf_log.h"
1061#include "hdf_usb_pnp_manage.h"
1062
1063#define HDF_LOG_TAG                     USB_HOST_ACM_RAW_API // Labels that can be queried in logs.
1064#define USB_CTRL_REQ_SIZE               64
1065#define USB_IO_THREAD_STACK_SIZE        8192
1066#define USB_RAW_IO_SLEEP_MS_TIME        100
1067#define USB_RAW_IO_STOP_WAIT_MAX_TIME   3
1068
1069static struct UsbRawRequest *g_syncRequest = NULL;
1070static UsbRawIoProcessStatusType g_stopIoStatus = USB_RAW_IO_PROCESS_RUNNING;
1071struct OsalMutex g_stopIoLock;
1072static bool g_rawAcmReleaseFlag = false;
1073......
1074
1075static int32_t UsbGetConfigDescriptor(UsbRawHandle *devHandle, struct UsbRawConfigDescriptor **config)
1076{
1077    UsbRawDevice *dev = NULL;
1078    int32_t activeConfig;
1079    int32_t ret;
1080
1081    if (devHandle == NULL) {
1082        return HDF_ERR_INVALID_PARAM;
1083    }
1084
1085    // Obtain the configuration of the active device.
1086    ret = UsbRawGetConfiguration(devHandle, &activeConfig);
1087    if (ret != HDF_SUCCESS) {
1088        return HDF_FAILURE;
1089    }
1090
1091    // Obtain the device pointer based on the specified device handle.
1092    dev = UsbRawGetDevice(devHandle);
1093    if (dev == NULL) {
1094        return HDF_FAILURE;
1095    }
1096
1097    // Obtain the device configuration descriptor based on the specified device ID.
1098    ret = UsbRawGetConfigDescriptor(dev, activeConfig, config);
1099    if (ret != HDF_SUCCESS) {
1100        HDF_LOGE("UsbRawGetConfigDescriptor failed, ret=%d\n", ret);
1101    }
1102    return ret;
1103}
1104...
1105static int32_t UsbAllocWriteRequests(struct AcmDevice *acm)
1106{
1107    int32_t i;
1108
1109    for (i = 0; i < ACM_NW; i++) {
1110        struct AcmWb *snd = &acm->wb[i];
1111        // Allocate a transfer request with the specified number of sync packet descriptors.
1112        snd->request = UsbRawAllocRequest(acm->devHandle, 0, acm->dataOutEp->maxPacketSize);
1113        snd->instance = acm;
1114        if (snd->request == NULL) {
1115            return HDF_ERR_MALLOC_FAIL;
1116        }
1117    }
1118
1119    return HDF_SUCCESS;
1120}
1121...
1122/* HdfDriverEntry implementations */
1123static int32_t UsbSerialDriverBind(struct HdfDeviceObject *device)
1124{
1125    struct AcmDevice *acm = NULL;
1126    struct UsbPnpNotifyServiceInfo *info = NULL;
1127    errno_t err;
1128
1129    if (device == NULL) {
1130        return HDF_ERR_INVALID_OBJECT;
1131    }
1132
1133    acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*acm));
1134    if (acm == NULL) {
1135        return HDF_FAILURE;
1136    }
1137    if (OsalMutexInit(&acm->lock) != HDF_SUCCESS) {
1138        goto error;
1139    }
1140
1141    info = (struct UsbPnpNotifyServiceInfo *)device->priv;
1142    if (info != NULL) {
1143        acm->busNum       = info->busNum;
1144        acm->devAddr      = info->devNum;
1145        acm->interfaceCnt = info->interfaceLength;
1146        err = memcpy_s((void *)(acm->interfaceIndex), USB_MAX_INTERFACES,
1147                       (const void*)info->interfaceNumber, info->interfaceLength);
1148        if (err != EOK) {
1149            goto lock_error;
1150        }
1151    } else {
1152        goto lock_error;
1153    }
1154
1155    device->service = &(acm->service);
1156    device->service->Dispatch = UsbSerialDeviceDispatch;
1157    acm->device = device;
1158    return HDF_SUCCESS;
1159
1160lock_error:
1161    if (OsalMutexDestroy(&acm->lock)) {
1162        HDF_LOGE("%s:%d OsalMutexDestroy failed", __func__, __LINE__);
1163    }
1164error:
1165    OsalMemFree(acm);
1166    acm = NULL;
1167    return HDF_FAILURE;
1168}
1169...
1170static int32_t UsbAllocReadRequests(struct AcmDevice *acm)
1171{
1172    struct UsbRawFillRequestData reqData;
1173    int32_t size = acm->dataInEp->maxPacketSize;
1174    int32_t ret;
1175
1176    for (int32_t i = 0; i < ACM_NR; i++) {
1177        // Allocate a transfer request with the specified number of sync packet descriptors.
1178        acm->readReq[i] = UsbRawAllocRequest(acm->devHandle, 0, size);
1179        if (!acm->readReq[i]) {
1180            return HDF_ERR_MALLOC_FAIL;
1181        }
1182
1183        reqData.endPoint      = acm->dataInEp->addr;
1184        reqData.numIsoPackets = 0;
1185        reqData.callback      = AcmReadBulkCallback;
1186        reqData.userData      = (void *)acm;
1187        reqData.timeout       = USB_CTRL_SET_TIMEOUT;
1188        reqData.length        = size;
1189
1190        // Fill the required information in the bulk transfer request.
1191        ret = UsbRawFillBulkRequest(acm->readReq[i], acm->devHandle, &reqData);
1192        if (ret != HDF_SUCCESS) {
1193            return HDF_FAILURE;
1194        }
1195    }
1196
1197    return HDF_SUCCESS;
1198}
1199...
1200static int32_t UsbAllocNotifyRequest(struct AcmDevice *acm)
1201{
1202    struct UsbRawFillRequestData fillRequestData;
1203    int32_t size = acm->notifyEp->maxPacketSize;
1204    int32_t ret;
1205
1206    // Allocate a transfer request with the specified number of sync packet descriptors.
1207    acm->notifyReq = UsbRawAllocRequest(acm->devHandle, 0, size);
1208    if (!acm->notifyReq) {
1209        return HDF_ERR_MALLOC_FAIL;
1210    }
1211
1212    fillRequestData.endPoint = acm->notifyEp->addr;
1213    fillRequestData.length = size;
1214    fillRequestData.numIsoPackets = 0;
1215    fillRequestData.callback = AcmNotifyReqCallback;
1216    fillRequestData.userData = (void *)acm;
1217    fillRequestData.timeout = USB_CTRL_SET_TIMEOUT;
1218
1219    // Fill the required information in the interrupt transfer request.
1220    ret = UsbRawFillInterruptRequest(acm->notifyReq, acm->devHandle, &fillRequestData);
1221    if (ret != HDF_SUCCESS) {
1222        return HDF_FAILURE;
1223    }
1224
1225    return HDF_SUCCESS;
1226}
1227...
1228static int32_t UsbSerialInit(struct AcmDevice *acm)
1229{
1230    struct UsbSession *session = NULL;
1231    UsbRawHandle *devHandle = NULL;
1232    int32_t ret;
1233
1234    if (acm->initFlag == true) {
1235        return HDF_SUCCESS;
1236    }
1237
1238    // Initialize the USB DDK in expert mode.
1239    ret = UsbRawInit(NULL);
1240    if (ret != HDF_SUCCESS) {
1241        return HDF_ERR_IO;
1242    }
1243    acm->session = session;
1244
1245    // Open a USB device object.
1246    devHandle = UsbRawOpenDevice(session, acm->busNum, acm->devAddr);
1247    if (devHandle == NULL) {
1248        ret =  HDF_FAILURE;
1249        goto err_open_device;
1250    }
1251    acm->devHandle = devHandle;
1252    // Obtain the configuration of the active device, device pointer, and configuration descriptor.
1253    ret = UsbGetConfigDescriptor(devHandle, &acm->config);
1254    if (ret != HDF_SUCCESS) {
1255        ret =  HDF_FAILURE;
1256        goto err_get_desc;
1257    }
1258    ret = UsbParseConfigDescriptor(acm, acm->config);
1259    if (ret != HDF_SUCCESS) {
1260        ret = HDF_FAILURE;
1261        goto err_parse_desc;
1262    }
1263
1264    ret = AcmWriteBufAlloc(acm);
1265    if (ret < 0) {
1266        ret = HDF_FAILURE;
1267        goto err_alloc_write_buf;
1268    }
1269    ret = UsbAllocWriteRequests(acm);
1270    if (ret < 0) {
1271        ret = HDF_FAILURE;
1272        goto err_alloc_write_reqs;
1273    }
1274    ret = UsbAllocNotifyRequest(acm);
1275    if (ret) {
1276        goto err_alloc_notify_req;
1277    }
1278    ret = UsbAllocReadRequests(acm);
1279    if (ret) {
1280        goto err_alloc_read_reqs;
1281    }
1282    ret = UsbStartIo(acm);
1283    if (ret) {
1284        goto err_start_io;
1285    }
1286
1287    acm->lineCoding.dwDTERate   = CpuToLe32(DATARATE);
1288    acm->lineCoding.bCharFormat = CHARFORMAT;
1289    acm->lineCoding.bParityType = USB_CDC_NO_PARITY;
1290    acm->lineCoding.bDataBits   = USB_CDC_1_STOP_BITS;
1291
1292    ret = UsbRawSubmitRequest(acm->notifyReq);
1293    if (ret) {
1294        goto err_submit_req;
1295    }
1296
1297    acm->initFlag = true;
1298    return HDF_SUCCESS;
1299
1300err_submit_req:
1301    UsbStopIo(acm); // Stop the I/O thread and release all resources.
1302err_start_io:
1303    UsbFreeReadRequests(acm);
1304err_alloc_read_reqs:
1305    UsbFreeNotifyRequest(acm);
1306 err_alloc_notify_req:
1307    UsbFreeWriteRequests(acm);
1308err_alloc_write_reqs:
1309    AcmWriteBufFree(acm);
1310err_alloc_write_buf:
1311    UsbReleaseInterfaces(acm);
1312err_parse_desc:
1313    UsbRawFreeConfigDescriptor(acm->config);
1314    acm->config = NULL;
1315err_get_desc:
1316    (void)UsbRawCloseDevice(devHandle); // Close the USB device object.
1317err_open_device:
1318    UsbRawExit(acm->session); // Exit the expert mode of the USB DDK.
1319
1320    return ret;
1321}
1322
1323static void UsbSerialRelease(struct AcmDevice *acm)
1324{
1325    if (acm->initFlag == false) {
1326        return;
1327    }
1328
1329    /* stop io thread and release all resources */
1330    UsbStopIo(acm);
1331    if (g_syncRequest != NULL) {
1332        UsbRawFreeRequest(g_syncRequest);
1333        g_syncRequest = NULL;
1334    }
1335    UsbFreeReadRequests(acm);
1336    UsbFreeNotifyRequest(acm);
1337    UsbFreeWriteRequests(acm);
1338    AcmWriteBufFree(acm);
1339    (void)UsbRawCloseDevice(acm->devHandle);
1340    UsbReleaseInterfaces(acm);
1341    UsbRawFreeConfigDescriptor(acm->config);
1342    acm->config = NULL;
1343    // Exit the expert mode of the USB DDK.
1344    UsbRawExit(acm->session);
1345
1346    acm->initFlag = false;
1347}
1348
1349static int32_t UsbSerialDriverInit(struct HdfDeviceObject *device)
1350{
1351    struct AcmDevice *acm = NULL;
1352    int32_t ret;
1353
1354    if (device == NULL) {
1355        return HDF_ERR_INVALID_OBJECT;
1356    }
1357    acm = (struct AcmDevice *)device->service;
1358    OsalMutexInit(&acm->readLock);
1359    OsalMutexInit(&acm->writeLock);
1360
1361    ret = UsbSerialDeviceAlloc(acm);
1362    if (ret != HDF_SUCCESS) {
1363        HDF_LOGE("%s:%d UsbSerialDeviceAlloc failed", __func__, __LINE__);
1364    }
1365
1366    acm->initFlag = false;
1367    g_rawAcmReleaseFlag = false;
1368    return ret;
1369}
1370
1371static void UsbSerialDriverRelease(struct HdfDeviceObject *device)
1372{
1373    struct AcmDevice *acm = NULL;
1374    if (device == NULL) {
1375        return;
1376    }
1377
1378    acm = (struct AcmDevice *)device->service;
1379    if (acm == NULL) {
1380        return;
1381    }
1382
1383    g_rawAcmReleaseFlag = true;
1384
1385    if (acm->initFlag == true) {
1386        UsbSerialRelease(acm);
1387    }
1388    UsbSeriaDevicelFree(acm);
1389    OsalMutexDestroy(&acm->writeLock);
1390    OsalMutexDestroy(&acm->readLock);
1391    OsalMutexDestroy(&acm->lock);
1392    OsalMemFree(acm);
1393    acm = NULL;
1394}
1395
1396struct HdfDriverEntry g_usbSerialRawDriverEntry = {
1397    .moduleVersion = 1,
1398    .moduleName    = "usbhost_acm_rawapi", // Driver module name, which must be the same as that configured in the .hcs file.
1399    .Bind          = UsbSerialDriverBind,
1400    .Init          = UsbSerialDriverInit,
1401    .Release       = UsbSerialDriverRelease,
1402};
1403HDF_INIT(g_usbSerialRawDriverEntry);
1404```
1405
1406#### Developing Driver Using Device DDK APIs
1407
1408The core code of the USB ACM device is stored in **drivers\peripheral\usb\gadget\function\acm\cdcacm.c**. The following sample code implements driver development by using the Device DDK APIs. To develop a driver, you must create a device based on the descriptor, obtain the interface, open the interface to obtain the pipe information, receive events, and then perform USB communication (such as read and write). When the device is uninstalled, you need to close the interface, stop receiving events, and remove the device.
1409
14101. Create a USB device.
1411
1412    ```cpp
1413    static int32_t AcmCreateFuncDevice(struct UsbAcmDevice *acm, struct DeviceResourceIface *iface)
1414    {
1415        struct UsbFnDevice *fnDev = NULL;
1416        struct UsbFnDescriptorData descData;
1417        uint8_t useHcs;
1418        ...
1419        if (useHcs == 0) { // The descriptor is sourced from the code.
1420            descData.type = USBFN_DESC_DATA_TYPE_DESC;
1421            descData.descriptor = &g_masterFuncDevice;
1422        } else {// The descriptor is sourced from the .hcs file.
1423            descData.type = USBFN_DESC_DATA_TYPE_PROP;
1424            descData.property = device->property;
1425        }
1426        /* Create a device. */
1427        fnDev = (struct UsbFnDevice *)UsbFnDeviceCreate(acm->udcName, &descData);
1428        if (fnDev == NULL) {
1429            return HDF_FAILURE;
1430        }
1431        ...
1432    }
1433    ```
1434
14352. Obtain an interface and open the interface to obtain the pipe information.
1436
1437    ```cpp
1438    static int32_t AcmParseEachPipe(struct UsbAcmDevice *acm, struct UsbAcmInterface *iface)
1439    {
1440        ...
1441        for (i = 0; i < fnIface->info.numPipes; i++) {
1442            struct UsbFnPipeInfo pipeInfo;
1443            /* Obtain pipe information. */
1444            ret = UsbFnInterfaceGetPipeInfo(fnIface, i, &pipeInfo);
1445            ...
1446        }
1447        return HDF_SUCCESS;
1448    }
1449    /* Obtain an interface and open the interface to obtain the handle. */
1450    static int32_t AcmParseEachIface(struct UsbAcmDevice *acm, struct UsbFnDevice *fnDev)
1451    {
1452        ...
1453        for (i = 0; i < fnDev->numInterfaces; i++) {
1454            /* Obtain an interface.*/
1455            fnIface = (struct UsbFnInterface *)UsbFnGetInterface(fnDev, i);
1456            ...
1457            /* Open the interface. */
1458            handle = UsbFnInterfaceOpen(fnIface);
1459            ...
1460        }
1461        return HDF_SUCCESS;
1462    }
1463    ```
1464
14653. Receive events (EP0 control transfer).
1466
1467    ```cpp
1468    static int32_t AcmAllocCtrlRequests(struct UsbAcmDevice *acm, int32_t num)
1469    {
1470        ...
1471        req = UsbFnCtrlRequestAlloc(acm->ctrlIface.handle,
1472            sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding));
1473        ...
1474    }
1475    static int32_t AcmDriverInit(struct HdfDeviceObject *device)
1476    {
1477        ...
1478        /* Start to receive events.*/
1479        ret = UsbFnInterfaceStartRecvEvent(acm->ctrlIface.fn, 0xff, UsbAcmEventCallback, acm);
1480        ...
1481    }
1482    ```
1483
14844. Perform USB communication (read and write).
1485
1486    ```cpp
1487    static int32_t AcmSendNotifyRequest(struct UsbAcmDevice *acm, uint8_t type,
1488        uint16_t value, void *data, uint32_t length)
1489    {
1490        ...
1491        /* Send an asynchronous request.*/
1492        ret = UsbFnRequestSubmitAsync(req);
1493        ...
1494    }
1495    ```
1496
14975. Close the interface, stop receiving events, and delete the device.
1498
1499    ```cpp
1500    static int32_t AcmReleaseFuncDevice(struct UsbAcmDevice *acm)
1501    {
1502        int32_t ret;
1503        /* Close the interface. */
1504        (void)UsbFnInterfaceClose(acm->ctrlIface.handle);
1505        (void)UsbFnInterfaceClose(acm->dataIface.handle);
1506        /* Stop receiving the Event EP0 control transfer. */
1507        (void)UsbFnInterfaceStopRecvEvent(acm->ctrlIface.fn);
1508        /* Delete the device. */
1509        ret = UsbFnDeviceRemove(acm->fnDev);
1510        if (ret != HDF_SUCCESS) {
1511            HDF_LOGE("%s: remove usb function device failed", __func__);
1512        }
1513        return ret;
1514    }
1515    ```
1516
1517## References
1518
1519- Code repositories:
1520
1521  **[drivers\_hdf\_core](https://gitee.com/openharmony/drivers_hdf_core)**
1522
1523  [drivers\_peripheral](https://gitee.com/openharmony/drivers_peripheral)
1524
1525  [drivers\_interface](https://gitee.com/openharmony/drivers_interface)
1526
1527- Code paths:
1528
1529  USB driver model adaptation for LiteOS: //drivers/hdf_core/adapter/khdf/liteos/model/usb
1530
1531  USB DDK driver loading: //drivers/hdf_core/framework/model/usb
1532
1533  USB HDI server implementation: //drivers/peripheral/usb/hdi_service
1534
1535  USB HDI external APIs: //out/{product_name}/gen/drivers/interface/usb/v1_0
1536