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

📄 nic_recv.c

📁 plx9054的WDM驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
    pHwRfd->RfdCbHeader.CbStatus = 0;
    pHwRfd->RfdActualCount = 0;
    pHwRfd->RfdCbHeader.CbCommand = (RFD_EL_BIT);
    pHwRfd->RfdCbHeader.CbLinkPointer = DRIVER_NULL;

    // Append this RFD to the RFD chain
    if (!IsListEmpty(&FdoData->RecvList))
    {
        pLastMpRfd = (PMP_RFD)GetListTailEntry(&FdoData->RecvList);

        // Link it onto the end of the chain dynamically
        pHwRfd = pLastMpRfd->HwRfd;
        pHwRfd->RfdCbHeader.CbLinkPointer = pMpRfd->HwRfdPhys;
        pHwRfd->RfdCbHeader.CbCommand = 0;
    }

    //
    // HW_SPECIFIC_END
    //

    //
    // The processing on this RFD is done, so put it back on the tail of
    // our list
    //
    InsertTailList(&FdoData->RecvList, (PLIST_ENTRY)pMpRfd);
    FdoData->nReadyRecv++;
    ASSERT(FdoData->nReadyRecv <= FdoData->CurrNumRfd);
}

NTSTATUS 
NICStartRecv(
    IN  PFDO_DATA  FdoData
    )
/*++
Routine Description:

    Start the receive unit if it's not in a ready state                    
    Assumption: Rcv spinlock has been acquired 

Arguments:

    FdoData     Pointer to our FdoData

Return Value:

    NT Status code
    
--*/
{
    PMP_RFD         pMpRfd;
    NTSTATUS        status;

    DebugPrint(TRACE, DBG_READ, "---> NICStartRecv\n");

    //
    // If the receiver is ready, then don't try to restart.
    //
    if (NIC_IS_RECV_READY(FdoData))
    {
        DebugPrint(LOUD, DBG_READ, "Receive unit already active\n");
        return STATUS_SUCCESS;
    }

    DebugPrint(LOUD, DBG_READ, "Re-start receive unit...\n");
    ASSERT(!IsListEmpty(&FdoData->RecvList));
    
    //
    // Get the MP_RFD head
    //
    pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);

    //
    // If more packets are received, clean up RFD chain again
    //
    if (NIC_RFD_GET_STATUS(pMpRfd->HwRfd))
    {
        NICHandleRecvInterrupt(FdoData);
        ASSERT(!IsListEmpty(&FdoData->RecvList));

        //
        // Get the new MP_RFD head
        //
        pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
    }

    //
    // Wait for the SCB to clear before we set the general pointer
    //
    if (!WaitScb(FdoData))
    {
        status = STATUS_DEVICE_DATA_ERROR;
        goto exit;
    }

    if (FdoData->DevicePowerState > PowerDeviceD0)
    {
        status = STATUS_DEVICE_DATA_ERROR;
        goto exit;
    }
    //
    // Set the SCB General Pointer to point the current Rfd
    //
    FdoData->CSRAddress->ScbGeneralPointer = pMpRfd->HwRfdPhys;

    //
    // Issue the SCB RU start command
    //
    status = D100IssueScbCommand(FdoData, SCB_RUC_START, FALSE);
    if (status == STATUS_SUCCESS)
    {
        // wait for the command to be accepted
        if (!WaitScb(FdoData))
        {
            status = STATUS_DEVICE_DATA_ERROR;
        }
    }        
    
    exit:

    DebugPrint(TRACE, DBG_READ, "<--- NICStartRecv, Status=%x\n", status);
    return status;
}



VOID 
NICResetRecv(
    IN  PFDO_DATA   FdoData
    )
/*++
Routine Description:

    Reset the receive list                    
    Assumption: Rcv spinlock has been acquired 
    
Arguments:

    FdoData     Pointer to our FdoData

Return Value:

     None

--*/
{
    PMP_RFD   pMpRfd;      
    PHW_RFD   pHwRfd;    
    LONG      RfdCount;

    DebugPrint(TRACE, DBG_READ, "--> NICResetRecv\n");

    ASSERT(!IsListEmpty(&FdoData->RecvList));
    
    //
    // Get the MP_RFD head
    //
    pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList);
    for (RfdCount = 0; RfdCount < FdoData->nReadyRecv; RfdCount++)
    {
        pHwRfd = pMpRfd->HwRfd;
        pHwRfd->RfdCbHeader.CbStatus = 0;

        pMpRfd = (PMP_RFD)GetListFLink(&pMpRfd->List);
    }

    DebugPrint(TRACE, DBG_READ, "<-- NICResetRecv\n");
}


