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.
 
 
 
 
 
 

1376 lines
34 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 (internal logging and
// debug print's).
//
VERY_LOUD_DEBUG(DbgPrint("TOK162!ISR\n");)
IF_LOG('o');
//
// Read the adapter interrupt register
//
READ_ADAPTER_USHORT(Adapter,PORT_OFFSET_STATUS,&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 this is a receive, go ahead and do the DPC. This allows us to keep
// in synch with the card concerning the receive list index. Also, for a
// a receive there is no need to allow the SSB to be updated as the DPC
// routine will do this for us. If it isn't a receive, we need to indicate
// that no DPC is necessary and we also allow the SSB to be updated.
//
if (Sif == STATUS_INT_CODE_RECEIVE_STATUS) {
IF_LOG('p');
*QueueDpc = TRUE;
//
// 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.
//
} else if (Sif == STATUS_INT_CODE_CMD_STATUS) {
if (Adapter->Ssb->Command == CMD_DMA_OPEN) {
Adapter->SsbStatus1 = Adapter->Ssb->Status1;
Adapter->InitialOpenComplete = TRUE;
}
//
// Enable updating of the SSB
//
IF_LOG('z');
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
ENABLE_SSB_UPDATE
);
*QueueDpc = FALSE;
//
// If we get the SCB clear interrupt, then we can do the receive command.
//
} else if (Sif == STATUS_INT_CODE_SCB_CLEAR) {
DoTheReceive(Adapter);
Adapter->InitialReceiveSent = TRUE;
} else {
//
// Enable updating of the SSB
//
IF_LOG('z');
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
ENABLE_SSB_UPDATE
);
*QueueDpc = FALSE;
}
//
// Indicate the ISR routine has ended.
//
IF_LOG('O');
}
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("TOK162!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 interrupt type
//
USHORT IMask = 0;
//
// 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("TOK162!DPC was just called\n");)
IF_LOG('r');
//
// Loop through processing interrupts until we have processed them all.
//
while (TRUE) {
//
// 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) {
//
// Indicate that we received a bad interrupt and break
// out of the loop.
//
IF_LOG('a');
break;
} else {
//
// Indicatate that the interrupt was found to be ours.
//
IF_LOG('A');
//
// 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;
}
//
// Figure out the type of interrupt
//
IMask = (UCHAR) (IMask & STATUS_INT_CODE_MASK);
//
// Indicate the type of interrupt to the debugger.
//
EXTRA_LOUD_DEBUG(DbgPrint("TOK162!New IMask is %x\n",IMask);)
//
// Process the interrupt based on the type of interrupt.
//
switch(IMask) {
case STATUS_INT_CODE_RING:
//
// We have a ring status change. Log this fact.
//
IF_LOG('b');
//
// 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) {
TOK162ProcessReceiveInterrupts(Adapter);
//
// Indicate that we did process receives during this
// DPC.
//
IndicateReceiveComplete = TRUE;
}
break;
case STATUS_INT_CODE_RECEIVE_STATUS:
//
// We have a receive interrupt. Log this fact.
//
IF_LOG('c');
//
// Process the interrupt.
//
TOK162ProcessReceiveInterrupts(Adapter);
//
// Indicate that we did process a receive during this
// DPC.
//
IndicateReceiveComplete = TRUE;
break;
case STATUS_INT_CODE_XMIT_STATUS:
//
// We have a transmit interrupt. Log this fact.
//
IF_LOG('d');
//
// Process the transmit.
//
TOK162ProcessTransmitInterrupts(Adapter);
break;
case STATUS_INT_CODE_CMD_STATUS:
//
// We have a command interrupt to process. Log this fact.
//
IF_LOG('e');
//
// 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);
}
break;
default:
//
// The interrupt type is not one that we know (illegal value).
// Indicate this to the debugger.
//
LOUD_DEBUG(DbgPrint("TOK162!Int Command %x, %x\n",Adapter->SsbCommand,
Adapter->SsbStatus1);)
break;
}
//
// Indicate that we are about to dismiss the interrupt.
//
IF_LOG('z');
//
// Dismiss the interrupt, allowing the SSB to be updated.
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_STATUS,
ENABLE_SSB_UPDATE
);
}
//
// 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 (IndicateReceiveComplete) {
//
// Indicate to the debugger that we are doing the complete.
//
EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Doing the indicate complete on the receive\n");)
//
// Call the Token Ring Filter to indicate the receive complete.
//
NdisMTrIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
}
//
// Log and indicate to the debugger that we are ending DPC processing.
//
IF_LOG('R');
EXTRA_LOUD_DEBUG(DbgPrint("TOK162!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('C');
//
// Continue processing receives until we have exhausted them.
//
while (TRUE) {
//
// Ensure that our Receive Entry is on an even boundary.
//
ASSERT(!(NdisGetPhysicalAddressLow(CurrentEntry->Self) & 1));
//
// Send the receive status byte to the debugger.
//
EXTRA_LOUD_DEBUG(DbgPrint(
"TOK162!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) {
//
// Record the receive list entry following the last good
// entry as the starting point for the next time receives
// are processed.
//
Adapter->ReceiveQueueCurrent = CurrentEntry;
//
// Tell the adapter to allow more receives.
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ENABLE_RECEIVE_VALID
);
return;
}
//
// 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++;
//
// Make sure the adapter and the system are in synch.
//
NdisFlushBuffer(CurrentEntry->FlushBuffer, FALSE);
//
// Get the frame size of this buffer.
//
FrameSize = BYTE_SWAP(CurrentEntry->Hardware.FrameSize);
//
// Indicate the frame size to the debugger
//
EXTRA_LOUD_DEBUG(DbgPrint("TOK162!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
// and log it.
EXTRA_LOUD_DEBUG(DbgPrint("TOK162!Doing receive indicate\n");)
IF_LOG('q');
//
// 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
);
} 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(
"TOK162!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
);
}
}
//
// Mark the receive list as processed and able to receive another
// buffer.
//
CurrentEntry->Hardware.CSTAT = RECEIVE_CSTAT_REQUEST_RESET;
//
// Move to the next entry to see if there are more to process.
//
CurrentEntry = CurrentEntry->NextEntry;
//
// Log the fact that we are telling the card to send us more receives.
//
IF_LOG('Q');
//
// Tell the card that we are ready to process more receives.
//
WRITE_ADAPTER_USHORT(Adapter,
PORT_OFFSET_COMMAND,
ENABLE_RECEIVE_VALID
);
}
}
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;
//
// Ensure that the Command Block is on an even boundary.
//
ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1));
//
// Log the fact that we are processing a command interrupt.
//
IF_LOG('E');
//
// 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("TOK162!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);
}
//
// 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("TOK162!Processing the open command.\n");)
//
// Relinquish the command block associcated with this open.
//
TOK162RelinquishCommandBlock(Adapter, CurrentCommandBlock);
//
// 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;
Adapter->OpenErrorCode = Adapter->SsbStatus1;
Status = NDIS_STATUS_FAILURE;
//
// Display the error code on the debugger.
//
VERY_LOUD_DEBUG(DbgPrint(
"TOK162!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;
Adapter->OpenErrorCode = 0;
Status = NDIS_STATUS_SUCCESS;
//
// Now send out the receive command. Display the fact that
// DoReceive is being called on the debugger.
//
VERY_LOUD_DEBUG(DbgPrint("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;
}
}
//
// Indicate to the wrapper the result of the open/receive for
// the original reset request.
//
TOK162DoResetIndications(Adapter, Status);
break;
case CMD_DMA_READ_ERRLOG:
LOUD_DEBUG(DbgPrint("TOK162!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("TOK162!CongestionErrors = %u\n",
Adapter->ErrorLog->ReceiveCongestionError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!LineErrors = %u\n",
Adapter->ErrorLog->LineError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!LostFrameErrors = %u\n",
Adapter->ErrorLog->LostFrameError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!BurstErrors = %u\n",
Adapter->ErrorLog->BurstError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!FrameCopiedErrors = %u\n",
Adapter->ErrorLog->FrameCopiedError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!TokenErrors = %u\n",
Adapter->ErrorLog->TokenError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!InternalErrors = %u\n",
Adapter->ErrorLog->InternalError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!ARIFCIErrors = %u\n",
Adapter->ErrorLog->ARIFCIError);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!AbortDelimeters = %u\n",
Adapter->ErrorLog->AbortDelimeter);)
VERY_LOUD_DEBUG(DbgPrint("TOK162!DMABusErrors = %u\n",
Adapter->ErrorLog->DMABusError);)
//
// If a query for information generated this interrupt, finish
// the query.
//
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 command block being processed.
//
PTOK162_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->TransmitOnCard;
//
// Pointer to the packet that started this transmission.
//
PNDIS_PACKET OwningPacket;
//
// Points to the reserved part of the OwningPacket.
//
PTOK162_RESERVED Reserved;
//
// Holds CSTAT variable for transmit
//
USHORT Cstat;
//
// Status variable
//
NDIS_STATUS Status;
//
// Ensure that the Command Block is on an even boundary.
//
ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1));
//
// Log the fact that we are processing a transmit interrupt
//
IF_LOG('D');
//
// Check if there is any reason to continue with the process. It is
// possible during a reset that not all of the transmits had completed.
// The reset path takes care of aborting all sends that didn't complete
// so we don't want to process anything during a reset. In the general
// case we don't want to process any transmit that doesn't have an
// associated command block.
//
if ((CurrentCommandBlock == NULL) ||
(Adapter->ResetInProgress == TRUE)) {
//
// Log the fact that we received a possibly bogus transmit interrupt.
//
IF_LOG('p');
return;
}
//
// Get a pointer to the owning packet and the reserved part of
// the packet.
//
OwningPacket = CurrentCommandBlock->OwningPacket;
Reserved = PTOK162_RESERVED_FROM_PACKET(OwningPacket);
//
// Check if this packet was constrained.
//
if (CurrentCommandBlock->UsedTOK162Buffer == FALSE) {
//
// Pointer to the current NDIS_BUFFER that we need to do the
// completemapregister on.
//
PNDIS_BUFFER CurrentBuffer;
//
// Index to the map register being freed.
//
UINT CurMapRegister;
//
// The transmit is finished, so we can release
// the physical mapping used for it.
//
NdisQueryPacket(
OwningPacket,
NULL,
NULL,
&CurrentBuffer,
NULL
);
//
// Compute the first map register used by this transmit.
//
CurMapRegister = CurrentCommandBlock->CommandBlockIndex *
Adapter->TransmitThreshold;
//
// Loop through the NDIS_BUFFERs until there are no more.
//
while (CurrentBuffer != NULL) {
//
// Free the current map register.
//
NdisMCompleteBufferPhysicalMapping(
Adapter->MiniportAdapterHandle,
CurrentBuffer,
CurMapRegister
);
//
// Move to the next map register.
//
++CurMapRegister;
//
// Get the next NDIS_BUFFER
//
NdisGetNextBuffer(
CurrentBuffer,
&CurrentBuffer
);
}
}
//
// If there was an error transmitting this
// packet, update our error counters.
//
Cstat = CurrentCommandBlock->Hardware.TransmitEntry.CSTAT;
//
// Display the completion status for the transmit entry on the debugger.
//
VERY_LOUD_DEBUG(DbgPrint(
"TOK162!Csat for the command block is %x\n",Cstat);)
//
// 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;
} else {
Adapter->GoodTransmits++;
Status = NDIS_STATUS_SUCCESS;
}
//
// Release the command block.
//
TOK162RelinquishTransmitBlock(Adapter, CurrentCommandBlock);
//
// Indicate to the filter than the send has been completed.
//
NdisMSendComplete(
Adapter->MiniportAdapterHandle,
OwningPacket,
Status
);
}
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;
//
// Log that we are processing a ring DPC. Display the ring interrupt
// information on the debugger.
//
IF_LOG('B');
VERY_LOUD_DEBUG(DbgPrint(
"TOK162!Doing ring processing -%04x\n",Adapter->SsbStatus1);)
//
// Initialize Ring Status to 0
//
RingStatus = 0;
//
// 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;
}
//
// Display the ring status that we will be indicating to the filter on
// the debugger.
//
VERY_LOUD_DEBUG(DbgPrint(
"TOK162!Indicating ring status - %lx\n",RingStatus);)
//
// Save the current status for query purposes.
//
Adapter->LastNotifyStatus = 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);
}