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