📄 e100bexadap.cpp
字号:
{
SendComplete(m_TxQueue.RemoveHead(), NDIS_STATUS_FAILURE);
}
while (!m_ActiveChainList.IsEmpty())
{
// here we have to fail any sends that haven't completed yet
PD100SwTcb pSwTcb = m_ActiveChainList.RemoveHead();
// If this wasn't a multicast command, then we need to check to see
// if we need to issue send complete
if ((pSwTcb->Tcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
{
// Do a send Complete for this frame
SendComplete(pSwTcb->Packet, NDIS_STATUS_FAILURE);
}
}
// Abort the Receive unit so the hardware doesn't continue to receive packets. If
// the Receive unit is not aborted, the hardware could still DMA receive packets
// into host memory after a warm boot.
m_pCard->AbortReceiveUnit();
// Wait 30 Milliseconds for the device to abort the RU.
// Try to avoid reseting the PHY when the RU is active.
StallExecution(30);
// Reset the PHY chip. This is done so that after a warm boot, the PHY will
// be in a known state, with auto-negotiation enabled.
m_pCard->ResetPhy();
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::Reset
//
// MiniportReset is a required function that issues a hardware reset
// to the NIC and/or resets the driver's software state.
//
// Parameters:
// AddressingReset
// Points to a variable that MiniportReset sets to TRUE if the
// NDIS library should call MiniportSetInformation to restore
// addressing information to the current values.
// IRQL:
// DISPATCH_LEVEL
// Return Mode:
// Asynchronous
NDIS_STATUS E100bexAdapter::Reset
(OUT PBOOLEAN AddressingReset)
{
TRACE("E100bexAdapter::Reset() Entered\n");
m_Lock.Lock();
*AddressingReset = TRUE;
// Disable interrupts while re-initializing the transmit structures
m_pCard->DisableInterrupt();
// The NDIS 5 support for deserialized miniports requires that
// when reset is called, the driver de-queue and fail all uncompleted
// sends, and complete any uncompleted sends. Essentially there must be
// no pending send requests left when this routine is exited.
// we will fail all sends that are left right now.
TRACE("DeQing: ");
while(!m_TxQueue.IsEmpty())
{
// we must release the lock here before returning control to ndis
// (even temporarily like this)
m_Lock.Unlock();
SendComplete(m_TxQueue.RemoveHead(), NDIS_STATUS_FAILURE);
m_Lock.Lock();
}
TRACE("\nDone!\n");
// clean up all the packets we have successfully TX'd
ProcessTXInterrupt();
while (!m_ActiveChainList.IsEmpty())
{
// here we have to fail any sends that haven't completed yet
PD100SwTcb pSwTcb = m_ActiveChainList.RemoveHead();
// If this wasn't a multicast command, then we need to check to see
// if we need to issue send complete
if ((pSwTcb->Tcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST)
{
m_Lock.Unlock();
// Do a send Complete for this frame
SendComplete(pSwTcb->Packet, NDIS_STATUS_FAILURE);
m_Lock.Lock();
}
}
// Cancel the timer
m_Timer.Cancel();
// Issue a selective reset to make the CU idle. This will also abort
// the RU, and make the receive unit go idle.
m_pCard->IssueSelectiveReset();
// since the d100/d101 both assert the interrupt line after reset,
// try disabling ints here, because nothing is handled
// on a reset interrupt anyway.
m_pCard->DisableInterrupt();
// Clear out our software transmit structures
NdisZeroMemory((PVOID) m_XmitCached, m_XmitCachedSize);
// re-init the map register related variables
m_NextFreeMapReg = 0;
m_OldestUsedMapReg = 0;
// re-initialize the transmit structures
TRACE("Reset: Calling SetupTransmitQueues\n");
SetupTransmitQueues();
// set a timer to call back in 500 ms so the
// spinlock is not held too long
m_Timer.Set(500);
m_Lock.Unlock();
// return NDIS_STATUS_PENDING so that this can be finished later
return NDIS_STATUS_PENDING;
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::Shutdown
//
// MiniportShutdown does nothing more than restore the NIC to its
// initial state (before the miniport's DriverEntry function runs)
//
// Parameters:
// None
// IRQL:
// If MiniportShutdown is called due to a user-initiated system shutdown,
// it runs at IRQL PASSIVE_LEVEL in a system-thread context. If it is called
// due to an unrecoverable error, MiniportShutdown runs at an arbitrary IRQL
// and in the context of whatever component raised the error.
// Return Mode:
// Synchronous
VOID E100bexAdapter::Shutdown(void)
{
TRACE("E100bexAdapter::Shutdown() Entered\n");
// Disable the device's interrupt line.
m_pCard->DisableInterrupt();
// Abort the Receive unit so the hardware doesn't continue to receive packets. If
// the Receive unit is not aborted, the hardware could still DMA receive packets
// into host memory after a warm boot.
m_pCard->AbortReceiveUnit();
// Wait 30 Milliseconds for the device to abort the RU. This really
// is not necessary, but I'm a little paranoid about reseting the PHY
// when the RU is active.
StallExecution(30);
// Reset the PHY chip. We do this so that after a warm boot, the PHY will
// be in a known state, with auto-negotiation enabled.
m_pCard->ResetPhy();
}
////////////////////////////////////////////////////////////////////
// E100bexAdapter::SendPackets
//
// Transfers a protocol-supplied packet over the network
//
// Parameters:
// PacketArray
// Points to an array of packet descriptors specifying the data to be transmitted.
// NumberOfPackets
// Specifies the number of packets in the array.
// IRQL:
// DISPATCH_LEVEL
// Return Mode:
// Asynchronous
// NOTE:
VOID E100bexAdapter::SendPackets(
IN PPNDIS_PACKET PacketArray,
IN UINT NumberOfPackets
)
{
NDIS_STATUS Status;
TRACE("E100bexAdapter::SendPackets() Entered\n");
m_Lock.Lock();
UINT PacketIndex;
KNdisPacketArray PktArray(PacketArray, NumberOfPackets);
KNdisPacket Pkt;
// Take each packet in the array and return a status for it
// if we return one packet with a NDIS_STATUS_RESOURCES,
// the MiniPort layer assumes the rest of the packets have the same status
// its up to the protocol to check those statuses after we return
for(PacketIndex=0;PacketIndex < NumberOfPackets; PacketIndex++)
{
Pkt = PktArray[PacketIndex];
// check for a zero pointer
ASSERT(Pkt.IsValid());
Status = SetupNextSend(Pkt);
if (Status == NDIS_STATUS_RESOURCES)
{
// Queue This packet for the Deserialized Miniport
m_TxQueue.InsertTail(Pkt);
Status = NDIS_STATUS_PENDING;
}
Pkt.STATUS(Status);
}
m_Lock.Unlock();
return;
}
//-----------------------------------------------------------------------------
// Procedure: SetupNextSend
//
// Description: This routine is called by SendPackets. It will setup all of the
// necessary structures (TCBs, TBDs, etc.) to send a packet. If
// the device has the necessary resources, the packet will be
// sent out on the active chain. If the device doesn't have the
// resources to send the packet, then the routine will return
// NDIS_STATUS_RESOURCES.
//
// The intention is to have this routine run only on a 82557
// or a 82558 in compatibility mode (indicated by Enhanced = FALSE
// in the registry)
// Arguments:
// Packet - The KNdisPacket that is to be transmitted.
// Returns:
// NDIS_STATUS_SUCCESS - We copied the entire packet into a host buffer,
// (either it was a short frame, or we coalesced
// the packet into a host buffer), so we can
// immediately return the buffer back to the upper
// layers.
// NDIS_STATUS_PENDING - If we were able to acquire the necessary TBD's
// or Coalesce buffer for the packet. This means
// that the device will send this packet soon.
// Eventually we'll return the packet back to the
// protocol stack by using the "SendComplete" call.
// NDIS_STATUS_RESOURCES - We didn't have the resouces (TCBs or TBDs) to
// accept this packet. The NDIS packet should
// queue this packet, and give it back to us at a
// later time.
//-----------------------------------------------------------------------------
NDIS_STATUS E100bexAdapter::SetupNextSend(KNdisPacket& Packet)
{
PD100SwTcb SwTcb;
PTXCB_STRUC HwTcb;
NDIS_STATUS Status;
// Attempt to acquire a Software TCB for the packet
SwTcb = m_TxCBList.RemoveHead();
if (!SwTcb)
{
TRACE2(("FailNoTcb\n"))
// No TCBs available so return NO_RESOURCES
Status = NDIS_STATUS_RESOURCES;
return (Status);
}
// this next line tries to workaround the case where
// on a D101 we can wrap our queue by setting the
// 'S' bit on our head
if (m_TxCBList.IsEmpty())
{
TRACE2(("Don't WRAP queue!!! Fail With Only 1 TCB left\n"))
m_TxCBList.InsertHead(SwTcb);
Status = NDIS_STATUS_RESOURCES;
return(Status);
}
// Prepare the TCB for transmission of this packet
if (PrepareForTransmit(Packet, SwTcb))
{
// debug stuff
TRACE3(("Assigning SwTcb %08x to 557\n", SwTcb))
ASSERT(SwTcb);
HwTcb = SwTcb->Tcb;
HwTcb->TxCbHeader.CbStatus = 0;
HwTcb->TxCbThreshold = (UCHAR) m_AiThreshold;
// If the packet is small then we don't use any TBDs, and we send
// the packet in simplified mode.
if (SwTcb->PacketLength <= MINIMUM_ETHERNET_PACKET_SIZE)
{
// Prep the hardware TCB. This Tcb will not point to any TBDs
// because the entire frame will be located in the TCB's data
// area.
HwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT;
HwTcb->TxCbTbdPointer = DRIVER_NULL;
HwTcb->TxCbTbdNumber = 0;
HwTcb->TxCbCount = (CB_TX_EOF_BIT | 0x003C);
}
// If the packet is not small then we do use TBDs, and thus send the
// packet using flexible mode.
else
{
// Prep the hardware TCB
HwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT | CB_TX_SF_BIT;
HwTcb->TxCbTbdPointer = SwTcb->FirstTbdPhys;
HwTcb->TxCbTbdNumber = (UCHAR) SwTcb->TbdsUsed;
HwTcb->TxCbCount = 0;
}
// If the transmit unit is idle (very first transmit) then we must
// setup the general pointer and issue a full CU-start
if (m_TransmitIdle)
{
TRACE2(("CU is idle -- First TCB added to Active List\n"))
m_ActiveChainList.InsertTail(SwTcb);
m_pCard->StartTransmitUnit(SwTcb->TcbPhys);
m_TransmitIdle = FALSE;
m_ResumeWait = TRUE;
}
// If the command unit has already been started, then append this
// TCB onto the end of the transmit chain, and issue a CU-Resume.
else
{
TRACE2(("adding TCB to Active chain\n"))
m_ActiveChainList.InsertTail(SwTcb);
// Clear the suspend bit on the previous packet.
SwTcb->PreviousTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;
m_pCard->ResumeCommandUnit();
}
// return NDIS_STATUS_PENDING and then later make a "SendComplete" call
// to return the packet the protocol stack.
Status = NDIS_STATUS_PENDING;
#if DBG
m_txsent++;
#endif
}
// If PrepareForTransmit didn't succeed, then put the TCB back on the free
// list, and return the proper error code
else
{
if ((!SwTcb->PacketLength) || (SwTcb->PacketLength > MAXIMUM_ETHERNET_PACKET_SIZE))
Status = NDIS_STATUS_INVALID_PACKET;
else
Status = NDIS_STATUS_RESOURCES;
// If prepare failed, then put the TCB back on queue because
// we don't have an available coalesce buffer
m_TxCBList.InsertHead(SwTcb);
}
return (Status);
}
//-----------------------------------------------------------------------------
// Procedure: PrepareForTransmit
//
// Description: This routine will Prepare a software TCB, and a set
// of linked TBDs, for the packet that is passed in. When this
// routine returns, this packet will be ready to send through the
// adapter, and onto the medium.
//
// Arguments:
// Packet - A KNdisPacket that is to be transmitted.
// SwTcb - Pointer to a software structure that represents a hardware TCB.
//
// Returns:
// TRUE If we were able to acquire the necessary TBD's or Coalesce buffer
// for the packet in we are attempting to prepare for transmission.
// FALSE If we needed a coalesce buffer, and we didn't have any available.
//-----------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -