1 /*
2 * Copyright (c) 2025 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 "serial_sysfs_device.h"
17 #include <dirent.h>
18 #include <fcntl.h>
19 #include <cinttypes>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <regex.h>
24 #include <hdf_base.h>
25
26 #include "hdf_log.h"
27 #include "securec.h"
28 #include "usbd_wrapper.h"
29
30 #define SEIAL_NUMBER_NAME "serial"
31 #define SYSFS_PATH_LEN 128
32 #define PROPERTY_MAX_LEN 128
33 #define HDF_LOG_TAG usb_ddk_sysfs_dev
34
35 namespace OHOS {
36 namespace HDI {
37 namespace Usb {
38 namespace Serial {
39 namespace V1_0 {
40
41 const int32_t DEC_BASE = 10;
42 const int32_t HEX_BASE = 16;
43 const uint64_t MOVE_NUM = 32;
44
SerialGetBase(const char * propName)45 static inline int32_t SerialGetBase(const char *propName)
46 {
47 if (strcmp(propName, "idProduct") == 0 || strcmp(propName, "idVendor") == 0 ||
48 strcmp(propName, "bInterfaceNumber") == 0 || strcmp(propName, "bInterfaceProtocol") == 0 ||
49 strcmp(propName, "bInterfaceClass") == 0 || strcmp(propName, "bInterfaceSubClass") == 0) {
50 return HEX_BASE;
51 }
52 return DEC_BASE;
53 }
54
SerialMakeDevAddr(uint32_t busNum,uint32_t devNum)55 inline uint64_t SerialMakeDevAddr(uint32_t busNum, uint32_t devNum)
56 {
57 return ((static_cast<uint64_t>(busNum) << MOVE_NUM) | devNum);
58 }
59
SerialReadProperty(const char * deviceDir,const char * propName,int64_t * value,uint64_t maxVal)60 static int32_t SerialReadProperty(const char *deviceDir, const char *propName, int64_t *value, uint64_t maxVal)
61 {
62 char pathTmp[SYSFS_PATH_LEN] = {0};
63 int32_t num = 0;
64 num = sprintf_s(pathTmp, SYSFS_PATH_LEN, "%s/%s", deviceDir, propName);
65 if (num <= 0) {
66 HDF_LOGE("%{public}s: sprintf_s error deviceDir:%{public}s, propName:%{public}s",
67 __func__, deviceDir, propName);
68 return HDF_FAILURE;
69 }
70 // read string from file
71 char path[PATH_MAX] = {'\0'};
72 if (realpath(pathTmp, path) == nullptr) {
73 HDF_LOGE("file %{public}s is invalid", pathTmp);
74 return HDF_FAILURE;
75 }
76 int32_t fd = open(path, O_RDONLY | O_CLOEXEC);
77 if (fd == -1) {
78 HDF_LOGE("%{public}s: open file failed path:%{public}s, errno:%{public}d", __func__, path, errno);
79 return HDF_ERR_IO;
80 }
81 int32_t ret = HDF_SUCCESS;
82 do {
83 char buf[PROPERTY_MAX_LEN] = {0};
84 ssize_t numRead = read(fd, buf, PROPERTY_MAX_LEN);
85 if (numRead <= 0) {
86 HDF_LOGE("%{public}s: read prop failed path:%{public}s, errno:%{public}d", __func__, path, errno);
87 ret = HDF_ERR_IO;
88 break;
89 }
90 // convert string to int64_t
91 if (buf[numRead - 1] != '\n') {
92 HDF_LOGE("%{public}s: prop is not end with newline path:%{public}s", __func__, path);
93 ret = HDF_ERR_INVALID_PARAM;
94 break;
95 }
96 buf[numRead - 1] = '\0';
97 int64_t res = strtoll(buf, nullptr, SerialGetBase(propName));
98 if (res == LLONG_MAX || res == LLONG_MIN || res > (int64_t)maxVal) {
99 HDF_LOGE("%{public}s: convert failed path:%{public}s, res:%{public}" PRId64 "", __func__, path, res);
100 ret = HDF_ERR_INVALID_PARAM;
101 break;
102 }
103 *value = res;
104 } while (0);
105
106 close(fd);
107 return ret;
108 }
109
SerialGetSerialNo(const char * deviceDir)110 static std::string SerialGetSerialNo(const char *deviceDir)
111 {
112 std::string serialNo;
113 char pathTmp[SYSFS_PATH_LEN] = {0};
114 int32_t num = sprintf_s(pathTmp, SYSFS_PATH_LEN, "%s/%s", deviceDir, SEIAL_NUMBER_NAME);
115 if (num <= 0) {
116 HDF_LOGE("%{public}s: sprintf_s error deviceDir:%{public}s, propName:%{public}s",
117 __func__, deviceDir, SEIAL_NUMBER_NAME);
118 return serialNo;
119 }
120 char path[PATH_MAX] = {'\0'};
121 if (realpath(pathTmp, path) == nullptr) {
122 HDF_LOGE("file %{public}s is invalid", pathTmp);
123 return serialNo;
124 }
125 int32_t fd = open(path, O_RDONLY | O_CLOEXEC);
126 if (fd == -1) {
127 HDF_LOGE("%{public}s: open file failed path:%{public}s, errno:%{public}d", __func__, path, errno);
128 return serialNo;
129 }
130 char buf[PROPERTY_MAX_LEN] = {0};
131 do {
132 ssize_t numRead = read(fd, buf, PROPERTY_MAX_LEN);
133 if (numRead <= 0) {
134 HDF_LOGE("%{public}s: read prop failed path:%{public}s, errno:%{public}d", __func__, path, errno);
135 break;
136 }
137 if (buf[numRead - 1] != '\n') {
138 HDF_LOGE("%{public}s: prop is not end with newline path:%{public}s", __func__, path);
139 break;
140 }
141 buf[numRead - 1] = '\0';
142 serialNo = std::string(buf);
143 } while (0);
144
145 close(fd);
146 return serialNo;
147 }
148
SerialGetDevice(const char * deviceDir,struct UsbPnpNotifyMatchInfoTable * device)149 int32_t SerialGetDevice(const char *deviceDir, struct UsbPnpNotifyMatchInfoTable *device)
150 {
151 int64_t value = 0;
152 int32_t ret = SerialReadProperty(deviceDir, "devnum", &value, INT32_MAX);
153 device->devNum = static_cast<int32_t>(value);
154 ret += SerialReadProperty(deviceDir, "busnum", &value, INT32_MAX);
155 device->busNum = static_cast<int32_t>(value);
156 ret += SerialReadProperty(deviceDir, "bNumInterfaces", &value, UINT8_MAX);
157 device->numInfos = static_cast<uint8_t>(value);
158
159 struct UsbPnpNotifyDeviceInfo *devInfo = &device->deviceInfo;
160 ret += SerialReadProperty(deviceDir, "idVendor", &value, UINT16_MAX);
161 devInfo->vendorId = static_cast<uint16_t>(value);
162 ret += SerialReadProperty(deviceDir, "idProduct", &value, UINT16_MAX);
163 devInfo->productId = static_cast<uint16_t>(value);
164 ret += SerialReadProperty(deviceDir, "bcdDevice", &value, UINT16_MAX);
165 devInfo->bcdDeviceLow = static_cast<uint16_t>(value);
166 devInfo->bcdDeviceHigh = devInfo->bcdDeviceLow;
167 ret += SerialReadProperty(deviceDir, "bDeviceClass", &value, UINT8_MAX);
168 devInfo->deviceClass = static_cast<uint8_t>(value);
169 ret += SerialReadProperty(deviceDir, "bDeviceSubClass", &value, UINT8_MAX);
170 devInfo->deviceSubClass = static_cast<uint8_t>(value);
171 ret += SerialReadProperty(deviceDir, "bDeviceProtocol", &value, UINT8_MAX);
172 devInfo->deviceProtocol = static_cast<uint8_t>(value);
173 devInfo->serialNo = SerialGetSerialNo(deviceDir);
174 if (ret != HDF_SUCCESS) {
175 HDF_LOGE("%{public}s: get property failed:%{public}d", __func__, ret);
176 return ret;
177 }
178 return HDF_SUCCESS;
179 }
180
181 } // V1_0
182 } // Serial
183 } // Usb
184 } // HDI
185 } // OHOS