Revert of Instrumented libraries: update the libnspr4 build script. (patchset #1...
[chromium-blink-merge.git] / device / hid / hid_service_linux.cc
blob3fb27aa27d2475a3ca4957d910a827318d7c36ec
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 "device/hid/hid_service_linux.h"
7 #include <linux/hidraw.h>
8 #include <sys/ioctl.h>
9 #include <stdint.h>
11 #include <string>
13 #include "base/bind.h"
14 #include "base/files/file.h"
15 #include "base/files/file_path.h"
16 #include "base/logging.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/strings/string_split.h"
21 #include "device/hid/hid_connection_linux.h"
22 #include "device/hid/hid_device_info.h"
23 #include "device/hid/hid_report_descriptor.h"
24 #include "device/udev_linux/udev.h"
26 #if defined(OS_CHROMEOS)
27 #include "base/sys_info.h"
28 #include "chromeos/dbus/dbus_thread_manager.h"
29 #include "chromeos/dbus/permission_broker_client.h"
30 #endif // defined(OS_CHROMEOS)
32 namespace device {
34 namespace {
36 const char kHidrawSubsystem[] = "hidraw";
37 const char kHIDID[] = "HID_ID";
38 const char kHIDName[] = "HID_NAME";
39 const char kHIDUnique[] = "HID_UNIQ";
41 } // namespace
43 HidServiceLinux::HidServiceLinux(
44 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
45 : ui_task_runner_(ui_task_runner),
46 weak_factory_(this) {
47 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance();
48 monitor->AddObserver(this);
49 monitor->Enumerate(
50 base::Bind(&HidServiceLinux::OnDeviceAdded, weak_factory_.GetWeakPtr()));
53 scoped_refptr<HidConnection> HidServiceLinux::Connect(
54 const HidDeviceId& device_id) {
55 HidDeviceInfo device_info;
56 if (!GetDeviceInfo(device_id, &device_info))
57 return NULL;
59 ScopedUdevDevicePtr device =
60 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath(
61 device_info.device_id);
63 if (device) {
64 std::string dev_node = udev_device_get_devnode(device.get());
65 return new HidConnectionLinux(device_info, dev_node);
68 return NULL;
71 HidServiceLinux::~HidServiceLinux() {
72 if (DeviceMonitorLinux::HasInstance())
73 DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
76 void HidServiceLinux::OnDeviceAdded(udev_device* device) {
77 if (!device)
78 return;
80 const char* device_path = udev_device_get_syspath(device);
81 if (!device_path)
82 return;
83 const char* subsystem = udev_device_get_subsystem(device);
84 if (!subsystem || strcmp(subsystem, kHidrawSubsystem) != 0)
85 return;
87 scoped_ptr<HidDeviceInfo> device_info(new HidDeviceInfo);
88 device_info->device_id = device_path;
90 uint32_t int_property = 0;
91 const char* str_property = NULL;
93 udev_device *parent = udev_device_get_parent(device);
94 if (!parent) {
95 return;
98 const char* hid_id = udev_device_get_property_value(parent, kHIDID);
99 if (!hid_id)
100 return;
102 std::vector<std::string> parts;
103 base::SplitString(hid_id, ':', &parts);
104 if (parts.size() != 3) {
105 return;
108 if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) {
109 device_info->vendor_id = int_property;
112 if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) {
113 device_info->product_id = int_property;
116 str_property = udev_device_get_property_value(parent, kHIDUnique);
117 if (str_property != NULL)
118 device_info->serial_number = str_property;
120 str_property = udev_device_get_property_value(parent, kHIDName);
121 if (str_property != NULL)
122 device_info->product_name = str_property;
124 const std::string dev_node = udev_device_get_devnode(device);
125 #if defined(OS_CHROMEOS)
126 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to
127 // use permission broker.
128 if (base::SysInfo::IsRunningOnChromeOS()) {
129 chromeos::PermissionBrokerClient* client =
130 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
131 DCHECK(client) << "Could not get permission broker client.";
132 if (!client) {
133 return;
135 ui_task_runner_->PostTask(
136 FROM_HERE,
137 base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
138 base::Unretained(client),
139 dev_node,
141 base::Bind(&HidServiceLinux::OnRequestAccessComplete,
142 weak_factory_.GetWeakPtr(),
143 dev_node,
144 base::Passed(&device_info))));
145 } else {
146 OnRequestAccessComplete(dev_node, device_info.Pass(), true);
148 #else
149 OnRequestAccessComplete(dev_node, device_info.Pass(), true);
150 #endif // defined(OS_CHROMEOS)
153 void HidServiceLinux::OnDeviceRemoved(udev_device* device) {
154 const char* device_path = udev_device_get_syspath(device);;
155 if (device_path)
156 RemoveDevice(device_path);
159 void HidServiceLinux::OnRequestAccessComplete(
160 const std::string& path,
161 scoped_ptr<HidDeviceInfo> device_info,
162 bool success) {
163 const int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
164 base::File device_file(base::FilePath(path), flags);
165 if (!device_file.IsValid()) {
166 LOG(ERROR) << "Cannot open '" << path << "': "
167 << base::File::ErrorToString(device_file.error_details());
168 return;
171 int desc_size = 0;
172 int res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESCSIZE, &desc_size);
173 if (res < 0) {
174 PLOG(ERROR) << "Failed to get report descriptor size";
175 device_file.Close();
176 return;
179 hidraw_report_descriptor rpt_desc;
180 rpt_desc.size = desc_size;
182 res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESC, &rpt_desc);
183 if (res < 0) {
184 PLOG(ERROR) << "Failed to get report descriptor";
185 device_file.Close();
186 return;
189 device_file.Close();
191 HidReportDescriptor report_descriptor(rpt_desc.value, rpt_desc.size);
192 report_descriptor.GetDetails(&device_info->collections,
193 &device_info->has_report_id,
194 &device_info->max_input_report_size,
195 &device_info->max_output_report_size,
196 &device_info->max_feature_report_size);
198 AddDevice(*device_info);
201 } // namespace device