1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /** \file 18 This file consists of implementation of class AdbWinUsbEndpointObject that 19 encapsulates a handle opened to a WinUsb endpoint on our device. 20 */ 21 22 #include "stdafx.h" 23 #include "adb_winusb_endpoint_object.h" 24 #include "adb_winusb_io_completion.h" 25 26 AdbWinUsbEndpointObject::AdbWinUsbEndpointObject( 27 AdbWinUsbInterfaceObject* parent_interf, 28 UCHAR endpoint_id, 29 UCHAR endpoint_index) 30 : AdbEndpointObject(parent_interf, endpoint_id, endpoint_index), 31 lock_(), is_closing_(false), pending_io_count_(0) { 32 } 33 34 AdbWinUsbEndpointObject::~AdbWinUsbEndpointObject() { 35 } 36 37 LONG AdbWinUsbEndpointObject::Release() { 38 ATLASSERT(ref_count_ > 0); 39 LONG ret = InterlockedDecrement(&ref_count_); 40 ATLASSERT(ret >= 0); 41 if (0 == ret) { 42 LastReferenceReleased(); 43 delete this; 44 } 45 return ret; 46 } 47 48 bool AdbWinUsbEndpointObject::CloseHandle() { 49 // This method only returns once all pending IOs are aborted and after 50 // preventing future pending IOs. This means that once CloseHandle() 51 // returns, threads using this object won't be using 52 // parent_winusb_interface()->winusb_handle(), so it can then be safely 53 // released. 54 lock_.Lock(); 55 if (!is_closing_) { 56 // Set flag to prevent new I/Os from starting up. 57 is_closing_ = true; 58 } 59 60 // While there are pending IOs, keep aborting the pipe. We have to do this 61 // repeatedly because pending_ios_ is incremented before the IO has actually 62 // started, and abort (probably) only works if the IO has been started. 63 while (pending_io_count_ > 0) { 64 lock_.Unlock(); 65 66 // It has been noticed that on Windows 7, if you only call 67 // WinUsb_AbortPipe(), without first calling WinUsb_ResetPipe(), the call 68 // to WinUsb_AbortPipe() hangs. 69 if (!WinUsb_ResetPipe(parent_winusb_interface()->winusb_handle(), 70 endpoint_id()) || 71 !WinUsb_AbortPipe(parent_winusb_interface()->winusb_handle(), 72 endpoint_id())) { 73 // Reset or Abort failed for unexpected reason. We might not be able to 74 // abort pending IOs, so we shouldn't keep polling pending_io_count_ or 75 // else we might hang forever waiting for the IOs to abort. In this 76 // situation it is preferable to risk a race condition (which may or may 77 // not crash) and just break now. 78 lock_.Lock(); 79 break; 80 } 81 82 // Give the IO threads time to break out of I/O calls and decrement 83 // pending_io_count_. They should finish up pretty quick. The amount of time 84 // "wasted" here (as opposed to if we did synchronization with an event) 85 // doesn't really matter since this is an uncommon corner-case. 86 Sleep(16); // 16 ms, old default OS scheduler granularity 87 88 lock_.Lock(); 89 } 90 91 lock_.Unlock(); 92 93 return AdbEndpointObject::CloseHandle(); 94 } 95 96 ADBAPIHANDLE AdbWinUsbEndpointObject::CommonAsyncReadWrite( 97 bool is_read, 98 void* buffer, 99 ULONG bytes_to_transfer, 100 ULONG* bytes_transferred, 101 HANDLE event_handle, 102 ULONG time_out) { 103 // TODO: Do synchronization with is_closing_ and pending_io_count_ like 104 // CommonSyncReadWrite(). This is not yet implemented because there are no 105 // callers to Adb{Read,Write}EndpointAsync() in AOSP, and hence no testing. 106 if (!SetTimeout(time_out)) 107 return false; 108 109 // Create completion i/o object 110 AdbIOCompletion* adb_io_completion = NULL; 111 112 try { 113 adb_io_completion = new AdbWinUsbIOCompletion(this, 114 bytes_to_transfer, 115 event_handle); 116 } catch (... ) { 117 SetLastError(ERROR_OUTOFMEMORY); 118 return NULL; 119 } 120 121 // Create a handle for it 122 ADBAPIHANDLE ret = adb_io_completion->CreateHandle(); 123 ULONG transferred = 0; 124 if (NULL != ret) { 125 BOOL res = TRUE; 126 // Go the read / write file way 127 res = is_read ? 128 WinUsb_ReadPipe(parent_winusb_interface()->winusb_handle(), 129 endpoint_id(), 130 reinterpret_cast<PUCHAR>(buffer), 131 bytes_to_transfer, 132 &transferred, 133 adb_io_completion->overlapped()) : 134 WinUsb_WritePipe(parent_winusb_interface()->winusb_handle(), 135 endpoint_id(), 136 reinterpret_cast<PUCHAR>(buffer), 137 bytes_to_transfer, 138 &transferred, 139 adb_io_completion->overlapped()); 140 141 if (NULL != bytes_transferred) 142 *bytes_transferred = transferred; 143 144 ULONG error = GetLastError(); 145 if (!res && (ERROR_IO_PENDING != error)) { 146 // I/O failed immediatelly. We need to close i/o completion object 147 // before we return NULL to the caller. 148 adb_io_completion->CloseHandle(); 149 ret = NULL; 150 SetLastError(error); 151 } 152 } 153 154 // Offseting 'new' 155 adb_io_completion->Release(); 156 157 return ret; 158 } 159 160 bool AdbWinUsbEndpointObject::CommonSyncReadWrite(bool is_read, 161 void* buffer, 162 ULONG bytes_to_transfer, 163 ULONG* bytes_transferred, 164 ULONG time_out) { 165 lock_.Lock(); 166 if (is_closing_) { 167 lock_.Unlock(); 168 // AdbCloseHandle() is in progress, so don't start up any new IOs. 169 SetLastError(ERROR_HANDLES_CLOSED); 170 return false; 171 } else { 172 // Not closing down, so record the fact that we're doing IO. This will 173 // prevent CloseHandle() from returning until our IO completes or it aborts 174 // our IO. 175 ++pending_io_count_; 176 lock_.Unlock(); 177 } 178 179 // Because we've incremented pending_ios_, do the matching decrement when this 180 // object goes out of scope. 181 DecrementPendingIO dec(this); 182 183 if (!SetTimeout(time_out)) 184 return false; 185 186 // This is synchronous I/O. Since we always open I/O items for 187 // overlapped I/O we're obligated to always provide OVERLAPPED 188 // structure to read / write routines. Prepare it now. 189 OVERLAPPED overlapped; 190 ZeroMemory(&overlapped, sizeof(overlapped)); 191 overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 192 193 BOOL ret = TRUE; 194 ULONG transferred = 0; 195 // Go the read / write file way 196 ret = is_read ? 197 WinUsb_ReadPipe(parent_winusb_interface()->winusb_handle(), 198 endpoint_id(), 199 reinterpret_cast<PUCHAR>(buffer), 200 bytes_to_transfer, 201 &transferred, 202 &overlapped) : 203 WinUsb_WritePipe(parent_winusb_interface()->winusb_handle(), 204 endpoint_id(), 205 reinterpret_cast<PUCHAR>(buffer), 206 bytes_to_transfer, 207 &transferred, 208 &overlapped); 209 210 // Lets see the result 211 if (!ret && (ERROR_IO_PENDING != GetLastError())) { 212 // I/O failed. 213 if (NULL != overlapped.hEvent) 214 ::CloseHandle(overlapped.hEvent); 215 return false; 216 } 217 218 // Lets wait till I/O completes 219 ret = WinUsb_GetOverlappedResult(parent_winusb_interface()->winusb_handle(), &overlapped, 220 &transferred, TRUE); 221 if (ret && (NULL != bytes_transferred)) { 222 *bytes_transferred = transferred; 223 } 224 225 if (NULL != overlapped.hEvent) 226 ::CloseHandle(overlapped.hEvent); 227 228 return ret ? true : false; 229 } 230 231 bool AdbWinUsbEndpointObject::SetTimeout(ULONG timeout) { 232 if (!WinUsb_SetPipePolicy(parent_winusb_interface()->winusb_handle(), 233 endpoint_id(), PIPE_TRANSFER_TIMEOUT, 234 sizeof(ULONG), &timeout)) { 235 return false; 236 } 237 238 return true; 239 } 240