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