| 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 |