• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */