📄 routines.c
字号:
// Copy the current multicast addresses to the command block
for (i = 0;(i < Adapter->NumberOfMcAddresses) &&
(i < MAX_MULTICAST_ADDRESSES); i++)
for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++)
*(McAddress++) = Adapter->PrivateMulticastBuffer[i][j];
// Setup the command and status words of the command block
SwTcb->Tcb->TxCbHeader.CbStatus = 0;
SwTcb->Tcb->TxCbHeader.CbCommand = CB_S_BIT | CB_MULTICAST;
// If CU is idle (very first command) then we must
// setup the general pointer and issue a full CU-start
if (Adapter->TransmitIdle)
{
TRACE2(Adapter, ("CU is idle -- First MC added to Active List\n"));
QueuePushHead(&Adapter->ActiveChainList, &SwTcb->Link);
// Wait for the SCB to clear before we set the general pointer
WaitScb(Adapter);
// Don't try to start the transmitter if the command unit is not
// idle ((not idle) == (Cu-Suspended or Cu-Active)).
if ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE)
{
TRACESTR(Adapter, ("CU Not IDLE\n"));
ASSERT(0);
NdisStallExecution(25); // hack to wait 25us
}
Adapter->CSRAddress->ScbGeneralPointer = SwTcb->TcbPhys;
D100IssueScbCommand(Adapter, SCB_CUC_START, FALSE);
Adapter->TransmitIdle = FALSE;
Adapter->ResumeWait = TRUE;
}
// If the CU has already been started, then append this
// TCB onto the end of the transmit chain, and issue a CU-Resume.
else
{
TRACE2(Adapter, ("adding MCB to Active chain\n"));
QueuePutTail(&Adapter->ActiveChainList, &SwTcb->Link);
// Clear the suspend bit on the previous packet.
SwTcb->PreviousTcb->TxCbHeader.CbCommand &= ~CB_S_BIT;
// We need to wait for the SCB to clear when inserting a non-
// transmit command dynamically into the CBL (command block list).
Adapter->ResumeWait = TRUE;
// Issue a CU-Resume command to the device -- and wait for the
// SCB command word to clear first.
if (!D100IssueScbCommand(Adapter, SCB_CUC_RESUME, TRUE))
{
TRACESTR(Adapter, ("CU-resume failed\n"));
}
}
}
DEBUGCHAR(Adapter,'b');
}
//-----------------------------------------------------------------------------
// Procedure: D100IssueSelectiveReset
//
// Description: This routine will issue a selective reset, forcing the adapter
// the CU and RU back into their idle states. The receive unit
// will then be re-enabled if it was previously enabled, because
// an RNR interrupt will be generated when we abort the RU.
//
// Arguments:
// Adapter - ptr to Adapter object instance
//
// Returns:
// NOTHING
//-----------------------------------------------------------------------------
VOID
D100IssueSelectiveReset(
PD100_ADAPTER Adapter
)
{
// BOOLEAN EnableInts = TRUE;
#if DBG
UINT counter=0;
USHORT x;
#endif
UINT i;
DEBUGFUNC("D100IssueSelectiveReset");
TRACE2(Adapter, ("Entered D100IssueSelectiveReset\n"));
INITSTR(("\n"));
// Wait for the SCB to clear before we check the CU status.
WaitScb(Adapter);
// If we have issued any transmits, then the CU will either be active, or
// in the suspended state. If the CU is active, then we wait for it to be
// suspended. If the the CU is suspended, then we need to put the CU back
// into the idle state by issuing a selective reset.
if (Adapter->TransmitIdle == FALSE)
{
// Wait for suspended state
for (i=1000; (i != 0) && (Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_ACTIVE; i--)
// while ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_ACTIVE)
{
TRACESTR(Adapter, ("CU active -- wait for it to suspend. ScbStatus=%04x\n",
Adapter->CSRAddress->ScbStatus));
NdisStallExecution(20);
}
if (!i)
{
HARDWARE_NOT_RESPONDING (Adapter);
return;
}
// Check the current status of the receive unit
if ((Adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE)
{
// Issue an RU abort. Since an interrupt will be issued, the
// RU will be started by the DPC.
D100IssueScbCommand(Adapter, SCB_RUC_ABORT, TRUE);
}
// Issue a selective reset.
TRACESTR(Adapter, ("CU suspended. ScbStatus=%04x Issue selective reset\n",
Adapter->CSRAddress->ScbStatus));
Adapter->CSRAddress->Port = PORT_SELECTIVE_RESET;
// stall 20 us (only need 10) after a port sel-reset command
NdisStallExecution(20);
for (i=100; i != 0; i--)
{
if (Adapter->CSRAddress->Port == 0)
break;
NdisStallExecution(10);
}
if (!i)
{
HARDWARE_NOT_RESPONDING (Adapter);
return;
}
// disable interrupts after issuing reset, because the int
// line gets raised when reset completes.
D100DisableInterrupt(Adapter);
// Restore the transmit software flags.
Adapter->TransmitIdle = TRUE;
Adapter->ResumeWait = TRUE;
}
}
//-----------------------------------------------------------------------------
// Procedure: D100SubmitCommandBlockAndWait
//
// Description: This routine will submit a command block to be executed, and
// then it will wait for that command block to be executed. Since
// board ints will be disabled, we will ack the interrupt in
// this routine.
//
// Arguments:
// Adapter - ptr to Adapter object instance
//
// Returns:
// TRUE - If we successfully submitted and completed the command.
// FALSE - If we didn't successfully submit and complete the command.
//-----------------------------------------------------------------------------
BOOLEAN
D100SubmitCommandBlockAndWait(
IN PD100_ADAPTER Adapter
)
{
UINT Delay;
BOOLEAN Status;
// Points to the Non Tx Command Block.
volatile PNON_TRANSMIT_CB CommandBlock = Adapter->NonTxCmdBlock;
DEBUGFUNC("D100SubmitCommandBlockAndWait");
TRACE2(Adapter, ("Entered D100SubmitCommandBlockAndWait\n"));
// Set the Command Block to be the last command block
CommandBlock->NonTxCb.Config.ConfigCBHeader.CbCommand |= CB_EL_BIT;
// Clear the status of the command block
CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus = 0;
#if DBG
// Don't try to start the CU if the command unit is active.
if ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_ACTIVE)
{
TRACESTR(Adapter, ("Scb %08x ScbStatus %04x\n", Adapter->CSRAddress, Adapter->CSRAddress->ScbStatus));
ASSERT(0);
return (FALSE);
}
#endif
// Start the command unit.
D100IssueScbCommand(Adapter, SCB_CUC_START, FALSE);
// Wait for the SCB to clear, indicating the completion of the command.
if (WaitScb(Adapter) == FALSE)
{
TRACESTR(Adapter, ("WaitScb failed\n"));
D100LogError(Adapter, EVENT_6, NDIS_ERROR_CODE_TIMEOUT, 0);
return (FALSE);
}
// Wait for some status
Delay = 300000;
while ((!(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_COMPLETE)) && Delay)
{
NdisStallExecution(10);
Delay--;
}
if (!Delay)
{
HARDWARE_NOT_RESPONDING (Adapter);
return (FALSE);
}
// Ack any interrupts
if (Adapter->CSRAddress->ScbStatus & SCB_ACK_MASK)
{
// Ack all pending interrupts now
Adapter->CSRAddress->ScbStatus &= SCB_ACK_MASK;
}
// Check the status of the command, and if the command failed return FALSE,
// otherwise return TRUE.
if (!(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_OK))
{
TRACESTR(Adapter, ("Command failed\n"));
Status = FALSE;
}
else
Status = TRUE;
return (Status);
}
//-----------------------------------------------------------------------------
// Procedure: GetConnectionStatus
//
// Description: This function returns the connection status that is
// a required indication for PC 97 specification from MS
// the value we are looking for is if there is link to the
// wire or not.
//
// Arguments: IN Adapter structure pointer
//
// Returns: NdisMediaStateConnected
// NdisMediaStateDisconnected
//-----------------------------------------------------------------------------
NDIS_MEDIA_STATE
GetConnectionStatus( IN PD100_ADAPTER Adapter )
{
USHORT MdiStatusReg;
// Read the status register at phy 1
MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);
MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, &MdiStatusReg);
if (MdiStatusReg & MDI_SR_LINK_STATUS)
return(NdisMediaStateConnected);
else
return(NdisMediaStateDisconnected);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -