Index: device/hid/hid_connection_win.cc |
diff --git a/device/hid/hid_connection_win.cc b/device/hid/hid_connection_win.cc |
index dfebcba971c54bb9049012e7ad1b767e02a857f1..8e00ae03db499fa2c77067a5de89955a058b0fa4 100644 |
--- a/device/hid/hid_connection_win.cc |
+++ b/device/hid/hid_connection_win.cc |
@@ -6,6 +6,7 @@ |
#include <cstring> |
+#include "base/bind.h" |
#include "base/files/file.h" |
#include "base/message_loop/message_loop.h" |
#include "base/win/object_watcher.h" |
@@ -27,10 +28,10 @@ namespace device { |
struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, |
public base::win::ObjectWatcher::Delegate, |
public base::MessageLoop::DestructionObserver { |
- PendingHidTransfer(scoped_refptr<HidConnectionWin> connection, |
- scoped_refptr<net::IOBufferWithSize> target_buffer, |
- scoped_refptr<net::IOBufferWithSize> receive_buffer, |
- HidConnection::IOCallback callback); |
+ typedef base::Callback<void(PendingHidTransfer*, bool)> Callback; |
+ |
+ PendingHidTransfer(scoped_refptr<net::IOBuffer> buffer, |
+ const Callback& callback); |
void TakeResultFromWindowsAPI(BOOL result); |
@@ -42,10 +43,10 @@ struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, |
// Implements base::MessageLoop::DestructionObserver |
virtual void WillDestroyCurrentMessageLoop() OVERRIDE; |
- scoped_refptr<HidConnectionWin> connection_; |
- scoped_refptr<net::IOBufferWithSize> target_buffer_; |
- scoped_refptr<net::IOBufferWithSize> receive_buffer_; |
- HidConnection::IOCallback callback_; |
+ // The buffer isn't used by this object but it's important that a reference |
+ // to it is held until the transfer completes. |
+ scoped_refptr<net::IOBuffer> buffer_; |
+ Callback callback_; |
OVERLAPPED overlapped_; |
base::win::ScopedHandle event_; |
base::win::ObjectWatcher watcher_; |
@@ -59,13 +60,9 @@ struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, |
}; |
PendingHidTransfer::PendingHidTransfer( |
- scoped_refptr<HidConnectionWin> connection, |
- scoped_refptr<net::IOBufferWithSize> target_buffer, |
- scoped_refptr<net::IOBufferWithSize> receive_buffer, |
- HidConnection::IOCallback callback) |
- : connection_(connection), |
- target_buffer_(target_buffer), |
- receive_buffer_(receive_buffer), |
+ scoped_refptr<net::IOBuffer> buffer, |
+ const PendingHidTransfer::Callback& callback) |
+ : buffer_(buffer), |
callback_(callback), |
event_(CreateEvent(NULL, FALSE, FALSE, NULL)) { |
memset(&overlapped_, 0, sizeof(OVERLAPPED)); |
@@ -77,23 +74,26 @@ PendingHidTransfer::~PendingHidTransfer() { |
} |
void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) { |
- if (result || GetLastError() != ERROR_IO_PENDING) { |
- connection_->OnTransferFinished(this); |
- } else { |
+ if (result) { |
+ callback_.Run(this, true); |
+ } else if (GetLastError() == ERROR_IO_PENDING) { |
base::MessageLoop::current()->AddDestructionObserver(this); |
AddRef(); |
watcher_.StartWatching(event_.Get(), this); |
+ } else { |
+ VPLOG(1) << "HID transfer failed"; |
+ callback_.Run(this, false); |
} |
} |
void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) { |
- connection_->OnTransferFinished(this); |
+ callback_.Run(this, true); |
Release(); |
} |
void PendingHidTransfer::WillDestroyCurrentMessageLoop() { |
watcher_.StopWatching(); |
- connection_->OnTransferCanceled(this); |
+ callback_.Run(this, false); |
} |
HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info) |
@@ -122,146 +122,139 @@ HidConnectionWin::~HidConnectionWin() { |
CancelIo(file_.Get()); |
} |
-void HidConnectionWin::PlatformRead(scoped_refptr<net::IOBufferWithSize> buffer, |
- const HidConnection::IOCallback& callback) { |
+void HidConnectionWin::PlatformRead( |
+ const HidConnection::ReadCallback& callback) { |
// Windows will always include the report ID (including zero if report IDs |
// are not in use) in the buffer. |
- scoped_refptr<net::IOBufferWithSize> receive_buffer = |
+ scoped_refptr<net::IOBufferWithSize> buffer = |
new net::IOBufferWithSize(device_info().max_input_report_size + 1); |
- |
- scoped_refptr<PendingHidTransfer> transfer( |
- new PendingHidTransfer(this, buffer, receive_buffer, callback)); |
+ scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( |
+ buffer, |
+ base::Bind(&HidConnectionWin::OnReadComplete, this, buffer, callback))); |
transfers_.insert(transfer); |
transfer->TakeResultFromWindowsAPI( |
ReadFile(file_.Get(), |
- receive_buffer->data(), |
- static_cast<DWORD>(receive_buffer->size()), |
+ buffer->data(), |
+ static_cast<DWORD>(buffer->size()), |
NULL, |
transfer->GetOverlapped())); |
} |
-void HidConnectionWin::PlatformWrite( |
- uint8_t report_id, |
- scoped_refptr<net::IOBufferWithSize> buffer, |
- const HidConnection::IOCallback& callback) { |
+void HidConnectionWin::PlatformWrite(scoped_refptr<net::IOBuffer> buffer, |
+ size_t size, |
+ const WriteCallback& callback) { |
// The Windows API always wants either a report ID (if supported) or |
// zero at the front of every output report. |
- scoped_refptr<net::IOBufferWithSize> output_buffer( |
- new net::IOBufferWithSize(buffer->size() + 1)); |
- output_buffer->data()[0] = report_id; |
- memcpy(output_buffer->data() + 1, buffer->data(), buffer->size()); |
- |
- scoped_refptr<PendingHidTransfer> transfer( |
- new PendingHidTransfer(this, output_buffer, NULL, callback)); |
+ scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( |
+ buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback))); |
transfers_.insert(transfer); |
- transfer->TakeResultFromWindowsAPI( |
- WriteFile(file_.Get(), |
- output_buffer->data(), |
- static_cast<DWORD>(output_buffer->size()), |
- NULL, |
- transfer->GetOverlapped())); |
+ transfer->TakeResultFromWindowsAPI(WriteFile(file_.Get(), |
+ buffer->data(), |
+ static_cast<DWORD>(size), |
+ NULL, |
+ transfer->GetOverlapped())); |
} |
-void HidConnectionWin::PlatformGetFeatureReport( |
- uint8_t report_id, |
- scoped_refptr<net::IOBufferWithSize> buffer, |
- const IOCallback& callback) { |
- int expected_report_size = device_info().max_feature_report_size; |
- if (device_info().has_report_id) { |
- expected_report_size++; |
- } |
- scoped_refptr<net::IOBufferWithSize> receive_buffer = |
- new net::IOBufferWithSize(expected_report_size); |
+void HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id, |
+ const ReadCallback& callback) { |
// The first byte of the destination buffer is the report ID being requested. |
- receive_buffer->data()[0] = report_id; |
- |
- scoped_refptr<PendingHidTransfer> transfer( |
- new PendingHidTransfer(this, buffer, receive_buffer, callback)); |
+ scoped_refptr<net::IOBufferWithSize> buffer = |
+ new net::IOBufferWithSize(device_info().max_feature_report_size + 1); |
+ buffer->data()[0] = report_id; |
+ |
+ scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( |
+ buffer, |
+ base::Bind( |
+ &HidConnectionWin::OnReadFeatureComplete, this, buffer, callback))); |
transfers_.insert(transfer); |
transfer->TakeResultFromWindowsAPI( |
DeviceIoControl(file_.Get(), |
IOCTL_HID_GET_FEATURE, |
NULL, |
0, |
- receive_buffer->data(), |
- static_cast<DWORD>(receive_buffer->size()), |
+ buffer->data(), |
+ static_cast<DWORD>(buffer->size()), |
NULL, |
transfer->GetOverlapped())); |
} |
void HidConnectionWin::PlatformSendFeatureReport( |
- uint8_t report_id, |
- scoped_refptr<net::IOBufferWithSize> buffer, |
- const IOCallback& callback) { |
+ scoped_refptr<net::IOBuffer> buffer, |
+ size_t size, |
+ const WriteCallback& callback) { |
// The Windows API always wants either a report ID (if supported) or |
// zero at the front of every output report. |
- scoped_refptr<net::IOBufferWithSize> output_buffer(buffer); |
- output_buffer = new net::IOBufferWithSize(buffer->size() + 1); |
- output_buffer->data()[0] = report_id; |
- memcpy(output_buffer->data() + 1, buffer->data(), buffer->size()); |
- |
- scoped_refptr<PendingHidTransfer> transfer( |
- new PendingHidTransfer(this, output_buffer, NULL, callback)); |
+ scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer( |
+ buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback))); |
transfer->TakeResultFromWindowsAPI( |
DeviceIoControl(file_.Get(), |
IOCTL_HID_SET_FEATURE, |
- output_buffer->data(), |
- static_cast<DWORD>(output_buffer->size()), |
+ buffer->data(), |
+ static_cast<DWORD>(size), |
NULL, |
0, |
NULL, |
transfer->GetOverlapped())); |
} |
-void HidConnectionWin::OnTransferFinished( |
- scoped_refptr<PendingHidTransfer> transfer) { |
- transfers_.erase(transfer); |
+void HidConnectionWin::OnReadComplete(scoped_refptr<net::IOBuffer> buffer, |
+ const ReadCallback& callback, |
+ PendingHidTransfer* transfer, |
+ bool signaled) { |
+ if (!signaled) { |
+ callback.Run(false, NULL, 0); |
+ return; |
+ } |
DWORD bytes_transferred; |
if (GetOverlappedResult( |
file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { |
- if (bytes_transferred == 0) { |
- transfer->callback_.Run(true, 0); |
- return; |
- } |
- |
- if (transfer->receive_buffer_) { |
- // If owner HID top-level collection does not have report ID, we need to |
- // copy the receive buffer into the target buffer, discarding the first |
- // byte. This is because the target buffer's owner is not expecting a |
- // report ID but Windows will always provide one. |
- if (!device_info().has_report_id) { |
- uint8_t report_id = transfer->receive_buffer_->data()[0]; |
- // Assert first byte is 0x00 |
- if (report_id != HidConnection::kNullReportId) { |
- VLOG(1) << "Unexpected report ID in HID report:" << report_id; |
- transfer->callback_.Run(false, 0); |
- } else { |
- // Move one byte forward. |
- --bytes_transferred; |
- memcpy(transfer->target_buffer_->data(), |
- transfer->receive_buffer_->data() + 1, |
- bytes_transferred); |
- } |
- } else { |
- memcpy(transfer->target_buffer_->data(), |
- transfer->receive_buffer_->data(), |
- bytes_transferred); |
- } |
- } |
- |
- CompleteRead( |
- transfer->target_buffer_, bytes_transferred, transfer->callback_); |
+ CompleteRead(buffer, bytes_transferred, callback); |
} else { |
- VPLOG(1) << "HID transfer failed"; |
- transfer->callback_.Run(false, 0); |
+ VPLOG(1) << "HID read failed"; |
+ callback.Run(false, NULL, 0); |
+ } |
+} |
+ |
+void HidConnectionWin::OnReadFeatureComplete( |
+ scoped_refptr<net::IOBuffer> buffer, |
+ const ReadCallback& callback, |
+ PendingHidTransfer* transfer, |
+ bool signaled) { |
+ if (!signaled) { |
+ callback.Run(false, NULL, 0); |
+ return; |
+ } |
+ |
+ DWORD bytes_transferred; |
+ if (GetOverlappedResult( |
+ file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { |
+ scoped_refptr<net::IOBuffer> new_buffer( |
+ new net::IOBuffer(bytes_transferred - 1)); |
+ memcpy(new_buffer->data(), buffer->data() + 1, bytes_transferred - 1); |
+ CompleteRead(new_buffer, bytes_transferred, callback); |
+ } else { |
+ VPLOG(1) << "HID read failed"; |
+ callback.Run(false, NULL, 0); |
} |
} |
-void HidConnectionWin::OnTransferCanceled( |
- scoped_refptr<PendingHidTransfer> transfer) { |
- transfers_.erase(transfer); |
- transfer->callback_.Run(false, 0); |
+void HidConnectionWin::OnWriteComplete(const WriteCallback& callback, |
+ PendingHidTransfer* transfer, |
+ bool signaled) { |
+ if (!signaled) { |
+ callback.Run(false); |
+ return; |
+ } |
+ |
+ DWORD bytes_transferred; |
+ if (GetOverlappedResult( |
+ file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { |
+ callback.Run(true); |
+ } else { |
+ VPLOG(1) << "HID write failed"; |
+ callback.Run(false); |
+ } |
} |
} // namespace device |