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
3 // found in the LICENSE file.
5 #include "device/hid/hid_connection_mac.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/message_loop/message_loop.h"
10 #include "device/hid/hid_connection_mac.h"
14 HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info)
15 : HidConnection(device_info),
16 device_(device_info.device_id, base::scoped_policy::RETAIN) {
17 message_loop_ = base::MessageLoopProxy::current();
19 DCHECK(device_.get());
21 size_t expected_report_size = device_info.max_input_report_size;
22 if (device_info.has_report_id) {
23 expected_report_size++;
25 inbound_buffer_.resize(expected_report_size);
26 if (inbound_buffer_.size() > 0) {
27 IOHIDDeviceRegisterInputReportCallback(
30 inbound_buffer_.size(),
31 &HidConnectionMac::InputReportCallback,
36 HidConnectionMac::~HidConnectionMac() {
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);
45 void HidConnectionMac::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer,
46 const IOCallback& callback) {
48 callback.Run(false, 0);
52 PendingHidRead pending_read;
53 pending_read.buffer = buffer;
54 pending_read.callback = callback;
55 pending_reads_.push(pending_read);
59 void HidConnectionMac::PlatformWrite(
61 scoped_refptr<net::IOBufferWithSize> buffer,
62 const IOCallback& callback) {
63 WriteReport(kIOHIDReportTypeOutput, report_id, buffer, callback);
66 void HidConnectionMac::PlatformGetFeatureReport(
68 scoped_refptr<net::IOBufferWithSize> buffer,
69 const IOCallback& callback) {
71 callback.Run(false, 0);
75 uint8_t* feature_report_buffer = reinterpret_cast<uint8_t*>(buffer->data());
76 CFIndex report_size = buffer->size();
77 IOReturn result = IOHIDDeviceGetReport(device_,
78 kIOHIDReportTypeFeature,
80 feature_report_buffer,
82 if (result == kIOReturnSuccess)
83 callback.Run(true, report_size);
85 VLOG(1) << "Failed to get feature report: " << result;
86 callback.Run(false, 0);
90 void HidConnectionMac::PlatformSendFeatureReport(
92 scoped_refptr<net::IOBufferWithSize> buffer,
93 const IOCallback& callback) {
94 WriteReport(kIOHIDReportTypeFeature, report_id, buffer, callback);
97 void HidConnectionMac::InputReportCallback(void* context,
100 IOHIDReportType type,
102 uint8_t* report_bytes,
103 CFIndex report_length) {
104 if (result != kIOReturnSuccess) {
105 VLOG(1) << "Failed to read input report: " << result;
109 HidConnectionMac* connection = static_cast<HidConnectionMac*>(context);
110 // report_id is already contained in report_bytes
111 scoped_refptr<net::IOBufferWithSize> buffer;
112 buffer = new net::IOBufferWithSize(report_length);
113 memcpy(buffer->data(), report_bytes, report_length);
115 connection->message_loop_->PostTask(
117 base::Bind(&HidConnectionMac::ProcessInputReport, connection, buffer));
120 void HidConnectionMac::WriteReport(IOHIDReportType type,
122 scoped_refptr<net::IOBufferWithSize> buffer,
123 const IOCallback& callback) {
125 callback.Run(false, 0);
129 scoped_refptr<net::IOBufferWithSize> output_buffer;
130 if (report_id != 0) {
131 output_buffer = new net::IOBufferWithSize(buffer->size() + 1);
132 output_buffer->data()[0] = static_cast<uint8_t>(report_id);
133 memcpy(output_buffer->data() + 1, buffer->data(), buffer->size());
135 output_buffer = new net::IOBufferWithSize(buffer->size());
136 memcpy(output_buffer->data(), buffer->data(), buffer->size());
139 IOHIDDeviceSetReport(device_.get(),
142 reinterpret_cast<uint8_t*>(output_buffer->data()),
143 output_buffer->size());
144 if (res != kIOReturnSuccess) {
145 callback.Run(false, 0);
147 VLOG(1) << "Failed to set report: " << res;
148 callback.Run(true, output_buffer->size());
152 void HidConnectionMac::Flush() {
153 while (!pending_reads_.empty()) {
154 pending_reads_.front().callback.Run(false, 0);
155 pending_reads_.pop();
159 void HidConnectionMac::ProcessInputReport(
160 scoped_refptr<net::IOBufferWithSize> buffer) {
161 DCHECK(thread_checker().CalledOnValidThread());
162 PendingHidReport report;
163 report.buffer = buffer;
164 pending_reports_.push(report);
168 void HidConnectionMac::ProcessReadQueue() {
169 DCHECK(thread_checker().CalledOnValidThread());
170 while (pending_reads_.size() && pending_reports_.size()) {
171 PendingHidRead read = pending_reads_.front();
172 PendingHidReport report = pending_reports_.front();
174 if (read.buffer->size() < report.buffer->size()) {
175 read.callback.Run(false, 0);
176 pending_reads_.pop();
178 memcpy(read.buffer->data(), report.buffer->data(), report.buffer->size());
179 pending_reports_.pop();
181 if (CompleteRead(read.buffer, report.buffer->size(), read.callback)) {
182 pending_reads_.pop();
188 } // namespace device