⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbfx2lk_io.cpp

📁 基于vc++6.0环境的cypress USB 驱动源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
                            urbFlags,
                            NULL);

    //
    // Set up our USBFX2 I/O context so that when the URB completes we can
    // resume from where we left off.
    //
    pFx2Context->Urb             = urb;
    pFx2Context->Irp             = Irp;
    pFx2Context->Mdl             = pMdl;

    //
    // Indicate how much more data there is to process
    //
    pFx2Context->RemainingLength = totalLength - stageLength;
    pFx2Context->Numxfer         = 0;
    
    //
    // Update the VirtualAddress pointer. We pass this pointer to
    //  IoBuildPartialMdl each time we want to map a portion of the 
    //  MDL to indicate the portion of the MDL that we want to map. 
    //  It must be adjusted after each transfer stage.
    //
    pFx2Context->VirtualAddress  = virtualAddress + stageLength;
    pFx2Context->DevExt          = devExt;
    pFx2Context->TotalLength     = totalLength;

    //
    // We will need a workitem in order to resubmit this IRP in
    //  the case of a multistage transfer. 
    //
    pFx2Context->PWorkItem = IoAllocateWorkItem(devExt->FunctionalDeviceObject);

    if(!pFx2Context->PWorkItem) {
        status = STATUS_INSUFFICIENT_RESOURCES;
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkRead: Failed IoAllocateWorkItem\n"));
        ExFreePool(pFx2Context);
        IoFreeMdl(pMdl);
        ExFreePool(urb);
        goto UsbFx2LkRead_Exit;

    }

    //
    // use the Users Irp as an internal device control irp, which
    //  is what is used to submit URBs to the host controller
    //
    nextStack = IoGetNextIrpStackLocation(Irp);

    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;

    //
    // The USB drivers expect the URB to be in 
    //  Parameters.Others.Argument1
    //
    nextStack->Parameters.Others.Argument1 = (PVOID) urb;

    //
    // Setup the I/O control code
    //
    nextStack->Parameters.DeviceIoControl.IoControlCode = 
                                             IOCTL_INTERNAL_USB_SUBMIT_URB;

    //
    // We need a completion routine for this transfer.
    //
    IoSetCompletionRoutine(Irp, 
                           (PIO_COMPLETION_ROUTINE)UsbFx2LkReadCompletionRoutine,
                           pFx2Context,
                           TRUE,
                           TRUE,
                           TRUE);

    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkRead: Queuing Read Irp\n"));

    //
    // While we have the Irp in our queue, store the address of the IO Context in our
    // DriverContext field of the Irp.   We do this so that if the Irp is canceled while
    // in our queue, we have enough information to do the correct cleanup.
    //
    Irp->Tail.Overlay.DriverContext[0] = pFx2Context;

    //
    // Mark the IRP as being in-progress before queueing it,
    //  because we're going to be returning STATUS_PENDING 
    //  from this entry point
    //
    IoMarkIrpPending(Irp);

    //
    // Queue the using the appropriate cancel safe queue routin
    //
#ifdef W2K3
    
    //
    // IoCsqInsertIrpEx returns whatever we return from OsrCsqInsertIoIrpEx, 
    //  which for us is STATUS_SUCCESS.
    //
    status = IoCsqInsertIrpEx(&devExt->CancelSafeIoQueue,Irp,NULL,devExt);
    ASSERT(status == STATUS_SUCCESS);

#else // W2K3
    IoCsqInsertIrp(&devExt->CancelSafeIoQueue,Irp,NULL);
#endif // W2K3


    //
    // We have queued this IRP onto our internal queue. 
    //  Now call our helper routine ProcessNextIrpInQueue
    //  to pass this request (or possibly another request
    //  that was running parallel and beat us to the queue)
    //  to the host controller. 
    //
    // ProcessNextIrpInQueue will pass the request on to the
    //  host if we are in an applicable PnP state otherwise the
    //  request will just stay in the queue.
    //
    ProcessNextIrpInQueue(devExt);    

    return STATUS_PENDING;

UsbFx2LkRead_Exit:

    //
    // If we're here then we are failing the request.
    //  Decrement our outstanding I/O count
    //
    ASSERT(!NT_SUCCESS(status));

    OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);

    Irp->IoStatus.Status      = status;
    Irp->IoStatus.Information = 0;

    IoCompleteRequest (Irp, IO_NO_INCREMENT);

    return status;
}

