驱动开发之五 --- TDI之十 【译文】

驱动开发之五 --- TDI之十 【译文】

/**********************************************************************

*

* HandleIrp_RemoveNextIrp

*

*    This function removes the next valid IRP.

*

**********************************************************************/

PIRP HandleIrp_RemoveNextIrp(PIRPLISTHEAD pIrpListHead)

{

    PIRP pIrp = NULL;

    KIRQL kOldIrql;

    PDRIVER_CANCEL pCancelRoutine;

    PIRPLIST pIrpListCurrent;

    KeAcquireSpinLock(&pIrpListHead->kspIrpListLock, &kOldIrql);

    

    pIrpListCurrent = pIrpListHead->pListFront;

    while(pIrpListCurrent && pIrp == NULL)

    {

        /*

         * To remove an IRP from the Queue we first want to

       * reset the cancel routine.

         */

        pCancelRoutine = IoSetCancelRoutine(pIrpListCurrent->pIrp, NULL);

        /*

         * The next phase is to determine if this IRP has been canceled

         */

        if(pIrpListCurrent->pIrp->Cancel)

        {

            /*

             * We have been canceled so we need to determine if our

             * cancel routine has already been called. pCancelRoutine

             * will be NULL if our cancel routine has been called.  

             * If will not be NULL if our cancel routine has not been

             * called. However, we don't care in either case and we

             * will simply complete the IRP here since we have to implement at

             * least that case anyway.

             *

             * Remove the IRP from the list.

             */

            pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;

            if(pIrpListHead->pListFront == NULL)

            {

                pIrpListHead->pListBack = NULL;

            }

            KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);

            

            pIrpListCurrent->pfnCleanUpIrp(pIrpListCurrent->pIrp,

                                            pIrpListCurrent->pContext);

            DbgPrint("HandleIrp_RemoveNextIrp Complete Free Memory =

                                               0x%0x \r\n", pIrpListCurrent);

            KMem_FreeNonPagedMemory(pIrpListCurrent);

            pIrpListCurrent = NULL;

            KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,

                                                    &kOldIrql);

            

            pIrpListCurrent = pIrpListHead->pListFront;

        }

        else

        {

            pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;

            if(pIrpListHead->pListFront == NULL)

            {

                pIrpListHead->pListBack = NULL;

            }

            pIrp = pIrpListCurrent->pIrp;

            KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);

            DbgPrint("HandleIrp_RemoveNextIrp Complete Free Memory = 0x%0x \r\n",

                                                          pIrpListCurrent);

            KMem_FreeNonPagedMemory(pIrpListCurrent);

            pIrpListCurrent = NULL;

            KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,

                                                      &kOldIrql);

            

        }

    }

    KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);

    return pIrp;

}


/**********************************************************************

*

* HandleIrp_PerformCancel

*

*    This function removes the specified IRP from the list.

*

**********************************************************************/

NTSTATUS HandleIrp_PerformCancel(PIRPLISTHEAD pIrpListHead, PIRP pIrp)

{

    NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;

    KIRQL kOldIrql;

    PIRPLIST pIrpListCurrent, pIrpListPrevious;

    KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,

                                             &kOldIrql);

    

    pIrpListPrevious = NULL;

    pIrpListCurrent = pIrpListHead->pListFront;

    while(pIrpListCurrent && NtStatus == STATUS_UNSUCCESSFUL)

    {

        if(pIrpListCurrent->pIrp == pIrp)

        {

            if(pIrpListPrevious)

            {

               pIrpListPrevious->pNextIrp = pIrpListCurrent->pNextIrp;

            }

            if(pIrpListHead->pListFront == pIrpListCurrent)

            {

               pIrpListHead->pListFront = pIrpListCurrent->pNextIrp;

            }

            if(pIrpListHead->pListBack == pIrpListCurrent)

            {

                pIrpListHead->pListBack = pIrpListPrevious;

            }

            KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);

            

            NtStatus = STATUS_SUCCESS;

            /*

             * We are going to allow the clean up function to complete the IRP.

             */

            pIrpListCurrent->pfnCleanUpIrp(pIrpListCurrent->pIrp,

                                              pIrpListCurrent->pContext);

            DbgPrint("HandleIrp_PerformCancel Complete Free Memory = 0x%0x \r\n",

                                                              pIrpListCurrent);

            KMem_FreeNonPagedMemory(pIrpListCurrent);

            pIrpListCurrent = NULL;

            KeAcquireSpinLock(&pIrpListHead->kspIrpListLock,

                                                     &kOldIrql);

       }

        else

        {

            pIrpListPrevious = pIrpListCurrent;

            pIrpListCurrent = pIrpListCurrent->pNextIrp;

        }

    }

    KeReleaseSpinLock(&pIrpListHead->kspIrpListLock, kOldIrql);

    return NtStatus;

}

/**********************************************************************

*

* TdiExample_CancelRoutine

*

*    This function is called if the IRP is ever canceled

*

*    CancelIo() from user mode, IoCancelIrp() from the Kernel

*

**********************************************************************/

VOID TdiExample_CancelRoutine(PDEVICE_OBJECT DeviceObject, PIRP pIrp)

{

    PIRPLISTHEAD pIrpListHead = NULL;

    /*

     * We must release the cancel spin lock

     */

    IoReleaseCancelSpinLock(pIrp->CancelIrql);

    

    DbgPrint("TdiExample_CancelRoutine Called IRP = 0x%0x \r\n", pIrp);

    /*

     * We stored the IRPLISTHEAD context in our DriverContext on the IRP

     * before adding it to the queue so it should not be NULL here.

     */

    pIrpListHead = (PIRPLISTHEAD)pIrp->Tail.Overlay.DriverContext[0];

    pIrp->Tail.Overlay.DriverContext[0] = NULL;

    

    /*

     * We can then just throw the IRP to the PerformCancel

     * routine since it will find it in the queue, remove it and

     * then call our clean up routine. Our clean up routine

     * will then complete the IRP. If this does not occur then

     * our completion of the IRP will occur in another context

     * since it is not in the list.

     */

    HandleIrp_PerformCancel(pIrpListHead, pIrp);

}

/**********************************************************************

*

* TdiExample_IrpCleanUp

*

*    This function is called to clean up the IRP if it is ever

*    canceled after we have given it to the queueing routines.

*

**********************************************************************/

VOID TdiExample_IrpCleanUp(PIRP pIrp, PVOID pContext)

{

    pIrp->IoStatus.Status      = STATUS_CANCELLED;

    pIrp->IoStatus.Information = 0;

    pIrp->Tail.Overlay.DriverContext[0] = NULL;

    DbgPrint("TdiExample_IrpCleanUp Called IRP = 0x%0x \r\n", pIrp);

    IoCompleteRequest(pIrp, IO_NO_INCREMENT);

}

你可能感兴趣的:(驱动开发学习)