diff options
author | ikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-30 10:41:05 +0000 |
---|---|---|
committer | ikarienator@chromium.org <ikarienator@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-01-30 10:41:05 +0000 |
commit | a2c724ab72ccebb6d78e228caefd36b100e8308a (patch) | |
tree | f023f4383558055b3a41f6183983da7e9183e1ee /device/hid/hid_connection_win.cc | |
parent | 441e25cdf56a650df64a17416314aeee1598ccff (diff) | |
download | chromium_src-a2c724ab72ccebb6d78e228caefd36b100e8308a.zip chromium_src-a2c724ab72ccebb6d78e228caefd36b100e8308a.tar.gz chromium_src-a2c724ab72ccebb6d78e228caefd36b100e8308a.tar.bz2 |
HID backend
BUG=290428
Review URL: https://codereview.chromium.org/143883005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247926 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'device/hid/hid_connection_win.cc')
-rw-r--r-- | device/hid/hid_connection_win.cc | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/device/hid/hid_connection_win.cc b/device/hid/hid_connection_win.cc new file mode 100644 index 0000000..34326d8 --- /dev/null +++ b/device/hid/hid_connection_win.cc @@ -0,0 +1,279 @@ +// Copyright 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/message_loop/message_loop.h" +#include "base/stl_util.h" +#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 { + +HidConnectionWin::PendingTransfer::PendingTransfer( + scoped_refptr<HidConnectionWin> conn, + scoped_refptr<net::IOBuffer> target, + scoped_refptr<net::IOBuffer> receiving, + bool is_input, + IOCallback callback) + : conn_(conn), + is_input_(is_input), + target_(target), + receiving_(receiving), + callback_(callback), + event_(CreateEvent(NULL, FALSE, FALSE, NULL)) { + memset(&overlapped_, 0, sizeof(OVERLAPPED)); + overlapped_.hEvent = event_.Get(); +} +HidConnectionWin::PendingTransfer::~PendingTransfer() { + base::MessageLoop::current()->RemoveDestructionObserver(this); +} + +void HidConnectionWin::PendingTransfer::TakeResultFromWindowsAPI(BOOL result) { + if (result || GetLastError() != ERROR_IO_PENDING) { + conn_->OnTransferFinished(this); + } else { + base::MessageLoop::current()->AddDestructionObserver(this); + AddRef(); + watcher_.StartWatching(event_.Get(), this); + } +} + +void HidConnectionWin::PendingTransfer::OnObjectSignaled(HANDLE event_handle) { + conn_->OnTransferFinished(this); + Release(); +} + +void HidConnectionWin::PendingTransfer::WillDestroyCurrentMessageLoop() { + watcher_.StopWatching(); + conn_->OnTransferCanceled(this); +} + +void HidConnectionWin::OnTransferFinished( + scoped_refptr<PendingTransfer> transfer) { + DWORD bytes_transfered; + transfers_.erase(transfer); + if (GetOverlappedResult(file_, + transfer->GetOverlapped(), + &bytes_transfered, + FALSE)) { + if (transfer->is_input_ && !device_info_.has_report_id) { + // Move one byte forward. + --bytes_transfered; + memcpy(transfer->target_->data(), + transfer->receiving_->data() + 1, + bytes_transfered); + } + transfer->callback_.Run(true, bytes_transfered); + } else { + transfer->callback_.Run(false, 0); + } +} + +void HidConnectionWin::OnTransferCanceled( + scoped_refptr<PendingTransfer> transfer) { + transfers_.erase(transfer); + transfer->callback_.Run(false, 0); +} + +HidConnectionWin::HidConnectionWin(HidDeviceInfo device_info) + : HidConnection(device_info), + available_(false) { + DCHECK(thread_checker_.CalledOnValidThread()); + file_.Set(CreateFileA(device_info.device_id.c_str(), + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL)); + available_ = file_.IsValid(); +} + +HidConnectionWin::~HidConnectionWin() { + DCHECK(thread_checker_.CalledOnValidThread()); + CancelIo(file_.Get()); +} + +void HidConnectionWin::Read(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const HidConnection::IOCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + size_t report_size = device_info_.input_report_size; + if (report_size == 0) { + // The device does not supoort input reports. + callback.Run(false, 0); + return; + } + + if (size + !device_info_.has_report_id < report_size) { + // Buffer too short. + callback.Run(false, 0); + return; + } + + scoped_refptr<net::IOBuffer> expanded_buffer; + if (!device_info_.has_report_id) { + ++size; + expanded_buffer = new net::IOBuffer(static_cast<int>(size)); + } + + scoped_refptr<PendingTransfer> transfer( + new PendingTransfer(this, buffer, expanded_buffer, true, callback)); + transfers_.insert(transfer); + transfer->TakeResultFromWindowsAPI(ReadFile(file_.Get(), + device_info_.has_report_id ? + buffer->data() : + expanded_buffer->data(), + static_cast<DWORD>(size), + NULL, + transfer->GetOverlapped())); +} + +void HidConnectionWin::Write(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const HidConnection::IOCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + size_t report_size = device_info_.output_report_size; + if (report_size == 0) { + // The device does not supoort output reports. + callback.Run(false, 0); + return; + } + + if (size + !device_info_.has_report_id > report_size) { + // Size of report too long. + callback.Run(false, 0); + return; + } + + scoped_refptr<net::IOBuffer> expanded_buffer; + if (!device_info_.has_report_id) { + expanded_buffer = new net::IOBuffer( + static_cast<int>(device_info_.output_report_size)); + memset(expanded_buffer->data(), 0, device_info_.output_report_size); + memcpy(expanded_buffer->data() + 1, + buffer->data(), + size); + size++; + } + + scoped_refptr<PendingTransfer> transfer( + new PendingTransfer(this, buffer, expanded_buffer, false, callback)); + transfers_.insert(transfer); + transfer->TakeResultFromWindowsAPI( + WriteFile(file_.Get(), + device_info_.has_report_id ? + buffer->data() : expanded_buffer->data(), + static_cast<DWORD>(device_info_.output_report_size), + NULL, + transfer->GetOverlapped())); +} + +void HidConnectionWin::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const IOCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + size_t report_size = device_info_.feature_report_size; + if (report_size == 0) { + // The device does not supoort input reports. + callback.Run(false, 0); + return; + } + + if (size + !device_info_.has_report_id < report_size) { + // Buffer too short. + callback.Run(false, 0); + return; + } + + scoped_refptr<net::IOBuffer> expanded_buffer; + if (!device_info_.has_report_id) { + ++size; + expanded_buffer = new net::IOBuffer(static_cast<int>(size)); + } + + scoped_refptr<PendingTransfer> transfer( + new PendingTransfer(this, buffer, expanded_buffer, true, callback)); + transfers_.insert(transfer); + transfer->TakeResultFromWindowsAPI( + DeviceIoControl(file_.Get(), + IOCTL_HID_GET_FEATURE, + NULL, + 0, + device_info_.has_report_id ? + buffer->data() : + expanded_buffer->data(), + static_cast<DWORD>(size), + NULL, + transfer->GetOverlapped())); +} + +void HidConnectionWin::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer, + size_t size, + const IOCallback& callback) { + DCHECK(thread_checker_.CalledOnValidThread()); + size_t report_size = device_info_.feature_report_size; + if (report_size == 0) { + // The device does not supoort output reports. + callback.Run(false, 0); + return; + } + + if (size + !device_info_.has_report_id > report_size) { + // Size of report too long. + callback.Run(false, 0); + return; + } + + scoped_refptr<net::IOBuffer> expanded_buffer; + if (!device_info_.has_report_id) { + expanded_buffer = new net::IOBuffer( + static_cast<int>(device_info_.feature_report_size)); + memset(expanded_buffer->data(), 0, device_info_.feature_report_size); + memcpy(expanded_buffer->data() + 1, + buffer->data(), + size); + size++; + } + + scoped_refptr<PendingTransfer> transfer( + new PendingTransfer(this, buffer, expanded_buffer, false, callback)); + transfer->TakeResultFromWindowsAPI( + DeviceIoControl(file_.Get(), + IOCTL_HID_SET_FEATURE, + device_info_.has_report_id ? + buffer->data() : + expanded_buffer->data(), + static_cast<DWORD>(device_info_.output_report_size), + NULL, + 0, + NULL, + transfer->GetOverlapped())); +} + +} // namespace device |