1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15#include "ddk_uevent_queue.h" 16 17#include <condition_variable> 18#include <mutex> 19#include <queue> 20#include <thread> 21 22#include <cstring> 23#include <sys/types.h> 24#include <unistd.h> 25 26#include "ddk_device_manager.h" 27#include "ddk_pnp_listener_mgr.h" 28#include "hdf_base.h" 29#include "hdf_io_service_if.h" 30#include "hdf_log.h" 31#include "securec.h" 32#include "usbd_wrapper.h" 33 34#ifdef __cplusplus 35extern "C" { 36#endif /* __cplusplus */ 37constexpr size_t MAX_ACTION_LEN = 20; 38constexpr size_t MAX_DEVPATH_LEN = 250; 39constexpr size_t MAX_SUBSYSTEM_LEN = 30; 40constexpr size_t MAX_DEVTYPE_LEN = 30; 41constexpr size_t MAX_DEVNUM_LEN = 10; 42constexpr size_t MAX_BUSNUM_LEN = 10; 43constexpr size_t MAX_TASK_NUM = 100000; 44#define HDF_LOG_TAG usb_ddk_uevent_queue 45struct DdkUeventTaskInfo { 46 char action[MAX_ACTION_LEN]; 47 char devPath[MAX_DEVPATH_LEN]; 48 char subSystem[MAX_SUBSYSTEM_LEN]; 49 char devType[MAX_DEVTYPE_LEN]; 50 char devNum[MAX_DEVNUM_LEN]; 51 char busNum[MAX_BUSNUM_LEN]; 52}; 53 54class TaskQueue { 55public: 56 TaskQueue() = default; 57 void Init(void); 58 void UnInit(void); 59 ~TaskQueue(); 60 int32_t AddTask(const DdkUeventTaskInfo &task); 61 62private: 63 std::queue<DdkUeventTaskInfo> taskQueue_; 64 std::mutex queueLock_; 65 std::condition_variable conditionVariable_; 66 bool threadRun_ {true}; 67}; 68 69static bool DdkUeventCopyTask(DdkUeventTaskInfo &task, const struct DdkUeventInfo *info) 70{ 71 int32_t ret = memcpy_s(task.action, MAX_ACTION_LEN, info->action, strlen(info->action)); 72 if (ret != EOK) { 73 HDF_LOGE("%{public}s: copy action failed:%{public}s", __func__, info->action); 74 return false; 75 } 76 77 ret = memcpy_s(task.devPath, MAX_DEVPATH_LEN, info->devPath, strlen(info->devPath)); 78 if (ret != EOK) { 79 HDF_LOGE("%{public}s: copy devPath failed:%{public}s", __func__, info->devPath); 80 return false; 81 } 82 83 ret = memcpy_s(task.subSystem, MAX_SUBSYSTEM_LEN, info->subSystem, strlen(info->subSystem)); 84 if (ret != EOK) { 85 HDF_LOGE("%{public}s: copy subSystem failed:%{public}s", __func__, info->subSystem); 86 return false; 87 } 88 89 ret = memcpy_s(task.devType, MAX_DEVTYPE_LEN, info->devType, strlen(info->devType)); 90 if (ret != EOK) { 91 HDF_LOGE("%{public}s: copy devType failed:%{public}s", __func__, info->devType); 92 return false; 93 } 94 95 ret = memcpy_s(task.devNum, MAX_DEVNUM_LEN, info->devNum, strlen(info->devNum)); 96 if (ret != EOK) { 97 HDF_LOGE("%{public}s: copy devNum failed:%{public}s", __func__, info->devNum); 98 return false; 99 } 100 101 ret = memcpy_s(task.busNum, MAX_BUSNUM_LEN, info->busNum, strlen(info->busNum)); 102 if (ret != EOK) { 103 HDF_LOGE("%{public}s: copy busNum failed:%{public}s", __func__, info->busNum); 104 return false; 105 } 106 return true; 107} 108 109static int32_t DdkUeventAddDevice(const char *devPath) 110{ 111 const char *pos = strrchr(devPath, '/'); 112 if (pos == nullptr) { 113 HDF_LOGE("%{public}s: no / in devpath:%{public}s", __func__, devPath); 114 return HDF_ERR_INVALID_PARAM; 115 } 116 117 const struct UsbPnpNotifyMatchInfoTable *device = DdkDevMgrCreateDevice(pos + 1); // 1 skip '/' 118 if (device == nullptr) { 119 HDF_LOGE("%{public}s: create device failed:%{public}s", __func__, devPath); 120 return HDF_FAILURE; 121 } 122 DdkListenerMgrNotifyAll(device, USB_PNP_NOTIFY_ADD_DEVICE); 123 return HDF_SUCCESS; 124} 125 126static int32_t DdkUeventRemoveDevice(const char *busNum, const char *devNum) 127{ 128 struct UsbPnpNotifyMatchInfoTable dev; 129 int32_t ret = 130 DdkDevMgrRemoveDevice(strtol(busNum, nullptr, 10), strtol(devNum, nullptr, 10), &dev); // 10 means decimal 131 if (ret != HDF_SUCCESS) { 132 HDF_LOGE("%{public}s: remove device failed, busNum:%{public}s, devNum:%{public}s", __func__, busNum, devNum); 133 return HDF_FAILURE; 134 } 135 DdkListenerMgrNotifyAll(&dev, USB_PNP_NOTIFY_REMOVE_DEVICE); 136 return HDF_SUCCESS; 137} 138 139static void DdkDispatchUevent(const struct DdkUeventTaskInfo *info) 140{ 141 int32_t ret = HDF_SUCCESS; 142 if (strcmp(info->action, "bind") == 0 && strcmp(info->devType, "usb_device") == 0) { 143 ret = DdkUeventAddDevice(info->devPath); 144 } else if (strcmp(info->action, "remove") == 0 && strcmp(info->devType, "usb_device") == 0) { 145 ret = DdkUeventRemoveDevice(info->busNum, info->devNum); 146 } 147 148 if (ret != HDF_SUCCESS) { 149 HDF_LOGE("%{public}s: action:%{public}s, ret:%{public}d", __func__, info->action, ret); 150 } 151} 152 153void TaskQueue::Init(void) 154{ 155 pthread_setname_np(pthread_self(), "ueventTaskQueue"); 156 auto taskWork = [this]() -> void { 157 while (threadRun_) { 158 std::unique_lock<std::mutex> uniqueLock(queueLock_); 159 conditionVariable_.wait(uniqueLock, [this] { 160 return (taskQueue_.size() > 0 || !threadRun_); 161 }); 162 if (taskQueue_.size() > 0) { 163 DdkUeventTaskInfo task = taskQueue_.front(); 164 taskQueue_.pop(); 165 uniqueLock.unlock(); 166 DdkDispatchUevent(&task); 167 } 168 } 169 }; 170 std::thread thd(taskWork); 171 172 thd.detach(); 173} 174 175 176 177void TaskQueue::UnInit(void) 178{ 179 threadRun_ = false; 180 conditionVariable_.notify_one(); 181 182 std::lock_guard<std::mutex> lock(queueLock_); 183 while (!taskQueue_.empty()) { 184 taskQueue_.pop(); 185 } 186} 187 188TaskQueue::~TaskQueue() 189{ 190 UnInit(); 191} 192 193int32_t TaskQueue::AddTask(const DdkUeventTaskInfo &task) 194{ 195 std::lock_guard<std::mutex> lock(queueLock_); 196 if (taskQueue_.size() > MAX_TASK_NUM) { 197 HDF_LOGE("%{public}s: task queue is full", __func__); 198 conditionVariable_.notify_one(); 199 return HDF_FAILURE; 200 } 201 taskQueue_.emplace(task); 202 conditionVariable_.notify_one(); 203 return HDF_SUCCESS; 204} 205 206static TaskQueue g_taskQueue; 207 208int32_t DdkUeventStartDispatchThread() 209{ 210 g_taskQueue.Init(); 211 return HDF_SUCCESS; 212} 213 214int32_t DdkUeventAddTask(const struct DdkUeventInfo *info) 215{ 216 if (strcmp(info->subSystem, "usb") != 0) { 217 return HDF_SUCCESS; 218 } 219 bool isAddDevice = strcmp(info->action, "bind") == 0 && strcmp(info->devType, "usb_device") == 0; 220 bool isRemoveDevice = strcmp(info->action, "remove") == 0 && strcmp(info->devType, "usb_device") == 0; 221 if (!(isAddDevice || isRemoveDevice)) { 222 return HDF_SUCCESS; 223 } 224 HDF_LOGI("%{public}s: bind=%{public}s, subsystem=%{public}s, devType=%{public}s, devPath=%{public}s", 225 __func__, info->action, info->subSystem, info->devType, info->devPath); 226 DdkUeventTaskInfo task { 227 {0x00}, 228 {0x00}, 229 {0x00}, 230 {0x00}, 231 {0x00}, 232 {0x00}, 233 }; 234 if (!DdkUeventCopyTask(task, info)) { 235 HDF_LOGW("%{public}s: copy task failed", __func__); 236 return HDF_FAILURE; 237 } 238 return g_taskQueue.AddTask(task); 239} 240 241#ifdef __cplusplus 242} 243#endif /* __cplusplus */