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