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

📄 isorwr.c

📁 WINDDK开发代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    the cancel routine will free all the resources.
    we do free the urb and mdl.

    it is expected of the cancellation routine to free 
    all the irps, free the subcontext and the context 
    and complete the main irp

    Case 3 is executed in Block 1b.

    Case 4:
    when we complete the last of the subsidiary irp,
    we check if the cancel routine for the main Irp
    has run. If yes, we atomically decrement the 
    rwContext->Lock field. (the completion routine
    is in race with Cancel routine). If the count is 0,
    we free the irp, subcontext and the context and
    complete the main irp. we also free the urb and
    the mdl for this particular stage.

    the reason we do not free the subsidiary irp at its
    completion is because the cancellation routine can
    run any time.

    Case 4 is executed in Block 1a.
    

Arguments:

    DeviceObject - pointer to device object
    Irp - I/O request packet
    Context - context for the completion routine

Return Value:

    NT status value

--*/
{
    PURB               urb;
    PMDL               mdl;
    PIRP               mainIrp;
    KIRQL              oldIrql;
    ULONG              info;
    NTSTATUS           ntStatus;
    PDEVICE_EXTENSION  deviceExtension;
    PISOUSB_RW_CONTEXT rwContext;
    PIO_STACK_LOCATION irpStack;

    irpStack = IoGetCurrentIrpStackLocation(Irp);
    urb = (PURB) irpStack->Parameters.Others.Argument1;
    mdl = (PMDL) irpStack->Parameters.Others.Argument2;
    info = 0;
    ntStatus = Irp->IoStatus.Status;
    rwContext = (PISOUSB_RW_CONTEXT) Context;
    deviceExtension = rwContext->DeviceExtension;

    IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - begins\n"));

    ASSERT(rwContext);
    
    KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);

    if(NT_SUCCESS(ntStatus) &&
       USBD_SUCCESS(urb->UrbHeader.Status)) {

        rwContext->NumXfer += 
                urb->UrbIsochronousTransfer.TransferBufferLength;

        IsoUsb_DbgPrint(1, ("rwContext->NumXfer = %d\n", rwContext->NumXfer));
    }
    else {
        
        ULONG i;

        IsoUsb_DbgPrint(1, ("read-write irp failed with status %X\n", ntStatus));
        IsoUsb_DbgPrint(1, ("urb header status %X\n", urb->UrbHeader.Status));

        for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {

            IsoUsb_DbgPrint(2, ("IsoPacket[%d].Length = %X IsoPacket[%d].Status = %X\n",
                                i,
                                urb->UrbIsochronousTransfer.IsoPacket[i].Length,
                                i,
                                urb->UrbIsochronousTransfer.IsoPacket[i].Status));
        }
    }

    if(InterlockedDecrement(&rwContext->IrpsPending) == 0) {

        IsoUsb_DbgPrint(3, ("no more irps pending\n"));

        if(NT_SUCCESS(ntStatus)) {
            
            ULONG i;
        
            IsoUsb_DbgPrint(1, ("urb start frame %X\n", 
                                urb->UrbIsochronousTransfer.StartFrame));

            for(i = 0; i < urb->UrbIsochronousTransfer.NumberOfPackets; i++) {

                if(urb->UrbIsochronousTransfer.IsoPacket[i].Length == 0) {

                    IsoUsb_DbgPrint(2, ("IsoPacket[%d].Status = %X\n",
                                        i,
                                        urb->UrbIsochronousTransfer.IsoPacket[i].Status));
                }
            }
        }

        mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);

        ASSERT(mainIrp);

        if(IoSetCancelRoutine(mainIrp, NULL) == NULL) {
            
            //
            // cancel routine has begun the race
            //
            // Block 1a.
            //
            IsoUsb_DbgPrint(3, ("cancel routine has begun the race\n"));

            if(InterlockedDecrement(&rwContext->Lock) == 0) {

                ULONG i;

                //
                // do the cleanup job ourselves
                //
                IsoUsb_DbgPrint(3, ("losers do the cleanup\n"));

                for(i = 0; i < rwContext->NumIrps; i++) {

                    IoFreeIrp(rwContext->SubContext[i].SubIrp);
                    rwContext->SubContext[i].SubIrp = NULL;
                }

                info = rwContext->NumXfer;

                KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);

                ExFreePool(rwContext->SubContext);
                ExFreePool(rwContext);

                //
                // if we transferred some data, main Irp completes with success
                //

                IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));

                IsoUsb_DbgPrint(1, ("***\n"));
                
                mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
                mainIrp->IoStatus.Information = info;
        
                IoCompleteRequest(mainIrp, IO_NO_INCREMENT);

                IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
                IsoUsb_IoDecrement(deviceExtension);

                IsoUsb_DbgPrint(3, ("-------------------------------\n"));

                goto IsoUsb_SinglePairComplete_Exit;
            }
            else {

                //
                // Block 1b.
                //

                IsoUsb_DbgPrint(3, ("cancel routine performs the cleanup\n"));
            }
        }
        else {

            //
            // Block 2.
            //

            ULONG i;

            IsoUsb_DbgPrint(3, ("cancel routine has NOT run\n"));

            for(i = 0; i < rwContext->NumIrps; i++) {

                IoFreeIrp(rwContext->SubContext[i].SubIrp);
                rwContext->SubContext[i].SubIrp = NULL;
            }

            info = rwContext->NumXfer;

            KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);

            ExFreePool(rwContext->SubContext);
            ExFreePool(rwContext);

            //
            // if we transferred some data, main Irp completes with success
            //
            IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));

            IsoUsb_DbgPrint(1, ("***\n"));
            
            mainIrp->IoStatus.Status = STATUS_SUCCESS; // ntStatus;
            mainIrp->IoStatus.Information = info;
        
            IoCompleteRequest(mainIrp, IO_NO_INCREMENT);

            IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
            IsoUsb_IoDecrement(deviceExtension);

            IsoUsb_DbgPrint(3, ("-------------------------------\n"));

            goto IsoUsb_SinglePairComplete_Exit;
        }
    }

    KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);

