diff --git a/bundle.json b/bundle.json index fa55a5c19c2e96b87cf4e304192c7259a506fe5e..8fe93c7da334d30396d6ef22f7f666ed54286b4b 100644 --- a/bundle.json +++ b/bundle.json @@ -15,7 +15,8 @@ "syscap": [ "SystemCapability.Driver.HID.Extension", "SystemCapability.Driver.ExternalDevice", - "SystemCapability.Driver.USB.Extension" + "SystemCapability.Driver.USB.Extension", + "SystemCapability.Driver.DDK.Extension" ], "features": [], "adapted_system_type": [ diff --git a/frameworks/ddk/BUILD.gn b/frameworks/ddk/BUILD.gn index babe71f23ac8154aec1508c759173e45ad5e2274..d4ce264e979aa8e2eeb37967d275c80dce1f328e 100644 --- a/frameworks/ddk/BUILD.gn +++ b/frameworks/ddk/BUILD.gn @@ -13,6 +13,7 @@ group("ddk") { deps = [ + "base:ddk_base", "hid:hid", "usb:usb_ndk", ] diff --git a/frameworks/ddk/base/BUILD.gn b/frameworks/ddk/base/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..6e574717f68a2f43d2c99512548a1e4fc2aea7bb --- /dev/null +++ b/frameworks/ddk/base/BUILD.gn @@ -0,0 +1,34 @@ +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//drivers/external_device_manager/extdevmgr.gni") + +ohos_shared_library("ddk_base") { + include_dirs = [ + "${ext_mgr_path}/interfaces/ddk/base/", + "${utils_path}/include/", + ] + + sources = [ "ddk_api.cpp" ] + + external_deps = [ + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + ] + install_enable = true + subsystem_name = "hdf" + part_name = "external_device_manager" +} diff --git a/frameworks/ddk/base/ddk_api.cpp b/frameworks/ddk/base/ddk_api.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ddea7ea0957fc4778467853fab653697428d7426 --- /dev/null +++ b/frameworks/ddk/base/ddk_api.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "ddk_api.h" +#include "ddk_types.h" +#include "hilog_wrapper.h" + +using namespace OHOS::ExternalDeviceManager; +namespace { +static std::unordered_map> g_shareMemoryMap; +std::mutex g_mutex; +} + +DDK_RetCode OH_DDK_CreateAshmem(const uint8_t *name, uint32_t size, DDK_Ashmem **ashmem) +{ + if (name == nullptr) { + EDM_LOGE(MODULE_BASE_DDK, "invalid buffer name!"); + return DDK_INVALID_PARAMETER; + } + + if (size <= 0) { + EDM_LOGE(MODULE_BASE_DDK, "invalid buffer size!, size = %{public}d", size); + return DDK_INVALID_PARAMETER; + } + + if (ashmem == nullptr) { + EDM_LOGE(MODULE_BASE_DDK, "invalid pointer of ashmem!"); + return DDK_INVALID_PARAMETER; + } + + OHOS::sptr shareMemory = OHOS::Ashmem::CreateAshmem(reinterpret_cast(name), size); + if (shareMemory == nullptr) { + EDM_LOGE(MODULE_BASE_DDK, "create ashmem failed! errno = %{public}d", errno); + return DDK_FAILURE; + } + + int32_t fd = shareMemory->GetAshmemFd(); + DDK_Ashmem *ddkAshmem = new DDK_Ashmem({fd, nullptr, size, 0, size, 0}); + if (ddkAshmem == nullptr) { + EDM_LOGE(MODULE_BASE_DDK, "alloc ddk ashmem failed! errno = %{public}d", errno); + return DDK_FAILURE; + } + *ashmem = ddkAshmem; + + std::lock_guard lock(g_mutex); + g_shareMemoryMap[ddkAshmem->ashmemFd] = shareMemory; + return DDK_SUCCESS; +} + +static DDK_RetCode AshmemValidityCheck(DDK_Ashmem *ashmem) +{ + if (ashmem == nullptr) { + EDM_LOGE(MODULE_BASE_DDK, "ashmem is nullptr!"); + return DDK_NULL_PTR; + } + + if (g_shareMemoryMap.find(ashmem->ashmemFd) == g_shareMemoryMap.end()) { + EDM_LOGE(MODULE_BASE_DDK, "ashmemFd dose not exist! error fd = %{public}d", ashmem->ashmemFd); + return DDK_FAILURE; + } + + if (g_shareMemoryMap[ashmem->ashmemFd] == nullptr) { + EDM_LOGE(MODULE_BASE_DDK, "share memory dose not create!"); + return DDK_FAILURE; + } + + return DDK_SUCCESS; +} + +DDK_RetCode OH_DDK_MapAshmem(DDK_Ashmem *ashmem, const uint8_t ashmemMapType) +{ + std::lock_guard lock(g_mutex); + DDK_RetCode ret = AshmemValidityCheck(ashmem); + if (ret != DDK_SUCCESS) { + EDM_LOGE(MODULE_BASE_DDK, "%{public}s: check the validity of ashmem fail!", __func__); + return ret; + } + + if (!g_shareMemoryMap[ashmem->ashmemFd]->MapAshmem(ashmemMapType)) { + EDM_LOGE(MODULE_BASE_DDK, "MapAshmem fail! errno = %{public}d", errno); + return DDK_INVALID_OPERATION; + } + + ashmem->address = + reinterpret_cast(g_shareMemoryMap[ashmem->ashmemFd]->ReadFromAshmem(ashmem->size, 0)); + return DDK_SUCCESS; +} + +DDK_RetCode OH_DDK_UnmapAshmem(DDK_Ashmem *ashmem) +{ + std::lock_guard lock(g_mutex); + DDK_RetCode ret = AshmemValidityCheck(ashmem); + if (ret != DDK_SUCCESS) { + EDM_LOGE(MODULE_BASE_DDK, "%{public}s: check the validity of ashmem fail!", __func__); + return ret; + } + + g_shareMemoryMap[ashmem->ashmemFd]->UnmapAshmem(); + ashmem->address = nullptr; + return DDK_SUCCESS; +} + +DDK_RetCode OH_DDK_DestroyAshmem(DDK_Ashmem *ashmem) +{ + std::lock_guard lock(g_mutex); + DDK_RetCode ret = AshmemValidityCheck(ashmem); + if (ret != DDK_SUCCESS) { + EDM_LOGE(MODULE_BASE_DDK, "%{public}s: check the validity of ashmem fail!", __func__); + return ret; + } + + g_shareMemoryMap.erase(ashmem->ashmemFd); + ashmem->address = nullptr; + delete ashmem; + ashmem = nullptr; + return DDK_SUCCESS; +} diff --git a/frameworks/ddk/usb/BUILD.gn b/frameworks/ddk/usb/BUILD.gn index cd79fbe1fa60aee65226fb41ab5f06995e5596a0..6ec2dfa5258734a5fcc43bd4cf23e7c59fd65d55 100644 --- a/frameworks/ddk/usb/BUILD.gn +++ b/frameworks/ddk/usb/BUILD.gn @@ -15,6 +15,7 @@ import("../../../extdevmgr.gni") ohos_shared_library("usb_ndk") { include_dirs = [ + "${ext_mgr_path}/interfaces/ddk/base/", "${ext_mgr_path}/interfaces/ddk/usb/", "${utils_path}/include/", "./", diff --git a/frameworks/ddk/usb/usb_ddk_api.cpp b/frameworks/ddk/usb/usb_ddk_api.cpp index 5223ad97de70e328698f41f591d7d1e25d7a07e7..81204e5eebd05355bfdd8f6b04fa3a3f28ea3535 100644 --- a/frameworks/ddk/usb/usb_ddk_api.cpp +++ b/frameworks/ddk/usb/usb_ddk_api.cpp @@ -265,6 +265,29 @@ int32_t OH_Usb_SendPipeRequest(const UsbRequestPipe *pipe, UsbDeviceMemMap *devM *tmpSetUp, devMmap->size, devMmap->offset, devMmap->bufferLength, devMmap->transferedLength); } +int32_t OH_Usb_SendPipeRequestWithAshmem(const UsbRequestPipe *pipe, DDK_Ashmem *ashmem) +{ + if (!ExtPermissionManager::GetInstance().HasPermission(PERMISSION_NAME)) { + EDM_LOGE(MODULE_USB_DDK, "no permission"); + return USB_DDK_FAILED; + } + + if (g_ddk == nullptr) { + EDM_LOGE(MODULE_USB_DDK, "invalid obj"); + return USB_DDK_INVALID_OPERATION; + } + + if (pipe == nullptr || ashmem == nullptr || ashmem->address == nullptr) { + EDM_LOGE(MODULE_USB_DDK, "param is null"); + return USB_DDK_INVALID_PARAMETER; + } + + auto tmpSetUp = reinterpret_cast(pipe); + std::vector address = std::vector(ashmem->address, ashmem->address + ashmem->size); + OHOS::HDI::Usb::Ddk::V1_0::UsbAshmem usbAshmem = {ashmem->ashmemFd, address, ashmem->size, 0, ashmem->size, 0}; + return g_ddk->SendPipeRequestWithAshmem(*tmpSetUp, usbAshmem, ashmem->transferredLength); +} + int32_t OH_Usb_CreateDeviceMemMap(uint64_t deviceId, size_t size, UsbDeviceMemMap **devMmap) { if (!ExtPermissionManager::GetInstance().HasPermission(PERMISSION_NAME)) { diff --git a/interfaces/ddk/base/ddk_api.h b/interfaces/ddk/base/ddk_api.h new file mode 100644 index 0000000000000000000000000000000000000000..0d260f8c721c04b38766cdedbb2a0773b3c57bdc --- /dev/null +++ b/interfaces/ddk/base/ddk_api.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DDK_API_H +#define DDK_API_H + +/** + * @addtogroup Ddk + * @{ + * + * @brief Provides Base DDK APIs, including creating the shared memory, mapping the shared memory,\n + * unmapping the shared memory, and destroying the shared memory. + * + * @since 12 + */ + +/** + * @file ddk_api.h + * + * @brief Declares the Base DDK APIs. + * + * @syscap SystemCapability.Driver.DDK.Extension + * @since 12 + */ + +#include +#include "ddk_types.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @brief Creates shared memory. To prevent resource leakage, destroy the shared memory that is not required by\n + * calling OH_DDK_DestroyAshmem. + * + * @param name Pointer to the shared memory to create. + * @param size Size of the buffer corresponding to the shared memory. + * @param ashmem Pointer to the shared memory created. + * @return Returns DDK_SUCCESS if the operation is successful; returns a negative value otherwise. + * @since 12 + */ +DDK_RetCode OH_DDK_CreateAshmem(const uint8_t *name, uint32_t size, DDK_Ashmem **ashmem); + +/** + * @brief Maps the created shared memory to the user space. Unmap the shared memory that is not required by using\n + * OH_DDK_UnmapAshmem. + * + * @param ashmem Pointer of the shared memory to map. + * @param ashmemMapType Protection permission value of the shared memory. + * @return Returns DDK_SUCCESS if the operation is successful; returns a negative value otherwise. + * @since 12 + */ +DDK_RetCode OH_DDK_MapAshmem(DDK_Ashmem *ashmem, const uint8_t ashmemMapType); + +/** + * @brief Unmaps shared memory. + * + * @param ashmem Pointer of the shared memory to unmap. + * @return Returns DDK_SUCCESS if the operation is successful; returns a negative value otherwise. + * @since 12 + */ +DDK_RetCode OH_DDK_UnmapAshmem(DDK_Ashmem *ashmem); + +/** + * @brief Destroys shared memory. + * + * @param ashmem Pointer of the shared memory to destroy. + * @return Returns DDK_SUCCESS if the operation is successful; returns a negative value otherwise. + * @since 12 + */ +DDK_RetCode OH_DDK_DestroyAshmem(DDK_Ashmem *ashmem); +#ifdef __cplusplus +} +/** @} */ +#endif /* __cplusplus */ +#endif // DDK_APIS_H \ No newline at end of file diff --git a/interfaces/ddk/base/ddk_types.h b/interfaces/ddk/base/ddk_types.h new file mode 100644 index 0000000000000000000000000000000000000000..9e782d1dd5fb2daca80c4cdddd6ce767a8262dea --- /dev/null +++ b/interfaces/ddk/base/ddk_types.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DDK_TYPES_H +#define DDK_TYPES_H + +/** + * @addtogroup Ddk + * @{ + * + * @brief Provides Base DDK types and declares the macros, enums, and\n + * data structs used by the Base DDK APIs. + * + * @since 12 + */ + +/** + * @file ddk_types.h + * + * @brief Provides the enums, structs, and macros used in USB Base APIs. + * + * @syscap SystemCapability.Driver.DDK.Extension + * @since 12 + */ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @brief Defines the shared memory created by using OH_DDK_CreateAShMem.\n + * A buffer for the shared memory provides better performance. + * + * @since 12 + */ +typedef struct DDK_Ashmem { + /** File descriptor of the shared memory. */ + int32_t ashmemFd; + /** Buffer address. */ + const uint8_t *address; + /** Buffer size. */ + const uint32_t size; + /** Offset of the used buffer. The default value is 0, which indicates that there is no offset\n + * and the buffer starts from the specified address. + */ + uint32_t offset; + /** Length of the used buffer. By default, the value is equal to the size, which indicates that\n + * the entire buffer is used. + */ + uint32_t bufferLength; + /** Length of the transferred data. */ + uint32_t transferredLength; +} DDK_Ashmem; + +/** + * @brief Enumerates the error codes used in the Base DDK. + * + * @since 12 + */ +typedef enum { + /** Operation success */ + DDK_SUCCESS = 0, + /** Operation failed */ + DDK_FAILURE = 28600001, + /** Invalid parameter */ + DDK_INVALID_PARAMETER, + /** Invalid operation */ + DDK_INVALID_OPERATION, + /** Null pointer exception */ + DDK_NULL_PTR +} DDK_RetCode; +#ifdef __cplusplus +} +/** @} */ +#endif /* __cplusplus */ +#endif // DDK_TYPES_H \ No newline at end of file diff --git a/interfaces/ddk/usb/usb_ddk_api.h b/interfaces/ddk/usb/usb_ddk_api.h index e128a7d345d784f42381994bf01655c30eb86e00..39f5b950e3bdbfb6ea9bf34996650af32c5d3d75 100644 --- a/interfaces/ddk/usb/usb_ddk_api.h +++ b/interfaces/ddk/usb/usb_ddk_api.h @@ -38,6 +38,7 @@ #include +#include "ddk_types.h" #include "usb_ddk_types.h" #ifdef __cplusplus @@ -198,6 +199,18 @@ int32_t OH_Usb_SendControlWriteRequest(uint64_t interfaceHandle, const struct Us */ int32_t OH_Usb_SendPipeRequest(const struct UsbRequestPipe *pipe, UsbDeviceMemMap *devMmap); +/** + * @brief Sends a pipe request. This API works in a synchronous manner. This API applies to interrupt transfer\n + * and bulk transfer. + * + * @permission ohos.permission.ACCESS_DDK_USB + * @param pipe Pipe used to transfer data. + * @param ashmem Shared memory, which can be obtained by calling OH_DDK_CreateAshmem. + * @return 0 if the operation is successful; a negative value otherwise. + * @since 12 + */ +int32_t OH_Usb_SendPipeRequestWithAshmem(const struct UsbRequestPipe *pipe, DDK_Ashmem *ashmem); + /** * @brief Creates a buffer. To avoid resource leakage, destroy a buffer by calling\n * OH_Usb_DestroyDeviceMemMap after use. diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 6ef960bc0e4ddc19da2e949131d47b342b1599b3..8085bba9810f02133111a6adfa5299c1dabf9882 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -140,6 +140,7 @@ ohos_unittest("ddk_permission_test") { ] include_dirs = [ + "${ext_mgr_path}/interfaces/ddk/base", "${ext_mgr_path}/frameworks/ddk/usb", "${ext_mgr_path}/interfaces/ddk/usb", "${ext_mgr_path}/interfaces/innerkits/", diff --git a/test/unittest/bus_extension_usb_test/include/usb_ddk_service_mock.h b/test/unittest/bus_extension_usb_test/include/usb_ddk_service_mock.h index c43517eb6c09943ec253e8c12f053a4bc2d18b41..8ada240060aff3f8a7580601d5b2746f8d9d0fc6 100644 --- a/test/unittest/bus_extension_usb_test/include/usb_ddk_service_mock.h +++ b/test/unittest/bus_extension_usb_test/include/usb_ddk_service_mock.h @@ -42,6 +42,8 @@ public: MOCK_METHOD5(SendPipeRequest, int32_t(const UsbRequestPipe &pipe, uint32_t size, uint32_t offset, uint32_t length, uint32_t &transferedLength)); MOCK_METHOD2(GetDeviceMemMapFd, int32_t(uint64_t deviceId, int &fd)); + MOCK_METHOD3(SendPipeRequestWithAshmem, int32_t(const UsbRequestPipe &pipe, const UsbAshmem &ashmem, + uint32_t &transferredLength)); }; } // namespace USB } // namespace OHOS diff --git a/utils/include/hilog_wrapper.h b/utils/include/hilog_wrapper.h index a5d8a010461515f1b01a96271aee92ac31580e95..449abb70f85af0634eb28db18ef969995268127f 100644 --- a/utils/include/hilog_wrapper.h +++ b/utils/include/hilog_wrapper.h @@ -59,6 +59,7 @@ enum UsbMgrSubModule { MODULE_USB_DDK, EDM_MODULE_TEST, MODULE_HID_DDK, + MODULE_BASE_DDK, EDM_MODULE_BUTT, }; @@ -76,6 +77,7 @@ enum UsbMgrDomainId { EDM_USB_DDK_DOMAIN, EDM_TEST, EDM_HID_DDK_DOMAIN, + EDM_BASE_DDK_DOMAIN, EDM_BUTT, }; @@ -101,6 +103,7 @@ static const EdmLable EDM_MGR_LABEL[EDM_MODULE_BUTT] = { {EDM_USB_DDK_DOMAIN, "EdmUsbDdk" }, {EDM_TEST, "EdmTest" }, {EDM_HID_DDK_DOMAIN, "EdmHidDdk" }, + {EDM_BASE_DDK_DOMAIN, "EdmBaseDdk" }, }; // In order to improve performance, do not check the module range, module should less than EDM_MODULE_BUTT.