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/" 36struct UsbDdkDeviceInfo { 37 struct OsalMutex deviceMutex; 38 struct DListHead list; 39 struct UsbPnpNotifyMatchInfoTable info; 40}; 41 42struct UsbDdkDeviceList { 43 bool isInit; 44 struct OsalMutex listMutex; 45 struct DListHead devList; 46}; 47 48#ifdef USB_EVENT_NOTIFY_LINUX_NATIVE_MODE 49static struct UsbDdkDeviceList g_ddkDevList = {.isInit = false}; 50#define STATE_STRING_LENGTH 20 51 52char *g_gadgetStatePath = "invalid_path"; 53 54static 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 76static 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 97int32_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 121static 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 134const 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 171static 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 199int32_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 227int32_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 248int32_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} 290bool 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 324struct HdfIoService *g_usbPnpSrv = NULL; 325#define HDF_USB_INFO_MAX_SIZE (127 * sizeof(struct UsbPnpNotifyMatchInfoTable)) // 127 is max deivce num 326int32_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 337int32_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 385static 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 416int32_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 437bool 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