IsoUsb_SinglePairComplete_Exit:

    //
    // Block 3.
    //

    ExFreePool(urb);
    IoFreeMdl(mdl);

    IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete::"));
    IsoUsb_IoDecrement(deviceExtension);

    IsoUsb_DbgPrint(3, ("IsoUsb_SinglePairComplete - ends\n"));

    return STATUS_MORE_PROCESSING_REQUIRED;
}

VOID
IsoUsb_CancelReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
/*++
 
Routine Description:

    This is the cancellation routine for the main read/write Irp.
    The policy is as follows:

    If the cancellation routine is the last to decrement
    rwContext->Lock, then free the irps, subcontext and
    the context. Complete the main irp
    
    Otherwise, call IoCancelIrp on each of the subsidiary irp.
    It is valid to call IoCancelIrp on irps for which the 
    completion routine has executed, because, we do not free the
    irps in the completion routine.

Arguments:

    DeviceObject - pointer to device object
    Irp - I/O request packet

Return Value:

    None

--*/
{
    PIRP               mainIrp;
    KIRQL              oldIrql;
    ULONG              i;
    ULONG              info;
    PDEVICE_EXTENSION  deviceExtension;
    PISOUSB_RW_CONTEXT rwContext;

    //
    // initialize vars
    //
    info = 0;

    IoReleaseCancelSpinLock(Irp->CancelIrql);

    IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - begins\n"));

    rwContext = (PISOUSB_RW_CONTEXT) Irp->Tail.Overlay.DriverContext[0];
    ASSERT(rwContext);
    deviceExtension = rwContext->DeviceExtension;

    KeAcquireSpinLock(&rwContext->SpinLock, &oldIrql);

    if(InterlockedDecrement(&rwContext->Lock)) {

        IsoUsb_DbgPrint(3, ("about to cancel sub context irps..\n"));

        for(i = 0; i < rwContext->NumIrps; i++) {

            if(rwContext->SubContext[i].SubIrp) {

                IoCancelIrp(rwContext->SubContext[i].SubIrp);
            }
        }

        KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);

        IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite - ends\n"));

        return;
    }
    else {

        ULONG i;

        for(i = 0; i < rwContext->NumIrps; i++) {

            IoFreeIrp(rwContext->SubContext[i].SubIrp);
            rwContext->SubContext[i].SubIrp = NULL;
        }

        mainIrp = (PIRP) InterlockedExchangePointer(&rwContext->RWIrp, NULL);

        info = rwContext->NumXfer;

        KeReleaseSpinLock(&rwContext->SpinLock, oldIrql);

        ExFreePool(rwContext->SubContext);
        ExFreePool(rwContext);

        //
        // if we transferred some data, main Irp completes with success
        //

        IsoUsb_DbgPrint(1, ("Total data transferred = %X\n", info));

        IsoUsb_DbgPrint(1, ("***\n"));

        Irp->IoStatus.Status = STATUS_SUCCESS;
        Irp->IoStatus.Status = info;
/*        
        Irp->IoStatus.Status = STATUS_CANCELLED;
        Irp->IoStatus.Information = 0;
*/
        IoCompleteRequest(Irp, IO_NO_INCREMENT);

        IsoUsb_DbgPrint(3, ("IsoUsb_CancelReadWrite::"));
        IsoUsb_IoDecrement(deviceExtension);

        IsoUsb_DbgPrint(3, ("-------------------------------\n"));

        return;
    }
}

