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.
1376 lines
34 KiB
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);
|
|
|
|
}
|
|
|