blob: 9a8bad9b6fd101c362e220a2ec3b7f0f0359c832 [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 "iioservice/daemon/udev_watcher.h"
#include <memory>
#include <utility>
#include <base/bind.h>
#include <brillo/udev/udev.h>
#include <brillo/udev/udev_device.h>
#include <brillo/udev/udev_monitor.h>
#include <libmems/iio_device_impl.h>
#include "iioservice/include/common.h"
namespace iioservice {
namespace {
constexpr char kSubsystemString[] = "iio";
constexpr char kDeviceTypeString[] = "iio_device";
} // namespace
// static
std::unique_ptr<UdevWatcher> UdevWatcher::Create(
UdevWatcher::Observer* observer, std::unique_ptr<brillo::Udev> udev) {
if (!observer)
return nullptr;
std::unique_ptr<UdevWatcher> watcher(
new UdevWatcher(observer, std::move(udev)));
if (!watcher->Start())
return nullptr;
return watcher;
}
UdevWatcher::UdevWatcher(UdevWatcher::Observer* observer,
std::unique_ptr<brillo::Udev> udev)
: observer_(observer), udev_(std::move(udev)) {
DCHECK(observer_);
}
bool UdevWatcher::Start() {
if (!udev_.get()) {
LOGF(ERROR) << "udev_new failed";
return false;
}
udev_monitor_ = udev_->CreateMonitorFromNetlink("udev");
if (!udev_monitor_.get()) {
LOGF(ERROR) << "udev_monitor_filter_add_match_subsystem_devtype failed";
return false;
}
if (!udev_monitor_->FilterAddMatchSubsystemDeviceType(kSubsystemString,
kDeviceTypeString)) {
LOGF(ERROR) << "udev_monitor_filter_add_match_subsystem_devtype failed";
return false;
}
if (!udev_monitor_->EnableReceiving()) {
LOGF(ERROR) << "udev_monitor_enable_receiving failed";
return false;
}
int fd = udev_monitor_->GetFileDescriptor();
if (fd < 0) {
LOGF(ERROR) << "udev_monitor_get_fd failed";
return false;
}
watcher_ = base::FileDescriptorWatcher::WatchReadable(
fd, base::BindRepeating(&UdevWatcher::OnReadable,
weak_factory_.GetWeakPtr()));
if (!watcher_) {
LOGF(ERROR) << "Failed to start watching a file descriptor";
return false;
}
return true;
}
void UdevWatcher::OnReadable() {
std::unique_ptr<brillo::UdevDevice> udev_device =
udev_monitor_->ReceiveDevice();
if (!udev_device.get()) {
LOGF(ERROR) << "udev_monitor_receive_device failed";
return;
}
const char* action = udev_device->GetAction();
if (!action) {
LOGF(ERROR) << "udev_device_get_action failed";
return;
}
if (strcmp(action, "add") == 0) {
auto id_opt =
libmems::IioDeviceImpl::GetIdFromString(udev_device->GetSysName());
if (id_opt.has_value())
observer_->OnDeviceAdded(id_opt.value());
}
}
} // namespace iioservice