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_sysfs_device.h" 17#include <dirent.h> 18#include <fcntl.h> 19#include <inttypes.h> 20#include <sys/stat.h> 21#include <sys/types.h> 22#include <unistd.h> 23 24#include "hdf_log.h" 25#include "securec.h" 26#include "usbd_wrapper.h" 27 28#define SYSFS_PATH_LEN 128 29#define PROPERTY_MAX_LEN 128 30#define HDF_LOG_TAG usb_ddk_sysfs_dev 31 32static inline int32_t DdkSysfsGetBase(const char *propName) 33{ 34 if (strcmp(propName, "idProduct") == 0 || strcmp(propName, "idVendor") == 0) { 35 return 16; // 16 means hexadecimal 36 } 37 return 10; // 10 means decimal 38} 39 40inline uint64_t DdkSysfsMakeDevAddr(uint32_t busNum, uint32_t devNum) 41{ 42 return (((uint64_t)busNum << 32) | devNum); // 32 means left shift 32 bit 43} 44 45static int32_t DdkSysfsReadProperty(const char *deviceDir, const char *propName, int64_t *value, uint64_t maxVal) 46{ 47 char pathTmp[SYSFS_PATH_LEN] = {0}; 48 int32_t num = sprintf_s(pathTmp, SYSFS_PATH_LEN, "%s%s/%s", SYSFS_DEVICES_DIR, deviceDir, propName); 49 if (num <= 0) { 50 HDF_LOGE( 51 "%{public}s: sprintf_s error deviceDir:%{public}s, propName:%{public}s", __func__, deviceDir, propName); 52 return HDF_FAILURE; 53 } 54 55 // read string from file 56 char path[PATH_MAX] = {'\0'}; 57 if (realpath(pathTmp, path) == NULL) { 58 HDF_LOGE("file %{public}s is invalid", pathTmp); 59 return HDF_FAILURE; 60 } 61 int32_t fd = open(path, O_RDONLY | O_CLOEXEC); 62 if (fd == -1) { 63 HDF_LOGE("%{public}s: open file failed path:%{public}s, errno:%{public}d", __func__, path, errno); 64 return HDF_ERR_IO; 65 } 66 67 int32_t ret = HDF_SUCCESS; 68 do { 69 char buf[PROPERTY_MAX_LEN] = {0}; 70 ssize_t numRead = read(fd, buf, PROPERTY_MAX_LEN); 71 if (numRead <= 0) { 72 HDF_LOGE("%{public}s: read prop failed path:%{public}s, errno:%{public}d", __func__, path, errno); 73 ret = HDF_ERR_IO; 74 break; 75 } 76 77 // convert string to int64_t 78 if (buf[numRead - 1] != '\n') { 79 HDF_LOGE("%{public}s: prop is not end with newline path:%{public}s", __func__, path); 80 ret = HDF_ERR_INVALID_PARAM; 81 break; 82 } 83 84 buf[numRead - 1] = '\0'; 85 int64_t res = strtoll(buf, NULL, DdkSysfsGetBase(propName)); 86 if (res == LLONG_MAX || res == LLONG_MIN || res > (int64_t)maxVal) { 87 HDF_LOGE("%{public}s: convert failed path:%{public}s, res:%{public}" PRId64 "", __func__, path, res); 88 ret = HDF_ERR_INVALID_PARAM; 89 break; 90 } 91 92 *value = res; 93 } while (0); 94 95 close(fd); 96 return ret; 97} 98 99static int32_t DdkSysfsGetInterface( 100 const char *deviceDir, const char *intfDir, struct UsbPnpNotifyInterfaceInfo * const intf) 101{ 102 char intfPath[SYSFS_PATH_LEN] = {0}; 103 int32_t num = sprintf_s(intfPath, SYSFS_PATH_LEN, "%s/%s", deviceDir, intfDir); 104 if (num <= 0) { 105 HDF_LOGE("%{public}s: sprintf_s error intfDir:%{public}s", __func__, intfDir); 106 return HDF_FAILURE; 107 } 108 109 int64_t value = 0; 110 int32_t ret = DdkSysfsReadProperty(intfPath, "bInterfaceClass", &value, UINT8_MAX); 111 intf->interfaceClass = (uint8_t)value; 112 ret += DdkSysfsReadProperty(intfPath, "bInterfaceSubClass", &value, UINT8_MAX); 113 intf->interfaceSubClass = (uint8_t)value; 114 ret += DdkSysfsReadProperty(intfPath, "bInterfaceProtocol", &value, UINT8_MAX); 115 intf->interfaceProtocol = (uint8_t)value; 116 ret += DdkSysfsReadProperty(intfPath, "bInterfaceNumber", &value, UINT8_MAX); 117 intf->interfaceNumber = (uint8_t)value; 118 if (ret != HDF_SUCCESS) { 119 HDF_LOGE("%{public}s: get intterface property failed", __func__); 120 return HDF_FAILURE; 121 } 122 return HDF_SUCCESS; 123} 124 125static int32_t DdkSysfsGetActiveInterfaces( 126 const char *deviceDir, uint8_t intfNum, struct UsbPnpNotifyInterfaceInfo intfs[]) 127{ 128 if (intfNum == 0) { 129 HDF_LOGW("%{public}s: infNum is zero", __func__); 130 return HDF_SUCCESS; 131 } 132 133 int64_t configValue = 0; 134 int32_t ret = DdkSysfsReadProperty(deviceDir, "bConfigurationValue", &configValue, INT8_MAX); 135 if (ret != HDF_SUCCESS) { 136 HDF_LOGE("%{public}s: get bConfigurationValue failed:%{public}d", __func__, ret); 137 return ret; 138 } 139 140 if (configValue == -1) { // unconfigure the device 141 HDF_LOGE("%{public}s: unconfigure the device", __func__); 142 return HDF_FAILURE; 143 } 144 145 char devPath[SYSFS_PATH_LEN] = {0}; 146 int32_t num = sprintf_s(devPath, SYSFS_PATH_LEN, "%s%s/", SYSFS_DEVICES_DIR, deviceDir); 147 if (num <= 0) { 148 HDF_LOGE("%{public}s: sprintf_s error deviceDir:%{public}s", __func__, deviceDir); 149 return HDF_FAILURE; 150 } 151 152 DIR *dir = opendir(devPath); 153 if (dir == NULL) { 154 HDF_LOGE("%{public}s: opendir failed sysfsDevDir:%{public}s", __func__, devPath); 155 return HDF_ERR_BAD_FD; 156 } 157 158 struct dirent *devHandle; 159 uint16_t intfIndex = 0; 160 while ((devHandle = readdir(dir)) && (intfIndex < intfNum)) { 161 // only read dir like 3-1:1.1 162 if (strncmp(devHandle->d_name, deviceDir, strlen(deviceDir)) != 0) { 163 continue; 164 } 165 166 ret = DdkSysfsGetInterface(deviceDir, devHandle->d_name, &intfs[intfIndex]); 167 if (ret != HDF_SUCCESS) { 168 HDF_LOGW("%{public}s: create device failed d_name:%{public}s", __func__, devHandle->d_name); 169 continue; 170 } 171 172 ++intfIndex; 173 } 174 closedir(dir); 175 176 if (intfIndex != intfNum) { 177 HDF_LOGE("%{public}s num error intfIndex:%{public}u, intfNum:%{public}u", __func__, intfIndex, intfNum); 178 return HDF_FAILURE; 179 } 180 return HDF_SUCCESS; 181} 182 183static int32_t DdkSysfsStandardizeDevice(struct UsbPnpNotifyMatchInfoTable * const device) 184{ 185 device->usbDevAddr = DdkSysfsMakeDevAddr(device->busNum, device->devNum); 186 return HDF_SUCCESS; 187} 188 189int32_t DdkSysfsGetDevice(const char *deviceDir, struct UsbPnpNotifyMatchInfoTable *device) 190{ 191 int64_t value = 0; 192 int32_t ret = DdkSysfsReadProperty(deviceDir, "devnum", &value, INT32_MAX); 193 device->devNum = (int32_t)value; 194 ret += DdkSysfsReadProperty(deviceDir, "busnum", &value, INT32_MAX); 195 device->busNum = (int32_t)value; 196 ret += DdkSysfsReadProperty(deviceDir, "bNumInterfaces", &value, UINT8_MAX); 197 device->numInfos = (uint8_t)value; 198 199 struct UsbPnpNotifyDeviceInfo *devInfo = &device->deviceInfo; 200 ret += DdkSysfsReadProperty(deviceDir, "idVendor", &value, UINT16_MAX); 201 devInfo->vendorId = (uint16_t)value; 202 ret += DdkSysfsReadProperty(deviceDir, "idProduct", &value, UINT16_MAX); 203 devInfo->productId = (uint16_t)value; 204 ret += DdkSysfsReadProperty(deviceDir, "bcdDevice", &value, UINT16_MAX); 205 devInfo->bcdDeviceLow = (uint16_t)value; 206 devInfo->bcdDeviceHigh = devInfo->bcdDeviceLow; 207 ret += DdkSysfsReadProperty(deviceDir, "bDeviceClass", &value, UINT8_MAX); 208 devInfo->deviceClass = (uint8_t)value; 209 ret += DdkSysfsReadProperty(deviceDir, "bDeviceSubClass", &value, UINT8_MAX); 210 devInfo->deviceSubClass = (uint8_t)value; 211 ret += DdkSysfsReadProperty(deviceDir, "bDeviceProtocol", &value, UINT8_MAX); 212 devInfo->deviceProtocol = (uint8_t)value; 213 if (ret != HDF_SUCCESS) { 214 HDF_LOGE("%{public}s: get property failed:%{public}d", __func__, ret); 215 return ret; 216 } 217 218 ret = DdkSysfsGetActiveInterfaces(deviceDir, device->numInfos, device->interfaceInfo); 219 if (ret != HDF_SUCCESS) { 220 HDF_LOGE("%{public}s: get active interfaces failed:%{public}d", __func__, ret); 221 return ret; 222 } 223 224 ret = DdkSysfsStandardizeDevice(device); 225 if (ret != HDF_SUCCESS) { 226 HDF_LOGE("%{public}s: standardize failed:%{public}d", __func__, ret); 227 return ret; 228 } 229 230 return HDF_SUCCESS; 231}