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 #include <regex.h>
24
25 #include "hdf_log.h"
26 #include "securec.h"
27 #include "usbd_wrapper.h"
28
29 #define SYSFS_PATH_LEN 128
30 #define PROPERTY_MAX_LEN 128
31 #define HDF_LOG_TAG usb_ddk_sysfs_dev
32
33 const int DEC_BASE = 10;
34 const int HEX_BASE = 16;
35
DdkSysfsGetBase(const char * propName)36 static inline int32_t DdkSysfsGetBase(const char *propName)
37 {
38 if (strcmp(propName, "idProduct") == 0 || strcmp(propName, "idVendor") == 0 ||
39 strcmp(propName, "bInterfaceNumber") == 0 || strcmp(propName, "bInterfaceProtocol") == 0 ||
40 strcmp(propName, "bInterfaceClass") == 0 || strcmp(propName, "bInterfaceSubClass") == 0) {
41 return HEX_BASE;
42 }
43 return DEC_BASE;
44 }
45
DdkSysfsMakeDevAddr(uint32_t busNum,uint32_t devNum)46 inline uint64_t DdkSysfsMakeDevAddr(uint32_t busNum, uint32_t devNum)
47 {
48 return (((uint64_t)busNum << 32) | devNum); // 32 means left shift 32 bit
49 }
50
DdkSysfsReadProperty(const char * deviceDir,const char * propName,int64_t * value,uint64_t maxVal)51 static int32_t DdkSysfsReadProperty(const char *deviceDir, const char *propName, int64_t *value, uint64_t maxVal)
52 {
53 char pathTmp[SYSFS_PATH_LEN] = {0};
54 int32_t num = sprintf_s(pathTmp, SYSFS_PATH_LEN, "%s%s/%s", SYSFS_DEVICES_DIR, deviceDir, propName);
55 if (num <= 0) {
56 HDF_LOGE(
57 "%{public}s: sprintf_s error deviceDir:%{public}s, propName:%{public}s", __func__, deviceDir, propName);
58 return HDF_FAILURE;
59 }
60
61 char normalizedPath[PATH_MAX] = {'\0'};
62 if (realpath(pathTmp, normalizedPath) == NULL) {
63 HDF_LOGE("%{public}s: failed to normalize path: %{public}s, errno: %{public}d", __func__, pathTmp, errno);
64 return HDF_FAILURE;
65 }
66 // read string from file
67 char *path = normalizedPath;
68 int32_t fd = open(path, O_RDONLY | O_CLOEXEC);
69 if (fd == -1) {
70 HDF_LOGE("%{public}s: open file failed path:%{public}s, errno:%{public}d", __func__, path, errno);
71 return HDF_ERR_IO;
72 }
73
74 int32_t ret = HDF_SUCCESS;
75 do {
76 char buf[PROPERTY_MAX_LEN] = {0};
77 ssize_t numRead = read(fd, buf, PROPERTY_MAX_LEN);
78 if (numRead <= 0) {
79 HDF_LOGE("%{public}s: read prop failed path:%{public}s, errno:%{public}d", __func__, path, errno);
80 ret = HDF_ERR_IO;
81 break;
82 }
83
84 // convert string to int64_t
85 if (buf[numRead - 1] != '\n') {
86 HDF_LOGE("%{public}s: prop is not end with newline path:%{public}s", __func__, path);
87 ret = HDF_ERR_INVALID_PARAM;
88 break;
89 }
90
91 buf[numRead - 1] = '\0';
92 int64_t res = strtoll(buf, NULL, DdkSysfsGetBase(propName));
93 if (res == LLONG_MAX || res == LLONG_MIN || res > (int64_t)maxVal) {
94 HDF_LOGE("%{public}s: convert failed path:%{public}s, res:%{public}" PRId64 "", __func__, path, res);
95 ret = HDF_ERR_INVALID_PARAM;
96 break;
97 }
98
99 *value = res;
100 } while (0);
101
102 close(fd);
103 return ret;
104 }
105
DdkSysfsGetInterface(const char * deviceDir,const char * intfDir,struct UsbPnpNotifyInterfaceInfo * const intf)106 static int32_t DdkSysfsGetInterface(
107 const char *deviceDir, const char *intfDir, struct UsbPnpNotifyInterfaceInfo * const intf)
108 {
109 char intfPath[SYSFS_PATH_LEN] = {0};
110 int32_t num = sprintf_s(intfPath, SYSFS_PATH_LEN, "%s/%s", deviceDir, intfDir);
111 if (num <= 0) {
112 HDF_LOGE("%{public}s: sprintf_s error intfDir:%{public}s", __func__, intfDir);
113 return HDF_FAILURE;
114 }
115
116 int64_t value = 0;
117 int32_t ret = DdkSysfsReadProperty(intfPath, "bInterfaceClass", &value, UINT8_MAX);
118 intf->interfaceClass = (uint8_t)value;
119 ret += DdkSysfsReadProperty(intfPath, "bInterfaceSubClass", &value, UINT8_MAX);
120 intf->interfaceSubClass = (uint8_t)value;
121 ret += DdkSysfsReadProperty(intfPath, "bInterfaceProtocol", &value, UINT8_MAX);
122 intf->interfaceProtocol = (uint8_t)value;
123 ret += DdkSysfsReadProperty(intfPath, "bInterfaceNumber", &value, UINT8_MAX);
124 intf->interfaceNumber = (uint8_t)value;
125 if (ret != HDF_SUCCESS) {
126 HDF_LOGE("%{public}s: get intterface property failed", __func__);
127 return HDF_FAILURE;
128 }
129 return HDF_SUCCESS;
130 }
131
DdkSysfsGetActiveInterfaces(const char * deviceDir,uint8_t intfNum,struct UsbPnpNotifyInterfaceInfo intfs[])132 static int32_t DdkSysfsGetActiveInterfaces(
133 const char *deviceDir, uint8_t intfNum, struct UsbPnpNotifyInterfaceInfo intfs[])
134 {
135 if (intfNum == 0) {
136 HDF_LOGW("%{public}s: infNum is zero", __func__);
137 return HDF_SUCCESS;
138 }
139
140 int64_t configValue = 0;
141 int32_t ret = DdkSysfsReadProperty(deviceDir, "bConfigurationValue", &configValue, INT8_MAX);
142 if (ret != HDF_SUCCESS) {
143 HDF_LOGE("%{public}s: get bConfigurationValue failed:%{public}d", __func__, ret);
144 return ret;
145 }
146
147 if (configValue == -1) { // unconfigure the device
148 HDF_LOGE("%{public}s: unconfigure the device", __func__);
149 return HDF_FAILURE;
150 }
151
152 char devPath[SYSFS_PATH_LEN] = {0};
153 int32_t num = sprintf_s(devPath, SYSFS_PATH_LEN, "%s%s/", SYSFS_DEVICES_DIR, deviceDir);
154 if (num <= 0) {
155 HDF_LOGE("%{public}s: sprintf_s error deviceDir:%{public}s", __func__, deviceDir);
156 return HDF_FAILURE;
157 }
158
159 DIR *dir = opendir(devPath);
160 if (dir == NULL) {
161 HDF_LOGE("%{public}s: opendir failed sysfsDevDir:%{public}s", __func__, devPath);
162 return HDF_ERR_BAD_FD;
163 }
164
165 struct dirent *devHandle;
166 uint16_t intfIndex = 0;
167 while ((devHandle = readdir(dir)) && (intfIndex < intfNum)) {
168 // only read dir like 3-1:1.1
169 if (strncmp(devHandle->d_name, deviceDir, strlen(deviceDir)) != 0) {
170 continue;
171 }
172
173 ret = DdkSysfsGetInterface(deviceDir, devHandle->d_name, &intfs[intfIndex]);
174 if (ret != HDF_SUCCESS) {
175 HDF_LOGW("%{public}s: create device failed d_name:%{public}s", __func__, devHandle->d_name);
176 continue;
177 }
178
179 ++intfIndex;
180 }
181 closedir(dir);
182
183 if (intfIndex != intfNum) {
184 HDF_LOGE("%{public}s num error intfIndex:%{public}u, intfNum:%{public}u", __func__, intfIndex, intfNum);
185 return HDF_FAILURE;
186 }
187 return HDF_SUCCESS;
188 }
189
DdkSysfsStandardizeDevice(struct UsbPnpNotifyMatchInfoTable * const device)190 static int32_t DdkSysfsStandardizeDevice(struct UsbPnpNotifyMatchInfoTable * const device)
191 {
192 device->usbDevAddr = DdkSysfsMakeDevAddr(device->busNum, device->devNum);
193 return HDF_SUCCESS;
194 }
195
DdkSysfsGetDevice(const char * deviceDir,struct UsbPnpNotifyMatchInfoTable * device)196 int32_t DdkSysfsGetDevice(const char *deviceDir, struct UsbPnpNotifyMatchInfoTable *device)
197 {
198 int64_t value = 0;
199 int32_t ret = DdkSysfsReadProperty(deviceDir, "devnum", &value, INT32_MAX);
200 device->devNum = (int32_t)value;
201 ret += DdkSysfsReadProperty(deviceDir, "busnum", &value, INT32_MAX);
202 device->busNum = (int32_t)value;
203 ret += DdkSysfsReadProperty(deviceDir, "bNumInterfaces", &value, UINT8_MAX);
204 device->numInfos = (uint8_t)value;
205
206 struct UsbPnpNotifyDeviceInfo *devInfo = &device->deviceInfo;
207 ret += DdkSysfsReadProperty(deviceDir, "idVendor", &value, UINT16_MAX);
208 devInfo->vendorId = (uint16_t)value;
209 ret += DdkSysfsReadProperty(deviceDir, "idProduct", &value, UINT16_MAX);
210 devInfo->productId = (uint16_t)value;
211 ret += DdkSysfsReadProperty(deviceDir, "bcdDevice", &value, UINT16_MAX);
212 devInfo->bcdDeviceLow = (uint16_t)value;
213 devInfo->bcdDeviceHigh = devInfo->bcdDeviceLow;
214 ret += DdkSysfsReadProperty(deviceDir, "bDeviceClass", &value, UINT8_MAX);
215 devInfo->deviceClass = (uint8_t)value;
216 ret += DdkSysfsReadProperty(deviceDir, "bDeviceSubClass", &value, UINT8_MAX);
217 devInfo->deviceSubClass = (uint8_t)value;
218 ret += DdkSysfsReadProperty(deviceDir, "bDeviceProtocol", &value, UINT8_MAX);
219 devInfo->deviceProtocol = (uint8_t)value;
220 if (ret != HDF_SUCCESS) {
221 HDF_LOGE("%{public}s: get property failed:%{public}d", __func__, ret);
222 return ret;
223 }
224
225 ret = DdkSysfsGetActiveInterfaces(deviceDir, device->numInfos, device->interfaceInfo);
226 if (ret != HDF_SUCCESS) {
227 HDF_LOGE("%{public}s: get active interfaces failed:%{public}d", __func__, ret);
228 return ret;
229 }
230
231 ret = DdkSysfsStandardizeDevice(device);
232 if (ret != HDF_SUCCESS) {
233 HDF_LOGE("%{public}s: standardize failed:%{public}d", __func__, ret);
234 return ret;
235 }
236
237 return HDF_SUCCESS;
238 }
239
DdkSysfsFindDevPath(uint32_t busNum,uint32_t devNum,char * buff,uint32_t buffSize)240 static int32_t DdkSysfsFindDevPath(uint32_t busNum, uint32_t devNum, char *buff, uint32_t buffSize)
241 {
242 if (buff == NULL || buffSize == 0) {
243 HDF_LOGE("%{public}s: invalid param", __func__);
244 return HDF_ERR_INVALID_PARAM;
245 }
246
247 int32_t ret = HDF_ERR_OUT_OF_RANGE;
248 DIR *dir = opendir(SYSFS_DEVICES_DIR);
249 if (dir == NULL) {
250 HDF_LOGE("%{public}s: opendir failed sysfsDevDir:%{public}s", __func__, SYSFS_DEVICES_DIR);
251 return HDF_ERR_BAD_FD;
252 }
253
254 struct dirent *devHandle;
255 while ((devHandle = readdir(dir)) != NULL) {
256 if ((uint32_t)strtol(devHandle->d_name, NULL, DEC_BASE) != busNum || strchr(devHandle->d_name, ':')) {
257 continue;
258 }
259 int64_t value = 0;
260 ret = DdkSysfsReadProperty(devHandle->d_name, "devnum", &value, INT32_MAX);
261 if (ret != HDF_SUCCESS) {
262 HDF_LOGE("%{public}s: retrieve devnum failed:%{public}d", __func__, ret);
263 break;
264 }
265 if ((uint32_t)value != devNum) {
266 continue;
267 }
268
269 errno_t err = strncpy_s(buff, buffSize, devHandle->d_name, buffSize - 1);
270 if (err != 0) {
271 HDF_LOGE("%{public}s: strncpy_s error for devHandle->d_name:%{public}s", __func__, devHandle->d_name);
272 break;
273 }
274
275 break;
276 }
277
278 closedir(dir);
279 return ret;
280 }
281
DdkSysfsFindIntfPath(char * deviceDir,uint8_t intfNum,char * buff,uint32_t buffSize)282 static int32_t DdkSysfsFindIntfPath(char *deviceDir, uint8_t intfNum, char *buff, uint32_t buffSize)
283 {
284 if (deviceDir == NULL || buff == NULL || buffSize == 0) {
285 HDF_LOGE("%{public}s: invalid param", __func__);
286 return HDF_ERR_INVALID_PARAM;
287 }
288
289 int32_t ret = HDF_ERR_OUT_OF_RANGE;
290 int32_t num = sprintf_s(buff, buffSize, "%s%s/", SYSFS_DEVICES_DIR, deviceDir);
291 if (num <= 0) {
292 HDF_LOGE("%{public}s: sprintf_s error deviceDir:%{public}s", __func__, deviceDir);
293 return HDF_FAILURE;
294 }
295
296 DIR *dir = opendir(buff);
297 if (dir == NULL) {
298 HDF_LOGE("%{public}s: opendir failed buff:%{public}s", __func__, buff);
299 return HDF_ERR_BAD_FD;
300 }
301
302 struct dirent *devHandle;
303 while ((devHandle = readdir(dir)) != NULL) {
304 if (strncmp(devHandle->d_name, deviceDir, strlen(deviceDir)) != 0) {
305 continue;
306 }
307
308 struct UsbPnpNotifyInterfaceInfo intf;
309 ret = DdkSysfsGetInterface(deviceDir, devHandle->d_name, &intf);
310 if (ret != HDF_SUCCESS) {
311 HDF_LOGE("%{public}s: DdkSysfsGetInterface failed:%{public}d", __func__, ret);
312 break;
313 }
314
315 if (intf.interfaceNumber != intfNum) {
316 continue;
317 }
318
319 errno_t err = strncat_s(buff, buffSize, devHandle->d_name, buffSize - strlen(buff) - 1);
320 if (err == 0) {
321 ret = HDF_SUCCESS;
322 break;
323 }
324 }
325
326 closedir(dir);
327 return ret;
328 }
329
DdkCheckProductDir(char * inputString)330 static bool DdkCheckProductDir(char *inputString)
331 {
332 if (inputString == NULL) {
333 HDF_LOGE("%{public}s: invalid param", __func__);
334 return false;
335 }
336
337 regex_t regex;
338 const char *pattern = "^[0-9A-F]{4}:[0-9A-F]{4}:[0-9A-F]{4}\\.[0-9A-F]{4}$";
339 int32_t ret = regcomp(®ex, pattern, REG_EXTENDED);
340 if (ret != 0) {
341 HDF_LOGE("%{public}s: Could not compile regex", __func__);
342 return false;
343 }
344
345 ret = regexec(®ex, inputString, 0, NULL, 0);
346 regfree(®ex);
347 return ret == 0;
348 }
349
DdkSysfsFindDevNodeName(char * path,const char * prefix,char * buff,uint32_t buffSize)350 static int32_t DdkSysfsFindDevNodeName(char *path, const char *prefix, char *buff, uint32_t buffSize)
351 {
352 if (path == NULL || prefix == NULL || buff == NULL || buffSize == 0) {
353 HDF_LOGE("%{public}s: invalid param", __func__);
354 return HDF_ERR_INVALID_PARAM;
355 }
356
357 int32_t ret = HDF_ERR_OUT_OF_RANGE;
358 DIR *dir = opendir(path);
359 if (dir == NULL) {
360 HDF_LOGE("%{public}s: opendir failed path:%{public}s", __func__, path);
361 return HDF_ERR_BAD_FD;
362 }
363
364 struct dirent *devHandle;
365 while ((devHandle = readdir(dir)) != NULL) {
366 char *pSubStrOffset = strstr(devHandle->d_name, prefix);
367 if (pSubStrOffset != NULL && strlen(devHandle->d_name) > strlen(prefix)) {
368 errno_t err = strncpy_s(buff, buffSize, devHandle->d_name, buffSize - 1);
369 if (err != 0) {
370 HDF_LOGE("%{public}s: strncpy_s error for devHandle->d_name:%{public}s", __func__, devHandle->d_name);
371 ret = HDF_FAILURE;
372 break;
373 }
374 ret = HDF_SUCCESS;
375 break;
376 }
377
378 if (!DdkCheckProductDir(devHandle->d_name) && strcmp(devHandle->d_name, prefix) != 0) {
379 continue;
380 }
381
382 char subPath[SYSFS_PATH_LEN] = { 0x00 };
383 int32_t num = sprintf_s(subPath, sizeof(subPath), "%s/%s", path, devHandle->d_name);
384 if (num <= 0) {
385 HDF_LOGE("%{public}s: sprintf_s error devHandle->d_name:%{public}s", __func__, devHandle->d_name);
386 ret = HDF_FAILURE;
387 break;
388 }
389
390 ret = DdkSysfsFindDevNodeName(subPath, prefix, buff, buffSize);
391 if (ret != HDF_ERR_OUT_OF_RANGE) {
392 HDF_LOGI("%{public}s: subPath:%{public}s", __func__, subPath);
393 break;
394 }
395 }
396
397 closedir(dir);
398 return ret;
399 }
400
DdkSysfsGetDevNodePath(DevInterfaceInfo * devInfo,const char * prefix,char * buff,uint32_t buffSize)401 int32_t DdkSysfsGetDevNodePath(DevInterfaceInfo *devInfo, const char *prefix, char *buff, uint32_t buffSize)
402 {
403 if (devInfo == NULL || buff == NULL || buffSize == 0) {
404 HDF_LOGE("%{public}s: invalid param", __func__);
405 return HDF_ERR_INVALID_PARAM;
406 }
407
408 char devicePath[SYSFS_PATH_LEN] = { 0x00 };
409 int32_t ret = DdkSysfsFindDevPath(devInfo->busNum, devInfo->devNum, devicePath, sizeof(devicePath));
410 if (ret != HDF_SUCCESS) {
411 HDF_LOGE("%{public}s: retrieve device path failed, ret:%{public}d", __func__, ret);
412 return ret;
413 }
414 char fullPath[SYSFS_PATH_LEN] = { 0x00 };
415 ret = DdkSysfsFindIntfPath(devicePath, devInfo->intfNum, fullPath, sizeof(fullPath));
416 if (ret != HDF_SUCCESS) {
417 HDF_LOGE("%{public}s: retrieve interface path failed, ret:%{public}d", __func__, ret);
418 return ret;
419 }
420
421 HDF_LOGI("%{public}s: fullPath [%{public}s]", __func__, fullPath);
422
423 char nodeName[SYSFS_PATH_LEN] = { 0x00 };
424 ret = DdkSysfsFindDevNodeName(fullPath, prefix, nodeName, sizeof(nodeName));
425 if (ret != HDF_SUCCESS) {
426 HDF_LOGE("%{public}s: retrieve device file path failed, ret:%{public}d", __func__, ret);
427 return ret;
428 }
429
430 int32_t num = sprintf_s(buff, buffSize, "/dev/%s", nodeName);
431 if (num <= 0) {
432 HDF_LOGE("%{public}s: sprintf_s error nodeName:%{public}s", __func__, nodeName);
433 return HDF_FAILURE;
434 }
435
436 HDF_LOGI("%{public}s: devPath [%{public}s]", __func__, buff);
437 return HDF_SUCCESS;
438 }