836 lines
20 KiB
C
836 lines
20 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
interrup.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the interrupt-processing code for the Novell
|
||
NE3200 NDIS 3.0 miniport driver.
|
||
|
||
Author:
|
||
|
||
Keith Moore (KeithMo) 04-Feb-1991
|
||
|
||
Environment:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <ne3200sw.h>
|
||
|
||
//
|
||
// Forward declarations of functions in this file
|
||
//
|
||
STATIC
|
||
BOOLEAN
|
||
FASTCALL
|
||
NE3200ProcessReceiveInterrupts(
|
||
IN PNE3200_ADAPTER Adapter
|
||
);
|
||
|
||
STATIC
|
||
BOOLEAN
|
||
FASTCALL
|
||
NE3200ProcessCommandInterrupts(
|
||
IN PNE3200_ADAPTER Adapter
|
||
);
|
||
|
||
VOID
|
||
NE3200Isr(
|
||
OUT PBOOLEAN InterruptRecognized,
|
||
OUT PBOOLEAN QueueDpc,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Interrupt service routine for the NE3200. It's main job is
|
||
to get the value of the System Doorbell Register and record the
|
||
changes in the adapters own list of interrupt reasons.
|
||
|
||
Arguments:
|
||
|
||
Interrupt - Interrupt object for the NE3200.
|
||
|
||
Context - Really a pointer to the adapter.
|
||
|
||
Return Value:
|
||
|
||
Returns true if the interrupt really was from our NE3200.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Will hold the value from the System Doorbell Register.
|
||
//
|
||
UCHAR SystemDoorbell;
|
||
|
||
//
|
||
// Holds the pointer to the adapter.
|
||
//
|
||
PNE3200_ADAPTER Adapter = Context;
|
||
|
||
IF_LOG('i');
|
||
|
||
//
|
||
// Get the interrupt status
|
||
//
|
||
NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(Adapter, &SystemDoorbell);
|
||
|
||
//
|
||
// Are any of the bits expected?
|
||
//
|
||
if (SystemDoorbell & NE3200_SYSTEM_DOORBELL_MASK) {
|
||
|
||
IF_LOG(SystemDoorbell);
|
||
|
||
//
|
||
// It's our interrupt. Disable further interrupts.
|
||
//
|
||
NE3200_WRITE_SYSTEM_DOORBELL_MASK(
|
||
Adapter,
|
||
0
|
||
);
|
||
|
||
IF_LOG('I');
|
||
|
||
//
|
||
// Return that we recognize it
|
||
//
|
||
*InterruptRecognized = TRUE;
|
||
|
||
} else {
|
||
|
||
IF_LOG('I');
|
||
|
||
//
|
||
// Return that we don't recognize it
|
||
//
|
||
*InterruptRecognized = FALSE;
|
||
|
||
}
|
||
|
||
//
|
||
// No Dpc call is needed for initialization
|
||
//
|
||
*QueueDpc = FALSE;
|
||
|
||
}
|
||
|
||
|
||
STATIC
|
||
VOID
|
||
NE3200HandleInterrupt(
|
||
IN NDIS_HANDLE MiniportAdapterContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Main routine for processing interrupts.
|
||
|
||
Arguments:
|
||
|
||
Adapter - The Adapter to process interrupts for.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// The adapter for which to handle interrupts.
|
||
//
|
||
PNE3200_ADAPTER Adapter = ((PNE3200_ADAPTER)MiniportAdapterContext);
|
||
|
||
//
|
||
// Holds a value of SystemDoorbellInterrupt.
|
||
//
|
||
USHORT SystemDoorbell = 0;
|
||
|
||
//
|
||
// Should NdisMEthIndicateReceiveComplete() be called?
|
||
//
|
||
BOOLEAN IndicateReceiveComplete = FALSE;
|
||
|
||
IF_LOG('p');
|
||
|
||
//
|
||
// Get the current reason for interrupts
|
||
//
|
||
NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(Adapter, &SystemDoorbell);
|
||
|
||
//
|
||
// Acknowledge those interrupts.
|
||
//
|
||
NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(
|
||
Adapter,
|
||
SystemDoorbell
|
||
);
|
||
|
||
//
|
||
// Get just the important ones.
|
||
//
|
||
SystemDoorbell &= NE3200_SYSTEM_DOORBELL_MASK;
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// If we have a reset in progress then start the reset.
|
||
//
|
||
|
||
if (Adapter->ResetInProgress) goto check_reset;
|
||
|
||
not_reset:
|
||
|
||
//
|
||
// Check the interrupt source and other reasons
|
||
// for processing. If there are no reasons to
|
||
// process then exit this loop.
|
||
//
|
||
|
||
//
|
||
// Check the interrupt vector and see if there are any
|
||
// more receives to process. After we process any
|
||
// other interrupt source we always come back to the top
|
||
// of the loop to check if any more receive packets have
|
||
// come in. This is to lessen the probability that we
|
||
// drop a receive.
|
||
//
|
||
if (SystemDoorbell & NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED) {
|
||
|
||
IF_LOG('r');
|
||
|
||
//
|
||
// Process receive interrupts.
|
||
//
|
||
if (NE3200ProcessReceiveInterrupts(Adapter)) {
|
||
|
||
//
|
||
// If done with all receives, then clear the interrupt
|
||
// from our status.
|
||
//
|
||
SystemDoorbell &= ~NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED;
|
||
|
||
}
|
||
|
||
//
|
||
// Note that we got a receive.
|
||
//
|
||
Adapter->ReceiveInterrupt = TRUE;
|
||
IndicateReceiveComplete = TRUE;
|
||
|
||
IF_LOG('R');
|
||
|
||
} else if ((SystemDoorbell &
|
||
NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE) == 0 ) {
|
||
|
||
//
|
||
// If the command is not completed, and no receives, then
|
||
// exit the loop.
|
||
//
|
||
break;
|
||
}
|
||
|
||
//
|
||
// First we check that this is a packet that was transmitted
|
||
// but not already processed. Recall that this routine
|
||
// will be called repeatedly until this tests false, Or we
|
||
// hit a packet that we don't completely own.
|
||
//
|
||
if ((Adapter->FirstCommandOnCard == NULL) ||
|
||
(Adapter->FirstCommandOnCard->Hardware.State != NE3200_STATE_EXECUTION_COMPLETE)) {
|
||
|
||
//
|
||
// No more work to do, clear the interrupt status bit.
|
||
//
|
||
IF_LOG('V');
|
||
SystemDoorbell &= ~NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE;
|
||
|
||
} else {
|
||
|
||
IF_LOG('c');
|
||
|
||
//
|
||
// Complete this transmit.
|
||
//
|
||
if ( NE3200ProcessCommandInterrupts(Adapter) ) {
|
||
SystemDoorbell &= ~NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE;
|
||
}
|
||
|
||
IF_LOG('C');
|
||
|
||
}
|
||
|
||
//
|
||
// Get more interrupt bits for processing
|
||
//
|
||
if (SystemDoorbell == 0) {
|
||
|
||
//
|
||
// Get the current reason for interrupts
|
||
//
|
||
NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(Adapter, &SystemDoorbell);
|
||
|
||
//
|
||
// Acknowledge those interrupts.
|
||
//
|
||
NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(
|
||
Adapter,
|
||
SystemDoorbell
|
||
);
|
||
|
||
//
|
||
// Get just the important ones.
|
||
//
|
||
SystemDoorbell &= NE3200_SYSTEM_DOORBELL_MASK;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
done:
|
||
|
||
IF_LOG('P');
|
||
|
||
if (IndicateReceiveComplete) {
|
||
|
||
NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
|
||
|
||
}
|
||
|
||
return;
|
||
|
||
check_reset:
|
||
|
||
if (Adapter->ResetState != NE3200ResetStateComplete) {
|
||
|
||
//
|
||
// The adapter is not in a state where it can process a reset.
|
||
//
|
||
goto not_reset;
|
||
|
||
}
|
||
|
||
//
|
||
// Start the reset
|
||
//
|
||
NE3200DoAdapterReset(Adapter);
|
||
|
||
goto done;
|
||
|
||
}
|
||
|
||
STATIC
|
||
BOOLEAN
|
||
FASTCALL
|
||
NE3200ProcessReceiveInterrupts(
|
||
IN PNE3200_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process the packets that have the adapter has finished receiving.
|
||
|
||
Arguments:
|
||
|
||
Adapter - The adapter to indicate to.
|
||
|
||
Return Value:
|
||
|
||
Whether to clear interrupt bit 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.
|
||
//
|
||
// Examine each receive block for errors.
|
||
//
|
||
// We keep an array whose elements are indexed by the block
|
||
// index of the receive blocks. The arrays elements are the
|
||
// virtual addresses of the buffers pointed to by each block.
|
||
//
|
||
// 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.
|
||
//
|
||
PNE3200_SUPER_RECEIVE_ENTRY CurrentEntry = Adapter->ReceiveQueueHead;
|
||
|
||
//
|
||
// Pointer to last receive block in the queue.
|
||
//
|
||
PNE3200_SUPER_RECEIVE_ENTRY LastEntry;
|
||
|
||
//
|
||
// Limit the number of consecutive receives we will do. This way
|
||
// we do not starve transmit interrupts when processing many, many
|
||
// receives
|
||
//
|
||
#define MAX_RECEIVES_PROCESSED 10
|
||
ULONG ReceivePacketCount = 0;
|
||
|
||
|
||
//
|
||
// Loop forever
|
||
//
|
||
while (TRUE) {
|
||
|
||
//
|
||
// Ensure that our Receive Entry is on an even boundary.
|
||
//
|
||
ASSERT(!(NdisGetPhysicalAddressLow(CurrentEntry->Self) & 1));
|
||
|
||
//
|
||
// Check to see whether we own the packet. If
|
||
// we don't then simply return to the caller.
|
||
//
|
||
if (CurrentEntry->Hardware.State != NE3200_STATE_FREE) {
|
||
|
||
//
|
||
// We've found a packet. Prepare the parameters
|
||
// for indication, then indicate.
|
||
//
|
||
if (ReceivePacketCount < MAX_RECEIVES_PROCESSED) {
|
||
|
||
//
|
||
// Increment the limit.
|
||
//
|
||
ReceivePacketCount++;
|
||
|
||
//
|
||
// Flush the receive buffer
|
||
//
|
||
NdisFlushBuffer(CurrentEntry->FlushBuffer, FALSE);
|
||
|
||
//
|
||
// Check the packet for a runt
|
||
//
|
||
if ((UINT)(CurrentEntry->Hardware.FrameSize) <
|
||
NE3200_HEADER_SIZE) {
|
||
|
||
if ((UINT)(CurrentEntry->Hardware.FrameSize) >=
|
||
NE3200_LENGTH_OF_ADDRESS) {
|
||
|
||
//
|
||
// Runt Packet, indicate it.
|
||
//
|
||
NdisMEthIndicateReceive(
|
||
Adapter->MiniportAdapterHandle,
|
||
(NDIS_HANDLE)(CurrentEntry->ReceiveBuffer),
|
||
CurrentEntry->ReceiveBuffer,
|
||
(UINT)CurrentEntry->Hardware.FrameSize,
|
||
NULL,
|
||
0,
|
||
0
|
||
);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Good frame, indicate it
|
||
//
|
||
NdisMEthIndicateReceive(
|
||
Adapter->MiniportAdapterHandle,
|
||
(NDIS_HANDLE)(CurrentEntry->ReceiveBuffer),
|
||
CurrentEntry->ReceiveBuffer,
|
||
NE3200_HEADER_SIZE,
|
||
((PUCHAR)CurrentEntry->ReceiveBuffer) + NE3200_HEADER_SIZE,
|
||
(UINT)CurrentEntry->Hardware.FrameSize - NE3200_HEADER_SIZE,
|
||
(UINT)CurrentEntry->Hardware.FrameSize - NE3200_HEADER_SIZE
|
||
);
|
||
|
||
}
|
||
|
||
//
|
||
// Give the packet back to the hardware.
|
||
//
|
||
// Chain the current block onto the tail of the Receive Queue.
|
||
//
|
||
CurrentEntry->Hardware.NextPending = NE3200_NULL;
|
||
CurrentEntry->Hardware.State = NE3200_STATE_FREE;
|
||
|
||
//
|
||
// Update receive ring
|
||
//
|
||
LastEntry = Adapter->ReceiveQueueTail;
|
||
LastEntry->Hardware.NextPending =
|
||
NdisGetPhysicalAddressLow(CurrentEntry->Self);
|
||
|
||
//
|
||
// Update the queue tail.
|
||
//
|
||
Adapter->ReceiveQueueTail = LastEntry->NextEntry;
|
||
|
||
//
|
||
// Advance to the next block.
|
||
//
|
||
CurrentEntry = CurrentEntry->NextEntry;
|
||
|
||
//
|
||
// See if the adapter needs to be restarted. The NE3200
|
||
// stops if it runs out receive buffers. Since we just
|
||
// released one, we restart the adapter.
|
||
//
|
||
if (LastEntry->Hardware.State != NE3200_STATE_FREE) {
|
||
|
||
//
|
||
// We've exhausted all Receive Blocks. Now we
|
||
// must restart the adapter.
|
||
//
|
||
IF_LOG('O');
|
||
NE3200StartChipAndDisableInterrupts(Adapter, Adapter->ReceiveQueueTail);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Update statistics, we are exiting to check for
|
||
// transmit interrupts.
|
||
//
|
||
Adapter->ReceiveQueueHead = CurrentEntry;
|
||
Adapter->GoodReceives += MAX_RECEIVES_PROCESSED+1;
|
||
|
||
IF_LOG('o');
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// All done, update statistics and exit.
|
||
//
|
||
Adapter->ReceiveQueueHead = CurrentEntry;
|
||
Adapter->GoodReceives += ReceivePacketCount;
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
STATIC
|
||
BOOLEAN
|
||
FASTCALL
|
||
NE3200ProcessCommandInterrupts(
|
||
IN PNE3200_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process the Command Complete interrupts.
|
||
|
||
Arguments:
|
||
|
||
Adapter - The adapter that was sent from.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Pointer to command block being processed.
|
||
//
|
||
PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->FirstCommandOnCard;
|
||
|
||
//
|
||
// Holds whether the packet successfully transmitted or not.
|
||
//
|
||
NDIS_STATUS StatusToReturn;
|
||
|
||
//
|
||
// Pointer to the packet that started this transmission.
|
||
//
|
||
PNDIS_PACKET OwningPacket;
|
||
|
||
//
|
||
// Points to the reserved part of the OwningPacket.
|
||
//
|
||
PNE3200_RESERVED Reserved;
|
||
|
||
//
|
||
// Ensure that the Command Block is on an even boundary.
|
||
//
|
||
ASSERT(!(NdisGetPhysicalAddressLow(CurrentCommandBlock->Self) & 1));
|
||
|
||
IF_LOG('t');
|
||
|
||
if (CurrentCommandBlock->Hardware.CommandCode == NE3200_COMMAND_TRANSMIT) {
|
||
|
||
//
|
||
// The current command block is from a transmit.
|
||
//
|
||
Adapter->SendInterrupt = TRUE;
|
||
|
||
//
|
||
// Get a pointer to the owning packet and the reserved part of
|
||
// the packet.
|
||
//
|
||
OwningPacket = CurrentCommandBlock->OwningPacket;
|
||
Reserved = PNE3200_RESERVED_FROM_PACKET(OwningPacket);
|
||
|
||
if (CurrentCommandBlock->UsedNE3200Buffer) {
|
||
|
||
//
|
||
// This packet used adapter buffers. We can
|
||
// now return these buffers to the adapter.
|
||
//
|
||
|
||
//
|
||
// The adapter buffer descriptor that was allocated to this packet.
|
||
//
|
||
PNE3200_BUFFER_DESCRIPTOR BufferDescriptor = Adapter->NE3200Buffers +
|
||
CurrentCommandBlock->NE3200BuffersIndex;
|
||
|
||
//
|
||
// Put the adapter buffer back on the free list.
|
||
//
|
||
BufferDescriptor->Next = Adapter->NE3200BufferListHead;
|
||
Adapter->NE3200BufferListHead = CurrentCommandBlock->NE3200BuffersIndex;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Ndis buffer mapped
|
||
//
|
||
PNDIS_BUFFER CurrentBuffer;
|
||
|
||
//
|
||
// Map register that was used
|
||
//
|
||
UINT CurMapRegister;
|
||
|
||
//
|
||
// The transmit is finished, so we can release
|
||
// the physical mapping used for it.
|
||
//
|
||
NdisQueryPacket(
|
||
OwningPacket,
|
||
NULL,
|
||
NULL,
|
||
&CurrentBuffer,
|
||
NULL
|
||
);
|
||
|
||
//
|
||
// Get starting map register
|
||
//
|
||
CurMapRegister = CurrentCommandBlock->CommandBlockIndex *
|
||
NE3200_MAXIMUM_BLOCKS_PER_PACKET;
|
||
|
||
//
|
||
// For each buffer
|
||
//
|
||
while (CurrentBuffer) {
|
||
|
||
//
|
||
// Finish the mapping
|
||
//
|
||
NdisMCompleteBufferPhysicalMapping(
|
||
Adapter->MiniportAdapterHandle,
|
||
CurrentBuffer,
|
||
CurMapRegister
|
||
);
|
||
|
||
++CurMapRegister;
|
||
|
||
NdisGetNextBuffer(
|
||
CurrentBuffer,
|
||
&CurrentBuffer
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// If there was an error transmitting this
|
||
// packet, update our error counters.
|
||
//
|
||
if (CurrentCommandBlock->Hardware.Status & NE3200_STATUS_FATALERROR_MASK) {
|
||
|
||
if (CurrentCommandBlock->Hardware.Status &
|
||
NE3200_STATUS_MAXIMUM_COLLISIONS) {
|
||
|
||
Adapter->RetryFailure++;
|
||
|
||
} else if (CurrentCommandBlock->Hardware.Status &
|
||
NE3200_STATUS_NO_CARRIER) {
|
||
|
||
Adapter->LostCarrier++;
|
||
|
||
} else if (CurrentCommandBlock->Hardware.Status &
|
||
NE3200_STATUS_HEART_BEAT) {
|
||
|
||
Adapter->NoClearToSend++;
|
||
|
||
} else if (CurrentCommandBlock->Hardware.Status &
|
||
NE3200_STATUS_DMA_UNDERRUN) {
|
||
|
||
Adapter->UnderFlow++;
|
||
|
||
}
|
||
|
||
StatusToReturn = NDIS_STATUS_FAILURE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Update good transmit counter
|
||
//
|
||
StatusToReturn = NDIS_STATUS_SUCCESS;
|
||
Adapter->GoodTransmits++;
|
||
}
|
||
|
||
ASSERT(sizeof(UINT) == sizeof(PNDIS_PACKET));
|
||
|
||
//
|
||
// Release the command block.
|
||
//
|
||
NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
|
||
|
||
//
|
||
// The transmit is now complete
|
||
//
|
||
NdisMSendComplete(
|
||
Adapter->MiniportAdapterHandle,
|
||
OwningPacket,
|
||
StatusToReturn
|
||
);
|
||
|
||
} else if (CurrentCommandBlock->Hardware.CommandCode ==
|
||
NE3200_COMMAND_READ_ADAPTER_STATISTICS) {
|
||
|
||
//
|
||
// Release the command block.
|
||
//
|
||
Adapter->OutOfResources =
|
||
CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.ResourceErrors;
|
||
|
||
Adapter->CrcErrors =
|
||
CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.CrcErrors;
|
||
|
||
Adapter->AlignmentErrors =
|
||
CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.AlignmentErrors;
|
||
|
||
Adapter->DmaOverruns =
|
||
CurrentCommandBlock->Hardware.PARAMETERS.STATISTICS.OverrunErrors;
|
||
|
||
|
||
//
|
||
// If this was from a request, complete it
|
||
//
|
||
if (Adapter->RequestInProgress) {
|
||
|
||
NE3200FinishQueryInformation(Adapter);
|
||
|
||
}
|
||
|
||
//
|
||
// Release the command block
|
||
//
|
||
NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
|
||
|
||
} else if (CurrentCommandBlock->Hardware.CommandCode ==
|
||
NE3200_COMMAND_CLEAR_ADAPTER_STATISTICS) {
|
||
|
||
//
|
||
// Release the command block.
|
||
//
|
||
NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
|
||
|
||
} else if (CurrentCommandBlock->Hardware.CommandCode ==
|
||
NE3200_COMMAND_SET_STATION_ADDRESS) {
|
||
|
||
//
|
||
// Ignore
|
||
//
|
||
|
||
} else {
|
||
|
||
//
|
||
// The current command block is not from a transmit.
|
||
//
|
||
// Complete the request.
|
||
//
|
||
// if the CurrentCommandBlock->Set is FALSE,
|
||
// it means this multicast operation was not caused by
|
||
// a SetInformation request.
|
||
//
|
||
|
||
if (CurrentCommandBlock->Set) {
|
||
|
||
//
|
||
// Release the command block.
|
||
//
|
||
NE3200RelinquishCommandBlock(Adapter, CurrentCommandBlock);
|
||
|
||
if (!Adapter->RequestInProgress) {
|
||
|
||
//
|
||
// Bogus interrupt. Ignore it
|
||
//
|
||
|
||
} else {
|
||
|
||
IF_LOG(']');
|
||
|
||
Adapter->RequestInProgress = FALSE;
|
||
|
||
//
|
||
// Complete the request
|
||
//
|
||
NdisMSetInformationComplete(
|
||
Adapter->MiniportAdapterHandle,
|
||
NDIS_STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
} else {
|
||
IF_LOG('T');
|
||
return TRUE;
|
||
}
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|