Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(845)

Side by Side Diff: device/hid/hid_service_linux.cc

Issue 641203003: Read HID report descriptor from sysfs and request permission on connect. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "device/hid/hid_service_linux.h" 5 #include "device/hid/hid_service_linux.h"
6 6
7 #include <linux/hidraw.h> 7 #include <linux/hidraw.h>
8 #include <sys/ioctl.h> 8 #include <sys/ioctl.h>
Yoyo Zhou 2014/10/10 23:05:24 Don't need this anymore?
9 #include <stdint.h> 9 #include <stdint.h>
10 10
11 #include <string> 11 #include <string>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/files/file.h" 14 #include "base/files/file.h"
15 #include "base/files/file_path.h" 15 #include "base/files/file_path.h"
16 #include "base/files/file_util.h"
16 #include "base/logging.h" 17 #include "base/logging.h"
17 #include "base/stl_util.h" 18 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h" 19 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h" 20 #include "base/strings/string_piece.h"
20 #include "base/strings/string_split.h" 21 #include "base/strings/string_split.h"
22 #include "base/thread_task_runner_handle.h"
21 #include "base/threading/thread_restrictions.h" 23 #include "base/threading/thread_restrictions.h"
22 #include "device/hid/hid_connection_linux.h" 24 #include "device/hid/hid_connection_linux.h"
23 #include "device/hid/hid_device_info.h" 25 #include "device/hid/hid_device_info.h"
24 #include "device/hid/hid_report_descriptor.h" 26 #include "device/hid/hid_report_descriptor.h"
25 #include "device/udev_linux/udev.h" 27 #include "device/udev_linux/udev.h"
26 28
27 #if defined(OS_CHROMEOS) 29 #if defined(OS_CHROMEOS)
28 #include "base/sys_info.h" 30 #include "base/sys_info.h"
29 #include "chromeos/dbus/dbus_thread_manager.h" 31 #include "chromeos/dbus/dbus_thread_manager.h"
30 #include "chromeos/dbus/permission_broker_client.h" 32 #include "chromeos/dbus/permission_broker_client.h"
31 #endif // defined(OS_CHROMEOS) 33 #endif // defined(OS_CHROMEOS)
32 34
33 namespace device { 35 namespace device {
34 36
35 namespace { 37 namespace {
36 38
37 const char kHidrawSubsystem[] = "hidraw"; 39 const char kHidrawSubsystem[] = "hidraw";
38 const char kHIDID[] = "HID_ID"; 40 const char kHIDID[] = "HID_ID";
39 const char kHIDName[] = "HID_NAME"; 41 const char kHIDName[] = "HID_NAME";
40 const char kHIDUnique[] = "HID_UNIQ"; 42 const char kHIDUnique[] = "HID_UNIQ";
43 const char kSysfsReportDescriptorKey[] = "report_descriptor";
41 44
42 } // namespace 45 } // namespace
43 46
44 HidServiceLinux::HidServiceLinux( 47 HidServiceLinux::HidServiceLinux(
45 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) 48 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
46 : ui_task_runner_(ui_task_runner), 49 : ui_task_runner_(ui_task_runner),
47 weak_factory_(this) { 50 weak_factory_(this) {
48 base::ThreadRestrictions::AssertIOAllowed(); 51 base::ThreadRestrictions::AssertIOAllowed();
52 task_runner_ = base::ThreadTaskRunnerHandle::Get();
49 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance(); 53 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance();
50 monitor->AddObserver(this); 54 monitor->AddObserver(this);
51 monitor->Enumerate( 55 monitor->Enumerate(
52 base::Bind(&HidServiceLinux::OnDeviceAdded, weak_factory_.GetWeakPtr())); 56 base::Bind(&HidServiceLinux::OnDeviceAdded, weak_factory_.GetWeakPtr()));
53 } 57 }
54 58
59 #if defined(OS_CHROMEOS)
60 void HidServiceLinux::RequestAccess(
61 const HidDeviceId& device_id,
62 const base::Callback<void(bool success)>& callback) {
63 bool success = false;
64 ScopedUdevDevicePtr device =
65 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath(
66 device_id);
67
68 if (device) {
69 const char* dev_node = udev_device_get_devnode(device.get());
70
71 if (base::SysInfo::IsRunningOnChromeOS()) {
72 chromeos::PermissionBrokerClient* client =
73 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
74 DCHECK(client) << "Could not get permission broker client.";
75 if (client) {
76 ui_task_runner_->PostTask(
77 FROM_HERE,
78 base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
79 base::Unretained(client),
80 std::string(dev_node),
81 -1,
82 base::Bind(&HidServiceLinux::OnRequestAccessComplete,
83 weak_factory_.GetWeakPtr(),
84 callback)));
85 return;
86 }
87 } else {
88 // Not really running on Chrome OS, declare success.
89 success = true;
90 }
91 }
92 task_runner_->PostTask(FROM_HERE, base::Bind(callback, success));
93 }
94 #endif
95
55 scoped_refptr<HidConnection> HidServiceLinux::Connect( 96 scoped_refptr<HidConnection> HidServiceLinux::Connect(
56 const HidDeviceId& device_id) { 97 const HidDeviceId& device_id) {
57 HidDeviceInfo device_info; 98 HidDeviceInfo device_info;
58 if (!GetDeviceInfo(device_id, &device_info)) 99 if (!GetDeviceInfo(device_id, &device_info))
59 return NULL; 100 return NULL;
60 101
61 ScopedUdevDevicePtr device = 102 ScopedUdevDevicePtr device =
62 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath( 103 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath(
63 device_info.device_id); 104 device_info.device_id);
64 105
65 if (device) { 106 if (device) {
66 std::string dev_node = udev_device_get_devnode(device.get()); 107 const char* dev_node = udev_device_get_devnode(device.get());
67 return new HidConnectionLinux(device_info, dev_node); 108 if (dev_node) {
109 return new HidConnectionLinux(device_info, dev_node);
110 }
68 } 111 }
69 112
70 return NULL; 113 return NULL;
71 } 114 }
72 115
73 HidServiceLinux::~HidServiceLinux() { 116 HidServiceLinux::~HidServiceLinux() {
74 if (DeviceMonitorLinux::HasInstance()) 117 if (DeviceMonitorLinux::HasInstance())
75 DeviceMonitorLinux::GetInstance()->RemoveObserver(this); 118 DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
76 } 119 }
77 120
78 void HidServiceLinux::OnDeviceAdded(udev_device* device) { 121 void HidServiceLinux::OnDeviceAdded(udev_device* device) {
79 if (!device) 122 if (!device)
80 return; 123 return;
81 124
82 const char* device_path = udev_device_get_syspath(device); 125 const char* device_path = udev_device_get_syspath(device);
83 if (!device_path) 126 if (!device_path)
84 return; 127 return;
85 const char* subsystem = udev_device_get_subsystem(device); 128 const char* subsystem = udev_device_get_subsystem(device);
86 if (!subsystem || strcmp(subsystem, kHidrawSubsystem) != 0) 129 if (!subsystem || strcmp(subsystem, kHidrawSubsystem) != 0)
87 return; 130 return;
88 131
89 scoped_ptr<HidDeviceInfo> device_info(new HidDeviceInfo); 132 HidDeviceInfo device_info;
90 device_info->device_id = device_path; 133 device_info.device_id = device_path;
91 134
92 uint32_t int_property = 0; 135 uint32_t int_property = 0;
93 const char* str_property = NULL; 136 const char* str_property = NULL;
94 137
95 udev_device *parent = udev_device_get_parent(device); 138 udev_device *parent = udev_device_get_parent(device);
96 if (!parent) { 139 if (!parent) {
97 return; 140 return;
98 } 141 }
99 142
100 const char* hid_id = udev_device_get_property_value(parent, kHIDID); 143 const char* hid_id = udev_device_get_property_value(parent, kHIDID);
101 if (!hid_id) 144 if (!hid_id) {
102 return; 145 return;
146 }
103 147
104 std::vector<std::string> parts; 148 std::vector<std::string> parts;
105 base::SplitString(hid_id, ':', &parts); 149 base::SplitString(hid_id, ':', &parts);
106 if (parts.size() != 3) { 150 if (parts.size() != 3) {
107 return; 151 return;
108 } 152 }
109 153
110 if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) { 154 if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) {
111 device_info->vendor_id = int_property; 155 device_info.vendor_id = int_property;
112 } 156 }
113 157
114 if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) { 158 if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) {
115 device_info->product_id = int_property; 159 device_info.product_id = int_property;
116 } 160 }
117 161
118 str_property = udev_device_get_property_value(parent, kHIDUnique); 162 str_property = udev_device_get_property_value(parent, kHIDUnique);
119 if (str_property != NULL) 163 if (str_property != NULL) {
120 device_info->serial_number = str_property; 164 device_info.serial_number = str_property;
165 }
121 166
122 str_property = udev_device_get_property_value(parent, kHIDName); 167 str_property = udev_device_get_property_value(parent, kHIDName);
123 if (str_property != NULL) 168 if (str_property != NULL) {
124 device_info->product_name = str_property; 169 device_info.product_name = str_property;
170 }
125 171
126 const std::string dev_node = udev_device_get_devnode(device); 172 const char* parent_sysfs_path = udev_device_get_syspath(parent);
127 #if defined(OS_CHROMEOS) 173 if (!parent_sysfs_path) {
128 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to 174 return;
129 // use permission broker.
130 if (base::SysInfo::IsRunningOnChromeOS()) {
131 chromeos::PermissionBrokerClient* client =
132 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
133 DCHECK(client) << "Could not get permission broker client.";
134 if (!client) {
135 return;
136 }
137 ui_task_runner_->PostTask(
138 FROM_HERE,
139 base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
140 base::Unretained(client),
141 dev_node,
142 -1,
143 base::Bind(&HidServiceLinux::OnRequestAccessComplete,
144 weak_factory_.GetWeakPtr(),
145 dev_node,
146 base::Passed(&device_info))));
147 } else {
148 OnRequestAccessComplete(dev_node, device_info.Pass(), true);
149 } 175 }
150 #else 176 base::FilePath report_descriptor_path =
151 OnRequestAccessComplete(dev_node, device_info.Pass(), true); 177 base::FilePath(parent_sysfs_path).Append(kSysfsReportDescriptorKey);
152 #endif // defined(OS_CHROMEOS) 178 std::string report_descriptor_str;
179 if (!base::ReadFileToString(report_descriptor_path, &report_descriptor_str)) {
180 return;
181 }
182
183 HidReportDescriptor report_descriptor(
184 reinterpret_cast<uint8_t*>(&report_descriptor_str[0]),
185 report_descriptor_str.length());
186 report_descriptor.GetDetails(&device_info.collections,
187 &device_info.has_report_id,
188 &device_info.max_input_report_size,
189 &device_info.max_output_report_size,
190 &device_info.max_feature_report_size);
191
192 AddDevice(device_info);
153 } 193 }
154 194
155 void HidServiceLinux::OnDeviceRemoved(udev_device* device) { 195 void HidServiceLinux::OnDeviceRemoved(udev_device* device) {
156 const char* device_path = udev_device_get_syspath(device);; 196 const char* device_path = udev_device_get_syspath(device);;
157 if (device_path) 197 if (device_path) {
158 RemoveDevice(device_path); 198 RemoveDevice(device_path);
199 }
159 } 200 }
160 201
161 void HidServiceLinux::OnRequestAccessComplete( 202 void HidServiceLinux::OnRequestAccessComplete(
162 const std::string& path, 203 const base::Callback<void(bool success)>& callback,
163 scoped_ptr<HidDeviceInfo> device_info,
164 bool success) { 204 bool success) {
165 const int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; 205 task_runner_->PostTask(FROM_HERE, base::Bind(callback, success));
166 base::File device_file(base::FilePath(path), flags);
167 if (!device_file.IsValid()) {
168 LOG(ERROR) << "Cannot open '" << path << "': "
169 << base::File::ErrorToString(device_file.error_details());
170 return;
171 }
172
173 int desc_size = 0;
174 int res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESCSIZE, &desc_size);
175 if (res < 0) {
176 PLOG(ERROR) << "Failed to get report descriptor size";
177 device_file.Close();
178 return;
179 }
180
181 hidraw_report_descriptor rpt_desc;
182 rpt_desc.size = desc_size;
183
184 res = ioctl(device_file.GetPlatformFile(), HIDIOCGRDESC, &rpt_desc);
185 if (res < 0) {
186 PLOG(ERROR) << "Failed to get report descriptor";
187 device_file.Close();
188 return;
189 }
190
191 device_file.Close();
192
193 HidReportDescriptor report_descriptor(rpt_desc.value, rpt_desc.size);
194 report_descriptor.GetDetails(&device_info->collections,
195 &device_info->has_report_id,
196 &device_info->max_input_report_size,
197 &device_info->max_output_report_size,
198 &device_info->max_feature_report_size);
199
200 AddDevice(*device_info);
201 } 206 }
202 207
203 } // namespace device 208 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698