1 // Copyright (c) 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.
9 #include "base/basictypes.h"
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/platform_file.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_piece.h"
17 #include "base/strings/string_split.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "device/hid/hid_connection.h"
20 #include "device/hid/hid_connection_linux.h"
21 #include "device/hid/hid_device_info.h"
22 #include "device/hid/hid_service_linux.h"
28 const char kUdevName
[] = "udev";
29 const char kUdevActionAdd
[] = "add";
30 const char kUdevActionRemove
[] = "remove";
31 const char kHIDSubSystem
[] = "hid";
33 const char kHIDID
[] = "HID_ID";
34 const char kHIDName
[] = "HID_NAME";
35 const char kHIDUnique
[] = "HID_UNIQ";
39 HidServiceLinux::HidServiceLinux() {
40 udev_
.reset(udev_new());
42 LOG(ERROR
) << "Failed to create udev.";
45 monitor_
.reset(udev_monitor_new_from_netlink(udev_
.get(), kUdevName
));
47 LOG(ERROR
) << "Failed to create udev monitor.";
50 int ret
= udev_monitor_filter_add_match_subsystem_devtype(
55 LOG(ERROR
) << "Failed to add udev monitor filter.";
59 ret
= udev_monitor_enable_receiving(monitor_
.get());
61 LOG(ERROR
) << "Failed to start udev monitoring.";
65 monitor_fd_
= udev_monitor_get_fd(monitor_
.get());
66 if (monitor_fd_
<= 0) {
67 LOG(ERROR
) << "Failed to start udev monitoring.";
71 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
74 base::MessageLoopForIO::WATCH_READ
,
82 HidServiceLinux::~HidServiceLinux() {
83 monitor_watcher_
.StopWatchingFileDescriptor();
87 void HidServiceLinux::Enumerate() {
88 scoped_ptr
<udev_enumerate
, UdevEnumerateDeleter
> enumerate(
89 udev_enumerate_new(udev_
.get()));
92 LOG(ERROR
) << "Failed to enumerate devices.";
96 if (udev_enumerate_add_match_subsystem(enumerate
.get(), kHIDSubSystem
)) {
97 LOG(ERROR
) << "Failed to enumerate devices.";
101 if (udev_enumerate_scan_devices(enumerate
.get()) != 0) {
102 LOG(ERROR
) << "Failed to enumerate devices.";
106 // This list is managed by |enumerate|.
107 udev_list_entry
* devices
= udev_enumerate_get_list_entry(enumerate
.get());
108 for (udev_list_entry
* i
= devices
; i
!= NULL
;
109 i
= udev_list_entry_get_next(i
)) {
110 ScopedUdevDevicePtr
hid_dev(
111 udev_device_new_from_syspath(udev_
.get(), udev_list_entry_get_name(i
)));
113 PlatformDeviceAdd(hid_dev
.get());
120 void HidServiceLinux::PlatformDeviceAdd(udev_device
* device
) {
124 const char* device_id
= udev_device_get_syspath(device
);
129 HidDeviceInfo device_info
;
130 device_info
.device_id
= device_id
;
132 uint32 int_property
= 0;
133 const char* str_property
= NULL
;
135 const char* hid_id
= udev_device_get_property_value(device
, kHIDID
);
139 std::vector
<std::string
> parts
;
140 base::SplitString(hid_id
, ':', &parts
);
141 if (parts
.size() != 3) {
145 if (HexStringToUInt(base::StringPiece(parts
[1]), &int_property
)) {
146 device_info
.vendor_id
= int_property
;
149 if (HexStringToUInt(base::StringPiece(parts
[2]), &int_property
)) {
150 device_info
.product_id
= int_property
;
153 str_property
= udev_device_get_property_value(device
, kHIDUnique
);
154 if (str_property
!= NULL
)
155 device_info
.serial_number
= str_property
;
157 str_property
= udev_device_get_property_value(device
, kHIDName
);
158 if (str_property
!= NULL
)
159 device_info
.product_name
= str_property
;
161 AddDevice(device_info
);
164 void HidServiceLinux::PlatformDeviceRemove(udev_device
* raw_dev
) {
165 // The returned the device is not referenced.
166 udev_device
* hid_dev
=
167 udev_device_get_parent_with_subsystem_devtype(raw_dev
, "hid", NULL
);
172 const char* device_id
= NULL
;
173 device_id
= udev_device_get_syspath(hid_dev
);
174 if (device_id
== NULL
)
177 RemoveDevice(device_id
);
180 scoped_refptr
<HidConnection
> HidServiceLinux::Connect(std::string device_id
) {
181 if (!ContainsKey(devices_
, device_id
))
183 ScopedUdevDevicePtr
hid_device(
184 udev_device_new_from_syspath(udev_
.get(), device_id
.c_str()));
186 scoped_refptr
<HidConnectionLinux
> connection
=
187 new HidConnectionLinux(devices_
[device_id
], hid_device
.Pass());
188 if (connection
->initialized())
194 void HidServiceLinux::OnFileCanReadWithoutBlocking(int fd
) {
195 DCHECK_EQ(monitor_fd_
, fd
);
197 ScopedUdevDevicePtr
dev(udev_monitor_receive_device(monitor_
.get()));
201 std::string
action(udev_device_get_action(dev
.get()));
202 if (action
== kUdevActionAdd
) {
203 PlatformDeviceAdd(dev
.get());
204 } else if (action
== kUdevActionRemove
) {
205 PlatformDeviceRemove(dev
.get());
209 void HidServiceLinux::OnFileCanWriteWithoutBlocking(int fd
) {}