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