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 "base/threading/thread_restrictions.h"
11 #include "device/hid/hid_connection_mac.h"
15 HidConnectionMac::HidConnectionMac(HidDeviceInfo device_info
)
16 : HidConnection(device_info
),
17 device_(device_info
.device_id
, base::scoped_policy::RETAIN
) {
18 DCHECK(thread_checker_
.CalledOnValidThread());
20 message_loop_
= base::MessageLoopProxy::current();
22 DCHECK(device_
.get());
23 inbound_buffer_
.reset((uint8_t*)malloc(device_info
.input_report_size
));
24 IOHIDDeviceRegisterInputReportCallback(device_
.get(),
25 inbound_buffer_
.get(),
26 device_info
.input_report_size
,
27 &HidConnectionMac::InputReportCallback
,
29 IOHIDDeviceOpen(device_
, kIOHIDOptionsTypeNone
);
32 HidConnectionMac::~HidConnectionMac() {
33 DCHECK(thread_checker_
.CalledOnValidThread());
35 while (!pending_reads_
.empty()) {
36 pending_reads_
.front().callback
.Run(false, 0);
40 IOHIDDeviceClose(device_
, kIOHIDOptionsTypeNone
);
43 void HidConnectionMac::Read(scoped_refptr
<net::IOBufferWithSize
> buffer
,
44 const IOCallback
& callback
) {
45 DCHECK(thread_checker_
.CalledOnValidThread());
47 callback
.Run(false, 0);
52 read
.callback
= callback
;
53 pending_reads_
.push(read
);
57 void HidConnectionMac::Write(uint8_t report_id
,
58 scoped_refptr
<net::IOBufferWithSize
> buffer
,
59 const IOCallback
& callback
) {
60 DCHECK(thread_checker_
.CalledOnValidThread());
61 WriteReport(kIOHIDReportTypeOutput
, report_id
, buffer
, callback
);
64 void HidConnectionMac::GetFeatureReport(
66 scoped_refptr
<net::IOBufferWithSize
> buffer
,
67 const IOCallback
& callback
) {
68 DCHECK(thread_checker_
.CalledOnValidThread());
69 if (device_info().feature_report_size
== 0) {
70 callback
.Run(false, 0);
74 if (buffer
->size() < device_info().feature_report_size
) {
75 callback
.Run(false, 0);
79 uint8_t* feature_report_buffer
= reinterpret_cast<uint8_t*>(buffer
->data());
80 CFIndex feature_report_size
= device_info().feature_report_size
;
81 IOReturn result
= IOHIDDeviceGetReport(device_
,
82 kIOHIDReportTypeFeature
,
84 feature_report_buffer
,
85 &feature_report_size
);
86 if (result
== kIOReturnSuccess
)
87 callback
.Run(true, feature_report_size
);
89 callback
.Run(false, 0);
92 void HidConnectionMac::SendFeatureReport(
94 scoped_refptr
<net::IOBufferWithSize
> buffer
,
95 const IOCallback
& callback
) {
96 DCHECK(thread_checker_
.CalledOnValidThread());
97 WriteReport(kIOHIDReportTypeFeature
, report_id
, buffer
, callback
);
100 void HidConnectionMac::InputReportCallback(void* context
,
103 IOHIDReportType type
,
105 uint8_t* report_bytes
,
106 CFIndex report_length
) {
107 HidConnectionMac
* connection
= static_cast<HidConnectionMac
*>(context
);
108 // report_id is already contained in report_bytes
109 scoped_refptr
<net::IOBufferWithSize
> buffer
;
110 buffer
= new net::IOBufferWithSize(report_length
);
111 memcpy(buffer
->data(), report_bytes
, report_length
);
113 connection
->message_loop_
->PostTask(
116 &HidConnectionMac::ProcessInputReport
, connection
, type
, buffer
));
119 void HidConnectionMac::ProcessReadQueue() {
120 DCHECK(thread_checker_
.CalledOnValidThread());
121 while (pending_reads_
.size() && pending_reports_
.size()) {
122 PendingHidRead read
= pending_reads_
.front();
123 pending_reads_
.pop();
124 PendingHidReport report
= pending_reports_
.front();
125 if (read
.buffer
->size() < report
.buffer
->size()) {
126 read
.callback
.Run(false, report
.buffer
->size());
128 memcpy(read
.buffer
->data(), report
.buffer
->data(), report
.buffer
->size());
129 pending_reports_
.pop();
130 read
.callback
.Run(true, report
.buffer
->size());
135 void HidConnectionMac::ProcessInputReport(
136 IOHIDReportType type
,
137 scoped_refptr
<net::IOBufferWithSize
> buffer
) {
138 DCHECK(thread_checker_
.CalledOnValidThread());
139 PendingHidReport report
;
140 report
.buffer
= buffer
;
141 pending_reports_
.push(report
);
145 void HidConnectionMac::WriteReport(IOHIDReportType type
,
147 scoped_refptr
<net::IOBufferWithSize
> buffer
,
148 const IOCallback
& callback
) {
149 DCHECK(thread_checker_
.CalledOnValidThread());
151 callback
.Run(false, 0);
154 scoped_refptr
<net::IOBufferWithSize
> output_buffer
;
155 if (report_id
!= 0) {
156 output_buffer
= new net::IOBufferWithSize(buffer
->size() + 1);
157 output_buffer
->data()[0] = static_cast<uint8_t>(report_id
);
158 memcpy(output_buffer
->data() + 1, buffer
->data(), buffer
->size());
160 output_buffer
= new net::IOBufferWithSize(buffer
->size());
161 memcpy(output_buffer
->data(), buffer
->data(), buffer
->size());
164 IOHIDDeviceSetReport(device_
.get(),
167 reinterpret_cast<uint8_t*>(output_buffer
->data()),
168 output_buffer
->size());
169 if (res
!= kIOReturnSuccess
) {
170 callback
.Run(false, 0);
172 callback
.Run(true, output_buffer
->size());
176 } // namespace device