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
33 #ifdef __cplusplus
34 extern "C" {
35 #endif /* __cplusplus */
36 constexpr size_t MAX_ACTION_LEN = 20;
37 constexpr size_t MAX_DEVPATH_LEN = 250;
38 constexpr size_t MAX_SUBSYSTEM_LEN = 30;
39 constexpr size_t MAX_DEVTYPE_LEN = 30;
40 constexpr size_t MAX_DEVNUM_LEN = 10;
41 constexpr size_t MAX_BUSNUM_LEN = 10;
42 constexpr size_t MAX_TASK_NUM = 100000;
43 #define HDF_LOG_TAG usb_ddk_uevent_queue
44 struct DdkUeventTaskInfo {
45 char action[MAX_ACTION_LEN];
46 char devPath[MAX_DEVPATH_LEN];
47 char subSystem[MAX_SUBSYSTEM_LEN];
48 char devType[MAX_DEVTYPE_LEN];
49 char devNum[MAX_DEVNUM_LEN];
50 char busNum[MAX_BUSNUM_LEN];
51 };
52
53 class TaskQueue {
54 public:
55 TaskQueue() = default;
56 void Init(void);
57 void UnInit(void);
58 ~TaskQueue();
59 int32_t AddTask(const DdkUeventTaskInfo &task);
60
61 private:
62 std::queue<DdkUeventTaskInfo> taskQueue_;
63 std::mutex queueLock_;
64 std::condition_variable conditionVariable_;
65 bool threadRun_ {true};
66 };
67
DdkUeventCopyTask(DdkUeventTaskInfo & task,const struct DdkUeventInfo * info)68 static bool DdkUeventCopyTask(DdkUeventTaskInfo &task, const struct DdkUeventInfo *info)
69 {
70 int32_t ret = memcpy_s(task.action, MAX_ACTION_LEN, info->action, strlen(info->action));
71 if (ret != EOK) {
72 HDF_LOGE("%{public}s: copy action failed:%{public}s", __func__, info->action);
73 return false;
74 }
75
76 ret = memcpy_s(task.devPath, MAX_DEVPATH_LEN, info->devPath, strlen(info->devPath));
77 if (ret != EOK) {
78 HDF_LOGE("%{public}s: copy devPath failed:%{public}s", __func__, info->devPath);
79 return false;
80 }
81
82 ret = memcpy_s(task.subSystem, MAX_SUBSYSTEM_LEN, info->subSystem, strlen(info->subSystem));
83 if (ret != EOK) {
84 HDF_LOGE("%{public}s: copy subSystem failed:%{public}s", __func__, info->subSystem);
85 return false;
86 }
87
88 ret = memcpy_s(task.devType, MAX_DEVTYPE_LEN, info->devType, strlen(info->devType));
89 if (ret != EOK) {
90 HDF_LOGE("%{public}s: copy devType failed:%{public}s", __func__, info->devType);
91 return false;
92 }
93
94 ret = memcpy_s(task.devNum, MAX_DEVNUM_LEN, info->devNum, strlen(info->devNum));
95 if (ret != EOK) {
96 HDF_LOGE("%{public}s: copy devNum failed:%{public}s", __func__, info->devNum);
97 return false;
98 }
99
100 ret = memcpy_s(task.busNum, MAX_BUSNUM_LEN, info->busNum, strlen(info->busNum));
101 if (ret != EOK) {
102 HDF_LOGE("%{public}s: copy busNum failed:%{public}s", __func__, info->busNum);
103 return false;
104 }
105 return true;
106 }
107
DdkUeventAddDevice(const char * devPath)108 static int32_t DdkUeventAddDevice(const char *devPath)
109 {
110 const char *pos = strrchr(devPath, '/');
111 if (pos == nullptr) {
112 HDF_LOGE("%{public}s: no / in devpath:%{public}s", __func__, devPath);
113 return HDF_ERR_INVALID_PARAM;
114 }
115
116 const struct UsbPnpNotifyMatchInfoTable *device = DdkDevMgrCreateDevice(pos + 1); // 1 skip '/'
117 if (device == nullptr) {
118 HDF_LOGE("%{public}s: create device failed:%{public}s", __func__, devPath);
119 return HDF_FAILURE;
120 }
121 DdkListenerMgrNotifyAll(device, USB_PNP_NOTIFY_ADD_DEVICE);
122 return HDF_SUCCESS;
123 }
124
DdkUeventRemoveDevice(const char * busNum,const char * devNum)125 static int32_t DdkUeventRemoveDevice(const char *busNum, const char *devNum)
126 {
127 struct UsbPnpNotifyMatchInfoTable dev;
128 int32_t ret =
129 DdkDevMgrRemoveDevice(strtol(busNum, nullptr, 10), strtol(devNum, nullptr, 10), &dev); // 10 means decimal
130 if (ret != HDF_SUCCESS) {
131 HDF_LOGE("%{public}s: remove device failed, busNum:%{public}s, devNum:%{public}s", __func__, busNum, devNum);
132 return HDF_FAILURE;
133 }
134 DdkListenerMgrNotifyAll(&dev, USB_PNP_NOTIFY_REMOVE_DEVICE);
135 return HDF_SUCCESS;
136 }
137
DdkDispatchUevent(const struct DdkUeventTaskInfo * info)138 static void DdkDispatchUevent(const struct DdkUeventTaskInfo *info)
139 {
140 int32_t ret = HDF_SUCCESS;
141 if (strcmp(info->action, "bind") == 0 && strcmp(info->devType, "usb_device") == 0) {
142 ret = DdkUeventAddDevice(info->devPath);
143 } else if (strcmp(info->action, "remove") == 0 && strcmp(info->devType, "usb_device") == 0) {
144 ret = DdkUeventRemoveDevice(info->busNum, info->devNum);
145 }
146
147 if (ret != HDF_SUCCESS) {
148 HDF_LOGE("%{public}s: action:%{public}s, ret:%{public}d", __func__, info->action, ret);
149 }
150 }
151
Init(void)152 void TaskQueue::Init(void)
153 {
154 pthread_setname_np(pthread_self(), "ueventTaskQueue");
155 auto taskWork = [this]() -> void {
156 while (threadRun_) {
157 std::unique_lock<std::mutex> uniqueLock(queueLock_);
158 conditionVariable_.wait(uniqueLock, [this] {
159 return (taskQueue_.size() > 0 || !threadRun_);
160 });
161 if (taskQueue_.size() > 0) {
162 DdkUeventTaskInfo task = taskQueue_.front();
163 taskQueue_.pop();
164 queueLock_.unlock();
165 conditionVariable_.notify_one();
166 DdkDispatchUevent(&task);
167 }
168 }
169 };
170 std::thread thd(taskWork);
171
172 thd.detach();
173 }
174
UnInit(void)175 void TaskQueue::UnInit(void)
176 {
177 threadRun_ = false;
178 conditionVariable_.notify_one();
179
180 std::lock_guard<std::mutex> lock(queueLock_);
181 while (!taskQueue_.empty()) {
182 taskQueue_.pop();
183 }
184 }
185
~TaskQueue()186 TaskQueue::~TaskQueue()
187 {
188 UnInit();
189 }
190
AddTask(const DdkUeventTaskInfo & task)191 int32_t TaskQueue::AddTask(const DdkUeventTaskInfo &task)
192 {
193 std::lock_guard<std::mutex> lock(queueLock_);
194 if (taskQueue_.size() > MAX_TASK_NUM) {
195 HDF_LOGE("%{public}s: task queue is full", __func__);
196 return HDF_FAILURE;
197 }
198 taskQueue_.emplace(task);
199 conditionVariable_.notify_one();
200 return HDF_SUCCESS;
201 }
202
203 static TaskQueue g_taskQueue;
204
DdkUeventStartDispatchThread()205 int32_t DdkUeventStartDispatchThread()
206 {
207 g_taskQueue.Init();
208 return HDF_SUCCESS;
209 }
210
DdkUeventAddTask(const struct DdkUeventInfo * info)211 int32_t DdkUeventAddTask(const struct DdkUeventInfo *info)
212 {
213 if (strcmp(info->subSystem, "usb") != 0) {
214 return HDF_SUCCESS;
215 }
216 bool isAddDevice = strcmp(info->action, "bind") == 0 && strcmp(info->devType, "usb_device") == 0;
217 bool isRemoveDevice = strcmp(info->action, "remove") == 0 && strcmp(info->devType, "usb_device") == 0;
218 if (!(isAddDevice || isRemoveDevice)) {
219 return HDF_SUCCESS;
220 }
221 DdkUeventTaskInfo task {
222 {0x00},
223 {0x00},
224 {0x00},
225 {0x00},
226 {0x00},
227 {0x00},
228 };
229 if (!DdkUeventCopyTask(task, info)) {
230 HDF_LOGW("%{public}s: copy task failed", __func__);
231 }
232 return g_taskQueue.AddTask(task);
233 }
234
235 #ifdef __cplusplus
236 }
237 #endif /* __cplusplus */