1 /*
2 * Copyright (c) 2022-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 #include <iostream>
16 #include <sstream>
17 #include <regex>
18
19 #include "usbd_ports.h"
20 #include "hdf_base.h"
21 #include "hdf_log.h"
22 #include "usbd_function.h"
23 #include "usb_portInfo.h"
24
25 using namespace OHOS::HDI::Usb::Port;
26
27 namespace OHOS {
28 namespace HDI {
29 namespace Usb {
30 namespace V1_2 {
31 constexpr int32_t NONE = 0;
32 constexpr int32_t SUPPORT_MODE = 1;
33 constexpr int32_t STRING_PORT = 4;
34
GetInstance()35 UsbdPorts &UsbdPorts::GetInstance()
36 {
37 static UsbdPorts instance;
38 return instance;
39 }
40
UsbdPorts()41 UsbdPorts::UsbdPorts()
42 {
43 InitMap();
44 }
45
InitMap()46 void UsbdPorts::InitMap()
47 {
48 portAttributeMap_[PORT_NONE] = NONE;
49 portAttributeMap_[PORT_MODE_UFP] = static_cast<int32_t>(Port::PortMode::UFP);
50 portAttributeMap_[PORT_MODE_DFP] = static_cast<int32_t>(Port::PortMode::DFP);
51 portAttributeMap_[PORT_MODE_DRP] = static_cast<int32_t>(Port::PortMode::DRP);
52 portAttributeMap_[POWER_ROLE_SOURCE] = static_cast<int32_t>(PowerRole::SOURCE);
53 portAttributeMap_[POWER_ROLE_SINK] = static_cast<int32_t>(PowerRole::SINK);
54 portAttributeMap_[DATA_ROLE_HOST] = static_cast<int32_t>(DataRole::HOST);
55 portAttributeMap_[DATA_ROLE_DEVICE] = static_cast<int32_t>(DataRole::DEVICE);
56 portAttributeMap_[SUPPORTED_MODE] = SUPPORT_MODE;
57 }
58
setPortPath(const std::string & path)59 void UsbdPorts::setPortPath(const std::string &path)
60 {
61 path_ = path;
62 HDF_LOGI("%{public}s: port_file_path = %{public}s", __func__, path_.c_str());
63 }
64
QueryPort(int32_t & portId,int32_t & powerRole,int32_t & dataRole,int32_t & mode)65 int32_t UsbdPorts::QueryPort(int32_t &portId, int32_t &powerRole, int32_t &dataRole, int32_t &mode)
66 {
67 HDF_LOGI("%{public}s: QueryPort start", __func__);
68 if (portCacheDataMap_.empty()) {
69 std::vector<V2_0::UsbPort> portList;
70 int32_t ret = QueryPorts(portList);
71 if (ret != HDF_SUCCESS) {
72 HDF_LOGE("%{public}s: QueryPorts failed!", __func__);
73 return HDF_FAILURE;
74 }
75 }
76
77 auto usbPort = portCacheDataMap_.begin();
78 portId = usbPort->first;
79 powerRole = usbPort->second.usbPortStatus.currentPowerRole;
80 dataRole = usbPort->second.usbPortStatus.currentDataRole;
81 mode = usbPort->second.usbPortStatus.currentMode;
82 return HDF_SUCCESS;
83 }
84
QueryPorts(std::vector<V2_0::UsbPort> & portList)85 int32_t UsbdPorts::QueryPorts(std::vector<V2_0::UsbPort>& portList)
86 {
87 HDF_LOGI("%{public}s: start", __func__);
88 std::vector<std::string> portIds;
89 int32_t ret = ParseDirectory(path_, portIds, true);
90 if (ret != HDF_SUCCESS) {
91 HDF_LOGE("%{public}s: ParseDirectory failed! ret:%{public}d", __func__, ret);
92 return HDF_FAILURE;
93 }
94
95 std::lock_guard<std::mutex> lock(mutex_);
96 for (auto portId : portIds) {
97 V2_0::UsbPort usbPort;
98 if (ReadPortInfo(portId, usbPort) != HDF_SUCCESS) {
99 HDF_LOGE("%{public}s: ReadPortInfo failed! ret:%{public}d", __func__, ret);
100 return HDF_FAILURE;
101 }
102 if (!std::regex_match(portId, std::regex("^[0-9]+$"))) {
103 HDF_LOGE("%{public}s Invalid portId", __func__);
104 return HDF_FAILURE;
105 }
106 usbPort.id = std::stoi(portId);
107 portList.emplace_back(usbPort);
108 AddPort(usbPort);
109 }
110
111 return HDF_SUCCESS;
112 }
113
ParseDirectory(const std::string & path,std::vector<std::string> & portIds,bool flag)114 int32_t UsbdPorts::ParseDirectory(const std::string& path, std::vector<std::string>& portIds, bool flag)
115 {
116 HDF_LOGI("%{public}s start", __func__);
117 DIR* dir = opendir(path.c_str());
118 if (dir == nullptr) {
119 HDF_LOGE("%{public}s: directory open error! path: %{public}s", __func__, path.c_str());
120 return HDF_FAILURE;
121 }
122
123 struct dirent* entry;
124 while ((entry = readdir(dir)) != nullptr) {
125 std::string value = entry->d_name;
126 if (value == "." || value == "..") {
127 continue;
128 }
129
130 if (flag) {
131 if (ParsePortId(value) != HDF_SUCCESS) {
132 HDF_LOGE("%{public}s: Parse portid failed! ", __func__);
133 closedir(dir);
134 return HDF_FAILURE;
135 }
136 portIds.push_back(value);
137 continue;
138 }
139
140 if (!IsFileFormat(entry->d_name)) {
141 continue;
142 }
143 portIds.push_back(entry->d_name);
144 }
145 closedir(dir);
146
147 return HDF_SUCCESS;
148 }
149
IsFileFormat(const std::string & dName)150 bool UsbdPorts::IsFileFormat(const std::string& dName)
151 {
152 if (dName != "port_mode" && dName != "power_role"
153 && dName != "data_role" && dName != "supported_mode") {
154 return false;
155 }
156
157 return true;
158 }
159
ParsePortId(std::string & value)160 int32_t UsbdPorts::ParsePortId(std::string& value)
161 {
162 std::string str = value;
163 if (str.substr(0, STRING_PORT) != "port") {
164 HDF_LOGE("%{public}s: The portid node is incorrect! portId: %{public}s", __func__, str.c_str());
165 return HDF_FAILURE;
166 }
167
168 value = str.substr(STRING_PORT);
169 if (value.empty()) {
170 HDF_LOGE("%{public}s: The portid node is incorrect! portId: %{public}s", __func__, str.c_str());
171 return HDF_FAILURE;
172 }
173
174 for (size_t i = 0; i < value.size(); i++) {
175 if (value.at(i) > '9' || value.at(i) < '0') {
176 HDF_LOGE("%{public}s: this node name incorrect! portId: %{public}s.", __func__, str.c_str());
177 return HDF_FAILURE;
178 }
179 }
180
181 return HDF_SUCCESS;
182 }
183
ReadPortInfo(const std::string & portId,V2_0::UsbPort & usbPort)184 int32_t UsbdPorts::ReadPortInfo(const std::string& portId, V2_0::UsbPort& usbPort)
185 {
186 HDF_LOGI("%{public}s start", __func__);
187 std::vector<std::string> portAttributeFileList;
188 const std::string portAttributeDir = path_ + "port" + portId;
189
190 int32_t ret = ParseDirectory(portAttributeDir, portAttributeFileList, false);
191 if (ret != HDF_SUCCESS) {
192 HDF_LOGE("%{public}s: ParseDirectory failed! ret:%{public}d", __func__, ret);
193 return HDF_FAILURE;
194 }
195
196 for (auto it : portAttributeFileList) {
197 std::string portAttributeFile;
198 char buff[PATH_MAX] = {'\0'};
199
200 portAttributeFile = portAttributeDir + "/" + it;
201 int32_t fd = OpenFile(portAttributeFile, O_RDONLY);
202 if (fd < 0) {
203 HDF_LOGE("%{public}s: file open error fd = %{public}d", __func__, fd);
204 return HDF_FAILURE;
205 }
206
207 ret = read(fd, buff, PATH_MAX - 1);
208 close(fd);
209 if (ret < 0) {
210 HDF_LOGE("%{public}s: read error: %{public}s", __func__, portAttributeFile.c_str());
211 return HDF_FAILURE;
212 }
213
214 ret = ParsePortAttribute(it, buff, usbPort);
215 if (ret != HDF_SUCCESS) {
216 HDF_LOGE("%{public}s: ParsePortAttribute failed! ret:%{public}d", __func__, ret);
217 return HDF_FAILURE;
218 }
219 }
220
221 return HDF_SUCCESS;
222 }
223
OpenFile(const std::string & path,int32_t flags)224 int32_t UsbdPorts::OpenFile(const std::string& path, int32_t flags)
225 {
226 if (path.empty()) {
227 HDF_LOGE("%{public}s: The path cannot be empty", __func__);
228 return HDF_FAILURE;
229 }
230
231 char realpathStr[PATH_MAX] = {'\0'};
232 if (realpath(path.c_str(), realpathStr) == nullptr) {
233 HDF_LOGE("%{public}s : realpath failed. ret = %{public}s", __func__, strerror(errno));
234 return HDF_FAILURE;
235 }
236 return open(realpathStr, flags);
237 }
238
ParsePortAttribute(const std::string & portAttributeFileName,const std::string & buff,V2_0::UsbPort & usbPort)239 int32_t UsbdPorts::ParsePortAttribute(const std::string& portAttributeFileName,
240 const std::string& buff, V2_0::UsbPort& usbPort)
241 {
242 HDF_LOGI("%{public}s start", __func__);
243 if (portAttributeFileName == "port_mode") {
244 return GetAttributeValue(buff, usbPort.usbPortStatus.currentMode);
245 } else if (portAttributeFileName == "power_role") {
246 return GetAttributeValue(buff, usbPort.usbPortStatus.currentPowerRole);
247 } else if (portAttributeFileName == "data_role") {
248 return GetAttributeValue(buff, usbPort.usbPortStatus.currentDataRole);
249 } else if (portAttributeFileName == "supported_mode") {
250 return GetAttributeValue(buff, usbPort.supportedModes);
251 }
252
253 return HDF_SUCCESS;
254 }
255
GetAttributeValue(const std::string & buff,int32_t & outEnumValue)256 int32_t UsbdPorts::GetAttributeValue(const std::string& buff, int32_t& outEnumValue)
257 {
258 if (portAttributeMap_.find(buff) == portAttributeMap_.end()) {
259 HDF_LOGE("%{public}s: %{public}s is invalid value", __func__, buff.c_str());
260 return HDF_FAILURE;
261 }
262
263 outEnumValue = portAttributeMap_[buff];
264 return HDF_SUCCESS;
265 }
266
AddPort(const V2_0::UsbPort & port)267 void UsbdPorts::AddPort(const V2_0::UsbPort &port)
268 {
269 portCacheDataMap_[port.id] = port;
270 }
271
IsSupportedMode(int32_t portId)272 bool UsbdPorts::IsSupportedMode(int32_t portId)
273 {
274 auto it = portCacheDataMap_.find(portId);
275 if (it == portCacheDataMap_.end()) {
276 HDF_LOGE("%{public}s: portId not exist, set failed", __func__);
277 return false;
278 }
279
280 if (it->second.supportedModes == NONE) {
281 HDF_LOGE("%{public}s The mode does not support settings", __func__);
282 return false;
283 }
284
285 return true;
286 }
287
SetPort(int32_t portId,int32_t powerRole,int32_t dataRole,UsbdSubscriber * usbdSubscribers,uint32_t len)288 int32_t UsbdPorts::SetPort(int32_t portId, int32_t powerRole, int32_t dataRole,
289 UsbdSubscriber *usbdSubscribers, uint32_t len)
290 {
291 HDF_LOGI("%{public}s: SetPort start", __func__);
292 auto usbPort = portCacheDataMap_.begin();
293 if (portId != usbPort->first) {
294 HDF_LOGE("%{public}s: portId not exist, set failed", __func__);
295 return HDF_FAILURE;
296 }
297
298 if (!IsSupportedMode(portId)) {
299 return HDF_FAILURE;
300 }
301
302 V2_0::UsbPort port;
303 int32_t ret = SetPortInfo(portId, powerRole, dataRole, port);
304 if (ret != HDF_SUCCESS) {
305 HDF_LOGE("%{public}s: SetPortInfo failed", __func__);
306 return HDF_FAILURE;
307 }
308
309 for (uint32_t i = 0; i < len; i++) {
310 if (usbdSubscribers[i].subscriber != nullptr) {
311 PortInfo portInfo;
312 ReportData(port, portInfo);
313 usbdSubscribers[i].subscriber->PortChangedEvent(portInfo);
314 }
315 }
316
317 AddPort(port);
318 return HDF_SUCCESS;
319 }
320
SetPort(int32_t portId,int32_t powerRole,int32_t dataRole,V2_0::UsbdSubscriber * usbdSubscribers,uint32_t len)321 int32_t UsbdPorts::SetPort(int32_t portId, int32_t powerRole, int32_t dataRole,
322 V2_0::UsbdSubscriber *usbdSubscribers, uint32_t len)
323 {
324 HDF_LOGI("%{public}s: SetPort start", __func__);
325 if (!IsSupportedMode(portId)) {
326 return HDF_FAILURE;
327 }
328
329 V2_0::UsbPort port;
330 int32_t ret = SetPortInfo(portId, powerRole, dataRole, port);
331 if (ret != HDF_SUCCESS) {
332 HDF_LOGE("%{public}s: SetPortInfo failed", __func__);
333 return HDF_FAILURE;
334 }
335
336 for (uint32_t i = 0; i < len; i++) {
337 if (usbdSubscribers[i].subscriber != nullptr) {
338 V2_0::PortInfo portInfo;
339 ReportData(port, portInfo);
340 usbdSubscribers[i].subscriber->PortChangedEvent(portInfo);
341 }
342 }
343
344 AddPort(port);
345 return HDF_SUCCESS;
346 }
347
SetPortInfo(int32_t portId,int32_t powerRole,int32_t dataRole,V2_0::UsbPort & port)348 int32_t UsbdPorts::SetPortInfo(int32_t portId, int32_t powerRole, int32_t dataRole, V2_0::UsbPort& port)
349 {
350 if (path_ == "/data/service/el1/public/usb/mode") {
351 HDF_LOGE("%{public}s: not support", __func__);
352 return HDF_ERR_NOT_SUPPORT;
353 }
354
355 if (!IsRoleValueLegality(powerRole, dataRole)) {
356 HDF_LOGE("%{public}s: invalid powerRole or dataRole", __func__);
357 return HDF_FAILURE;
358 }
359
360 port = portCacheDataMap_[portId];
361 const std::string portIdNode = std::to_string(portId);
362 std::string data;
363 GetRoleStrValue(powerRole, data, true);
364 int32_t ret = WritePortInfo(portIdNode, "power_role", data);
365 if (ret != HDF_SUCCESS) {
366 HDF_LOGE("%{public}s: Execute WritePortInfo failed", __func__);
367 return HDF_FAILURE;
368 }
369
370 GetRoleStrValue(dataRole, data, false);
371 WritePortInfo(portIdNode, "data_role", data);
372 if (ret != HDF_SUCCESS) {
373 HDF_LOGE("%{public}s: Execute WritePortInfo failed", __func__);
374 return HDF_FAILURE;
375 }
376
377 if (portCacheDataMap_.find(portId) == portCacheDataMap_.end()) {
378 HDF_LOGE("%{public}s: portId not found", __func__);
379 return HDF_FAILURE;
380 }
381
382 port.usbPortStatus.currentPowerRole = powerRole;
383 port.usbPortStatus.currentDataRole = dataRole;
384
385 return HDF_SUCCESS;
386 }
387
IsRoleValueLegality(int32_t powerRole,int32_t dataRole)388 bool UsbdPorts::IsRoleValueLegality(int32_t powerRole, int32_t dataRole)
389 {
390 if (powerRole < (int32_t)PowerRole::NONE || powerRole >= (int32_t)PowerRole::NUM_POWER_ROLES
391 || dataRole < (int32_t)DataRole::NONE || dataRole >= (int32_t)DataRole::NUM_DATA_ROLES) {
392 return false;
393 }
394
395 return true;
396 }
397
WritePortInfo(const std::string & portId,const std::string & portAttributeFilePath,std::string & data)398 int32_t UsbdPorts::WritePortInfo(const std::string& portId, const std::string& portAttributeFilePath, std::string& data)
399 {
400 HDF_LOGI("%{public}s: start", __func__);
401 std::lock_guard<std::mutex> lock(mutex_);
402 std::string writePath = path_ + "port" + portId + "/" + portAttributeFilePath;
403
404 int32_t fd = OpenFile(writePath, O_WRONLY | O_TRUNC);
405 if (fd < 0) {
406 HDF_LOGE("%{public}s: file open error! ret:%{public}s", __func__, writePath.c_str());
407 return HDF_FAILURE;
408 }
409
410 int32_t ret = write(fd, data.c_str(), data.size());
411 close(fd);
412 if (ret <= 0) {
413 HDF_LOGE("%{public}s: write file failed! ret:%{public}d path: %{public}s",
414 __func__, ret, writePath.c_str());
415 return HDF_FAILURE;
416 }
417
418 return HDF_SUCCESS;
419 }
420
GetRoleStrValue(int32_t role,std::string & strRole,bool flag)421 void UsbdPorts::GetRoleStrValue(int32_t role, std::string& strRole, bool flag)
422 {
423 for (auto it : portAttributeMap_) {
424 if (flag) {
425 // powerRole
426 if ((it.first != POWER_ROLE_SOURCE) && (it.first != POWER_ROLE_SINK)) {
427 continue;
428 }
429 if (it.second == role) {
430 strRole = it.first;
431 break;
432 }
433 } else {
434 //dataRole
435 if ((it.first != DATA_ROLE_HOST) && (it.first != DATA_ROLE_DEVICE)) {
436 continue;
437 }
438 if (it.second == role) {
439 strRole = it.first;
440 break;
441 }
442 }
443 }
444 }
445
IsUpdate(const V2_0::UsbPort & usbPortInfo)446 bool UsbdPorts::IsUpdate(const V2_0::UsbPort& usbPortInfo)
447 {
448 HDF_LOGI("%{public}s: start", __func__);
449 if (portCacheDataMap_.find(usbPortInfo.id) == portCacheDataMap_.end()) {
450 return true;
451 }
452
453 V2_0::UsbPort usbPort = portCacheDataMap_[usbPortInfo.id];
454 if (usbPort.usbPortStatus.currentMode != usbPortInfo.usbPortStatus.currentMode
455 || usbPort.usbPortStatus.currentPowerRole != usbPortInfo.usbPortStatus.currentPowerRole
456 || usbPort.usbPortStatus.currentDataRole != usbPortInfo.usbPortStatus.currentDataRole
457 || usbPort.supportedModes != usbPortInfo.supportedModes) {
458 return true;
459 }
460
461 return false;
462 }
463
ReportData(const V2_0::UsbPort & usbPort,V2_0::PortInfo & portInfo)464 void UsbdPorts::ReportData(const V2_0::UsbPort& usbPort, V2_0::PortInfo& portInfo)
465 {
466 HDF_LOGI("%{public}s: start", __func__);
467 portInfo.portId = usbPort.id;
468 portInfo.supportedModes = usbPort.supportedModes;
469 portInfo.powerRole = usbPort.usbPortStatus.currentPowerRole;
470 portInfo.dataRole = usbPort.usbPortStatus.currentDataRole;
471 portInfo.mode = usbPort.usbPortStatus.currentMode;
472 }
473
ReportData(const V2_0::UsbPort & usbPort,PortInfo & portInfo)474 void UsbdPorts::ReportData(const V2_0::UsbPort& usbPort, PortInfo& portInfo)
475 {
476 HDF_LOGI("%{public}s: start", __func__);
477 portInfo.portId = usbPort.id;
478 portInfo.powerRole = usbPort.usbPortStatus.currentPowerRole;
479 portInfo.dataRole = usbPort.usbPortStatus.currentDataRole;
480 portInfo.mode = usbPort.usbPortStatus.currentMode;
481 }
482
UpdatePort(int32_t mode,const sptr<IUsbdSubscriber> & subscriber)483 int32_t UsbdPorts::UpdatePort(int32_t mode, const sptr<IUsbdSubscriber>& subscriber)
484 {
485 (void)mode;
486 std::vector<V2_0::UsbPort> portList;
487 int32_t ret = QueryPorts(portList);
488 if (ret != HDF_SUCCESS) {
489 HDF_LOGE("%{public}s: data update failuer", __func__);
490 return HDF_FAILURE;
491 }
492
493 for (size_t i = 0; i < portList.size(); i++) {
494 if (IsUpdate(portList.at(i))) {
495 PortInfo portInfo;
496 ReportData(portList.at(i), portInfo);
497 subscriber->PortChangedEvent(portInfo);
498 }
499 }
500
501 return HDF_SUCCESS;
502 }
503
UpdatePort(int32_t mode,const sptr<OHOS::HDI::Usb::V2_0::IUsbdSubscriber> & subscriber)504 int32_t UsbdPorts::UpdatePort(int32_t mode, const sptr<OHOS::HDI::Usb::V2_0::IUsbdSubscriber>& subscriber)
505 {
506 (void)mode;
507 std::vector<V2_0::UsbPort> portList;
508 int32_t ret = QueryPorts(portList);
509 if (ret != HDF_SUCCESS) {
510 HDF_LOGE("%{public}s: data update failuer", __func__);
511 return HDF_FAILURE;
512 }
513
514 for (size_t i = 0; i < portList.size(); i++) {
515 if (IsUpdate(portList.at(i))) {
516 V2_0::PortInfo portInfo;
517 ReportData(portList.at(i), portInfo);
518 subscriber->PortChangedEvent(portInfo);
519 }
520 }
521
522 return HDF_SUCCESS;
523 }
524 } // namespace V1_2
525 } // namespace Usb
526 } // namespace HDI
527 } // namespace OHOS
528