Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(970)

Side by Side Diff: ui/events/ozone/evdev/event_factory.cc

Issue 150633005: evdev: Support device hotplug with udev (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add TODOs Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/events/ozone/evdev/event_factory.h ('k') | ui/events/ozone/evdev/key_event_converter.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/events/ozone/evdev/event_factory.h" 5 #include "ui/events/ozone/evdev/event_factory.h"
6 6
7 #include <errno.h>
8 #include <fcntl.h> 7 #include <fcntl.h>
9 #include <linux/input.h> 8 #include <linux/input.h>
10 #include <poll.h>
11 #include <unistd.h>
12 9
13 #if defined(USE_UDEV)
14 #include <libudev.h>
15 #endif
16
17 #include "base/callback.h"
18 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
19 #include "base/files/file_enumerator.h" 11 #include "base/files/file_enumerator.h"
20 #include "base/stl_util.h" 12 #include "base/stl_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/threading/thread_restrictions.h"
23 #include "ui/events/ozone/evdev/event_device_info.h" 13 #include "ui/events/ozone/evdev/event_device_info.h"
24 #include "ui/events/ozone/evdev/key_event_converter.h" 14 #include "ui/events/ozone/evdev/key_event_converter.h"
25 #include "ui/events/ozone/evdev/touch_event_converter.h" 15 #include "ui/events/ozone/evdev/touch_event_converter.h"
26 #include "ui/events/ozone/event_factory_ozone.h" 16
17 #if defined(USE_UDEV)
18 #include "ui/events/ozone/evdev/device_manager_udev.h"
19 #endif
27 20
28 namespace ui { 21 namespace ui {
29 22
30 namespace { 23 namespace {
31 24
32 bool IsTouchPad(const EventDeviceInfo& devinfo) { 25 bool IsTouchPad(const EventDeviceInfo& devinfo) {
33 if (!devinfo.HasEventType(EV_ABS)) 26 if (!devinfo.HasEventType(EV_ABS))
34 return false; 27 return false;
35 28
36 return devinfo.HasKeyEvent(BTN_LEFT) || devinfo.HasKeyEvent(BTN_MIDDLE) || 29 return devinfo.HasKeyEvent(BTN_LEFT) || devinfo.HasKeyEvent(BTN_MIDDLE) ||
37 devinfo.HasKeyEvent(BTN_RIGHT) || devinfo.HasKeyEvent(BTN_TOOL_FINGER); 30 devinfo.HasKeyEvent(BTN_RIGHT) || devinfo.HasKeyEvent(BTN_TOOL_FINGER);
38 } 31 }
39 32
40 bool IsTouchScreen(const EventDeviceInfo& devinfo) { 33 bool IsTouchScreen(const EventDeviceInfo& devinfo) {
41 return devinfo.HasEventType(EV_ABS) && !IsTouchPad(devinfo); 34 return devinfo.HasEventType(EV_ABS) && !IsTouchPad(devinfo);
42 } 35 }
43 36
44 #if defined(USE_UDEV) 37 class DeviceManagerManual : public DeviceManagerEvdev {
38 public:
39 DeviceManagerManual() {}
40 virtual ~DeviceManagerManual() {}
45 41
46 // Severity levels from syslog.h. We can't include it directly as it 42 // Enumerate existing devices & start watching for device changes.
47 // conflicts with base/logging.h 43 virtual void ScanAndStartMonitoring(const EvdevDeviceCallback& device_added,
48 enum { 44 const EvdevDeviceCallback& device_removed)
49 SYS_LOG_EMERG = 0, 45 OVERRIDE {
50 SYS_LOG_ALERT = 1, 46 base::FileEnumerator file_enum(base::FilePath("/dev/input"),
51 SYS_LOG_CRIT = 2, 47 false,
52 SYS_LOG_ERR = 3, 48 base::FileEnumerator::FILES,
53 SYS_LOG_WARNING = 4, 49 "event*[0-9]");
54 SYS_LOG_NOTICE = 5, 50 for (base::FilePath path = file_enum.Next(); !path.empty();
55 SYS_LOG_INFO = 6, 51 path = file_enum.Next())
56 SYS_LOG_DEBUG = 7, 52 device_added.Run(path);
53 }
57 }; 54 };
58 55
59 // Log handler for messages generated from libudev. 56 } // namespace
60 void UdevLog(struct udev* udev,
61 int priority,
62 const char* file,
63 int line,
64 const char* fn,
65 const char* format,
66 va_list args) {
67 std::string message = base::StringPrintf("libudev: %s: ", fn);
68 base::StringAppendV(&message, format, args);
69 if (priority <= SYS_LOG_ERR)
70 LOG(ERROR) << message;
71 else if (priority <= SYS_LOG_INFO)
72 VLOG(1) << message;
73 else // SYS_LOG_DEBUG
74 VLOG(2) << message;
75 }
76 57
77 // Connect to the udev daemon. 58 DeviceManagerEvdev::~DeviceManagerEvdev() {}
78 scoped_udev UdevConnect() {
79 struct udev* udev = udev_new();
80 if (udev) {
81 udev_set_log_fn(udev, UdevLog);
82 udev_set_log_priority(udev, SYS_LOG_DEBUG);
83 }
84 return scoped_udev(udev);
85 }
86
87 // Enumerate all input devices using udev. Calls device_callback per device.
88 bool UdevEnumerateInputDevices(
89 struct udev* udev,
90 base::Callback<void(const base::FilePath&)> device_callback) {
91 scoped_udev_enumerate enumerate(udev_enumerate_new(udev));
92 if (!enumerate)
93 return false;
94
95 udev_enumerate_add_match_subsystem(enumerate.get(), "input");
96 udev_enumerate_scan_devices(enumerate.get());
97
98 struct udev_list_entry* devices =
99 udev_enumerate_get_list_entry(enumerate.get());
100 struct udev_list_entry* entry;
101
102 udev_list_entry_foreach(entry, devices) {
103 const char* name = udev_list_entry_get_name(entry);
104
105 scoped_udev_device device(udev_device_new_from_syspath(udev, name));
106 if (!device)
107 continue;
108
109 const char* path = udev_device_get_devnode(device.get());
110 if (!path)
111 continue;
112
113 // Found input device node; attach.
114 device_callback.Run(base::FilePath(path));
115 }
116
117 return true;
118 }
119
120 #endif // defined(USE_UDEV)
121
122 } // namespace
123 59
124 EventFactoryEvdev::EventFactoryEvdev() {} 60 EventFactoryEvdev::EventFactoryEvdev() {}
125 61
126 EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); } 62 EventFactoryEvdev::~EventFactoryEvdev() { STLDeleteValues(&converters_); }
127 63
128 void EventFactoryEvdev::AttachInputDevice(const base::FilePath& path) { 64 void EventFactoryEvdev::AttachInputDevice(const base::FilePath& path) {
129 TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value()); 65 TRACE_EVENT1("ozone", "AttachInputDevice", "path", path.value());
130 66
131 int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK); 67 int fd = open(path.value().c_str(), O_RDONLY | O_NONBLOCK);
132 if (fd < 0) { 68 if (fd < 0) {
133 PLOG(ERROR) << "Cannot open '" << path.value(); 69 PLOG(ERROR) << "Cannot open '" << path.value();
134 return; 70 return;
135 } 71 }
136 72
137 EventDeviceInfo devinfo; 73 EventDeviceInfo devinfo;
138 if (!devinfo.Initialize(fd)) { 74 if (!devinfo.Initialize(fd)) {
139 LOG(ERROR) << "failed to get device information for " << path.value(); 75 LOG(ERROR) << "failed to get device information for " << path.value();
140 close(fd); 76 close(fd);
141 return; 77 return;
142 } 78 }
143 79
144 if (IsTouchPad(devinfo)) { 80 if (IsTouchPad(devinfo)) {
145 LOG(WARNING) << "touchpad device not supported: " << path.value(); 81 LOG(WARNING) << "touchpad device not supported: " << path.value();
146 close(fd); 82 close(fd);
147 return; 83 return;
148 } 84 }
149 85
150 // TODO(spang) Add more device types. Support hot-plugging. 86 // TODO(spang) Add more device types.
151 scoped_ptr<EventConverterEvdev> converter; 87 scoped_ptr<EventConverterEvdev> converter;
152 if (IsTouchScreen(devinfo)) 88 if (IsTouchScreen(devinfo))
153 converter.reset(new TouchEventConverterEvdev(fd, path)); 89 converter.reset(new TouchEventConverterEvdev(fd, path));
154 else if (devinfo.HasEventType(EV_KEY)) 90 else if (devinfo.HasEventType(EV_KEY))
155 converter.reset(new KeyEventConverterEvdev(fd, path, &modifiers_)); 91 converter.reset(new KeyEventConverterEvdev(fd, path, &modifiers_));
156 92
157 if (converter) { 93 if (converter) {
94 delete converters_[path];
158 converters_[path] = converter.release(); 95 converters_[path] = converter.release();
159 } else { 96 } else {
160 close(fd); 97 close(fd);
161 } 98 }
162 } 99 }
163 100
101 void EventFactoryEvdev::DetachInputDevice(const base::FilePath& path) {
102 TRACE_EVENT1("ozone", "DetachInputDevice", "path", path.value());
103 delete converters_[path];
104 converters_.erase(path);
105 }
106
164 void EventFactoryEvdev::StartProcessingEvents() { 107 void EventFactoryEvdev::StartProcessingEvents() {
165 base::ThreadRestrictions::AssertIOAllowed();
166
167 #if defined(USE_UDEV) 108 #if defined(USE_UDEV)
168 // Scan for input devices using udev. 109 // Scan for input devices using udev.
169 StartProcessingEventsUdev(); 110 device_manager_ = CreateDeviceManagerUdev();
170 #else 111 #else
171 // No udev support. Scan devices manually in /dev/input. 112 // No udev support. Scan devices manually in /dev/input.
172 StartProcessingEventsManual(); 113 device_manager_.reset(new DeviceManagerManual);
173 #endif 114 #endif
115
116 device_manager_->ScanAndStartMonitoring(
117 base::Bind(&EventFactoryEvdev::AttachInputDevice, base::Unretained(this)),
118 base::Bind(&EventFactoryEvdev::DetachInputDevice,
119 base::Unretained(this)));
174 } 120 }
175 121
176 void EventFactoryEvdev::StartProcessingEventsManual() {
177 base::FileEnumerator file_enum(base::FilePath("/dev/input"),
178 false,
179 base::FileEnumerator::FILES,
180 "event*[0-9]");
181 for (base::FilePath path = file_enum.Next(); !path.empty();
182 path = file_enum.Next())
183 AttachInputDevice(path);
184 }
185
186 #if defined(USE_UDEV)
187 void EventFactoryEvdev::StartProcessingEventsUdev() {
188 udev_ = UdevConnect();
189 if (!udev_) {
190 LOG(ERROR) << "failed to connect to udev";
191 return;
192 }
193 if (!UdevEnumerateInputDevices(
194 udev_.get(),
195 base::Bind(&EventFactoryEvdev::AttachInputDevice,
196 base::Unretained(this))))
197 LOG(ERROR) << "failed to enumerate input devices via udev";
198 }
199 #endif
200
201 } // namespace ui 122 } // namespace ui
OLDNEW
« no previous file with comments | « ui/events/ozone/evdev/event_factory.h ('k') | ui/events/ozone/evdev/key_event_converter.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698