OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 <libudev.h> | 5 #include <libudev.h> |
6 #include <stdint.h> | 6 #include <stdint.h> |
7 | 7 |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
| 11 #include "base/bind.h" |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "base/platform_file.h" | 13 #include "base/platform_file.h" |
13 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
14 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
15 #include "base/strings/string_piece.h" | 16 #include "base/strings/string_piece.h" |
16 #include "base/strings/string_split.h" | 17 #include "base/strings/string_split.h" |
17 #include "device/hid/hid_connection_linux.h" | 18 #include "device/hid/hid_connection_linux.h" |
18 #include "device/hid/hid_device_info.h" | 19 #include "device/hid/hid_device_info.h" |
19 #include "device/hid/hid_service_linux.h" | 20 #include "device/hid/hid_service_linux.h" |
| 21 #include "device/hid/udev_common.h" |
20 | 22 |
21 namespace device { | 23 namespace device { |
22 | 24 |
23 namespace { | 25 namespace { |
24 | 26 |
25 const char kUdevName[] = "udev"; | |
26 const char kUdevActionAdd[] = "add"; | |
27 const char kUdevActionRemove[] = "remove"; | |
28 const char kHIDSubSystem[] = "hid"; | 27 const char kHIDSubSystem[] = "hid"; |
29 | 28 |
30 const char kHIDID[] = "HID_ID"; | 29 const char kHIDID[] = "HID_ID"; |
31 const char kHIDName[] = "HID_NAME"; | 30 const char kHIDName[] = "HID_NAME"; |
32 const char kHIDUnique[] = "HID_UNIQ"; | 31 const char kHIDUnique[] = "HID_UNIQ"; |
33 | 32 |
34 } // namespace | 33 } // namespace |
35 | 34 |
36 HidServiceLinux::HidServiceLinux() { | 35 HidServiceLinux::HidServiceLinux() { |
37 udev_.reset(udev_new()); | 36 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance(); |
38 if (!udev_) { | 37 monitor->AddObserver(this); |
39 LOG(ERROR) << "Failed to create udev."; | 38 monitor->Enumerate( |
40 return; | 39 base::Bind(&HidServiceLinux::OnDeviceAdded, base::Unretained(this))); |
41 } | |
42 monitor_.reset(udev_monitor_new_from_netlink(udev_.get(), kUdevName)); | |
43 if (!monitor_) { | |
44 LOG(ERROR) << "Failed to create udev monitor."; | |
45 return; | |
46 } | |
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; | |
54 } | |
55 | |
56 ret = udev_monitor_enable_receiving(monitor_.get()); | |
57 if (ret != 0) { | |
58 LOG(ERROR) << "Failed to start udev monitoring."; | |
59 return; | |
60 } | |
61 | |
62 monitor_fd_ = udev_monitor_get_fd(monitor_.get()); | |
63 if (monitor_fd_ <= 0) { | |
64 LOG(ERROR) << "Failed to start udev monitoring."; | |
65 return; | |
66 } | |
67 | |
68 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
69 monitor_fd_, | |
70 true, | |
71 base::MessageLoopForIO::WATCH_READ, | |
72 &monitor_watcher_, | |
73 this)) | |
74 return; | |
75 | |
76 Enumerate(); | |
77 } | 40 } |
78 | 41 |
79 scoped_refptr<HidConnection> HidServiceLinux::Connect( | 42 scoped_refptr<HidConnection> HidServiceLinux::Connect( |
80 const HidDeviceId& device_id) { | 43 const HidDeviceId& device_id) { |
81 HidDeviceInfo device_info; | 44 HidDeviceInfo device_info; |
82 if (!GetDeviceInfo(device_id, &device_info)) | 45 if (!GetDeviceInfo(device_id, &device_info)) |
83 return NULL; | 46 return NULL; |
84 | 47 |
85 ScopedUdevDevicePtr hid_device( | 48 ScopedUdevDevicePtr device = |
86 udev_device_new_from_syspath(udev_.get(), device_info.device_id.c_str())); | 49 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath( |
87 if (hid_device) { | 50 device_info.device_id); |
88 return new HidConnectionLinux(device_info, hid_device.Pass()); | 51 if (device) |
89 } | 52 return new HidConnectionLinux(device_info, device.Pass()); |
90 return NULL; | 53 return NULL; |
91 } | 54 } |
92 | 55 |
93 void HidServiceLinux::OnFileCanReadWithoutBlocking(int fd) { | 56 HidServiceLinux::~HidServiceLinux() { |
94 DCHECK_EQ(monitor_fd_, fd); | 57 if (DeviceMonitorLinux::HasInstance()) |
95 | 58 DeviceMonitorLinux::GetInstance()->RemoveObserver(this); |
96 ScopedUdevDevicePtr dev(udev_monitor_receive_device(monitor_.get())); | |
97 if (!dev) | |
98 return; | |
99 | |
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()); | |
105 } | |
106 } | 59 } |
107 | 60 |
108 void HidServiceLinux::OnFileCanWriteWithoutBlocking(int fd) {} | 61 void HidServiceLinux::OnDeviceAdded(udev_device* device) { |
109 | |
110 HidServiceLinux::~HidServiceLinux() { | |
111 monitor_watcher_.StopWatchingFileDescriptor(); | |
112 close(monitor_fd_); | |
113 } | |
114 | |
115 void HidServiceLinux::Enumerate() { | |
116 scoped_ptr<udev_enumerate, UdevEnumerateDeleter> enumerate( | |
117 udev_enumerate_new(udev_.get())); | |
118 | |
119 if (!enumerate) { | |
120 LOG(ERROR) << "Failed to enumerate devices."; | |
121 return; | |
122 } | |
123 | |
124 if (udev_enumerate_add_match_subsystem(enumerate.get(), kHIDSubSystem)) { | |
125 LOG(ERROR) << "Failed to enumerate devices."; | |
126 return; | |
127 } | |
128 | |
129 if (udev_enumerate_scan_devices(enumerate.get()) != 0) { | |
130 LOG(ERROR) << "Failed to enumerate devices."; | |
131 return; | |
132 } | |
133 | |
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()); | |
142 } | |
143 } | |
144 } | |
145 | |
146 void HidServiceLinux::PlatformAddDevice(udev_device* device) { | |
147 if (!device) | 62 if (!device) |
148 return; | 63 return; |
149 | 64 |
150 const char* device_path = udev_device_get_syspath(device); | 65 const char* device_path = udev_device_get_syspath(device); |
151 if (!device_path) | 66 if (!device_path) |
152 return; | 67 return; |
| 68 const char* subsystem = udev_device_get_subsystem(device); |
| 69 if (!subsystem || strcmp(subsystem, kHIDSubSystem) != 0) |
| 70 return; |
153 | 71 |
154 HidDeviceInfo device_info; | 72 HidDeviceInfo device_info; |
155 device_info.device_id = device_path; | 73 device_info.device_id = device_path; |
156 | 74 |
157 uint32_t int_property = 0; | 75 uint32_t int_property = 0; |
158 const char* str_property = NULL; | 76 const char* str_property = NULL; |
159 | 77 |
160 const char* hid_id = udev_device_get_property_value(device, kHIDID); | 78 const char* hid_id = udev_device_get_property_value(device, kHIDID); |
161 if (!hid_id) | 79 if (!hid_id) |
162 return; | 80 return; |
(...skipping 16 matching lines...) Expand all Loading... |
179 if (str_property != NULL) | 97 if (str_property != NULL) |
180 device_info.serial_number = str_property; | 98 device_info.serial_number = str_property; |
181 | 99 |
182 str_property = udev_device_get_property_value(device, kHIDName); | 100 str_property = udev_device_get_property_value(device, kHIDName); |
183 if (str_property != NULL) | 101 if (str_property != NULL) |
184 device_info.product_name = str_property; | 102 device_info.product_name = str_property; |
185 | 103 |
186 AddDevice(device_info); | 104 AddDevice(device_info); |
187 } | 105 } |
188 | 106 |
189 void HidServiceLinux::PlatformRemoveDevice(udev_device* raw_dev) { | 107 void HidServiceLinux::OnDeviceRemoved(udev_device* device) { |
190 const char* device_path = NULL; | 108 const char* device_path = udev_device_get_syspath(device);; |
191 device_path = udev_device_get_syspath(raw_dev); | 109 if (device_path) |
192 if (device_path == NULL) | 110 RemoveDevice(device_path); |
193 return; | |
194 RemoveDevice(device_path); | |
195 } | 111 } |
196 | 112 |
197 } // namespace dev | 113 } // namespace dev |
OLD | NEW |