1 /*
2 * Copyright (c) 2022-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
16 #include "ddk_device_manager.h"
17
18 #include <ctype.h>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22
23 #include "ddk_sysfs_device.h"
24 #include "hdf_base.h"
25 #include "hdf_dlist.h"
26 #include "hdf_io_service_if.h"
27 #include "hdf_log.h"
28 #include "hdf_sbuf.h"
29 #include "osal_mem.h"
30 #include "osal_mutex.h"
31 #include "securec.h"
32 #include "usbd_wrapper.h"
33
34 #define HDF_LOG_TAG usb_ddk_dev_mgr
35 #define USB_GADGET_STATE_PATH "/sys/devices/virtual/"
36 struct UsbDdkDeviceInfo {
37 struct OsalMutex deviceMutex;
38 struct DListHead list;
39 struct UsbPnpNotifyMatchInfoTable info;
40 };
41
42 struct UsbDdkDeviceList {
43 bool isInit;
44 struct OsalMutex listMutex;
45 struct DListHead devList;
46 };
47
48 #ifdef USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
49 static struct UsbDdkDeviceList g_ddkDevList = {.isInit = false};
50 #define STATE_STRING_LENGTH 20
51
52 char *g_gadgetStatePath = "invalid_path";
53
DdkDevMgrIsDevExists(uint64_t devAddr)54 static struct UsbDdkDeviceInfo *DdkDevMgrIsDevExists(uint64_t devAddr)
55 {
56 OsalMutexLock(&g_ddkDevList.listMutex);
57 if (DListIsEmpty(&g_ddkDevList.devList)) {
58 HDF_LOGI("%{public}s: the devList is empty.", __func__);
59 OsalMutexUnlock(&g_ddkDevList.listMutex);
60 return NULL;
61 }
62
63 struct UsbDdkDeviceInfo *res = NULL;
64 struct UsbDdkDeviceInfo *infoPos = NULL;
65 struct UsbDdkDeviceInfo *infoTemp = NULL;
66 DLIST_FOR_EACH_ENTRY_SAFE(infoPos, infoTemp, &g_ddkDevList.devList, struct UsbDdkDeviceInfo, list) {
67 if (infoPos->info.usbDevAddr == devAddr) {
68 res = infoPos;
69 break;
70 }
71 }
72 OsalMutexUnlock(&g_ddkDevList.listMutex);
73 return res;
74 }
75
DdkDevMgrAddDevice(struct UsbDdkDeviceInfo * device)76 static int32_t DdkDevMgrAddDevice(struct UsbDdkDeviceInfo *device)
77 {
78 if (device == NULL) {
79 HDF_LOGE("%{public}s: invalid param", __func__);
80 return HDF_ERR_INVALID_PARAM;
81 }
82
83 HDF_LOGI("%{public}s: make device address and whether the device exists", __func__);
84 if (DdkDevMgrIsDevExists(DdkSysfsMakeDevAddr(device->info.busNum, device->info.devNum)) != NULL) {
85 HDF_LOGW("%{public}s: add device repeatedly busNum:%{public}d, devNum:%{public}d", __func__,
86 device->info.busNum, device->info.devNum);
87 return HDF_SUCCESS;
88 }
89
90 OsalMutexLock(&g_ddkDevList.listMutex);
91 DListInsertTail(&device->list, &g_ddkDevList.devList);
92 OsalMutexUnlock(&g_ddkDevList.listMutex);
93 HDF_LOGI("%{public}s: add device successed", __func__);
94 return HDF_SUCCESS;
95 }
96
DdkDevMgrRemoveDevice(int32_t busNum,int32_t devNum,struct UsbPnpNotifyMatchInfoTable * info)97 int32_t DdkDevMgrRemoveDevice(int32_t busNum, int32_t devNum, struct UsbPnpNotifyMatchInfoTable *info)
98 {
99 uint64_t devAddr = DdkSysfsMakeDevAddr(busNum, devNum);
100 struct UsbDdkDeviceInfo *dev = DdkDevMgrIsDevExists(devAddr);
101 if (dev == NULL) {
102 HDF_LOGE("%{public}s: no device busNum:%{public}d, devNum:%{public}d", __func__, busNum, devNum);
103 return HDF_DEV_ERR_NO_DEVICE;
104 }
105
106 int32_t ret = memcpy_s(
107 info, sizeof(struct UsbPnpNotifyMatchInfoTable), &dev->info, sizeof(struct UsbPnpNotifyMatchInfoTable));
108 if (ret != EOK) {
109 HDF_LOGE("%{public}s: memcpy_s failed", __func__);
110 return HDF_FAILURE;
111 }
112
113 OsalMutexLock(&g_ddkDevList.listMutex);
114 if (dev->list.prev != NULL && dev->list.next != NULL) {
115 DListRemove(&dev->list);
116 } else {
117 HDF_LOGE("%{public}s: The node prev or next is NULL", __func__);
118 }
119 OsalMemFree(dev);
120 dev = NULL;
121 OsalMutexUnlock(&g_ddkDevList.listMutex);
122 return HDF_SUCCESS;
123 }
124
DdkDevMgrInitDevice(struct UsbDdkDeviceInfo * deviceInfo)125 static int32_t DdkDevMgrInitDevice(struct UsbDdkDeviceInfo *deviceInfo)
126 {
127 (void)memset_s(deviceInfo, sizeof(struct UsbDdkDeviceInfo), 0, sizeof(struct UsbDdkDeviceInfo));
128 int32_t ret = OsalMutexInit(&deviceInfo->deviceMutex);
129 if (ret != HDF_SUCCESS) {
130 HDF_LOGE("%{public}s: init mutex failed", __func__);
131 return HDF_FAILURE;
132 }
133 DListHeadInit(&deviceInfo->list);
134
135 return HDF_SUCCESS;
136 }
137
DdkDevMgrCreateDevice(const char * deviceDir)138 const struct UsbPnpNotifyMatchInfoTable *DdkDevMgrCreateDevice(const char *deviceDir)
139 {
140 struct UsbDdkDeviceInfo *device = (struct UsbDdkDeviceInfo *)OsalMemCalloc(sizeof(struct UsbDdkDeviceInfo));
141 if (device == NULL) {
142 HDF_LOGE("%{public}s: init device failed", __func__);
143 return NULL;
144 }
145
146 int32_t status = HDF_SUCCESS;
147 do {
148 // init device
149 status = DdkDevMgrInitDevice(device);
150 if (status != HDF_SUCCESS) {
151 HDF_LOGE("%{public}s: init device failed:%{public}d", __func__, status);
152 break;
153 }
154
155 // get device from sysfs
156 status = DdkSysfsGetDevice(deviceDir, &device->info);
157 if (status != HDF_SUCCESS) {
158 HDF_LOGE("%{public}s: sysfs get device failed:%{public}d", __func__, status);
159 break;
160 }
161
162 // insert device to list
163 status = DdkDevMgrAddDevice(device);
164 if (status != HDF_SUCCESS) {
165 HDF_LOGE("%{public}s: add device failed:%{public}d", __func__, status);
166 break;
167 }
168 return &device->info;
169 } while (0);
170
171 OsalMemFree(device);
172 return status == HDF_SUCCESS ? &device->info : NULL;
173 }
174
DdkDevMgrScanSysfs(const char * sysfsDevDir)175 static int32_t DdkDevMgrScanSysfs(const char *sysfsDevDir)
176 {
177 if (sysfsDevDir == NULL) {
178 HDF_LOGE("%{public}s: invalid param", __func__);
179 return HDF_ERR_INVALID_PARAM;
180 }
181
182 DIR *dir = opendir(sysfsDevDir);
183 if (dir == NULL) {
184 HDF_LOGE("%{public}s: opendir failed sysfsDevDir:%{public}s", __func__, sysfsDevDir);
185 return HDF_ERR_BAD_FD;
186 }
187
188 struct dirent *devHandle;
189 while ((devHandle = readdir(dir))) {
190 // only read dir like 3-1
191 if (devHandle->d_name[0] > '9' || devHandle->d_name[0] < '0' || strchr(devHandle->d_name, ':')) {
192 continue;
193 }
194
195 if (DdkDevMgrCreateDevice(devHandle->d_name) == NULL) {
196 HDF_LOGW("%{public}s: create device failed d_name:%{public}s", __func__, devHandle->d_name);
197 }
198 }
199 closedir(dir);
200 return HDF_SUCCESS;
201 }
202
DdkDevMgrInit(const char * gadgetStatePath)203 int32_t DdkDevMgrInit(const char *gadgetStatePath)
204 {
205 if (g_ddkDevList.isInit) {
206 return HDF_SUCCESS;
207 }
208
209 if (gadgetStatePath == NULL) {
210 HDF_LOGE("%{public}s: invalid gadgetStatePath", __func__);
211 return HDF_ERR_INVALID_PARAM;
212 }
213
214 g_gadgetStatePath = (char *)gadgetStatePath;
215 int32_t ret = OsalMutexInit(&g_ddkDevList.listMutex);
216 if (ret != HDF_SUCCESS) {
217 HDF_LOGE("%{public}s: init mutex failed", __func__);
218 return HDF_FAILURE;
219 }
220
221 DListHeadInit(&g_ddkDevList.devList);
222 ret = DdkDevMgrScanSysfs(SYSFS_DEVICES_DIR);
223 if (ret != HDF_SUCCESS) {
224 HDF_LOGE("%{public}s: Scan sysfs failed ret=%{public}d", __func__, ret);
225 return HDF_FAILURE;
226 }
227 g_ddkDevList.isInit = true;
228 return HDF_SUCCESS;
229 }
230
DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle,void * priv)231 int32_t DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle, void *priv)
232 {
233 OsalMutexLock(&g_ddkDevList.listMutex);
234 if (DListIsEmpty(&g_ddkDevList.devList)) {
235 HDF_LOGI("%{public}s:the devList is empty", __func__);
236 OsalMutexUnlock(&g_ddkDevList.listMutex);
237 return HDF_SUCCESS;
238 }
239
240 struct UsbDdkDeviceInfo *pos = NULL;
241 struct UsbDdkDeviceInfo *tmp = NULL;
242 DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, &g_ddkDevList.devList, struct UsbDdkDeviceInfo, list) {
243 if (handle(&pos->info, priv) != HDF_SUCCESS) {
244 HDF_LOGW("%{public}s: handle failed", __func__);
245 }
246 }
247
248 OsalMutexUnlock(&g_ddkDevList.listMutex);
249 return HDF_SUCCESS;
250 }
251
DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle,void * priv)252 int32_t DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle, void *priv)
253 {
254 if (priv == NULL || handle == NULL) {
255 HDF_LOGE("%{public}s: invalid param.", __func__);
256 return HDF_ERR_INVALID_OBJECT;
257 }
258
259 char pathBuf[PATH_MAX] = {'\0'};
260 if (realpath(g_gadgetStatePath, pathBuf) == NULL) {
261 HDF_LOGE("%{public}s: path conversion failed", __func__);
262 return HDF_FAILURE;
263 }
264
265 if (strncmp(USB_GADGET_STATE_PATH, pathBuf, strlen(USB_GADGET_STATE_PATH)) != 0) {
266 HDF_LOGE("%{public}s: The file path is incorrect", __func__);
267 return HDF_FAILURE;
268 }
269
270 int32_t fd = open(pathBuf, O_RDONLY | O_CLOEXEC);
271 if (fd == -1) {
272 HDF_LOGE("%{public}s: open %{public}s failed errno:%{public}d", __func__, g_gadgetStatePath, errno);
273 return HDF_ERR_IO;
274 }
275
276 char buf[STATE_STRING_LENGTH] = {0};
277 ssize_t numRead = read(fd, buf, STATE_STRING_LENGTH);
278 close(fd);
279 if (numRead <= 0) {
280 HDF_LOGE("%{public}s: read state failed errno:%{public}d", __func__, errno);
281 return HDF_ERR_IO;
282 }
283
284 if ((strncmp(buf, "CONNECTED", strlen("CONNECTED")) == 0) ||
285 (strncmp(buf, "CONFIGURED", strlen("CONFIGURED")) == 0)) {
286 // call back
287 if (handle(priv) != HDF_SUCCESS) {
288 HDF_LOGW("%{public}s: handle failed", __func__);
289 }
290 }
291
292 return HDF_SUCCESS;
293 }
DdkDevMgrGetGadgetLinkStatus()294 bool DdkDevMgrGetGadgetLinkStatus()
295 {
296 char pathBuf[PATH_MAX] = {'\0'};
297 if (realpath(g_gadgetStatePath, pathBuf) == NULL) {
298 HDF_LOGE("%{public}s: path conversion failed", __func__);
299 return false;
300 }
301
302 if (strncmp(USB_GADGET_STATE_PATH, pathBuf, strlen(USB_GADGET_STATE_PATH)) != 0) {
303 HDF_LOGE("%{public}s: The file path is incorrect", __func__);
304 return false;
305 }
306
307 int32_t fd = open(pathBuf, O_RDONLY | O_CLOEXEC);
308 if (fd == -1) {
309 HDF_LOGE("%{public}s: open %{public}s failed errno:%{public}d", __func__, g_gadgetStatePath, errno);
310 return false;
311 }
312
313 char buf[STATE_STRING_LENGTH] = {0};
314 ssize_t numRead = read(fd, buf, STATE_STRING_LENGTH);
315 close(fd);
316 if (numRead <= 0) {
317 HDF_LOGE("%{public}s: read state failed errno:%{public}d", __func__, errno);
318 return false;
319 }
320 HDF_LOGE("%{public}s: read status:%{public}s", __func__, buf);
321 if ((strncmp(buf, "CONNECTED", strlen("CONNECTED")) == 0) ||
322 (strncmp(buf, "CONFIGURED", strlen("CONFIGURED")) == 0)) {
323 return true;
324 }
325 return false;
326 }
327 #else // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
328 struct HdfIoService *g_usbPnpSrv = NULL;
329 #define HDF_USB_INFO_MAX_SIZE (127 * sizeof(struct UsbPnpNotifyMatchInfoTable)) // 127 is max deivce num
DdkDevMgrInit(const char * gadgetStatePath)330 int32_t DdkDevMgrInit(const char *gadgetStatePath)
331 {
332 (void)gadgetStatePath;
333 g_usbPnpSrv = HdfIoServiceBind(USB_PNP_NOTIFY_SERVICE_NAME);
334 if (g_usbPnpSrv == NULL) {
335 HDF_LOGE("%{public}s: HdfIoServiceBind failed.", __func__);
336 return HDF_ERR_INVALID_OBJECT;
337 }
338 return HDF_SUCCESS;
339 }
340
DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle,void * priv)341 int32_t DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle, void *priv)
342 {
343 if (g_usbPnpSrv == NULL || handle == NULL) {
344 HDF_LOGE("%{public}s: invalid param.", __func__);
345 return HDF_ERR_INVALID_OBJECT;
346 }
347
348 struct HdfSBuf *reply = HdfSbufObtain(HDF_USB_INFO_MAX_SIZE);
349 if (reply == NULL) {
350 HDF_LOGE("%{public}s: HdfSbufObtain reply failed", __func__);
351 return HDF_DEV_ERR_NO_MEMORY;
352 }
353
354 // request device list from pnp service
355 int32_t ret = g_usbPnpSrv->dispatcher->Dispatch(&g_usbPnpSrv->object, USB_PNP_DRIVER_GETDEVICES, NULL, reply);
356 if (ret != HDF_SUCCESS) {
357 HDF_LOGE("%{public}s:failed to send service call, ret:%{public}d", __func__, ret);
358 HdfSbufRecycle(reply);
359 return ret;
360 }
361
362 // read device list
363 int32_t count = 0;
364 if (!HdfSbufReadInt32(reply, &count)) {
365 HDF_LOGE("%{public}s: failed to read count from reply", __func__);
366 HdfSbufRecycle(reply);
367 return HDF_ERR_INVALID_PARAM;
368 }
369
370 HDF_LOGI("%{public}s: total obj num count:%{public}d ", __func__, count);
371 struct UsbPnpNotifyMatchInfoTable *info = NULL;
372 uint32_t infoSize = 0;
373 for (int32_t i = 0; i < count; ++i) {
374 if (!HdfSbufReadBuffer(reply, (const void **)(&info), &infoSize) || info == NULL) {
375 HDF_LOGE("%{public}s: HdfSbufReadBuffer failed", __func__);
376 HdfSbufRecycle(reply);
377 return HDF_ERR_INVALID_PARAM;
378 }
379 // call back
380 if (handle(info, priv) != HDF_SUCCESS) {
381 HDF_LOGW("%{public}s: handle failed", __func__);
382 }
383 }
384
385 HdfSbufRecycle(reply);
386 return HDF_SUCCESS;
387 }
388
DdkDevMgrGetGadgetStatus(int32_t * gadgetStatus)389 static int32_t DdkDevMgrGetGadgetStatus(int32_t *gadgetStatus)
390 {
391 if (g_usbPnpSrv == NULL) {
392 HDF_LOGE("%{public}s: invalid param.", __func__);
393 return HDF_ERR_INVALID_OBJECT;
394 }
395
396 struct HdfSBuf *reply = HdfSbufObtain(HDF_USB_INFO_MAX_SIZE);
397 if (reply == NULL) {
398 HDF_LOGE("%{public}s: HdfSbufObtain reply failed", __func__);
399 return HDF_DEV_ERR_NO_MEMORY;
400 }
401
402 int32_t ret =
403 g_usbPnpSrv->dispatcher->Dispatch(&g_usbPnpSrv->object, USB_PNP_DRIVER_GET_GADGET_LINK_STATUS, NULL, reply);
404 if (ret != HDF_SUCCESS) {
405 HDF_LOGE("%{public}s:failed to send service call, ret:%{public}d", __func__, ret);
406 HdfSbufRecycle(reply);
407 return ret;
408 }
409
410 if (!HdfSbufReadInt32(reply, gadgetStatus)) {
411 HDF_LOGE("%{public}s: failed to read count from reply", __func__);
412 HdfSbufRecycle(reply);
413 return HDF_ERR_INVALID_PARAM;
414 }
415
416 HdfSbufRecycle(reply);
417 return HDF_SUCCESS;
418 }
419
DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle,void * priv)420 int32_t DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle, void *priv)
421 {
422 if (priv == NULL || handle == NULL) {
423 HDF_LOGE("%{public}s: invalid param.", __func__);
424 return HDF_ERR_INVALID_OBJECT;
425 }
426 int32_t gadgetStatus = 0;
427 if (DdkDevMgrGetGadgetStatus(&gadgetStatus) != HDF_SUCCESS) {
428 HDF_LOGE("%{public}s: DdkDevMgrGetGadgetStatus failed", __func__);
429 return HDF_FAILURE;
430 }
431 // gadget add
432 if (gadgetStatus != 0) {
433 // call back
434 if (handle(priv) != HDF_SUCCESS) {
435 HDF_LOGW("%{public}s: handle failed", __func__);
436 }
437 }
438 return HDF_SUCCESS;
439 }
440
DdkDevMgrGetGadgetLinkStatus()441 bool DdkDevMgrGetGadgetLinkStatus()
442 {
443 int32_t gadgetStatus = 0;
444 if (DdkDevMgrGetGadgetStatus(&gadgetStatus) != HDF_SUCCESS) {
445 HDF_LOGE("%{public}s: DdkDevMgrGetGadgetStatus failed", __func__);
446 return false;
447 }
448 // gadget add
449 if (gadgetStatus != 0) {
450 return gadgetStatus == USB_PNP_DRIVER_GADGET_ADD ? true : false;
451 }
452 return false;
453 }
454 #endif // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
455