Commit 2eb0ef65 authored by Reilly Grant's avatar Reilly Grant Committed by Commit Bot

[serial] Enumerate platform serial ports

This adds code to recognize platform serial ports which aren't on a
particular bus like USB. They are identifiable because they end up in
the /devices/platform namespace.

Bug: 981483
Change-Id: I95613d57fd81a1edd060b140fd9b47f5297037b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1760986Reviewed-by: default avatarOvidio de Jesús Ruiz-Henríquez <odejesush@chromium.org>
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#688300}
parent 09fe090e
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/threading/scoped_blocking_call.h" #include "base/threading/scoped_blocking_call.h"
namespace device { namespace device {
...@@ -74,26 +75,58 @@ void SerialDeviceEnumeratorLinux::OnDeviceAdded(ScopedUdevDevicePtr device) { ...@@ -74,26 +75,58 @@ void SerialDeviceEnumeratorLinux::OnDeviceAdded(ScopedUdevDevicePtr device) {
if (!subsystem || strcmp(subsystem, kSerialSubsystem) != 0) if (!subsystem || strcmp(subsystem, kSerialSubsystem) != 0)
return; return;
const char* syspath_str = udev_device_get_syspath(device.get());
if (!syspath_str)
return;
std::string syspath(syspath_str);
// Platform serial ports.
if (base::StartsWith(syspath, "/sys/devices/platform/",
base::CompareCase::SENSITIVE)) {
CreatePort(std::move(device), syspath);
return;
}
// USB serial ports and others that have a proper bus identifier.
const char* bus = udev_device_get_property_value(device.get(), kHostBusKey);
if (bus) {
CreatePort(std::move(device), syspath);
return;
}
// Bluetooth ports are virtual TTYs but have an identifiable major number.
const char* major = udev_device_get_property_value(device.get(), kMajorKey);
if (major && base::StringPiece(major) == kRfcommMajor) {
CreatePort(std::move(device), syspath);
return;
}
}
void SerialDeviceEnumeratorLinux::OnDeviceChanged(ScopedUdevDevicePtr device) {}
void SerialDeviceEnumeratorLinux::OnDeviceRemoved(ScopedUdevDevicePtr device) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
const char* syspath = udev_device_get_syspath(device.get()); const char* syspath = udev_device_get_syspath(device.get());
if (!syspath) if (!syspath)
return; return;
auto it = paths_.find(syspath);
if (it == paths_.end())
return;
ports_.erase(it->second);
paths_.erase(it);
}
void SerialDeviceEnumeratorLinux::CreatePort(ScopedUdevDevicePtr device,
const std::string& syspath) {
const char* path = udev_device_get_property_value(device.get(), kHostPathKey); const char* path = udev_device_get_property_value(device.get(), kHostPathKey);
if (!path) if (!path)
return; return;
// TODO(rockot): There may be a better way to filter serial devices here,
// but it's not clear what that would be. Udev will list lots of virtual
// devices with no real endpoint to back them anywhere. The presence of
// a bus identifier (e.g., "pci" or "usb") seems to be a good heuristic
// for detecting actual devices.
const char* bus = udev_device_get_property_value(device.get(), kHostBusKey);
if (!bus) {
const char* major = udev_device_get_property_value(device.get(), kMajorKey);
if (!major || strcmp(major, kRfcommMajor) != 0)
return;
}
auto token = base::UnguessableToken::Create(); auto token = base::UnguessableToken::Create();
auto info = mojom::SerialPortInfo::New(); auto info = mojom::SerialPortInfo::New();
info->path = base::FilePath(path); info->path = base::FilePath(path);
...@@ -122,23 +155,4 @@ void SerialDeviceEnumeratorLinux::OnDeviceAdded(ScopedUdevDevicePtr device) { ...@@ -122,23 +155,4 @@ void SerialDeviceEnumeratorLinux::OnDeviceAdded(ScopedUdevDevicePtr device) {
paths_.insert(std::make_pair(syspath, token)); paths_.insert(std::make_pair(syspath, token));
} }
void SerialDeviceEnumeratorLinux::OnDeviceChanged(ScopedUdevDevicePtr device) {}
void SerialDeviceEnumeratorLinux::OnDeviceRemoved(ScopedUdevDevicePtr device) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
const char* syspath = udev_device_get_syspath(device.get());
if (!syspath)
return;
auto it = paths_.find(syspath);
if (it == paths_.end())
return;
ports_.erase(it->second);
paths_.erase(it);
}
} // namespace device } // namespace device
...@@ -36,6 +36,8 @@ class SerialDeviceEnumeratorLinux : public SerialDeviceEnumerator, ...@@ -36,6 +36,8 @@ class SerialDeviceEnumeratorLinux : public SerialDeviceEnumerator,
void OnDeviceRemoved(ScopedUdevDevicePtr device) override; void OnDeviceRemoved(ScopedUdevDevicePtr device) override;
private: private:
void CreatePort(ScopedUdevDevicePtr device, const std::string& syspath);
std::unique_ptr<UdevWatcher> watcher_; std::unique_ptr<UdevWatcher> watcher_;
std::map<base::UnguessableToken, mojom::SerialPortInfoPtr> ports_; std::map<base::UnguessableToken, mojom::SerialPortInfoPtr> ports_;
std::map<std::string, base::UnguessableToken> paths_; std::map<std::string, base::UnguessableToken> paths_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment