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

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: Remove unnecessary code. 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
« no previous file with comments | « device/hid/hid_service_linux.h ('k') | extensions/browser/api/hid/hid_api.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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>
8 #include <sys/ioctl.h>
9 #include <stdint.h>
10
11 #include <string> 7 #include <string>
12 8
13 #include "base/bind.h" 9 #include "base/bind.h"
14 #include "base/files/file.h" 10 #include "base/files/file.h"
15 #include "base/files/file_path.h" 11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
16 #include "base/logging.h" 13 #include "base/logging.h"
17 #include "base/stl_util.h" 14 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h" 16 #include "base/strings/string_piece.h"
20 #include "base/strings/string_split.h" 17 #include "base/strings/string_split.h"
18 #include "base/thread_task_runner_handle.h"
21 #include "base/threading/thread_restrictions.h" 19 #include "base/threading/thread_restrictions.h"
22 #include "device/hid/hid_connection_linux.h" 20 #include "device/hid/hid_connection_linux.h"
23 #include "device/hid/hid_device_info.h" 21 #include "device/hid/hid_device_info.h"
24 #include "device/hid/hid_report_descriptor.h" 22 #include "device/hid/hid_report_descriptor.h"
25 #include "device/udev_linux/udev.h" 23 #include "device/udev_linux/udev.h"
26 24
27 #if defined(OS_CHROMEOS) 25 #if defined(OS_CHROMEOS)
28 #include "base/sys_info.h" 26 #include "base/sys_info.h"
29 #include "chromeos/dbus/dbus_thread_manager.h" 27 #include "chromeos/dbus/dbus_thread_manager.h"
30 #include "chromeos/dbus/permission_broker_client.h" 28 #include "chromeos/dbus/permission_broker_client.h"
31 #endif // defined(OS_CHROMEOS) 29 #endif // defined(OS_CHROMEOS)
32 30
33 namespace device { 31 namespace device {
34 32
35 namespace { 33 namespace {
36 34
37 const char kHidrawSubsystem[] = "hidraw"; 35 const char kHidrawSubsystem[] = "hidraw";
38 const char kHIDID[] = "HID_ID"; 36 const char kHIDID[] = "HID_ID";
39 const char kHIDName[] = "HID_NAME"; 37 const char kHIDName[] = "HID_NAME";
40 const char kHIDUnique[] = "HID_UNIQ"; 38 const char kHIDUnique[] = "HID_UNIQ";
39 const char kSysfsReportDescriptorKey[] = "report_descriptor";
41 40
42 } // namespace 41 } // namespace
43 42
44 HidServiceLinux::HidServiceLinux( 43 HidServiceLinux::HidServiceLinux(
45 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) 44 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
46 : ui_task_runner_(ui_task_runner), 45 : ui_task_runner_(ui_task_runner),
47 weak_factory_(this) { 46 weak_factory_(this) {
48 base::ThreadRestrictions::AssertIOAllowed(); 47 base::ThreadRestrictions::AssertIOAllowed();
48 task_runner_ = base::ThreadTaskRunnerHandle::Get();
49 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance(); 49 DeviceMonitorLinux* monitor = DeviceMonitorLinux::GetInstance();
50 monitor->AddObserver(this); 50 monitor->AddObserver(this);
51 monitor->Enumerate( 51 monitor->Enumerate(
52 base::Bind(&HidServiceLinux::OnDeviceAdded, weak_factory_.GetWeakPtr())); 52 base::Bind(&HidServiceLinux::OnDeviceAdded, weak_factory_.GetWeakPtr()));
53 } 53 }
54 54
55 #if defined(OS_CHROMEOS)
56 void HidServiceLinux::RequestAccess(
57 const HidDeviceId& device_id,
58 const base::Callback<void(bool success)>& callback) {
59 bool success = false;
60 ScopedUdevDevicePtr device =
61 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath(
62 device_id);
63
64 if (device) {
65 const char* dev_node = udev_device_get_devnode(device.get());
66
67 if (base::SysInfo::IsRunningOnChromeOS()) {
68 chromeos::PermissionBrokerClient* client =
69 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
70 DCHECK(client) << "Could not get permission broker client.";
71 if (client) {
72 ui_task_runner_->PostTask(
73 FROM_HERE,
74 base::Bind(&chromeos::PermissionBrokerClient::RequestPathAccess,
75 base::Unretained(client),
76 std::string(dev_node),
77 -1,
78 base::Bind(&HidServiceLinux::OnRequestAccessComplete,
79 weak_factory_.GetWeakPtr(),
80 callback)));
81 return;
82 }
83 } else {
84 // Not really running on Chrome OS, declare success.
85 success = true;
86 }
87 }
88 task_runner_->PostTask(FROM_HERE, base::Bind(callback, success));
89 }
90 #endif
91
55 scoped_refptr<HidConnection> HidServiceLinux::Connect( 92 scoped_refptr<HidConnection> HidServiceLinux::Connect(
56 const HidDeviceId& device_id) { 93 const HidDeviceId& device_id) {
57 HidDeviceInfo device_info; 94 HidDeviceInfo device_info;
58 if (!GetDeviceInfo(device_id, &device_info)) 95 if (!GetDeviceInfo(device_id, &device_info))
59 return NULL; 96 return NULL;
60 97
61 ScopedUdevDevicePtr device = 98 ScopedUdevDevicePtr device =
62 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath( 99 DeviceMonitorLinux::GetInstance()->GetDeviceFromPath(
63 device_info.device_id); 100 device_info.device_id);
64 101
65 if (device) { 102 if (device) {
66 std::string dev_node = udev_device_get_devnode(device.get()); 103 const char* dev_node = udev_device_get_devnode(device.get());
67 return new HidConnectionLinux(device_info, dev_node); 104 if (dev_node) {
105 return new HidConnectionLinux(device_info, dev_node);
106 }
68 } 107 }
69 108
70 return NULL; 109 return NULL;
71 } 110 }
72 111
73 HidServiceLinux::~HidServiceLinux() { 112 HidServiceLinux::~HidServiceLinux() {
74 if (DeviceMonitorLinux::HasInstance()) 113 if (DeviceMonitorLinux::HasInstance())
75 DeviceMonitorLinux::GetInstance()->RemoveObserver(this); 114 DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
76 } 115 }
77 116
78 void HidServiceLinux::OnDeviceAdded(udev_device* device) { 117 void HidServiceLinux::OnDeviceAdded(udev_device* device) {
79 if (!device) 118 if (!device)
80 return; 119 return;
81 120
82 const char* device_path = udev_device_get_syspath(device); 121 const char* device_path = udev_device_get_syspath(device);
83 if (!device_path) 122 if (!device_path)
84 return; 123 return;
85 const char* subsystem = udev_device_get_subsystem(device); 124 const char* subsystem = udev_device_get_subsystem(device);
86 if (!subsystem || strcmp(subsystem, kHidrawSubsystem) != 0) 125 if (!subsystem || strcmp(subsystem, kHidrawSubsystem) != 0)
87 return; 126 return;
88 127
89 scoped_ptr<HidDeviceInfo> device_info(new HidDeviceInfo); 128 HidDeviceInfo device_info;
90 device_info->device_id = device_path; 129 device_info.device_id = device_path;
91 130
92 uint32_t int_property = 0; 131 uint32_t int_property = 0;
93 const char* str_property = NULL; 132 const char* str_property = NULL;
94 133
95 udev_device *parent = udev_device_get_parent(device); 134 udev_device *parent = udev_device_get_parent(device);
96 if (!parent) { 135 if (!parent) {
97 return; 136 return;
98 } 137 }
99 138
100 const char* hid_id = udev_device_get_property_value(parent, kHIDID); 139 const char* hid_id = udev_device_get_property_value(parent, kHIDID);
101 if (!hid_id) 140 if (!hid_id) {
102 return; 141 return;
142 }
103 143
104 std::vector<std::string> parts; 144 std::vector<std::string> parts;
105 base::SplitString(hid_id, ':', &parts); 145 base::SplitString(hid_id, ':', &parts);
106 if (parts.size() != 3) { 146 if (parts.size() != 3) {
107 return; 147 return;
108 } 148 }
109 149
110 if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) { 150 if (HexStringToUInt(base::StringPiece(parts[1]), &int_property)) {
111 device_info->vendor_id = int_property; 151 device_info.vendor_id = int_property;
112 } 152 }
113 153
114 if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) { 154 if (HexStringToUInt(base::StringPiece(parts[2]), &int_property)) {
115 device_info->product_id = int_property; 155 device_info.product_id = int_property;
116 } 156 }
117 157
118 str_property = udev_device_get_property_value(parent, kHIDUnique); 158 str_property = udev_device_get_property_value(parent, kHIDUnique);
119 if (str_property != NULL) 159 if (str_property != NULL) {
120 device_info->serial_number = str_property; 160 device_info.serial_number = str_property;
161 }
121 162
122 str_property = udev_device_get_property_value(parent, kHIDName); 163 str_property = udev_device_get_property_value(parent, kHIDName);
123 if (str_property != NULL) 164 if (str_property != NULL) {
124 device_info->product_name = str_property; 165 device_info.product_name = str_property;
166 }
125 167
126 const std::string dev_node = udev_device_get_devnode(device); 168 const char* parent_sysfs_path = udev_device_get_syspath(parent);
127 #if defined(OS_CHROMEOS) 169 if (!parent_sysfs_path) {
128 // ChromeOS builds on non-ChromeOS machines (dev) should not attempt to 170 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 } 171 }
150 #else 172 base::FilePath report_descriptor_path =
151 OnRequestAccessComplete(dev_node, device_info.Pass(), true); 173 base::FilePath(parent_sysfs_path).Append(kSysfsReportDescriptorKey);
152 #endif // defined(OS_CHROMEOS) 174 std::string report_descriptor_str;
175 if (!base::ReadFileToString(report_descriptor_path, &report_descriptor_str)) {
176 return;
177 }
178
179 HidReportDescriptor report_descriptor(
180 reinterpret_cast<uint8_t*>(&report_descriptor_str[0]),
181 report_descriptor_str.length());
182 report_descriptor.GetDetails(&device_info.collections,
183 &device_info.has_report_id,
184 &device_info.max_input_report_size,
185 &device_info.max_output_report_size,
186 &device_info.max_feature_report_size);
187
188 AddDevice(device_info);
153 } 189 }
154 190
155 void HidServiceLinux::OnDeviceRemoved(udev_device* device) { 191 void HidServiceLinux::OnDeviceRemoved(udev_device* device) {
156 const char* device_path = udev_device_get_syspath(device);; 192 const char* device_path = udev_device_get_syspath(device);;
157 if (device_path) 193 if (device_path) {
158 RemoveDevice(device_path); 194 RemoveDevice(device_path);
195 }
159 } 196 }
160 197
161 void HidServiceLinux::OnRequestAccessComplete( 198 void HidServiceLinux::OnRequestAccessComplete(
162 const std::string& path, 199 const base::Callback<void(bool success)>& callback,
163 scoped_ptr<HidDeviceInfo> device_info,
164 bool success) { 200 bool success) {
165 const int flags = base::File::FLAG_OPEN | base::File::FLAG_READ; 201 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 } 202 }
202 203
203 } // namespace device 204 } // namespace device
OLDNEW
« no previous file with comments | « device/hid/hid_service_linux.h ('k') | extensions/browser/api/hid/hid_api.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698