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(const ReadCallback
& callback
) {
47 callback
.Run(false, NULL
, 0);
51 PendingHidRead pending_read
;
52 pending_read
.callback
= callback
;
53 pending_reads_
.push(pending_read
);
57 void HidConnectionMac::PlatformWrite(scoped_refptr
<net::IOBuffer
> buffer
,
59 const WriteCallback
& callback
) {
60 WriteReport(kIOHIDReportTypeOutput
, buffer
, size
, callback
);
63 void HidConnectionMac::PlatformGetFeatureReport(uint8_t report_id
,
64 const ReadCallback
& callback
) {
66 callback
.Run(false, NULL
, 0);
70 scoped_refptr
<net::IOBufferWithSize
> buffer(
71 new net::IOBufferWithSize(device_info().max_feature_report_size
));
72 CFIndex report_size
= buffer
->size();
74 IOHIDDeviceGetReport(device_
,
75 kIOHIDReportTypeFeature
,
77 reinterpret_cast<uint8_t*>(buffer
->data()),
79 if (result
== kIOReturnSuccess
) {
80 callback
.Run(true, buffer
, report_size
);
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
,
90 const WriteCallback
& callback
) {
91 WriteReport(kIOHIDReportTypeFeature
, buffer
, size
, callback
);
94 void HidConnectionMac::InputReportCallback(void* context
,
99 uint8_t* report_bytes
,
100 CFIndex report_length
) {
101 if (result
!= kIOReturnSuccess
) {
102 VLOG(1) << "Failed to read input report: " << result
;
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
);
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(
120 base::Bind(&HidConnectionMac::ProcessInputReport
, connection
, buffer
));
123 void HidConnectionMac::WriteReport(IOHIDReportType type
,
124 scoped_refptr
<net::IOBuffer
> buffer
,
126 const WriteCallback
& callback
) {
132 uint8_t* data
= reinterpret_cast<uint8_t*>(buffer
->data());
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.
143 IOHIDDeviceSetReport(device_
.get(), type
, report_id
, data
, size
);
144 if (res
== kIOReturnSuccess
) {
147 VLOG(1) << "Failed to set report: " << res
;
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
);
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