OLD | NEW |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 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_connection_mac.h" | 5 #include "device/hid/hid_connection_mac.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/mac/foundation_util.h" | 8 #include "base/mac/foundation_util.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "device/hid/hid_connection_mac.h" | 10 #include "device/hid/hid_connection_mac.h" |
11 | 11 |
12 namespace device { | 12 namespace device { |
13 | 13 |
14 HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info) | 14 HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info) |
15 : HidConnection(device_info), | 15 : HidConnection(device_info), |
16 device_(device_info.device_id, base::scoped_policy::RETAIN) { | 16 device_(device_info.device_id, base::scoped_policy::RETAIN) { |
17 message_loop_ = base::MessageLoopProxy::current(); | 17 message_loop_ = base::MessageLoopProxy::current(); |
18 | 18 |
19 DCHECK(device_.get()); | 19 DCHECK(device_.get()); |
| 20 |
20 size_t expected_report_size = device_info.max_input_report_size; | 21 size_t expected_report_size = device_info.max_input_report_size; |
21 if (device_info.has_report_id) { | 22 if (device_info.has_report_id) { |
22 expected_report_size++; | 23 expected_report_size++; |
23 } | 24 } |
24 inbound_buffer_.reset(new uint8_t[expected_report_size]); | 25 inbound_buffer_.resize(expected_report_size); |
25 IOHIDDeviceRegisterInputReportCallback(device_.get(), | 26 if (inbound_buffer_.size() > 0) { |
26 inbound_buffer_.get(), | 27 IOHIDDeviceRegisterInputReportCallback( |
27 expected_report_size, | 28 device_.get(), |
28 &HidConnectionMac::InputReportCallback, | 29 &inbound_buffer_[0], |
29 this); | 30 inbound_buffer_.size(), |
30 IOHIDDeviceOpen(device_, kIOHIDOptionsTypeNone); | 31 &HidConnectionMac::InputReportCallback, |
| 32 this); |
| 33 } |
31 } | 34 } |
32 | 35 |
33 HidConnectionMac::~HidConnectionMac() { | 36 HidConnectionMac::~HidConnectionMac() { |
34 IOHIDDeviceClose(device_, kIOHIDOptionsTypeNone); | 37 if (inbound_buffer_.size() > 0) { |
| 38 // Unregister the input report callback before this object is freed. |
| 39 IOHIDDeviceRegisterInputReportCallback( |
| 40 device_.get(), &inbound_buffer_[0], inbound_buffer_.size(), NULL, this); |
| 41 } |
35 Flush(); | 42 Flush(); |
36 } | 43 } |
37 | 44 |
38 void HidConnectionMac::PlatformRead(const ReadCallback& callback) { | 45 void HidConnectionMac::PlatformRead(const ReadCallback& callback) { |
39 if (!device_) { | 46 if (!device_) { |
40 callback.Run(false, NULL, 0); | 47 callback.Run(false, NULL, 0); |
41 return; | 48 return; |
42 } | 49 } |
43 | 50 |
44 PendingHidRead pending_read; | 51 PendingHidRead pending_read; |
(...skipping 20 matching lines...) Expand all Loading... |
65 CFIndex report_size = buffer->size(); | 72 CFIndex report_size = buffer->size(); |
66 IOReturn result = | 73 IOReturn result = |
67 IOHIDDeviceGetReport(device_, | 74 IOHIDDeviceGetReport(device_, |
68 kIOHIDReportTypeFeature, | 75 kIOHIDReportTypeFeature, |
69 report_id, | 76 report_id, |
70 reinterpret_cast<uint8_t*>(buffer->data()), | 77 reinterpret_cast<uint8_t*>(buffer->data()), |
71 &report_size); | 78 &report_size); |
72 if (result == kIOReturnSuccess) { | 79 if (result == kIOReturnSuccess) { |
73 callback.Run(true, buffer, report_size); | 80 callback.Run(true, buffer, report_size); |
74 } else { | 81 } else { |
| 82 VLOG(1) << "Failed to get feature report: " << result; |
75 callback.Run(false, NULL, 0); | 83 callback.Run(false, NULL, 0); |
76 } | 84 } |
77 } | 85 } |
78 | 86 |
79 void HidConnectionMac::PlatformSendFeatureReport( | 87 void HidConnectionMac::PlatformSendFeatureReport( |
80 scoped_refptr<net::IOBuffer> buffer, | 88 scoped_refptr<net::IOBuffer> buffer, |
81 size_t size, | 89 size_t size, |
82 const WriteCallback& callback) { | 90 const WriteCallback& callback) { |
83 WriteReport(kIOHIDReportTypeFeature, buffer, size, callback); | 91 WriteReport(kIOHIDReportTypeFeature, buffer, size, callback); |
84 } | 92 } |
85 | 93 |
86 void HidConnectionMac::InputReportCallback(void* context, | 94 void HidConnectionMac::InputReportCallback(void* context, |
87 IOReturn result, | 95 IOReturn result, |
88 void* sender, | 96 void* sender, |
89 IOHIDReportType type, | 97 IOHIDReportType type, |
90 uint32_t report_id, | 98 uint32_t report_id, |
91 uint8_t* report_bytes, | 99 uint8_t* report_bytes, |
92 CFIndex report_length) { | 100 CFIndex report_length) { |
| 101 if (result != kIOReturnSuccess) { |
| 102 VLOG(1) << "Failed to read input report: " << result; |
| 103 return; |
| 104 } |
| 105 |
93 HidConnectionMac* connection = static_cast<HidConnectionMac*>(context); | 106 HidConnectionMac* connection = static_cast<HidConnectionMac*>(context); |
94 scoped_refptr<net::IOBufferWithSize> buffer; | 107 scoped_refptr<net::IOBufferWithSize> buffer; |
95 if (connection->device_info().has_report_id) { | 108 if (connection->device_info().has_report_id) { |
96 // report_id is already contained in report_bytes | 109 // report_id is already contained in report_bytes |
97 buffer = new net::IOBufferWithSize(report_length); | 110 buffer = new net::IOBufferWithSize(report_length); |
98 memcpy(buffer->data(), report_bytes, report_length); | 111 memcpy(buffer->data(), report_bytes, report_length); |
99 } else { | 112 } else { |
100 buffer = new net::IOBufferWithSize(report_length + 1); | 113 buffer = new net::IOBufferWithSize(report_length + 1); |
101 buffer->data()[0] = 0; | 114 buffer->data()[0] = 0; |
102 memcpy(buffer->data() + 1, report_bytes, report_length); | 115 memcpy(buffer->data() + 1, report_bytes, report_length); |
(...skipping 21 matching lines...) Expand all Loading... |
124 // report ID is non-zero. | 137 // report ID is non-zero. |
125 ++data; | 138 ++data; |
126 --size; | 139 --size; |
127 } | 140 } |
128 | 141 |
129 IOReturn res = | 142 IOReturn res = |
130 IOHIDDeviceSetReport(device_.get(), type, report_id, data, size); | 143 IOHIDDeviceSetReport(device_.get(), type, report_id, data, size); |
131 if (res == kIOReturnSuccess) { | 144 if (res == kIOReturnSuccess) { |
132 callback.Run(true); | 145 callback.Run(true); |
133 } else { | 146 } else { |
| 147 VLOG(1) << "Failed to set report: " << res; |
134 callback.Run(false); | 148 callback.Run(false); |
135 } | 149 } |
136 } | 150 } |
137 | 151 |
138 void HidConnectionMac::Flush() { | 152 void HidConnectionMac::Flush() { |
139 while (!pending_reads_.empty()) { | 153 while (!pending_reads_.empty()) { |
140 pending_reads_.front().callback.Run(false, NULL, 0); | 154 pending_reads_.front().callback.Run(false, NULL, 0); |
141 pending_reads_.pop(); | 155 pending_reads_.pop(); |
142 } | 156 } |
143 } | 157 } |
(...skipping 15 matching lines...) Expand all Loading... |
159 PendingHidReport report = pending_reports_.front(); | 173 PendingHidReport report = pending_reports_.front(); |
160 | 174 |
161 pending_reports_.pop(); | 175 pending_reports_.pop(); |
162 if (CompleteRead(report.buffer, report.size, read.callback)) { | 176 if (CompleteRead(report.buffer, report.size, read.callback)) { |
163 pending_reads_.pop(); | 177 pending_reads_.pop(); |
164 } | 178 } |
165 } | 179 } |
166 } | 180 } |
167 | 181 |
168 } // namespace device | 182 } // namespace device |
OLD | NEW |