Revert of Instrumented libraries: update the libnspr4 build script. (patchset #1...
[chromium-blink-merge.git] / device / hid / hid_connection_mac.cc
blobae1a14261df13ac440cc3aa2188dd2e27bc104d1
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"
7 #include "base/bind.h"
8 #include "base/mac/foundation_util.h"
9 #include "base/message_loop/message_loop.h"
10 #include "device/hid/hid_connection_mac.h"
12 namespace device {
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(
28 device_.get(),
29 &inbound_buffer_[0],
30 inbound_buffer_.size(),
31 &HidConnectionMac::InputReportCallback,
32 this);
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);
42 Flush();
45 void HidConnectionMac::PlatformRead(const ReadCallback& callback) {
46 if (!device_) {
47 callback.Run(false, NULL, 0);
48 return;
51 PendingHidRead pending_read;
52 pending_read.callback = callback;
53 pending_reads_.push(pending_read);
54 ProcessReadQueue();
57 void HidConnectionMac::PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
58 size_t size,
59 const WriteCallback& callback) {
60 WriteReport(kIOHIDReportTypeOutput, buffer, size, callback);
63 void HidConnectionMac::PlatformGetFeatureReport(uint8_t report_id,
64 const ReadCallback& callback) {
65 if (!device_) {
66 callback.Run(false, NULL, 0);
67 return;
70 scoped_refptr<net::IOBufferWithSize> buffer(
71 new net::IOBufferWithSize(device_info().max_feature_report_size));
72 CFIndex report_size = buffer->size();
73 IOReturn result =
74 IOHIDDeviceGetReport(device_,
75 kIOHIDReportTypeFeature,
76 report_id,
77 reinterpret_cast<uint8_t*>(buffer->data()),
78 &report_size);
79 if (result == kIOReturnSuccess) {
80 callback.Run(true, buffer, report_size);
81 } else {
82 VLOG(1) << "Failed to get feature report: " << result;
83 callback.Run(false, NULL, 0);
87 void HidConnectionMac::PlatformSendFeatureReport(
88 scoped_refptr<net::IOBuffer> buffer,
89 size_t size,
90 const WriteCallback& callback) {
91 WriteReport(kIOHIDReportTypeFeature, buffer, size, callback);
94 void HidConnectionMac::InputReportCallback(void* context,
95 IOReturn result,
96 void* sender,
97 IOHIDReportType type,
98 uint32_t report_id,
99 uint8_t* report_bytes,
100 CFIndex report_length) {
101 if (result != kIOReturnSuccess) {
102 VLOG(1) << "Failed to read input report: " << result;
103 return;
106 HidConnectionMac* connection = static_cast<HidConnectionMac*>(context);
107 scoped_refptr<net::IOBufferWithSize> buffer;
108 if (connection->device_info().has_report_id) {
109 // report_id is already contained in report_bytes
110 buffer = new net::IOBufferWithSize(report_length);
111 memcpy(buffer->data(), report_bytes, report_length);
112 } else {
113 buffer = new net::IOBufferWithSize(report_length + 1);
114 buffer->data()[0] = 0;
115 memcpy(buffer->data() + 1, report_bytes, report_length);
118 connection->message_loop_->PostTask(
119 FROM_HERE,
120 base::Bind(&HidConnectionMac::ProcessInputReport, connection, buffer));
123 void HidConnectionMac::WriteReport(IOHIDReportType type,
124 scoped_refptr<net::IOBuffer> buffer,
125 size_t size,
126 const WriteCallback& callback) {
127 if (!device_) {
128 callback.Run(false);
129 return;
132 uint8_t* data = reinterpret_cast<uint8_t*>(buffer->data());
133 DCHECK(size >= 1);
134 uint8_t report_id = data[0];
135 if (report_id == 0) {
136 // OS X only expects the first byte of the buffer to be the report ID if the
137 // report ID is non-zero.
138 ++data;
139 --size;
142 IOReturn res =
143 IOHIDDeviceSetReport(device_.get(), type, report_id, data, size);
144 if (res == kIOReturnSuccess) {
145 callback.Run(true);
146 } else {
147 VLOG(1) << "Failed to set report: " << res;
148 callback.Run(false);
152 void HidConnectionMac::Flush() {
153 while (!pending_reads_.empty()) {
154 pending_reads_.front().callback.Run(false, NULL, 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 report.size = buffer->size();
165 pending_reports_.push(report);
166 ProcessReadQueue();
169 void HidConnectionMac::ProcessReadQueue() {
170 DCHECK(thread_checker().CalledOnValidThread());
171 while (pending_reads_.size() && pending_reports_.size()) {
172 PendingHidRead read = pending_reads_.front();
173 PendingHidReport report = pending_reports_.front();
175 pending_reports_.pop();
176 if (CompleteRead(report.buffer, report.size, read.callback)) {
177 pending_reads_.pop();
182 } // namespace device