OLD | NEW |
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_mac.h" | 5 #include "device/hid/hid_service_mac.h" |
6 | 6 |
7 #include <CoreFoundation/CoreFoundation.h> | 7 #include <CoreFoundation/CoreFoundation.h> |
8 #include <IOKit/hid/IOHIDDevice.h> | 8 #include <IOKit/hid/IOHIDDevice.h> |
9 | 9 |
10 #include <set> | 10 #include <set> |
11 #include <string> | 11 #include <string> |
12 #include <vector> | 12 #include <vector> |
13 | 13 |
14 #include "base/bind.h" | 14 #include "base/bind.h" |
15 #include "base/location.h" | 15 #include "base/location.h" |
16 #include "base/logging.h" | 16 #include "base/logging.h" |
17 #include "base/mac/foundation_util.h" | 17 #include "base/mac/foundation_util.h" |
18 #include "base/single_thread_task_runner.h" | 18 #include "base/single_thread_task_runner.h" |
19 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
20 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
21 #include "base/strings/sys_string_conversions.h" | 21 #include "base/strings/sys_string_conversions.h" |
22 #include "base/thread_task_runner_handle.h" | 22 #include "base/thread_task_runner_handle.h" |
23 #include "base/threading/thread_restrictions.h" | 23 #include "base/threading/thread_restrictions.h" |
| 24 #include "components/device_event_log/device_event_log.h" |
24 #include "device/hid/hid_connection_mac.h" | 25 #include "device/hid/hid_connection_mac.h" |
25 | 26 |
26 namespace device { | 27 namespace device { |
27 | 28 |
28 namespace { | 29 namespace { |
29 | 30 |
| 31 std::string HexErrorCode(IOReturn error_code) { |
| 32 return base::StringPrintf("0x%04x", error_code); |
| 33 } |
| 34 |
30 bool TryGetHidIntProperty(IOHIDDeviceRef device, | 35 bool TryGetHidIntProperty(IOHIDDeviceRef device, |
31 CFStringRef key, | 36 CFStringRef key, |
32 int32_t* result) { | 37 int32_t* result) { |
33 CFNumberRef ref = | 38 CFNumberRef ref = |
34 base::mac::CFCast<CFNumberRef>(IOHIDDeviceGetProperty(device, key)); | 39 base::mac::CFCast<CFNumberRef>(IOHIDDeviceGetProperty(device, key)); |
35 return ref && CFNumberGetValue(ref, kCFNumberSInt32Type, result); | 40 return ref && CFNumberGetValue(ref, kCFNumberSInt32Type, result); |
36 } | 41 } |
37 | 42 |
38 int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key) { | 43 int32_t GetHidIntProperty(IOHIDDeviceRef device, CFStringRef key) { |
39 int32_t value; | 44 int32_t value; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 | 94 |
90 io_iterator_t iterator; | 95 io_iterator_t iterator; |
91 IOReturn result = | 96 IOReturn result = |
92 IOServiceAddMatchingNotification(notify_port_, | 97 IOServiceAddMatchingNotification(notify_port_, |
93 kIOFirstMatchNotification, | 98 kIOFirstMatchNotification, |
94 IOServiceMatching(kIOHIDDeviceKey), | 99 IOServiceMatching(kIOHIDDeviceKey), |
95 FirstMatchCallback, | 100 FirstMatchCallback, |
96 this, | 101 this, |
97 &iterator); | 102 &iterator); |
98 if (result != kIOReturnSuccess) { | 103 if (result != kIOReturnSuccess) { |
99 LOG(ERROR) << "Failed to listen for device arrival: " | 104 HID_LOG(ERROR) << "Failed to listen for device arrival: " |
100 << base::StringPrintf("0x%04x", result); | 105 << HexErrorCode(result); |
101 return; | 106 return; |
102 } | 107 } |
103 | 108 |
104 // Drain the iterator to arm the notification. | 109 // Drain the iterator to arm the notification. |
105 devices_added_iterator_.reset(iterator); | 110 devices_added_iterator_.reset(iterator); |
106 AddDevices(); | 111 AddDevices(); |
107 iterator = IO_OBJECT_NULL; | 112 iterator = IO_OBJECT_NULL; |
108 | 113 |
109 result = IOServiceAddMatchingNotification(notify_port_, | 114 result = IOServiceAddMatchingNotification(notify_port_, |
110 kIOTerminatedNotification, | 115 kIOTerminatedNotification, |
111 IOServiceMatching(kIOHIDDeviceKey), | 116 IOServiceMatching(kIOHIDDeviceKey), |
112 TerminatedCallback, | 117 TerminatedCallback, |
113 this, | 118 this, |
114 &iterator); | 119 &iterator); |
115 if (result != kIOReturnSuccess) { | 120 if (result != kIOReturnSuccess) { |
116 LOG(ERROR) << "Failed to listen for device removal: " | 121 HID_LOG(ERROR) << "Failed to listen for device removal: " |
117 << base::StringPrintf("0x%04x", result); | 122 << HexErrorCode(result); |
118 return; | 123 return; |
119 } | 124 } |
120 | 125 |
121 // Drain devices_added_iterator_ to arm the notification. | 126 // Drain devices_added_iterator_ to arm the notification. |
122 devices_removed_iterator_.reset(iterator); | 127 devices_removed_iterator_.reset(iterator); |
123 RemoveDevices(); | 128 RemoveDevices(); |
124 FirstEnumerationComplete(); | 129 FirstEnumerationComplete(); |
125 } | 130 } |
126 | 131 |
127 void HidServiceMac::Connect(const HidDeviceId& device_id, | 132 void HidServiceMac::Connect(const HidDeviceId& device_id, |
128 const ConnectCallback& callback) { | 133 const ConnectCallback& callback) { |
129 DCHECK(thread_checker_.CalledOnValidThread()); | 134 DCHECK(thread_checker_.CalledOnValidThread()); |
130 | 135 |
131 const auto& map_entry = devices().find(device_id); | 136 const auto& map_entry = devices().find(device_id); |
132 if (map_entry == devices().end()) { | 137 if (map_entry == devices().end()) { |
133 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); | 138 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
134 return; | 139 return; |
135 } | 140 } |
136 scoped_refptr<HidDeviceInfo> device_info = map_entry->second; | 141 scoped_refptr<HidDeviceInfo> device_info = map_entry->second; |
137 | 142 |
138 io_string_t service_path; | 143 io_string_t service_path; |
139 strncpy(service_path, device_id.c_str(), sizeof service_path); | 144 strncpy(service_path, device_id.c_str(), sizeof service_path); |
140 base::mac::ScopedIOObject<io_service_t> service( | 145 base::mac::ScopedIOObject<io_service_t> service( |
141 IORegistryEntryFromPath(kIOMasterPortDefault, service_path)); | 146 IORegistryEntryFromPath(kIOMasterPortDefault, service_path)); |
142 if (!service.get()) { | 147 if (!service.get()) { |
143 VLOG(1) << "IOService not found for path: " << device_id; | 148 HID_LOG(EVENT) << "IOService not found for path: " << device_id; |
144 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); | 149 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
145 return; | 150 return; |
146 } | 151 } |
147 | 152 |
148 base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device( | 153 base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device( |
149 IOHIDDeviceCreate(kCFAllocatorDefault, service)); | 154 IOHIDDeviceCreate(kCFAllocatorDefault, service)); |
150 if (!hid_device) { | 155 if (!hid_device) { |
151 VLOG(1) << "Unable to create IOHIDDevice object."; | 156 HID_LOG(EVENT) << "Unable to create IOHIDDevice object."; |
152 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); | 157 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
153 return; | 158 return; |
154 } | 159 } |
155 | 160 |
156 IOReturn result = IOHIDDeviceOpen(hid_device, kIOHIDOptionsTypeNone); | 161 IOReturn result = IOHIDDeviceOpen(hid_device, kIOHIDOptionsTypeNone); |
157 if (result != kIOReturnSuccess) { | 162 if (result != kIOReturnSuccess) { |
158 VLOG(1) << "Failed to open device: " << base::StringPrintf("0x%04x", | 163 HID_LOG(EVENT) << "Failed to open device: " << HexErrorCode(result); |
159 result); | |
160 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); | 164 task_runner_->PostTask(FROM_HERE, base::Bind(callback, nullptr)); |
161 return; | 165 return; |
162 } | 166 } |
163 | 167 |
164 task_runner_->PostTask( | 168 task_runner_->PostTask( |
165 FROM_HERE, base::Bind(callback, make_scoped_refptr(new HidConnectionMac( | 169 FROM_HERE, base::Bind(callback, make_scoped_refptr(new HidConnectionMac( |
166 hid_device.release(), device_info, | 170 hid_device.release(), device_info, |
167 file_task_runner_)))); | 171 file_task_runner_)))); |
168 } | 172 } |
169 | 173 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 } | 226 } |
223 } | 227 } |
224 | 228 |
225 // static | 229 // static |
226 scoped_refptr<HidDeviceInfo> HidServiceMac::CreateDeviceInfo( | 230 scoped_refptr<HidDeviceInfo> HidServiceMac::CreateDeviceInfo( |
227 io_service_t service) { | 231 io_service_t service) { |
228 io_string_t service_path; | 232 io_string_t service_path; |
229 IOReturn result = | 233 IOReturn result = |
230 IORegistryEntryGetPath(service, kIOServicePlane, service_path); | 234 IORegistryEntryGetPath(service, kIOServicePlane, service_path); |
231 if (result != kIOReturnSuccess) { | 235 if (result != kIOReturnSuccess) { |
232 VLOG(1) << "Failed to get IOService path: " << base::StringPrintf("0x%04x", | 236 HID_LOG(EVENT) << "Failed to get IOService path: " << HexErrorCode(result); |
233 result); | |
234 return nullptr; | 237 return nullptr; |
235 } | 238 } |
236 | 239 |
237 base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device( | 240 base::ScopedCFTypeRef<IOHIDDeviceRef> hid_device( |
238 IOHIDDeviceCreate(kCFAllocatorDefault, service)); | 241 IOHIDDeviceCreate(kCFAllocatorDefault, service)); |
239 if (!hid_device) { | 242 if (!hid_device) { |
240 VLOG(1) << "Unable to create IOHIDDevice object for " << service_path | 243 HID_LOG(EVENT) << "Unable to create IOHIDDevice object for " << service_path |
241 << "."; | 244 << "."; |
242 return nullptr; | 245 return nullptr; |
243 } | 246 } |
244 | 247 |
245 std::vector<uint8> report_descriptor; | 248 std::vector<uint8> report_descriptor; |
246 if (!TryGetHidDataProperty(hid_device, CFSTR(kIOHIDReportDescriptorKey), | 249 if (!TryGetHidDataProperty(hid_device, CFSTR(kIOHIDReportDescriptorKey), |
247 &report_descriptor)) { | 250 &report_descriptor)) { |
248 VLOG(1) << "Unable to get report descriptor for " << service_path << "."; | 251 HID_LOG(EVENT) << "Unable to get report descriptor for " << service_path |
| 252 << "."; |
249 return nullptr; | 253 return nullptr; |
250 } | 254 } |
251 | 255 |
252 return new HidDeviceInfo( | 256 return new HidDeviceInfo( |
253 service_path, GetHidIntProperty(hid_device, CFSTR(kIOHIDVendorIDKey)), | 257 service_path, GetHidIntProperty(hid_device, CFSTR(kIOHIDVendorIDKey)), |
254 GetHidIntProperty(hid_device, CFSTR(kIOHIDProductIDKey)), | 258 GetHidIntProperty(hid_device, CFSTR(kIOHIDProductIDKey)), |
255 GetHidStringProperty(hid_device, CFSTR(kIOHIDProductKey)), | 259 GetHidStringProperty(hid_device, CFSTR(kIOHIDProductKey)), |
256 GetHidStringProperty(hid_device, CFSTR(kIOHIDSerialNumberKey)), | 260 GetHidStringProperty(hid_device, CFSTR(kIOHIDSerialNumberKey)), |
257 kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335 | 261 kHIDBusTypeUSB, // TODO(reillyg): Detect Bluetooth. crbug.com/443335 |
258 report_descriptor); | 262 report_descriptor); |
259 } | 263 } |
260 | 264 |
261 } // namespace device | 265 } // namespace device |
OLD | NEW |