| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #include "device/hid/hid_connection_win.h" | 
|  | 6 | 
|  | 7 #include <cstring> | 
|  | 8 | 
|  | 9 #include "base/message_loop/message_loop.h" | 
|  | 10 #include "base/stl_util.h" | 
|  | 11 #include "base/threading/thread_restrictions.h" | 
|  | 12 #include "device/hid/hid_service.h" | 
|  | 13 #include "device/hid/hid_service_win.h" | 
|  | 14 #include "net/base/io_buffer.h" | 
|  | 15 | 
|  | 16 #if defined(OS_WIN) | 
|  | 17 | 
|  | 18 #define INITGUID | 
|  | 19 | 
|  | 20 #include <windows.h> | 
|  | 21 #include <hidclass.h> | 
|  | 22 | 
|  | 23 extern "C" { | 
|  | 24 | 
|  | 25 #include <hidsdi.h> | 
|  | 26 | 
|  | 27 } | 
|  | 28 | 
|  | 29 #include <setupapi.h> | 
|  | 30 #include <winioctl.h> | 
|  | 31 #include "base/win/scoped_handle.h" | 
|  | 32 | 
|  | 33 #endif  // defined(OS_WIN) | 
|  | 34 | 
|  | 35 namespace device { | 
|  | 36 | 
|  | 37 HidConnectionWin::PendingTransfer::PendingTransfer( | 
|  | 38     scoped_refptr<HidConnectionWin> conn, | 
|  | 39     scoped_refptr<net::IOBuffer> target, | 
|  | 40     scoped_refptr<net::IOBuffer> receiving, | 
|  | 41     bool is_input, | 
|  | 42     IOCallback callback) | 
|  | 43     : conn_(conn), | 
|  | 44       is_input_(is_input), | 
|  | 45       target_(target), | 
|  | 46       receiving_(receiving), | 
|  | 47       callback_(callback), | 
|  | 48       event_(CreateEvent(NULL, FALSE, FALSE, NULL)) { | 
|  | 49   memset(&overlapped_, 0, sizeof(OVERLAPPED)); | 
|  | 50   overlapped_.hEvent = event_.Get(); | 
|  | 51 } | 
|  | 52 HidConnectionWin::PendingTransfer::~PendingTransfer() { | 
|  | 53   base::MessageLoop::current()->RemoveDestructionObserver(this); | 
|  | 54 } | 
|  | 55 | 
|  | 56 void HidConnectionWin::PendingTransfer::TakeResultFromWindowsAPI(BOOL result) { | 
|  | 57   if (result || GetLastError() != ERROR_IO_PENDING) { | 
|  | 58     conn_->OnTransferFinished(this); | 
|  | 59   } else { | 
|  | 60     base::MessageLoop::current()->AddDestructionObserver(this); | 
|  | 61     AddRef(); | 
|  | 62     watcher_.StartWatching(event_.Get(), this); | 
|  | 63   } | 
|  | 64 } | 
|  | 65 | 
|  | 66 void HidConnectionWin::PendingTransfer::OnObjectSignaled(HANDLE event_handle) { | 
|  | 67   conn_->OnTransferFinished(this); | 
|  | 68   Release(); | 
|  | 69 } | 
|  | 70 | 
|  | 71 void HidConnectionWin::PendingTransfer::WillDestroyCurrentMessageLoop() { | 
|  | 72   watcher_.StopWatching(); | 
|  | 73   conn_->OnTransferCanceled(this); | 
|  | 74 } | 
|  | 75 | 
|  | 76 void HidConnectionWin::OnTransferFinished( | 
|  | 77     scoped_refptr<PendingTransfer> transfer) { | 
|  | 78   DWORD bytes_transfered; | 
|  | 79   transfers_.erase(transfer); | 
|  | 80   if (GetOverlappedResult(file_, | 
|  | 81                           transfer->GetOverlapped(), | 
|  | 82                           &bytes_transfered, | 
|  | 83                           FALSE)) { | 
|  | 84     if (transfer->is_input_ && !device_info_.has_report_id) { | 
|  | 85       // Move one byte forward. | 
|  | 86       --bytes_transfered; | 
|  | 87       memcpy(transfer->target_->data(), | 
|  | 88              transfer->receiving_->data() + 1, | 
|  | 89              bytes_transfered); | 
|  | 90     } | 
|  | 91     transfer->callback_.Run(true, bytes_transfered); | 
|  | 92   } else { | 
|  | 93     transfer->callback_.Run(false, 0); | 
|  | 94   } | 
|  | 95 } | 
|  | 96 | 
|  | 97 void HidConnectionWin::OnTransferCanceled( | 
|  | 98     scoped_refptr<PendingTransfer> transfer) { | 
|  | 99   transfers_.erase(transfer); | 
|  | 100   transfer->callback_.Run(false, 0); | 
|  | 101 } | 
|  | 102 | 
|  | 103 HidConnectionWin::HidConnectionWin(HidDeviceInfo device_info) | 
|  | 104     : HidConnection(device_info), | 
|  | 105       available_(false) { | 
|  | 106   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 107   file_.Set(CreateFileA(device_info.device_id.c_str(), | 
|  | 108                         GENERIC_WRITE | GENERIC_READ, | 
|  | 109                         FILE_SHARE_READ | FILE_SHARE_WRITE, | 
|  | 110                         NULL, | 
|  | 111                         OPEN_EXISTING, | 
|  | 112                         FILE_FLAG_OVERLAPPED, | 
|  | 113                         NULL)); | 
|  | 114   available_ = file_.IsValid(); | 
|  | 115 } | 
|  | 116 | 
|  | 117 HidConnectionWin::~HidConnectionWin() { | 
|  | 118   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 119   CancelIo(file_.Get()); | 
|  | 120 } | 
|  | 121 | 
|  | 122 void HidConnectionWin::Read(scoped_refptr<net::IOBuffer> buffer, | 
|  | 123                             size_t size, | 
|  | 124                             const HidConnection::IOCallback& callback) { | 
|  | 125   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 126   size_t report_size = device_info_.input_report_size; | 
|  | 127   if (report_size == 0) { | 
|  | 128     // The device does not supoort input reports. | 
|  | 129     callback.Run(false, 0); | 
|  | 130     return; | 
|  | 131   } | 
|  | 132 | 
|  | 133   if (size + !device_info_.has_report_id < report_size) { | 
|  | 134     // Buffer too short. | 
|  | 135     callback.Run(false, 0); | 
|  | 136     return; | 
|  | 137   } | 
|  | 138 | 
|  | 139   scoped_refptr<net::IOBuffer> expanded_buffer; | 
|  | 140   if (!device_info_.has_report_id) { | 
|  | 141     ++size; | 
|  | 142     expanded_buffer = new net::IOBuffer(static_cast<int>(size)); | 
|  | 143   } | 
|  | 144 | 
|  | 145   scoped_refptr<PendingTransfer> transfer( | 
|  | 146       new PendingTransfer(this, buffer, expanded_buffer, true, callback)); | 
|  | 147   transfers_.insert(transfer); | 
|  | 148   transfer->TakeResultFromWindowsAPI(ReadFile(file_.Get(), | 
|  | 149                                               device_info_.has_report_id ? | 
|  | 150                                                   buffer->data() : | 
|  | 151                                                   expanded_buffer->data(), | 
|  | 152                                               static_cast<DWORD>(size), | 
|  | 153                                               NULL, | 
|  | 154                                               transfer->GetOverlapped())); | 
|  | 155 } | 
|  | 156 | 
|  | 157 void HidConnectionWin::Write(scoped_refptr<net::IOBuffer> buffer, | 
|  | 158                              size_t size, | 
|  | 159                              const HidConnection::IOCallback& callback) { | 
|  | 160   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 161   size_t report_size = device_info_.output_report_size; | 
|  | 162   if (report_size == 0) { | 
|  | 163     // The device does not supoort output reports. | 
|  | 164     callback.Run(false, 0); | 
|  | 165     return; | 
|  | 166   } | 
|  | 167 | 
|  | 168   if (size + !device_info_.has_report_id > report_size) { | 
|  | 169     // Size of report too long. | 
|  | 170     callback.Run(false, 0); | 
|  | 171     return; | 
|  | 172   } | 
|  | 173 | 
|  | 174   scoped_refptr<net::IOBuffer> expanded_buffer; | 
|  | 175   if (!device_info_.has_report_id) { | 
|  | 176     expanded_buffer = new net::IOBuffer( | 
|  | 177         static_cast<int>(device_info_.output_report_size)); | 
|  | 178     memset(expanded_buffer->data(), 0, device_info_.output_report_size); | 
|  | 179     memcpy(expanded_buffer->data() + 1, | 
|  | 180            buffer->data(), | 
|  | 181            size); | 
|  | 182     size++; | 
|  | 183   } | 
|  | 184 | 
|  | 185   scoped_refptr<PendingTransfer> transfer( | 
|  | 186       new PendingTransfer(this, buffer, expanded_buffer, false, callback)); | 
|  | 187   transfers_.insert(transfer); | 
|  | 188   transfer->TakeResultFromWindowsAPI( | 
|  | 189       WriteFile(file_.Get(), | 
|  | 190                 device_info_.has_report_id ? | 
|  | 191                     buffer->data() : expanded_buffer->data(), | 
|  | 192                 static_cast<DWORD>(device_info_.output_report_size), | 
|  | 193                 NULL, | 
|  | 194                 transfer->GetOverlapped())); | 
|  | 195 } | 
|  | 196 | 
|  | 197 void HidConnectionWin::GetFeatureReport(scoped_refptr<net::IOBuffer> buffer, | 
|  | 198                                         size_t size, | 
|  | 199                                         const IOCallback& callback) { | 
|  | 200   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 201   size_t report_size = device_info_.feature_report_size; | 
|  | 202   if (report_size == 0) { | 
|  | 203     // The device does not supoort input reports. | 
|  | 204     callback.Run(false, 0); | 
|  | 205     return; | 
|  | 206   } | 
|  | 207 | 
|  | 208   if (size + !device_info_.has_report_id < report_size) { | 
|  | 209     // Buffer too short. | 
|  | 210     callback.Run(false, 0); | 
|  | 211     return; | 
|  | 212   } | 
|  | 213 | 
|  | 214   scoped_refptr<net::IOBuffer> expanded_buffer; | 
|  | 215   if (!device_info_.has_report_id) { | 
|  | 216     ++size; | 
|  | 217     expanded_buffer = new net::IOBuffer(static_cast<int>(size)); | 
|  | 218   } | 
|  | 219 | 
|  | 220   scoped_refptr<PendingTransfer> transfer( | 
|  | 221       new PendingTransfer(this, buffer, expanded_buffer, true, callback)); | 
|  | 222   transfers_.insert(transfer); | 
|  | 223   transfer->TakeResultFromWindowsAPI( | 
|  | 224       DeviceIoControl(file_.Get(), | 
|  | 225                       IOCTL_HID_GET_FEATURE, | 
|  | 226                       NULL, | 
|  | 227                       0, | 
|  | 228                       device_info_.has_report_id ? | 
|  | 229                           buffer->data() : | 
|  | 230                           expanded_buffer->data(), | 
|  | 231                       static_cast<DWORD>(size), | 
|  | 232                       NULL, | 
|  | 233                       transfer->GetOverlapped())); | 
|  | 234 } | 
|  | 235 | 
|  | 236 void HidConnectionWin::SendFeatureReport(scoped_refptr<net::IOBuffer> buffer, | 
|  | 237                                          size_t size, | 
|  | 238                                          const IOCallback& callback) { | 
|  | 239   DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | 240   size_t report_size = device_info_.feature_report_size; | 
|  | 241   if (report_size == 0) { | 
|  | 242     // The device does not supoort output reports. | 
|  | 243     callback.Run(false, 0); | 
|  | 244     return; | 
|  | 245   } | 
|  | 246 | 
|  | 247   if (size + !device_info_.has_report_id > report_size) { | 
|  | 248     // Size of report too long. | 
|  | 249     callback.Run(false, 0); | 
|  | 250     return; | 
|  | 251   } | 
|  | 252 | 
|  | 253   scoped_refptr<net::IOBuffer> expanded_buffer; | 
|  | 254   if (!device_info_.has_report_id) { | 
|  | 255     expanded_buffer = new net::IOBuffer( | 
|  | 256         static_cast<int>(device_info_.feature_report_size)); | 
|  | 257     memset(expanded_buffer->data(), 0, device_info_.feature_report_size); | 
|  | 258     memcpy(expanded_buffer->data() + 1, | 
|  | 259            buffer->data(), | 
|  | 260            size); | 
|  | 261     size++; | 
|  | 262   } | 
|  | 263 | 
|  | 264   scoped_refptr<PendingTransfer> transfer( | 
|  | 265       new PendingTransfer(this, buffer, expanded_buffer, false, callback)); | 
|  | 266   transfer->TakeResultFromWindowsAPI( | 
|  | 267       DeviceIoControl(file_.Get(), | 
|  | 268                       IOCTL_HID_SET_FEATURE, | 
|  | 269                       device_info_.has_report_id ? | 
|  | 270                           buffer->data() : | 
|  | 271                           expanded_buffer->data(), | 
|  | 272                       static_cast<DWORD>(device_info_.output_report_size), | 
|  | 273                       NULL, | 
|  | 274                       0, | 
|  | 275                       NULL, | 
|  | 276                       transfer->GetOverlapped())); | 
|  | 277 } | 
|  | 278 | 
|  | 279 }  // namespace device | 
| OLD | NEW | 
|---|