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

📄 usbfx2lk_io.cpp

📁 基于vc++6.0环境的cypress USB 驱动源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
//
///////////////////////////////////////////////////////////////////////////////
VOID IssueUsbReadRequest(IN PDEVICE_OBJECT DeviceObject,IN PVOID Context)
{
    PUSBFX2LK_IO_CONTEXT pFx2Context = (PUSBFX2LK_IO_CONTEXT) Context;
    PIO_STACK_LOCATION   nextStack;

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

    //
    // Prepare the next stack location so that we can resubmit the irp
    //  to do the next part of the transfer. Note that this step is 
    //  required because the I/O manager zeroes the lower stack
    //  locations as part of completion processing.
    //
    nextStack = IoGetNextIrpStackLocation(pFx2Context->Irp);
    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
    nextStack->Parameters.Others.Argument1 = pFx2Context->Urb;
    nextStack->Parameters.DeviceIoControl.IoControlCode = 
                                IOCTL_INTERNAL_USB_SUBMIT_URB;

    //
    // Set our completion routine to be called when this stage of
    //  the read completes.
    //
    IoSetCompletionRoutine(pFx2Context->Irp,
                            UsbFx2LkReadCompletionRoutine,
                            pFx2Context,
                            TRUE,
                            TRUE,
                            TRUE);

    //
    // Send the request to the USB Driver.
    //
    IoCallDriver(pFx2Context->DevExt->DeviceToSendIrpsTo, 
                    pFx2Context->Irp);

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


///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkWrite
//
//  This routine is called by the IO Manager to process a IRP_MJ_WRITE
//  Irp.
//
//
//  INPUTS:
//
//      DeviceObject  -  One of our Device Objects.
//      Irp  -  The Irp to process.
//
//  OUTPUTS:
//
//      None
//
//  RETURNS:
//
//      STATUS_PENDING, or an ERROR.  
//
//  IRQL:
//
//      IRQL == PASSIVE_LEVEL
//
//  CONTEXT:
//
//      User Context
//
//  NOTES:
//
//      WRITE requests are always serviced by the bulk out pipe
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkWrite(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
    PUSBFX2LK_EXT           devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
    PIO_STACK_LOCATION      ioStack = IoGetCurrentIrpStackLocation(Irp);
    KIRQL                   oldIrql;
    PUSBFX2LK_IO_CONTEXT    pFx2Context = NULL;
    NTSTATUS                status;
    PMDL                    pMdl = NULL;
    ULONG                   totalLength = 0;
    ULONG                   urbFlags = 0;
    PUCHAR                  virtualAddress = 0;
    ULONG                   stageLength = 0;
    PURB                    urb = NULL;
    PIO_STACK_LOCATION      nextStack = IoGetNextIrpStackLocation(Irp);

    //
    // We should never be here and not at PASSIVE_LEVEL
    //
    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);

    //
    // Major issue is we haven't setup our bulk output pipe yet
    //
    ASSERT(devExt->BulkOutPipe);

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

    //
    // Increment the number of outstanding IOs queued to the device.
    //
    OsrIncrementOutstandingIoCount(devExt,__FILE__,__LINE__);

    //
    // See what sort of state we're in. 
    //
    KeAcquireSpinLock(&devExt->IoStateLock,&oldIrql);
    if (devExt->DevicePnPState < STATE_ALL_BELOW_FAIL) {
        KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);

        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE, 
                ("UsbFx2LkWrite: Failing  request due to Pnp State! Current PnP state - %s\n",
                  OsrPrintState(devExt)));

        status = STATUS_INVALID_DEVICE_STATE;
        goto UsbFx2LkWrite_Exit;
    }
    KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);
            
    //
    //
    // We do not support zero length operations in this driver
    //
    if(!ioStack->Parameters.Write.Length || !Irp->MdlAddress) {

        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE, 
                ("UsbFx2LkWrite: Invalid Parameters to Write \n"));

        status = STATUS_INVALID_PARAMETER;
        goto UsbFx2LkWrite_Exit;
    }


    //
    // Get the total length of the transfer we are asked to perform.
    //
    totalLength = ioStack->Parameters.Write.Length;

    //
    // See if the transfer length is greater than the maximum packet
    //  size of the pipe * the amount of buffering that the firmware
    //  provides. If the transfer is too large, we will reject it here
    //  without further processing
    //
    if(totalLength > 
            (ULONG)(devExt->BulkOutPipe->PipeInformation.MaximumPacketSize * \
                                         USBFX2LK_BULK_TRANSFER_FW_BUFFERING)) {

        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
           ("UsbFx2LkWrite: Length exceeds %d\n",
             devExt->BulkOutPipe->PipeInformation.MaximumPacketSize * USBFX2LK_BULK_TRANSFER_FW_BUFFERING));
        status = STATUS_INVALID_PARAMETER;
        goto UsbFx2LkWrite_Exit;
    }

    //
    // Allocate a USBFX2 I/O context. This is a driver specific
    //  structure that we'll use to contain all the necessary
    //  information about this particular request while we
    //  own that request
    //
    pFx2Context = (PUSBFX2LK_IO_CONTEXT) ExAllocatePoolWithTag(NonPagedPool,sizeof(USBFX2LK_IO_CONTEXT),'ciuO');

    if(pFx2Context == NULL) {
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkWrite: Failed to allocate IO Context\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        goto UsbFx2LkWrite_Exit;
    }

    //
    // Get the user's base virtual address from the MDL. This
    //  will be used as a cookie to indicate what area of the 
    //  user's data buffer we are currently copying data into
    //
    virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);

    //
    // the transfer request is for totalLength. We can perform a maximum of
    // the BulkOut pipe's PipeInformation.MaximumPacketSize in each stage.
    //
    pFx2Context->MaxmimumStageSize = devExt->BulkInPipe->PipeInformation.MaximumPacketSize;

    if(totalLength > pFx2Context->MaxmimumStageSize) {
        //
        // Total length is bigger that we can send, so we will break up
        // the transfer into smaller pieces.
        //
        stageLength = pFx2Context->MaxmimumStageSize;
    } else {
        //
        // We can send this packet in one transfer.
        //
        stageLength = totalLength;
    }

    //
    // We asked the I/O manager to supply reads and writes from user
    //  mode components in the form of MDLs by setting the DO_DIRECT_IO
    //  bit in our device object during AddDevice. This will result in
    //  the I/O manager sending our driver MDLs that describe the entire
    //  length of the user's buffer for the entire operation.
    //
    // However, we may need to split this single user transfer up
    //  into multiple "stages" so that we don't send our device
    //  I/O operations that exceed the maximum supported single 
    //  transfer size. To do this, we will build what are called
    //  "partial MDLs" that describe only the portion of the user's
    //  data buffer that we will be transferring at each individual
    //  stage. 
    //
    // The first step in building partial MDLs will be allocating 
    //  a new MDL that is large enough to describe the passed in MDL.
    //  
    pMdl = IoAllocateMdl((PVOID)virtualAddress,
                         totalLength,
                         FALSE,
                         FALSE,
                         NULL);

    if(pMdl == NULL) {
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkWrite: Failed to Allocate Mdl\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        ExFreePool(pFx2Context);
        goto UsbFx2LkWrite_Exit;
    }

    //
    // Now, build a partial MDL out of the newly allocated 
    //  MDL. This will map the first stageLength bytes of
    //  the MDL in the IRP into the newly allocated MDL
    //
    IoBuildPartialMdl(Irp->MdlAddress,
                      pMdl,
                      (PVOID)virtualAddress,
                      stageLength);

    //
    // Allocate an URB to be used for the transfer.
    //
    urb = (PURB) ExAllocatePoolWithTag(NonPagedPool,sizeof(URB),'bruO');

    if(urb == NULL) {
        OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkWrite: Failed to allocate URB\n"));
        status = STATUS_INSUFFICIENT_RESOURCES;
        ExFreePool(pFx2Context);
        IoFreeMdl(pMdl);
        goto UsbFx2LkWrite_Exit;
    }

    //
    // Build the Transfer URB.
    //

    //
    // Indicate that this is a write function and that we will allow short
    // transfers of data.
    //
    urbFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_OUT;

    UsbBuildInterruptOrBulkTransferRequest(
                            urb,
                            sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
                            devExt->BulkOutPipe->PipeInformation.PipeHandle,
                            NULL,
                            pMdl,
                            stageLength,
                            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,("UsbFx2LkWrite: Failed IoAllocateWorkItem\n"));
        ExFreePool(pFx2Context);
        IoFreeMdl(pMdl);
        ExFreePool(urb);
        goto UsbFx2LkWrite_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)UsbFx2LkWriteCompletionRoutine,
                           pFx2Context,
                           TRUE,
                           TRUE,
                           TRUE);

    OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE,("UsbFx2LkWrite: Queuing Write 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);    

⌨️ 快捷键说明

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