hid_connection_win.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_connection_win.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <cstring> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h" 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/win/object_watcher.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/win/scoped_handle.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "device/hid/hid_service_win.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define INITGUID 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h> 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidclass.h> 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extern "C" { 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidsdi.h> 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <setupapi.h> 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <winioctl.h> 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device { 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>, 32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public base::win::ObjectWatcher::Delegate, 33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public base::MessageLoop::DestructionObserver { 34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) PendingHidTransfer(scoped_refptr<HidConnectionWin> connection, 35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> target_buffer, 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> receive_buffer, 37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HidConnection::IOCallback callback); 38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void TakeResultFromWindowsAPI(BOOL result); 40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OVERLAPPED* GetOverlapped() { return &overlapped_; } 42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Implements base::win::ObjectWatcher::Delegate. 44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void OnObjectSignaled(HANDLE object) OVERRIDE; 45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Implements base::MessageLoop::DestructionObserver 47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual void WillDestroyCurrentMessageLoop() OVERRIDE; 48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<HidConnectionWin> connection_; 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> target_buffer_; 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> receive_buffer_; 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HidConnection::IOCallback callback_; 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) OVERLAPPED overlapped_; 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::win::ScopedHandle event_; 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::win::ObjectWatcher watcher_; 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) friend class base::RefCounted<PendingHidTransfer>; 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) virtual ~PendingHidTransfer(); 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(PendingHidTransfer); 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PendingHidTransfer::PendingHidTransfer( 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<HidConnectionWin> connection, 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> target_buffer, 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> receive_buffer, 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) HidConnection::IOCallback callback) 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : connection_(connection), 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) target_buffer_(target_buffer), 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) receive_buffer_(receive_buffer), 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback_(callback), 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) event_(CreateEvent(NULL, FALSE, FALSE, NULL)) { 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) memset(&overlapped_, 0, sizeof(OVERLAPPED)); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) overlapped_.hEvent = event_.Get(); 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PendingHidTransfer::~PendingHidTransfer() { 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoop::current()->RemoveDestructionObserver(this); 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) { 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (result || GetLastError() != ERROR_IO_PENDING) { 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) connection_->OnTransferFinished(this); 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::MessageLoop::current()->AddDestructionObserver(this); 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AddRef(); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) watcher_.StartWatching(event_.Get(), this); 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) { 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) connection_->OnTransferFinished(this); 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Release(); 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PendingHidTransfer::WillDestroyCurrentMessageLoop() { 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) watcher_.StopWatching(); 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) connection_->OnTransferCanceled(this); 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info) 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : HidConnection(device_info) { 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) file_.Set(CreateFileA(device_info.device_id.c_str(), 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GENERIC_WRITE | GENERIC_READ, 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FILE_SHARE_READ | FILE_SHARE_WRITE, 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OPEN_EXISTING, 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FILE_FLAG_OVERLAPPED, 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL)); 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HidConnectionWin::available() const { 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return file_.IsValid(); 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionWin::~HidConnectionWin() { 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CancelIo(file_.Get()); 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionWin::Read(scoped_refptr<net::IOBufferWithSize> buffer, 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const HidConnection::IOCallback& callback) { 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (device_info().input_report_size == 0) { 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The device does not support input reports. 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (buffer->size() < device_info().input_report_size) { 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If the device doesn't support report IDs, the caller should not be 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // expecting one; however, Windows will always expect enough space for one, 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // so we need to use a buffer with one extra byte of space in this case. 141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> receive_buffer(buffer); 142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!device_info().has_report_id) 143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) receive_buffer = new net::IOBufferWithSize(buffer->size() + 1); 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<PendingHidTransfer> transfer( 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new PendingHidTransfer(this, buffer, receive_buffer, callback)); 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfers_.insert(transfer); 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->TakeResultFromWindowsAPI( 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ReadFile(file_.Get(), 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) receive_buffer->data(), 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<DWORD>(receive_buffer->size()), 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) NULL, 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->GetOverlapped())); 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionWin::Write(uint8_t report_id, 157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> buffer, 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const HidConnection::IOCallback& callback) { 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 160a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (device_info().output_report_size == 0) { 161a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The device does not support output reports. 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The Windows API always wants either a report ID (if supported) or 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // zero at the front of every output report. 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> output_buffer(buffer); 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_buffer = new net::IOBufferWithSize(buffer->size() + 1); 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_buffer->data()[0] = report_id; 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) memcpy(output_buffer->data() + 1, buffer->data(), buffer->size()); 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<PendingHidTransfer> transfer( 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new PendingHidTransfer(this, buffer, NULL, callback)); 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfers_.insert(transfer); 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfer->TakeResultFromWindowsAPI( 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) WriteFile(file_.Get(), 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_buffer->data(), 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<DWORD>(output_buffer->size()), 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfer->GetOverlapped())); 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionWin::GetFeatureReport( 185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint8_t report_id, 186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> buffer, 187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const IOCallback& callback) { 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (device_info().feature_report_size == 0) { 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The device does not support feature reports. 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (buffer->size() < device_info().feature_report_size) { 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> receive_buffer(buffer); 201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!device_info().has_report_id) 202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) receive_buffer = new net::IOBufferWithSize(buffer->size() + 1); 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The first byte of the destination buffer is the report ID being requested. 205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) receive_buffer->data()[0] = report_id; 206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<PendingHidTransfer> transfer( 207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new PendingHidTransfer(this, buffer, receive_buffer, callback)); 2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfers_.insert(transfer); 2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfer->TakeResultFromWindowsAPI( 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DeviceIoControl(file_.Get(), 2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IOCTL_HID_GET_FEATURE, 2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0, 214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) receive_buffer->data(), 215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<DWORD>(receive_buffer->size()), 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfer->GetOverlapped())); 2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionWin::SendFeatureReport( 221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) uint8_t report_id, 222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> buffer, 223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const IOCallback& callback) { 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (device_info().feature_report_size == 0) { 226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The device does not support feature reports. 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (buffer->size() < device_info().feature_report_size) { 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(false, 0); 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // The Windows API always wants either a report ID (if supported) or 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // zero at the front of every output report. 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<net::IOBufferWithSize> output_buffer(buffer); 239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_buffer = new net::IOBufferWithSize(buffer->size() + 1); 240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_buffer->data()[0] = report_id; 241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) memcpy(output_buffer->data() + 1, buffer->data(), buffer->size()); 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<PendingHidTransfer> transfer( 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) new PendingHidTransfer(this, buffer, NULL, callback)); 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfer->TakeResultFromWindowsAPI( 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DeviceIoControl(file_.Get(), 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IOCTL_HID_SET_FEATURE, 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) output_buffer->data(), 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) static_cast<DWORD>(output_buffer->size()), 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0, 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) transfer->GetOverlapped())); 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionWin::OnTransferFinished( 257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<PendingHidTransfer> transfer) { 258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DWORD bytes_transferred; 259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfers_.erase(transfer); 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (GetOverlappedResult( 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) { 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (bytes_transferred == 0) 263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->callback_.Run(true, 0); 264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If this is an input transfer and the receive buffer is not the same as 265a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // the target buffer, we need to copy the receive buffer into the target 266a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // buffer, discarding the first byte. This is because the target buffer's 267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // owner is not expecting a report ID but Windows will always provide one. 268a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (transfer->receive_buffer_ && 269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->receive_buffer_ != transfer->target_buffer_) { 270a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Move one byte forward. 271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) --bytes_transferred; 272a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) memcpy(transfer->target_buffer_->data(), 273a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->receive_buffer_->data() + 1, 274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bytes_transferred); 275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->callback_.Run(true, bytes_transferred); 277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->callback_.Run(false, 0); 279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void HidConnectionWin::OnTransferCanceled( 283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_refptr<PendingHidTransfer> transfer) { 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfers_.erase(transfer); 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) transfer->callback_.Run(false, 0); 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace device 289