Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1501 lines
39 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
interrup.c
Abstract:
This module contains the interrupt-processing code for the
TOK162 NDIS 3.0 driver.
Author:
Kevin Martin (KevinMa) 26-Jan-1994
Environment:
Kernel Mode.
Revision History:
--*/
#include <tok162sw.h>
VOID
TOK162ProcessReceiveInterrupts(
IN PTOK162_ADAPTER Adapter
);
VOID
TOK162ProcessCommandInterrupts(
IN PTOK162_ADAPTER Adapter
);
VOID
TOK162Isr(
OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueDpc,
IN PVOID Context
)
/*++
Routine Description:
Interrupt service routine for the TOK162. Used only during init.
The NdisMRegisterInterrupt() call (reset.c) specified not to call the
ISR for every interrupt. The DPC is called directly instead.
Arguments:
Interrupt - Interrupt object for the TOK162.
Context - Really a pointer to the adapter.
Return Value:
Returns true if the interrupt really was from the TOK162 and whether the
wrapper should queue a DPC.
--*/
{
//
// Holds the pointer to the adapter structure.
//
PTOK162_ADAPTER Adapter = Context;
//
// Holds IsrpHigh with some bits masked off.
//
USHORT Sif;
//
// Indicate that an interrupt has occurred
//
VERY_LOUD_DEBUG(DbgPrint("TOK162E!ISR\n");)
//
// Read the adapter interrupt register
//
READ_ADAPTER_USHORT(Adapter,PORT_OFFSET_STATUS,&Sif);
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!SIF = %x\n",Sif);)
//
// Check if this is our interrupt. If it is, set flag indicating that the
// interrupt is recognized. Otherwise indicate that the interrupt is not
// ours.
//
if ((Sif & STATUS_SYSTEM_INTERRUPT) != 0) {
*InterruptRecognized = TRUE;
} else {
*InterruptRecognized = FALSE;
}
//
// Mask off the interrupt type portion of the register.
//
Sif = (UCHAR) (Sif & STATUS_INT_CODE_MASK);
//
// If we have a command, then it is the open or an error has occurred.
// Indicate that the Ssb can be cleared after the open info has been
// obtained.
//
if (Sif == STATUS_INT_CODE_CMD_STATUS) {
TOK162UpLoadSsb(Adapter);
Adapter->SsbCommand = Adapter->Ssb->Command;
Adapter->SsbStatus1 = Adapter->Ssb->Status1;
if (Adapter->SsbCommand == CMD_DMA_OPEN) {
Adapter->InitialOpenComplete = TRUE;
}
}
//
// Enable updating of the SSB
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
ENABLE_SSB_UPDATE
);
*QueueDpc = FALSE;
}
VOID
TOK162DeferredTimer(
IN PVOID SystemSpecific1,
IN PTOK162_ADAPTER Adapter,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
/*++
Routine Description:
Just an entry point to distinguish between a timer call and the wrapper
calling the DPC directly.
Arguments:
Adapter - pointer to current adapter
The rest are not used, but simply passed on
Return Value:
None
--*/
{
//
// Indicate that a timer has expired.
//
VERY_LOUD_DEBUG(DbgPrint("TOK162E!Deferred Timer called\n");)
//
// Call the standard DPC handler.
//
TOK162HandleInterrupt(Adapter);
}
VOID
TOK162HandleInterrupt(
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
Main routine for processing interrupts.
Arguments:
Adapter - The Adapter to process interrupts for.
Return Value:
None.
--*/
{
//
// Pointer to the TOK162 adapter structure.
//
PTOK162_ADAPTER Adapter = ((PTOK162_ADAPTER)MiniportAdapterContext);
//
// Holds the value of the status register
//
USHORT IMask = 0;
//
// Holds the interrupt type value
//
USHORT IType = 0;
//
// Hold value to write to adapter for receives/transmits
//
USHORT RcvXmtContinue;
//
// Boolean to indicate receive processing
//
BOOLEAN DoReceives;
//
// Boolean to indicate transmit processing
//
BOOLEAN DoTransmits;
//
// If any receive interrupts are processed, we have to indicate that
// the receive work has been completed after all interrupts have been
// processed.
//
BOOLEAN IndicateReceiveComplete = FALSE;
//
// Indicate that the DPC routine has been called.
//
EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!DPC was just called\n");)
//
// Loop through processing interrupts until we have processed them all.
//
while (TRUE) {
//
// Assume no transmits or receives
//
DoReceives = FALSE;
DoTransmits = FALSE;
//
// Read the adapter interrupt register
//
READ_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
&IMask
);
//
// If this is not our interrupt, end DPC processing
//
if ((IMask & STATUS_SYSTEM_INTERRUPT) == 0) {
break;
}
//
// Figure out the interrupt according to the spec.
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
CMD_PIO_RESET_RCV_XMT
);
//
// Read the adapter interrupt register again
//
READ_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
&IMask
);
//
// Get the Ssb from the Adapter
//
TOK162UpLoadSsb(Adapter);
//
// Record pertinent information about the interrupt as this
// card/chipset only allows one interrupt to be indicated by
// the card at a time.
//
Adapter->SsbCommand = Adapter->Ssb->Command;
Adapter->SsbStatus1 = Adapter->Ssb->Status1;
Adapter->SsbStatus2 = Adapter->Ssb->Status2;
Adapter->SsbStatus3 = Adapter->Ssb->Status3;
IType = (UCHAR) (IMask & STATUS_INT_CODE_MASK);
//
// Indicate the type of interrupt to the debugger.
//
EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!New IMask is %x\n",IMask);)
//
// Process the interrupt based on the type of interrupt.
//
switch(IType) {
//
// Ring state or command interrupt
//
case STATUS_INT_CODE_RING:
case STATUS_INT_CODE_CMD_STATUS:
if(IType == STATUS_INT_CODE_RING) {
//
// If we have a soft error, it is possible that the
// card has become overrun with receives. Therefore, the
// TOK162ProcessRingInterrupts will return TRUE in this
// case to allow us to call ProcessReceiveInterrupts().
// In all other cases, TOK162ProcessRingInterrupts() will
// return FALSE.
//
if (TOK162ProcessRingInterrupts(Adapter) == TRUE) {
DoReceives = TRUE;
}
} else {
//
// If there is a command structure that has been sent to the
// adapter, then we will process that command. Otherwise, we
// simply return.
//
if (Adapter->CommandOnCard != NULL) {
//
// Process the active command.
//
TOK162ProcessCommandInterrupts(Adapter);
}
}
//
// Read the adapter interrupt register again
//
READ_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
&IMask
);
//
// Dismiss the interrupt, allowing the SSB to be updated.
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
ENABLE_SSB_UPDATE
);
//
// Were there any receive interrupts indicated
//
if ((IMask & STATUS_RECEIVE_FRAME_COMPLETE) == 0) {
DoReceives = TRUE;
}
//
// Were there any transmit interrupts indicated
//
if ((IMask & STATUS_TRANSMIT_FRAME_COMPLETE) == 0) {
DoTransmits = TRUE;
}
break;
case STATUS_INT_CODE_FRAME_STATUS:
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
CMD_PIO_RESET_RCV_XMT
);
//
// Read the adapter interrupt register again
//
READ_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
&IMask
);
//
// Were there any receive interrupts indicated
//
if ((IMask & STATUS_RECEIVE_FRAME_COMPLETE) == 0) {
DoReceives = TRUE;
}
//
// Were there any transmit interrupts indicated
//
if ((IMask & STATUS_TRANSMIT_FRAME_COMPLETE) == 0) {
DoTransmits = TRUE;
}
break;
}
//
// Reset value to be sent out
//
RcvXmtContinue = 0;
//
// Do the continue on the card.
//
if ((DoReceives == TRUE) && (DoTransmits == TRUE)) {
RcvXmtContinue = CMD_PIO_RECEIVE_COMPLETE |
CMD_PIO_TRANSMIT_COMPLETE |
CMD_PIO_RESET_SYSTEM;
} else if (DoReceives == TRUE) {
RcvXmtContinue = CMD_PIO_RECEIVE_COMPLETE |
CMD_PIO_RESET_SYSTEM;
} else if (DoTransmits == TRUE) {
RcvXmtContinue = CMD_PIO_TRANSMIT_COMPLETE |
CMD_PIO_RESET_SYSTEM;
}
if (RcvXmtContinue != 0) {
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
RcvXmtContinue
);
}
//
// Check to see if we have a receive
//
if (DoReceives == TRUE) {
//
// Process the receive
//
TOK162ProcessReceiveInterrupts(Adapter);
}
//
// Check to see if we have a transmit
//
if (DoTransmits == TRUE) {
//
// Process the transmit(s)
//
TOK162ProcessTransmitInterrupts(Adapter);
}
}
//
// If we processed any receive interrupts, IndicateReceiveComplete() will
// be set to TRUE. In this case, we need to indicate that all receives
// are complete.
//
if (Adapter->DoReceiveComplete) {
//
// Indicate to the debugger that we are doing the complete.
//
EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Doing the indicate complete on the receive\n");)
//
// Call the Token Ring Filter to indicate the receive complete.
//
NdisMTrIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
Adapter->DoReceiveComplete = FALSE;
}
//
// Indicate to the debugger that we are ending DPC processing.
//
EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Ending DPC processing\n");)
}
VOID
TOK162ProcessReceiveInterrupts(
IN PTOK162_ADAPTER Adapter
)
/*++
Routine Description:
Process the packets that have finished receiving.
NOTE: This routine assumes that no other thread of execution
is processing receives!
Arguments:
Adapter - The adapter to indicate to.
Return Value:
Whether to clear interrupt or not
--*/
{
//
// We don't get here unless there was a receive. Loop through
// the receive blocks starting at the last known block owned by
// the hardware.
//
// After we find a packet we give the routine that process the
// packet through the filter, the buffers virtual address (which
// is always the lookahead size) and as the MAC Context the
// index to the receive block.
//
//
// Pointer to the receive block being examined.
//
PTOK162_SUPER_RECEIVE_LIST CurrentEntry = Adapter->ReceiveQueueCurrent;
//
// Used during receiveindicate to let the filter know the header size
// of the given buffer.
//
USHORT HeaderSize;
//
// Used to indicate the total size of the frame to the filter.
//
USHORT FrameSize;
//
// Points to the beginning of the received buffer. Used to determine the
// size of the frame header (source routing).
//
PUCHAR Temp;
//
// Log the fact that we are processing a receive.
//
IF_LOG('m');
//
// Continue processing receives until we have exhausted them.
//
while (TRUE) {
IF_LOG('k');
//
// Get the receive list info from the card for the current entry
//
TOK162UpLoadReceiveList(Adapter,CurrentEntry);
IF_LOG('K');
//
// Send the receive status byte to the debugger.
//
EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Receive CSTAT == %x\n",
CurrentEntry->Hardware.CSTAT);)
//
// Check to see if CSTAT has been changed indicating
// the receive entry has been modified
//
if (((CurrentEntry->Hardware.CSTAT & RECEIVE_CSTAT_VALID) == 0) &&
((CurrentEntry->Hardware.CSTAT & 0x4000) != 0)) {
CURRENT_DEBUG(DbgPrint("IBMTOK2E!Receive DPC\n");)
//
// Make sure the adapter and the system are in synch.
//
NdisFlushBuffer(CurrentEntry->FlushBuffer, FALSE);
//
// Get a pointer to the first byte of the current receive buffer.
//
Temp = (PUCHAR)CurrentEntry->ReceiveBuffer;
//
// If the source routing bit is on, figure out the size of the
// MAC Frame header. Otherwise, the size is set to the default
// of 14 (decimal).
//
HeaderSize = 14;
if (Temp[8] & 0x80) {
//
// Source routing bit is on in source address, so calculate
// the frame header size.
//
HeaderSize = (Temp[14] & 0x1f) + 14;
}
//
// Save the received header size.
//
Adapter->SizeOfReceivedHeader = HeaderSize;
//
// Record the fact that we had a good receive.
//
Adapter->GoodReceives++;
//
// Get the frame size of this buffer.
//
FrameSize = CurrentEntry->Hardware.FrameSize;
//
// Indicate the frame size to the debugger
//
EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Frame size is %u\n",
FrameSize);)
//
// If the frame that we have been passed has an invalid length
// (less than the reported header size) then we need to check
// if the frame size is larger than the default address length.
//
if (FrameSize >= HeaderSize) {
//
// We have a 'normal' packet. Indicate this to the debugger
//
EXTRA_LOUD_DEBUG(DbgPrint("IBMTOK2E!Doing receive indicate\n");)
//
// Do the indication to the filter.
//
NdisMTrIndicateReceive(
Adapter->MiniportAdapterHandle,
(NDIS_HANDLE)(
((PUCHAR)(CurrentEntry->ReceiveBuffer))+HeaderSize),
CurrentEntry->ReceiveBuffer,
(UINT)HeaderSize,
((PUCHAR)CurrentEntry->ReceiveBuffer) + HeaderSize,
FrameSize - HeaderSize,
FrameSize - HeaderSize
);
Adapter->DoReceiveComplete = TRUE;
} else {
//
// If the frame size is greater than or equal to the length
// of an address (network address, 12 bytes) then we can
// indicate it as a runt packet to the filter. Otherwise,
// we ignore the received buffer.
//
if (FrameSize >= TOK162_LENGTH_OF_ADDRESS) {
//
// Indicate this is a runt packet to the debugger
//
VERY_LOUD_DEBUG(DbgPrint(
"IBMTOK2E!Doing receive indicate for a runt\n");)
//
// Indicate the packet to the filter.
//
NdisMTrIndicateReceive(
Adapter->MiniportAdapterHandle,
(NDIS_HANDLE)(
((PUCHAR)(CurrentEntry->ReceiveBuffer)) + HeaderSize),
(PUCHAR)Temp,
(UINT)FrameSize,
NULL,
0,
0
);
Adapter->DoReceiveComplete = TRUE;
}
}
//
// Mark the receive list as processed and able to receive another
// buffer.
//
CurrentEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
//
// Reset the buffer size
//
CurrentEntry->Hardware.FrameSize = Adapter->ReceiveBufferSize;
//
// Download the receive list to the card (updated)
//
TOK162DownLoadReceiveList(Adapter,CurrentEntry);
//
// Move to the next entry to see if there are more to process.
//
CurrentEntry = CurrentEntry->NextEntry;
//
// Tell adapter we are accepting more receives
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ENABLE_RECEIVE_VALID
);
} else {
//
// Record the receive list entry following the last good
// entry as the starting point for the next time receives
// are processed.
//
Adapter->ReceiveQueueCurrent = CurrentEntry;
//
// Log that we are leaving the receive processing
//
IF_LOG('M');
//
// Tell adapter we are accepting more receives
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ENABLE_RECEIVE_VALID
);
return;
}
}
}
VOID
TOK162ProcessCommandInterrupts(
IN PTOK162_ADAPTER Adapter
)
/*++
Routine Description:
Process the Command Complete interrupts.
NOTE: This routine assumes that it is being executed in a
single thread of execution.
Arguments:
Adapter - The adapter that was sent from.
Return Value:
None.
--*/
{
//
// Pointer to command block being processed.
//
PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->CommandOnCard;
//
// Status variable
//
NDIS_STATUS Status;
//
// NetCard Address Block
//
PTOK162_ADDRESSBLOCK Addresses;
//
// Process the command based on the command code.
//
switch(CurrentCommandBlock->Hardware.CommandCode) {
case CMD_DMA_READ:
//
// We are processing a read command. The read command is
// generated by a query request.
//
// Indicate we are processing a read command to the
// debugger.
//
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!DPC for read adapter called\n");)
// Get a pointer to the block of memory set aside for the
// read command.
//
Addresses = (PTOK162_ADDRESSBLOCK)Adapter->AdapterBuf;
//
// Check the Oid to see if we are after the permanent card
// address or the current addresses.
//
if (Adapter->Oid == OID_802_5_PERMANENT_ADDRESS) {
//
// Update the permanent node address
//
NdisMoveMemory(
Adapter->NetworkAddress,
Addresses->NodeAddress,
6
);
} else {
//
// Update the current network address
//
NdisMoveMemory(
(UNALIGNED PUCHAR)Adapter->CurrentAddress,
Addresses->NodeAddress,
6
);
//
// Update the current group address
//
NdisMoveMemory(
(UNALIGNED PUCHAR)&(Adapter->GroupAddress),
Addresses->GroupAddress,
4
);
//
// The address on the card is "backwards" and must be
// byte-swapped and word-swapped for us to store.
//
Adapter->GroupAddress =
BYTE_SWAP_ULONG((ULONG)(Adapter->GroupAddress));
//
// Update the current functional address
//
NdisMoveMemory(
(UNALIGNED PUCHAR)&(Adapter->FunctionalAddress),
Addresses->FunctionalAddress,
4
);
//
// The address on the card is "backwards" and must be
// byte-swapped and word-swapped for us to store.
//
Adapter->FunctionalAddress =
BYTE_SWAP_ULONG(Adapter->FunctionalAddress);
}
//
// Finish the query and relenquish the command block
//
TOK162FinishQueryInformation(Adapter);
TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
break;
case CMD_DMA_OPEN:
//
// An open command is generated during a reset command. The
// initial open is called during adapter initialization and
// no DPC is generated.
//
// Indicate we are processing an open to the debugger.
//
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Processing the open command.\n");)
//
// Check to see if the open succeeded.
//
if ((Adapter->SsbStatus1 & OPEN_COMPLETION_MASK_RESULT)
!= OPEN_RESULT_ADAPTER_OPEN) {
//
// The open failed. Set the current ring state and set the
// return variable to NDIS_STATUS_FAILURE.
//
Adapter->CurrentRingState = NdisRingStateOpenFailure;
Status = NDIS_STATUS_FAILURE;
//
// Indicate to the wrapper the result of the open/receive for
// the original reset request.
//
TOK162DoResetIndications(Adapter, Status);
//
// Display the error code on the debugger.
//
VERY_LOUD_DEBUG(DbgPrint(
"IBMTOK2E!Error on the open - %x\n",Adapter->SsbStatus1);)
} else {
//
// The open succeeded. Set the current ring state and set the
// return variable to NDIS_STATUS_SUCCESS.
//
Adapter->CurrentRingState = NdisRingStateOpened;
Status = NDIS_STATUS_SUCCESS;
//
// Indicate to the wrapper the result of the open/receive for
// the original reset request.
//
TOK162DoResetIndications(Adapter, Status);
//
// Now send out the receive command. Display the fact that
// DoReceive is being called on the debugger.
//
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!Doing the receive\n");)
//
// Check if the receive command succeeded. If not, set the
// return variable to NDIS_STATUS_FAILURE. It is currently
// set to NDIS_STATUS_SUCCESS, so no change is necessary
// if the receive command succeeds.
//
if (DoTheReceive(Adapter) == FALSE) {
Status = NDIS_STATUS_FAILURE;
}
}
//
// Relinquish the command block associcated with this open.
//
TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
break;
case CMD_DMA_READ_ERRLOG:
LOUD_DEBUG(DbgPrint("IBMTOK2E!DPC for read errorlog called\n");)
//
// Record the values for the error counters
//
Adapter->ReceiveCongestionError +=
Adapter->ErrorLog->ReceiveCongestionError;
Adapter->LineError += Adapter->ErrorLog->LineError;
Adapter->LostFrameError += Adapter->ErrorLog->LostFrameError;
Adapter->BurstError += Adapter->ErrorLog->BurstError;
Adapter->FrameCopiedError += Adapter->ErrorLog->FrameCopiedError;
Adapter->TokenError += Adapter->ErrorLog->TokenError;
Adapter->InternalError += Adapter->ErrorLog->InternalError;
Adapter->ARIFCIError += Adapter->ErrorLog->ARIFCIError;
Adapter->AbortDelimeter += Adapter->ErrorLog->AbortDelimeter;
Adapter->DMABusError += Adapter->ErrorLog->DMABusError;
//
// Indicate the values to the debugger
//
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!CongestionErrors = %u\n",
Adapter->ErrorLog->ReceiveCongestionError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!LineErrors = %u\n",
Adapter->ErrorLog->LineError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!LostFrameErrors = %u\n",
Adapter->ErrorLog->LostFrameError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!BurstErrors = %u\n",
Adapter->ErrorLog->BurstError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!FrameCopiedErrors = %u\n",
Adapter->ErrorLog->FrameCopiedError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!TokenErrors = %u\n",
Adapter->ErrorLog->TokenError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!InternalErrors = %u\n",
Adapter->ErrorLog->InternalError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!ARIFCIErrors = %u\n",
Adapter->ErrorLog->ARIFCIError);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!AbortDelimeters = %u\n",
Adapter->ErrorLog->AbortDelimeter);)
VERY_LOUD_DEBUG(DbgPrint("IBMTOK2E!DMABusErrors = %u\n",
Adapter->ErrorLog->DMABusError);)
//
//
//
if (Adapter->RequestInProgress) {
TOK162FinishQueryInformation(Adapter);
}
//
// Relinquish the command block associated with this
// readadapterlog.
//
TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
break;
default:
//
// Did this command come from a set information request?
//
if (CurrentCommandBlock->Set) {
//
// Relinquish the command block.
//
TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
//
// Mark the current request state as complete.
//
Adapter->RequestInProgress = FALSE;
//
// Inform the wrapper the request has been completed.
//
NdisMSetInformationComplete(
Adapter->MiniportAdapterHandle,
NDIS_STATUS_SUCCESS);
//
// Not from a set. If this is the unique case of where a group
// address and a functional address had to be set to satisfy a
// packet filter change command (two commands for one), then we
// will only do an indication on the last one. The first one,
// however, still needs to have the command block associated
// with it relinquished.
//
} else if ((CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_GRP_ADDR) ||
(CurrentCommandBlock->Hardware.CommandCode == CMD_DMA_SET_FUNC_ADDR)) {
TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
}
break;
}
}
VOID
TOK162ProcessTransmitInterrupts(
IN PTOK162_ADAPTER Adapter
)
/*++
Routine Description:
Process the Transmit Complete interrupts.
NOTE: This routine assumes that it is being executed in a
single thread of execution.
Arguments:
Adapter - The adapter the transmit was sent from.
Return Value:
None.
--*/
{
//
// Pointer to the transmit list started this transmission.
//
PTOK162_SUPER_TRANSMIT_LIST Transmit;
//
// Pointer to the packet that started this transmission.
//
PNDIS_PACKET Packet;
//
// Holds CSTAT variable for transmit
//
USHORT Cstat;
//
// Status variable
//
NDIS_STATUS Status;
//
// Log that we entered transmit dpc processing
//
IF_LOG('a');
//
// Loop until we are done
//
while (TRUE) {
Transmit = Adapter->ActiveTransmitHead;
if(Transmit == NULL) {
//
// Log that we are leaving due to no more transmits to process
//
IF_LOG('A');
return;
}
//
// We are processing another transmit
//
IF_LOG('B');
//
// Get the result of the transmit
//
//
// First set the address register on the card to point to correct
// transmit list.
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_ADDRESS,
(Transmit->FirstEntry * 8) + COMMUNICATION_XMT_OFFSET + 6
);
//
// Now read the Transmit List CSTAT
//
READ_ADAPTER_USHORT(Adapter,
PORT_OFFSET_DATA,
&Cstat
);
//
// Display the completion status for the transmit entry on the debugger.
//
VERY_LOUD_DEBUG(DbgPrint(
"IBMTOK2E!Csat for the transmit is %x\n",Cstat);)
//
// If the valid bit is not zero, leave
//
if ((Cstat & TRANSMIT_CSTAT_VALID) != 0) {
//
// Restart the transmits
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ENABLE_TRANSMIT_VALID
);
//
// Log valid bit not zero
//
IF_LOG('P');
return;
}
//
// If the frame is not complete (no bit set), return.
//
if ((Cstat & TRANSMIT_CSTAT_FRAME_COMPLETE) == 0) {
//
// Restart the transmits
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ENABLE_TRANSMIT_VALID
);
//
// Log frame complete bit not set
//
IF_LOG('Q');
return;
}
//
// Get packet info.
//
Packet = Transmit->Packet;
//
// Give up the current transmit
//
//
// Increase the number of available transmit blocks
//
Adapter->NumberOfAvailableTransmitBlocks++;
//
// Move the active pointer to the next active transmit
//
Adapter->ActiveTransmitHead = Transmit->NextActive;
//
// Clear up next pointer
//
Transmit->NextActive = NULL;
//
// Check if there was an error on the transmit. Set Status and increment
// appropriate counter.
//
if ((Cstat & TRANSMIT_CSTAT_XMIT_ERROR) != 0) {
Adapter->BadTransmits++;
Status = NDIS_STATUS_FAILURE;
CURRENT_DEBUG(DbgPrint("IBMTOK2E!Bad Transmit DPC\n");)
} else {
Adapter->GoodTransmits++;
Status = NDIS_STATUS_SUCCESS;
CURRENT_DEBUG(DbgPrint("IBMTOK2E!Good Transmit DPC\n");)
}
//
// Check if the packet has map register associated
//
if (Transmit->UsedBuffer == FALSE) {
//
// Pointer to the current NDIS_BUFFER
//
PNDIS_BUFFER CurrentBuffer;
//
// Index to map register
//
UINT CurMapRegister;
//
// Transmit is finished, so release the physical mappings
//
NdisQueryPacket(
Transmit->Packet,
NULL,
NULL,
&CurrentBuffer,
NULL
);
//
// Set the first map register
//
CurMapRegister = Transmit->FirstEntry;
//
// Loop through all the buffers releasing the map registers
//
while (CurrentBuffer != NULL) {
//
// Free the current map register
//
NdisMCompleteBufferPhysicalMapping(
Adapter->MiniportAdapterHandle,
CurrentBuffer,
CurMapRegister
);
//
// Move to next map register
//
CurMapRegister++;
CurMapRegister %= TRANSMIT_ENTRIES;
//
// Move to next buffer
//
NdisGetNextBuffer(
CurrentBuffer,
&CurrentBuffer
);
}
}
//
// Indicate to the filter than the send has been completed.
//
IF_LOG('C');
NdisMSendComplete(
Adapter->MiniportAdapterHandle,
Packet,
Status
);
//
// Restart the transmits
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ENABLE_TRANSMIT_VALID
);
}
}
BOOLEAN
TOK162ProcessRingInterrupts(
IN PTOK162_ADAPTER Adapter
)
/*++
Routine Description:
Process ring status interrupts.
Arguments:
Adapter - The adapter registering the ring interrupt
Return Value:
FALSE - Don't need to process receives as a result of the ring condition
TRUE - Need to process receives
--*/
{
//
// Holds the return status value
//
ULONG RingStatus;
//
// Command block variable used if we need to read the errorlog due to
// an overflow condition.
//
PTOK162_SUPER_COMMAND_BLOCK CommandBlock;
//
// Return value for the function. Assume we don't need to process
// receives.
//
BOOLEAN SoftError = FALSE;
VERY_LOUD_DEBUG(DbgPrint(
"IBMTOK2E!Doing ring processing -%04x\n",Adapter->SsbStatus1);)
//
// Determine the reason for the ring interrupt.
//
if (Adapter->SsbStatus1 & RING_STATUS_SIGNAL_LOSS) {
RingStatus = NDIS_RING_SIGNAL_LOSS;
} else if (Adapter->SsbStatus1 & RING_STATUS_HARD_ERROR) {
RingStatus = NDIS_RING_HARD_ERROR;
} else if (Adapter->SsbStatus1 & RING_STATUS_SOFT_ERROR) {
//
// If we have a soft error, we should check the receives.
//
RingStatus = NDIS_RING_SOFT_ERROR;
SoftError = TRUE;
} else if (Adapter->SsbStatus1 & RING_STATUS_XMIT_BEACON) {
RingStatus = NDIS_RING_TRANSMIT_BEACON;
} else if (Adapter->SsbStatus1 & RING_STATUS_LOBE_WIRE_FAULT) {
RingStatus = NDIS_RING_LOBE_WIRE_FAULT;
} else if (Adapter->SsbStatus1 & RING_STATUS_AUTO_REMOVE_1) {
RingStatus = NDIS_RING_AUTO_REMOVAL_ERROR;
} else if (Adapter->SsbStatus1 & RING_STATUS_REMOVE_RECEIVED) {
RingStatus = NDIS_RING_REMOVE_RECEIVED;
} else if (Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) {
RingStatus = NDIS_RING_COUNTER_OVERFLOW;
} else if (Adapter->SsbStatus1 & RING_STATUS_SINGLESTATION) {
RingStatus = NDIS_RING_SINGLE_STATION;
} else if (Adapter->SsbStatus1 & RING_STATUS_RINGRECOVERY) {
RingStatus = NDIS_RING_RING_RECOVERY;
} else {
RingStatus = 0;
}
//
// Display the ring status that we will be indicating to the filter on
// the debugger.
//
VERY_LOUD_DEBUG(DbgPrint(
"IBMTOK2E!Indicating ring status - %lx\n",RingStatus);)
//
// Indicate to the filter the ring status.
//
NdisMIndicateStatus(
Adapter->MiniportAdapterHandle,
NDIS_STATUS_RING_STATUS,
&RingStatus,
sizeof(ULONG)
);
//
// Tell the filter that we have completed the ring status.
//
NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
//
// If a counter has overflowed, we need to read the stats from
// the adapter to clear this condition.
//
if ((Adapter->SsbStatus1 & RING_STATUS_OVERFLOW) != 0) {
//
// Get a command block.
//
TOK162AcquireCommandBlock(Adapter,
&CommandBlock
);
//
// Set up the command block for a read_error_log command.
//
CommandBlock->Set = FALSE;
CommandBlock->NextCommand = NULL;
CommandBlock->Hardware.Status = 0;
CommandBlock->Hardware.NextPending = TOK162_NULL;
CommandBlock->Hardware.CommandCode = CMD_DMA_READ_ERRLOG;
CommandBlock->Hardware.ParmPointer =
NdisGetPhysicalAddressLow(Adapter->ErrorLogPhysical);
//
// Submit the command to the card.
//
TOK162SubmitCommandBlock(Adapter,
CommandBlock
);
}
//
// Return whether processreceiveinterrupts needs to be called.
//
return(SoftError);
}