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