Revert of Instrumented libraries: update the libnspr4 build script. (patchset #1...
[chromium-blink-merge.git] / device / hid / hid_connection_win.cc
blob8e00ae03db499fa2c77067a5de89955a058b0fa4
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_win.h"
7 #include <cstring>
9 #include "base/bind.h"
10 #include "base/files/file.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/win/object_watcher.h"
14 #define INITGUID
16 #include <windows.h>
17 #include <hidclass.h>
19 extern "C" {
20 #include <hidsdi.h>
23 #include <setupapi.h>
24 #include <winioctl.h>
26 namespace device {
28 struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>,
29 public base::win::ObjectWatcher::Delegate,
30 public base::MessageLoop::DestructionObserver {
31 typedef base::Callback<void(PendingHidTransfer*, bool)> Callback;
33 PendingHidTransfer(scoped_refptr<net::IOBuffer> buffer,
34 const Callback& callback);
36 void TakeResultFromWindowsAPI(BOOL result);
38 OVERLAPPED* GetOverlapped() { return &overlapped_; }
40 // Implements base::win::ObjectWatcher::Delegate.
41 virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
43 // Implements base::MessageLoop::DestructionObserver
44 virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
46 // The buffer isn't used by this object but it's important that a reference
47 // to it is held until the transfer completes.
48 scoped_refptr<net::IOBuffer> buffer_;
49 Callback callback_;
50 OVERLAPPED overlapped_;
51 base::win::ScopedHandle event_;
52 base::win::ObjectWatcher watcher_;
54 private:
55 friend class base::RefCounted<PendingHidTransfer>;
57 virtual ~PendingHidTransfer();
59 DISALLOW_COPY_AND_ASSIGN(PendingHidTransfer);
62 PendingHidTransfer::PendingHidTransfer(
63 scoped_refptr<net::IOBuffer> buffer,
64 const PendingHidTransfer::Callback& callback)
65 : buffer_(buffer),
66 callback_(callback),
67 event_(CreateEvent(NULL, FALSE, FALSE, NULL)) {
68 memset(&overlapped_, 0, sizeof(OVERLAPPED));
69 overlapped_.hEvent = event_.Get();
72 PendingHidTransfer::~PendingHidTransfer() {
73 base::MessageLoop::current()->RemoveDestructionObserver(this);
76 void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) {
77 if (result) {
78 callback_.Run(this, true);
79 } else if (GetLastError() == ERROR_IO_PENDING) {
80 base::MessageLoop::current()->AddDestructionObserver(this);
81 AddRef();
82 watcher_.StartWatching(event_.Get(), this);
83 } else {
84 VPLOG(1) << "HID transfer failed";
85 callback_.Run(this, false);
89 void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) {
90 callback_.Run(this, true);
91 Release();
94 void PendingHidTransfer::WillDestroyCurrentMessageLoop() {
95 watcher_.StopWatching();
96 callback_.Run(this, false);
99 HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info)
100 : HidConnection(device_info) {
101 file_.Set(CreateFileA(device_info.device_id.c_str(),
102 GENERIC_WRITE | GENERIC_READ,
103 FILE_SHARE_READ | FILE_SHARE_WRITE,
104 NULL,
105 OPEN_EXISTING,
106 FILE_FLAG_OVERLAPPED,
107 NULL));
109 if (!file_.IsValid() &&
110 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
111 file_.Set(CreateFileA(device_info.device_id.c_str(),
112 GENERIC_READ,
113 FILE_SHARE_READ,
114 NULL,
115 OPEN_EXISTING,
116 FILE_FLAG_OVERLAPPED,
117 NULL));
121 HidConnectionWin::~HidConnectionWin() {
122 CancelIo(file_.Get());
125 void HidConnectionWin::PlatformRead(
126 const HidConnection::ReadCallback& callback) {
127 // Windows will always include the report ID (including zero if report IDs
128 // are not in use) in the buffer.
129 scoped_refptr<net::IOBufferWithSize> buffer =
130 new net::IOBufferWithSize(device_info().max_input_report_size + 1);
131 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
132 buffer,
133 base::Bind(&HidConnectionWin::OnReadComplete, this, buffer, callback)));
134 transfers_.insert(transfer);
135 transfer->TakeResultFromWindowsAPI(
136 ReadFile(file_.Get(),
137 buffer->data(),
138 static_cast<DWORD>(buffer->size()),
139 NULL,
140 transfer->GetOverlapped()));
143 void HidConnectionWin::PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
144 size_t size,
145 const WriteCallback& callback) {
146 // The Windows API always wants either a report ID (if supported) or
147 // zero at the front of every output report.
148 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
149 buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
150 transfers_.insert(transfer);
151 transfer->TakeResultFromWindowsAPI(WriteFile(file_.Get(),
152 buffer->data(),
153 static_cast<DWORD>(size),
154 NULL,
155 transfer->GetOverlapped()));
158 void HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id,
159 const ReadCallback& callback) {
160 // The first byte of the destination buffer is the report ID being requested.
161 scoped_refptr<net::IOBufferWithSize> buffer =
162 new net::IOBufferWithSize(device_info().max_feature_report_size + 1);
163 buffer->data()[0] = report_id;
165 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
166 buffer,
167 base::Bind(
168 &HidConnectionWin::OnReadFeatureComplete, this, buffer, callback)));
169 transfers_.insert(transfer);
170 transfer->TakeResultFromWindowsAPI(
171 DeviceIoControl(file_.Get(),
172 IOCTL_HID_GET_FEATURE,
173 NULL,
175 buffer->data(),
176 static_cast<DWORD>(buffer->size()),
177 NULL,
178 transfer->GetOverlapped()));
181 void HidConnectionWin::PlatformSendFeatureReport(
182 scoped_refptr<net::IOBuffer> buffer,
183 size_t size,
184 const WriteCallback& callback) {
185 // The Windows API always wants either a report ID (if supported) or
186 // zero at the front of every output report.
187 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
188 buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
189 transfer->TakeResultFromWindowsAPI(
190 DeviceIoControl(file_.Get(),
191 IOCTL_HID_SET_FEATURE,
192 buffer->data(),
193 static_cast<DWORD>(size),
194 NULL,
196 NULL,
197 transfer->GetOverlapped()));
200 void HidConnectionWin::OnReadComplete(scoped_refptr<net::IOBuffer> buffer,
201 const ReadCallback& callback,
202 PendingHidTransfer* transfer,
203 bool signaled) {
204 if (!signaled) {
205 callback.Run(false, NULL, 0);
206 return;
209 DWORD bytes_transferred;
210 if (GetOverlappedResult(
211 file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
212 CompleteRead(buffer, bytes_transferred, callback);
213 } else {
214 VPLOG(1) << "HID read failed";
215 callback.Run(false, NULL, 0);
219 void HidConnectionWin::OnReadFeatureComplete(
220 scoped_refptr<net::IOBuffer> buffer,
221 const ReadCallback& callback,
222 PendingHidTransfer* transfer,
223 bool signaled) {
224 if (!signaled) {
225 callback.Run(false, NULL, 0);
226 return;
229 DWORD bytes_transferred;
230 if (GetOverlappedResult(
231 file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
232 scoped_refptr<net::IOBuffer> new_buffer(
233 new net::IOBuffer(bytes_transferred - 1));
234 memcpy(new_buffer->data(), buffer->data() + 1, bytes_transferred - 1);
235 CompleteRead(new_buffer, bytes_transferred, callback);
236 } else {
237 VPLOG(1) << "HID read failed";
238 callback.Run(false, NULL, 0);
242 void HidConnectionWin::OnWriteComplete(const WriteCallback& callback,
243 PendingHidTransfer* transfer,
244 bool signaled) {
245 if (!signaled) {
246 callback.Run(false);
247 return;
250 DWORD bytes_transferred;
251 if (GetOverlappedResult(
252 file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
253 callback.Run(true);
254 } else {
255 VPLOG(1) << "HID write failed";
256 callback.Run(false);
260 } // namespace device