Relanding this change. The bug 332430 which caused this to be reverted will be addres...
[chromium-blink-merge.git] / device / hid / hid_service_linux.cc
blob04a3c160664468d68db60c74e28f4925e52ec63f
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 <libudev.h>
6 #include <stdint.h>
8 #include <string>
9 #include <vector>
11 #include "base/logging.h"
12 #include "base/platform_file.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "base/strings/string_split.h"
17 #include "device/hid/hid_connection_linux.h"
18 #include "device/hid/hid_device_info.h"
19 #include "device/hid/hid_service_linux.h"
21 namespace device {
23 namespace {
25 const char kUdevName[] = "udev";
26 const char kUdevActionAdd[] = "add";
27 const char kUdevActionRemove[] = "remove";
28 const char kHIDSubSystem[] = "hid";
30 const char kHIDID[] = "HID_ID";
31 const char kHIDName[] = "HID_NAME";
32 const char kHIDUnique[] = "HID_UNIQ";
34 } // namespace
36 HidServiceLinux::HidServiceLinux() {
37 udev_.reset(udev_new());
38 if (!udev_) {
39 LOG(ERROR) << "Failed to create udev.";
40 return;
42 monitor_.reset(udev_monitor_new_from_netlink(udev_.get(), kUdevName));
43 if (!monitor_) {
44 LOG(ERROR) << "Failed to create udev monitor.";
45 return;
47 int ret = udev_monitor_filter_add_match_subsystem_devtype(
48 monitor_.get(),
49 kHIDSubSystem,
50 NULL);
51 if (ret != 0) {
52 LOG(ERROR) << "Failed to add udev monitor filter.";
53 return;
56 ret = udev_monitor_enable_receiving(monitor_.get());
57 if (ret != 0) {
58 LOG(ERROR) << "Failed to start udev monitoring.";
59 return;
62 monitor_fd_ = udev_monitor_get_fd(monitor_.get());
63 if (monitor_fd_ <= 0) {
64 LOG(ERROR) << "Failed to start udev monitoring.";
65 return;
68 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
69 monitor_fd_,
70 true,
71 base::MessageLoopForIO::WATCH_READ,
72 &monitor_watcher_,
73 this))
74 return;
76 Enumerate();
79 scoped_refptr<HidConnection> HidServiceLinux::Connect(
80 const HidDeviceId& device_id) {
81 HidDeviceInfo device_info;
82 if (!GetDeviceInfo(device_id, &device_info))
83 return NULL;
85 ScopedUdevDevicePtr hid_device(
86 udev_device_new_from_syspath(udev_.get(), device_info.device_id.c_str()));
87 if (hid_device) {
88 return new HidConnectionLinux(device_info, hid_device.Pass());
90 return NULL;
93 void HidServiceLinux::OnFileCanReadWithoutBlocking(int fd) {
94 DCHECK_EQ(monitor_fd_, fd);
96 ScopedUdevDevicePtr dev(udev_monitor_receive_device(monitor_.get()));
97 if (!dev)
98 return;
100 std::string action(udev_device_get_action(dev.get()));
101 if (action == kUdevActionAdd) {
102 PlatformAddDevice(dev.get());
103 } else if (action == kUdevActionRemove) {
104 PlatformRemoveDevice(dev.get());
108 void HidServiceLinux::OnFileCanWriteWithoutBlocking(int fd) {}
110 HidServiceLinux::~HidServiceLinux() {
111 monitor_watcher_.StopWatchingFileDescriptor();
112 close(monitor_fd_);
115 void HidServiceLinux::Enumerate() {
116 scoped_ptr<udev_enumerate, UdevEnumerateDeleter> enumerate(
117 udev_enumerate_new(udev_.get()));
119 if (!enumerate) {
120 LOG(ERROR) << "Failed to enumerate devices.";
121 return;
124 if (udev_enumerate_add_match_subsystem(enumerate.get(), kHIDSubSystem)) {
125 LOG(ERROR) << "Failed to enumerate devices.";
126 return;
129 if (udev_enumerate_scan_devices(enumerate.get()) != 0) {
130 LOG(ERROR) << "Failed to enumerate devices.";
131 return;
134 // This list is managed by |enumerate|.
135 udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate.get());
136 for (udev_list_entry* i = devices; i != NULL;
137 i = udev_list_entry_get_next(i)) {
138 ScopedUdevDevicePtr hid_dev(
139 udev_device_new_from_syspath(udev_.get(), udev_list_entry_get_name(i)));
140 if (hid_dev) {
141 PlatformAddDevice(hid_dev.get());
146 void HidServiceLinux::PlatformAddDevice(udev_device* device) {
147 if (!device)
148 return;
150 const char* device_path = udev_device_get_syspath(device);
151 if (!device_path)
152 return;
154 HidDeviceInfo device_info;
155 device_info.device_id = device_path;
157 uint32_t int_property = 0;
158 const char* str_property = NULL;
160 const char* hid_id = udev_device_get_property_value(device, kHIDID);
161 if (!hid_id)
162 return;
164 std::vector<std::string> parts;
165 base::SplitString(hid_id, ':', &parts);
166 if (parts.size() != 3) {
167 return;
170 if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) {
171 device_info.vendor_id = int_property;
174 if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) {
175 device_info.product_id = int_property;
178 str_property = udev_device_get_property_value(device, kHIDUnique);
179 if (str_property != NULL)
180 device_info.serial_number = str_property;
182 str_property = udev_device_get_property_value(device, kHIDName);
183 if (str_property != NULL)
184 device_info.product_name = str_property;
186 AddDevice(device_info);
189 void HidServiceLinux::PlatformRemoveDevice(udev_device* raw_dev) {
190 const char* device_path = NULL;
191 device_path = udev_device_get_syspath(raw_dev);
192 if (device_path == NULL)
193 return;
194 RemoveDevice(device_path);
197 } // namespace dev