///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkReadCompletionRoutine
//
//  This routine is called by the IO Manager when a USB Read Completes
//
//
//  INPUTS:
//
//      DeviceObject  -  One of our Device Objects.
//      Irp  -  The Irp to process.
//      Context - 
//
//  OUTPUTS:
//
//      None
//
//  RETURNS:
//
//      None
//
//  IRQL:
//
//      IRQL <= DISPATCH_LEVEL
//
//  CONTEXT:
//
//      User Context
//
//  NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkReadCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)
{
    NTSTATUS             status = Irp->IoStatus.Status;
    PUSBFX2LK_IO_CONTEXT pFx2Context = (PUSBFX2LK_IO_CONTEXT) Context;
    ULONG                stageLength = 0;

    UNREFERENCED_PARAMETER(DeviceObject);

    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkReadCompletionRoutine:  Entered.\n"));

    //
    // There's no reason why this pointer
    //  shouldn't be valid
    //
    ASSERT(pFx2Context);

    //
    // successfully performed a stageLength of transfer.
    // check if we need to recirculate the irp.
    //
    if(NT_SUCCESS(status)) {

        //
        // The transfer completed successfully, see if we need to continue transfering.
        //

        //
        // Calculate how much data has been recently received.
        //
        pFx2Context->Numxfer += pFx2Context->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
        
        //
        // Determine if there is more to transfer.
        //
        if(pFx2Context->RemainingLength) {

            //
            // Set up the next stage of the transfer.
            //
            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,
                    ("UsbFx2LkReadCompletionRoutine: Another stage transfer %d of %d\n",
                        pFx2Context->Numxfer,pFx2Context->TotalLength));

            //
            // Compare the remaining length to our maximum stage size.
            //  If it is larger, then this transfer will require at 
            //  least two more sub-transfers
            //
            if(pFx2Context->RemainingLength > pFx2Context->MaxmimumStageSize) {

                stageLength = pFx2Context->MaxmimumStageSize;

            } else {

                stageLength = pFx2Context->RemainingLength;

            }

            // 
            // Prepare the partial MDL to be reused for the next part of the transfer.
            // This function unmaps any pages that may have been previously mapped
            // by this MDL before reusing it.
            //
            MmPrepareMdlForReuse(pFx2Context->Mdl);

            //
            // Setup the partial MDL again, but this time we 
            //  use the updated VirtualAddress pointer from the 
            //  original MDL. This is the cookie that the memory
            //  manager uses to figure out which portion of the 
            //  MDL needs to be mapped into the partial MDL.
            //
            IoBuildPartialMdl(Irp->MdlAddress,
                              pFx2Context->Mdl,
                              (PVOID)pFx2Context->VirtualAddress,
                              stageLength);
            
            //
            // reinitialize the urb
            //
            pFx2Context->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;

            //
            // And update the VirtualAddress and remaining transfer length in the 
            //  FX2 I/O context.
            //
            pFx2Context->VirtualAddress += stageLength;
            pFx2Context->RemainingLength -= stageLength;

            //
            // We cannot simply resubmit the IRP here with IoCallDriver for two
            //  reasons:
            //
            //  1) We may be running at IRQL == DISPATCH_LEVEL and the USB stack
            //     is not explicitly documented to be called at its dispatch 
            //     entry points at IRQL DISPATCH_LEVEL
            //
            //  2) If the request is completed in the lower driver's dispatch entry
            //     point, we will be called back here at our completion routine 
            //     recursively. If we then submit the IRP back down inline, we 
            //     can continue doing this recursion until we finally run out 
            //     stack space
            //
            // For those two reasons, we will queue a work item (guaranteeing an 
            //  IRQL of PASSIVE_LEVEL and a fresh stack) and resubmit the IRP 
            //  from the work item.
            //
            IoQueueWorkItem(pFx2Context->PWorkItem,IssueUsbReadRequest,CriticalWorkQueue,pFx2Context);

            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkReadCompletionRoutine:  Next Stage.\n"));

            //
            // We are going to be resubmitting this IRP to the host in our 
            //  work item, so we need to indicate to the I/O manager
            //  that we are still processing the IRP by returning the
            //  special STATUS_MORE_PROCESSING_REQUIRED status
            //
            return STATUS_MORE_PROCESSING_REQUIRED;

        } else {

            //
            // this is the last transfer
            //

            //
            // Update Statistics
            //
            pFx2Context->DevExt->WmiStatistics.TotalBulkBytesRead += pFx2Context->Numxfer;
            pFx2Context->DevExt->WmiStatistics.TotalBulkReadIrpCount++;

            //
            // Indicate the number of bytes transfered.
            //
            Irp->IoStatus.Information = pFx2Context->Numxfer;

            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,
                          ("UsbFx2LkReadCompletionRoutine:  Receive Complete.\n"));
        }

    } else {
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
            ("UsbFx2LkReadCompletionRoutine: failed status = %08.8x %s\n", status,OsrNtStatusToString(status)));
    }
    
    //
    // dump Fx2Context
    //
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
        ("UsbFx2LkReadCompletionRoutine: pFx2Context->Urb             = %p\n", 
            pFx2Context->Urb));
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
        ("UsbFx2LkReadCompletionRoutine: pFx2Context->Mdl             = %p\n", 
            pFx2Context->Mdl));
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
        ("UsbFx2LkReadCompletionRoutine: pFx2Context->RemainingLength = %d\n", 
            pFx2Context->RemainingLength));
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
        ("UsbFx2LkReadCompletionRoutine: pFx2Context->Numxfer         = %d\n", 
            pFx2Context->Numxfer));
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
        ("UsbFx2LkReadCompletionRoutine: pFx2Context->VirtualAddress  = %p\n", 
            pFx2Context->VirtualAddress));
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE,
        ("UsbFx2LkReadCompletionRoutine: pFx2Context->DevExt          = %p\n", 
            pFx2Context->DevExt));

    //
    // Decrement the outstanding IO count
    //
    OsrDecrementOutstandingIoCount(pFx2Context->DevExt,__FILE__,__LINE__);

    //
    // Clean up all of the resources used for this transfer
    //
    IoFreeWorkItem(pFx2Context->PWorkItem);
    ExFreePool(pFx2Context->Urb);
    IoFreeMdl(pFx2Context->Mdl);
    ExFreePool(pFx2Context);

    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkReadCompletionRoutine:  Exit.\n"));

    return STATUS_SUCCESS;
}

///////////////////////////////////////////////////////////////////////////////
//
// IssueUsbReadRequest
//
//  This routine is called in response to our UsbFx2LkReadCompletionRoutine
//  queuing the Work Item to do the next stage of the Read request.
//
//
//  INPUTS:
//
//      DeviceObject  -  One of our Device Objects.
//      Context - our pFx2Context
//
//  OUTPUTS:
//
//      None
//
//  RETURNS:
//
//      None
//
//  IRQL:
//
//      IRQL == PASSIVE_LEVEL
//
//  CONTEXT:
//
//      System Context
//
//  NOTES:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -