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     DListRemove(&dev->list);
115     OsalMemFree(dev);
116     dev = NULL;
117     OsalMutexUnlock(&g_ddkDevList.listMutex);
118     return HDF_SUCCESS;
119 }
120 
DdkDevMgrInitDevice(struct UsbDdkDeviceInfo * deviceInfo)121 static int32_t DdkDevMgrInitDevice(struct UsbDdkDeviceInfo *deviceInfo)
122 {
123     (void)memset_s(deviceInfo, sizeof(struct UsbDdkDeviceInfo), 0, sizeof(struct UsbDdkDeviceInfo));
124     int32_t ret = OsalMutexInit(&deviceInfo->deviceMutex);
125     if (ret != HDF_SUCCESS) {
126         HDF_LOGE("%{public}s: init mutex failed", __func__);
127         return HDF_FAILURE;
128     }
129     DListHeadInit(&deviceInfo->list);
130 
131     return HDF_SUCCESS;
132 }
133 
DdkDevMgrCreateDevice(const char * deviceDir)134 const struct UsbPnpNotifyMatchInfoTable *DdkDevMgrCreateDevice(const char *deviceDir)
135 {
136     struct UsbDdkDeviceInfo *device = (struct UsbDdkDeviceInfo *)OsalMemCalloc(sizeof(struct UsbDdkDeviceInfo));
137     if (device == NULL) {
138         HDF_LOGE("%{public}s: init device failed", __func__);
139         return NULL;
140     }
141 
142     int32_t status = HDF_SUCCESS;
143     do {
144         // init device
145         status = DdkDevMgrInitDevice(device);
146         if (status != HDF_SUCCESS) {
147             HDF_LOGE("%{public}s: init device failed:%{public}d", __func__, status);
148             break;
149         }
150 
151         // get device from sysfs
152         status = DdkSysfsGetDevice(deviceDir, &device->info);
153         if (status != HDF_SUCCESS) {
154             HDF_LOGE("%{public}s: sysfs get device failed:%{public}d", __func__, status);
155             break;
156         }
157 
158         // insert device to list
159         status = DdkDevMgrAddDevice(device);
160         if (status != HDF_SUCCESS) {
161             HDF_LOGE("%{public}s: add device failed:%{public}d", __func__, status);
162             break;
163         }
164         return &device->info;
165     } while (0);
166 
167     OsalMemFree(device);
168     return status == HDF_SUCCESS ? &device->info : NULL;
169 }
170 
DdkDevMgrScanSysfs(const char * sysfsDevDir)171 static int32_t DdkDevMgrScanSysfs(const char *sysfsDevDir)
172 {
173     if (sysfsDevDir == NULL) {
174         HDF_LOGE("%{public}s: invalid param", __func__);
175         return HDF_ERR_INVALID_PARAM;
176     }
177 
178     DIR *dir = opendir(sysfsDevDir);
179     if (dir == NULL) {
180         HDF_LOGE("%{public}s: opendir failed sysfsDevDir:%{public}s", __func__, sysfsDevDir);
181         return HDF_ERR_BAD_FD;
182     }
183 
184     struct dirent *devHandle;
185     while ((devHandle = readdir(dir))) {
186         // only read dir like 3-1
187         if (devHandle->d_name[0] > '9' || devHandle->d_name[0] < '0' || strchr(devHandle->d_name, ':')) {
188             continue;
189         }
190 
191         if (DdkDevMgrCreateDevice(devHandle->d_name) == NULL) {
192             HDF_LOGW("%{public}s: create device failed d_name:%{public}s", __func__, devHandle->d_name);
193         }
194     }
195     closedir(dir);
196     return HDF_SUCCESS;
197 }
198 
DdkDevMgrInit(const char * gadgetStatePath)199 int32_t DdkDevMgrInit(const char *gadgetStatePath)
200 {
201     if (g_ddkDevList.isInit) {
202         return HDF_SUCCESS;
203     }
204 
205     if (gadgetStatePath == NULL) {
206         HDF_LOGE("%{public}s: invalid gadgetStatePath", __func__);
207         return HDF_ERR_INVALID_PARAM;
208     }
209 
210     g_gadgetStatePath = (char *)gadgetStatePath;
211     int32_t ret = OsalMutexInit(&g_ddkDevList.listMutex);
212     if (ret != HDF_SUCCESS) {
213         HDF_LOGE("%{public}s: init mutex failed", __func__);
214         return HDF_FAILURE;
215     }
216 
217     DListHeadInit(&g_ddkDevList.devList);
218     ret = DdkDevMgrScanSysfs(SYSFS_DEVICES_DIR);
219     if (ret != HDF_SUCCESS) {
220         HDF_LOGE("%{public}s: Scan sysfs failed ret=%{public}d", __func__, ret);
221         return HDF_FAILURE;
222     }
223     g_ddkDevList.isInit = true;
224     return HDF_SUCCESS;
225 }
226 
DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle,void * priv)227 int32_t DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle, void *priv)
228 {
229     OsalMutexLock(&g_ddkDevList.listMutex);
230     if (DListIsEmpty(&g_ddkDevList.devList)) {
231         HDF_LOGI("%{public}s:the devList is empty", __func__);
232         OsalMutexUnlock(&g_ddkDevList.listMutex);
233         return HDF_SUCCESS;
234     }
235 
236     struct UsbDdkDeviceInfo *pos = NULL;
237     struct UsbDdkDeviceInfo *tmp = NULL;
238     DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, &g_ddkDevList.devList, struct UsbDdkDeviceInfo, list) {
239         if (handle(&pos->info, priv) != HDF_SUCCESS) {
240             HDF_LOGW("%{public}s: handle failed", __func__);
241         }
242     }
243 
244     OsalMutexUnlock(&g_ddkDevList.listMutex);
245     return HDF_SUCCESS;
246 }
247 
DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle,void * priv)248 int32_t DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle, void *priv)
249 {
250     if (priv == NULL || handle == NULL) {
251         HDF_LOGE("%{public}s: invalid param.", __func__);
252         return HDF_ERR_INVALID_OBJECT;
253     }
254 
255     char pathBuf[PATH_MAX] = {'\0'};
256     if (realpath(g_gadgetStatePath, pathBuf) == NULL) {
257         HDF_LOGE("%{public}s: path conversion failed", __func__);
258         return HDF_FAILURE;
259     }
260 
261     if (strncmp(USB_GADGET_STATE_PATH, pathBuf, strlen(USB_GADGET_STATE_PATH)) != 0) {
262         HDF_LOGE("%{public}s: The file path is incorrect", __func__);
263         return HDF_FAILURE;
264     }
265 
266     int32_t fd = open(pathBuf, O_RDONLY | O_CLOEXEC);
267     if (fd == -1) {
268         HDF_LOGE("%{public}s: open %{public}s failed  errno:%{public}d", __func__, g_gadgetStatePath, errno);
269         return HDF_ERR_IO;
270     }
271 
272     char buf[STATE_STRING_LENGTH] = {0};
273     ssize_t numRead = read(fd, buf, STATE_STRING_LENGTH);
274     close(fd);
275     if (numRead <= 0) {
276         HDF_LOGE("%{public}s: read state failed errno:%{public}d", __func__, errno);
277         return HDF_ERR_IO;
278     }
279 
280     if ((strncmp(buf, "CONNECTED", strlen("CONNECTED")) == 0) ||
281         (strncmp(buf, "CONFIGURED", strlen("CONFIGURED")) == 0)) {
282         // call back
283         if (handle(priv) != HDF_SUCCESS) {
284             HDF_LOGW("%{public}s: handle failed", __func__);
285         }
286     }
287 
288     return HDF_SUCCESS;
289 }
DdkDevMgrGetGadgetLinkStatus()290 bool DdkDevMgrGetGadgetLinkStatus()
291 {
292     char pathBuf[PATH_MAX] = {'\0'};
293     if (realpath(g_gadgetStatePath, pathBuf) == NULL) {
294         HDF_LOGE("%{public}s: path conversion failed", __func__);
295         return false;
296     }
297 
298     if (strncmp(USB_GADGET_STATE_PATH, pathBuf, strlen(USB_GADGET_STATE_PATH)) != 0) {
299         HDF_LOGE("%{public}s: The file path is incorrect", __func__);
300         return false;
301     }
302 
303     int32_t fd = open(pathBuf, O_RDONLY | O_CLOEXEC);
304     if (fd == -1) {
305         HDF_LOGE("%{public}s: open %{public}s failed  errno:%{public}d", __func__, g_gadgetStatePath, errno);
306         return false;
307     }
308 
309     char buf[STATE_STRING_LENGTH] = {0};
310     ssize_t numRead = read(fd, buf, STATE_STRING_LENGTH);
311     close(fd);
312     if (numRead <= 0) {
313         HDF_LOGE("%{public}s: read state failed errno:%{public}d", __func__, errno);
314         return false;
315     }
316     HDF_LOGE("%{public}s: read status:%{public}s", __func__, buf);
317     if ((strncmp(buf, "CONNECTED", strlen("CONNECTED")) == 0) ||
318         (strncmp(buf, "CONFIGURED", strlen("CONFIGURED")) == 0)) {
319         return true;
320     }
321     return false;
322 }
323 #else                                                                           // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
324 struct HdfIoService *g_usbPnpSrv = NULL;
325 #define HDF_USB_INFO_MAX_SIZE (127 * sizeof(struct UsbPnpNotifyMatchInfoTable)) // 127  is max deivce num
DdkDevMgrInit(const char * gadgetStatePath)326 int32_t DdkDevMgrInit(const char *gadgetStatePath)
327 {
328     (void)gadgetStatePath;
329     g_usbPnpSrv = HdfIoServiceBind(USB_PNP_NOTIFY_SERVICE_NAME);
330     if (g_usbPnpSrv == NULL) {
331         HDF_LOGE("%{public}s: HdfIoServiceBind failed.", __func__);
332         return HDF_ERR_INVALID_OBJECT;
333     }
334     return HDF_SUCCESS;
335 }
336 
DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle,void * priv)337 int32_t DdkDevMgrForEachDeviceSafe(DdkDevMgrHandleDev handle, void *priv)
338 {
339     if (g_usbPnpSrv == NULL || handle == NULL) {
340         HDF_LOGE("%{public}s: invalid param.", __func__);
341         return HDF_ERR_INVALID_OBJECT;
342     }
343 
344     struct HdfSBuf *reply = HdfSbufObtain(HDF_USB_INFO_MAX_SIZE);
345     if (reply == NULL) {
346         HDF_LOGE("%{public}s: HdfSbufObtain reply failed", __func__);
347         return HDF_DEV_ERR_NO_MEMORY;
348     }
349 
350     // request device list from pnp service
351     int32_t ret = g_usbPnpSrv->dispatcher->Dispatch(&g_usbPnpSrv->object, USB_PNP_DRIVER_GETDEVICES, NULL, reply);
352     if (ret != HDF_SUCCESS) {
353         HDF_LOGE("%{public}s:failed to send service call, ret:%{public}d", __func__, ret);
354         HdfSbufRecycle(reply);
355         return ret;
356     }
357 
358     // read device list
359     int32_t count = 0;
360     if (!HdfSbufReadInt32(reply, &count)) {
361         HDF_LOGE("%{public}s: failed to read count from reply", __func__);
362         HdfSbufRecycle(reply);
363         return HDF_ERR_INVALID_PARAM;
364     }
365 
366     HDF_LOGI("%{public}s: total obj num count:%{public}d ", __func__, count);
367     struct UsbPnpNotifyMatchInfoTable *info = NULL;
368     uint32_t infoSize = 0;
369     for (int32_t i = 0; i < count; ++i) {
370         if (!HdfSbufReadBuffer(reply, (const void **)(&info), &infoSize) || info == NULL) {
371             HDF_LOGE("%{public}s: HdfSbufReadBuffer failed", __func__);
372             HdfSbufRecycle(reply);
373             return HDF_ERR_INVALID_PARAM;
374         }
375         // call back
376         if (handle(info, priv) != HDF_SUCCESS) {
377             HDF_LOGW("%{public}s: handle failed", __func__);
378         }
379     }
380 
381     HdfSbufRecycle(reply);
382     return HDF_SUCCESS;
383 }
384 
DdkDevMgrGetGadgetStatus(int32_t * gadgetStatus)385 static int32_t DdkDevMgrGetGadgetStatus(int32_t *gadgetStatus)
386 {
387     if (g_usbPnpSrv == NULL) {
388         HDF_LOGE("%{public}s: invalid param.", __func__);
389         return HDF_ERR_INVALID_OBJECT;
390     }
391 
392     struct HdfSBuf *reply = HdfSbufObtain(HDF_USB_INFO_MAX_SIZE);
393     if (reply == NULL) {
394         HDF_LOGE("%{public}s: HdfSbufObtain reply failed", __func__);
395         return HDF_DEV_ERR_NO_MEMORY;
396     }
397 
398     int32_t ret =
399         g_usbPnpSrv->dispatcher->Dispatch(&g_usbPnpSrv->object, USB_PNP_DRIVER_GET_GADGET_LINK_STATUS, NULL, reply);
400     if (ret != HDF_SUCCESS) {
401         HDF_LOGE("%{public}s:failed to send service call, ret:%{public}d", __func__, ret);
402         HdfSbufRecycle(reply);
403         return ret;
404     }
405 
406     if (!HdfSbufReadInt32(reply, gadgetStatus)) {
407         HDF_LOGE("%{public}s: failed to read count from reply", __func__);
408         HdfSbufRecycle(reply);
409         return HDF_ERR_INVALID_PARAM;
410     }
411 
412     HdfSbufRecycle(reply);
413     return HDF_SUCCESS;
414 }
415 
DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle,void * priv)416 int32_t DdkDevMgrGetGadgetLinkStatusSafe(DdkDevMgrHandleGadget handle, void *priv)
417 {
418     if (priv == NULL || handle == NULL) {
419         HDF_LOGE("%{public}s: invalid param.", __func__);
420         return HDF_ERR_INVALID_OBJECT;
421     }
422     int32_t gadgetStatus = 0;
423     if (DdkDevMgrGetGadgetStatus(&gadgetStatus) != HDF_SUCCESS) {
424         HDF_LOGE("%{public}s: DdkDevMgrGetGadgetStatus failed", __func__);
425         return HDF_FAILURE;
426     }
427     // gadget add
428     if (gadgetStatus != 0) {
429         // call back
430         if (handle(priv) != HDF_SUCCESS) {
431             HDF_LOGW("%{public}s: handle failed", __func__);
432         }
433     }
434     return HDF_SUCCESS;
435 }
436 
DdkDevMgrGetGadgetLinkStatus()437 bool DdkDevMgrGetGadgetLinkStatus()
438 {
439     int32_t gadgetStatus = 0;
440     if (DdkDevMgrGetGadgetStatus(&gadgetStatus) != HDF_SUCCESS) {
441         HDF_LOGE("%{public}s: DdkDevMgrGetGadgetStatus failed", __func__);
442         return false;
443     }
444     // gadget add
445     if (gadgetStatus != 0) {
446         return gadgetStatus == USB_PNP_DRIVER_GADGET_ADD ? true : false;
447     }
448     return false;
449 }
450 #endif                                                                          // USB_EVENT_NOTIFY_LINUX_NATIVE_MODE
451