Home | History | Annotate | Download | only in winusb
      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