Update Smart lock strings in chrome://settings.
[chromium-blink-merge.git] / device / hid / hid_connection_win.cc
blob1783092a0310e9b6d9f0638fc65d06ed37ea67a2
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/numerics/safe_conversions.h"
13 #include "base/profiler/scoped_profile.h"
14 #include "base/win/object_watcher.h"
16 #define INITGUID
18 #include <windows.h>
19 #include <hidclass.h>
21 extern "C" {
22 #include <hidsdi.h>
25 #include <setupapi.h>
26 #include <winioctl.h>
28 namespace device {
30 struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>,
31 public base::win::ObjectWatcher::Delegate,
32 public base::MessageLoop::DestructionObserver {
33 typedef base::Callback<void(PendingHidTransfer*, bool)> Callback;
35 PendingHidTransfer(scoped_refptr<net::IOBuffer> buffer,
36 const Callback& callback);
38 void TakeResultFromWindowsAPI(BOOL result);
40 OVERLAPPED* GetOverlapped() { return &overlapped_; }
42 // Implements base::win::ObjectWatcher::Delegate.
43 virtual void OnObjectSignaled(HANDLE object) override;
45 // Implements base::MessageLoop::DestructionObserver
46 virtual void WillDestroyCurrentMessageLoop() override;
48 // The buffer isn't used by this object but it's important that a reference
49 // to it is held until the transfer completes.
50 scoped_refptr<net::IOBuffer> buffer_;
51 Callback callback_;
52 OVERLAPPED overlapped_;
53 base::win::ScopedHandle event_;
54 base::win::ObjectWatcher watcher_;
56 private:
57 friend class base::RefCounted<PendingHidTransfer>;
59 virtual ~PendingHidTransfer();
61 DISALLOW_COPY_AND_ASSIGN(PendingHidTransfer);
64 PendingHidTransfer::PendingHidTransfer(
65 scoped_refptr<net::IOBuffer> buffer,
66 const PendingHidTransfer::Callback& callback)
67 : buffer_(buffer),
68 callback_(callback),
69 event_(CreateEvent(NULL, FALSE, FALSE, NULL)) {
70 memset(&overlapped_, 0, sizeof(OVERLAPPED));
71 overlapped_.hEvent = event_.Get();
74 PendingHidTransfer::~PendingHidTransfer() {
75 base::MessageLoop::current()->RemoveDestructionObserver(this);
78 void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) {
79 if (result) {
80 callback_.Run(this, true);
81 } else if (GetLastError() == ERROR_IO_PENDING) {
82 base::MessageLoop::current()->AddDestructionObserver(this);
83 AddRef();
84 watcher_.StartWatching(event_.Get(), this);
85 } else {
86 VPLOG(1) << "HID transfer failed";
87 callback_.Run(this, false);
91 void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) {
92 // TODO(vadimt): Remove ScopedProfile below once crbug.com/418183 is fixed.
93 tracked_objects::ScopedProfile tracking_profile(
94 FROM_HERE_WITH_EXPLICIT_FUNCTION(
95 "PendingHidTransfer_OnObjectSignaled"));
97 callback_.Run(this, true);
98 Release();
101 void PendingHidTransfer::WillDestroyCurrentMessageLoop() {
102 watcher_.StopWatching();
103 callback_.Run(this, false);
106 HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info)
107 : HidConnection(device_info) {
108 file_.Set(CreateFileA(device_info.device_id.c_str(),
109 GENERIC_WRITE | GENERIC_READ,
110 FILE_SHARE_READ | FILE_SHARE_WRITE,
111 NULL,
112 OPEN_EXISTING,
113 FILE_FLAG_OVERLAPPED,
114 NULL));
116 if (!file_.IsValid() &&
117 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
118 file_.Set(CreateFileA(device_info.device_id.c_str(),
119 GENERIC_READ,
120 FILE_SHARE_READ,
121 NULL,
122 OPEN_EXISTING,
123 FILE_FLAG_OVERLAPPED,
124 NULL));
128 HidConnectionWin::~HidConnectionWin() {
131 void HidConnectionWin::PlatformClose() {
132 CancelIo(file_.Get());
135 void HidConnectionWin::PlatformRead(
136 const HidConnection::ReadCallback& callback) {
137 // Windows will always include the report ID (including zero if report IDs
138 // are not in use) in the buffer.
139 scoped_refptr<net::IOBufferWithSize> buffer = new net::IOBufferWithSize(
140 base::checked_cast<int>(device_info().max_input_report_size + 1));
141 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
142 buffer,
143 base::Bind(&HidConnectionWin::OnReadComplete, this, buffer, callback)));
144 transfers_.insert(transfer);
145 transfer->TakeResultFromWindowsAPI(
146 ReadFile(file_.Get(),
147 buffer->data(),
148 static_cast<DWORD>(buffer->size()),
149 NULL,
150 transfer->GetOverlapped()));
153 void HidConnectionWin::PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
154 size_t size,
155 const WriteCallback& callback) {
156 // The Windows API always wants either a report ID (if supported) or
157 // zero at the front of every output report.
158 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
159 buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
160 transfers_.insert(transfer);
161 transfer->TakeResultFromWindowsAPI(WriteFile(file_.Get(),
162 buffer->data(),
163 static_cast<DWORD>(size),
164 NULL,
165 transfer->GetOverlapped()));
168 void HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id,
169 const ReadCallback& callback) {
170 // The first byte of the destination buffer is the report ID being requested.
171 scoped_refptr<net::IOBufferWithSize> buffer = new net::IOBufferWithSize(
172 base::checked_cast<int>(device_info().max_feature_report_size + 1));
173 buffer->data()[0] = report_id;
175 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
176 buffer,
177 base::Bind(
178 &HidConnectionWin::OnReadFeatureComplete, this, buffer, callback)));
179 transfers_.insert(transfer);
180 transfer->TakeResultFromWindowsAPI(
181 DeviceIoControl(file_.Get(),
182 IOCTL_HID_GET_FEATURE,
183 NULL,
185 buffer->data(),
186 static_cast<DWORD>(buffer->size()),
187 NULL,
188 transfer->GetOverlapped()));
191 void HidConnectionWin::PlatformSendFeatureReport(
192 scoped_refptr<net::IOBuffer> buffer,
193 size_t size,
194 const WriteCallback& callback) {
195 // The Windows API always wants either a report ID (if supported) or
196 // zero at the front of every output report.
197 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
198 buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
199 transfer->TakeResultFromWindowsAPI(
200 DeviceIoControl(file_.Get(),
201 IOCTL_HID_SET_FEATURE,
202 buffer->data(),
203 static_cast<DWORD>(size),
204 NULL,
206 NULL,
207 transfer->GetOverlapped()));
210 void HidConnectionWin::OnReadComplete(scoped_refptr<net::IOBuffer> buffer,
211 const ReadCallback& callback,
212 PendingHidTransfer* transfer,
213 bool signaled) {
214 if (!signaled) {
215 callback.Run(false, NULL, 0);
216 return;
219 DWORD bytes_transferred;
220 if (GetOverlappedResult(
221 file_.Get(), transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
222 CompleteRead(buffer, bytes_transferred, callback);
223 } else {
224 VPLOG(1) << "HID read failed";
225 callback.Run(false, NULL, 0);
229 void HidConnectionWin::OnReadFeatureComplete(
230 scoped_refptr<net::IOBuffer> buffer,
231 const ReadCallback& callback,
232 PendingHidTransfer* transfer,
233 bool signaled) {
234 if (!signaled) {
235 callback.Run(false, NULL, 0);
236 return;
239 DWORD bytes_transferred;
240 if (GetOverlappedResult(
241 file_.Get(), transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
242 callback.Run(true, buffer, bytes_transferred);
243 } else {
244 VPLOG(1) << "HID read failed";
245 callback.Run(false, NULL, 0);
249 void HidConnectionWin::OnWriteComplete(const WriteCallback& callback,
250 PendingHidTransfer* transfer,
251 bool signaled) {
252 if (!signaled) {
253 callback.Run(false);
254 return;
257 DWORD bytes_transferred;
258 if (GetOverlappedResult(
259 file_.Get(), transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
260 callback.Run(true);
261 } else {
262 VPLOG(1) << "HID write failed";
263 callback.Run(false);
267 } // namespace device