mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
977 lines
27 KiB
977 lines
27 KiB
|
|
//**********************************************************************
|
|
//**********************************************************************
|
|
//
|
|
// File Name: INT.C
|
|
//
|
|
// Program Name: NetFlex NDIS 3.0 Miniport Driver
|
|
//
|
|
// Companion Files: None
|
|
//
|
|
// Function: This module contains the NetFlex Miniport Driver
|
|
// interface routines called by the Wrapper and the
|
|
// configuration manager.
|
|
//
|
|
// (c) Compaq Computer Corporation, 1992,1993,1994
|
|
//
|
|
// This file is licensed by Compaq Computer Corporation to Microsoft
|
|
// Corporation pursuant to the letter of August 20, 1992 from
|
|
// Gary Stimac to Mark Baber.
|
|
//
|
|
// History:
|
|
//
|
|
// 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver
|
|
//
|
|
//
|
|
//
|
|
//***********************************************************************
|
|
|
|
|
|
/*-------------------------------------*/
|
|
/* Include all general companion files */
|
|
/*-------------------------------------*/
|
|
|
|
#include <ndis.h>
|
|
#include "tmsstrct.h"
|
|
#include "macstrct.h"
|
|
#include "adapter.h"
|
|
#include "protos.h"
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexISR
|
|
//
|
|
// Description:
|
|
// This routine is the ISR for this Netflx mac driver.
|
|
// This routine determines if the interrupt is for it
|
|
// and if so, it clears the system interrupt bit of
|
|
// the sifint register.
|
|
//
|
|
// Input:
|
|
// Context - Our Driver Context for this adapter or head.
|
|
//
|
|
// Output:
|
|
// Returns TRUE if the interrupt belongs to the
|
|
// adapter and returns FALSE if it does not
|
|
// belong to the adapter.
|
|
//
|
|
// Called By:
|
|
// Miniport Wrapper
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID NetFlexISR(
|
|
OUT PBOOLEAN InterruptRecognized,
|
|
OUT PBOOLEAN QueueDpc,
|
|
IN PVOID Context )
|
|
{
|
|
PACB acb;
|
|
USHORT sifint_reg;
|
|
USHORT actl_reg;
|
|
|
|
acb = (PACB) Context;
|
|
|
|
//
|
|
// Read the Sifint register.
|
|
//
|
|
NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
|
|
|
|
//
|
|
// See if the System Interrupt bit is set. If it is, this is an
|
|
// interrupt for us.
|
|
//
|
|
if (sifint_reg & SIFINT_SYSINT)
|
|
{
|
|
//
|
|
// Acknowledge and Clear Int
|
|
//
|
|
if (!acb->InterruptsDisabled)
|
|
{
|
|
actl_reg = acb->actl_reg & ~ACTL_SINTEN;
|
|
NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
|
|
DebugPrint(3,("NF(%d)(D)\n",acb->anum));
|
|
acb->InterruptsDisabled = TRUE;
|
|
|
|
//
|
|
// Return that we recognize it
|
|
//
|
|
*InterruptRecognized = TRUE;
|
|
*QueueDpc = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// It appears that a second head is generating
|
|
// the interrupt, and we have a DPC queued to
|
|
// process our int, return that we don't recognize it
|
|
// so that the oterh head's isr gets called...
|
|
//
|
|
*InterruptRecognized = FALSE;
|
|
*QueueDpc = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Return that we don't recognize it
|
|
//
|
|
*InterruptRecognized = FALSE;
|
|
*QueueDpc = FALSE;
|
|
}
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexDeferredTimer
|
|
//
|
|
// Description:
|
|
// This routine is called every 10ms to check to see
|
|
// if there is any receives or transmits which need
|
|
// to be cleaned up since we don't require an interrupt
|
|
// for each frame.
|
|
//
|
|
// Input:
|
|
// acb - Our Driver Context for this adapter or head.
|
|
//
|
|
// Output:
|
|
// None.
|
|
//
|
|
// Called By:
|
|
// Miniport Wrapper via acb->DpcTimer
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
#ifdef NEW_DYNAMIC_RATIO
|
|
UINT MaxIntRatio = 4;
|
|
|
|
//
|
|
// New Threshold for xmit disabled case.
|
|
//
|
|
UINT RaiseIntThreshold = 26;
|
|
|
|
//
|
|
// Run threshold of 1.5 seconds instead of 200msecs.
|
|
//
|
|
UINT RunThreshold = 15;
|
|
UINT RatioCheckCount = 10;
|
|
#else
|
|
|
|
UINT sw24 = 220;
|
|
UINT sw21 = 40;
|
|
#endif
|
|
|
|
#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
|
|
BOOLEAN EnableDynamicRatio = TRUE;
|
|
UINT ratio = 1;
|
|
#endif
|
|
|
|
VOID NetFlexDeferredTimer(
|
|
IN PVOID SystemSpecific1,
|
|
IN PACB acb,
|
|
IN PVOID SystemSpecific2,
|
|
IN PVOID SystemSpecific3
|
|
)
|
|
{
|
|
USHORT ReceivesProcessed = 0;
|
|
USHORT sifint_reg;
|
|
UINT IntAve;
|
|
|
|
//
|
|
// Indicate that a timer has expired.
|
|
//
|
|
DebugPrint(3,("NF(%d) - Defered Timer Expired!\n",acb->anum));
|
|
|
|
//
|
|
// If we are resetting, get out...
|
|
//
|
|
if (acb->acb_state == AS_RESETTING)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// See if there are any recieves to do...
|
|
//
|
|
|
|
if (acb->acb_rcv_head->RCV_CSTAT & RCSTAT_COMPLETE)
|
|
{
|
|
//
|
|
// Increment the interrupt count.
|
|
//
|
|
acb->acb_int_count++;
|
|
|
|
// yes, do them...
|
|
//
|
|
ReceivesProcessed = acb->ProcessReceiveHandler(acb);
|
|
}
|
|
|
|
//
|
|
// See if there are any transmits to do...
|
|
//
|
|
NetFlexProcessXmit(acb);
|
|
|
|
//
|
|
// Processed any receives which need IndicateReceiveComplete?
|
|
//
|
|
if (ReceivesProcessed)
|
|
{
|
|
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
|
|
{
|
|
// Token Ring
|
|
//
|
|
NdisMTrIndicateReceiveComplete(acb->acb_handle);
|
|
}
|
|
else
|
|
{
|
|
// Ethernet
|
|
//
|
|
NdisMEthIndicateReceiveComplete(acb->acb_handle);
|
|
}
|
|
}
|
|
|
|
|
|
if ( ++acb->timer_run_count >= RatioCheckCount )
|
|
{
|
|
acb->timer_run_count = 0;
|
|
|
|
#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
|
|
if ( EnableDynamicRatio )
|
|
{
|
|
#endif
|
|
|
|
#ifdef NEW_DYNAMIC_RATIO
|
|
|
|
//
|
|
// Should we increase the ratio?
|
|
//
|
|
if ( acb->handled_interrupts > RaiseIntThreshold)
|
|
{
|
|
acb->current_run_down = 0;
|
|
if (acb->XmitIntRatio == 1)
|
|
{
|
|
if ( ++acb->current_run_up > RunThreshold )
|
|
{
|
|
#ifdef XMIT_INTS
|
|
acb->XmitIntRatio = acb->acb_maxtrans;
|
|
#endif
|
|
acb->acb_gen_objs.interrupt_ratio_changes++;
|
|
acb->current_run_up = 0;
|
|
DebugPrint(1,("NF(%d) - RcvIntRatio = %d\n",acb->anum,acb->RcvIntRatio));
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Or, should we decrease it?
|
|
//
|
|
else //if ( acb->handled_interrupts < LowerIntThreshold )
|
|
{
|
|
acb->current_run_up = 0;
|
|
if (acb->XmitIntRatio != 1)
|
|
|
|
{
|
|
if ( ++acb->current_run_down > RunThreshold )
|
|
{
|
|
|
|
#ifdef XMIT_INTS
|
|
acb->XmitIntRatio = 1;
|
|
#endif
|
|
acb->acb_gen_objs.interrupt_ratio_changes++;
|
|
acb->current_run_down = 0;
|
|
DebugPrint(1,("NF(%d) - RcvIntRatio = %d\n",acb->anum,acb->RcvIntRatio));
|
|
}
|
|
}
|
|
}
|
|
|
|
#else // !defined(NEW_DYNAMIC_RATIO)
|
|
|
|
if ( acb->XmitIntRatio != 1 )
|
|
{
|
|
if ( acb->handled_interrupts < sw21 )
|
|
{
|
|
if ( ++acb->current_run > RunThreshold )
|
|
{
|
|
|
|
#ifdef XMIT_INTS
|
|
acb->XmitIntRatio = 1;
|
|
#endif
|
|
acb->RcvIntRatio = 1;
|
|
acb->acb_gen_objs.interrupt_ratio_changes++;
|
|
acb->current_run = 0;
|
|
acb->sw24 += 3;
|
|
|
|
acb->cleartime = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
acb->current_run = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( acb->handled_interrupts > sw24 )
|
|
{
|
|
if ( ++acb->current_run > RunThreshold )
|
|
{
|
|
|
|
#ifdef XMIT_INTS
|
|
acb->XmitIntRatio = ratio;
|
|
#endif
|
|
acb->RcvIntRatio = ratio;
|
|
acb->acb_gen_objs.interrupt_ratio_changes++;
|
|
acb->current_run = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
acb->current_run = 0;
|
|
}
|
|
}
|
|
|
|
#ifdef DYNAMIC_RATIO_HISTORY
|
|
acb->IntHistory[acb->Hndx] = acb->handled_interrupts;
|
|
acb->RatioHistory[acb->Hndx] = (UCHAR)acb->RcvIntRatio;
|
|
|
|
if ( ++acb->Hndx >= 1024 )
|
|
{
|
|
acb->Hndx = 0;
|
|
}
|
|
#endif
|
|
//
|
|
// The switchover value to turbo gets incremented each time
|
|
// we drop to normal mode. We reset this value every x seconds.
|
|
// This will prevent the driver from toggling rapidly between
|
|
// turbo <-> normal mode.
|
|
//
|
|
if ( ++acb->cleartime > 50 )
|
|
{
|
|
acb->sw24 = sw24;
|
|
acb->cleartime = 0;
|
|
}
|
|
|
|
#endif // !NEW_DYNAMIC_RATIO
|
|
|
|
#ifdef ALLOW_DISABLE_DYNAMIC_RATIO
|
|
}
|
|
else
|
|
{
|
|
|
|
#ifdef XMIT_INTS
|
|
acb->XmitIntRatio = ratio;
|
|
#endif
|
|
acb->RcvIntRatio = ratio;
|
|
}
|
|
#endif // ALLOW_DISABLE_DYNAMIC_RATIO
|
|
|
|
acb->acb_gen_objs.interrupt_count = acb->handled_interrupts;
|
|
acb->handled_interrupts = 0;
|
|
}
|
|
|
|
//
|
|
// Set the timer...
|
|
//
|
|
NdisMSetTimer(&acb->DpcTimer, 10);
|
|
|
|
} // NetFlexDeferredTimer
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexHandleInterrupt
|
|
//
|
|
// Description:
|
|
// This routine is the deferred processing
|
|
// routine for all adapter interrupts.
|
|
//
|
|
// Input:
|
|
// acb - Our Driver Context for this adapter or head.
|
|
//
|
|
// Output:
|
|
// None
|
|
//
|
|
// Called By:
|
|
// Miniport Wrapper
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID
|
|
NetFlexHandleInterrupt(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
{
|
|
USHORT sifint_reg;
|
|
USHORT tmp_reg;
|
|
USHORT ReceivesProcessed = 0;
|
|
|
|
PACB acb = (PACB) MiniportAdapterContext;
|
|
|
|
//
|
|
// Read the SifInt
|
|
//
|
|
NdisRawReadPortUshort( acb->SifIntPort, &sifint_reg);
|
|
|
|
while (sifint_reg & SIFINT_SYSINT)
|
|
{
|
|
//
|
|
// Ack the interrupt
|
|
//
|
|
sifint_reg &= ~SIFINT_SYSINT;
|
|
NdisRawWritePortUshort( acb->SifIntPort, sifint_reg);
|
|
|
|
//
|
|
// mask off the int code
|
|
//
|
|
sifint_reg &= INT_CODES;
|
|
|
|
//
|
|
// See if there are any recieves to do...
|
|
//
|
|
if (acb->acb_rcv_head->RCV_CSTAT & RCSTAT_COMPLETE)
|
|
{
|
|
//
|
|
// Increment the interrupt count.
|
|
//
|
|
acb->acb_int_count++;
|
|
|
|
//
|
|
// yes, do them...
|
|
//
|
|
acb->handled_interrupts++;
|
|
ReceivesProcessed += acb->ProcessReceiveHandler(acb);
|
|
}
|
|
|
|
//
|
|
// See if there are any transmits to do...
|
|
//
|
|
NetFlexProcessXmit(acb);
|
|
|
|
switch (sifint_reg)
|
|
{
|
|
case INT_SCBCLEAR:
|
|
acb->acb_scbclearout = FALSE;
|
|
//
|
|
// Is the SCB really clear?
|
|
//
|
|
// If the SCB is clear, send a SCB command off now.
|
|
// Otherwise, if we are not currently waiting for an SCB clear
|
|
// interrupt, signal the adapter to send us a SCB clear interrupt
|
|
// when it is done with the SCB.
|
|
//
|
|
if (acb->acb_scb_virtptr->SCB_Cmd == 0)
|
|
{
|
|
NetFlexSendNextSCB(acb);
|
|
}
|
|
else if ((acb->acb_xmit_whead) ||
|
|
(acb->acb_rcv_whead) ||
|
|
(acb->acb_scbreq_next))
|
|
{
|
|
acb->acb_scbclearout = TRUE;
|
|
NdisRawWritePortUshort(
|
|
acb->SifIntPort,
|
|
(USHORT)SIFINT_SCBREQST);
|
|
}
|
|
break;
|
|
|
|
case INT_COMMAND:
|
|
NetFlexCommand(acb);
|
|
|
|
//
|
|
// Do we have any commands to complete?
|
|
//
|
|
if (acb->acb_confirm_qhead != NULL)
|
|
{
|
|
NetFlexProcessMacReq(acb);
|
|
}
|
|
break;
|
|
|
|
case INT_ADPCHECK:
|
|
//
|
|
// Read the Adapter Check Status @ 1.05e0
|
|
//
|
|
NdisRawWritePortUshort(acb->SifAddrxPort, (USHORT) 1);
|
|
NdisRawWritePortUshort(acb->SifAddrPort, (USHORT) 0x5e0);
|
|
NdisRawReadPortUshort( acb->SifDIncPort, &tmp_reg);
|
|
|
|
DebugPrint(1,("NF(%d): Adapter Check - 0x%x\n",acb->anum,tmp_reg));
|
|
|
|
//
|
|
// Reset has failed, errorlog an entry.
|
|
//
|
|
|
|
NdisWriteErrorLogEntry( acb->acb_handle,
|
|
EVENT_NDIS_ADAPTER_CHECK_ERROR,
|
|
2,
|
|
NETFLEX_ADAPTERCHECK_ERROR_CODE,
|
|
tmp_reg );
|
|
|
|
//
|
|
// Set the variables up showing that the hardware has an unrecoverable
|
|
// error.
|
|
//
|
|
acb->acb_state = AS_HARDERROR;
|
|
break;
|
|
|
|
case INT_RINGSTAT:
|
|
NetFlexRingStatus(acb);
|
|
break;
|
|
|
|
case INT_RECEIVE:
|
|
break;
|
|
|
|
case INT_TRANSMIT:
|
|
//
|
|
// If we reached the end of the xmit lists,
|
|
// then the xmit status will indicate COMMAND_COMPLETE.
|
|
// The transmiter will be stalled until another transmit
|
|
// command is issued with a valid list.
|
|
//
|
|
if (acb->acb_ssb_virtptr->SSB_Status & XSTAT_LERROR)
|
|
{
|
|
//
|
|
// We have a list error...
|
|
//
|
|
NetFlexTransmitStatus(acb);
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Issue a ssb clear. After this we may see SIFCMD interrupts.
|
|
//
|
|
NdisRawWritePortUshort(acb->SifIntPort, SIFINT_SSBCLEAR);
|
|
|
|
//
|
|
// Read the SifInt
|
|
//
|
|
NdisRawReadPortUshort(acb->SifIntPort, &sifint_reg);
|
|
}
|
|
|
|
//
|
|
// Processed any receives which need IndicateReceiveComplete?
|
|
//
|
|
if (ReceivesProcessed)
|
|
{
|
|
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
|
|
{
|
|
// Token Ring
|
|
//
|
|
NdisMTrIndicateReceiveComplete(acb->acb_handle);
|
|
}
|
|
else
|
|
{
|
|
// Ethernet
|
|
//
|
|
NdisMEthIndicateReceiveComplete(acb->acb_handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexRingStatus
|
|
//
|
|
// Description:
|
|
// This routine does the clean up work necessary
|
|
// when a ring status occurs.
|
|
//
|
|
// Input:
|
|
// acb - Our Driver Context for this adapter or head.
|
|
//
|
|
// Output:
|
|
// None
|
|
//
|
|
// Called By:
|
|
// NetFlexHandleInterrupt
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID
|
|
NetFlexRingStatus(
|
|
PACB acb
|
|
)
|
|
{
|
|
USHORT value;
|
|
ULONG RingStatus = 0;
|
|
|
|
value = acb->acb_ssb_virtptr->SSB_Status;
|
|
|
|
DebugPrint(1,("NF(%d): RingStatus value = %x\n",acb->anum, value));
|
|
|
|
//
|
|
// Determine the reason for the ring interrupt.
|
|
//
|
|
if (value & RING_STATUS_SIGNAL_LOSS)
|
|
{
|
|
RingStatus |= NDIS_RING_SIGNAL_LOSS;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_SIGNAL_LOSS\n",acb->anum));
|
|
|
|
//
|
|
// Have we already reported the error?
|
|
//
|
|
if (!acb->SentRingStatusLog &&
|
|
((acb->acb_lastringstatus & RING_STATUS_SIGNAL_LOSS) == 0))
|
|
{
|
|
// no, so send one.
|
|
NdisWriteErrorLogEntry( acb->acb_handle,
|
|
EVENT_NDIS_SIGNAL_LOSS_ERROR,
|
|
3,
|
|
NETFLEX_RINGSTATUS_ERROR_CODE,
|
|
(ULONG) acb->acb_baseaddr,
|
|
(ULONG) value
|
|
);
|
|
acb->SentRingStatusLog = TRUE;
|
|
}
|
|
}
|
|
|
|
if (value & RING_STATUS_HARD_ERROR)
|
|
{
|
|
RingStatus |= NDIS_RING_HARD_ERROR;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_HARD_ERROR\n",acb->anum));
|
|
}
|
|
if (value & RING_STATUS_SOFT_ERROR)
|
|
{
|
|
RingStatus |= NDIS_RING_SOFT_ERROR;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_SOFT_ERROR\n",acb->anum));
|
|
}
|
|
if (value & RING_STATUS_XMIT_BEACON)
|
|
{
|
|
RingStatus |= NDIS_RING_TRANSMIT_BEACON;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_XMIT_BEACON\n",acb->anum));
|
|
}
|
|
if (value & RING_STATUS_LOBE_WIRE_FAULT)
|
|
{
|
|
RingStatus |= NDIS_RING_LOBE_WIRE_FAULT;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_LOBE_WIRE_FAULT\n",acb->anum));
|
|
//
|
|
// Have we already reported the error?
|
|
//
|
|
if (!acb->SentRingStatusLog &&
|
|
((acb->acb_lastringstatus & NDIS_RING_LOBE_WIRE_FAULT) == 0))
|
|
{
|
|
// no, so send one.
|
|
NdisWriteErrorLogEntry( acb->acb_handle,
|
|
EVENT_NDIS_LOBE_FAILUE_ERROR,
|
|
3,
|
|
NETFLEX_RINGSTATUS_ERROR_CODE,
|
|
(ULONG) acb->acb_baseaddr,
|
|
(ULONG) value
|
|
);
|
|
|
|
acb->SentRingStatusLog = TRUE;
|
|
}
|
|
}
|
|
|
|
if (value & (RING_STATUS_AUTO_REMOVE_1 | RING_STATUS_REMOVE_RECEIVED))
|
|
{
|
|
if (value & RING_STATUS_AUTO_REMOVE_1)
|
|
{
|
|
RingStatus |= NDIS_RING_AUTO_REMOVAL_ERROR;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_AUTO_REMOVE_1\n",acb->anum));
|
|
}
|
|
if (value & RING_STATUS_REMOVE_RECEIVED)
|
|
{
|
|
RingStatus |= NDIS_RING_REMOVE_RECEIVED;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_REMOVE_RECEIVED\n",acb->anum));
|
|
}
|
|
//
|
|
// Have we already reported the error?
|
|
//
|
|
if ((acb->acb_lastringstatus &
|
|
(RING_STATUS_AUTO_REMOVE_1 | RING_STATUS_REMOVE_RECEIVED )) == 0)
|
|
{
|
|
// no, so send one.
|
|
NdisWriteErrorLogEntry( acb->acb_handle,
|
|
EVENT_NDIS_REMOVE_RECEIVED_ERROR,
|
|
3,
|
|
NETFLEX_RINGSTATUS_ERROR_CODE,
|
|
(ULONG) acb->acb_baseaddr,
|
|
(ULONG) value
|
|
);
|
|
}
|
|
}
|
|
|
|
if (value & RING_STATUS_OVERFLOW)
|
|
{
|
|
RingStatus |= NDIS_RING_COUNTER_OVERFLOW;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_OVERFLOW\n",acb->anum));
|
|
}
|
|
|
|
if (value & RING_STATUS_SINGLESTATION)
|
|
{
|
|
RingStatus |= NDIS_RING_SINGLE_STATION;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_SINGLESTATION\n",acb->anum));
|
|
}
|
|
|
|
if (value & RING_STATUS_RINGRECOVERY)
|
|
{
|
|
RingStatus |= NDIS_RING_RING_RECOVERY;
|
|
DebugPrint(1,("NF(%d): RING_STATUS_RINGRECOVERY\n",acb->anum));
|
|
}
|
|
|
|
//
|
|
// Save the Ring Status
|
|
//
|
|
acb->acb_lastringstatus = RingStatus;
|
|
|
|
|
|
//
|
|
// Indicate to the filter the ring status.
|
|
//
|
|
NdisMIndicateStatus(
|
|
acb->acb_handle,
|
|
NDIS_STATUS_RING_STATUS,
|
|
&RingStatus,
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
//
|
|
// Tell the filter that we have completed the ring status.
|
|
//
|
|
NdisMIndicateStatusComplete(acb->acb_handle);
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexCommand
|
|
//
|
|
// Description:
|
|
// This routine looks at the current SSB struct
|
|
// and places the corresponding request on the
|
|
// Request Confirm Queue. If the command that
|
|
// has completed is an open, a receive and
|
|
// transmit command are issued.
|
|
//
|
|
// Input:
|
|
// acb - Our Driver Context for this adapter or head.
|
|
//
|
|
// Output:
|
|
// None
|
|
//
|
|
// Called By:
|
|
// NetFlexHandleInterrupt
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID
|
|
NetFlexCommand(
|
|
PACB acb
|
|
)
|
|
{
|
|
PSCBREQ scbreq;
|
|
PMACREQ macreq;
|
|
PTR_OBJS trobjs;
|
|
PETH_OBJS ethobjs;
|
|
SHORT value,i;
|
|
PUSHORT tempptr;
|
|
NDIS_STATUS Status;
|
|
|
|
#if (DBG || DBGPRINT)
|
|
//
|
|
// I wanted to know if I'm getting bad commands
|
|
//
|
|
if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_CMDREJECT)
|
|
{
|
|
DebugPrint(0,("NF(%d): Command rejected\n",acb->anum));
|
|
DebugPrint(0,("NF(%d): SSB Status %x\n",acb->anum,SWAPS(acb->acb_ssb_virtptr->SSB_Status)));
|
|
DebugPrint(0,("NF(%d): SSB Ptr %x\n",acb->anum,SWAPL(acb->acb_ssb_virtptr->SSB_Ptr)));
|
|
}
|
|
else if (acb->acb_ssb_virtptr->SSB_Status != SSB_GOOD)
|
|
{
|
|
DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
|
|
DebugPrint(0,("NF(%d): cmd is %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Cmd));
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Get the scb request associated with the completed request.
|
|
//
|
|
Status = NetFlexDequeue_TwoPtrQ_Head(
|
|
(PVOID *)&(acb->acb_scbreq_head),
|
|
(PVOID *)&(acb->acb_scbreq_tail),
|
|
(PVOID *)&scbreq
|
|
);
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
DebugPrint(0,("NF(%d) NetFlexCommand - dequeue scbreq failed!\n",acb->anum));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If we have a Macreq to place on the confirm q. Do this now.
|
|
//
|
|
macreq = scbreq->req_macreq;
|
|
|
|
if (macreq)
|
|
{
|
|
//
|
|
// If the command had a problem, save the failure reason and
|
|
// exit out of the routine. Otherwise, save the success code
|
|
// and see if the completed command is an open or a read error log.
|
|
//
|
|
if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_CMDREJECT)
|
|
{
|
|
DebugPrint(0,("NF(%d): Command rejected\n",acb->anum));
|
|
DebugPrint(0,("NF(%d): SSB Status %x\n",acb->anum,SWAPS(acb->acb_ssb_virtptr->SSB_Status)));
|
|
DebugPrint(0,("NF(%d): SSB Ptr %x\n",acb->anum,SWAPL(acb->acb_ssb_virtptr->SSB_Ptr)));
|
|
macreq->req_status = NDIS_STATUS_FAILURE;
|
|
}
|
|
else if (acb->acb_ssb_virtptr->SSB_Status != SSB_GOOD)
|
|
{
|
|
DebugPrint(0,("NF(%d): Bad status %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Status));
|
|
DebugPrint(0,("NF(%d): cmd is %x\n",acb->anum,acb->acb_ssb_virtptr->SSB_Cmd));
|
|
|
|
if ((acb->acb_ssb_virtptr->SSB_Cmd == TMS_OPEN) &&
|
|
(acb->acb_ssb_virtptr->SSB_Status & SSB_OPENERR)
|
|
)
|
|
{
|
|
macreq->req_status = NDIS_STATUS_TOKEN_RING_OPEN_ERROR;
|
|
macreq->req_info = (PVOID)(acb->acb_ssb_virtptr->SSB_Status >> 8);
|
|
}
|
|
else
|
|
{
|
|
macreq->req_status = NDIS_STATUS_FAILURE;
|
|
}
|
|
}
|
|
else if (acb->acb_ssb_virtptr->SSB_Cmd == TMS_READLOG)
|
|
{
|
|
acb->acb_logbuf_valid = TRUE;
|
|
//
|
|
// Fill in the appropriate fields with the information
|
|
// given by the log buffer.
|
|
//
|
|
if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_5)
|
|
{
|
|
// TOKEN RING
|
|
trobjs = (PTR_OBJS)(acb->acb_spec_objs);
|
|
trobjs->REL_Congestion += ((PREL)(acb->acb_logbuf_virtptr))->REL_Congestion;
|
|
trobjs->REL_LineError += ((PREL)(acb->acb_logbuf_virtptr))->REL_LineError;
|
|
trobjs->REL_LostError += ((PREL)(acb->acb_logbuf_virtptr))->REL_LostError;
|
|
trobjs->REL_BurstError += ((PREL)(acb->acb_logbuf_virtptr))->REL_BurstError;
|
|
trobjs->REL_ARIFCIError += ((PREL)(acb->acb_logbuf_virtptr))->REL_ARIFCIError;
|
|
trobjs->REL_Congestion += ((PREL)(acb->acb_logbuf_virtptr))->REL_Congestion;
|
|
trobjs->REL_CopiedError += ((PREL)(acb->acb_logbuf_virtptr))->REL_CopiedError;
|
|
trobjs->REL_TokenError += ((PREL)(acb->acb_logbuf_virtptr))->REL_TokenError;
|
|
}
|
|
else
|
|
{
|
|
// ETHERNET
|
|
ethobjs = (PETH_OBJS)(acb->acb_spec_objs);
|
|
ethobjs->RSL_AlignmentErr = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_AlignmentErr);
|
|
ethobjs->RSL_1_Collision = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_1_Collision);
|
|
ethobjs->RSL_FrameCheckSeq = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_FrameCheckSeq);
|
|
ethobjs->RSL_DeferredXmit = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_DeferredXmit);
|
|
ethobjs->RSL_LateCollision = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_LateCollision);
|
|
ethobjs->RSL_Excessive = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_Excessive);
|
|
ethobjs->RSL_CarrierErr = (USHORT)SWAPS(((PRSL)(acb->acb_logbuf_virtptr))->RSL_CarrierErr);
|
|
tempptr = (PUSHORT)&(((PRSL)(acb->acb_logbuf_virtptr))->RSL_2_Collision);
|
|
value = 0;
|
|
for (i = 0; i < 14; i++)
|
|
{
|
|
value += SWAPS( *(tempptr+i) );
|
|
}
|
|
ethobjs->RSL_More_Collision = value;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Take the Mac request off the macreq queue and place it on
|
|
// the confirm queue so that the command can be completed.
|
|
//
|
|
NetFlexDequeue_TwoPtrQ(
|
|
(PVOID *)&(acb->acb_macreq_head),
|
|
(PVOID *)&(acb->acb_macreq_tail),
|
|
(PVOID)macreq
|
|
);
|
|
|
|
NetFlexEnqueue_TwoPtrQ_Tail(
|
|
(PVOID *)&(acb->acb_confirm_qhead),
|
|
(PVOID *)&(acb->acb_confirm_qtail),
|
|
(PVOID)macreq
|
|
);
|
|
} // if (macreq)
|
|
|
|
//
|
|
// Free up the SCB request associated with this command.
|
|
//
|
|
scbreq->req_macreq = NULL;
|
|
|
|
NetFlexEnqueue_OnePtrQ_Head(
|
|
(PVOID *)&(acb->acb_scbreq_free),
|
|
(PVOID)scbreq
|
|
);
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexEnableInterrupt
|
|
//
|
|
// Description:
|
|
// This routine is used to enable the adapter to
|
|
// interrupt the system.
|
|
//
|
|
// Input:
|
|
// Context - Our Driver Context for this adapter or head.
|
|
//
|
|
// Output:
|
|
// None
|
|
//
|
|
// Called By:
|
|
// Miniport Wrapper
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID
|
|
NetFlexEnableInterrupt(
|
|
IN NDIS_HANDLE Context
|
|
)
|
|
{
|
|
USHORT actl_reg;
|
|
PACB acb = (PACB) Context;
|
|
|
|
DebugPrint(3,("NF(%d)(E)\n",acb->anum));
|
|
//
|
|
// Enable System Interrupts
|
|
//
|
|
actl_reg = acb->actl_reg | ACTL_SINTEN;
|
|
|
|
NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
|
|
|
|
acb->InterruptsDisabled = FALSE;
|
|
}
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Routine Name: NetFlexDisableInterrupt
|
|
//
|
|
// Description:
|
|
// This routine is used to disable the adapter from being
|
|
// able to interrupt the system.
|
|
//
|
|
// Input:
|
|
// Context - Our Driver Context for this adapter or head.
|
|
//
|
|
// Output:
|
|
// None
|
|
//
|
|
// Called By:
|
|
// Miniport Wrapper
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
VOID
|
|
NetFlexDisableInterrupt(
|
|
IN NDIS_HANDLE Context
|
|
)
|
|
{
|
|
USHORT actl_reg;
|
|
PACB acb = (PACB) Context;
|
|
|
|
//
|
|
// Disable System Interrupts
|
|
//
|
|
actl_reg = acb->actl_reg & ~ACTL_SINTEN;
|
|
|
|
NdisRawWritePortUshort(acb->SifActlPort, actl_reg);
|
|
|
|
acb->InterruptsDisabled = TRUE;
|
|
|
|
DebugPrint(3,("NF(%d)(D)\n",acb->anum));
|
|
}
|