blob: d94a387c6317be41ece2951388865095be2417e7 [file] [log] [blame]
// 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_manager.h"
#include <base/logging.h>
#include <re2/re2.h>
namespace typecd {
void PortManager::OnPortAddedOrRemoved(const base::FilePath& path,
int port_num,
bool added) {
auto it = ports_.find(port_num);
if (added) {
if (it != ports_.end()) {
LOG(WARNING) << "Attempting to add an already added port.";
return;
}
ports_.emplace(port_num, std::make_unique<Port>(path, port_num));
} else {
if (it == ports_.end()) {
LOG(WARNING) << "Attempting to remove a non-existent port.";
return;
}
ports_.erase(it);
}
}
void PortManager::OnPartnerAddedOrRemoved(const base::FilePath& path,
int port_num,
bool added) {
auto it = ports_.find(port_num);
if (it == ports_.end()) {
LOG(WARNING) << "Partner add/remove attempted for non-existent port "
<< port_num;
return;
}
auto port = it->second.get();
if (added) {
port->AddPartner(path);
} else {
port->RemovePartner();
}
}
void PortManager::OnPartnerAltModeAddedOrRemoved(const base::FilePath& path,
int port_num,
bool added) {
auto it = ports_.find(port_num);
if (it == ports_.end()) {
LOG(WARNING)
<< "Partner alt mode add/remove attempted for non-existent port "
<< port_num;
return;
}
auto port = it->second.get();
port->AddRemovePartnerAltMode(path, added);
}
void PortManager::OnCableAddedOrRemoved(const base::FilePath& path,
int port_num,
bool added) {
auto it = ports_.find(port_num);
if (it == ports_.end()) {
LOG(WARNING) << "Cable add/remove attempted for non-existent port "
<< port_num;
return;
}
auto port = it->second.get();
if (added) {
port->AddCable(path);
} else {
port->RemoveCable();
}
}
void PortManager::OnCablePlugAdded(const base::FilePath& path, int port_num) {
auto it = ports_.find(port_num);
if (it == ports_.end()) {
LOG(WARNING) << "Cable plug (SOP') add attempted for non-existent port "
<< port_num;
return;
}
auto port = it->second.get();
port->AddCablePlug(path);
}
void PortManager::OnCableAltModeAdded(const base::FilePath& path,
int port_num) {
auto it = ports_.find(port_num);
if (it == ports_.end()) {
LOG(WARNING) << "Cable alt mode add attempted for non-existent port "
<< port_num;
return;
}
auto port = it->second.get();
port->AddCableAltMode(path);
}
void PortManager::OnPartnerChanged(int port_num) {
auto it = ports_.find(port_num);
if (it == ports_.end()) {
LOG(WARNING) << "Partner change detected for non-existent port "
<< port_num;
return;
}
auto port = it->second.get();
port->PartnerChanged();
}
void PortManager::RunModeEntry(int port_num) {
if (!ec_util_) {
LOG(ERROR) << "No EC Util implementation registered, mode entry aborted.";
return;
}
if (!ec_util_->ModeEntrySupported()) {
LOG(INFO) << "Mode entry not supported on this device.";
return;
}
auto it = ports_.find(port_num);
if (it == ports_.end()) {
LOG(WARNING) << "Mode entry attempted for non-existent port " << port_num;
return;
}
auto port = it->second.get();
if (port->GetDataRole() != "dfp") {
LOG(WARNING) << "Can't switch modes because data role is not DFP on port "
<< port_num;
return;
}
if (!port->IsPartnerDiscoveryComplete() ||
!port->IsCableDiscoveryComplete()) {
LOG(WARNING)
<< "Can't switch modes Partner/Cable discovery not complete for port "
<< port_num;
return;
}
// If the host supports USB4 and we can enter USB4 in this partner, do so.
if (port->CanEnterUSB4()) {
if (!ec_util_->EnterMode(port_num, TYPEC_MODE_USB4))
LOG(ERROR) << "Attempt to call Enter USB4 failed for port " << port_num;
return;
}
if (port->CanEnterTBTCompatibilityMode()) {
if (!ec_util_->EnterMode(port_num, TYPEC_MODE_TBT))
LOG(ERROR) << "Attempt to call Enter TBT failed for port " << port_num;
return;
}
if (port->CanEnterDPAltMode()) {
if (!ec_util_->EnterMode(port_num, TYPEC_MODE_DP))
LOG(ERROR) << "Attempt to call Enter DP failed for port " << port_num;
return;
}
}
} // namespace typecd