ULONG
IsoUsb_GetCurrentFrame(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp
    )
/*++
 
Routine Description:

    This routine send an irp/urb pair with
    function code URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
    to fetch the current frame

Arguments:

    DeviceObject - pointer to device object
    PIRP - I/O request packet

Return Value:

    Current frame

--*/
{
    KEVENT                               event;
    PDEVICE_EXTENSION                    deviceExtension;
    PIO_STACK_LOCATION                   nextStack;
    struct _URB_GET_CURRENT_FRAME_NUMBER urb;

    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

    //
    // initialize the urb
    //

    IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - begins\n"));

    urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
    urb.Hdr.Length = sizeof(urb);
    urb.FrameNumber = (ULONG) -1;

    nextStack = IoGetNextIrpStackLocation(Irp);
    nextStack->Parameters.Others.Argument1 = (PVOID) &urb;
    nextStack->Parameters.DeviceIoControl.IoControlCode = 
                                IOCTL_INTERNAL_USB_SUBMIT_URB;
    nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;

    KeInitializeEvent(&event,
                      NotificationEvent,
                      FALSE);

    IoSetCompletionRoutine(Irp,
                           IsoUsb_StopCompletion,
                           &event,
                           TRUE,
                           TRUE,
                           TRUE);

    IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
    IsoUsb_IoIncrement(deviceExtension);

    IoCallDriver(deviceExtension->TopOfStackDeviceObject,
                 Irp);

    KeWaitForSingleObject((PVOID) &event,
                          Executive,
                          KernelMode,
                          FALSE,
                          NULL);

    IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame::"));
    IsoUsb_IoDecrement(deviceExtension);

    IsoUsb_DbgPrint(3, ("IsoUsb_GetCurrentFrame - ends\n"));

    return urb.FrameNumber;
}

NTSTATUS
IsoUsb_StopCompletion(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP           Irp,
    IN PVOID          Context
    )
/*++
 
Routine Description:

    This is the completion routine for request to retrieve the frame number

Arguments:

    DeviceObject - pointer to device object
    Irp - I/O request packet
    Context - context passed to the completion routine

Return Value:

    NT status value

--*/
{
    PKEVENT event;

    IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - begins\n"));

    event = (PKEVENT) Context;

    KeSetEvent(event, IO_NO_INCREMENT, FALSE);

    IsoUsb_DbgPrint(3, ("IsoUsb_StopCompletion - ends\n"));

    return STATUS_MORE_PROCESSING_REQUIRED;
}

⌨️ 快捷键说明

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