typecd: Update Cable initialization
Now that SOP' plug alt modes generate udev events (thanks to a fix in
the kernel), fix the cable and cable plug registration to be more
deterministic. This is done by:
- Adding a callback for a udev add event for a cable plug (SOP'): This
gets invoked during daemon init (for pre-connected cables) and whenever
a new cable is connected.
- Adding a callback (and handling) for cable plug (SOP') alt mode add
events: These get generated any time after initial cable plug (SOP')
registration, whenever a cable plug (SOP') alt mode is added.
BUG=b:172097194
TEST=All unit tests still pass. Ensure from the typecd.log file that alt
modes for cables are getting parsed as expected on daemon init and also
on cable hotplug.
Change-Id: I04d19524b887a01e534a95b8f4c5c4498ab879af
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2600216
Tested-by: Prashant Malani <pmalani@chromium.org>
Reviewed-by: Mengqi Guo <mqg@chromium.org>
Reviewed-by: Prashant Malani <pmalani@chromium.org>
Commit-Queue: Prashant Malani <pmalani@chromium.org>
diff --git a/typecd/cable.cc b/typecd/cable.cc
index 92073b8..051f371 100644
--- a/typecd/cable.cc
+++ b/typecd/cable.cc
@@ -17,9 +17,10 @@
namespace typecd {
-void Cable::SearchForAltModes(const base::FilePath& plug_syspath) {
- base::FileEnumerator iter(plug_syspath, false,
- base::FileEnumerator::DIRECTORIES);
+void Cable::RegisterCablePlug(const base::FilePath& syspath) {
+ // Search for all alt modes which were already registered prior to daemon
+ // init.
+ base::FileEnumerator iter(syspath, false, base::FileEnumerator::DIRECTORIES);
for (auto path = iter.Next(); !path.empty(); path = iter.Next())
AddAltMode(path);
}
@@ -31,7 +32,7 @@
return false;
if (IsAltModePresent(index)) {
- LOG(ERROR) << "Alt mode already registered for syspath " << mode_syspath;
+ LOG(INFO) << "Alt mode already registered for syspath " << mode_syspath;
return false;
}
diff --git a/typecd/cable.h b/typecd/cable.h
index ed804e3..c623daa 100644
--- a/typecd/cable.h
+++ b/typecd/cable.h
@@ -21,17 +21,17 @@
// cable.
class Cable : public Peripheral {
public:
- explicit Cable(const base::FilePath& syspath) : Peripheral(syspath) {}
+ explicit Cable(const base::FilePath& syspath)
+ : Peripheral(syspath), num_alt_modes_(-1) {}
Cable(const Cable&) = delete;
Cable& operator=(const Cable&) = delete;
- // The Linux Type C connector class framework doesn't generate udev events for
- // alternate modes added to plugs. Therefore, the alternate mode addition code
- // needs to be handled a little differently from partners.
- //
- // Search |plug_syspath| for directories that follow the SOP' alternate mode
- // regex, and run the |AddAltMode| for each such path.
- void SearchForAltModes(const base::FilePath& plug_syspath);
+ // Register the contents of a cable plug (SOP') for this cable. The Linux
+ // kernel Type C connector class creates two devices for the two types of
+ // cable plugs (SOP' & SOP''). Since the Chrome OS Embedded Controller only
+ // parses SOP', we don't create a separate object for the plug and instead
+ // fold its contents into the Cable object itself.
+ void RegisterCablePlug(const base::FilePath& syspath);
// Add an alternate mode for the plug associated with the cable.
// NOTE: We currently only process SOP' plugs.
diff --git a/typecd/port.cc b/typecd/port.cc
index c07f3c7..e9eff1a 100644
--- a/typecd/port.cc
+++ b/typecd/port.cc
@@ -50,6 +50,15 @@
LOG(INFO) << "Cable removed for port " << port_num_;
}
+void Port::AddCablePlug(const base::FilePath& syspath) {
+ if (!cable_) {
+ LOG(WARNING) << "No cable present for port " << port_num_;
+ return;
+ }
+
+ cable_->RegisterCablePlug(syspath);
+}
+
void Port::AddPartner(const base::FilePath& path) {
if (partner_) {
LOG(WARNING) << "Partner already exists for port " << port_num_;
@@ -93,7 +102,10 @@
return;
}
- cable_->SearchForAltModes(path);
+ if (!cable_->AddAltMode(path)) {
+ LOG(ERROR) << "Failed to add SOP' alt mode for port " << port_num_
+ << " at path " << path;
+ }
}
void Port::PartnerChanged() {
diff --git a/typecd/port.h b/typecd/port.h
index 7577bd1..d455662 100644
--- a/typecd/port.h
+++ b/typecd/port.h
@@ -30,6 +30,8 @@
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);
diff --git a/typecd/port_manager.cc b/typecd/port_manager.cc
index 6b4f9a8..8b85c99 100644
--- a/typecd/port_manager.cc
+++ b/typecd/port_manager.cc
@@ -81,6 +81,18 @@
}
}
+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);
diff --git a/typecd/port_manager.h b/typecd/port_manager.h
index 4b7a5c7..e881e35 100644
--- a/typecd/port_manager.h
+++ b/typecd/port_manager.h
@@ -46,6 +46,7 @@
void OnCableAddedOrRemoved(const base::FilePath& path,
int port_num,
bool added) override;
+ void OnCablePlugAdded(const base::FilePath& path, int port_num) override;
void OnCableAltModeAdded(const base::FilePath& path, int port_num) override;
void OnPartnerChanged(int port_num) override;
diff --git a/typecd/test_constants.h b/typecd/test_constants.h
index f5bd50e..1561494 100644
--- a/typecd/test_constants.h
+++ b/typecd/test_constants.h
@@ -39,9 +39,9 @@
"/sys/class/typec/port0/port0-partner";
constexpr char kFakePort0CableSysPath[] = "/sys/class/typec/port0/port0-cable";
constexpr char kFakePort0SOPPrimeAltModeSysPath[] =
- "/sys/class/typec/port0/port0-cable/port0-plug0";
+ "/sys/class/typec/port0/port0-cable/port0-plug0/port0-plug0.0";
constexpr char kFakePort0SOPDoublePrimeAltModeSysPath[] =
- "/sys/class/typec/port0/port0-cable/port0-plug1";
+ "/sys/class/typec/port0/port0-cable/port0-plug1/port0-plug1.0";
} // namespace typecd
diff --git a/typecd/udev_monitor.cc b/typecd/udev_monitor.cc
index f5b91d1..a404d23 100644
--- a/typecd/udev_monitor.cc
+++ b/typecd/udev_monitor.cc
@@ -16,7 +16,8 @@
constexpr char kCableRegex[] = R"(port(\d+)-cable)";
constexpr char kPortRegex[] = R"(port(\d+))";
// TODO(pmalani): Add SOP'' support when the kernel also supports it.
-constexpr char kSOPPrimePlugAltModeRegex[] = R"(port(\d+)-plug0)";
+constexpr char kSOPPrimePlugRegex[] = R"(port(\d+)-plug0)";
+constexpr char kSOPPrimePlugAltModeRegex[] = R"(port(\d+)-plug0.(\d+))";
} // namespace
@@ -115,6 +116,8 @@
observer.OnPartnerAltModeAddedOrRemoved(path, port_num, added);
else if (RE2::FullMatch(name.value(), kCableRegex, &port_num))
observer.OnCableAddedOrRemoved(path, port_num, added);
+ else if (RE2::FullMatch(name.value(), kSOPPrimePlugRegex, &port_num))
+ observer.OnCablePlugAdded(path, port_num);
else if (RE2::FullMatch(name.value(), kSOPPrimePlugAltModeRegex,
&port_num) &&
added)
diff --git a/typecd/udev_monitor.h b/typecd/udev_monitor.h
index b57577d..d1fed9c 100644
--- a/typecd/udev_monitor.h
+++ b/typecd/udev_monitor.h
@@ -86,6 +86,12 @@
int port_num,
bool added) = 0;
+ // Callback that is executed when a cable plug (SOP') device is registered.
+ //
+ // The |path| argument refers to the sysfs device path of the cable plug
+ // (SOP'). The |port_num| argument refers to the port's index number.
+ virtual void OnCablePlugAdded(const base::FilePath& path, int port_num) = 0;
+
// Callback that is executed when a cable (SOP') alternate mode is
// registered.
//
diff --git a/typecd/udev_monitor_test.cc b/typecd/udev_monitor_test.cc
index 31344d9..479c9ec 100644
--- a/typecd/udev_monitor_test.cc
+++ b/typecd/udev_monitor_test.cc
@@ -62,6 +62,8 @@
num_cables_--;
};
+ void OnCablePlugAdded(const base::FilePath& path, int port_num) override {}
+
void OnCableAltModeAdded(const base::FilePath& path, int port_num) override {
num_cable_altmodes_++;
};