blob: 1d946b7b6dfe6433c8c1df4c6ddf0eb0eeaed660 [file] [log] [blame]
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TYPECD_PORT_H_
#define TYPECD_PORT_H_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/cancelable_callback.h>
#include <dbus/typecd/dbus-constants.h>
#include <gtest/gtest_prod.h>
#include "typecd/cable.h"
#include "typecd/ec_util.h"
#include "typecd/partner.h"
namespace typecd {
// Possible return values for the various CanEnter*() Mode entry checks.
enum class ModeEntryResult {
kSuccess = 0,
kCableError = 1,
kPartnerError = 2,
kPortError = 3,
kMaxValue = kPortError,
};
// Possible data roles for the port.
enum class DataRole {
kNone = 0,
kDevice = 1,
kHost = 2,
kMaxValue = kHost,
};
// Possible power roles for the port.
enum class PowerRole {
kNone = 0,
kSink = 1,
kSource = 2,
kMaxValue = kSource,
};
// Panel surface of the system's physical housing the port resides on.
// The enum order is based on Section 6.1.8 (_PLD) of ACPI Spec v6.3.
enum class Panel {
kTop = 0,
kBottom = 1,
kLeft = 2,
kRight = 3,
kFront = 4,
kBack = 5,
kUnknown = 6,
kMaxValue = kUnknown,
};
// Horizontal position of the port on its panel. This enum order is based on the
// physical_location kernel driver.
enum class HorizontalPosition {
kLeft = 0,
kCenter = 1,
kRight = 2,
kUnknown = 3,
kMaxValue = kUnknown,
};
// Vertical position of the port on its panel. This enum order is based on the
// physical_location kernel driver.
enum class VerticalPosition {
kUpper = 0,
kCenter = 1,
kLower = 2,
kUnknown = 3,
kMaxValue = kUnknown,
};
// This class is used to represent a Type C Port. It can be used to access PD
// state associated with the port, and will also contain handles to the object
// representing a peripheral (i.e "Partner") if one is connected to the port.
class Port {
public:
static std::unique_ptr<Port> CreatePort(const base::FilePath& syspath);
Port(const base::FilePath& syspath, int port_num);
virtual ~Port() = default;
void AddPartner(const base::FilePath& path);
void RemovePartner();
bool HasPartner();
void AddCable(const base::FilePath& path);
void RemoveCable();
void AddCablePlug(const base::FilePath& path);
// Add/remove an alternate mode for the partner.
void AddRemovePartnerAltMode(const base::FilePath& path, bool added);
// Add/remove an alternate mode for the partner.
virtual void AddRemovePartnerPowerProfile(bool added);
void AddCableAltMode(const base::FilePath& path);
void PartnerChanged();
void PortChanged();
void SetCurrentMode(TypeCMode mode) { current_mode_ = mode; }
TypeCMode GetCurrentMode() { return current_mode_; }
void SetActiveStateOnModeEntry(bool state) {
user_active_on_mode_entry_ = state;
}
bool GetActiveStateOnModeEntry() { return user_active_on_mode_entry_; }
void SetECUtil(ECUtil* ec_util) { ec_util_ = ec_util; }
// Returns a list of alternate modes supported by the partner or cable.
std::vector<AltMode*> GetAltModes(uint32_t recipient);
// Returns the discover identity response of the partner or cable.
std::vector<uint32_t> GetIdentity(uint32_t recipient);
// Returns the USB PD revision of the partner or cable.
PDRevision GetPDRevision(uint32_t recipient);
// Returns the current data role for the port.
virtual DataRole GetDataRole();
// Returns the current power role for the port.
virtual PowerRole GetPowerRole();
// Returns the panel that the port is located at.
virtual Panel GetPanel();
// Returns horizontal position on the panel the port is located at.
virtual HorizontalPosition GetHorizontalPosition();
// Returns vertical position on the panel the port is located at.
virtual VerticalPosition GetVerticalPosition();
// Configure whether the port supports USB4 (and by extension, TBT Compat)
// mode.
void SetSupportsUSB4(bool enable) { supports_usb4_ = enable; }
// Check whether we can enter DP Alt Mode. This should check for the presence
// of required attributes on the partner and cable. |invalid_cable_flag| is an
// optional argument which will be set to true if the partner supports mode
// entry and the cable may not be able to drive a display.
virtual bool CanEnterDPAltMode(bool* invalid_cable_flag);
// Check whether we can enter Thunderbolt Compatibility Alt Mode. This should
// check for the presence of required attributes on the Partner and
// (if applicable) Cable.
virtual ModeEntryResult CanEnterTBTCompatibilityMode();
// Returns whether the partner can enter USB4. This should check the following
// attributes for USB4 support:
// - Partner(SOP) PD identity.
// - Cable speed.
// - Cable type.
virtual ModeEntryResult CanEnterUSB4();
// Returns true when all PD discovery information (PD Identity VDOs, all
// Discover Mode data) for a partner has been processed.
//
// NOTE: Any mode entry decision logic should only run if this function
// returns true.
virtual bool IsPartnerDiscoveryComplete();
// Returns true when the partner reports PD support, and false otherwise.
virtual bool PartnerSupportsPD();
// Return true when all PD discovery information (PD Identity VDOs, all
// Discover Mode data) for a cable has been processed.
//
// NOTE: Any mode entry decision logic should only run if this function
// returns true.
virtual bool IsCableDiscoveryComplete();
// Returns true if the port's partner supports a higher USB gen than the
// cable.
virtual bool CableLimitingUSBSpeed(bool tbt3_alt_mode);
// Enqueue metrics reporting task with a delay to give time for PD
// negotiation.
void EnqueueMetricsTask(Metrics* metrics, bool mode_entry_supported);
// Cancel enqueued metrics task.
void CancelMetricsTask();
// Configure whether the port is driving a display.
void SetIsDisplayConnected(bool is_display_connected) {
is_display_connected_ = is_display_connected;
}
// Return true if there's any indication that
// connected device uses a captive cable or a plug.
bool IsCaptiveCableConnected();
private:
friend class MetricsTest;
friend class PortTest;
FRIEND_TEST(MetricsTest, CheckDpSuccessMetric);
FRIEND_TEST(PortTest, BasicAdd);
FRIEND_TEST(PortTest, DPAltModeEntryCheckTrue);
FRIEND_TEST(PortTest, DPAltModeEntryCheckFalseWithDPSID);
FRIEND_TEST(PortTest, DPAltModeEntryCheckFalse);
FRIEND_TEST(PortTest, DPAltModeEntryCheckTrueOneAltModeIsNullptr);
FRIEND_TEST(PortTest, DPAltModeEntryCheckPartnerIsReceptacle);
FRIEND_TEST(PortTest, DPAltModeEntryCalDigitTBT4ToDisplay);
FRIEND_TEST(PortTest, DPAltModeEntryAnkerUsb3Gen2ToDisplay);
FRIEND_TEST(PortTest, DPAltModeEntryHPUsb3Gen1ToDisplay);
FRIEND_TEST(PortTest, DPAltModeEntryAppleTBT3ToDisplay);
FRIEND_TEST(PortTest, DPAltModeEntryUnbrandedUSB2ToDisplay);
FRIEND_TEST(PortTest, DPAltModeEntryNekteckUSB2ToDisplay);
FRIEND_TEST(PortTest, DPAltModeEntryTBT3ToDock);
FRIEND_TEST(PortTest, DPAltModeEntryUnbrandedUSB2ToDock);
FRIEND_TEST(PortTest, DPAltModeEntryNekteckUSB2ToDock);
FRIEND_TEST(PortTest, DPAltModeEntryBelkinTBT3ToDock);
FRIEND_TEST(PortTest, DPAltModeEntryCableMattersDock);
FRIEND_TEST(PortTest, TBTCompatibilityModeEntryCheckTrueStartech);
FRIEND_TEST(PortTest, TBTCompatibilityModeEntryCheckFalseStartech);
FRIEND_TEST(PortTest, TBTCompatibilityModeEntryCheckTrueWD19TB);
FRIEND_TEST(PortTest, USB4EntryTrueGatkexPassiveTBT3Cable);
FRIEND_TEST(PortTest, USB4EntryTrueGatkexPassiveNonTBT3Cable);
FRIEND_TEST(PortTest, USB4EntryFalseGatkexPassiveNonTBT3Cable);
FRIEND_TEST(PortTest, USB4EntryFalseGatkexActiveTBT3Cable);
FRIEND_TEST(PortTest, USB4EntryTrueOWCAnker3p2Gen2Cable);
FRIEND_TEST(PortTest, USB4EntryTrueGatkexAppleTBT3ProCable);
FRIEND_TEST(PortTest, USB4EntryFalseTargusDV4KTargus3p2Gen2Cable);
FRIEND_TEST(PortTest, USB4EntryFalseTargus180Targus3p1Gen1Cable);
FRIEND_TEST(PortTest, USB4ToTBT);
FRIEND_TEST(PortTest, USB4ToDPAltMode);
FRIEND_TEST(PortTest, USB4LimitedByCableFalse);
FRIEND_TEST(PortTest, USB4LimitedByCableTrue);
FRIEND_TEST(PortTest, USB4LimitedByTBT3PassiveCableFalse);
FRIEND_TEST(PortTest, USB4LimitedByTBT4PassiveLRDCableFalse);
FRIEND_TEST(PortTest, BillboardOnlyDisplayNotLimitedByCable);
FRIEND_TEST(PortTest, CableLimitingSpeedTBT4DockAppleTBT3ProCable);
FRIEND_TEST(PortTest, TBTCableLimitingSpeedTBT3DockFalse);
FRIEND_TEST(PortTest, TBTCableLimitingSpeedTBT3DockTrue);
FRIEND_TEST(PortTest, TBTCableLimitingSpeedTBT3DockFalseTBT3Cable);
FRIEND_TEST(PortTest, CaptiveCableFalse);
FRIEND_TEST(PortTest, CaptiveCableTrueCableVDO);
FRIEND_TEST(PortTest, CaptiveCableTrueIdHeaderVDO);
FRIEND_TEST(PortTest, CaptiveCableTrueDPAltModeVDO);
// Helper functions from test_util for defining devices used in unit tests.
friend void AddUnbrandedUSB2Cable(Port& port);
friend void AddNekteckUSB2PassiveCable(Port& port);
friend void AddHongjuUSB3p1Gen1Cable(Port& port);
friend void AddHPUSB3p2Gen1Cable(Port& port);
friend void AddAnkerUSB3p2Gen2Cable(Port& port);
friend void AddCableMatters20GbpsCable(Port& port);
friend void AddUnbrandedTBT3Cable(Port& port);
friend void AddBelkinTBT3PassiveCable(Port& port);
friend void AddBelkinTBT3ActiveCable(Port& port);
friend void AddAppleTBT3ProCable(Port& port);
friend void AddCalDigitTBT4Cable(Port& port);
friend void AddCableMattersTBT4LRDCable(Port& port);
friend void AddStartech40GbpsCable(Port& port);
friend void AddTargusUSB3p2Gen2Cable(Port& port);
friend void AddTargusUSB3p1Gen1Cable(Port& port);
friend void AddCableMattersDock(Port& port);
friend void AddDellWD19TBDock(Port& port);
friend void AddStartechDock(Port& port);
friend void AddStartechTB3DK2DPWDock(Port& port);
friend void AddThinkpadTBT3Dock(Port& port);
friend void AddIntelUSB4GatkexCreekDock(Port& port);
friend void AddOWCTBT4Dock(Port& port);
friend void AddWimaxitDisplay(Port& port);
friend void AddTargusDV4KDock(Port& port);
friend void AddTargus180Dock(Port& port);
bool IsPartnerAltModePresent(uint16_t altmode_sid);
bool IsCableAltModePresent(uint16_t altmode_sid);
// Reads the current port data role from sysfs and stores it in |data_role_|.
void ParseDataRole();
// Reads the current port power role from sysfs and stores it in
// |power_role_|.
void ParsePowerRole();
// Reads port physical location from sysfs and stores its fields.
void ParsePhysicalLocation();
// Calls the |partner_|'s metrics reporting function, if a |partner_| is
// registered.
void ReportPartnerMetrics(Metrics* metrics);
// Calls the |cable_|'s metrics reporting function, if a |cable_| is
// registered.
void ReportCableMetrics(Metrics* metrics);
// Reports port level metrics.
void ReportPortMetrics(Metrics* metrics);
// Function which provides the DpSuccess metric for the port.
// This function is separated from the ReportDpMetric wrapper
// to facilitate unit testing (since we don't need a Metrics object
// pointer)
bool GetDpEntryState(DpSuccessMetric& result);
// Reports whether DP alt mode was successfully entered on a system.
// NOTE: This only generates a valid metric on AMD systems (other systems
// don't use HPD GPIO signalling from the EC).
void ReportDpMetric(Metrics* metrics);
// Reports all metrics.
virtual void ReportMetrics(Metrics* metrics, bool mode_entry_supported);
// Sysfs path used to access partner PD information.
base::FilePath syspath_;
// Port number as described by the Type C connector class framework.
int port_num_;
std::unique_ptr<Cable> cable_;
std::unique_ptr<Partner> partner_;
// Tracks the user active state when a mode was last entered.
bool user_active_on_mode_entry_;
TypeCMode current_mode_;
// Field which tracks whether port metrics have been reported. This
// prevents duplicate reporting.
bool metrics_reported_;
// Indicates whether the port supports USB4 entry.
bool supports_usb4_;
DataRole data_role_;
PowerRole power_role_;
// Physical location of the port.
Panel panel_;
HorizontalPosition horizontal_position_;
VerticalPosition vertical_position_;
// Indicates whether the port is driving a display
bool is_display_connected_;
// Cancelable callback for metrics reporting.
base::CancelableOnceClosure report_metrics_callback_;
ECUtil* ec_util_;
};
} // namespace typecd
#endif // TYPECD_PORT_H_