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());
20 inbound_buffer_
.reset((uint8_t*)malloc(device_info
.max_input_report_size
));
21 IOHIDDeviceRegisterInputReportCallback(device_
.get(),
22 inbound_buffer_
.get(),
23 device_info
.max_input_report_size
,
24 &HidConnectionMac::InputReportCallback
,
26 IOHIDDeviceOpen(device_
, kIOHIDOptionsTypeNone
);
29 HidConnectionMac::~HidConnectionMac() {
30 IOHIDDeviceClose(device_
, kIOHIDOptionsTypeNone
);
34 void HidConnectionMac::PlatformRead(scoped_refptr
<net::IOBufferWithSize
> buffer
,
35 const IOCallback
& callback
) {
37 callback
.Run(false, 0);
41 PendingHidRead pending_read
;
42 pending_read
.buffer
= buffer
;
43 pending_read
.callback
= callback
;
44 pending_reads_
.push(pending_read
);
48 void HidConnectionMac::PlatformWrite(
50 scoped_refptr
<net::IOBufferWithSize
> buffer
,
51 const IOCallback
& callback
) {
52 WriteReport(kIOHIDReportTypeOutput
, report_id
, buffer
, callback
);
55 void HidConnectionMac::PlatformGetFeatureReport(
57 scoped_refptr
<net::IOBufferWithSize
> buffer
,
58 const IOCallback
& callback
) {
60 callback
.Run(false, 0);
64 uint8_t* feature_report_buffer
= reinterpret_cast<uint8_t*>(buffer
->data());
65 CFIndex max_feature_report_size
= device_info().max_feature_report_size
;
66 IOReturn result
= IOHIDDeviceGetReport(device_
,
67 kIOHIDReportTypeFeature
,
69 feature_report_buffer
,
70 &max_feature_report_size
);
71 if (result
== kIOReturnSuccess
)
72 callback
.Run(true, max_feature_report_size
);
74 callback
.Run(false, 0);
77 void HidConnectionMac::PlatformSendFeatureReport(
79 scoped_refptr
<net::IOBufferWithSize
> buffer
,
80 const IOCallback
& callback
) {
81 WriteReport(kIOHIDReportTypeFeature
, report_id
, buffer
, callback
);
84 void HidConnectionMac::InputReportCallback(void* context
,
89 uint8_t* report_bytes
,
90 CFIndex report_length
) {
91 HidConnectionMac
* connection
= static_cast<HidConnectionMac
*>(context
);
92 // report_id is already contained in report_bytes
93 scoped_refptr
<net::IOBufferWithSize
> buffer
;
94 buffer
= new net::IOBufferWithSize(report_length
);
95 memcpy(buffer
->data(), report_bytes
, report_length
);
97 connection
->message_loop_
->PostTask(
99 base::Bind(&HidConnectionMac::ProcessInputReport
, connection
, buffer
));
102 void HidConnectionMac::WriteReport(IOHIDReportType type
,
104 scoped_refptr
<net::IOBufferWithSize
> buffer
,
105 const IOCallback
& callback
) {
107 callback
.Run(false, 0);
111 scoped_refptr
<net::IOBufferWithSize
> output_buffer
;
112 if (report_id
!= 0) {
113 output_buffer
= new net::IOBufferWithSize(buffer
->size() + 1);
114 output_buffer
->data()[0] = static_cast<uint8_t>(report_id
);
115 memcpy(output_buffer
->data() + 1, buffer
->data(), buffer
->size());
117 output_buffer
= new net::IOBufferWithSize(buffer
->size());
118 memcpy(output_buffer
->data(), buffer
->data(), buffer
->size());
121 IOHIDDeviceSetReport(device_
.get(),
124 reinterpret_cast<uint8_t*>(output_buffer
->data()),
125 output_buffer
->size());
126 if (res
!= kIOReturnSuccess
) {
127 callback
.Run(false, 0);
129 callback
.Run(true, output_buffer
->size());
133 void HidConnectionMac::Flush() {
134 while (!pending_reads_
.empty()) {
135 pending_reads_
.front().callback
.Run(false, 0);
136 pending_reads_
.pop();
140 void HidConnectionMac::ProcessInputReport(
141 scoped_refptr
<net::IOBufferWithSize
> buffer
) {
142 DCHECK(thread_checker().CalledOnValidThread());
143 PendingHidReport report
;
144 report
.buffer
= buffer
;
145 pending_reports_
.push(report
);
149 void HidConnectionMac::ProcessReadQueue() {
150 DCHECK(thread_checker().CalledOnValidThread());
151 while (pending_reads_
.size() && pending_reports_
.size()) {
152 PendingHidRead read
= pending_reads_
.front();
153 PendingHidReport report
= pending_reports_
.front();
155 if (read
.buffer
->size() < report
.buffer
->size()) {
156 read
.callback
.Run(false, 0);
157 pending_reads_
.pop();
159 memcpy(read
.buffer
->data(), report
.buffer
->data(), report
.buffer
->size());
160 pending_reports_
.pop();
162 if (CompleteRead(report
.buffer
, read
.callback
)) {
163 pending_reads_
.pop();
169 } // namespace device