Home | History | Annotate | Download | only in driver
      1 /*
      2  * Copyright (C) 2006 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 AndroidUsbPipeFileObject that
     19   encapsulates a common extension for pipe file objects.
     20 */
     21 #pragma data_seg()
     22 #pragma code_seg()
     23 
     24 #include "precomp.h"
     25 #include "android_usb_pipe_file_object.h"
     26 
     27 #pragma data_seg()
     28 #pragma code_seg("PAGE")
     29 
     30 AndroidUsbPipeFileObject::AndroidUsbPipeFileObject(
     31     AndroidUsbDeviceObject* dev_obj,
     32     WDFFILEOBJECT wdf_fo,
     33     WDFUSBPIPE wdf_pipe_obj)
     34     : AndroidUsbFileObject(AndroidUsbFileObjectTypePipe, dev_obj, wdf_fo),
     35       wdf_pipe_(wdf_pipe_obj) {
     36   ASSERT_IRQL_PASSIVE();
     37   ASSERT(NULL != wdf_pipe_obj);
     38 }
     39 
     40 #pragma code_seg()
     41 
     42 AndroidUsbPipeFileObject::~AndroidUsbPipeFileObject() {
     43   ASSERT_IRQL_LOW_OR_DISPATCH();
     44 }
     45 
     46 #pragma code_seg("PAGE")
     47 
     48 NTSTATUS AndroidUsbPipeFileObject::InitializePipe(
     49     const WDF_USB_PIPE_INFORMATION* pipe_info) {
     50   ASSERT_IRQL_LOW();
     51   ASSERT(IsPipeAttached());
     52   if (!IsPipeAttached())
     53     return STATUS_INTERNAL_ERROR;
     54 
     55   // Initialize base class
     56   NTSTATUS status = AndroidUsbFileObject::Initialize();
     57   ASSERT(NT_SUCCESS(status));
     58   if (!NT_SUCCESS(status))
     59     return status;
     60 
     61   // Save pipe information
     62   pipe_information_ = *pipe_info;
     63 
     64   // We will provide size check ourselves (less surprizes always better)
     65   WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(wdf_pipe());
     66 
     67   GoogleDbgPrint("\n===== File %p for %s pipe. max_transfer_size = %X, max_packet_size = %X",
     68                  this, is_input_pipe() ? "read" : "write",
     69                  max_transfer_size(), max_packet_size());
     70   return STATUS_SUCCESS;
     71 }
     72 
     73 #pragma code_seg()
     74 
     75 void AndroidUsbPipeFileObject::OnEvtIoRead(WDFREQUEST request,
     76                                            size_t length) {
     77   ASSERT_IRQL_LOW_OR_DISPATCH();
     78 
     79   // Make sure that this is an input pipe
     80   if (is_output_pipe()) {
     81     GoogleDbgPrint("\n!!!! Attempt to read from output pipe %p", this);
     82     WdfRequestComplete(request, STATUS_ACCESS_DENIED);
     83     return;
     84   }
     85 
     86   // Make sure zero length I/O doesn't go through
     87   if (0 == length) {
     88     WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0);
     89     return;
     90   }
     91 
     92   // Get MDL for this request.
     93   PMDL request_mdl = NULL;
     94   NTSTATUS status = WdfRequestRetrieveOutputWdmMdl(request, &request_mdl);
     95   ASSERT(NT_SUCCESS(status) && (NULL != request_mdl));
     96   if (NT_SUCCESS(status)) {
     97     CommonBulkReadWrite(request,
     98                         request_mdl,
     99                         static_cast<ULONG>(length),
    100                         true,
    101                         0,
    102                         false);
    103   } else {
    104     WdfRequestComplete(request, status);
    105   }
    106 }
    107 
    108 void AndroidUsbPipeFileObject::OnEvtIoWrite(WDFREQUEST request,
    109                                             size_t length) {
    110 
    111   // Make sure that this is an output pipe
    112   if (is_input_pipe()) {
    113     GoogleDbgPrint("\n!!!! Attempt to write to input pipe %p", this);
    114     WdfRequestComplete(request, STATUS_ACCESS_DENIED);
    115     return;
    116   }
    117 
    118   // Make sure zero length I/O doesn't go through
    119   if (0 == length) {
    120     WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0);
    121     return;
    122   }
    123 
    124   // Get MDL for this request.
    125   PMDL request_mdl = NULL;
    126   NTSTATUS status = WdfRequestRetrieveInputWdmMdl(request, &request_mdl);
    127   ASSERT(NT_SUCCESS(status) && (NULL != request_mdl));
    128   if (NT_SUCCESS(status)) {
    129     CommonBulkReadWrite(request,
    130                         request_mdl,
    131                         static_cast<ULONG>(length),
    132                         false,
    133                         0,
    134                         false);
    135   } else {
    136     WdfRequestComplete(request, status);
    137   }
    138 }
    139 
    140 void AndroidUsbPipeFileObject::OnEvtIoDeviceControl(WDFREQUEST request,
    141                                                     size_t output_buf_len,
    142                                                     size_t input_buf_len,
    143                                                     ULONG ioctl_code) {
    144   ASSERT_IRQL_LOW_OR_DISPATCH();
    145 
    146   switch (ioctl_code) {
    147     case ADB_IOCTL_GET_ENDPOINT_INFORMATION:
    148       OnCtlGetEndpointInformation(request, output_buf_len);
    149       break;
    150 
    151     case ADB_IOCTL_BULK_READ:
    152       OnCtlBulkRead(request, output_buf_len, input_buf_len);
    153       break;
    154 
    155     case ADB_IOCTL_BULK_WRITE:
    156       OnCtlBulkWrite(request, output_buf_len, input_buf_len);
    157       break;
    158 
    159     default:
    160       AndroidUsbFileObject::OnEvtIoDeviceControl(request,
    161                                                  output_buf_len,
    162                                                  input_buf_len,
    163                                                  ioctl_code);
    164       break;
    165   }
    166 }
    167 
    168 void AndroidUsbPipeFileObject::OnCtlGetEndpointInformation(
    169     WDFREQUEST request,
    170     size_t output_buf_len) {
    171   ASSERT_IRQL_LOW_OR_DISPATCH();
    172 
    173   // Verify output buffer
    174   if (output_buf_len < sizeof(AdbEndpointInformation)) {
    175     WdfRequestCompleteWithInformation(request,
    176                                       STATUS_BUFFER_TOO_SMALL,
    177                                       sizeof(AdbEndpointInformation));
    178     return;
    179   }
    180 
    181   // Get the output buffer
    182   NTSTATUS status;
    183   AdbEndpointInformation* ret_info =
    184     reinterpret_cast<AdbEndpointInformation*>(OutAddress(request, &status));
    185   ASSERT(NT_SUCCESS(status) && (NULL != ret_info));
    186   if (!NT_SUCCESS(status)) {
    187     WdfRequestComplete(request, status);
    188     return;
    189   }
    190 
    191   // Copy endpoint info to the output
    192   ret_info->max_packet_size = pipe_information_.MaximumPacketSize;
    193   ret_info->endpoint_address = pipe_information_.EndpointAddress;
    194   ret_info->polling_interval = pipe_information_.Interval;
    195   ret_info->setting_index = pipe_information_.SettingIndex;
    196   ret_info->endpoint_type =
    197     static_cast<AdbEndpointType>(pipe_information_.PipeType);
    198   ret_info->max_transfer_size = pipe_information_.MaximumTransferSize;
    199 
    200   WdfRequestCompleteWithInformation(request,
    201                                     STATUS_SUCCESS,
    202                                     sizeof(AdbEndpointInformation));
    203 }
    204 
    205 void AndroidUsbPipeFileObject::OnCtlBulkRead(WDFREQUEST request,
    206                                              size_t output_buf_len,
    207                                              size_t input_buf_len) {
    208   ASSERT_IRQL_LOW_OR_DISPATCH();
    209 
    210   // Make sure that this is an input pipe
    211   if (is_output_pipe()) {
    212     GoogleDbgPrint("\n!!!! Attempt to IOCTL read from output pipe %p", this);
    213     WdfRequestComplete(request, STATUS_ACCESS_DENIED);
    214     return;
    215   }
    216 
    217   // Make sure zero length I/O doesn't go through
    218   if (0 == output_buf_len) {
    219     WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, 0);
    220     return;
    221   }
    222 
    223   // Verify buffers
    224   ASSERT(input_buf_len >= sizeof(AdbBulkTransfer));
    225   if (input_buf_len < sizeof(AdbBulkTransfer)) {
    226     WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE);
    227     return;
    228   }
    229 
    230   // Get the input buffer
    231   NTSTATUS status;
    232   AdbBulkTransfer* transfer_param =
    233     reinterpret_cast<AdbBulkTransfer*>(InAddress(request, &status));
    234   ASSERT(NT_SUCCESS(status) && (NULL != transfer_param));
    235   if (!NT_SUCCESS(status)) {
    236     WdfRequestComplete(request, status);
    237     return;
    238   }
    239 
    240   // Get MDL for this request.
    241   PMDL request_mdl = NULL;
    242   status = WdfRequestRetrieveOutputWdmMdl(request, &request_mdl);
    243   ASSERT(NT_SUCCESS(status) && (NULL != request_mdl));
    244   if (NT_SUCCESS(status)) {
    245     // Perform the read
    246     CommonBulkReadWrite(request,
    247                         request_mdl,
    248                         static_cast<ULONG>(output_buf_len),
    249                         true,
    250                         transfer_param->time_out,
    251                         true);
    252   } else {
    253     WdfRequestComplete(request, status);
    254   }
    255 }
    256 
    257 void AndroidUsbPipeFileObject::OnCtlBulkWrite(WDFREQUEST request,
    258                                               size_t output_buf_len,
    259                                               size_t input_buf_len) {
    260   ASSERT_IRQL_LOW_OR_DISPATCH();
    261 
    262   // Make sure that this is an output pipe
    263   if (is_input_pipe()) {
    264     GoogleDbgPrint("\n!!!! Attempt to IOCTL write to input pipe %p", this);
    265     WdfRequestComplete(request, STATUS_ACCESS_DENIED);
    266     return;
    267   }
    268 
    269   // Verify buffers
    270   ASSERT(input_buf_len >= sizeof(AdbBulkTransfer));
    271   // Output buffer points to ULONG that receives number of transferred bytes
    272   ASSERT(output_buf_len >= sizeof(ULONG));
    273   if ((input_buf_len < sizeof(AdbBulkTransfer)) ||
    274       (output_buf_len < sizeof(ULONG))) {
    275     WdfRequestComplete(request, STATUS_INVALID_BUFFER_SIZE);
    276     return;
    277   }
    278 
    279   // Get the input buffer
    280   NTSTATUS status = STATUS_SUCCESS;
    281   AdbBulkTransfer* transfer_param =
    282     reinterpret_cast<AdbBulkTransfer*>(InAddress(request, &status));
    283   ASSERT(NT_SUCCESS(status) && (NULL != transfer_param));
    284   if (!NT_SUCCESS(status)) {
    285     WdfRequestComplete(request, status);
    286     return;
    287   }
    288 
    289   // Get the output buffer
    290   ULONG* ret_transfer =
    291     reinterpret_cast<ULONG*>(OutAddress(request, &status));
    292   ASSERT(NT_SUCCESS(status) && (NULL != ret_transfer));
    293   if (!NT_SUCCESS(status)) {
    294     WdfRequestComplete(request, status);
    295     return;
    296   }
    297 
    298   // Cache these param to prevent us from sudden change after we've chacked it.
    299   // This is common practice in protecting ourselves from malicious code:
    300   // 1. Never trust anything that comes from the User Mode.
    301   // 2. Never assume that anything that User Mode buffer has will remain
    302   // unchanged.
    303   void* transfer_buffer = transfer_param->GetWriteBuffer();
    304   ULONG transfer_size = transfer_param->transfer_size;
    305 
    306   // Make sure zero length I/O doesn't go through
    307   if (0 == transfer_size) {
    308     *ret_transfer = 0;
    309     WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, sizeof(ULONG));
    310     return;
    311   }
    312 
    313   // Make sure that buffer is not NULL
    314   ASSERT(NULL != transfer_buffer);
    315   if (NULL == transfer_buffer) {
    316     WdfRequestComplete(request, STATUS_INVALID_PARAMETER);
    317     return;
    318   }
    319 
    320   // At this point we are ready to build MDL for the user buffer.
    321   PMDL write_mdl =
    322     IoAllocateMdl(transfer_buffer, transfer_size, FALSE, FALSE, NULL);
    323   ASSERT(NULL != write_mdl);
    324   if (NULL == write_mdl) {
    325     WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    326     return;
    327   }
    328 
    329   // Now we need to probe/lock this mdl
    330   __try {
    331     MmProbeAndLockPages(write_mdl,
    332                         WdfRequestGetRequestorMode(request),
    333                         IoReadAccess);
    334     status = STATUS_SUCCESS;
    335   } __except (EXCEPTION_EXECUTE_HANDLER) {
    336     status = GetExceptionCode();
    337     ASSERTMSG("\n!!!!! AndroidUsbPipeFileObject::OnCtlBulkWrite exception",
    338               false);
    339   }
    340 
    341   if (!NT_SUCCESS(status)) {
    342     IoFreeMdl(write_mdl);
    343     WdfRequestComplete(request, status);
    344     return;
    345   }
    346 
    347   // Perform the write
    348   status = CommonBulkReadWrite(request,
    349                                write_mdl,
    350                                transfer_size,
    351                                false,
    352                                transfer_param->time_out,
    353                                true);
    354   if (!NT_SUCCESS(status)) {
    355     // If CommonBulkReadWrite failed we need to unlock and free MDL here
    356     MmUnlockPages(write_mdl);
    357     IoFreeMdl(write_mdl);
    358   }
    359 }
    360 
    361 NTSTATUS AndroidUsbPipeFileObject::CommonBulkReadWrite(
    362     WDFREQUEST request,
    363     PMDL transfer_mdl,
    364     ULONG length,
    365     bool is_read,
    366     ULONG time_out,
    367     bool is_ioctl) {
    368   ASSERT_IRQL_LOW_OR_DISPATCH();
    369 
    370   ASSERT(IsPipeAttached());
    371   if (!IsPipeAttached()) {
    372     WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE);
    373     return STATUS_INVALID_DEVICE_STATE;
    374   }
    375 
    376   // Quick access check. Might be redundant though...
    377   ASSERT((is_read && is_input_pipe()) || (!is_read && is_output_pipe()));
    378   if ((is_read && is_output_pipe()) || (!is_read && is_input_pipe())) {
    379     WdfRequestComplete(request, STATUS_ACCESS_DENIED);
    380     return STATUS_ACCESS_DENIED;
    381   }
    382 
    383   // Set URB flags
    384   ULONG urb_flags = USBD_SHORT_TRANSFER_OK | (is_read ?
    385                                                 USBD_TRANSFER_DIRECTION_IN :
    386                                                 USBD_TRANSFER_DIRECTION_OUT);
    387 
    388   // Calculate transfer length for this stage.
    389   ULONG stage_len =
    390     (length > GetTransferGranularity()) ? GetTransferGranularity() : length;
    391 
    392   // Get virtual address that we're gonna use in the transfer.
    393   // We rely here on the fact that we're in the context of the calling thread.
    394   void* virtual_address = MmGetMdlVirtualAddress(transfer_mdl);
    395 
    396   // Allocate our private MDL for this address which we will use for the transfer
    397   PMDL new_mdl = IoAllocateMdl(virtual_address, length, FALSE, FALSE, NULL);
    398   ASSERT(NULL != new_mdl);
    399   if (NULL == new_mdl) {
    400     WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    401     return STATUS_INSUFFICIENT_RESOURCES;
    402   }
    403 
    404   // Map the portion of user buffer that we're going to transfer at this stage
    405   // to our mdl.
    406   IoBuildPartialMdl(transfer_mdl, new_mdl, virtual_address, stage_len);
    407 
    408   // Allocate memory for URB and associate it with this request
    409   WDF_OBJECT_ATTRIBUTES mem_attrib;
    410   WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib);
    411   mem_attrib.ParentObject = request;
    412 
    413   WDFMEMORY urb_mem = NULL;
    414   PURB urb = NULL;
    415   NTSTATUS status =
    416     WdfMemoryCreate(&mem_attrib,
    417                     NonPagedPool,
    418                     GANDR_POOL_TAG_BULKRW_URB,
    419                     sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
    420                     &urb_mem,
    421                     reinterpret_cast<PVOID*>(&urb));
    422   ASSERT(NT_SUCCESS(status) && (NULL != urb));
    423   if (!NT_SUCCESS(status)) {
    424     IoFreeMdl(new_mdl);
    425     WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES);
    426     return STATUS_INSUFFICIENT_RESOURCES;
    427   }
    428 
    429   // Get USB pipe handle for our pipe and initialize transfer request for it
    430   USBD_PIPE_HANDLE usbd_pipe_hndl = usbd_pipe();
    431   ASSERT(NULL != usbd_pipe_hndl);
    432   if (NULL == usbd_pipe_hndl) {
    433     IoFreeMdl(new_mdl);
    434     WdfRequestComplete(request, STATUS_INTERNAL_ERROR);
    435     return STATUS_INTERNAL_ERROR;
    436   }
    437 
    438   // Initialize URB with request information
    439   UsbBuildInterruptOrBulkTransferRequest(
    440     urb,
    441     sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
    442     usbd_pipe_hndl,
    443     NULL,
    444     new_mdl,
    445     stage_len,
    446     urb_flags,
    447     NULL);
    448 
    449   // Build transfer request
    450   status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(),
    451                                                request,
    452                                                urb_mem,
    453                                                NULL);
    454   ASSERT(NT_SUCCESS(status));
    455   if (!NT_SUCCESS(status)) {
    456     IoFreeMdl(new_mdl);
    457     WdfRequestComplete(request, status);
    458     return status;
    459   }
    460 
    461   // Initialize our request context.
    462   AndroidUsbWdfRequestContext* context =
    463     GetAndroidUsbWdfRequestContext(request);
    464   ASSERT(NULL != context);
    465   if (NULL == context) {
    466     IoFreeMdl(new_mdl);
    467     WdfRequestComplete(request, STATUS_INTERNAL_ERROR);
    468     return STATUS_INTERNAL_ERROR;
    469   }
    470 
    471   context->object_type = AndroidUsbWdfObjectTypeRequest;
    472   context->urb_mem = urb_mem;
    473   context->transfer_mdl = transfer_mdl;
    474   context->mdl = new_mdl;
    475   context->length = length;
    476   context->transfer_size = stage_len;
    477   context->num_xfer = 0;
    478   context->virtual_address = virtual_address;
    479   context->is_read = is_read;
    480   context->initial_time_out = time_out;
    481   context->is_ioctl = is_ioctl;
    482 
    483   // Set our completion routine
    484   WdfRequestSetCompletionRoutine(request,
    485                                  CommonReadWriteCompletionEntry,
    486                                  this);
    487 
    488   // Init send options (our timeout goes here)
    489   WDF_REQUEST_SEND_OPTIONS send_options;
    490   if (0 != time_out) {
    491     WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_TIMEOUT);
    492     WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&send_options, WDF_REL_TIMEOUT_IN_MS(time_out));
    493   }
    494 
    495   // Timestamp first WdfRequestSend
    496   KeQuerySystemTime(&context->sent_at);
    497 
    498   // Send request asynchronously.
    499   if (WdfRequestSend(request, wdf_pipe_io_target(),
    500                      (0 == time_out) ? WDF_NO_SEND_OPTIONS : &send_options)) {
    501     return STATUS_SUCCESS;
    502   }
    503 
    504   // Something went wrong here
    505   status = WdfRequestGetStatus(request);
    506   ASSERT(!NT_SUCCESS(status));
    507   GoogleDbgPrint("\n!!!!! CommonBulkReadWrite: WdfRequestGetStatus (is_read = %u) failed: %08X",
    508            is_read, status);
    509   WdfRequestCompleteWithInformation(request, status, 0);
    510 
    511   return status;
    512 }
    513 
    514 void AndroidUsbPipeFileObject::OnCommonReadWriteCompletion(
    515     WDFREQUEST request,
    516     PWDF_REQUEST_COMPLETION_PARAMS completion_params,
    517     AndroidUsbWdfRequestContext* context) {
    518   ASSERT_IRQL_LOW_OR_DISPATCH();
    519 
    520   NTSTATUS status = completion_params->IoStatus.Status;
    521   if (!NT_SUCCESS(status)){
    522     GoogleDbgPrint("\n========== Request completed with failure: %X", status);
    523     IoFreeMdl(context->mdl);
    524     // If this was IOCTL-originated write we must unlock and free
    525     // our transfer MDL.
    526     if (context->is_ioctl && !context->is_read) {
    527       MmUnlockPages(context->transfer_mdl);
    528       IoFreeMdl(context->transfer_mdl);
    529     }
    530     WdfRequestComplete(request, status);
    531     return;
    532   }
    533 
    534   // Get our URB buffer
    535   PURB urb
    536     = reinterpret_cast<PURB>(WdfMemoryGetBuffer(context->urb_mem, NULL));
    537   ASSERT(NULL != urb);
    538 
    539   // Lets see how much has been transfered and update our counters accordingly
    540   ULONG bytes_transfered =
    541     urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
    542   // We expect writes to transfer entire packet
    543   ASSERT((bytes_transfered == context->transfer_size) || context->is_read);
    544   context->num_xfer += bytes_transfered;
    545   context->length -= bytes_transfered;
    546 
    547   // Is there anything left to transfer? Now, by the protocol we should
    548   // successfuly complete partial reads, instead of waiting on full set
    549   // of requested bytes being accumulated in the read buffer.
    550   if ((0 == context->length) || context->is_read) {
    551     status = STATUS_SUCCESS;
    552 
    553     // This was the last transfer
    554     if (context->is_ioctl && !context->is_read) {
    555       // For IOCTL-originated writes we have to return transfer size through
    556       // the IOCTL's output buffer.
    557       ULONG* ret_transfer =
    558         reinterpret_cast<ULONG*>(OutAddress(request, NULL));
    559       ASSERT(NULL != ret_transfer);
    560       if (NULL != ret_transfer)
    561         *ret_transfer = context->num_xfer;
    562       WdfRequestSetInformation(request, sizeof(ULONG));
    563 
    564       // We also must unlock / free transfer MDL
    565       MmUnlockPages(context->transfer_mdl);
    566       IoFreeMdl(context->transfer_mdl);
    567     } else {
    568       // For other requests we report transfer size through the request I/O
    569       // completion status.
    570       WdfRequestSetInformation(request, context->num_xfer);
    571     }
    572     IoFreeMdl(context->mdl);
    573     WdfRequestComplete(request, status);
    574     return;
    575   }
    576 
    577   // There are something left for the transfer. Prepare for it.
    578   // Required to free any mapping made on the partial MDL and
    579   // reset internal MDL state.
    580   MmPrepareMdlForReuse(context->mdl);
    581 
    582   // Update our virtual address
    583   context->virtual_address =
    584     reinterpret_cast<char*>(context->virtual_address) + bytes_transfered;
    585 
    586   // Calculate size of this transfer
    587   ULONG stage_len =
    588     (context->length > GetTransferGranularity()) ? GetTransferGranularity() :
    589                                                    context->length;
    590 
    591   IoBuildPartialMdl(context->transfer_mdl,
    592                     context->mdl,
    593                     context->virtual_address,
    594                     stage_len);
    595 
    596   // Reinitialize the urb and context
    597   urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stage_len;
    598   context->transfer_size = stage_len;
    599 
    600   // Format the request to send a URB to a USB pipe.
    601   status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(),
    602                                                request,
    603                                                context->urb_mem,
    604                                                NULL);
    605   ASSERT(NT_SUCCESS(status));
    606   if (!NT_SUCCESS(status)) {
    607     if (context->is_ioctl && !context->is_read) {
    608       MmUnlockPages(context->transfer_mdl);
    609       IoFreeMdl(context->transfer_mdl);
    610     }
    611     IoFreeMdl(context->mdl);
    612     WdfRequestComplete(request, status);
    613     return;
    614   }
    615 
    616   // Reset the completion routine
    617   WdfRequestSetCompletionRoutine(request,
    618                                  CommonReadWriteCompletionEntry,
    619                                  this);
    620 
    621   // Send the request asynchronously.
    622   if (!WdfRequestSend(request, wdf_pipe_io_target(), WDF_NO_SEND_OPTIONS)) {
    623     if (context->is_ioctl && !context->is_read) {
    624       MmUnlockPages(context->transfer_mdl);
    625       IoFreeMdl(context->transfer_mdl);
    626     }
    627     status = WdfRequestGetStatus(request);
    628     IoFreeMdl(context->mdl);
    629     WdfRequestComplete(request, status);
    630   }
    631 }
    632 
    633 NTSTATUS AndroidUsbPipeFileObject::ResetPipe() {
    634   ASSERT_IRQL_PASSIVE();
    635 
    636   // This routine synchronously submits a URB_FUNCTION_RESET_PIPE
    637   // request down the stack.
    638   NTSTATUS status = WdfUsbTargetPipeAbortSynchronously(wdf_pipe(),
    639                                                        WDF_NO_HANDLE,
    640                                                        NULL);
    641   if (NT_SUCCESS(status)) {
    642     status = WdfUsbTargetPipeResetSynchronously(wdf_pipe(),
    643                                                 WDF_NO_HANDLE,
    644                                                 NULL);
    645     if (!NT_SUCCESS(status))
    646       GoogleDbgPrint("\n!!!!! AndroidUsbPipeFileObject::ResetPipe failed %X", status);
    647   } else {
    648       GoogleDbgPrint("\n!!!!! WdfUsbTargetPipeAbortSynchronously failed %X", status);
    649   }
    650 
    651   return status;
    652 }
    653 
    654 NTSTATUS AndroidUsbPipeFileObject::QueueResetPipePassiveCallback() {
    655   ASSERT_IRQL_LOW_OR_DISPATCH();
    656 
    657   // Initialize workitem
    658   WDF_OBJECT_ATTRIBUTES attr;
    659   WDF_OBJECT_ATTRIBUTES_INIT(&attr);
    660   WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&attr, AndroidUsbWorkitemContext);
    661   attr.ParentObject = wdf_device();
    662 
    663   WDFWORKITEM wdf_work_item = NULL;
    664   WDF_WORKITEM_CONFIG workitem_config;
    665   WDF_WORKITEM_CONFIG_INIT(&workitem_config, ResetPipePassiveCallbackEntry);
    666   NTSTATUS status = WdfWorkItemCreate(&workitem_config,
    667                                       &attr,
    668                                       &wdf_work_item);
    669   ASSERT(NT_SUCCESS(status) && (NULL != wdf_work_item));
    670   if (!NT_SUCCESS(status))
    671     return status;
    672 
    673   // Initialize our extension to work item
    674   AndroidUsbWorkitemContext* context =
    675     GetAndroidUsbWorkitemContext(wdf_work_item);
    676   ASSERT(NULL != context);
    677   if (NULL == context) {
    678     WdfObjectDelete(wdf_work_item);
    679     return STATUS_INTERNAL_ERROR;
    680   }
    681 
    682   context->object_type = AndroidUsbWdfObjectTypeWorkitem;
    683   context->pipe_file_ext = this;
    684 
    685   // Enqueue this work item.
    686   WdfWorkItemEnqueue(wdf_work_item);
    687 
    688   return STATUS_SUCCESS;
    689 }
    690 
    691 void AndroidUsbPipeFileObject::CommonReadWriteCompletionEntry(
    692     WDFREQUEST request,
    693     WDFIOTARGET wdf_target,
    694     PWDF_REQUEST_COMPLETION_PARAMS completion_params,
    695     WDFCONTEXT completion_context) {
    696   ASSERT_IRQL_LOW_OR_DISPATCH();
    697 
    698   AndroidUsbWdfRequestContext*
    699     context = GetAndroidUsbWdfRequestContext(request);
    700   ASSERT((NULL != context) && (AndroidUsbWdfObjectTypeRequest == context->object_type));
    701 
    702   AndroidUsbPipeFileObject* pipe_file_ext =
    703     reinterpret_cast<AndroidUsbPipeFileObject*>(completion_context);
    704   ASSERT((NULL != pipe_file_ext) &&
    705          (pipe_file_ext->wdf_pipe() == (WDFUSBPIPE)wdf_target));
    706 
    707   pipe_file_ext->OnCommonReadWriteCompletion(request,
    708                                              completion_params,
    709                                              context);
    710 }
    711 
    712 void AndroidUsbPipeFileObject::ResetPipePassiveCallbackEntry(
    713     WDFWORKITEM wdf_work_item) {
    714   ASSERT_IRQL_PASSIVE();
    715 
    716   AndroidUsbWorkitemContext* context =
    717     GetAndroidUsbWorkitemContext(wdf_work_item);
    718   ASSERT((NULL != context) &&
    719          (AndroidUsbWdfObjectTypeWorkitem == context->object_type));
    720   if ((NULL == context) ||
    721       (AndroidUsbWdfObjectTypeWorkitem != context->object_type)) {
    722     WdfObjectDelete(wdf_work_item);
    723     return;
    724   }
    725 
    726   // In the sample they reset the device if pipe reset failed
    727   AndroidUsbDeviceObject* wdf_device_ext =
    728     context->pipe_file_ext->device_object();
    729 
    730   NTSTATUS status = context->pipe_file_ext->ResetPipe();
    731   if (!NT_SUCCESS(status))
    732     status = wdf_device_ext->ResetDevice();
    733 
    734   WdfObjectDelete(wdf_work_item);
    735 }
    736 
    737 #pragma data_seg()
    738 #pragma code_seg()
    739