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

📄 nic_send.c

📁 ddk开发pci范例,使用9054芯片
💻 C
📖 第 1 页 / 共 2 页
字号:
/*++
    
Copyright (c) Microsoft Corporation.  All rights reserved.

    THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY      
    KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
    PURPOSE.

Module Name:
    nic_send.c

Abstract:
    This module contains routines to write packets.


Environment:

    Kernel mode


Revision History:
    DChen       11-01-99    created
    EliyasY     Feb 13, 2003 converted to WDM
    
--*/

#include "precomp.h"

#if defined(EVENT_TRACING)
#include "nic_send.tmh"
#endif


__inline VOID 
MP_FREE_SEND_PACKET(
    IN  PFDO_DATA   FdoData,
    IN  PMP_TCB     pMpTcb,
    IN  NTSTATUS    Status
    )
/*++
Routine Description:

    Recycle a MP_TCB and complete the packet if necessary
    Assumption: Send spinlock has been acquired 

Arguments:

    FdoData     Pointer to our FdoData
    pMpTcb      Pointer to MP_TCB        
    Status      Irp completion status

Return Value:

    None

--*/
{
    
    PIRP  Irp;

    ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));

    Irp = pMpTcb->Irp;
    pMpTcb->Irp = NULL;
    pMpTcb->Count = 0;

    MP_CLEAR_FLAGS(pMpTcb);

    FdoData->CurrSendHead = FdoData->CurrSendHead->Next;
    FdoData->nBusySend--;
    ASSERT(FdoData->nBusySend >= 0);

    if (Irp)
    {
        KeReleaseSpinLockFromDpcLevel(&FdoData->SendLock);
        NICCompleteSendRequest(FdoData, 
                            Irp, 
                            Status, 
                            pMpTcb->PacketLength,
                            TRUE // Yes, we are calling at DISPATCH_LEVEL
                            );
        
        KeAcquireSpinLockAtDpcLevel(&FdoData->SendLock);
    }
}



NTSTATUS 
NICWrite(
    IN  PFDO_DATA     FdoData,
    IN  PIRP          Irp
)
/*++

Routine Description:

    This routine handles the hardware specific write request.
    If the device is not ready, fail the request. Otherwise
    get scatter-gather list for the request buffer and send the
    list to the hardware for DMA.
        
Arguments:

    FdoData - Pointer to the device context.
    Irp     - Pointer to the write request.
    
Return Value:

    NT Status code.
    
--*/
{
    NTSTATUS     returnStatus, status;   
    PVOID        virtualAddress;
    ULONG        pageCount = 0, length = 0;
    PMDL         tempMdl, mdl;
    KIRQL        oldIrql;
#if defined(DMA_VER2)       
    PVOID        sgListBuffer;
#endif

    DebugPrint(TRACE, DBG_WRITE, "--> PciDrvWrite %p\n", Irp);

    Irp->Tail.Overlay.DriverContext[3] = NULL;
    Irp->Tail.Overlay.DriverContext[2] = NULL;
    returnStatus = status = STATUS_SUCCESS;
    
    //
    // Is this adapter ready for sending?
    //
    if (MP_SHOULD_FAIL_SEND(FdoData))
    {        
        DebugPrint(ERROR, DBG_WRITE, "Device not ready %p\n", Irp);  
        returnStatus = status = STATUS_DEVICE_NOT_READY;
        goto Error;
    }

    tempMdl = mdl = Irp->MdlAddress;    

    //
    // Check for zero length buffer
    //
    if (mdl == NULL || MmGetMdlByteCount(mdl) == 0)
     {
        DebugPrint(ERROR, DBG_WRITE, "Zero length buffer %p\n", Irp);  
        status = returnStatus = STATUS_INVALID_DEVICE_REQUEST;
        goto Error;
    }

    //
    // Calculate the total packet length and the number of pages
    // spanned by all the buffers by walking the MDL chain.
    // NOTE: If this driver is used in the miniport configuration, it will
    // not get chained MDLs because the upper filter (NDISEDGE.SYS)
    // coalesces the fragements to a single contiguous buffer before presenting
    // the packet to us.
    //
    while(tempMdl != NULL)                         
    {   
        virtualAddress = MmGetMdlVirtualAddress(tempMdl);           
        length += MmGetMdlByteCount(tempMdl);
        pageCount += ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, length);
        tempMdl = tempMdl->Next;
    }                                                                   
    
    if (length < NIC_MIN_PACKET_SIZE)
    {
        //
        // This will never happen in our case because the ndis-edge 
        // pads smaller size packets with zero to make it NIC_MIN_PACKET_SIZE
        // long.
        //
        DebugPrint(ERROR, DBG_WRITE, "Packet size is less than %d\n", NIC_MIN_PACKET_SIZE);     
        status = returnStatus = STATUS_INVALID_DEVICE_REQUEST;
        goto Error;
    }

    //
    // Check to see if the packet spans more than the physical pages
    // our hardware can handle or the pageCount exceeds the total number of 
    // map registers allocated. If so, we should coalesce the scattered
    // buffers to fit the limit. We can't really break the transfers and
    // DMA in small chunks because each packets has to be DMA'ed in one shot.
    // The code on how to colesce the packet for this hardware is present 
    // in the original E100BEX sample.
    //        
    if (pageCount > NIC_MAX_PHYS_BUF_COUNT ||
            pageCount > FdoData->AllocatedMapRegisters)
    {
        // TODO: Packet needs to be coalesced
        DebugPrint(ERROR, DBG_WRITE, "Packet needs to be coalesced\n");        
        status = returnStatus = STATUS_INVALID_DEVICE_REQUEST;
        goto Error;
    }    
    //
    // Build a scatter-gather list of the packet buffer and send the packet. 
    //
    // If DMA_VER2 is not defined, use GetScatterGatherList. If the driver
    // is meant to work on XP and above, define DMA_VER2, so that you can
    // use BuildScatterGatherList.
    //
    // Since Build/GetScatterGatherList should be called at DISPATCH_LEVEL
    // let us raise the IRQL.
    //
    
    KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);

    //
    // Let us mark the IRP pending, because NICProcessSGList is an asynchronous
    // callback and we wouldn't know the status of the IRP. This IRP may either
    // get completed by the DPC handler after the DMA transfer or may 
    // get queued if we are low on resources. So the safest thing
    // to do for us here is return STATUS_PENDING irrespective of what happens
    // to the IRP. 
    //
    IoMarkIrpPending(Irp);
    returnStatus = STATUS_PENDING;
    
