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)
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/files/file.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/win/object_watcher.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define INITGUID
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <windows.h>
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidclass.h>
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)extern "C" {
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <hidsdi.h>
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <setupapi.h>
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <winioctl.h>
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace device {
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)struct PendingHidTransfer : public base::RefCounted<PendingHidTransfer>,
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            public base::win::ObjectWatcher::Delegate,
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            public base::MessageLoop::DestructionObserver {
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  typedef base::Callback<void(PendingHidTransfer*, bool)> Callback;
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PendingHidTransfer(scoped_refptr<net::IOBuffer> buffer,
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                     const Callback& callback);
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void TakeResultFromWindowsAPI(BOOL result);
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OVERLAPPED* GetOverlapped() { return &overlapped_; }
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Implements base::win::ObjectWatcher::Delegate.
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Implements base::MessageLoop::DestructionObserver
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The buffer isn't used by this object but it's important that a reference
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // to it is held until the transfer completes.
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<net::IOBuffer> buffer_;
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Callback callback_;
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  OVERLAPPED overlapped_;
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::win::ScopedHandle event_;
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::win::ObjectWatcher watcher_;
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private:
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  friend class base::RefCounted<PendingHidTransfer>;
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual ~PendingHidTransfer();
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(PendingHidTransfer);
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PendingHidTransfer::PendingHidTransfer(
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<net::IOBuffer> buffer,
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const PendingHidTransfer::Callback& callback)
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : buffer_(buffer),
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback_(callback),
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      event_(CreateEvent(NULL, FALSE, FALSE, NULL)) {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  memset(&overlapped_, 0, sizeof(OVERLAPPED));
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  overlapped_.hEvent = event_.Get();
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)PendingHidTransfer::~PendingHidTransfer() {
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::MessageLoop::current()->RemoveDestructionObserver(this);
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PendingHidTransfer::TakeResultFromWindowsAPI(BOOL result) {
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result) {
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback_.Run(this, true);
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (GetLastError() == ERROR_IO_PENDING) {
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::MessageLoop::current()->AddDestructionObserver(this);
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AddRef();
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    watcher_.StartWatching(event_.Get(), this);
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VPLOG(1) << "HID transfer failed";
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback_.Run(this, false);
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PendingHidTransfer::OnObjectSignaled(HANDLE event_handle) {
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback_.Run(this, true);
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Release();
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void PendingHidTransfer::WillDestroyCurrentMessageLoop() {
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  watcher_.StopWatching();
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback_.Run(this, false);
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)HidConnectionWin::HidConnectionWin(const HidDeviceInfo& device_info)
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : HidConnection(device_info) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  file_.Set(CreateFileA(device_info.device_id.c_str(),
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        GENERIC_WRITE | GENERIC_READ,
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        FILE_SHARE_READ | FILE_SHARE_WRITE,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        NULL,
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        OPEN_EXISTING,
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        FILE_FLAG_OVERLAPPED,
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        NULL));
1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!file_.IsValid() &&
1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      GetLastError() == base::File::FILE_ERROR_ACCESS_DENIED) {
1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    file_.Set(CreateFileA(device_info.device_id.c_str(),
1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          GENERIC_READ,
1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          FILE_SHARE_READ,
1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          NULL,
1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          OPEN_EXISTING,
1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          FILE_FLAG_OVERLAPPED,
1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                          NULL));
1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)HidConnectionWin::~HidConnectionWin() {
1221675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch}
1231675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch
1241675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdochvoid HidConnectionWin::PlatformClose() {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CancelIo(file_.Get());
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HidConnectionWin::PlatformRead(
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const HidConnection::ReadCallback& callback) {
13003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Windows will always include the report ID (including zero if report IDs
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // are not in use) in the buffer.
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<net::IOBufferWithSize> buffer =
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      new net::IOBufferWithSize(device_info().max_input_report_size + 1);
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      buffer,
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&HidConnectionWin::OnReadComplete, this, buffer, callback)));
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transfers_.insert(transfer);
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  transfer->TakeResultFromWindowsAPI(
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ReadFile(file_.Get(),
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               buffer->data(),
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               static_cast<DWORD>(buffer->size()),
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               NULL,
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)               transfer->GetOverlapped()));
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HidConnectionWin::PlatformWrite(scoped_refptr<net::IOBuffer> buffer,
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     size_t size,
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     const WriteCallback& callback) {
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The Windows API always wants either a report ID (if supported) or
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // zero at the front of every output report.
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transfers_.insert(transfer);
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  transfer->TakeResultFromWindowsAPI(WriteFile(file_.Get(),
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                               buffer->data(),
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                               static_cast<DWORD>(size),
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                               NULL,
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                               transfer->GetOverlapped()));
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HidConnectionWin::PlatformGetFeatureReport(uint8_t report_id,
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                const ReadCallback& callback) {
163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The first byte of the destination buffer is the report ID being requested.
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<net::IOBufferWithSize> buffer =
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new net::IOBufferWithSize(device_info().max_feature_report_size + 1);
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  buffer->data()[0] = report_id;
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      buffer,
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &HidConnectionWin::OnReadFeatureComplete, this, buffer, callback)));
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transfers_.insert(transfer);
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transfer->TakeResultFromWindowsAPI(
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DeviceIoControl(file_.Get(),
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      IOCTL_HID_GET_FEATURE,
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      NULL,
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      0,
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      buffer->data(),
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      static_cast<DWORD>(buffer->size()),
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      NULL,
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      transfer->GetOverlapped()));
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
184116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid HidConnectionWin::PlatformSendFeatureReport(
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<net::IOBuffer> buffer,
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t size,
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const WriteCallback& callback) {
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // The Windows API always wants either a report ID (if supported) or
189a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // zero at the front of every output report.
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<PendingHidTransfer> transfer(new PendingHidTransfer(
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      buffer, base::Bind(&HidConnectionWin::OnWriteComplete, this, callback)));
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transfer->TakeResultFromWindowsAPI(
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      DeviceIoControl(file_.Get(),
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      IOCTL_HID_SET_FEATURE,
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      buffer->data(),
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      static_cast<DWORD>(size),
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      NULL,
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      0,
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      NULL,
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      transfer->GetOverlapped()));
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HidConnectionWin::OnReadComplete(scoped_refptr<net::IOBuffer> buffer,
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      const ReadCallback& callback,
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      PendingHidTransfer* transfer,
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                      bool signaled) {
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!signaled) {
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false, NULL, 0);
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
211116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
212116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DWORD bytes_transferred;
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (GetOverlappedResult(
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CompleteRead(buffer, bytes_transferred, callback);
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VPLOG(1) << "HID read failed";
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false, NULL, 0);
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HidConnectionWin::OnReadFeatureComplete(
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<net::IOBuffer> buffer,
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const ReadCallback& callback,
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PendingHidTransfer* transfer,
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    bool signaled) {
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!signaled) {
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false, NULL, 0);
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DWORD bytes_transferred;
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (GetOverlappedResult(
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<net::IOBuffer> new_buffer(
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        new net::IOBuffer(bytes_transferred - 1));
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    memcpy(new_buffer->data(), buffer->data() + 1, bytes_transferred - 1);
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CompleteRead(new_buffer, bytes_transferred, callback);
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VPLOG(1) << "HID read failed";
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false, NULL, 0);
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid HidConnectionWin::OnWriteComplete(const WriteCallback& callback,
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       PendingHidTransfer* transfer,
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       bool signaled) {
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!signaled) {
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false);
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DWORD bytes_transferred;
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (GetOverlappedResult(
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          file_, transfer->GetOverlapped(), &bytes_transferred, FALSE)) {
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(true);
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    VPLOG(1) << "HID write failed";
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    callback.Run(false);
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace device
264