VOID
NICServiceReadIrps(
    PFDO_DATA   FdoData,
    PMP_RFD     *PacketArray,
    ULONG       PacketArrayCount
    )
/*++
Routine Description:

    Copy the data from the recv buffers to pending read IRP buffers
    and complete the IRP. When used as network driver, copy operation
    can be avoided by devising a private interface between us and the 
    NDIS-WDM filter and have the NDIS-WDM edge to indicate our buffers
    directly to NDIS.
    
Arguments:

    FdoData     Pointer to our FdoData

Return Value:

     None

--*/
{
    PIRP                irp;
    PLIST_ENTRY         listEntry;
    PMP_RFD             pMpRfd = NULL;
    ULONG               index, length;
    NTSTATUS            status;
    PVOID               buffer;
    
    DebugPrint(TRACE, DBG_READ, "--> NICServiceReadIrps\n");
    
    //
    // We need to dequeue all the entries in the queue, reset the cancel
    // routine for each of them and then process then:
    // - if the device is active, we will send them down
    // - else we will complete them with STATUS_NO_SUCH_DEVICE 
    //

    for(index=0; index < PacketArrayCount; index++)
    {
        pMpRfd = PacketArray[index];
        ASSERT(pMpRfd);
        
        //
        // Acquire the queue lock before manipulating the list entries.
        //
        KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);

        while(TRUE){
            
            if(IsListEmpty(&FdoData->RecvQueueHead))
            {
                KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
                break;
            }

            //
            // Remove a request from the queue.
            //
            listEntry = RemoveHeadList(&FdoData->RecvQueueHead);

            irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);

            //
            // Set the cancel routine to NULL. This is an atomic operation.
            //
            if (IoSetCancelRoutine(irp, NULL))
            {
                //
                // Cancel routine cannot run now and cannot have already 
                // started to run.
                //
                KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
                //
                // Copy data from the RFD buffer to the IRP and complete
                // the IRP
                //
                buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
                if(!buffer){
                    status = STATUS_INSUFFICIENT_RESOURCES;
                    length = 0;
                } else {
                
                    length = min(MmGetMdlByteCount(irp->MdlAddress), pMpRfd->PacketSize);                    
                    RtlCopyMemory(buffer, pMpRfd->Buffer, length);
                    
                    DebugPrintEx((LOUD, DBG_READ, 
                                    "Received Packet Data: %!HEXDUMP!\n",
                                    log_xstr(buffer, (USHORT)length)));
                    
                    status = STATUS_SUCCESS;
                }

                irp->IoStatus.Status = status;
                irp->IoStatus.Information = length;
                IoCompleteRequest(irp, IO_NO_INCREMENT);
                PciDrvIoDecrement (FdoData);
                break;
            }
            else
            {
                //
                // Cancel rotuine is running. Leave the irp alone.
                //
                InitializeListHead(&irp->Tail.Overlay.ListEntry);
                irp = NULL;
                continue; 
            }
        }
        
        KeAcquireSpinLockAtDpcLevel(&FdoData->RcvLock);

        //
        // Decrement the number of outstanding Recvs
        //
        PciDrvIoDecrement (FdoData);        
        
        ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_PEND));
        MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_PEND);


        if (FdoData->RfdShrinkCount < NIC_RFD_SHRINK_THRESHOLD)
        {
            NICReturnRFD(FdoData, pMpRfd);
        }
        else
        {
            ASSERT(FdoData->CurrNumRfd > FdoData->NumRfd);
            //
            // Queue a passive level callback to free RFD memory.
            // Increment the IO count to accout for the pending workitem. This
            // will prevent us from freeing resources during stop/remove until
            // the workitem callback is executed.
            //
            PciDrvIoIncrement (FdoData);              
            status = PciDrvQueuePassiveLevelCallback(FdoData, 
                                    NICFreeRfdWorkItem, (PVOID)pMpRfd, 
                                    NULL);
            if(NT_SUCCESS(status)){
                
                FdoData->RfdShrinkCount = 0;
                FdoData->CurrNumRfd--;            
                DebugPrint(TRACE, DBG_READ, "Shrink... CurrNumRfd = %d\n", 
                                                    FdoData->CurrNumRfd);
            } else {
                PciDrvIoDecrement (FdoData); // Free the reference                 
                //
                // We couldn't queue a workitem to free memory, so let us
                // put that back in the main pool and try again next time.
                //
                NICReturnRFD(FdoData, pMpRfd);
            }
        }
        
        KeReleaseSpinLockFromDpcLevel(&FdoData->RcvLock);
            
    }// end of loop

    DebugPrint(TRACE, DBG_READ, "<-- NICServiceReadIrps\n");

    return;

}

⌨️ 快捷键说明

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