Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / device / hid / hid_service_linux.cc
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.
4
5 #include "device/hid/hid_service_linux.h"
6
7 #include <linux/hidraw.h>
8 #include <sys/ioctl.h>
9 #include <stdint.h>
10
11 #include <string>
12
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"
25
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)
31
32 namespace device {
33
34 namespace {
35
36 const char kHidrawSubsystem[] = "hidraw";
37 const char kHIDID[] = "HID_ID";
38 const char kHIDName[] = "HID_NAME";
39 const char kHIDUnique[] = "HID_UNIQ";
40
41 }  // namespace
42
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()));
51 }
52
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;
58
59   ScopedUdevDevicePtr device =
60       DeviceMonitorLinux::GetInstance()->GetDeviceFromPath(
61           device_info.device_id);
62
63   if (device) {
64     std::string dev_node = udev_device_get_devnode(device.get());
65     return new HidConnectionLinux(device_info, dev_node);
66   }
67
68   return NULL;
69 }
70
71 HidServiceLinux::~HidServiceLinux() {
72   if (DeviceMonitorLinux::HasInstance())
73     DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
74 }
75
76 void HidServiceLinux::OnDeviceAdded(udev_device* device) {
77   if (!device)
78     return;
79
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;
86
87   scoped_ptr<HidDeviceInfo> device_info(new HidDeviceInfo);
88   device_info->device_id = device_path;
89
90   uint32_t int_property = 0;
91   const char* str_property = NULL;
92
93   udev_device *parent = udev_device_get_parent(device);
94   if (!parent) {
95     return;
96   }
97
98   const char* hid_id = udev_device_get_property_value(parent, kHIDID);
99   if (!hid_id)
100     return;
101
102   std::vector<std::string> parts;
103   base::SplitString(hid_id, ':', &parts);
104   if (parts.size() != 3) {
105     return;
106   }
107
108   if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) {
109     device_info->vendor_id = int_property;
110   }
111
112   if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) {
113     device_info->product_id = int_property;
114   }
115
116   str_property = udev_device_get_property_value(parent, kHIDUnique);
117   if (str_property != NULL)
118     device_info->serial_number = str_property;
119
120   str_property = udev_device_get_property_value(parent, kHIDName);
121   if (str_property != NULL)
122     device_info->product_name = str_property;
123
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;
134     }
135     ui_task_runner_->PostTask(
136         FROM_HERE,
137         base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
138                    base::Unretained(client),
139                    dev_node,
140                    -1,
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);
147   }
148 #else
149   OnRequestAccessComplete(dev_node, device_info.Pass(), true);
150 #endif  // defined(OS_CHROMEOS)
151 }
152
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);
157 }
158
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;
169   }
170
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;
177   }
178
179   hidraw_report_descriptor rpt_desc;
180   rpt_desc.size = desc_size;
181
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;
187   }
188
189   device_file.Close();
190
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);
197
198   AddDevice(*device_info);
199 }
200
201 }  // namespace device