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.
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"
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";
36 HidServiceLinux::HidServiceLinux() {
37 udev_
.reset(udev_new());
39 LOG(ERROR
) << "Failed to create udev.";
42 monitor_
.reset(udev_monitor_new_from_netlink(udev_
.get(), kUdevName
));
44 LOG(ERROR
) << "Failed to create udev monitor.";
47 int ret
= udev_monitor_filter_add_match_subsystem_devtype(
52 LOG(ERROR
) << "Failed to add udev monitor filter.";
56 ret
= udev_monitor_enable_receiving(monitor_
.get());
58 LOG(ERROR
) << "Failed to start udev monitoring.";
62 monitor_fd_
= udev_monitor_get_fd(monitor_
.get());
63 if (monitor_fd_
<= 0) {
64 LOG(ERROR
) << "Failed to start udev monitoring.";
68 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
71 base::MessageLoopForIO::WATCH_READ
,
79 scoped_refptr
<HidConnection
> HidServiceLinux::Connect(
80 const HidDeviceId
& device_id
) {
81 HidDeviceInfo device_info
;
82 if (!GetDeviceInfo(device_id
, &device_info
))
85 ScopedUdevDevicePtr
hid_device(
86 udev_device_new_from_syspath(udev_
.get(), device_info
.device_id
.c_str()));
88 return new HidConnectionLinux(device_info
, hid_device
.Pass());
93 void HidServiceLinux::OnFileCanReadWithoutBlocking(int fd
) {
94 DCHECK_EQ(monitor_fd_
, fd
);
96 ScopedUdevDevicePtr
dev(udev_monitor_receive_device(monitor_
.get()));
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();
115 void HidServiceLinux::Enumerate() {
116 scoped_ptr
<udev_enumerate
, UdevEnumerateDeleter
> enumerate(
117 udev_enumerate_new(udev_
.get()));
120 LOG(ERROR
) << "Failed to enumerate devices.";
124 if (udev_enumerate_add_match_subsystem(enumerate
.get(), kHIDSubSystem
)) {
125 LOG(ERROR
) << "Failed to enumerate devices.";
129 if (udev_enumerate_scan_devices(enumerate
.get()) != 0) {
130 LOG(ERROR
) << "Failed to enumerate devices.";
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
)));
141 PlatformAddDevice(hid_dev
.get());
146 void HidServiceLinux::PlatformAddDevice(udev_device
* device
) {
150 const char* device_path
= udev_device_get_syspath(device
);
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
);
164 std::vector
<std::string
> parts
;
165 base::SplitString(hid_id
, ':', &parts
);
166 if (parts
.size() != 3) {
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
)
194 RemoveDevice(device_path
);