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