• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&regex, 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(&regex, inputString, 0, NULL, 0);
346     regfree(&regex);
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 }