Remove "bashism" from plain shell script
[chromium-blink-merge.git] / device / hid / hid_service_mac.cc
blob3df7e592333e6b8ec9620d8f924456b951202572
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.
5 #include "device/hid/hid_service_mac.h"
7 #include <CoreFoundation/CoreFoundation.h>
8 #include <IOKit/hid/IOHIDManager.h>
10 #include <string>
11 #include <vector>
13 #include "base/bind.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop_proxy.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "device/hid/hid_connection_mac.h"
20 #include "device/hid/hid_utils_mac.h"
22 namespace device {
24 class HidServiceMac;
26 namespace {
28 typedef std::vector<IOHIDDeviceRef> HidDeviceList;
30 HidServiceMac* HidServiceFromContext(void* context) {
31 return static_cast<HidServiceMac*>(context);
34 // Callback for CFSetApplyFunction as used by EnumerateHidDevices.
35 void HidEnumerationBackInserter(const void* value, void* context) {
36 HidDeviceList* devices = static_cast<HidDeviceList*>(context);
37 const IOHIDDeviceRef device =
38 static_cast<IOHIDDeviceRef>(const_cast<void*>(value));
39 devices->push_back(device);
42 void EnumerateHidDevices(IOHIDManagerRef hid_manager,
43 HidDeviceList* device_list) {
44 DCHECK(device_list->size() == 0);
45 // Note that our ownership of each copied device is implied.
46 base::ScopedCFTypeRef<CFSetRef> devices(IOHIDManagerCopyDevices(hid_manager));
47 if (devices)
48 CFSetApplyFunction(devices, HidEnumerationBackInserter, device_list);
51 } // namespace
53 HidServiceMac::HidServiceMac() {
54 DCHECK(thread_checker_.CalledOnValidThread());
55 message_loop_ = base::MessageLoopProxy::current();
56 DCHECK(message_loop_);
57 hid_manager_.reset(IOHIDManagerCreate(NULL, 0));
58 if (!hid_manager_) {
59 LOG(ERROR) << "Failed to initialize HidManager";
60 return;
62 DCHECK(CFGetTypeID(hid_manager_) == IOHIDManagerGetTypeID());
63 IOHIDManagerOpen(hid_manager_, kIOHIDOptionsTypeNone);
64 IOHIDManagerSetDeviceMatching(hid_manager_, NULL);
66 // Enumerate all the currently known devices.
67 Enumerate();
69 // Register for plug/unplug notifications.
70 StartWatchingDevices();
73 HidServiceMac::~HidServiceMac() {
74 StopWatchingDevices();
77 void HidServiceMac::StartWatchingDevices() {
78 DCHECK(thread_checker_.CalledOnValidThread());
79 IOHIDManagerRegisterDeviceMatchingCallback(
80 hid_manager_, &AddDeviceCallback, this);
81 IOHIDManagerRegisterDeviceRemovalCallback(
82 hid_manager_, &RemoveDeviceCallback, this);
83 IOHIDManagerScheduleWithRunLoop(
84 hid_manager_, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
87 void HidServiceMac::StopWatchingDevices() {
88 DCHECK(thread_checker_.CalledOnValidThread());
89 if (!hid_manager_)
90 return;
91 IOHIDManagerUnscheduleFromRunLoop(
92 hid_manager_, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
93 IOHIDManagerClose(hid_manager_, kIOHIDOptionsTypeNone);
96 void HidServiceMac::AddDeviceCallback(void* context,
97 IOReturn result,
98 void* sender,
99 IOHIDDeviceRef hid_device) {
100 DCHECK(CFRunLoopGetMain() == CFRunLoopGetCurrent());
101 // Claim ownership of the device.
102 CFRetain(hid_device);
103 HidServiceMac* service = HidServiceFromContext(context);
104 service->message_loop_->PostTask(FROM_HERE,
105 base::Bind(&HidServiceMac::PlatformAddDevice,
106 base::Unretained(service),
107 base::Unretained(hid_device)));
110 void HidServiceMac::RemoveDeviceCallback(void* context,
111 IOReturn result,
112 void* sender,
113 IOHIDDeviceRef hid_device) {
114 DCHECK(CFRunLoopGetMain() == CFRunLoopGetCurrent());
115 HidServiceMac* service = HidServiceFromContext(context);
116 service->message_loop_->PostTask(
117 FROM_HERE,
118 base::Bind(&HidServiceMac::PlatformRemoveDevice,
119 base::Unretained(service),
120 base::Unretained(hid_device)));
123 void HidServiceMac::Enumerate() {
124 DCHECK(thread_checker_.CalledOnValidThread());
125 HidDeviceList devices;
126 EnumerateHidDevices(hid_manager_, &devices);
127 for (HidDeviceList::const_iterator iter = devices.begin();
128 iter != devices.end();
129 ++iter) {
130 IOHIDDeviceRef hid_device = *iter;
131 PlatformAddDevice(hid_device);
135 void HidServiceMac::PlatformAddDevice(IOHIDDeviceRef hid_device) {
136 // Note that our ownership of hid_device is implied if calling this method.
137 // It is balanced in PlatformRemoveDevice.
138 DCHECK(thread_checker_.CalledOnValidThread());
140 HidDeviceInfo device_info;
141 device_info.device_id = hid_device;
142 device_info.vendor_id =
143 GetHidIntProperty(hid_device, CFSTR(kIOHIDVendorIDKey));
144 device_info.product_id =
145 GetHidIntProperty(hid_device, CFSTR(kIOHIDProductIDKey));
146 device_info.usage =
147 GetHidIntProperty(hid_device, CFSTR(kIOHIDPrimaryUsageKey));
148 device_info.usage_page =
149 GetHidIntProperty(hid_device, CFSTR(kIOHIDPrimaryUsagePageKey));
150 device_info.input_report_size =
151 GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxInputReportSizeKey));
152 device_info.output_report_size =
153 GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxOutputReportSizeKey));
154 device_info.feature_report_size =
155 GetHidIntProperty(hid_device, CFSTR(kIOHIDMaxFeatureReportSizeKey));
156 device_info.product_name =
157 GetHidStringProperty(hid_device, CFSTR(kIOHIDProductKey));
158 device_info.serial_number =
159 GetHidStringProperty(hid_device, CFSTR(kIOHIDSerialNumberKey));
160 AddDevice(device_info);
163 void HidServiceMac::PlatformRemoveDevice(IOHIDDeviceRef hid_device) {
164 DCHECK(thread_checker_.CalledOnValidThread());
165 RemoveDevice(hid_device);
166 CFRelease(hid_device);
169 scoped_refptr<HidConnection> HidServiceMac::Connect(
170 const HidDeviceId& device_id) {
171 DCHECK(thread_checker_.CalledOnValidThread());
172 HidDeviceInfo device_info;
173 if (!GetDeviceInfo(device_id, &device_info))
174 return NULL;
175 return scoped_refptr<HidConnection>(new HidConnectionMac(device_info));
178 } // namespace device