1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/events/ozone/device/udev/device_manager_udev.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/trace_event/trace_event.h"
9 #include "ui/events/ozone/device/device_event.h"
10 #include "ui/events/ozone/device/device_event_observer.h"
16 const char* const kSubsystems
[] = {
21 // Severity levels from syslog.h. We can't include it directly as it
22 // conflicts with base/logging.h
34 // Log handler for messages generated from libudev.
35 void UdevLog(struct udev
* udev
,
42 if (priority
<= SYS_LOG_ERR
)
43 LOG(ERROR
) << "libudev: " << fn
<< ": " << base::StringPrintV(format
, args
);
44 else if (priority
<= SYS_LOG_INFO
)
45 VLOG(1) << "libudev: " << fn
<< ": " << base::StringPrintV(format
, args
);
47 VLOG(2) << "libudev: " << fn
<< ": " << base::StringPrintV(format
, args
);
50 // Create libudev context.
51 device::ScopedUdevPtr
UdevCreate() {
52 struct udev
* udev
= device::udev_new();
54 device::udev_set_log_fn(udev
, UdevLog
);
55 device::udev_set_log_priority(udev
, SYS_LOG_DEBUG
);
57 return device::ScopedUdevPtr(udev
);
60 // Start monitoring input device changes.
61 device::ScopedUdevMonitorPtr
UdevCreateMonitor(struct udev
* udev
) {
62 struct udev_monitor
* monitor
=
63 device::udev_monitor_new_from_netlink(udev
, "udev");
65 for (size_t i
= 0; i
< arraysize(kSubsystems
); ++i
)
66 device::udev_monitor_filter_add_match_subsystem_devtype(
67 monitor
, kSubsystems
[i
], NULL
);
69 if (device::udev_monitor_enable_receiving(monitor
))
70 LOG(ERROR
) << "Failed to start receiving events from udev";
72 LOG(ERROR
) << "Failed to create udev monitor";
75 return device::ScopedUdevMonitorPtr(monitor
);
80 DeviceManagerUdev::DeviceManagerUdev() : udev_(UdevCreate()) {
83 DeviceManagerUdev::~DeviceManagerUdev() {
86 void DeviceManagerUdev::CreateMonitor() {
89 monitor_
= UdevCreateMonitor(udev_
.get());
91 int fd
= device::udev_monitor_get_fd(monitor_
.get());
93 base::MessageLoopForUI::current()->WatchFileDescriptor(
94 fd
, true, base::MessagePumpLibevent::WATCH_READ
, &controller_
, this);
98 void DeviceManagerUdev::ScanDevices(DeviceEventObserver
* observer
) {
101 device::ScopedUdevEnumeratePtr
enumerate(
102 device::udev_enumerate_new(udev_
.get()));
106 for (size_t i
= 0; i
< arraysize(kSubsystems
); ++i
)
107 device::udev_enumerate_add_match_subsystem(enumerate
.get(), kSubsystems
[i
]);
108 device::udev_enumerate_scan_devices(enumerate
.get());
110 struct udev_list_entry
* devices
=
111 device::udev_enumerate_get_list_entry(enumerate
.get());
112 struct udev_list_entry
* entry
;
114 udev_list_entry_foreach(entry
, devices
) {
115 device::ScopedUdevDevicePtr
device(device::udev_device_new_from_syspath(
116 udev_
.get(), device::udev_list_entry_get_name(entry
)));
120 scoped_ptr
<DeviceEvent
> event
= ProcessMessage(device
.get());
122 observer
->OnDeviceEvent(*event
.get());
126 void DeviceManagerUdev::AddObserver(DeviceEventObserver
* observer
) {
127 observers_
.AddObserver(observer
);
130 void DeviceManagerUdev::RemoveObserver(DeviceEventObserver
* observer
) {
131 observers_
.RemoveObserver(observer
);
134 void DeviceManagerUdev::OnFileCanReadWithoutBlocking(int fd
) {
135 // The netlink socket should never become disconnected. There's no need
136 // to handle broken connections here.
137 TRACE_EVENT1("evdev", "UdevDeviceChange", "socket", fd
);
139 device::ScopedUdevDevicePtr
device(
140 device::udev_monitor_receive_device(monitor_
.get()));
144 scoped_ptr
<DeviceEvent
> event
= ProcessMessage(device
.get());
147 DeviceEventObserver
, observers_
, OnDeviceEvent(*event
.get()));
150 void DeviceManagerUdev::OnFileCanWriteWithoutBlocking(int fd
) {
154 scoped_ptr
<DeviceEvent
> DeviceManagerUdev::ProcessMessage(udev_device
* device
) {
155 const char* path
= device::udev_device_get_devnode(device
);
156 const char* action
= device::udev_device_get_action(device
);
157 const char* subsystem
=
158 device::udev_device_get_property_value(device
, "SUBSYSTEM");
160 if (!path
|| !subsystem
)
163 DeviceEvent::DeviceType device_type
;
164 if (!strcmp(subsystem
, "input") &&
165 base::StartsWith(path
, "/dev/input/event", base::CompareCase::SENSITIVE
))
166 device_type
= DeviceEvent::INPUT
;
167 else if (!strcmp(subsystem
, "drm") &&
168 base::StartsWith(path
, "/dev/dri/card",
169 base::CompareCase::SENSITIVE
))
170 device_type
= DeviceEvent::DISPLAY
;
174 DeviceEvent::ActionType action_type
;
175 if (!action
|| !strcmp(action
, "add"))
176 action_type
= DeviceEvent::ADD
;
177 else if (!strcmp(action
, "remove"))
178 action_type
= DeviceEvent::REMOVE
;
179 else if (!strcmp(action
, "change"))
180 action_type
= DeviceEvent::CHANGE
;
184 return make_scoped_ptr(
185 new DeviceEvent(device_type
, action_type
, base::FilePath(path
)));