diff --git a/en/device-dev/subsystems/figure/structure-of-a-signed-hap.png b/en/device-dev/subsystems/figure/structure-of-a-signed-hap.png new file mode 100644 index 0000000000000000000000000000000000000000..ef0b2154947c2fa3ea3624bf3a46233485a0e1a1 Binary files /dev/null and b/en/device-dev/subsystems/figure/structure-of-a-signed-hap.png differ diff --git a/en/device-dev/subsystems/subsys-security-communicationverify.md b/en/device-dev/subsystems/subsys-security-communicationverify.md index 2432b3991460f75c348de2a094e993a63abd4fc7..5d98f1429cc85c245bfcd3827ba92e71443e0bd7 100644 --- a/en/device-dev/subsystems/subsys-security-communicationverify.md +++ b/en/device-dev/subsystems/subsys-security-communicationverify.md @@ -9,13 +9,13 @@ System services registered with Samgr can be accessed by other processes through IPC APIs. When a process requests to access such an API, IPC authentication is triggered to check whether the process has the required permission. If the process does not have the required permission, the access request will be denied. -When developing a system service, you can use the IPC authentication component to configure access policies for APIs of the service. When other processes access these APIs through IPC, Samgr calls APIs of the IPC authentication component to check whether the processes have the access permission. +When developing a system service, you can use the IPC authentication component to configure access policies for APIs of the service. When other services access these APIs through IPC, Samgr calls APIs of the IPC authentication component to check whether the services have the access permission. ## Available APIs The following table lists the APIs provided by IPC authentication \(intended for Samgr only\). -**Table 1** APIs provided by IPC authentication +**Table 1** APIs provided by IPC authentication - @@ -39,15 +39,15 @@ The following table lists the APIs provided by IPC authentication \(intended for ## How to Develop -This section uses BMS as an example to describe how to configure access policies for APIs provided by the IPC authentication component. In this example, the service registered by BMS with Samgr is **bundlems**, and the feature registered for open APIs is **BmsFeature**. +This section uses BMS as an example to describe how to configure access policies for APIs provided by the IPC authentication component. In this example, the service registered by BMS with Samgr is **bundlems**, and the feature registered for open APIs is **BmsFeature**. -1. On the OpenHarmony side, configure access policies in the **base/security/permission/services/permission\_lite/ipc\_auth/include/policy\_preset.h** file. On the device side, configure access policies in the **vendor/hisilicon/product_name/hals/security/permission\_lite/ipc\_auth/include/policy\_preset\_product.h** file (replace product_name with the actual product name). After that, set **POLICY\_PRODUCT** in the header files to **1**. Access policies are classified into the following three types: +1. On the OpenHarmony side, configure access policies in the **base/security/permission/services/permission\_lite/ipc\_auth/include/policy\_preset.h** file. On the device side, configure access policies in the **vendor/hisilicon/_product name_/hals/security/permission\_lite/ipc\_auth/include/policy\_preset\_product.h** file. After that, set **POLICY\_PRODUCT** in the header files to **1**. Access policies are classified into the following three types: - 1. **RANGE**: Processes with a specified range of UIDs can access BMS APIs. **uidMin** and **uidMax** must be specified. + 1. **RANGE**: Processes with a specified range of UIDs can access BMS APIs. **uidMin** and **uidMax** must be specified. - 2. **FIXED**: Processes with specified UIDs can access BMS APIs. **fixedUid** must be specified, and a maximum of eight UIDs are allowed. + 2. **FIXED**: Processes with specified UIDs can access BMS APIs. **fixedUid** must be specified, and a maximum of eight UIDs are allowed. - 3. **BUNDLENAME**: An application with a specified **bundleName** can access BMS APIs. + 3. **BUNDLENAME**: An application with a specified **bundleName** can access BMS APIs. ``` FeaturePolicy bmsFeature[] = { @@ -59,7 +59,7 @@ This section uses BMS as an example to describe how to configure access policies .fixedUid={2, 3, 8} }, { - .type=RANGE, // Processes with a specified range of UIDs can access BMS APIs. + .type=RANGE, // Processes with a specified range of UIDs can access BMS APIs. .uidMin=100, .uidMax=__INT_MAX__, }, @@ -82,13 +82,13 @@ This section uses BMS as an example to describe how to configure access policies }; ``` -2. Add the policies configured for the features in [Step 1](#li15901515152517) to the global policy settings. You need to set the number of features. +2. Add the policies configured for the features in [Step 1](#li15901515152517) to the global policy settings. You need to set the number of features. ``` static PolicySetting g_presetPolicies[] = { {"permissionms", pmsFeature, 1}, {"abilityms", amsFeature, 2}, - {"bundlems", bmsFeature, 2}, // Add the policies configured for the two features in Step 1 to the global policy settings. + {"bundlems", bmsFeature, 2}, // Add the policies configured for the two features in [Step 1](#li15901515152517) to the global policy settings. {"dtbschedsrv", dmsFeature, 1}, {"samgr", samgrFeature, 1}, {"appspawn", appspawnFeature, 1}, @@ -97,7 +97,7 @@ This section uses BMS as an example to describe how to configure access policies }; ``` -3. Register the **BmsFeature** defined in [Step 1](#li15901515152517) with Samgr. +3. Register the **BmsFeature** defined in [Step 1](#li15901515152517) with Samgr. ``` const char BMS_SERVICE[] = "bundlems"; @@ -118,22 +118,22 @@ This section uses BMS as an example to describe how to configure access policies ``` -When you register a service with Samgr, Samgr calls the **GetCommunicationStrategy** function of the IPC authentication component to obtain access policies of the service. When other processes access this service through IPC, Samgr calls the **IsCommunicationAllowed** function of the IPC authentication component to check whether the processes have the access permission. +When you register a service with Samgr, Samgr calls the **GetCommunicationStrategy** function of the IPC authentication component to obtain access policies of the service. When other services or applications access this service through IPC, Samgr calls the **IsCommunicationAllowed** function of the IPC authentication component to check whether the services or applications have the access permission. ## FAQ -- Service registration failure +- Registering a service with Samgr failed - **Symptom** + **Problem** During the startup of a new service, a message is displayed indicating that the service fails to be registered with Samgr. - **Possible Causes** + **Cause** The service UID is not configured in the IPC authentication component. - **Solutions** + **Solution** - Configure the service UID in the **base/security/permission/services/permission\_lite/ipc\_auth/src/ipc\_auth\_impl.c** file. + Configure a valid UID for the service in the **base/security/permission/services/permission\_lite/ipc\_auth/src/ipc\_auth\_impl.c** file. diff --git a/en/device-dev/subsystems/subsys-security-overview.md b/en/device-dev/subsystems/subsys-security-overview.md index 6149a7ce057d16bf7106862a7448d6742cc78fc1..11159d39de4e69aade5326c7ba4b31705d460934 100644 --- a/en/device-dev/subsystems/subsys-security-overview.md +++ b/en/device-dev/subsystems/subsys-security-overview.md @@ -13,13 +13,9 @@ The OpenHarmony security subsystem provides security capabilities that make your Application permissions determine what system resources and capabilities an application can access. During application development, you need to declare the permissions that the application may require in the **profile.json** file. Static permissions need to be registered during application installation, while dynamic permissions usually involve sensitive information and need users' dynamic authorization. -- Inter-process communication \(IPC\) authentication - - APIs are provided for processes to access system services through IPC. Access policies are configured for these APIs. When a process requests to access an API, the IPC authentication mechanism is triggered to check whether the process has the required permission. If it is found that the process does not have the required permission, the access request will be denied. - - Trusted device group management - You can create and query a group of trusted devices that use the same HUAWEI ID or a peer-to-peer group created by scanning a QR code or using OneHop. With this capability, distributed applications can perform trusted authentication between devices and request from the distributed virtual bus for secure sessions between devices. + You can create and query a group of trusted devices that use the same ID or a peer-to-peer group created by scanning a QR code or using OneHop. With this capability, distributed applications can perform trusted authentication between devices and request from the distributed virtual bus for secure sessions between devices. ## Basic Concepts @@ -33,7 +29,7 @@ Before developing an application that depends on the signature verification comp - BMS - Bundle Manager Service \(BMS\) manages application installation, uninstallation, and data. + Bundle Manager Service \(BMS\) manages application installation, uninstallation, and data on OpenHarmony. - Profile @@ -41,19 +37,9 @@ Before developing an application that depends on the signature verification comp The profile in this document refers to HarmonyAppProvision \(profile for short\). HarmonyAppProvision is in JSON format. -- Leaf certificate - - A leaf certificate is used to sign a bundle or profile. It is the last certificate in a digital certificate chain. - - - Debugging application - A debugging application is a HarmonyOS Ability Package \(HAP\) that is signed with a debugging certificate and profile obtained from the application market. - - -- Application for release - - This application refers to a HAP that is signed with a distribution certificate and profile obtained from the application market, but has not been released in the application market. + A debugging application is a HAP that is signed with a debugging certificate and profile obtained from the application market. - Released application @@ -63,14 +49,11 @@ Before developing an application that depends on the signature verification comp - OpenHarmony self-signed application - This application refers to a HAP that is signed with the profile of the OpenHarmony application you have compiled, and a public/private key pair and certificate of OpenHarmony. + A self-signed application is one that has been signed with the signing certificate and profile issued by OpenHarmony's open-source root CA, which is comprised of a certificate and a key. ## Limitations and Constraints -- Only signatures of debugging, released, and self-signed applications can be verified. +- Only signatures of debugging, released, and OpenHarmony self-signed applications can be verified. - To verify the signature of a debugging application, the UDID of the device on which the debugging application is installed must be in the UDID list contained in the profile. -- Signatures of the applications for release cannot be verified. -- APIs provided by the signature verification component are stored in the [app\_verify\_pub.h](https://gitee.com/fork_ohos_wj/security_interfaces_innerkits_app_verify/blob/master/app_verify_pub.h) file of the **security\_interfaces\_innerkits\_app\_verify** repository and can be called only by system application developers. -- APIs for managing trusted device groups are only available for applications with the system signature permission. diff --git a/en/device-dev/subsystems/subsys-security-rightmanagement.md b/en/device-dev/subsystems/subsys-security-rightmanagement.md index 747ecce03eb0dfdeeda525206f398330dbd6f6c4..8b15372203c89016c5862f443303daa59cdefc67 100644 --- a/en/device-dev/subsystems/subsys-security-rightmanagement.md +++ b/en/device-dev/subsystems/subsys-security-rightmanagement.md @@ -7,7 +7,7 @@ ## How Application Permission Management Works -OpenHarmony allows users to install third-party applications and controls calls made by third-party applications to sensitive permissions. When developing an application, you need to declare the sensitive permissions that the application may require in the **profile.json** file. The permissions include static and dynamic ones. Static permissions need to be registered during application installation, and dynamic permissions can be obtained only upon user authorization. Authorization modes include system settings, manual authorization by applications, and others. In addition, application signature control is used to ensure that the application installation package has been confirmed by the device vendor. +OpenHarmony allows users to install third-party applications and controls calls made by third-party applications to sensitive permissions. When developing an application, you need to declare the sensitive permissions that the application may require in the **profile.json** file. The permissions can be static or dynamic. Static permissions need to be registered during application installation, and dynamic permissions can be obtained only upon user authorization. Authorization modes include system settings, manual authorization by applications, and others. In addition, application signature control is used to ensure that the application installation package has been confirmed by the device vendor. **Table 1** OpenHarmony permissions @@ -215,7 +215,7 @@ This section uses the BMS as an example to describe the application permission d HILOG_ERROR(HILOG_MODULE_APP, "BundleManager install failed due to nullptr parameters"); return false; } - // Check whether the ohos.permission.INSTALL_BUNDLE permission has been granted. + // Check whether the ohos.permission.INSTALL_BUNDLE permission has been granted. if (CheckPermission(0, static_cast(PERMISSION_INSTALL_BUNDLE)) != GRANTED) { HILOG_ERROR(HILOG_MODULE_APP, "BundleManager install failed due to permission denied"); return false; // Application installation fails. diff --git a/en/device-dev/subsystems/subsys-security-sigverify.md b/en/device-dev/subsystems/subsys-security-sigverify.md index 8436c859d8d7708e4fd34d08f786dc53a359db4f..dfc7051d811f6dfe7e7ad0926ae764eac76b5c17 100644 --- a/en/device-dev/subsystems/subsys-security-sigverify.md +++ b/en/device-dev/subsystems/subsys-security-sigverify.md @@ -3,60 +3,48 @@ - [When to Use](#section18502174174019) - [Signature Verification Process](#section554632717226) - [Available APIs](#section1633115419401) -- [Development Procedure \(Scenario 1\)](#section4207112818418) - - [Signature Verification](#section11470123816297) - - [OpenHarmony Self-signed Application Generation](#section167151429133312) - - [Development Examples](#section174318361353) +- [How to Develop](#section4207112818418) + - [OpenHarmony Self-signed Application](#section167151429133312) -- [Development Procedure \(Scenario 2\)](#section81272563427) - - [Signature Verification](#section07028210442) - - [Development Examples](#section1930711345445) - -- [Debugging and Verification](#section427316292411) ## When to Use -You can call the APIs provided by the signature verification component to check integrity of a debugging, released, or OpenHarmony self-signed application. You can also call APIs of the signature verification component to obtain some information in the profile, for example, **appid**. In addition, you can call APIs to check whether the UDID of a debugging application matches that of the device to ensure that the application is installed on the right device. +To ensure the integrity and trustworthiness of the applications to be installed in OpenHarmony, the applications must be signed and their signatures must be verified. + +- In application development: After developing an application, you need to sign its installation package to ensure that the installation package is not tampered with when it is released on devices. To sign the application package, you can use the signature tools and the public key certificates and follow the signing certificate generation specifications provided by the application integrity verification module. For your convenience, a public key certificate and a corresponding private key are preset in OpenHarmony. You need to replace the public key certificate and private key in your commercial version of OpenHarmony. +- In application installation: The Application Framework subsystem of OpenHarmony installs applications. Upon receiving an application installation package, the Application Framework subsystem parses the signature of the installation package, and verifies the signature using the application integrity verification APIs. The application can be installed only after the verification succeeds. During the verification, the application integrity verification module uses the preset public key certificate to verify the signature. ## Signature Verification Process An unsigned HAP is in **.zip** format and consists of a file block, central directory, and end of central directory \(EOCD\). -After the HAP is signed, a signature block is added between the file block and the central directory. The signature block consists of a file signature block, profile signature block, and signature header. The following figure shows the structure of a signed HAP. - -**Figure 1** Structure of a signed HAP - +After the HAP is signed, a signature block is added between the file block and the central directory. The integrated signature block consists of a profile signature block, HAP signature block, and signature header. The following figure shows the structure of a signed HAP. -![](figure/安全子系统.png) +**Figure 1** Structure of a signed HAP +![](figure/structure-of-a-signed-hap.png "structure-of-a-signed-hap") -The signature verification process consists of three steps: HAP signature verification, signature verification for the profile signature block, and profile content verification. +The signature verification process consists of three steps: HAP signature verification, profile signature verification, and profile content verification. **HAP signature verification** -Use the preset root certificate of the device and the certificate chain to prove that the leaf certificate is trusted. Then use the digest obtained by decrypting the public key of the leaf certificate to prove that the HAP is not tampered with. +The HAP signature block is a signed data block in PKCS7 format. The signature verification process includes PKSC7 signature verification, hash comparison, certificate chain verification, and matching between the certificate chain and the device's preset root certificate. -The process is as follows: +**Profile signature verification** -1. Use the preset root certificate of the device to verify the certificate chain in the file signature block and prove that the leaf certificate is trusted. -2. Use the public key in the leaf certificate to verify the file signature block and prove that this block is not tampered with. -3. Calculate and merge the digests of the file block, central directory, and EOCD. Merge the calculation result with the digest of the profile signature block in the signature block. Then compare the merge result with the digest of the file signature block. If they are the same, the HAP signature verification is successful. - -**Signature verification for the profile signature block** - -First of all, check who issued the signature of the profile signature block. If the signature was issued by the application market, the signature is trusted and does not need to be verified. Otherwise, the signature needs to be verified. Next, verify the certificate chain and then use the leaf certificate to verify the signature of the profile signature block to prove that it is not tampered with. +The profile signature block is a signed data block in PKCS7 format. The profile content is stored in **contentinfo** of the PKCS7 signature block. The signature verification process includes PKCS7 signature verification, hash comparison, certificate chain verification, and profile certificate validity verification. **Profile content verification** -Obtain the profile and check the validity of its content. If the HAP is a debugging application, check whether the UDID of the current device is contained in the UDID list in the profile. If yes, the verification is successful. Then compare the certificate in the profile with the leaf certificate used for HAP verification \(this is not required for a released or OpenHarmony self-signed application\). If they are the same, the entire signature verification process is complete. +The signature verification module checks the validity of the profile content. If the profile is of the debugging type, the module checks whether the UDID of the current device is contained in the UDID list in the profile. If yes, the module compares the certificate in the profile with the certificate used for HAP signature verification. If they are the same, the entire verification process is complete. ## Available APIs The following table lists the innerkits APIs provided by the signature verification component. These APIs are available only for system applications. -**Table 1** APIs provided by the signature verification component +**Table 1** APIs provided by the signature verification component for mini systems -

Function

@@ -31,7 +31,7 @@ The following table lists the APIs provided by IPC authentication \(intended for

int IsCommunicationAllowed(AuthParams params)

Checks whether a process has the permission to access an API of another service.

+

Checks whether a process has the permission to access an API of another process.

Function

+ @@ -81,192 +69,26 @@ The following table lists the innerkits APIs provided by the signature verificat

API

Description

-## Development Procedure \(Scenario 1\) - -### Signature Verification - -To verify applications released in the application market, debugging applications signed with debugging certificates of the application market, and OpenHarmony self-signed applications, perform the following steps: - -1. Construct the VerifyResult structure. - - ``` - VerifyResult verifyResult = {0}; - ``` - -2. Call the APPVERI\_AppVerify function by specifying the file path and VerifyResult to verify the application signature. - - ``` - int32_t ret = APPVERI_AppVerify(hapFilepath.c_str(), &verifyResult); - ``` - -3. Check the returned result. If the verification is successful, obtain and process the data in VerifyResult. - - ``` - signatureInfo.appId = verifyResult.profile.appid; - signatureInfo.provisionBundleName = verifyResult.profile.bundleInfo.bundleName; - ``` - -4. Call the APPVERI\_FreeVerifyRst function to release memory in VerifyResult. - - ``` - APPVERI_FreeVerifyRst(&verifyResult); - ``` - - -### OpenHarmony Self-signed Application Generation - -The procedure is as follows: - -1. Prepare required materials. - - Prepare the signature tool, system application HAP, system application profile \(\*.p7b\), signing certificate \(\*.cer\), and signing public/private key pair \(\*.jks\). - -2. Place all the materials in the same directory and start the shell. -3. Run the following command in the shell to sign the application: - - ``` - java -jar hapsigntoolv2.jar sign -mode localjks -privatekey "OpenHarmony Software Signature" -inputFile camera.hap -outputFile signed_camera.hap -signAlg SHA256withECDSA -keystore OpenHarmony.jks -keystorepasswd 123456 -keyaliaspasswd 123456 -profile camera_release.p7b -certpath OpenHarmony.cer -profileSigned 1 - ``` - - Key fields: - - **-jar**: signature tool, which is **[hapsigntool](https://repo.huaweicloud.com/harmonyos/develop_tools/hapsigntoolv2.jar)** - - **-mode**: local signature flag, which is fixed at **localjks** - - **-privatekey**: alias of the public/private key pair, which is **OpenHarmony Software Signature** - - **-inputFile**: application to be signed, which is generated through compilation - - **-outputFile**: signed application +**Table 2** APIs provided by the signature verification component for standard systems - **-signAlg**: signing algorithm, which is fixed at **SHA256withECDSA** - - **-keystore**: public/private key pair, which is [OpenHarmony.jks](https://gitee.com/openharmony/security_appverify/blob/master/interfaces/innerkits/appverify_lite/OpenHarmonyCer/OpenHarmony.jks) in the **OpenHarmonyCer** directory of the **security\_services\_app\_verify** repository. The default password is **123456**. You can use a tool \(such as keytool\) to change the password. - - **-keystorepasswd**: password of the public/private key pair, which is **123456** by default - - **-keyaliaspasswd**: password of the public/private key pair alias, which is **123456** by default - - **-profile**: application profile, which is stored in the code directory - - **-certpath**: signing certificate, which is [OpenHarmony.cer](https://gitee.com/openharmony/security_appverify/blob/master/interfaces/innerkits/appverify_lite/OpenHarmonyCer/OpenHarmony.cer) in the **OpenHarmonyCer** directory of the **security\_services\_app\_verify** repository. - - **-profileSigned**: whether the signature block contains the profile. The value is fixed at **1**, indicating that the signature block contains the profile. - - -### Development Examples - -The following example describes how the application management framework component verifies the signature of an application during its installation. - -``` -uint8_t HapSignVerify::VerifySignature(const std::string &hapFilepath, SignatureInfo &signatureInfo) -{ - bool mode = ManagerService::GetInstance().IsDebugMode(); - HILOG_INFO(HILOG_MODULE_APP, "current mode is %d!", mode); - // Construct the VerifyResult structure. - VerifyResult verifyResult = {0}; - // Verify the signature by specifying the file path. - int32_t ret = APPVERI_AppVerify(hapFilepath.c_str(), &verifyResult); - uint8_t errorCode = SwitchErrorCode(ret); - if (errorCode != ERR_OK) { - return errorCode; - } - // Obtain appid from the VerifyResult structure. - signatureInfo.appId = verifyResult.profile.appid; - // Obtain the application name written in the profile from the VerifyResult structure. - signatureInfo.provisionBundleName = verifyResult.profile.bundleInfo.bundleName; - int32_t restricNum = verifyResult.profile.permission.restricNum; - for (int32_t i = 0; i < restricNum; i++) { - signatureInfo.restrictedPermissions.emplace_back((verifyResult.profile.permission.restricPermission)[i]); - } - // Release memory in VerifyResult. - APPVERI_FreeVerifyRst(&verifyResult); - return ERR_OK; -} -``` - -## Development Procedure \(Scenario 2\) - -### Signature Verification - -To verify applications signed with certificates that are based on debugging root keys, perform the following steps: - -1. Call the APPVERI\_SetDebugMode\(true\) function to enable the debugging mode. - - ``` - ManagerService::SetDebugMode(true); - ... - uint8_t ManagerService::SetDebugMode(bool enable) - { - int32_t ret = APPVERI_SetDebugMode(enable); - if (ret < 0) { - HILOG_ERROR(HILOG_MODULE_APP, "set signature debug mode failed"); - return ERR_APPEXECFWK_SET_DEBUG_MODE_ERROR; - } - isDebugMode_ = enable; - HILOG_INFO(HILOG_MODULE_APP, "current sign debug mode is %d", isDebugMode_); - return ERR_OK; - } - ``` - -2. Construct the **VerifyResult** structure, verify the application signature, and release memory in **VerifyResult**. -3. Call the APPVERI\_SetDebugMode\(false\) function to disable the debugging mode. - - ``` - ManagerService::SetDebugMode(false); - ``` - - -### Development Examples - -The following is the example code \(supplemented based on the example code for scenario 1\): + + + + + + + + + +

API

+

Description

+

nt HapVerify(const std::string& filePath, HapVerifyResult& hapVerifyResult)

+

Verifies application integrity and identifies the application source.

+
-``` -uint8_t ManagerService::SetDebugMode(bool enable) -{ - int32_t ret = APPVERI_SetDebugMode(enable); - if (ret < 0) { - HILOG_ERROR(HILOG_MODULE_APP, "set signature debug mode failed"); - return ERR_APPEXECFWK_SET_DEBUG_MODE_ERROR; - } - isDebugMode_ = enable; - HILOG_INFO(HILOG_MODULE_APP, "current sign debug mode is %d", isDebugMode_); - return ERR_OK; -} -uint8_t HapSignVerify::VerifySignature(const std::string &hapFilepath, SignatureInfo &signatureInfo) -{ - // Enable debugging mode. - ManagerService::SetDebugMode(true); - bool mode = ManagerService::GetInstance().IsDebugMode(); - HILOG_INFO(HILOG_MODULE_APP, "current mode is %d!", mode); - // Construct the VerifyResult structure. - VerifyResult verifyResult = {0}; - // Verify the signature by specifying the file path. - int32_t ret = APPVERI_AppVerify(hapFilepath.c_str(), &verifyResult); - uint8_t errorCode = SwitchErrorCode(ret); - if (errorCode != ERR_OK) { - return errorCode; - } - // Obtain appid from the VerifyResult structure. - signatureInfo.appId = verifyResult.profile.appid; - // Obtain the application name written in the profile from the VerifyResult structure. - signatureInfo.provisionBundleName = verifyResult.profile.bundleInfo.bundleName; - int32_t restricNum = verifyResult.profile.permission.restricNum; - for (int32_t i = 0; i < restricNum; i++) { - signatureInfo.restrictedPermissions.emplace_back((verifyResult.profile.permission.restricPermission)[i]); - } - // Release memory in VerifyResult. - APPVERI_FreeVerifyRst(&verifyResult); - // Disable debugging mode. - ManagerService::SetDebugMode(false); - return ERR_OK; -} -``` +## How to Develop -## Debugging and Verification +### OpenHarmony Self-signed Application -1. Choose an application that can be properly installed on OpenHarmony. -2. Develop the application based on the development guidelines. -3. Use a self-developed program to verify the signature of the developed application. If the verification is successful and **appid** can be obtained, the development is successful. +To develop an OpenHarmony self-signed application, follow instructions provided in the guide of [_Configuring the OpenHarmony App Signature_](https://gitee.com/openharmony/docs/blob/master/en/application-dev/quick-start/configuring-openharmony-app-signature.md) : diff --git a/zh-cn/device-dev/driver/Readme-CN.md b/zh-cn/device-dev/driver/Readme-CN.md index 17116f4e45cb37b89953e10d828a63f229c8c7a1..9ffeaad33f07ca81142fd8b18f3e7bc4fa100c76 100755 --- a/zh-cn/device-dev/driver/Readme-CN.md +++ b/zh-cn/device-dev/driver/Readme-CN.md @@ -33,4 +33,5 @@ - [LCD](driver-peripherals-lcd-des.md) - [TOUCHSCREEN](driver-peripherals-touch-des.md) - [SENSOR](driver-peripherals-sensor-des.md) - - [WLAN](driver-peripherals-external-des.md) \ No newline at end of file + - [WLAN](driver-peripherals-external-des.md) + - [USB](driver-peripherals-usb-des.md) \ No newline at end of file diff --git a/zh-cn/device-dev/driver/driver-peripherals-usb-des.md b/zh-cn/device-dev/driver/driver-peripherals-usb-des.md new file mode 100644 index 0000000000000000000000000000000000000000..cb0f0ef8a5a0c714ea93ae7a161bc4fe4151dc7c --- /dev/null +++ b/zh-cn/device-dev/driver/driver-peripherals-usb-des.md @@ -0,0 +1,1551 @@ +# USB + +- [概述](#section127mcpsimp) + - [接口说明](#section141mcpsimp) + +- [开发指导](#section581mcpsimp) + - [Host DDK API驱动开发步骤](#section584mcpsimp) + - [Host RAW API驱动开发步骤](#section594mcpsimp) + - [Device DDK API驱动开发步骤](#section600mcpsimp) + +- [开发实例](#section607mcpsimp) + - [Host DDK API驱动开发](#section609mcpsimp) + - [Host RAW API驱动开发](#section612mcpsimp) + - [Device DDK API驱动开发](#section615mcpsimp) + + +## 概述 + +USB Host部分,主要包括协议封装、设备管理、驱动安装与卸载等。 + +USB Device部分,支持USB功能设备的开发,提供USB设备相关功能,主要包括设备管理、配置管理、IO管理,实现USB功能设备创建、配置、数据通信等。 + +USB Host驱动模型如下图1所示: + +**图 1** USB Host驱动模型图 +![](figures/USB-Host驱动模型图.png "USB-Host驱动模型图") + +**图 2** USB Device驱动模型图 +![](figures/USB-Device驱动模型图.png "USB-Device驱动模型图") + +USB驱动模型对外开放的API接口能力如下: + +- Usb Host DDK提供给用户态可直接调用的驱动能力接口,按照功能分类三大类:DDK初始化类、对interface对象操作类、对request对象操作类,可以提供DDK初始化、interface绑定和释放,打开和关闭操作,request的申请和释放,同步和异步传输等。 +- Usb Deivce DDK提供设备管理、IO管理、配置管理,主要功能有:创建和删除设备、获取和打开接口、同步和异步传输等。 + +### 接口说明 + +USB驱动模型Host侧开放的API接口功能,参考[图1](#fig1649563542917)。 + +**表 1** USB驱动模型Host侧开放的API接口功能介绍 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

头文件

+

接口名称

+

功能描述

+

usb_ddk_interface.h

+

int32_t UsbInitHostSdk(struct UsbSession **session);

+

USB主机端驱动开发工具包初始化

+

int32_t UsbExitHostSdk(const struct UsbSession *session);

+

USB主机端驱动开发工具包退出

+

const struct UsbInterface *UsbClaimInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex);

+

获取USB接口对象

+

int UsbReleaseInterface(const struct UsbInterface *interfaceObj);

+

释放USB接口对象

+

int UsbAddOrRemoveInterface(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr, uint8_t interfaceIndex, UsbInterfaceStatus status);

+

增加移除接口

+

UsbInterfaceHandle *UsbOpenInterface(const struct UsbInterface *interfaceObj);

+

打开USB对象接口

+

int32_t UsbCloseInterface(const UsbInterfaceHandle *interfaceHandle);

+

关闭USB接口对象

+

int32_t UsbSelectInterfaceSetting(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, struct UsbInterface **interfaceObj);

+

设置可选配置

+

int32_t UsbGetPipeInfo(const UsbInterfaceHandle *interfaceHandle, uint8_t settingIndex, uint8_t pipeId, struct UsbPipeInfo *pipeInfo);

+

获取指定可选设置的管道信息

+

int32_t UsbClearInterfaceHalt(const UsbInterfaceHandle *interfaceHandle, uint8_t pipeAddress);

+

清除指定索引的管道状态

+

struct UsbRequest *UsbAllocRequest(const UsbInterfaceHandle *interfaceHandle, int isoPackets, int length);

+

分配请求对象

+

int UsbFreeRequest(const struct UsbRequest *request);