#if defined(DMA_VER2)    

    sgListBuffer = ExAllocateFromNPagedLookasideList(
                            &FdoData->SGListLookasideList);
    if (sgListBuffer)
    {
        Irp->Tail.Overlay.DriverContext[2] =  sgListBuffer;        
        status = FdoData->DmaAdapterObject->DmaOperations->BuildScatterGatherList(
                        FdoData->DmaAdapterObject,
                        FdoData->Self,
                        mdl,
                        MmGetMdlVirtualAddress(mdl),
                        length,
                        NICProcessSGList,
                        Irp,
                        TRUE,
                        sgListBuffer,
                        FdoData->ScatterGatherListSize);
        
        if (!NT_SUCCESS(status))
        {
            DebugPrint(ERROR, DBG_WRITE, "BuildScatterGatherList %x\n", status);
            ExFreeToNPagedLookasideList(&FdoData->SGListLookasideList, sgListBuffer);
            Irp->Tail.Overlay.DriverContext[2] =  NULL;
        }
    }
    
#else

    status = FdoData->DmaAdapterObject->DmaOperations->GetScatterGatherList(
                    FdoData->DmaAdapterObject,
                    FdoData->Self,
                    mdl,
                    MmGetMdlVirtualAddress(mdl),
                    length,
                    NICProcessSGList,
                    Irp,
                    TRUE);
    
    if (!NT_SUCCESS(status))
    {
        DebugPrint(ERROR, DBG_WRITE, "GetScatterGatherList %x\n", status);
    }
    
#endif
   
    KeLowerIrql(oldIrql);

Error:
    if(!NT_SUCCESS(status)){
        //
        // Our call to get the scatter-gather list failed. We know the
        // NICProcessSGList is not called for sure in that case. So let us
        // complete the IRP here with failure status. Since we marked the
        // IRP pending, we have no choice but to return status-pending
        // even though we are completing the IRP in the incoming thread
        // context.
        //
        NICCompleteSendRequest(FdoData, Irp, status, 0, FALSE);
    }

    DebugPrint(LOUD, DBG_WRITE, "<-- PciDrvWrite %x\n", returnStatus);

    return returnStatus;
}

