📄 send.c
字号:
SwTcb->Coalesce->OwningTcb = (PVOID) SwTcb;
SwTcb->CoalesceBufferLen = SwTcb->PacketLength;
TRACE2(Adapter, ("Acquired CoalesceBuffer %08x \n", SwTcb->Coalesce));
return (TRUE);
}
//-----------------------------------------------------------------------------
// Procedure: D100CopyFromPacketToBuffer
//
// Description: This routine will copy a packet to a the passed buffer (which
// in this case will be a coalesce buffer).
//
// Arguments:
// Adapter - ptr to Adapter object instance
// Packet - The packet to copy from.
// BytesToCopy - The number of bytes to copy from the packet.
// DestBuffer - The destination of the copy.
// FirstBuffer - The first buffer of the packet that we are copying from.
//
// Result:
// BytesCopied - The number of bytes actually copied
//
// Returns:
//-----------------------------------------------------------------------------
VOID
D100CopyFromPacketToBuffer( PD100_ADAPTER Adapter,
PNDIS_PACKET Packet,
UINT BytesToCopy,
PCHAR DestBuffer,
PNDIS_BUFFER FirstBuffer,
PUINT BytesCopied)
{
PNDIS_BUFFER CurrentBuffer;
PVOID VirtualAddress;
UINT CurrentLength;
UINT AmountToMove;
*BytesCopied = 0;
if (!BytesToCopy)
return;
CurrentBuffer = FirstBuffer;
NdisQueryBuffer(
CurrentBuffer,
&VirtualAddress,
&CurrentLength);
while (BytesToCopy)
{
while (!CurrentLength)
{
NdisGetNextBuffer(
CurrentBuffer,
&CurrentBuffer);
// If we've reached the end of the packet. We return with what
// we've done so far (which must be shorter than requested).
if (!CurrentBuffer)
return;
NdisQueryBuffer(
CurrentBuffer,
&VirtualAddress,
&CurrentLength);
}
// Compute how much data to move from this fragment
if (CurrentLength > BytesToCopy)
AmountToMove = BytesToCopy;
else
AmountToMove = CurrentLength;
// Copy the data.
NdisMoveMemory(DestBuffer, VirtualAddress, AmountToMove);
// Update destination pointer
DestBuffer = (PCHAR) DestBuffer + AmountToMove;
// Update counters
*BytesCopied +=AmountToMove;
BytesToCopy -=AmountToMove;
CurrentLength = 0;
}
}
//-----------------------------------------------------------------------------
// Procedure: ProcessTXInterrupt
//
// Description: This routine is called by HandleInterrupt to process transmit
// interrupts for D100 adapters. Basically, this routine will
// remove any completed packets from the active transmit chain,
// append them to the completed list. TransmitCleanup will be
// called to free up the TCBs, map registers, etc, that the
// packets on the completed list consumed. At the end of this
// routine, the MAC version of this driver will try to send any
// packets that it queued because of an earlier lack of resources.
//
// Arguments:
// Adapter - ptr to Adapter object instance
//
// Return:
// TRUE - If we indicated any loopback packets during this function call
// FALSE - If we didn't indicate any loopaback packets
//-----------------------------------------------------------------------------
BOOLEAN
ProcessTXInterrupt(PD100_ADAPTER Adapter)
{
PD100SwTcb SwTcb;
BOOLEAN Status = FALSE;
NDIS_STATUS SendStatus;
DEBUGFUNC("ProcessTXInterrupt");
TRACE2(Adapter, ("\n"));
DEBUGCHAR(Adapter,'X');
// If we don't have an active transmit chain, AND we haven't pended any transmits,
// then we don't have anything to clean-up.
if (QueueEmpty(&Adapter->ActiveChainList) && !Adapter->FirstTxQueue)
{
DEBUGCHAR(Adapter,'z');
return FALSE;
}
// Look at the TCB at the head of the queue. If it has been completed
// then pop it off and place it at the tail of the completed list.
// Repeat this process until all the completed TCBs have been moved to the
// completed list
while (SwTcb = (PD100SwTcb) QueueGetHead(&Adapter->ActiveChainList))
{
// check to see if the TCB has been DMA'd
if (SwTcb->Tcb->TxCbHeader.CbStatus & CB_STATUS_COMPLETE)
{
DEBUGCHAR(Adapter,'c');
TRACE3(Adapter, ("Found a completed TCB\n"));
// Remove the TCB from the active queue.
SwTcb = (PD100SwTcb) QueuePopHead(&Adapter->ActiveChainList);
// Put the TCB on the completed queue.
QueuePutTail(&Adapter->CompletedChainList, &SwTcb->Link);
}
else
break;
}
// Cleanup after the transmits that have already been sent -- free their
// TCBs, map registers, and coalesce buffers.
if (!QueueEmpty(&Adapter->CompletedChainList))
Status = TransmitCleanup(Adapter);
// If we queued any transmits because we didn't have any TCBs earlier,
// dequeue and send those packets now, as long as we have free TCBs.
while ((Adapter->FirstTxQueue) &&
((PD100SwTcb) QueueGetHead(&Adapter->TxCBList)))
{
PNDIS_PACKET QueuePacket;
// If any packets are in the queue, dequeue it, send it, and
// acknowledge success.
QueuePacket = Adapter->FirstTxQueue;
Adapter->NumPacketsQueued--;
DequeuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue);
DEBUGCHAR(Adapter,'q');
// Attempt to put it onto the hardware
SendStatus = SetupNextSend(Adapter, QueuePacket);
// If there were no resources for this packet, then we'll just have
// to try and send it later.
if (SendStatus == NDIS_STATUS_RESOURCES)
{
// re-queue the packet
Adapter->NumPacketsQueued++;
EnqueuePacket(Adapter->FirstTxQueue, Adapter->LastTxQueue, QueuePacket);
DEBUGCHAR(Adapter,'Q');
break;
}
}
DEBUGCHAR(Adapter,'x');
return Status;
}
//-----------------------------------------------------------------------------
// Procedure: TransmitCleanup
//
// Description: This routine will clean up after a transmitted frame. It will
// update the transmit statistic counters, free up TCBs and map
// regs, and issue a send complete which will unlock the pages.
//
// Arguments:
// Adapter - ptr to Adapter object instance
//
// Returns:
// TRUE - If we indicated any loopback packets during this function call
// FALSE - If we didn't indicate any loopaback packets
//-----------------------------------------------------------------------------
BOOLEAN
TransmitCleanup(PD100_ADAPTER Adapter)
{
PD100SwTcb SwTcb;
PNDIS_PACKET Packet;
PNDIS_BUFFER CurrBuff;
BOOLEAN Status = FALSE;
BOOLEAN DoSendComplete = TRUE;
INT MapRegToFree;
DEBUGFUNC("TransmitCleanup");
TRACE2(Adapter, ("\n"));
DEBUGCHAR(Adapter,'_');
// If the completed transmit list is empty, then we have nothing to do here
while (!QueueEmpty(&Adapter->CompletedChainList))
{
// Get the first entry in the completed list.
SwTcb = (PD100SwTcb) QueuePopHead(&Adapter->CompletedChainList);
ASSERT(SwTcb);
// PACKET is nothin when the element being processed is a MC Command
Packet = SwTcb->Packet;
TRACE3(Adapter, ("Processing SwTcb %08x, Packet %08x\n", SwTcb, Packet));
// Free a coalesce buffer (if there were any)
if (SwTcb->Coalesce)
{
// debug checks
ASSERT(SwTcb->CoalesceBufferLen);
// ASSERT(!SwTcb->NumPhysDesc);
// ASSERT(!SwTcb->MapsUsed);
ASSERT(SwTcb->Coalesce->OwningTcb == (PVOID) SwTcb);
// Return the coalesce buffer back to the list
QueuePutTail(&Adapter->CoalesceBufferList, &SwTcb->Coalesce->Link);
// Clear the coalesce buffer pointer
SwTcb->Coalesce = (PCOALESCE) 0;
SwTcb->CoalesceBufferLen = 0;
}
// unlock all of the pages held by this packet
if (SwTcb->MapsUsed > 0)
{
// start with the first buffer
CurrBuff = SwTcb->FirstBuffer;
// free the map register associated with each buffer
while (CurrBuff)
{
// free a map register
MapRegToFree = Adapter->OldestUsedMapReg;
Adapter->OldestUsedMapReg++;
if (Adapter->OldestUsedMapReg == Adapter->NumMapRegisters)
Adapter->OldestUsedMapReg = 0;
#if DBG
SwTcb->MapsUsed--;
#endif
// Release the map register and its associated physical mapping
NdisMCompleteBufferPhysicalMapping(
Adapter->D100AdapterHandle,
CurrBuff,
MapRegToFree);
// Get the next buffer that needs the be "de-mapped"
NdisGetNextBuffer(CurrBuff, &CurrBuff);
}
#if DBG
// This counter gets decremented each time a map reg is freed,
// under the debug build. Under the free build, we just zero
// the counter at the end of the loop.
ASSERT(SwTcb->MapsUsed == 0);
#endif
}
// Clear NumPhysDesc, and NumMapsUsed.
SwTcb->NumPhysDesc =
SwTcb->MapsUsed = 0;
// Free the TCB for the given frame
TRACE3(Adapter, ("Releasing SwTcb %08x\n", SwTcb));
QueuePutTail(&Adapter->TxCBList, &SwTcb->Link);
// If this wasn't a multicast command, then we need to check to see
// if we need to issue send complete
if ((SwTcb->Tcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
{
#if DBG
Adapter->txind++;
#endif
DEBUGCHAR(Adapter,'-');
// If we originally returned NDIS_STATUS_PENDING on this packet, then
// we need to tell the protocol that we are finished with the packet
// now. If we originally returned NDIS_STATUS_SUCCESS, then we don't
// need to make the SendComplete call, because the protocol will have
// already freed or re-used the "packet".
if (DoSendComplete == TRUE)
{
NdisReleaseSpinLock(&Adapter->Lock);
// Do a send Complete for this frame
NdisMSendComplete(
Adapter->D100AdapterHandle,
Packet,
NDIS_STATUS_SUCCESS);
NdisAcquireSpinLock(&Adapter->Lock);
}
}
}
DEBUGCHAR(Adapter,'=');
return Status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -