| Index: device/hid/hid_connection_win.cc
|
| diff --git a/device/hid/hid_connection_win.cc b/device/hid/hid_connection_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..eba31e1701fc66aec313fdf65d243b7485cc60cf
|
| --- /dev/null
|
| +++ b/device/hid/hid_connection_win.cc
|
| @@ -0,0 +1,182 @@
|
| +// Copyright (c) 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "device/hid/hid_connection_win.h"
|
| +
|
| +#include <cstring>
|
| +
|
| +#include "base/threading/thread_restrictions.h"
|
| +#include "device/hid/hid_service.h"
|
| +#include "device/hid/hid_service_win.h"
|
| +#include "net/base/io_buffer.h"
|
| +
|
| +#if defined(OS_WIN)
|
| +
|
| +#define INITGUID
|
| +
|
| +#include <windows.h>
|
| +#include <hidclass.h>
|
| +
|
| +extern "C" {
|
| +
|
| +#include <hidsdi.h>
|
| +
|
| +}
|
| +
|
| +#include <setupapi.h>
|
| +#include <winioctl.h>
|
| +#include "base/win/scoped_handle.h"
|
| +
|
| +#endif // defined(OS_WIN)
|
| +
|
| +namespace device {
|
| +
|
| +AsyncTransfer::AsyncTransfer(HANDLE file,
|
| + scoped_refptr<net::IOBuffer> buffer,
|
| + const HidIOCallback& callback,
|
| + bool is_read)
|
| + : file_(file),
|
| + buffer_(buffer),
|
| + callback_(callback),
|
| + actual_size_(0),
|
| + is_read_(is_read) {
|
| + memset(&overlapped_, 0, sizeof(OVERLAPPED));
|
| + event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
|
| + overlapped_.hEvent = event_.Get();
|
| +}
|
| +
|
| +AsyncTransfer::~AsyncTransfer() {
|
| +}
|
| +
|
| +void AsyncTransfer::StartWatching(BOOL result_from_winapi) {
|
| + if (!result_from_winapi) {
|
| + if (GetLastError() == ERROR_IO_PENDING) {
|
| + if (watcher_.StartWatching(event_.Get(), this)) {
|
| + AddRef();
|
| + } else {
|
| + callback_.Run(false, NULL, 0);
|
| + }
|
| + } else {
|
| + PLOG(ERROR) << "HidConnectionWin::Read";
|
| + callback_.Run(false, NULL, 0);
|
| + }
|
| + } else {
|
| + AddRef();
|
| + OnObjectSignaled(overlapped_.hEvent);
|
| + }
|
| +}
|
| +
|
| +OVERLAPPED* AsyncTransfer::GetOverlappedPtr() {
|
| + return &overlapped_;
|
| +}
|
| +
|
| +DWORD* AsyncTransfer::GetActualSizePtr() {
|
| + return &actual_size_;
|
| +}
|
| +
|
| +void AsyncTransfer::OnObjectSignaled(HANDLE object) {
|
| + DCHECK_EQ(object, event_.Get());
|
| + BOOL result = GetOverlappedResult(file_,&overlapped_, &actual_size_, FALSE);
|
| +
|
| + // For input transfers, if the first byte is zero, we need to remove it.
|
| + if (is_read_ && buffer_->data()[0] == 0) {
|
| + actual_size_--;
|
| + memmove(buffer_->data(), buffer_->data() + 1, actual_size_);
|
| + }
|
| + callback_.Run(result != 0, buffer_, (size_t)actual_size_);
|
| + Release();
|
| +}
|
| +
|
| +HidConnectionWin::HidConnectionWin(HidDeviceInfo device_info)
|
| + : HidConnection(device_info),
|
| + available_(false) {
|
| + file_.Set(CreateFileA(device_info.device_id.c_str(),
|
| + GENERIC_WRITE | GENERIC_READ,
|
| + FILE_SHARE_READ,
|
| + NULL,
|
| + OPEN_EXISTING,
|
| + FILE_FLAG_OVERLAPPED,
|
| + NULL));
|
| + available_ = file_.Get() != INVALID_HANDLE_VALUE;
|
| +}
|
| +
|
| +HidConnectionWin::~HidConnectionWin() {}
|
| +
|
| +void HidConnectionWin::Read(const HidIOCallback& callback) {
|
| + size_t report_size = device_info_.input_report_size;
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(report_size));
|
| + scoped_refptr<AsyncTransfer> aync_transfer(
|
| + new AsyncTransfer(file_, buffer, callback, true));
|
| +
|
| + aync_transfer->StartWatching(ReadFile(file_.Get(),
|
| + buffer->data(),
|
| + report_size,
|
| + aync_transfer->GetActualSizePtr(),
|
| + aync_transfer->GetOverlappedPtr()));
|
| +}
|
| +
|
| +void HidConnectionWin::Write(scoped_refptr<net::IOBuffer> buffer,
|
| + size_t size,
|
| + const HidIOCallback& callback) {
|
| + size_t report_size = device_info_.output_report_size;
|
| + if (size < report_size) {
|
| + scoped_refptr<net::IOBuffer> expanded_buffer(
|
| + new net::IOBuffer(report_size));
|
| + memset(expanded_buffer->data(), 0, report_size);
|
| + memcpy(expanded_buffer->data(), buffer->data(), size);
|
| + size = report_size;
|
| + buffer = expanded_buffer;
|
| + }
|
| +
|
| + scoped_refptr<AsyncTransfer> aync_transfer(
|
| + new AsyncTransfer(file_, NULL, callback, false));
|
| +
|
| + aync_transfer->StartWatching(WriteFile(file_,
|
| + buffer->data(),
|
| + size,
|
| + aync_transfer->GetActualSizePtr(),
|
| + aync_transfer->GetOverlappedPtr()));
|
| +}
|
| +
|
| +void HidConnectionWin::GetFeatureReport(const HidIOCallback& callback) {
|
| + size_t report_size = device_info_.feature_report_size;
|
| + scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(report_size));
|
| + scoped_refptr<AsyncTransfer> aync_transfer(
|
| + new AsyncTransfer(file_, buffer, callback, true));
|
| +
|
| + aync_transfer->
|
| + StartWatching(DeviceIoControl(file_,
|
| + IOCTL_HID_GET_FEATURE,
|
| + NULL, 0,
|
| + buffer->data(), report_size,
|
| + aync_transfer->GetActualSizePtr(),
|
| + aync_transfer->GetOverlappedPtr()));
|
| +}
|
| +
|
| +void HidConnectionWin::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer,
|
| + size_t size,
|
| + const HidIOCallback& callback) {
|
| + size_t report_size = device_info_.feature_report_size;
|
| + if (size < report_size) {
|
| + scoped_refptr<net::IOBuffer> expanded_buffer(
|
| + new net::IOBuffer(report_size));
|
| + memset(expanded_buffer->data(), 0, report_size);
|
| + memcpy(expanded_buffer->data(), buffer->data(), size);
|
| + size = report_size;
|
| + buffer = expanded_buffer;
|
| + }
|
| +
|
| + scoped_refptr<AsyncTransfer> aync_transfer(
|
| + new AsyncTransfer(file_, NULL, callback, false));
|
| +
|
| + aync_transfer->
|
| + StartWatching(DeviceIoControl(file_,
|
| + IOCTL_HID_SET_FEATURE,
|
| + buffer->data(), report_size,
|
| + NULL, 0,
|
| + aync_transfer->GetActualSizePtr(),
|
| + aync_transfer->GetOverlappedPtr()));
|
| +}
|
| +
|
| +} // namespace device
|
|
|