| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright 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 | 
|---|