• 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     // 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(&regex, 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(&regex, inputString, 0, NULL, 0);
345     regfree(&regex);
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 }