blob: d62c7d7212291bbc51d481b779ffc3526417ce74 [file] [log] [blame]
// Copyright 2022 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/usb_monitor.h"
#include <utility>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <re2/re2.h>
namespace {
constexpr char kTypecPortUeventRegex[] = R"(TYPEC_PORT=port(\d+))";
}
namespace typecd {
void UsbMonitor::OnDeviceAddedOrRemoved(const base::FilePath& path,
bool added) {
auto key = path.BaseName().value();
auto it = devices_.find(key);
if (added) {
if (it != devices_.end()) {
LOG(WARNING) << "Attempting to add an already added usb device in "
<< path;
return;
}
std::string busnum;
std::string devnum;
if (!base::ReadFileToString(path.Append("busnum"), &busnum)) {
PLOG(ERROR) << "Failed to find busnum in " << path;
return;
}
if (!base::ReadFileToString(path.Append("devnum"), &devnum)) {
PLOG(ERROR) << "Failed to find devnum in " << path;
return;
}
devices_.emplace(
key, std::make_unique<UsbDevice>(std::stoi(busnum), std::stoi(devnum)));
std::string typec_port_uevent;
int typec_port_num;
if (base::ReadFileToString(path.Append("port/connector/uevent"),
&typec_port_uevent) &&
RE2::PartialMatch(typec_port_uevent, kTypecPortUeventRegex,
&typec_port_num)) {
GetDevice(key)->SetTypecPortNum(typec_port_num);
} else {
// Parent USB hub device's sysfs directory name.
// e.g. Parent sysfs of 2-1.5.4 would be 2-1
auto parent_key = key.substr(0, key.find("."));
// If parent USB hub device is present and has a Type C port associated,
// use the parent's Type C port number.
if (GetDevice(parent_key) != nullptr)
GetDevice(key)->SetTypecPortNum(
GetDevice(parent_key)->GetTypecPortNum());
}
} else {
if (it == devices_.end()) {
LOG(WARNING) << "Attempting to remove a non-existent usb device in "
<< path;
return;
}
devices_.erase(key);
}
}
UsbDevice* UsbMonitor::GetDevice(std::string key) {
auto it = devices_.find(key);
if (it == devices_.end())
return nullptr;
return it->second.get();
}
} // namespace typecd