VOID
NICProcessSGList(
    IN  PDEVICE_OBJECT          DeviceObject,
    IN  PIRP                    Irp,//unused
    IN  PSCATTER_GATHER_LIST    ScatterGather,
    IN  PVOID                   Context
    )
/*++

Routine Description:

    This routine is called at IRQL = DISPATCH_LEVEL when the 
    bus-master adapter is available. 

Arguments:

    DeviceObject - This is the device object for the target device, 
                    previously created by the driver's AddDevice routine. 
    Irp  - Useful only if the driver has a StartIo routine. 

    ScatterGather - Structure describing scatter/gather regions. 

    Context - Pointer to the Request.

Return Value:

    None.

--*/
{
    PFDO_DATA       fdoData;
    PIRP            irp = (PIRP)Context;
    
    DebugPrint(TRACE, DBG_WRITE, "--> NICProcessSGList\n");

    fdoData = DeviceObject->DeviceExtension;

    //
    // Save the ScatterGather pointer in the DriverContext so that we can free
    // the list when we complete the request.
    //
    irp->Tail.Overlay.DriverContext[3] = ScatterGather;
    
    KeAcquireSpinLockAtDpcLevel(&fdoData->SendLock);

    //
    // If tcb is not available or the device is doing link detection (during init),
    // queue the request
    //       
    if (!MP_TCB_RESOURCES_AVAIABLE(fdoData) || 
        MP_TEST_FLAG(fdoData, fMP_ADAPTER_LINK_DETECTION))
    {
        //
        // Instead of locking up the map registers while the request is
        // waiting in the queue or, we could free it up and reallocate it whenever
        // we are ready to handle the request later.
        // 
        //
        DebugPrint(TRACE, DBG_WRITE, "Resource or the link is not available, queue packet\n");
        InsertTailList(&fdoData->SendQueueHead, &irp->Tail.Overlay.ListEntry);
        fdoData->nWaitSend++;
        
    } else {

        NICWritePacket(fdoData, irp, FALSE);
    }
    
    KeReleaseSpinLockFromDpcLevel(&fdoData->SendLock);

    DebugPrint(TRACE, DBG_WRITE, "<-- NICProcessSGList\n");

    return;
}

VOID 
NICWritePacket(
    IN  PFDO_DATA   FdoData,
    IN  PIRP        Irp,
    IN  BOOLEAN     bFromQueue
    )
/*++
Routine Description:

    Do the work to send a packet
    Assumption: Send spinlock has been acquired 

Arguments:

    FdoData     Pointer to our FdoData
    Packet      The packet
    bFromQueue  TRUE if it's taken from the send wait queue

Return Value:

--*/
{
    PMP_TCB         pMpTcb = NULL;
    ULONG           packetLength;
    PVOID           virtualAddress;
        
    DebugPrint(TRACE, DBG_WRITE, "--> NICWritePacket, Irp= %p\n", Irp);
    
    //
    // Get the next free TCB and initialize it to represent the
    // request buffer.
    //
    pMpTcb = FdoData->CurrSendTail;
    ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE));

    //
    // If the adapter is not ready, fail the request.
    //
    if(MP_IS_NOT_READY(FdoData)) {
        MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_DEVICE_NOT_READY);
        return;
    }

    pMpTcb->FirstBuffer = Irp->MdlAddress;    
    virtualAddress = MmGetMdlVirtualAddress(Irp->MdlAddress);    
    pMpTcb->BufferCount = 1;
    pMpTcb->PacketLength = packetLength = MmGetMdlByteCount(Irp->MdlAddress);
    pMpTcb->PhysBufCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(virtualAddress, 
                                            packetLength);
    pMpTcb->Irp = Irp;
    MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE);

    //
    // Call the send handler, it only needs to deal with the frag list
    //
    NICSendPacket(FdoData, pMpTcb, Irp->Tail.Overlay.DriverContext[3]);

    FdoData->nBusySend++;
    ASSERT(FdoData->nBusySend <= FdoData->NumTcb);
    FdoData->CurrSendTail = FdoData->CurrSendTail->Next;

    DebugPrint(TRACE, DBG_WRITE, "<-- NICWritePacket\n");
    return;

}  

NTSTATUS 
NICSendPacket(
    IN  PFDO_DATA     FdoData,
    IN  PMP_TCB         pMpTcb,
    IN  PSCATTER_GATHER_LIST   pFragList
    )

⌨️ 快捷键说明

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