Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1542)

Side by Side Diff: device/hid/hid_connection_win.cc

Issue 499713002: Don't pass buffers to HidConnection::Read because it knows the size. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "device/hid/hid_connection_win.h" 5 #include "device/hid/hid_connection_win.h"
6 6
7 #include <cstring> 7 #include <cstring>
8 8
9 #include "base/bind.h"
9 #include "base/files/file.h" 10 #include "base/files/file.h"
10 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
11 #include "base/win/object_watcher.h" 12 #include "base/win/object_watcher.h"
12 13
13 #define INITGUID 14 #define INITGUID
14 15
15 #include <windows.h> 16 #include <windows.h>
16 #include <hidclass.h> 17 #include <hidclass.h>
17 18
18 extern "C" { 19 extern "C" {
19 #include <hidsdi.h> 20 #include <hidsdi.h>
20 } 21 }
21 22
22 #include <setupapi.h> 23 #include <setupapi.h>
23 #include <winioctl.h> 24 #include <winioctl.h>
24 25
25 namespace device { 26 namespace device {
26 27
27 struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, 28 struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>,
28 public base::win::ObjectWatcher::Delegate, 29 public base::win::ObjectWatcher::Delegate,
29 public base::MessageLoop::DestructionObserver { 30 public base::MessageLoop::DestructionObserver {
30 PendingHidTransfer(scoped_refptr<HidConnectionWin> connection, 31 typedef base::Callback<void(PendingHidTransfer*, bool)> Callback;
31 scoped_refptr<net::IOBufferWithSize> target_buffer, 32
32 scoped_refptr<net::IOBufferWithSize> receive_buffer, 33 PendingHidTransfer(scoped_refptr<net::IOBuffer> buffer,
33 HidConnection::IOCallback callback); 34 const Callback& callback);
34 35
35 void TakeResultFromWindowsAPI(BOOL result); 36 void TakeResultFromWindowsAPI(BOOL result);
36 37
37 OVERLAPPED* GetOverlapped() { return &overlapped_; } 38 OVERLAPPED* GetOverlapped() { return &overlapped_; }
38 39
39 // Implements base::win::ObjectWatcher::Delegate. 40 // Implements base::win::ObjectWatcher::Delegate.
40 virtual void OnObjectSignaled(HANDLE object) OVERRIDE; 41 virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
41 42
42 // Implements base::MessageLoop::DestructionObserver 43 // Implements base::MessageLoop::DestructionObserver
43 virtual void WillDestroyCurrentMessageLoop() OVERRIDE; 44 virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
44 45
45 scoped_refptr<HidConnectionWin> connection_; 46 // The buffer isn't used by this object but it's important that a reference
46 scoped_refptr<net::IOBufferWithSize> target_buffer_; 47 // to it is held until the transfer completes.
47 scoped_refptr<net::IOBufferWithSize> receive_buffer_; 48 scoped_refptr<net::IOBuffer> buffer_;
48 HidConnection::IOCallback callback_; 49 Callback callback_;
49 OVERLAPPED overlapped_; 50 OVERLAPPED overlapped_;
50 base::win::ScopedHandle event_; 51 base::win::ScopedHandle event_;
51 base::win::ObjectWatcher watcher_; 52 base::win::ObjectWatcher watcher_;
52 53
53 private: 54 private:
54 friend class base::RefCounted<PendingHidTransfer>; 55 friend class base::RefCounted<PendingHidTransfer>;
55 56
56 virtual ~PendingHidTransfer(); 57 virtual ~PendingHidTransfer();
57 58
58 DISALLOW_COPY_AND_ASSIGN(PendingHidTransfer); 59 DISALLOW_COPY_AND_ASSIGN(PendingHidTransfer);
59 }; 60 };
60 61
61 PendingHidTransfer::PendingHidTransfer( 62 PendingHidTransfer::PendingHidTransfer(
62 scoped_refptr<HidConnectionWin> connection, 63 scoped_refptr<net::IOBuffer> buffer,
63 scoped_refptr<net::IOBufferWithSize> target_buffer, 64 const PendingHidTransfer::Callback& callback)
64 scoped_refptr<net::IOBufferWithSize> receive_buffer, 65 : buffer_(buffer),
65 HidConnection::IOCallback callback)
66 : connection_(connection),
67 target_buffer_(target_buffer),
68 receive_buffer_(receive_buffer),
69 callback_(callback), 66 callback_(callback),
70 event_(CreateEvent(NULL, FALSE, FALSE, NULL)) { 67 event_(CreateEvent(NULL, FALSE, FALSE, NULL)) {
71 memset(&overlapped_, 0, sizeof(OVERLAPPED)); 68 memset(&overlapped_, 0, sizeof(OVERLAPPED));
72 overlapped_.hEvent = event_.Get(); 69 overlapped_.hEvent = event_.Get();
73 } 70 }
74 71
75 PendingHidTransfer::~PendingHidTransfer() { 72 PendingHidTransfer::~PendingHidTransfer() {
76 base::MessageLoop::current()->RemoveDestructionObserver(this); 73 base::MessageLoop::current()->RemoveDestructionObserver(this);
77 } 74 }
78 75
79 void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) { 76 void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) {
80 if (result || GetLastError() != ERROR_IO_PENDING) { 77 if (result) {
81 connection_->OnTransferFinished(this); 78 callback_.Run(this, true);
82 } else { 79 } else if (GetLastError() == ERROR_IO_PENDING) {
83 base::MessageLoop::current()->AddDestructionObserver(this); 80 base::MessageLoop::current()->AddDestructionObserver(this);
84 AddRef(); 81 AddRef();
85 watcher_.StartWatching(event_.Get(), this); 82 watcher_.StartWatching(event_.Get(), this);
83 } else {
84 VPLOG(1) << "HID transfer failed";
85 callback_.Run(this, false);
86 } 86 }
87 } 87 }
88 88
89 void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) { 89 void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) {
90 connection_->OnTransferFinished(this); 90 callback_.Run(this, true);
91 Release(); 91 Release();
92 } 92 }
93 93
94 void PendingHidTransfer::WillDestroyCurrentMessageLoop() { 94 void PendingHidTransfer::WillDestroyCurrentMessageLoop() {
95 watcher_.StopWatching(); 95 watcher_.StopWatching();
96 connection_->OnTransferCanceled(this); 96 callback_.Run(this, false);
97 } 97 }
98 98
99 HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info) 99 HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info)
100 : HidConnection(device_info) { 100 : HidConnection(device_info) {
101 file_.Set(CreateFileA(device_info.device_id.c_str(), 101 file_.Set(CreateFileA(device_info.device_id.c_str(),
102 GENERIC_WRITE | GENERIC_READ, 102 GENERIC_WRITE | GENERIC_READ,
103 FILE_SHARE_READ | FILE_SHARE_WRITE, 103 FILE_SHARE_READ | FILE_SHARE_WRITE,
104 NULL, 104 NULL,
105 OPEN_EXISTING, 105 OPEN_EXISTING,
106 FILE_FLAG_OVERLAPPED, 106 FILE_FLAG_OVERLAPPED,
107 NULL)); 107 NULL));
108 108
109 if (!file_.IsValid() && 109 if (!file_.IsValid() &&
110 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) { 110 GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
111 file_.Set(CreateFileA(device_info.device_id.c_str(), 111 file_.Set(CreateFileA(device_info.device_id.c_str(),
112 GENERIC_READ, 112 GENERIC_READ,
113 FILE_SHARE_READ, 113 FILE_SHARE_READ,
114 NULL, 114 NULL,
115 OPEN_EXISTING, 115 OPEN_EXISTING,
116 FILE_FLAG_OVERLAPPED, 116 FILE_FLAG_OVERLAPPED,
117 NULL)); 117 NULL));
118 } 118 }
119 } 119 }
120 120
121 HidConnectionWin::~HidConnectionWin() { 121 HidConnectionWin::~HidConnectionWin() {
122 CancelIo(file_.Get()); 122 CancelIo(file_.Get());
123 } 123 }
124 124
125 void HidConnectionWin::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer, 125 void HidConnectionWin::PlatformRead(
126 const HidConnection::IOCallback& callback) { 126 const HidConnection::ReadCallback& callback) {
127 // Windows will always include the report ID (including zero if report IDs 127 // Windows will always include the report ID (including zero if report IDs
128 // are not in use) in the buffer. 128 // are not in use) in the buffer.
129 scoped_refptr<net::IOBufferWithSize> receive_buffer = 129 scoped_refptr<net::IOBufferWithSize> buffer =
130 new net::IOBufferWithSize(device_info().max_input_report_size + 1); 130 new net::IOBufferWithSize(device_info().max_input_report_size + 1);
131 131 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
132 scoped_refptr<PendingHidTransfer> transfer( 132 buffer,
133 new PendingHidTransfer(this, buffer, receive_buffer, callback)); 133 base::Bind(&HidConnectionWin::OnReadComplete, this, buffer, callback)));
134 transfers_.insert(transfer); 134 transfers_.insert(transfer);
135 transfer->TakeResultFromWindowsAPI( 135 transfer->TakeResultFromWindowsAPI(
136 ReadFile(file_.Get(), 136 ReadFile(file_.Get(),
137 receive_buffer->data(), 137 buffer->data(),
138 static_cast<DWORD>(receive_buffer->size()), 138 static_cast<DWORD>(buffer->size()),
139 NULL, 139 NULL,
140 transfer->GetOverlapped())); 140 transfer->GetOverlapped()));
141 } 141 }
142 142
143 void HidConnectionWin::PlatformWrite( 143 void HidConnectionWin::PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
144 uint8_t report_id, 144 size_t size,
145 scoped_refptr<net::IOBufferWithSize> buffer, 145 const WriteCallback& callback) {
146 const HidConnection::IOCallback& callback) {
147 // The Windows API always wants either a report ID (if supported) or 146 // The Windows API always wants either a report ID (if supported) or
148 // zero at the front of every output report. 147 // zero at the front of every output report.
149 scoped_refptr<net::IOBufferWithSize> output_buffer( 148 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
150 new net::IOBufferWithSize(buffer->size() + 1)); 149 buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
151 output_buffer->data()[0] = report_id;
152 memcpy(output_buffer->data() + 1, buffer->data(), buffer->size());
153
154 scoped_refptr<PendingHidTransfer> transfer(
155 new PendingHidTransfer(this, output_buffer, NULL, callback));
156 transfers_.insert(transfer); 150 transfers_.insert(transfer);
157 transfer->TakeResultFromWindowsAPI( 151 transfer->TakeResultFromWindowsAPI(WriteFile(file_.Get(),
158 WriteFile(file_.Get(), 152 buffer->data(),
159 output_buffer->data(), 153 static_cast<DWORD>(size),
160 static_cast<DWORD>(output_buffer->size()), 154 NULL,
161 NULL, 155 transfer->GetOverlapped()));
162 transfer->GetOverlapped()));
163 } 156 }
164 157
165 void HidConnectionWin::PlatformGetFeatureReport( 158 void HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id,
166 uint8_t report_id, 159 const ReadCallback& callback) {
167 scoped_refptr<net::IOBufferWithSize> buffer,
168 const IOCallback& callback) {
169 int expected_report_size = device_info().max_feature_report_size;
170 if (device_info().has_report_id) {
171 expected_report_size++;
172 }
173 scoped_refptr<net::IOBufferWithSize> receive_buffer =
174 new net::IOBufferWithSize(expected_report_size);
175 // The first byte of the destination buffer is the report ID being requested. 160 // The first byte of the destination buffer is the report ID being requested.
176 receive_buffer->data()[0] = report_id; 161 scoped_refptr<net::IOBufferWithSize> buffer =
162 new net::IOBufferWithSize(device_info().max_feature_report_size + 1);
163 buffer->data()[0] = report_id;
177 164
178 scoped_refptr<PendingHidTransfer> transfer( 165 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
179 new PendingHidTransfer(this, buffer, receive_buffer, callback)); 166 buffer,
167 base::Bind(
168 &HidConnectionWin::OnReadFeatureComplete, this, buffer, callback)));
180 transfers_.insert(transfer); 169 transfers_.insert(transfer);
181 transfer->TakeResultFromWindowsAPI( 170 transfer->TakeResultFromWindowsAPI(
182 DeviceIoControl(file_.Get(), 171 DeviceIoControl(file_.Get(),
183 IOCTL_HID_GET_FEATURE, 172 IOCTL_HID_GET_FEATURE,
184 NULL, 173 NULL,
185 0, 174 0,
186 receive_buffer->data(), 175 buffer->data(),
187 static_cast<DWORD>(receive_buffer->size()), 176 static_cast<DWORD>(buffer->size()),
188 NULL, 177 NULL,
189 transfer->GetOverlapped())); 178 transfer->GetOverlapped()));
190 } 179 }
191 180
192 void HidConnectionWin::PlatformSendFeatureReport( 181 void HidConnectionWin::PlatformSendFeatureReport(
193 uint8_t report_id, 182 scoped_refptr<net::IOBuffer> buffer,
194 scoped_refptr<net::IOBufferWithSize> buffer, 183 size_t size,
195 const IOCallback& callback) { 184 const WriteCallback& callback) {
196 // The Windows API always wants either a report ID (if supported) or 185 // The Windows API always wants either a report ID (if supported) or
197 // zero at the front of every output report. 186 // zero at the front of every output report.
198 scoped_refptr<net::IOBufferWithSize> output_buffer(buffer); 187 scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
199 output_buffer = new net::IOBufferWithSize(buffer->size() + 1); 188 buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
200 output_buffer->data()[0] = report_id;
201 memcpy(output_buffer->data() + 1, buffer->data(), buffer->size());
202
203 scoped_refptr<PendingHidTransfer> transfer(
204 new PendingHidTransfer(this, output_buffer, NULL, callback));
205 transfer->TakeResultFromWindowsAPI( 189 transfer->TakeResultFromWindowsAPI(
206 DeviceIoControl(file_.Get(), 190 DeviceIoControl(file_.Get(),
207 IOCTL_HID_SET_FEATURE, 191 IOCTL_HID_SET_FEATURE,
208 output_buffer->data(), 192 buffer->data(),
209 static_cast<DWORD>(output_buffer->size()), 193 static_cast<DWORD>(size),
210 NULL, 194 NULL,
211 0, 195 0,
212 NULL, 196 NULL,
213 transfer->GetOverlapped())); 197 transfer->GetOverlapped()));
214 } 198 }
215 199
216 void HidConnectionWin::OnTransferFinished( 200 void HidConnectionWin::OnReadComplete(scoped_refptr<net::IOBuffer> buffer,
217 scoped_refptr<PendingHidTransfer> transfer) { 201 const ReadCallback& callback,
218 transfers_.erase(transfer); 202 PendingHidTransfer* transfer,
203 bool signaled) {
204 if (!signaled) {
205 callback.Run(false, NULL, 0);
206 return;
207 }
219 208
220 DWORD bytes_transferred; 209 DWORD bytes_transferred;
221 if (GetOverlappedResult( 210 if (GetOverlappedResult(
222 file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { 211 file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
223 if (bytes_transferred == 0) { 212 CompleteRead(buffer, bytes_transferred, callback);
224 transfer->callback_.Run(true, 0);
225 return;
226 }
227
228 if (transfer->receive_buffer_) {
229 // If owner HID top-level collection does not have report ID, we need to
230 // copy the receive buffer into the target buffer, discarding the first
231 // byte. This is because the target buffer's owner is not expecting a
232 // report ID but Windows will always provide one.
233 if (!device_info().has_report_id) {
234 uint8_t report_id = transfer->receive_buffer_->data()[0];
235 // Assert first byte is 0x00
236 if (report_id != HidConnection::kNullReportId) {
237 VLOG(1) << "Unexpected report ID in HID report:" << report_id;
238 transfer->callback_.Run(false, 0);
239 } else {
240 // Move one byte forward.
241 --bytes_transferred;
242 memcpy(transfer->target_buffer_->data(),
243 transfer->receive_buffer_->data() + 1,
244 bytes_transferred);
245 }
246 } else {
247 memcpy(transfer->target_buffer_->data(),
248 transfer->receive_buffer_->data(),
249 bytes_transferred);
250 }
251 }
252
253 CompleteRead(
254 transfer->target_buffer_, bytes_transferred, transfer->callback_);
255 } else { 213 } else {
256 VPLOG(1) << "HID transfer failed"; 214 VPLOG(1) << "HID read failed";
257 transfer->callback_.Run(false, 0); 215 callback.Run(false, NULL, 0);
258 } 216 }
259 } 217 }
260 218
261 void HidConnectionWin::OnTransferCanceled( 219 void HidConnectionWin::OnReadFeatureComplete(
262 scoped_refptr<PendingHidTransfer> transfer) { 220 scoped_refptr<net::IOBuffer> buffer,
263 transfers_.erase(transfer); 221 const ReadCallback& callback,
264 transfer->callback_.Run(false, 0); 222 PendingHidTransfer* transfer,
223 bool signaled) {
224 if (!signaled) {
225 callback.Run(false, NULL, 0);
226 return;
227 }
228
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);
239 }
240 }
241
242 void HidConnectionWin::OnWriteComplete(const WriteCallback& callback,
243 PendingHidTransfer* transfer,
244 bool signaled) {
245 if (!signaled) {
246 callback.Run(false);
247 return;
248 }
249
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);
257 }
265 } 258 }
266 259
267 } // namespace device 260 } // namespace device
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698