| // Copyright 2020 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "typecd/port.h" |
| |
| #include <base/files/file_util.h> |
| #include <base/logging.h> |
| #include <base/strings/string_util.h> |
| #include <re2/re2.h> |
| |
| namespace { |
| constexpr char kDataRoleDRPRegex[] = R"(.*\[(\w+)\].*)"; |
| } // namespace |
| |
| namespace { |
| const uint16_t kDPAltModeSID = 0xff01; |
| } // namespace |
| |
| namespace typecd { |
| |
| Port::Port(const base::FilePath& syspath, int port_num) |
| : syspath_(syspath), port_num_(port_num) { |
| LOG(INFO) << "Port " << port_num_ << " enumerated."; |
| } |
| |
| void Port::AddCable(const base::FilePath& path) { |
| if (cable_) { |
| LOG(WARNING) << "Cable already exists for port " << port_num_; |
| return; |
| } |
| cable_ = std::make_unique<Cable>(path); |
| |
| LOG(INFO) << "Cable enumerated for port " << port_num_; |
| } |
| |
| void Port::RemoveCable() { |
| if (!cable_) { |
| LOG(WARNING) << "No partner present for port " << port_num_; |
| return; |
| } |
| cable_.reset(); |
| |
| LOG(INFO) << "Cable removed for port " << port_num_; |
| } |
| |
| void Port::AddPartner(const base::FilePath& path) { |
| if (partner_) { |
| LOG(WARNING) << "Partner already exists for port " << port_num_; |
| return; |
| } |
| partner_ = std::make_unique<Partner>(path); |
| |
| LOG(INFO) << "Partner enumerated for port " << port_num_; |
| } |
| |
| void Port::RemovePartner() { |
| if (!partner_) { |
| LOG(WARNING) << "No partner present for port " << port_num_; |
| return; |
| } |
| partner_.reset(); |
| |
| LOG(INFO) << "Partner removed for port " << port_num_; |
| } |
| |
| void Port::AddRemovePartnerAltMode(const base::FilePath& path, bool added) { |
| if (!partner_) { |
| LOG(WARNING) << "Trying to add alt mode for non-existent partner on port " |
| << port_num_; |
| return; |
| } |
| |
| if (added) { |
| if (!partner_->AddAltMode(path)) |
| LOG(ERROR) << "Failed to add alt mode for port " << port_num_ |
| << " at path " << path; |
| } else { |
| partner_->RemoveAltMode(path); |
| } |
| } |
| |
| std::string Port::GetDataRole() { |
| std::string data_role; |
| std::string sysfs_str; |
| auto path = syspath_.Append("data_role"); |
| |
| if (!base::ReadFileToString(path, &sysfs_str)) { |
| LOG(ERROR) << "Couldn't read sysfs path " << path; |
| goto end; |
| } |
| |
| // First check for a dual role port, in which case the current role is in |
| // box-brackets. For example: [host] device |
| if (!RE2::FullMatch(sysfs_str, kDataRoleDRPRegex, &data_role)) { |
| LOG(INFO) |
| << "Couldn't determine role, assuming DRP(Dual Role Port) for port " |
| << port_num_; |
| } |
| |
| if (data_role == "") |
| data_role = sysfs_str; |
| |
| base::TrimWhitespaceASCII(data_role, base::TRIM_ALL, &data_role); |
| |
| if (data_role != "host" && data_role != "device") |
| data_role = ""; |
| |
| end: |
| return data_role; |
| } |
| |
| bool Port::CanEnterDPAltMode() { |
| auto num_alt_modes = partner_->GetNumAltModes(); |
| for (int i = 0; i < num_alt_modes; i++) { |
| auto alt_mode = partner_->GetAltMode(i); |
| if (!alt_mode) |
| continue; |
| if (alt_mode->GetSVID() == kDPAltModeSID) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| } // namespace typecd |