OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "ui/events/ozone/device_udev.h" |
| 6 |
| 7 #include <libudev.h> |
| 8 |
| 9 #include "base/debug/trace_event.h" |
| 10 #include "base/message_loop/message_pump_libevent.h" |
| 11 #include "base/stl_util.h" |
| 12 #include "base/strings/stringprintf.h" |
| 13 |
| 14 namespace ui { |
| 15 |
| 16 namespace { |
| 17 |
| 18 // Severity levels from syslog.h. We can't include it directly as it |
| 19 // conflicts with base/logging.h |
| 20 enum { |
| 21 SYS_LOG_EMERG = 0, |
| 22 SYS_LOG_ALERT = 1, |
| 23 SYS_LOG_CRIT = 2, |
| 24 SYS_LOG_ERR = 3, |
| 25 SYS_LOG_WARNING = 4, |
| 26 SYS_LOG_NOTICE = 5, |
| 27 SYS_LOG_INFO = 6, |
| 28 SYS_LOG_DEBUG = 7, |
| 29 }; |
| 30 |
| 31 // Log handler for messages generated from libudev. |
| 32 void UdevLog(struct udev* udev, |
| 33 int priority, |
| 34 const char* file, |
| 35 int line, |
| 36 const char* fn, |
| 37 const char* format, |
| 38 va_list args) { |
| 39 if (priority <= SYS_LOG_ERR) |
| 40 LOG(ERROR) << "libudev: " << fn << ": " << base::StringPrintV(format, args); |
| 41 else if (priority <= SYS_LOG_INFO) |
| 42 VLOG(1) << "libudev: " << fn << ": " << base::StringPrintV(format, args); |
| 43 else // SYS_LOG_DEBUG |
| 44 VLOG(2) << "libudev: " << fn << ": " << base::StringPrintV(format, args); |
| 45 } |
| 46 |
| 47 // Create libudev context. |
| 48 scoped_udev UdevCreate() { |
| 49 struct udev* udev = udev_new(); |
| 50 if (udev) { |
| 51 udev_set_log_fn(udev, UdevLog); |
| 52 udev_set_log_priority(udev, SYS_LOG_DEBUG); |
| 53 } |
| 54 return scoped_udev(udev); |
| 55 } |
| 56 |
| 57 // Start monitoring input device changes. |
| 58 scoped_udev_monitor UdevCreateMonitor(struct udev* udev, |
| 59 const std::string& subsystem) { |
| 60 struct udev_monitor* monitor = udev_monitor_new_from_netlink(udev, "udev"); |
| 61 if (monitor) { |
| 62 udev_monitor_filter_add_match_subsystem_devtype( |
| 63 monitor, subsystem.c_str(), NULL); |
| 64 |
| 65 if (udev_monitor_enable_receiving(monitor)) |
| 66 LOG(ERROR) << "failed to start receiving events from udev"; |
| 67 } |
| 68 |
| 69 return scoped_udev_monitor(monitor); |
| 70 } |
| 71 |
| 72 } // namespace |
| 73 |
| 74 class DeviceUdev::WatcherUdev : public base::MessagePumpLibevent::Watcher { |
| 75 public: |
| 76 WatcherUdev(MonitorUdev* monitor, scoped_udev_monitor udev_monitor); |
| 77 virtual ~WatcherUdev(); |
| 78 |
| 79 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE; |
| 80 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE; |
| 81 private: |
| 82 base::MessagePumpLibevent::FileDescriptorWatcher controller_; |
| 83 |
| 84 MonitorUdev* monitor_; // Not owned. |
| 85 scoped_udev_monitor udev_monitor_; |
| 86 |
| 87 DISALLOW_COPY_AND_ASSIGN(WatcherUdev); |
| 88 }; |
| 89 |
| 90 DeviceUdev::WatcherUdev::WatcherUdev(MonitorUdev* monitor, |
| 91 scoped_udev_monitor udev_monitor) |
| 92 : monitor_(monitor), |
| 93 udev_monitor_(udev_monitor.Pass()) { |
| 94 int fd = udev_monitor_get_fd(udev_monitor_.get()); |
| 95 CHECK_GT(fd, 0); |
| 96 base::MessageLoopForUI::current()->WatchFileDescriptor( |
| 97 fd, true, base::MessagePumpLibevent::WATCH_READ, &controller_, this); |
| 98 } |
| 99 |
| 100 DeviceUdev::WatcherUdev::~WatcherUdev() {} |
| 101 |
| 102 void DeviceUdev::WatcherUdev::OnFileCanReadWithoutBlocking(int fd) { |
| 103 // The netlink socket should never become disconnected. There's no need |
| 104 // to handle broken connections here. |
| 105 TRACE_EVENT1("ozone", "UdevDeviceChange", "socket", fd); |
| 106 |
| 107 scoped_udev_device device(udev_monitor_receive_device(udev_monitor_.get())); |
| 108 if (!device) |
| 109 return; |
| 110 |
| 111 monitor_->HandleUdevEvent(device.Pass()); |
| 112 } |
| 113 |
| 114 void DeviceUdev::WatcherUdev::OnFileCanWriteWithoutBlocking(int fd) { |
| 115 NOTREACHED(); |
| 116 } |
| 117 |
| 118 DeviceUdev::DeviceUdev() : udev_(UdevCreate()) {} |
| 119 |
| 120 DeviceUdev::~DeviceUdev() { |
| 121 STLDeleteContainerPairSecondPointers(monitors_.begin(), monitors_.end()); |
| 122 } |
| 123 |
| 124 bool DeviceUdev::RegisterDeviceMonitor(MonitorUdev* monitor, |
| 125 const std::string& subsystem) { |
| 126 scoped_udev_monitor udev_monitor = UdevCreateMonitor(udev_.get(), subsystem); |
| 127 if (!udev_monitor) |
| 128 return false; |
| 129 |
| 130 monitors_[monitor] = new WatcherUdev(monitor, udev_monitor.Pass()); |
| 131 return true; |
| 132 } |
| 133 |
| 134 void DeviceUdev::UnregisterDeviceMonitor(MonitorUdev* monitor) { |
| 135 std::map<MonitorUdev*, WatcherUdev*>::iterator it = monitors_.find(monitor); |
| 136 if (it == monitors_.end()) |
| 137 return; |
| 138 |
| 139 delete it->second; |
| 140 monitors_.erase(it); |
| 141 } |
| 142 |
| 143 bool DeviceUdev::ScanDevices(MonitorUdev* monitor, |
| 144 const std::string& subsystem) { |
| 145 scoped_udev_enumerate enumerate(udev_enumerate_new(udev_.get())); |
| 146 if (!enumerate) |
| 147 return false;; |
| 148 |
| 149 udev_enumerate_add_match_subsystem(enumerate.get(), subsystem.c_str()); |
| 150 udev_enumerate_scan_devices(enumerate.get()); |
| 151 |
| 152 struct udev_list_entry* devices = |
| 153 udev_enumerate_get_list_entry(enumerate.get()); |
| 154 struct udev_list_entry* entry; |
| 155 |
| 156 udev_list_entry_foreach(entry, devices) { |
| 157 scoped_udev_device device(udev_device_new_from_syspath( |
| 158 udev_.get(), udev_list_entry_get_name(entry))); |
| 159 if (!device) |
| 160 continue; |
| 161 |
| 162 monitor->HandleUdevEvent(device.Pass()); |
| 163 } |
| 164 |
| 165 return true; |
| 166 } |
| 167 |
| 168 } // namespace ui |
OLD | NEW |