This source file includes following definitions.
- UdevLog
- UdevCreate
- UdevCreateMonitor
- UdevEnumerateInputDevices
- ScanAndStartMonitoring
- Stop
- OnFileCanReadWithoutBlocking
- OnFileCanWriteWithoutBlocking
- StartMonitoring
- CreateDeviceManagerUdev
#include "ui/events/ozone/evdev/device_manager_udev.h"
#include <libudev.h>
#include "base/debug/trace_event.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump_ozone.h"
#include "base/strings/stringprintf.h"
#include "ui/events/ozone/evdev/device_manager_evdev.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/events/ozone/evdev/scoped_udev.h"
namespace ui {
namespace {
const char kSubsystemInput[] = "input";
enum {
SYS_LOG_EMERG = 0,
SYS_LOG_ALERT = 1,
SYS_LOG_CRIT = 2,
SYS_LOG_ERR = 3,
SYS_LOG_WARNING = 4,
SYS_LOG_NOTICE = 5,
SYS_LOG_INFO = 6,
SYS_LOG_DEBUG = 7,
};
void UdevLog(struct udev* udev,
int priority,
const char* file,
int line,
const char* fn,
const char* format,
va_list args) {
if (priority <= SYS_LOG_ERR)
LOG(ERROR) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
else if (priority <= SYS_LOG_INFO)
VLOG(1) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
else
VLOG(2) << "libudev: " << fn << ": " << base::StringPrintV(format, args);
}
scoped_udev UdevCreate() {
struct udev* udev = udev_new();
if (udev) {
udev_set_log_fn(udev, UdevLog);
udev_set_log_priority(udev, SYS_LOG_DEBUG);
}
return scoped_udev(udev);
}
scoped_udev_monitor UdevCreateMonitor(struct udev* udev) {
struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev");
if (monitor) {
udev_monitor_filter_add_match_subsystem_devtype(
monitor, kSubsystemInput, NULL);
if (udev_monitor_enable_receiving(monitor))
LOG(ERROR) << "failed to start receiving events from udev";
}
return scoped_udev_monitor(monitor);
}
bool UdevEnumerateInputDevices(struct udev* udev,
const EvdevDeviceCallback& device_callback) {
scoped_udev_enumerate enumerate(udev_enumerate_new(udev));
if (!enumerate)
return false;
udev_enumerate_add_match_subsystem(enumerate.get(), kSubsystemInput);
udev_enumerate_scan_devices(enumerate.get());
struct udev_list_entry* devices =
udev_enumerate_get_list_entry(enumerate.get());
struct udev_list_entry* entry;
udev_list_entry_foreach(entry, devices) {
const char* name = udev_list_entry_get_name(entry);
scoped_udev_device device(udev_device_new_from_syspath(udev, name));
if (!device)
continue;
const char* path = udev_device_get_devnode(device.get());
if (!path)
continue;
device_callback.Run(base::FilePath(path));
}
return true;
}
class DeviceManagerUdev : public DeviceManagerEvdev,
base::MessagePumpLibevent::Watcher {
public:
DeviceManagerUdev() {}
virtual ~DeviceManagerUdev() { Stop(); }
virtual void ScanAndStartMonitoring(const EvdevDeviceCallback& device_added,
const EvdevDeviceCallback& device_removed)
OVERRIDE {
udev_ = UdevCreate();
if (!udev_) {
LOG(ERROR) << "failed to initialize libudev";
return;
}
if (!StartMonitoring(device_added, device_removed))
LOG(ERROR) << "failed to start monitoring device changes via udev";
if (!UdevEnumerateInputDevices(udev_.get(), device_added))
LOG(ERROR) << "failed to enumerate input devices via udev";
}
virtual void Stop() OVERRIDE {
controller_.StopWatchingFileDescriptor();
device_added_.Reset();
device_removed_.Reset();
}
virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
TRACE_EVENT1("ozone", "UdevDeviceChange", "socket", fd);
scoped_udev_device device(udev_monitor_receive_device(udev_monitor_.get()));
if (!device)
return;
const char* path = udev_device_get_devnode(device.get());
const char* action = udev_device_get_action(device.get());
if (!path || !action)
return;
if (!strcmp(action, "add") || !strcmp(action, "change"))
device_added_.Run(base::FilePath(path));
else if (!strcmp(action, "remove"))
device_removed_.Run(base::FilePath(path));
}
virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE { NOTREACHED(); }
private:
bool StartMonitoring(const EvdevDeviceCallback& device_added,
const EvdevDeviceCallback& device_removed) {
udev_monitor_ = UdevCreateMonitor(udev_.get());
if (!udev_monitor_)
return false;
int fd = udev_monitor_get_fd(udev_monitor_.get());
if (fd < 0)
return false;
device_added_ = device_added;
device_removed_ = device_removed;
return base::MessagePumpOzone::Current()->WatchFileDescriptor(
fd, true, base::MessagePumpOzone::WATCH_READ, &controller_, this);
}
scoped_udev udev_;
scoped_udev_monitor udev_monitor_;
EvdevDeviceCallback device_added_;
EvdevDeviceCallback device_removed_;
base::MessagePumpLibevent::FileDescriptorWatcher controller_;
DISALLOW_COPY_AND_ASSIGN(DeviceManagerUdev);
};
}
scoped_ptr<DeviceManagerEvdev> CreateDeviceManagerUdev() {
return make_scoped_ptr<DeviceManagerEvdev>(new DeviceManagerUdev());
}
}