+

释放请求对象

+

int UsbSubmitRequestAsync(const struct UsbRequest *request);

+

发送异步请求

+

int32_t UsbFillRequest(const struct UsbRequest *request, const UsbInterfaceHandle *interfaceHandle, const struct UsbRequestParams *params);

+

填充请求

+

sint UsbCancelRequest(const struct UsbRequest *request);

+

取消异步请求

+

int UsbSubmitRequestSync(const struct UsbRequest *request);

+

发送同步请求

+

usb_raw_api.h

+

int UsbRawInit(struct UsbSession **session);

+

USB驱动开发工具包专家模式初始化

+

int UsbRawExit(const struct UsbSession *session);

+

USB驱动开发工具包专家模式退出

+

UsbRawHandle *UsbRawOpenDevice(const struct UsbSession *session, uint8_t busNum, uint8_t usbAddr);

+

打开USB设备对象

+

int UsbRawCloseDevice(const UsbRawHandle *devHandle);

+

关闭USB设备对象

+

int UsbRawSendControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbControlRequestData *requestData);

+

执行同步控制传输

+

int UsbRawSendBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);

+

执行同步批量传输

+

int UsbRawSendInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRequestData *requestData);

+

执行同步中断传输

+

int UsbRawGetConfigDescriptor(const UsbRawDevice *rawDev, uint8_t configIndex, struct UsbRawConfigDescriptor **config);

+

获取给定设备指定ID的设备配置描述符

+

void UsbRawFreeConfigDescriptor(const struct UsbRawConfigDescriptor *config);

+

释放配置描述符内存空间

+

int UsbRawGetConfiguration(const UsbRawHandle *devHandle, int *config);

+

获取当前激活配置

+

int UsbRawSetConfiguration(const UsbRawHandle *devHandle, int config);

+

设置当前激活配置

+

int UsbRawGetDescriptor(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawDescriptorParam *param, const unsigned char *data);

+

获取描述符信息

+

UsbRawDevice *UsbRawGetDevice(const UsbRawHandle *devHandle);

+

由设备句柄获取设备指针

+

int UsbRawGetDeviceDescriptor(const UsbRawDevice *rawDev, struct UsbDeviceDescriptor *desc);

+

获取给定设备的USB设备描述符

+

int UsbRawClaimInterface(const UsbRawHandle *devHandle, int interfaceNumber);

+

声明给定设备句柄上的接口

+

int UsbRawReleaseInterface(const UsbRawHandle *devHandle, int interfaceNumber);

+

释放之前声明的接口

+

int UsbRawResetDevice(const UsbRawHandle *devHandle);

+

复位设备

+

struct UsbRawRequest *UsbRawAllocRequest(const UsbRawHandle *devHandle, int isoPackets, int length);

+

分配一个带有指定数量的同步包描述符的传输请求

+

int UsbRawFreeRequest(const struct UsbRawRequest *request);

+

释放之前分配的传输请求

+

int UsbRawFillBulkRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

+

填充批量传输请求所需信息

+

int UsbRawFillControlSetup(const unsigned char *setup, const struct UsbControlRequestData *requestData);

+

填充控制传输设置包所需信息

+

int UsbRawFillControlRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

+

填充控制传输请求所需信息

+

int UsbRawFillInterruptRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

+

填充中断传输请求所需信息

+

int UsbRawFillIsoRequest(const struct UsbRawRequest *request, const UsbRawHandle *devHandle, const struct UsbRawFillRequestData *fillData);

+

填充同步传输(Isochronous Transfers)请求所需信息

+

int UsbRawSubmitRequest(const struct UsbRawRequest *request);

+

提交一个传输请求

+

int UsbRawCancelRequest(const struct UsbRawRequest *request);

+

取消一个传输请求

+

int UsbRawHandleRequests(const UsbRawHandle *devHandle);

+

传输请求事件完成处理

+
+ +USB驱动模型Device侧开放的API接口功能,参考[图2](#fig8847615103013)。 + +**表 2** USB驱动模型Device侧开放的API接口功能介绍 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

头文件

+

头文件

+

功能描述

+

usbfn_device.h

+

const struct UsbFnDevice *UsbFnCreateDevice(const char *udcName, const struct UsbFnDescriptorData *descriptor);

+

创建Usb设备

+

int UsbFnRemoveDevice(struct UsbFnDevice *fnDevice);

+

删除Usb设备

+

const struct UsbFnDevice *UsbFnGetDevice(const char *udcName);

+

获取Usb设备

+

usbfn_interface.h

+

int UsbFnStartRecvInterfaceEvent(struct UsbFnInterface *interface, uint32_t eventMask, UsbFnEventCallback callback, void *context);

+

开始接受Event事件

+

int UsbFnStopRecvInterfaceEvent(struct UsbFnInterface *interface);

+

停止接受Event事件

+

UsbFnInterfaceHandle UsbFnOpenInterface(struct UsbFnInterface *interface);

+

打开一个接口

+

int UsbFnCloseInterface(UsbFnInterfaceHandle handle);

+

关闭一个接口

+

int UsbFnGetInterfacePipeInfo(struct UsbFnInterface *interface, uint8_t pipeId, struct UsbFnPipeInfo *info);

+

获取管道信息

+

int UsbFnSetInterfaceProp(const struct UsbFnInterface *interface, const char *name, const char *value);

+

设置自定义属性

+

usbfn_request.h

+

struct UsbFnRequest *UsbFnAllocCtrlRequest(UsbFnInterfaceHandle handle, uint32_t len);

+

申请一个控制请求

+

struct UsbFnRequest *UsbFnAllocRequest(UsbFnInterfaceHandle handle, uint8_t pipe, uint32_t len);

+

申请一个数据请求

+

int UsbFnFreeRequest(struct UsbFnRequest *req);

+

释放一个请求

+

int UsbFnSubmitRequestAsync(struct UsbFnRequest *req);

+

发送异步请求

+

int UsbFnSubmitRequestSync(struct UsbFnRequest *req, uint32_t timeout);

+

发送同步请求

+

int UsbFnCancelRequest(struct UsbFnRequest *req);

+

取消请求

+
+ +## 开发指导 + +USB驱动是基于HDF框架、PLATFORM和OSAL基础接口进行开发,不区分操作系统和芯片平台,为不同USB器件提供统一的驱动模型。本篇开发指导以串口为例,分别介绍USB Host和USB Device驱动开发。 + +### 开发步骤 + +### Host DDK API驱动开发步骤 + +1. 驱动匹配表配置。 +2. 初始化Host DDK。 +3. 待步骤2初始化完后获取UsbInterface接口对象。 +4. 打开步骤3获取到的UsbInterface接口对象,获取对应接口的UsbInterfaceHandle对象。 +5. 根据步骤4获取到的UsbInterfaceHandle对象,获取指定索引为pinpeIndex的pipeInfo信息。 +6. 为步骤4获取到的UsbInterfaceHandle预先分配待发送的IO Request对象。 +7. 根据输入参数params填充步骤6预先分配的IO Request。 +8. 提交IO Request对象,可以选择同步或异步两种模式。 + +### Host RAW API驱动开发步骤 + +1. 驱动匹配表配置。 +2. 初始化Host RAW,并打开USB设备,然后获取描述符,通过描述符获取接口、端点信息。 +3. 分配Request,并根据传输类型使用如下接口对Request进行填充。 +4. 提交IO Request对象,可以选择同步或异步两种模式。 + +### Device DDK API驱动开发步骤 + +1. 构造描述符。 +2. 创建设备,使用步骤1构造的描述符实例化一个USB设备。 +3. 根据创建的设备获取接口(UsbFnDeviceGetInterface),获取Pipe信息(UsbFnInterfaceGetPipeInfo),打开接口获取Handle(UsbFnInterfaceOpen),根据Handle和Pipe号获取Request(UsbFnRequestAlloc)。 +4. 接收Event事件(UsbFnInterfaceStartRecvEvent)如Enable、Setup等事件,回调函数(UsbFnEventCallback)中对Event事件做出响应。 +5. 收发数据,可以选择同步异步发送模式。 + +## 开发实例 + +本实例提供USB串口驱动开发示例,并简要对具体关键点进行开发说明。 + +### Host DDK API驱动开发 + +``` +root { + module = "usb_pnp_device"; + usb_pnp_config { + match_attr = "usb_pnp_match"; + usb_pnp_device_id = "UsbPnpDeviceId"; + UsbPnpDeviceId { + idTableList = [ + "host_acm_table" + ]; + host_acm_table { + //驱动模块名,该字段的值必须和驱动入口结构的moduleName一致 + moduleName = "usbhost_acm"; + //驱动对外发布服务的名称,必须唯一 + serviceName = "usbhost_acm_pnp_service"; + //驱动私有数据匹配关键字 + deviceMatchAttr = "usbhost_acm_pnp_matchAttr"; + //从该字段开始(包含该字段)之后数据长度,以byte为单位 + length = 21; + //USB驱动匹配规则vendorId+productId+interfaceSubClass+interfaceProtocol+interfaceNumber + matchFlag = 0x0303; + //厂商编号 + vendorId = 0x12D1; + //产品编号 + productId = 0x5000; + //设备出厂编号,低16位 + bcdDeviceLow = 0x0000; + //设备出厂编号,高16位 + bcdDeviceHigh = 0x0000; + //USB分配的设备类代码 + deviceClass = 0; + //USB分配的子类代码 + deviceSubClass = 0; + //USB分配的设备协议代码 + deviceProtocol = 0; + //接口类型,根据实际需要可填写多个 + interfaceClass = [0]; + //接口子类型,根据实际需要可填写多个 + interfaceSubClass = [2, 0]; + //接口所遵循的协议,根据实际需要可填写多个 + interfaceProtocol = [1, 2]; + //接口的编号,根据实际需要可填写多个 + interfaceNumber = [2, 3]; + } + } + } +} + +#include "usb_serial.h" +#include "hdf_base.h" +#include "hdf_log.h" +#include "osal_mem.h" +#include "osal_time.h" +#include "securec.h" +#include "usb_ddk_interface.h" +#include "hdf_usb_pnp_manage.h" + +#define HDF_LOG_TAG USB_HOST_ACM +#define STR_LEN 512 + +static struct UsbRequest *g_syncRequest = NULL; +static struct UsbRequest *g_ctrlCmdRequest = NULL; +static bool g_acmReleaseFlag = false; +static uint8_t *g_acmReadBuffer = NULL; +... +static int SerialCtrlMsg(struct AcmDevice *acm, uint8_t request, + uint16_t value, void *buf, uint16_t len) +{ + int ret; + uint16_t index = acm->intPipe->interfaceId; + struct UsbControlParams controlParams = {}; + struct UsbRequestParams parmas = {}; + if (acm == NULL || buf == NULL) { + HDF_LOGE("%{public}s:invalid param", __func__); + return HDF_ERR_IO; + } + if (acm->ctrlReq == NULL) { + acm->ctrlReq = UsbAllocRequest(acm->ctrDevHandle, 0, len); + if (acm->ctrlReq == NULL) { + HDF_LOGE("%{public}s: UsbAllocRequest faild", __func__); + return HDF_ERR_IO; + } + } + + controlParams.request = request; + controlParams.target = USB_REQUEST_TARGET_INTERFACE; + controlParams.reqType = USB_REQUEST_TYPE_CLASS; + controlParams.directon = USB_REQUEST_DIR_TO_DEVICE; + controlParams.value = value; + controlParams.index = index; + controlParams.data = buf; + controlParams.size = len; + + parmas.interfaceId = USB_CTRL_INTERFACE_ID; + parmas.pipeAddress = acm->ctrPipe->pipeAddress; + parmas.pipeId = acm->ctrPipe->pipeId; + parmas.requestType = USB_REQUEST_PARAMS_CTRL_TYPE; + parmas.timeout = USB_CTRL_SET_TIMEOUT; + parmas.ctrlReq = UsbControlSetUp(&controlParams); + ret = UsbFillRequest(acm->ctrlReq, acm->ctrDevHandle, &parmas); + if (HDF_SUCCESS != ret) { + HDF_LOGE("%{public}s: faile, ret=%{public}d ", __func__, ret); + return ret; + } + ret = UsbSubmitRequestSync(acm->ctrlReq); //发送同步IO Request + if (HDF_SUCCESS != ret) { + HDF_LOGE("UsbSubmitRequestSync faile, ret=%{public}d ", ret); + return ret; + } + if (!acm->ctrlReq->compInfo.status) { + HDF_LOGE("%{public}s status=%{public}d ", __func__, acm->ctrlReq->compInfo.status); + } + return HDF_SUCCESS; +} +... +static struct UsbInterface *GetUsbInterfaceById(const struct AcmDevice *acm, + uint8_t interfaceIndex) +{ + struct UsbInterface *tmpIf = NULL; + tmpIf = (struct UsbInterface *)UsbClaimInterface(acm->session, acm->busNum, + acm->devAddr, interfaceIndex); //获取UsbInterface接口对象 + return tmpIf; +} +... +static struct UsbPipeInfo *EnumePipe(const struct AcmDevice *acm, + uint8_t interfaceIndex, UsbPipeType pipeType, UsbPipeDirection pipeDirection) +{ + uint8_t i; + int ret; + struct UsbInterfaceInfo *info = NULL; + UsbInterfaceHandle *interfaceHandle = NULL; + if (pipeType == USB_PIPE_TYPE_CONTROL) + { + info = &acm->ctrIface->info; + interfaceHandle = acm->ctrDevHandle; + } + else + { + info = &acm->iface[interfaceIndex]->info; + interfaceHandle = InterfaceIdToHandle(acm, info->interfaceIndex); + } + + for (i = 0; i <= info->pipeNum; i++) { + struct UsbPipeInfo p; + ret = UsbGetPipeInfo(interfaceHandle, info->curAltSetting, i, &p);//获取指定索引为i的pipeInfo信息 + if (ret < 0) { + continue; + } + if ((p.pipeDirection == pipeDirection) && (p.pipeType == pipeType)) { + struct UsbPipeInfo *pi = OsalMemCalloc(sizeof(*pi)); + if (pi == NULL) { + HDF_LOGE("%{public}s: Alloc pipe failed", __func__); + return NULL; + } + p.interfaceId = info->interfaceIndex; + *pi = p; + return pi; + } + } + return NULL; +} + +static struct UsbPipeInfo *GetPipe(const struct AcmDevice *acm, + UsbPipeType pipeType, UsbPipeDirection pipeDirection) +{ + uint8_t i; + if (acm == NULL) { + HDF_LOGE("%{public}s: invalid parmas", __func__); + return NULL; + } + for (i = 0; i < acm->interfaceCnt; i++) { + struct UsbPipeInfo *p = NULL; + if (!acm->iface[i]) { + continue; + } + p = EnumePipe(acm, i, pipeType, pipeDirection); + if (p == NULL) { + continue; + } + return p; + } + return NULL; +} + +/* HdfDriverEntry implementations */ +static int32_t UsbSerialDriverBind(struct HdfDeviceObject *device) +{ + struct UsbPnpNotifyServiceInfo *info = NULL; + errno_t err; + struct AcmDevice *acm = NULL; + if (device == NULL) { + HDF_LOGE("%s: device is null", __func__); + return HDF_ERR_INVALID_OBJECT; + } + acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*acm)); + if (acm == NULL) { + HDF_LOGE("%s: Alloc usb serial device failed", __func__); + return HDF_FAILURE; + } + if (OsalMutexInit(&acm->lock) != HDF_SUCCESS) { + HDF_LOGE("%s:%d OsalMutexInit fail", __func__, __LINE__); + goto error; + } + info = (struct UsbPnpNotifyServiceInfo *)device->priv; + if (info != NULL) { + HDF_LOGD("%s:%d busNum=%d,devAddr=%d,interfaceLength=%d", + __func__, __LINE__, info->busNum, info->devNum, info->interfaceLength); + acm->busNum = info->busNum; + acm->devAddr = info->devNum; + acm->interfaceCnt = info->interfaceLength; + err = memcpy_s((void *)(acm->interfaceIndex), USB_MAX_INTERFACES, + (const void*)info->interfaceNumber, info->interfaceLength); + if (err != EOK) { + HDF_LOGE("%s:%d memcpy_s faile err=%d", + __func__, __LINE__, err); + goto lock_error; + } + } else { + HDF_LOGE("%s:%d info is NULL!", __func__, __LINE__); + goto lock_error; + } + acm->device = device; + device->service = &(acm->service); + acm->device->service->Dispatch = UsbSerialDeviceDispatch; + HDF_LOGD("UsbSerialDriverBind=========================OK"); + return HDF_SUCCESS; + +lock_error: + if (OsalMutexDestroy(&acm->lock)) { + HDF_LOGE("%s:%d OsalMutexDestroy fail", __func__, __LINE__); + } +error: + OsalMemFree(acm); + acm = NULL; + return HDF_FAILURE; +} +... +static int AcmAllocReadRequests(struct AcmDevice *acm) +{ + int ret; + struct UsbRequestParams readParmas = {}; + for (int i = 0; i < ACM_NR; i++) { + acm->readReq[i] = UsbAllocRequest(InterfaceIdToHandle(acm, acm->dataInPipe->interfaceId), 0, acm->readSize); //分配待发送的readReq IO Request对象 + if (!acm->readReq[i]) { + HDF_LOGE("readReq request faildn"); + goto error; + } + readParmas.userData = (void *)acm; + readParmas.pipeAddress = acm->dataInPipe->pipeAddress; + readParmas.pipeId = acm->dataInPipe->pipeId; + readParmas.interfaceId = acm->dataInPipe->interfaceId; + readParmas.callback = AcmReadBulk; + readParmas.requestType = USB_REQUEST_PARAMS_DATA_TYPE; + readParmas.timeout = USB_CTRL_SET_TIMEOUT; + readParmas.dataReq.numIsoPackets = 0; + readParmas.dataReq.directon = (acm->dataInPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & 0x1; + readParmas.dataReq.length = acm->readSize; + ret = UsbFillRequest(acm->readReq[i], InterfaceIdToHandle(acm, acm->dataInPipe->interfaceId), &readParmas); //填充待发送的readReq对象 + if (HDF_SUCCESS != ret) { + HDF_LOGE("%{public}s: UsbFillRequest faile, ret=%{public}d n", __func__, ret); + goto error; + } + } + return HDF_SUCCESS; + +error: + AcmFreeReadRequests(acm); + return HDF_ERR_MALLOC_FAIL; +} + +static int AcmAllocNotifyRequest(struct AcmDevice *acm) +{ + int ret; + struct UsbRequestParams intParmas = {}; + acm->notifyReq = UsbAllocRequest(InterfaceIdToHandle(acm, acm->intPipe->interfaceId), 0, acm->intSize); //分配待发送的中断IO Request对象 + if (!acm->notifyReq) { + HDF_LOGE("notifyReq request failn"); + return HDF_ERR_MALLOC_FAIL; + } + intParmas.userData = (void *)acm; + intParmas.pipeAddress = acm->intPipe->pipeAddress; + intParmas.pipeId = acm->intPipe->pipeId; + intParmas.interfaceId = acm->intPipe->interfaceId; + intParmas.callback = AcmCtrlIrq; + intParmas.requestType = USB_REQUEST_PARAMS_DATA_TYPE; + intParmas.timeout = USB_CTRL_SET_TIMEOUT; + intParmas.dataReq.numIsoPackets = 0; + intParmas.dataReq.directon = (acm->intPipe->pipeDirection >> USB_PIPE_DIR_OFFSET) & DIRECTION_MASK; + intParmas.dataReq.length = acm->intSize; + ret = UsbFillRequest(acm->notifyReq, InterfaceIdToHandle(acm, acm->intPipe->interfaceId), &intParmas); //填充预先分配的中断IO Request + if (HDF_SUCCESS != ret) { + HDF_LOGE("%{public}s: UsbFillRequest faile, ret=%{public}d n", __func__, ret); + goto error; + } + return HDF_SUCCESS; + +error: + AcmFreeNotifyReqeust(acm); + return ret; +} + +static void AcmReleaseInterfaces(struct AcmDevice *acm) +{ + for (int i = 0; i < acm->interfaceCnt; i++) { + if (acm->iface[i]) { + UsbReleaseInterface(acm->iface[i]); + acm->iface[i] = NULL; + } + } + if (acm->ctrIface) { + UsbReleaseInterface(acm->ctrIface); + acm->ctrIface = NULL; + } +} + +static int32_t AcmClaimInterfaces(struct AcmDevice *acm) +{ + for (int i = 0; i < acm->interfaceCnt; i++) { + acm->iface[i] = GetUsbInterfaceById((const struct AcmDevice *)acm, acm->interfaceIndex[i]); //获取UsbInterface接口对象 + if (acm->iface[i] == NULL) { + HDF_LOGE("%{public}s: interface%{public}d is null", __func__, acm->interfaceIndex[i]); + goto error; + } + } + + acm->ctrIface = GetUsbInterfaceById((const struct AcmDevice *)acm, USB_CTRL_INTERFACE_ID); //获取控制接口对应的UsbInterface接口对象 + if (acm->ctrIface == NULL) { + HDF_LOGE("%{public}s: GetUsbInterfaceById null", __func__); + goto error; + } + + return HDF_SUCCESS; + + error: + AcmReleaseInterfaces(acm); + return HDF_FAILURE; +} + +static void AcmCloseInterfaces(struct AcmDevice *acm) +{ + for (int i = 0; i < acm->interfaceCnt; i++) { + if (acm->devHandle[i]) { + UsbCloseInterface(acm->devHandle[i]); + acm->devHandle[i] = NULL; + } + } + if (acm->ctrDevHandle) { + UsbCloseInterface(acm->ctrDevHandle); + acm->ctrDevHandle = NULL; + } +} + +static int32_t AcmOpenInterfaces(struct AcmDevice *acm) +{ + for (int i = 0; i < acm->interfaceCnt; i++) { + if (acm->iface[i]) { + acm->devHandle[i] = UsbOpenInterface(acm->iface[i]); //打开获取到的UsbInterface接口对象 + if (acm->devHandle[i] == NULL) { + HDF_LOGE("%{public}s: UsbOpenInterface null", __func__); + goto error; + } + } + } + acm->ctrDevHandle = UsbOpenInterface(acm->ctrIface); + if (acm->ctrDevHandle == NULL) { + HDF_LOGE("%{public}s: ctrDevHandle UsbOpenInterface null", __func__); + goto error; + } + + return HDF_SUCCESS; + +error: + AcmCloseInterfaces(acm); + return HDF_FAILURE; +} + +static int32_t AcmGetPipes(struct AcmDevice *acm) +{ + acm->dataInPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_IN);//获取dataInPipe的pipeInfo信息 + if (acm->dataInPipe == NULL) { + HDF_LOGE("dataInPipe is NULL"); + goto error; + } + + acm->dataOutPipe = GetPipe(acm, USB_PIPE_TYPE_BULK, USB_PIPE_DIRECTION_OUT);//获取dataOutPipe的pipeInfo信息 + if (acm->dataOutPipe == NULL) { + HDF_LOGE("dataOutPipe is NULL"); + goto error; + } + + acm->ctrPipe = EnumePipe(acm, acm->ctrIface->info.interfaceIndex, USB_PIPE_TYPE_CONTROL, USB_PIPE_DIRECTION_OUT); //获取控制pipe的pipeInfo信息 + if (acm->ctrPipe == NULL) { + HDF_LOGE("ctrPipe is NULL"); + goto error; + } + + acm->intPipe = GetPipe(acm, USB_PIPE_TYPE_INTERRUPT, USB_PIPE_DIRECTION_IN);//获取中断pipe的pipeInfo信息 + if (acm->intPipe == NULL) { + HDF_LOGE("intPipe is NULL"); + goto error; + } + + acm->readSize = acm->dataInPipe->maxPacketSize; + acm->writeSize = acm->dataOutPipe->maxPacketSize; + acm->ctrlSize = acm->ctrPipe->maxPacketSize; + acm->intSize = acm->intPipe->maxPacketSize; + + return HDF_SUCCESS; + +error: + AcmFreePipes(acm); + return HDF_FAILURE; +} + +static void AcmFreeRequests(struct AcmDevice *acm) +{ + if (g_syncRequest != NULL) { + UsbFreeRequest(g_syncRequest); + g_syncRequest = NULL; + } + AcmFreeReadRequests(acm); + AcmFreeNotifyReqeust(acm); + AcmFreeWriteRequests(acm); + AcmWriteBufFree(acm); +} + +static int32_t AcmAllocRequests(struct AcmDevice *acm) +{ + int32_t ret; + + if (AcmWriteBufAlloc(acm) < 0) { + HDF_LOGE("%{public}s: AcmWriteBufAlloc failed", __func__); + return HDF_ERR_MALLOC_FAIL; + } + + for (int i = 0; i < ACM_NW; i++) { + struct AcmWb *snd = &(acm->wb[i]); + snd->request = UsbAllocRequest(InterfaceIdToHandle(acm, acm->dataOutPipe->interfaceId), 0, acm->writeSize); //分配待发送的IO Request对象 + snd->instance = acm; + if (snd->request == NULL) { + HDF_LOGE("%{public}s:%{public}d snd request fail", __func__, __LINE__); + goto error_alloc_write_req; + } + } + + ret = AcmAllocNotifyRequest(acm); //分配并填充中断IO Request对象 + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s:%{public}d AcmAllocNotifyRequest fail", __func__, __LINE__); + goto error_alloc_int_req; + } + + ret = AcmAllocReadRequests(acm); //分配并填充readReq IO Request对象 + if (ret) { + HDF_LOGE("%{public}s:%{public}d AcmAllocReadRequests fail", __func__, __LINE__); + goto error_alloc_read_req; + } + + return HDF_SUCCESS; + +error_alloc_read_req: + AcmFreeNotifyReqeust(acm); +error_alloc_int_req: + AcmFreeWriteRequests(acm); +error_alloc_write_req: + AcmWriteBufFree(acm); + return HDF_FAILURE; +} + +static int32_t AcmInit(struct AcmDevice *acm) +{ + int32_t ret; + struct UsbSession *session = NULL; + + if (acm->initFlag == true) { + HDF_LOGE("%{public}s:%{public}d: initFlag is true", __func__, __LINE__); + return HDF_SUCCESS; + } + + ret = UsbInitHostSdk(NULL); //初始化Host DDK + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: UsbInitHostSdk faild", __func__); + return HDF_ERR_IO; + } + acm->session = session; + + ret = AcmClaimInterfaces(acm); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: AcmClaimInterfaces faild", __func__); + goto error_claim_interfaces; + } + + ret = AcmOpenInterfaces(acm); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: AcmOpenInterfaces faild", __func__); + goto error_open_interfaces; + } + + ret = AcmGetPipes(acm); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: AcmGetPipes failed", __func__); + goto error_get_pipes; + } + + ret = AcmAllocRequests(acm); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: AcmAllocRequests failed", __func__); + goto error_alloc_reqs; + } + + acm->lineCoding.dwDTERate = CpuToLe32(DATARATE); + acm->lineCoding.bCharFormat = CHARFORMAT; + acm->lineCoding.bParityType = USB_CDC_NO_PARITY; + acm->lineCoding.bDataBits = USB_CDC_1_STOP_BITS; + acm->initFlag = true; + + HDF_LOGD("%{public}s:%{public}d========OK", __func__, __LINE__); + return HDF_SUCCESS; + +error_alloc_reqs: + AcmFreePipes(acm); +error_get_pipes: + AcmCloseInterfaces(acm); +error_open_interfaces: + AcmReleaseInterfaces(acm); +error_claim_interfaces: + UsbExitHostSdk(acm->session); + acm->session = NULL; + return ret; +} + +static void AcmRelease(struct AcmDevice *acm) +{ + if (acm->initFlag == false) { + HDF_LOGE("%{public}s:%{public}d: initFlag is false", __func__, __LINE__); + return; + } + + AcmFreeRequests(acm); + AcmFreePipes(acm); + AcmCloseInterfaces(acm); + AcmReleaseInterfaces(acm); + UsbExitHostSdk(acm->session); + acm->session = NULL; + + acm->initFlag = false; +} + +static int32_t UsbSerialDriverInit(struct HdfDeviceObject *device) +{ + int32_t ret; + struct AcmDevice *acm = NULL; + + if (device == NULL) { + HDF_LOGE("%{public}s: device is null", __func__); + return HDF_ERR_INVALID_OBJECT; + } + acm = (struct AcmDevice *)device->service; + OsalMutexInit(&acm->readLock); + OsalMutexInit(&acm->writeLock); + HDF_LOGD("%{public}s:%{public}d busNum=%{public}d,devAddr=%{public}d", + __func__, __LINE__, acm->busNum, acm->devAddr); + + ret = UsbSerialDeviceAlloc(acm); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: Serial Device alloc faild", __func__); + } + + acm->initFlag = false; + g_acmReleaseFlag = false; + + HDF_LOGD("%{public}s:%{public}d init ok!", __func__, __LINE__); + + return ret; +} + +static void UsbSerialDriverRelease(struct HdfDeviceObject *device) +{ + struct AcmDevice *acm = NULL; + + if (device == NULL) { + HDF_LOGE("%{public}s: device is NULL", __func__); + return; + } + acm = (struct AcmDevice *)device->service; + if (acm == NULL) { + HDF_LOGE("%{public}s: acm is null", __func__); + return; + } + + g_acmReleaseFlag = true; + + if (acm->initFlag == true) { + HDF_LOGE("%{public}s:%{public}d AcmRelease", __func__, __LINE__); + AcmRelease(acm); + } + UsbSeriaDevicelFree(acm); + OsalMutexDestroy(&acm->writeLock); + OsalMutexDestroy(&acm->readLock); + OsalMutexDestroy(&acm->lock); + OsalMemFree(acm); + acm = NULL; + HDF_LOGD("%{public}s:%{public}d exit", __func__, __LINE__); +} + +struct HdfDriverEntry g_usbSerialDriverEntry = { + .moduleVersion = 1, + .moduleName = "usbhost_acm", //驱动模块名称,必须与hcs文件中配置的名称一致 + .Bind = UsbSerialDriverBind, + .Init = UsbSerialDriverInit, + .Release = UsbSerialDriverRelease, +}; +HDF_INIT(g_usbSerialDriverEntry); +``` + +### Host RAW API驱动开发 + +``` +root { + module = "usb_pnp_device"; + usb_pnp_config { + match_attr = "usb_pnp_match"; + usb_pnp_device_id = "UsbPnpDeviceId"; + UsbPnpDeviceId { + idTableList = [ + "host_acm_rawapi_table" + ]; + host_acm_rawapi_table { //驱动配置匹配表信息 + //驱动模块名,该字段的值必须和驱动入口结构的moduleName一致 + moduleName = "usbhost_acm_rawapi"; + //驱动对外发布服务的名称,必须唯一 + serviceName = "usbhost_acm_rawapi_service"; + //驱动私有数据匹配关键字 + deviceMatchAttr = "usbhost_acm_rawapi_matchAttr"; + //从该字段开始(包含该字段)之后数据长度,以byte为单位 + length = 21; + //USB驱动匹配规则vendorId+productId+interfaceSubClass+interfaceProtocol+interfaceNumber + matchFlag = 0x0303; + //厂商编号 + vendorId = 0x12D1; + //产品编号 + productId = 0x5000; + //设备出厂编号,低16位 + bcdDeviceLow = 0x0000; + //设备出厂编号,高16位 + bcdDeviceHigh = 0x0000; + //USB分配的设备类代码 + deviceClass = 0; + //USB分配的子类代码 + deviceSubClass = 0; + //USB分配的设备协议代码 + deviceProtocol = 0; + //接口类型,根据实际需要可填写多个 + interfaceClass = [0]; + //接口子类型,根据实际需要可填写多个 + interfaceSubClass = [2, 0]; + //接口所遵循的协议,根据实际需要可填写多个 + interfaceProtocol = [1, 2]; + //接口的编号,根据实际需要可填写多个 + interfaceNumber = [2, 3]; + } + } + } +} + +#include "usb_serial_rawapi.h" +#include +#include "osal_mem.h" +#include "osal_time.h" +#include "securec.h" +#include "hdf_base.h" +#include "hdf_log.h" +#include "hdf_usb_pnp_manage.h" + +#define HDF_LOG_TAG USB_HOST_ACM_RAW_API +#define USB_CTRL_REQ_SIZE 64 +#define USB_IO_THREAD_STACK_SIZE 8192 +#define USB_RAW_IO_SLEEP_MS_TIME 100 +#define USB_RAW_IO_STOP_WAIT_MAX_TIME 3 + +static struct UsbRawRequest *g_syncRequest = NULL; +static UsbRawIoProcessStatusType g_stopIoStatus = USB_RAW_IO_PROCESS_RUNNING; +struct OsalMutex g_stopIoLock; +static bool g_rawAcmReleaseFlag = false; +...... + +static int UsbGetConfigDescriptor(UsbRawHandle *devHandle, struct UsbRawConfigDescriptor **config) +{ + UsbRawDevice *dev = NULL; + int activeConfig; + int ret; + + if (devHandle == NULL) { + HDF_LOGE("%{public}s:%{public}d devHandle is NULL", + __func__, __LINE__); + return HDF_ERR_INVALID_PARAM; + } + + ret = UsbRawGetConfiguration(devHandle, &activeConfig); + if (ret) { + HDF_LOGE("%{public}s:%{public}d UsbRawGetConfiguration failed, ret=%{public}d", + __func__, __LINE__, ret); + return HDF_FAILURE; + } + HDF_LOGE("%{public}s:%{public}d activeConfig=%{public}d", __func__, __LINE__, activeConfig); + dev = UsbRawGetDevice(devHandle); + if (dev == NULL) { + HDF_LOGE("%{public}s:%{public}d UsbRawGetDevice failed", + __func__, __LINE__); + return HDF_FAILURE; + } + + ret = UsbRawGetConfigDescriptor(dev, activeConfig, config); + if (ret) { + HDF_LOGE("UsbRawGetConfigDescriptor failed, ret=%{public}dn", ret); + return HDF_FAILURE; + } + + return HDF_SUCCESS; +} +... +static int UsbAllocWriteRequests(struct AcmDevice *acm) +{ + int i; + + for (i = 0; i < ACM_NW; i++) { + struct AcmWb *snd = &acm->wb[i]; + snd->request = UsbRawAllocRequest(acm->devHandle, 0, acm->dataOutEp->maxPacketSize); + snd->instance = acm; + if (snd->request == NULL) { + HDF_LOGE("%{public}s: UsbRawAllocRequest faild", __func__); + return HDF_ERR_MALLOC_FAIL; + } + } + + return HDF_SUCCESS; +} +... +/* HdfDriverEntry implementations */ +static int32_t UsbSerialDriverBind(struct HdfDeviceObject *device) +{ + struct AcmDevice *acm = NULL; + struct UsbPnpNotifyServiceInfo *info = NULL; + errno_t err; + + if (device == NULL) { + HDF_LOGE("%s: device is null", __func__); + return HDF_ERR_INVALID_OBJECT; + } + + acm = (struct AcmDevice *)OsalMemCalloc(sizeof(*acm)); + if (acm == NULL) { + HDF_LOGE("%s: Alloc usb serial device failed", __func__); + return HDF_FAILURE; + } + if (OsalMutexInit(&acm->lock) != HDF_SUCCESS) { + HDF_LOGE("%s:%d OsalMutexInit fail", __func__, __LINE__); + goto error; + } + + info = (struct UsbPnpNotifyServiceInfo *)device->priv; + if (info != NULL) { + acm->busNum = info->busNum; + acm->devAddr = info->devNum; + acm->interfaceCnt = info->interfaceLength; + err = memcpy_s((void *)(acm->interfaceIndex), USB_MAX_INTERFACES, + (const void*)info->interfaceNumber, info->interfaceLength); + if (err != EOK) { + HDF_LOGE("%s:%d memcpy_s faile err=%d", + __func__, __LINE__, err); + goto lock_error; + } + } else { + HDF_LOGE("%s:%d info is NULL!", __func__, __LINE__); + goto lock_error; + } + + device->service = &(acm->service); + device->service->Dispatch = UsbSerialDeviceDispatch; + acm->device = device; + HDF_LOGD("UsbSerialDriverBind=========================OK"); + return HDF_SUCCESS; + +lock_error: + if (OsalMutexDestroy(&acm->lock)) { + HDF_LOGE("%s:%d OsalMutexDestroy fail", __func__, __LINE__); + } +error: + OsalMemFree(acm); + acm = NULL; + return HDF_FAILURE; +} +... +static int UsbAllocReadRequests(struct AcmDevice *acm) +{ + struct UsbRawFillRequestData reqData; + int size = acm->dataInEp->maxPacketSize; + int ret; + + for (int i = 0; i < ACM_NR; i++) { + acm->readReq[i] = UsbRawAllocRequest(acm->devHandle, 0, size); + if (!acm->readReq[i]) { + HDF_LOGE("readReq request faildn"); + return HDF_ERR_MALLOC_FAIL; + } + + reqData.endPoint = acm->dataInEp->addr; + reqData.numIsoPackets = 0; + reqData.callback = AcmReadBulkCallback; + reqData.userData = (void *)acm; + reqData.timeout = USB_CTRL_SET_TIMEOUT; + reqData.length = size; + + ret = UsbRawFillBulkRequest(acm->readReq[i], acm->devHandle, &reqData); + if (ret) { + HDF_LOGE("%{public}s: FillBulkRequest faile, ret=%{public}d n", + __func__, ret); + return HDF_FAILURE; + } + } + + return HDF_SUCCESS; +} +... +static int UsbAllocNotifyRequest(struct AcmDevice *acm) +{ + struct UsbRawFillRequestData fillRequestData; + int size = acm->notifyEp->maxPacketSize; + int ret; + + acm->notifyReq = UsbRawAllocRequest(acm->devHandle, 0, size); + if (!acm->notifyReq) { + HDF_LOGE("notifyReq request failn"); + return HDF_ERR_MALLOC_FAIL; + } + + fillRequestData.endPoint = acm->notifyEp->addr; + fillRequestData.length = size; + fillRequestData.numIsoPackets = 0; + fillRequestData.callback = AcmNotifyReqCallback; + fillRequestData.userData = (void *)acm; + fillRequestData.timeout = USB_CTRL_SET_TIMEOUT; + + ret = UsbRawFillInterruptRequest(acm->notifyReq, acm->devHandle, &fillRequestData); + if (ret) { + HDF_LOGE("%{public}s: FillInterruptRequest faile, ret=%{public}d", __func__, ret); + return HDF_FAILURE; + } + + return HDF_SUCCESS; +} +... +static int32_t UsbSerialInit(struct AcmDevice *acm) +{ + struct UsbSession *session = NULL; + UsbRawHandle *devHandle = NULL; + int32_t ret; + + if (acm->initFlag == true) { + HDF_LOGE("%{public}s:%{public}d: initFlag is true", __func__, __LINE__); + return HDF_SUCCESS; + } + + ret = UsbRawInit(NULL); + if (ret) { + HDF_LOGE("%{public}s:%{public}d UsbRawInit faild", __func__, __LINE__); + return HDF_ERR_IO; + } + acm->session = session; + + devHandle = UsbRawOpenDevice(session, acm->busNum, acm->devAddr); + if (devHandle == NULL) { + HDF_LOGE("%{public}s:%{public}d UsbRawOpenDevice faild", __func__, __LINE__); + ret = HDF_FAILURE; + goto err_open_device; + } + acm->devHandle = devHandle; + ret = UsbGetConfigDescriptor(devHandle, &acm->config); + if (ret) { + HDF_LOGE("%{public}s:%{public}d UsbGetConfigDescriptor faild", __func__, __LINE__); + ret = HDF_FAILURE; + goto err_get_desc; + } + ret = UsbParseConfigDescriptor(acm, acm->config); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s:%{public}d UsbParseConfigDescriptor faild", __func__, __LINE__); + ret = HDF_FAILURE; + goto err_parse_desc; + } + + ret = AcmWriteBufAlloc(acm); + if (ret < 0) { + HDF_LOGE("%{public}s:%{public}d AcmWriteBufAlloc faild", __func__, __LINE__); + ret = HDF_FAILURE; + goto err_alloc_write_buf; + } + ret = UsbAllocWriteRequests(acm); + if (ret < 0) { + HDF_LOGE("%{public}s:%{public}d UsbAllocWriteRequests faild", __func__, __LINE__); + ret = HDF_FAILURE; + goto err_alloc_write_reqs; + } + ret = UsbAllocNotifyRequest(acm); + if (ret) { + HDF_LOGE("%{public}s:%{public}d UsbAllocNotifyRequests faild", __func__, __LINE__); + goto err_alloc_notify_req; + } + ret = UsbAllocReadRequests(acm); + if (ret) { + HDF_LOGE("%{public}s:%{public}d UsbAllocReadRequests faild", __func__, __LINE__); + goto err_alloc_read_reqs; + } + ret = UsbStartIo(acm); + if (ret) { + HDF_LOGE("%{public}s:%{public}d UsbAllocReadRequests faild", __func__, __LINE__); + goto err_start_io; + } + + acm->lineCoding.dwDTERate = CpuToLe32(DATARATE); + acm->lineCoding.bCharFormat = CHARFORMAT; + acm->lineCoding.bParityType = USB_CDC_NO_PARITY; + acm->lineCoding.bDataBits = USB_CDC_1_STOP_BITS; + + ret = UsbRawSubmitRequest(acm->notifyReq); + if (ret) { + HDF_LOGE("%{public}s:%{public}d UsbRawSubmitRequest failed", __func__, __LINE__); + goto err_submit_req; + } + + acm->initFlag = true; + + HDF_LOGD("%{public}s:%{public}d=========================OK", __func__, __LINE__); + + return HDF_SUCCESS; + +err_submit_req: + UsbStopIo(acm); +err_start_io: + UsbFreeReadRequests(acm); +err_alloc_read_reqs: + UsbFreeNotifyReqeust(acm); + err_alloc_notify_req: + UsbFreeWriteRequests(acm); +err_alloc_write_reqs: + AcmWriteBufFree(acm); +err_alloc_write_buf: + UsbReleaseInterfaces(acm); +err_parse_desc: + UsbRawFreeConfigDescriptor(acm->config); + acm->config = NULL; +err_get_desc: + (void)UsbRawCloseDevice(devHandle); +err_open_device: + UsbRawExit(acm->session); + + return ret; +} + +static void UsbSerialRelease(struct AcmDevice *acm) +{ + if (acm->initFlag == false) { + HDF_LOGE("%{public}s:%{public}d: initFlag is false", __func__, __LINE__); + return; + } + + /* stop io thread and release all resources */ + UsbStopIo(acm); + if (g_syncRequest != NULL) { + UsbRawFreeRequest(g_syncRequest); + g_syncRequest = NULL; + } + UsbFreeReadRequests(acm); + UsbFreeNotifyReqeust(acm); + UsbFreeWriteRequests(acm); + AcmWriteBufFree(acm); + (void)UsbRawCloseDevice(acm->devHandle); + UsbReleaseInterfaces(acm); + UsbRawFreeConfigDescriptor(acm->config); + acm->config = NULL; + UsbRawExit(acm->session); + + acm->initFlag = false; +} + +static int32_t UsbSerialDriverInit(struct HdfDeviceObject *device) +{ + struct AcmDevice *acm = NULL; + int32_t ret; + + if (device == NULL) { + HDF_LOGE("%{public}s:%{public}d device is null", __func__, __LINE__); + return HDF_ERR_INVALID_OBJECT; + } + acm = (struct AcmDevice *)device->service; + OsalMutexInit(&acm->readLock); + OsalMutexInit(&acm->writeLock); + + ret = UsbSerialDeviceAlloc(acm); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s:%{public}d UsbSerialDeviceAlloc faild", __func__, __LINE__); + } + + acm->initFlag = false; + g_rawAcmReleaseFlag = false; + + HDF_LOGD("%{public}s:%{public}d init ok!", __func__, __LINE__); + + return ret; +} + +static void UsbSerialDriverRelease(struct HdfDeviceObject *device) +{ + struct AcmDevice *acm = NULL; + if (device == NULL) { + HDF_LOGE("%{public}s: device is NULL", __func__); + return; + } + + acm = (struct AcmDevice *)device->service; + if (acm == NULL) { + HDF_LOGE("%{public}s: acm is null", __func__); + return; + } + + g_rawAcmReleaseFlag = true; + + if (acm->initFlag == true) { + HDF_LOGE("%{public}s:%{public}d UsbSerialRelease", __func__, __LINE__); + UsbSerialRelease(acm); + } + UsbSeriaDevicelFree(acm); + OsalMutexDestroy(&acm->writeLock); + OsalMutexDestroy(&acm->readLock); + OsalMutexDestroy(&acm->lock); + OsalMemFree(acm); + acm = NULL; + HDF_LOGD("%{public}s:%{public}d exit", __func__, __LINE__); +} + +struct HdfDriverEntry g_usbSerialRawDriverEntry = { + .moduleVersion = 1, + .moduleName = "usbhost_acm_rawapi", //驱动模块名称,必须与hcs文件中配置的名称一致 + .Bind = UsbSerialDriverBind, + .Init = UsbSerialDriverInit, + .Release = UsbSerialDriverRelease, +}; +HDF_INIT(g_usbSerialRawDriverEntry); +``` + +### Device DDK API驱动开发 + +USB ACM设备核心代码路径为driversperipheralusbgadgetfunctionacmcdcacm.c,其使用示例如下所示,首先根据描述符创建设备,然后获取接口,打开接口,获取Pipe信息,接收Event事件,接着进行USB通信(读写等),设备卸载时候,关闭接口,停止Event接收,删除设备。 + +``` +1、创建设备 +static int32_t AcmCreateFuncDevice(struct UsbAcmDevice *acm, + struct DeviceResourceIface *iface) +{ + struct UsbFnDevice *fnDev = NULL; +struct UsbFnDescriptorData descData; +uint8_t useHcs; + ... +if (useHcs == 0) { + descData.type = USBFN_DESC_DATA_TYPE_DESC; + descData.descriptor = &g_masterFuncDevice; +} else { + descData.type = USBFN_DESC_DATA_TYPE_PROP; + descData.property = device->property; +} +/* 创建设备 */ + fnDev = (struct UsbFnDevice *)UsbFnDeviceCreate(acm->udcName, &descData); + if (fnDev == NULL) { + HDF_LOGE("%{public}s: create usb function device failed", __func__); + return HDF_FAILURE; + } + ... +} +2、获取接口,打开接口,获取Pipe信息 +static int32_t AcmParseEachPipe(struct UsbAcmDevice *acm, struct UsbAcmInterface *iface) +{ + ... + for (i = 0; i < fnIface->info.numPipes; i++) { + struct UsbFnPipeInfo pipeInfo; +/* 获取pipe信息 */ + ret = UsbFnInterfaceGetPipeInfo(fnIface, i, &pipeInfo); + ... + } + return HDF_SUCCESS; +} +/* 获取接口,打开接口获取handle */ +static int32_t AcmParseEachIface(struct UsbAcmDevice *acm, struct UsbFnDevice *fnDev) +{ + ... + for (i = 0; i < fnDev->numInterfaces; i++) { + /* 获取接口 */ + fnIface = (struct UsbFnInterface *)UsbFnDeviceGetInterface(fnDev, i); + ... + /* 打开接口 */ + handle = UsbFnInterfaceOpen(fnIface); + ... + } + return HDF_SUCCESS; +} +3、接收Event事件 +static int32_t AcmAllocCtrlRequests(struct UsbAcmDevice *acm, int num) +{ + ... + req = UsbFnCtrlRequestAlloc(acm->ctrlIface.handle, + sizeof(struct UsbCdcLineCoding) + sizeof(struct UsbCdcLineCoding)); + ... +} +static int32_t AcmDriverInit(struct HdfDeviceObject *device) +{ +... +/* 开始接收Event */ + ret = UsbFnInterfaceStartRecvEvent(acm->ctrlIface.fn, 0xff, UsbAcmEventCallback, acm); + ... +} +4、进行USB通信(读写等) +static int32_t AcmSendNotifyRequest(struct UsbAcmDevice *acm, uint8_t type, + uint16_t value, void *data, uint32_t length) +{ +... +/* 异步发送 */ + ret = UsbFnRequestSubmitAsync(req); + ... +} +5、关闭接口,停止Event接收,删除设备 +static int32_t AcmReleaseFuncDevice(struct UsbAcmDevice *acm) +{ +int32_t ret; +/* 关闭接口 */ + (void)UsbFnInterfaceClose(acm->ctrlIface.handle); +(void)UsbFnInterfaceClose(acm->dataIface.handle); +/* 停止接收Event */ +(void)UsbFnInterfaceStopRecvEvent(acm->ctrlIface.fn); +/* 删除设备 */ + ret = UsbFnDeviceRemove(acm->fnDev); + if (ret != HDF_SUCCESS) { + HDF_LOGE("%{public}s: remove usb function device failed", __func__); + } + return ret; +} +``` + diff --git "a/zh-cn/device-dev/driver/figures/USB-Device\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" "b/zh-cn/device-dev/driver/figures/USB-Device\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..3766cf8117505a0d47720dcbccc1030536921bdb Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/USB-Device\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" differ diff --git "a/zh-cn/device-dev/driver/figures/USB-Host\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" "b/zh-cn/device-dev/driver/figures/USB-Host\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..6bea2992afd00b031176998278c0bcfce0f8e843 Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/USB-Host\351\251\261\345\212\250\346\250\241\345\236\213\345\233\276.png" differ diff --git a/zh-cn/device-dev/subsystems/subsys-security-communicationverify.md b/zh-cn/device-dev/subsystems/subsys-security-communicationverify.md old mode 100755 new mode 100644