diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ndis/ne3200 | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/ndis/ne3200')
22 files changed, 9762 insertions, 0 deletions
diff --git a/private/ntos/ndis/ne3200/command.c b/private/ntos/ndis/ne3200/command.c new file mode 100644 index 000000000..1e3bee680 --- /dev/null +++ b/private/ntos/ndis/ne3200/command.c @@ -0,0 +1,272 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + command.c + +Abstract: + + This file contains the code for managing Command Blocks on the + NE3200's Command Queue. + +Author: + + Keith Moore (KeithMo) 07-Feb-1991 + +Environment: + +Revision History: + + +--*/ + +#include <ne3200sw.h> + + +VOID +FASTCALL +Ne3200Stall( + PULONG Dummy + ) +/*++ + +Routine Description: + + This routine is used to cause the processor to spin momentarily, + without actually having to stall for a full microsecond, as in + NdisStallExecution. + +Arguments: + + Dummy - A variable to increment. + +Return Value: + + None. + +--*/ + +{ + (*Dummy)++; +} + + +VOID +NE3200AcquirePublicCommandBlock( + IN PNE3200_ADAPTER Adapter, + OUT PNE3200_SUPER_COMMAND_BLOCK * CommandBlock + ) + +/*++ + +Routine Description: + + Gets a public command block. + +Arguments: + + Adapter - The adapter that points to the ring entry structures. + + CommandBlock - Will receive a pointer to a Command Block. + +Return Value: + + None. + +--*/ + +{ + + // + // This is a pointer to the "public" Command Block. + // + PNE3200_SUPER_COMMAND_BLOCK PublicCommandBlock = + Adapter->PublicCommandQueue + Adapter->NextPublicCommandBlock; + + + ASSERT(Adapter->NumberOfPublicCommandBlocks > 0); + + // + // Remove a command block count. + // + Adapter->NumberOfPublicCommandBlocks--; + + // + // Initialize the Command Block. + // + NdisZeroMemory( + PublicCommandBlock, + sizeof(NE3200_SUPER_COMMAND_BLOCK) + ); + + PublicCommandBlock->Hardware.NextPending = NE3200_NULL; + PublicCommandBlock->AvailableCommandBlockCounter = + &Adapter->NumberOfPublicCommandBlocks; + NdisSetPhysicalAddressLow( + PublicCommandBlock->Self, + NdisGetPhysicalAddressLow(Adapter->PublicCommandQueuePhysical) + + Adapter->NextPublicCommandBlock * sizeof(NE3200_SUPER_COMMAND_BLOCK)); + + // + // Increment to next command block + // + Adapter->NextPublicCommandBlock++; + if (Adapter->NextPublicCommandBlock == NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS) { + Adapter->NextPublicCommandBlock = 0; + } + + IF_LOG('q'); + + // + // Return the Command Block pointer. + // + *CommandBlock = PublicCommandBlock; + + IF_NE3200DBG(ACQUIRE) { + + DPrint2( + "Acquired public command block @ %08lX\n", + (ULONG)PublicCommandBlock + ); + + } + +} + + +VOID +FASTCALL +NE3200RelinquishCommandBlock( + IN PNE3200_ADAPTER Adapter, + IN PNE3200_SUPER_COMMAND_BLOCK CommandBlock + ) + +/*++ + +Routine Description: + + Relinquish the Command Block resource. If this is a "public" + Command Block, then update the CommandQueue. If this is a + "private" Command Block, then free to the private command queue. + +Arguments: + + Adapter - The adapter that owns the Command Block. + + CommandBlock - The Command Block to relinquish. + +Return Value: + + None. + +--*/ + +{ + IF_NE3200DBG(SUBMIT) { + + DPrint2( + "Relinquishing command @ %08lX\n", + (ULONG)NdisGetPhysicalAddressLow(CommandBlock->Self) + ); + + } + + // + // If this is the last pending command block, then we + // can remove the adapter's last pending command pointer. + // + if (CommandBlock == Adapter->LastCommandOnCard) { + + // + // If there is another waiting chain of commands -- submit those + // + if (Adapter->FirstWaitingCommand != NULL) { + + // + // Move the chain to the on card queue. + // + Adapter->FirstCommandOnCard = Adapter->FirstWaitingCommand; + Adapter->LastCommandOnCard = Adapter->LastWaitingCommand; + Adapter->FirstWaitingCommand = NULL; + + IF_NE3200DBG(SUBMIT) { + + DPrint2( + "Starting command @ %08lX\n", + (ULONG)NdisGetPhysicalAddressLow(Adapter->FirstCommandOnCard->Self) + ); + + } + + // + // Submit this command chain to the card. + // + NE3200_WRITE_COMMAND_POINTER( + Adapter, + NdisGetPhysicalAddressLow(Adapter->FirstCommandOnCard->Self) + ); + + // + // Stall momentarily for the adapter to get the command. + // + { + ULONG i; + Ne3200Stall(&i); + } + + // + // Inform the card of the command + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_COMMAND + ); + + } else { + + // + // No commands are pending, clear the on card queue + // + Adapter->FirstCommandOnCard = NULL; + + } + + } else { + + // + // Point the adapter's first pending command to the + // next command on the command queue. + // + Adapter->FirstCommandOnCard = CommandBlock->NextCommand; + + } + + // + // Free this command block + // + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.State = NE3200_STATE_FREE; + + // + // Update the correct queue. + // + (*CommandBlock->AvailableCommandBlockCounter)++; + +#if DBG + if (CommandBlock->AvailableCommandBlockCounter == &Adapter->NumberOfAvailableCommandBlocks) { + // + // This is a "private" Command Block. + // + IF_LOG('A'); + } else { + // + // This is a "public" Command Block. + // + IF_LOG('Q'); + } +#endif + +} + diff --git a/private/ntos/ndis/ne3200/interrup.c b/private/ntos/ndis/ne3200/interrup.c new file mode 100644 index 000000000..d1fef19b0 --- /dev/null +++ b/private/ntos/ndis/ne3200/interrup.c @@ -0,0 +1,835 @@ +/*++ + +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; + +} + diff --git a/private/ntos/ndis/ne3200/keywords.h b/private/ntos/ndis/ne3200/keywords.h new file mode 100644 index 000000000..30b52656f --- /dev/null +++ b/private/ntos/ndis/ne3200/keywords.h @@ -0,0 +1,43 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + keywords.h + +Abstract: + + Contains all Ndis2 and Ndis3 mac-specific keywords. + +Author: + + Bob Noradki + +Environment: + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + + +--*/ +#ifndef NDIS2 +#define NDIS2 0 +#endif + +#if NDIS2 + +#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS") + +#else // NDIS3 + +#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress") + +#endif diff --git a/private/ntos/ndis/ne3200/mac2hex/mac.bin b/private/ntos/ndis/ne3200/mac2hex/mac.bin Binary files differnew file mode 100644 index 000000000..259f85a8e --- /dev/null +++ b/private/ntos/ndis/ne3200/mac2hex/mac.bin diff --git a/private/ntos/ndis/ne3200/mac2hex/mac2hex.c b/private/ntos/ndis/ne3200/mac2hex/mac2hex.c new file mode 100644 index 000000000..661e768c1 --- /dev/null +++ b/private/ntos/ndis/ne3200/mac2hex/mac2hex.c @@ -0,0 +1,309 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + mac2hex.c + +Abstract: + + This program will read in MAC.BIN and produce MACBIN.H. MACBIN.H + will consist of a character array representation (MacBinImage[]) + of MAC.BIN. + +Author: + + Keith Moore (KeithMo) 23-Jan-1991 + +Environment: + + OS/2 1.x/2.x Protected Mode + +Revision History: + + +--*/ + +#define INCL_BASE +#include <os2.h> + +#include <stdio.h> +#include <stdlib.h> + + +// +// Macros +// +#define CHECK_RETURN(code) \ +{ \ + if ((code) != NO_ERROR) { \ + printf( \ + "Error %d, File %s, Line %ld\n", \ + (code), \ + __FILE__, \ + (long)__LINE__ \ + ); \ + exit(1); \ + } \ +} + + +// +// Prototypes +// +int +main( + int nArgc, + char *pArgv[] + ); + +VOID +CreateHeaderFile( + PUCHAR pBuffer, + USHORT usLength + ); + + +// +// main +// +int +main( + int nArgc, + char *pArgv[] + ) + +/*++ + +Routine Description: + + Usual C entry point. + +Arguments: + + nArgc - Count of command line arguments. + pArgv - Array of pointers to the command line arguments. + +Return Value: + + 0 if everything went OK. + 1 if something horrible happened. + +--*/ + +{ + + FILESTATUS FileStatus; + HFILE hFile; + PCHAR pFileName; + PVOID pBuffer; + SEL Selector; + USHORT usAction; + USHORT usFileSize; + USHORT usNumRead; + USHORT usResult; + + // + // If no command line arguments are given, then + // use "MAC.BIN" for the input file. Otherwise, + // assume that the first (only?) argument is the + // name of the download file. + // + + pFileName = (nArgc > 1) ? (PCHAR)pArgv[1] : (PCHAR)"MAC.BIN"; + + // + // Open MAC.BIN. + // + + usResult = DosOpen( + pFileName, + &hFile, + &usAction, + 0L, + FILE_NORMAL, + FILE_OPEN, + OPEN_ACCESS_READONLY + | OPEN_SHARE_DENYNONE, + 0L + ); + CHECK_RETURN(usResult); + + // + // Query the file so we can retrive its length. + // + + usResult = DosQFileInfo( + hFile, + FIL_STANDARD, + (PBYTE)&FileStatus, + sizeof(FILESTATUS) + ); + CHECK_RETURN(usResult); + + usFileSize = (USHORT)FileStatus.cbFile; + + // + // Allocate a chunk of memory to use. + // + + usResult = DosAllocSeg( + usFileSize, + &Selector, + SEG_NONSHARED + ); + CHECK_RETURN(usResult); + + // + // Build our pointer from the selector we just allocated. + // + + pBuffer = MAKEP(Selector, 0); + + // + // Read MAC.BIN into our buffer. + // + + usResult = DosRead( + hFile, + pBuffer, + usFileSize, + &usNumRead + ); + CHECK_RETURN(usResult); + + // + // Close MAC.BIN. + // + + usResult = DosClose( + hFile + ); + CHECK_RETURN(usResult); + + // + // Write the new file. + // + CreateHeaderFile(pBuffer, usFileSize); + + // + // Free the allocated memory. + // + usResult = DosFreeSeg( + Selector + ); + CHECK_RETURN(usResult); + + return 0; + +} + + +// +// CreateHeaderFile +// +VOID +CreateHeaderFile( + PUCHAR pBuffer, + USHORT usLength + ) + +/*++ + +Routine Description: + + Create a C header file containing a character + array representation of the specified buffer. + +Arguments: + + pBuffer - Pointer to the buffer to convert. + + usLength - The length (in bytes) of the buffer. + +Return Value: + + None. + +--*/ + +{ + + // + // TRUE if we're starting a new line. + // + BOOL fNewLine; + + // + // Number of bytes on current line. + // + USHORT usNumBytes; + + // + // Create the prologue + // + + printf("/*++\n"); + printf("\n"); + printf("Copyright (c) 1990 Microsoft Corporation\n"); + printf("\n"); + printf("Module Name:\n"); + printf("\n"); + printf(" macbin.h\n"); + printf("\n"); + printf("Abstract:\n"); + printf("\n"); + printf(" This module is generated by MAC2HEX.EXE. MAC2HEX reads in the\n"); + printf(" NE3200's MAC.BIN module and produces this C character array\n"); + printf(" representation. This is an unfortunate artifact of having\n"); + printf(" all device drivers linked into the kernel. Once we have real\n"); + printf(" installable device drivers, this will be unnecessary (the\n"); + printf(" NE3200 driver will just open MAC.BIN and read it). But for now,\n"); + printf(" all device drivers get initialized *before* the filesystem.\n"); + printf(" Ergo, device drivers cannot open files at initialization time.\n"); + printf("\n"); + printf("Author:\n"); + printf("\n"); + printf(" Keith Moore (KeithMo) 24-Jan-1991\n"); + printf("\n"); + printf("Environment:\n"); + printf("\n"); + printf(" Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.\n"); + printf("\n"); + printf("Revision History:\n"); + printf("\n"); + printf("\n"); + printf("--*/\n"); + printf("\n"); + printf("#define NE3200_MACBIN_LENGTH %u\n", usLength); + printf("\n"); + printf("UCHAR NE3200MacBinImage[] = {"); + + fNewLine = TRUE; + + while(usLength--) { + + if (fNewLine) { + + printf("\n"); + printf(" "); + fNewLine = FALSE; + usNumBytes = 0; + + } + + printf("0x%02X", (UINT)(*pBuffer++)); + + if (usLength > 0) + printf(","); + + if (++usNumBytes >= 13) + fNewLine = TRUE; + + } + + printf("\n"); + printf(" };\n"); + +} diff --git a/private/ntos/ndis/ne3200/mac2hex/mac2hex.def b/private/ntos/ndis/ne3200/mac2hex/mac2hex.def new file mode 100644 index 000000000..d879f7eb3 --- /dev/null +++ b/private/ntos/ndis/ne3200/mac2hex/mac2hex.def @@ -0,0 +1,5 @@ +NAME MAC2HEX WINDOWCOMPAT + +DESCRIPTION 'Convert MAC.BIN to C Header File' + +STACKSIZE 8192 diff --git a/private/ntos/ndis/ne3200/mac2hex/makefile b/private/ntos/ndis/ne3200/mac2hex/makefile new file mode 100644 index 000000000..ac264b66c --- /dev/null +++ b/private/ntos/ndis/ne3200/mac2hex/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\maketool.def diff --git a/private/ntos/ndis/ne3200/mac2hex/sources b/private/ntos/ndis/ne3200/mac2hex/sources new file mode 100644 index 000000000..055ce7ff7 --- /dev/null +++ b/private/ntos/ndis/ne3200/mac2hex/sources @@ -0,0 +1,19 @@ +MAJORCOMP=ne3200 +MINORCOMP=mac2hex + +TARGETNAME=mac2hex +TARGETPATH=obj +TARGETTYPE=PROGRAM + +INCLUDES=\nt\private\tools\inc + +SOURCES=mac2hex.c + +BUILDTOOL=1 +TOOL_MODEL=/AS /G2s +TOOL_LIBS=\nt\private\tools\lib\slibcep /NOD/NOE +TOOL_TYPE=WINDOWCOMPAT + +MSC_WARNING_LEVEL=/W3 /WX + + diff --git a/private/ntos/ndis/ne3200/makefile b/private/ntos/ndis/ne3200/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/ndis/ne3200/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/ndis/ne3200/makefile.inc b/private/ntos/ndis/ne3200/makefile.inc new file mode 100644 index 000000000..439bc1088 --- /dev/null +++ b/private/ntos/ndis/ne3200/makefile.inc @@ -0,0 +1,5 @@ +ne3200.bin: $(TARGETEXEFILES) + chmode -r ne3200.bin + binplace ne3200.bin + touch ne3200.bin + chmode +r ne3200.bin diff --git a/private/ntos/ndis/ne3200/ne3200.bin b/private/ntos/ndis/ne3200/ne3200.bin Binary files differnew file mode 100644 index 000000000..91b9b0dec --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200.bin diff --git a/private/ntos/ndis/ne3200/ne3200.c b/private/ntos/ndis/ne3200/ne3200.c new file mode 100644 index 000000000..f4bd1dbab --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200.c @@ -0,0 +1,2497 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ne3200.c + +Abstract: + + This is the main file for the Novell NE3200 EISA Ethernet adapter. + This driver conforms to the NDIS 3.0 miniport interface. + +Author: + + Keith Moore (KeithMo) 08-Jan-1991 + +Environment: + +Revision History: + +--*/ + +#include <ne3200sw.h> +#include "keywords.h" + +// +// Global data block for holding MAC.BIN infomormation. +// +NE3200_GLOBAL_DATA NE3200Globals = {0}; +BOOLEAN FirstAdd = TRUE; + +// +// Global for the largest acceptable piece of memory +// +NDIS_PHYSICAL_ADDRESS MinusOne = NDIS_PHYSICAL_ADDRESS_CONST (-1, -1); + +#if DBG + +// +// Debugging flags for various debugging modes. +// +ULONG NE3200Debug = 0 ; // NE3200_DEBUG_LOUD | + // NE3200_DEBUG_ACQUIRE | + // NE3200_DEBUG_SUBMIT | + // NE3200_DEBUG_DUMP_COMMAND + // ; +#endif + + +// +// Forward declarations for functions in this file +// +STATIC +BOOLEAN +NE3200AllocateAdapterMemory( + IN PNE3200_ADAPTER Adapter + ); + +STATIC +VOID +NE3200DeleteAdapterMemory( + IN PNE3200_ADAPTER Adapter + ); + +STATIC +BOOLEAN +NE3200InitialInit( + IN PNE3200_ADAPTER Adapter, + IN UINT NE3200InterruptVector, + IN NDIS_INTERRUPT_MODE NE3200InterruptMode + ); + +STATIC +BOOLEAN +NE3200InitializeGlobals( + OUT PNE3200_GLOBAL_DATA Globals, + IN NDIS_HANDLE MiniportAdapterHandle + ); + +STATIC +VOID +NE3200DestroyGlobals( + IN PNE3200_GLOBAL_DATA Globals + ); + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + + +VOID +NE3200Shutdown( + IN NDIS_HANDLE MiniportAdapterContext + ); + +#pragma NDIS_INIT_FUNCTION(DriverEntry) + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This is the primary initialization routine for the NE3200 driver. + It is simply responsible for the intializing the wrapper and registering + the Miniport driver. It then calls a system and architecture specific + routine that will initialize and register each adapter. + +Arguments: + + DriverObject - Pointer to driver object created by the system. + +Return Value: + + The status of the operation. + +--*/ + +{ + // + // Receives the status of the NdisRegisterMiniport operation. + // + NDIS_STATUS Status; + + // + // The characteristics table + // + NDIS_MINIPORT_CHARACTERISTICS NE3200Char; + + // + // The handle returned by NdisMInitializeWrapper + // + NDIS_HANDLE NdisWrapperHandle; + +#if NDIS_WIN + UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)]; +#endif + +#if NDIS_WIN + ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1; + ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0; + *(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=EISA_NE3200_IDENTIFICATION; + (PVOID)DriverObject=(PVOID)pIds; +#endif + + // + // Initialize the wrapper. + // + NdisMInitializeWrapper( + &NdisWrapperHandle, + DriverObject, + RegistryPath, + NULL + ); + + // + // Initialize the Miniport characteristics for the call to + // NdisMRegisterMiniport. + // + NE3200Globals.NE3200NdisWrapperHandle = NdisWrapperHandle; + + NE3200Char.MajorNdisVersion = NE3200_NDIS_MAJOR_VERSION; + NE3200Char.MinorNdisVersion = NE3200_NDIS_MINOR_VERSION; + NE3200Char.CheckForHangHandler = NE3200CheckForHang; + NE3200Char.DisableInterruptHandler = NE3200DisableInterrupt; + NE3200Char.EnableInterruptHandler = NE3200EnableInterrupt; + NE3200Char.HaltHandler = NE3200Halt; + NE3200Char.HandleInterruptHandler = NE3200HandleInterrupt; + NE3200Char.InitializeHandler = NE3200Initialize; + NE3200Char.ISRHandler = NE3200Isr; + NE3200Char.QueryInformationHandler = NE3200QueryInformation; + NE3200Char.ReconfigureHandler = NULL; + NE3200Char.ResetHandler = NE3200Reset; + NE3200Char.SendHandler = NE3200Send; + NE3200Char.SetInformationHandler = NE3200SetInformation; + NE3200Char.TransferDataHandler = NE3200TransferData; + + // + // Register this driver with NDIS + // + Status = NdisMRegisterMiniport( + NdisWrapperHandle, + &NE3200Char, + sizeof(NE3200Char) + ); + + if (Status == NDIS_STATUS_SUCCESS) { + + return STATUS_SUCCESS; + + } + + // + // We can only get here if something went wrong with registering + // the driver or *all* of the adapters. + // + NE3200DestroyGlobals(&NE3200Globals); + NdisTerminateWrapper(NdisWrapperHandle, NULL); + + return STATUS_UNSUCCESSFUL; + +} + + +#pragma NDIS_INIT_FUNCTION(NE3200RegisterAdapter) + +BOOLEAN +NE3200RegisterAdapter( + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT EisaSlot, + IN UINT InterruptVector, + IN NDIS_INTERRUPT_MODE InterruptMode, + IN PUCHAR CurrentAddress + ) + +/*++ + +Routine Description: + + This routine is responsible for the allocation of the datastructures + for the driver as well as any hardware specific details necessary + to talk with the device. + +Arguments: + + MiniportAdapterHandle - The handle given by ndis identifying this mini-port. + + EisaSlot - The EISA Slot Number for this NE3200 adapter. + + InterruptVector - The interrupt vector to used for the adapter. + + InterruptMode - The interrupt mode (Latched or LevelSensitive) + used for this adapter. + + CurrentAddress - The address the card will assume. If this is NULL, + then the card will use the BIA. + +Return Value: + + Returns false if anything occurred that prevents the initialization + of the adapter. + +--*/ + +{ + // + // Status of nt calls + // + NDIS_STATUS Status; + + // + // Pointer for the adapter root. + // + PNE3200_ADAPTER Adapter; + + // + // All of the code that manipulates physical addresses depends + // on the fact that physical addresses are 4 byte quantities. + // + ASSERT(sizeof(NE3200_PHYSICAL_ADDRESS) == 4); + + // + // Allocate the Adapter block. + // + NE3200_ALLOC_PHYS(&Status, &Adapter, sizeof(NE3200_ADAPTER)); + + if ( Status == NDIS_STATUS_SUCCESS ) { + + // + // The IoBase Address for this adapter + // + ULONG AdapterIoBase; + + // + // The resulting mapped base address + // + PUCHAR MappedIoBase; + + // + // Initialize the adapter structure to all zeros + // + NdisZeroMemory( + Adapter, + sizeof(NE3200_ADAPTER) + ); + +#if DBG + Adapter->LogAddress = Adapter->Log; +#endif + + // + // Save the adapter handle + // + Adapter->MiniportAdapterHandle = MiniportAdapterHandle; + + // + // Compute the base address + // + AdapterIoBase = (ULONG)(EisaSlot << 12); + + // + // Save the base address + // + Adapter->AdapterIoBase = AdapterIoBase; + + // + // Set the attributes for this adapter + // + NdisMSetAttributes( + MiniportAdapterHandle, + (NDIS_HANDLE)Adapter, + TRUE, + NdisInterfaceEisa + ); + + // + // Register the reset port addresses. + // + Status = NdisMRegisterIoPortRange( + (PVOID *)(&(Adapter->ResetPort)), + MiniportAdapterHandle, + AdapterIoBase, + 0x4 + ); + + + if (Status != NDIS_STATUS_SUCCESS) { + + NE3200_FREE_PHYS(Adapter); + return FALSE; + } + + // + // Register the command ports + // + Status = NdisMRegisterIoPortRange( + (PVOID *)(&(MappedIoBase)), + MiniportAdapterHandle, + AdapterIoBase + NE3200_ID_PORT, + 0x20 + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NE3200_FREE_PHYS(Adapter); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase, + 4, + (PVOID)Adapter->ResetPort + ); + return FALSE; + } + + // + // Allocate the map registers + // + Status = NdisMAllocateMapRegisters( + MiniportAdapterHandle, + 0, + FALSE, + NE3200_NUMBER_OF_COMMAND_BLOCKS * NE3200_MAXIMUM_BLOCKS_PER_PACKET, + MAXIMUM_ETHERNET_PACKET_SIZE + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NE3200_FREE_PHYS(Adapter); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase, + 4, + (PVOID)Adapter->ResetPort + ); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase + NE3200_ID_PORT, + 0x20, + (PVOID)MappedIoBase + ); + return FALSE; + } + + // + // Should an alternative ethernet address be used? + // + if (CurrentAddress != NULL) { + + Adapter->AddressChanged = TRUE; + + NdisMoveMemory( + Adapter->CurrentAddress, + CurrentAddress, + NE3200_LENGTH_OF_ADDRESS + ); + } else { + + Adapter->AddressChanged = FALSE; + } + + // + // Save the eisa slot number + // + Adapter->EisaSlot = EisaSlot; + //DbgPrint( "NE3200: Adapter %x is slot %d\n", Adapter, EisaSlot ); + + // + // ResetPort is set by NdisRegisterAdapter. + // MappedIoBase is set in NdisRegisterAdapter to be the mapped + // of NE3200_ID_PORT. Now we set the other ports based on + // this offset. + // + Adapter->SystemInterruptPort = MappedIoBase + NE3200_SYSTEM_INTERRUPT_PORT - NE3200_ID_PORT; + Adapter->LocalDoorbellInterruptPort = MappedIoBase + NE3200_LOCAL_DOORBELL_INTERRUPT_PORT - NE3200_ID_PORT; + Adapter->SystemDoorbellMaskPort = MappedIoBase + NE3200_SYSTEM_DOORBELL_MASK_PORT - NE3200_ID_PORT; + Adapter->SystemDoorbellInterruptPort = MappedIoBase + NE3200_SYSTEM_DOORBELL_INTERRUPT_PORT - NE3200_ID_PORT; + Adapter->BaseMailboxPort = MappedIoBase + NE3200_BASE_MAILBOX_PORT - NE3200_ID_PORT; + + // + // Allocate the global resources if needed. + // + if (FirstAdd) { + + if (!NE3200InitializeGlobals(&NE3200Globals, Adapter->MiniportAdapterHandle)) { + + NdisMFreeMapRegisters(MiniportAdapterHandle); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase, + 4, + (PVOID)Adapter->ResetPort + ); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase + NE3200_ID_PORT, + 0x20, + (PVOID)MappedIoBase + ); + NE3200_FREE_PHYS(Adapter); + return FALSE; + + } + + FirstAdd = FALSE; + } + + // + // Setup default numbers for resources + // + Adapter->NumberOfTransmitBuffers = NE3200_NUMBER_OF_TRANSMIT_BUFFERS; + Adapter->NumberOfReceiveBuffers = NE3200_NUMBER_OF_RECEIVE_BUFFERS; + Adapter->NumberOfCommandBlocks = NE3200_NUMBER_OF_COMMAND_BLOCKS; + Adapter->NumberOfPublicCommandBlocks = NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS; + + // + // Allocate memory for all of the adapter structures. + // + if (NE3200AllocateAdapterMemory(Adapter)) { + + // + // Set the initial internal state + // + NE3200ResetVariables(Adapter); + + // + // Initialize the timer for doing asynchronous resets + // + NdisMInitializeTimer( + &Adapter->ResetTimer, + MiniportAdapterHandle, + (PVOID) NE3200ResetHandler, + (PVOID) Adapter + ); + + // + // Now start the adapter + // + if (!NE3200InitialInit( + Adapter, + InterruptVector, + InterruptMode + )) { + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, + 0 + ); + + NE3200DeleteAdapterMemory(Adapter); + NdisMFreeMapRegisters(MiniportAdapterHandle); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase, + 4, + (PVOID)Adapter->ResetPort + ); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase + NE3200_ID_PORT, + 0x20, + (PVOID)MappedIoBase + ); + NE3200_FREE_PHYS(Adapter); + return FALSE; + } + + // + // Enable further interrupts. + // + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + NE3200_SYSTEM_DOORBELL_MASK + ); + + // + // Record it in the global adapter list. + // + + InsertTailList(&NE3200Globals.AdapterList, + &Adapter->AdapterList, + ); + + // + // Register our shutdown handler. + // + + NdisMRegisterAdapterShutdownHandler( + Adapter->MiniportAdapterHandle, // miniport handle. + Adapter, // shutdown context. + NE3200Shutdown // shutdown handler. + ); + + return(TRUE); + + } else { + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + registerAdapter, + NE3200_ERRMSG_ALLOC_MEM, + 0 + ); + + NdisMFreeMapRegisters(MiniportAdapterHandle); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase, + 4, + (PVOID)Adapter->ResetPort + ); + NdisMDeregisterIoPortRange(MiniportAdapterHandle, + AdapterIoBase + NE3200_ID_PORT, + 0x20, + (PVOID)MappedIoBase + ); + return(FALSE); + + } + + } else { + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + registerAdapter, + NE3200_ERRMSG_ALLOC_MEM, + 1 + ); + + return FALSE; + } +} + + +#pragma NDIS_INIT_FUNCTION(NE3200AllocateAdapterMemory) + +STATIC +BOOLEAN +NE3200AllocateAdapterMemory( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine allocates memory for: + + - Configuration Block + + - Command Queue + + - Receive Queue + + - Receive Buffers + + - Transmit Buffers for use if user transmit buffers don't meet hardware + contraints + + - Structures to map Command Queue entries back to the packets. + +Arguments: + + Adapter - The adapter to allocate memory for. + +Return Value: + + Returns FALSE if some memory needed for the adapter could not + be allocated. + +--*/ + +{ + // + // Pointer to a Receive Entry. Used while initializing + // the Receive Queue. + // + PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry; + + // + // Pointer to a Command Block. Used while initializing + // the Command Queue. + // + PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock; + + // + // Simple iteration variable. + // + UINT i; + + // + // Status of allocation + // + NDIS_STATUS Status; + + // + // Allocate the public command block + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_SUPER_COMMAND_BLOCK) * NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS, + FALSE, + (PVOID *) &Adapter->PublicCommandQueue, + &Adapter->PublicCommandQueuePhysical + ); + + if (Adapter->PublicCommandQueue == NULL) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 1 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + + } + + // + // Allocate the card multicast table + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY * + NE3200_MAXIMUM_MULTICAST, + FALSE, // noncached + (PVOID*)&Adapter->CardMulticastTable, + &Adapter->CardMulticastTablePhysical + ); + + if (Adapter->CardMulticastTable == NULL) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 2 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + + } + + // + // Allocate the Configuration Block. + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_CONFIGURATION_BLOCK), + FALSE, // noncached + (PVOID*)&Adapter->ConfigurationBlock, + &Adapter->ConfigurationBlockPhysical + ); + + if (Adapter->ConfigurationBlock == NULL) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 3 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + } + + // + // Allocate the Padding Buffer used to pad very short + // packets to the minimum Ethernet packet size (60 bytes). + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + MINIMUM_ETHERNET_PACKET_SIZE, + FALSE, + (PVOID*)&Adapter->PaddingVirtualAddress, + &Adapter->PaddingPhysicalAddress + ); + + if (Adapter->PaddingVirtualAddress == NULL) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 4 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + + } + + // + // Zero the Padding Buffer so we don't pad with garbage. + // + NdisZeroMemory( + Adapter->PaddingVirtualAddress, + MINIMUM_ETHERNET_PACKET_SIZE + ); + + + // + // Allocate the Command Queue. + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_SUPER_COMMAND_BLOCK) * + Adapter->NumberOfCommandBlocks, + FALSE, + (PVOID*)&Adapter->CommandQueue, + &Adapter->CommandQueuePhysical + ); + + + if (!Adapter->CommandQueue) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 5 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + } + + // + // Set the tail pointer + // + Adapter->LastCommandBlockAllocated = + Adapter->CommandQueue + Adapter->NumberOfCommandBlocks; + + // + // Clear the command list + // + NdisZeroMemory( + Adapter->CommandQueue, + sizeof(NE3200_SUPER_COMMAND_BLOCK) * Adapter->NumberOfCommandBlocks + ); + + // + // Put the Command Blocks into a known state. + // + for( + i = 0, CurrentCommandBlock = Adapter->CommandQueue; + i < Adapter->NumberOfCommandBlocks; + i++, CurrentCommandBlock++ + ) { + + CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE; + CurrentCommandBlock->Hardware.NextPending = NE3200_NULL; + + CurrentCommandBlock->NextCommand = NULL; + + NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0); + NdisSetPhysicalAddressLow( + CurrentCommandBlock->Self, + NdisGetPhysicalAddressLow(Adapter->CommandQueuePhysical) + + i * sizeof(NE3200_SUPER_COMMAND_BLOCK)); + + CurrentCommandBlock->AvailableCommandBlockCounter = + &Adapter->NumberOfAvailableCommandBlocks; + CurrentCommandBlock->CommandBlockIndex = (USHORT)i; + CurrentCommandBlock->Timeout = FALSE; + } + + // + // Now do the same for the public command queue. + // + for( + i = 0, CurrentCommandBlock = Adapter->PublicCommandQueue; + i < NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS; + i++, CurrentCommandBlock++ + ) { + + CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE; + CurrentCommandBlock->Hardware.NextPending = NE3200_NULL; + + CurrentCommandBlock->NextCommand = NULL; + + NdisSetPhysicalAddressHigh (CurrentCommandBlock->Self, 0); + NdisSetPhysicalAddressLow( + CurrentCommandBlock->Self, + NdisGetPhysicalAddressLow(Adapter->PublicCommandQueuePhysical) + + i * sizeof(NE3200_SUPER_COMMAND_BLOCK)); + + CurrentCommandBlock->AvailableCommandBlockCounter = + &Adapter->NumberOfPublicCommandBlocks; + CurrentCommandBlock->CommandBlockIndex = (USHORT)i; + CurrentCommandBlock->Timeout = FALSE; + } + + + // + // Allocate Flush Buffer Pool + // + NdisAllocateBufferPool( + &Status, + (PVOID*)&Adapter->FlushBufferPoolHandle, + NE3200_NUMBER_OF_TRANSMIT_BUFFERS + + Adapter->NumberOfReceiveBuffers + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 6 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + } + + // + // Allocate the Receive Queue. + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_SUPER_RECEIVE_ENTRY) * + Adapter->NumberOfReceiveBuffers, + FALSE, + (PVOID*)&Adapter->ReceiveQueue, + &Adapter->ReceiveQueuePhysical + ); + + if (!Adapter->ReceiveQueue) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 7 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + + } + + // + // Clear the receive ring + // + NdisZeroMemory( + Adapter->ReceiveQueue, + sizeof(NE3200_SUPER_RECEIVE_ENTRY) * Adapter->NumberOfReceiveBuffers + ); + + + // + // Allocate the receive buffers and attach them to the Receive + // Queue entries. + // + for( + i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue; + i < Adapter->NumberOfReceiveBuffers; + i++, CurrentReceiveEntry++ + ) { + + // + // Allocate the actual receive buffers + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + NE3200_SIZE_OF_RECEIVE_BUFFERS, + TRUE, + &CurrentReceiveEntry->ReceiveBuffer, + &CurrentReceiveEntry->ReceiveBufferPhysical + ); + + if (!CurrentReceiveEntry->ReceiveBuffer) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 8 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + + } + + // + // Build flush buffers + // + NdisAllocateBuffer( + &Status, + &CurrentReceiveEntry->FlushBuffer, + Adapter->FlushBufferPoolHandle, + CurrentReceiveEntry->ReceiveBuffer, + NE3200_SIZE_OF_RECEIVE_BUFFERS + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 9 + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + } + + // + // Initialize receive buffers + // + NdisFlushBuffer(CurrentReceiveEntry->FlushBuffer, FALSE); + + CurrentReceiveEntry->Hardware.State = NE3200_STATE_FREE; + CurrentReceiveEntry->Hardware.FrameSize = NE3200_SIZE_OF_RECEIVE_BUFFERS; + CurrentReceiveEntry->Hardware.NextPending = + NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) + + (i + 1) * sizeof(NE3200_SUPER_RECEIVE_ENTRY); + + CurrentReceiveEntry->Hardware.BufferDescriptor.BlockLength = + NE3200_SIZE_OF_RECEIVE_BUFFERS; + CurrentReceiveEntry->Hardware.BufferDescriptor.PhysicalAddress = + NdisGetPhysicalAddressLow(CurrentReceiveEntry->ReceiveBufferPhysical); + + NdisSetPhysicalAddressHigh (CurrentReceiveEntry->Self, 0); + NdisSetPhysicalAddressLow( + CurrentReceiveEntry->Self, + NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) + + i * sizeof(NE3200_SUPER_RECEIVE_ENTRY)); + + CurrentReceiveEntry->NextEntry = CurrentReceiveEntry + 1; + + } + + // + // Make sure the last entry is properly terminated. + // + (CurrentReceiveEntry - 1)->Hardware.NextPending = NE3200_NULL; + (CurrentReceiveEntry - 1)->NextEntry = Adapter->ReceiveQueue; + + // + // Allocate the array of buffer descriptors. + // + NE3200_ALLOC_PHYS( + &Status, + &Adapter->NE3200Buffers, + sizeof(NE3200_BUFFER_DESCRIPTOR)* + (NE3200_NUMBER_OF_TRANSMIT_BUFFERS) + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 0xA + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + } + + // + // Zero the memory of all the descriptors so that we can + // know which buffers weren't allocated incase we can't allocate + // them all. + // + NdisZeroMemory( + Adapter->NE3200Buffers, + sizeof(NE3200_BUFFER_DESCRIPTOR)* + (NE3200_NUMBER_OF_TRANSMIT_BUFFERS) + ); + + + // + // Allocate each of the buffers and fill in the + // buffer descriptor. + // + Adapter->NE3200BufferListHead = 0; + + for ( + i = 0; + i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS; + i++ + ) { + + // + // Allocate a buffer + // + NdisMAllocateSharedMemory( + Adapter->MiniportAdapterHandle, + NE3200_SIZE_OF_TRANSMIT_BUFFERS, + TRUE, + &Adapter->NE3200Buffers[i].VirtualNE3200Buffer, + &Adapter->NE3200Buffers[i].PhysicalNE3200Buffer + ); + + if (!Adapter->NE3200Buffers[i].VirtualNE3200Buffer) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 0xB + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + + } + + // + // Build flush buffers + // + NdisAllocateBuffer( + &Status, + &Adapter->NE3200Buffers[i].FlushBuffer, + Adapter->FlushBufferPoolHandle, + Adapter->NE3200Buffers[i].VirtualNE3200Buffer, + NE3200_SIZE_OF_TRANSMIT_BUFFERS + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 3, + allocateAdapterMemory, + NE3200_ERRMSG_ALLOC_MEM, + 0xC + ); + + NE3200DeleteAdapterMemory(Adapter); + return FALSE; + } + + // + // Insert this buffer into the queue + // + Adapter->NE3200Buffers[i].Next = i+1; + Adapter->NE3200Buffers[i].BufferSize = NE3200_SIZE_OF_TRANSMIT_BUFFERS; + + } + + // + // Make sure that the last buffer correctly terminates the free list. + // + Adapter->NE3200Buffers[i-1].Next = -1; + + return TRUE; + +} + + +STATIC +VOID +NE3200DeleteAdapterMemory( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine deallocates memory for: + + - Command Queue. + + - Receive Queue. + + - Receive buffers + + - Transmit Buffers for use if user transmit buffers don't meet hardware + contraints + + - Structures to map transmit ring entries back to the packets. + +Arguments: + + Adapter - The adapter to deallocate memory for. + +Return Value: + + None. + +--*/ + +{ + + // + // Do the public command queue + // + if (Adapter->PublicCommandQueue) { + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_SUPER_COMMAND_BLOCK) * NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS, + FALSE, + Adapter->PublicCommandQueue, + Adapter->PublicCommandQueuePhysical + ); + } + + // + // The table for downloading multicast addresses + // + if (Adapter->CardMulticastTable) { + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY * + NE3200_MAXIMUM_MULTICAST, + FALSE, + Adapter->CardMulticastTable, + Adapter->CardMulticastTablePhysical + ); + + } + + // + // The configuration block + // + if (Adapter->ConfigurationBlock) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_CONFIGURATION_BLOCK), + FALSE, + Adapter->ConfigurationBlock, + Adapter->ConfigurationBlockPhysical + ); + + } + + // + // The pad buffer for short packets + // + if (Adapter->PaddingVirtualAddress) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + MINIMUM_ETHERNET_PACKET_SIZE, + FALSE, + Adapter->PaddingVirtualAddress, + Adapter->PaddingPhysicalAddress + ); + + } + + // + // The private command blocks + // + if (Adapter->CommandQueue) { + + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_SUPER_COMMAND_BLOCK) * + Adapter->NumberOfCommandBlocks, + FALSE, + Adapter->CommandQueue, + Adapter->CommandQueuePhysical + ); + + } + + + // + // The receive buffers + // + if (Adapter->ReceiveQueue) { + + // + // Pointer to current Receive Entry being deallocated. + // + PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry; + + // + // Simple iteration counter. + // + UINT i; + + + for( + i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue; + i < Adapter->NumberOfReceiveBuffers; + i++, CurrentReceiveEntry++ + ) { + + + if (CurrentReceiveEntry->ReceiveBuffer) { + + // + // Free the memory + // + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + NE3200_SIZE_OF_RECEIVE_BUFFERS, + TRUE, + CurrentReceiveEntry->ReceiveBuffer, + CurrentReceiveEntry->ReceiveBufferPhysical + ); + + + if (CurrentReceiveEntry->FlushBuffer) { + + // + // Free the flush buffer + // + NdisFreeBuffer( + CurrentReceiveEntry->FlushBuffer + ); + } + + } + + } + + // + // Free the receive ring + // + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + sizeof(NE3200_SUPER_RECEIVE_ENTRY) * + Adapter->NumberOfReceiveBuffers, + FALSE, + Adapter->ReceiveQueue, + Adapter->ReceiveQueuePhysical + ); + + } + + // + // Free the merge buffers + // + if (Adapter->NE3200Buffers) { + + // + // Loop counter + // + UINT i; + + for ( + i = 0; + i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS; + i++ + ) { + + + if (Adapter->NE3200Buffers[i].VirtualNE3200Buffer) { + + // + // Free the memory + // + NdisMFreeSharedMemory( + Adapter->MiniportAdapterHandle, + NE3200_SIZE_OF_TRANSMIT_BUFFERS, + TRUE, + Adapter->NE3200Buffers[i].VirtualNE3200Buffer, + Adapter->NE3200Buffers[i].PhysicalNE3200Buffer + ); + + if (Adapter->NE3200Buffers[i].FlushBuffer) { + + // + // Free the flush buffer + // + NdisFreeBuffer( + Adapter->NE3200Buffers[i].FlushBuffer + ); + + } + + } + + } + + // + // Free the buffer ring + // + NE3200_FREE_PHYS(Adapter->NE3200Buffers); + + } + + if (Adapter->FlushBufferPoolHandle) { + + // + // Free the buffer pool + // + NdisFreeBufferPool( + Adapter->FlushBufferPoolHandle + ); + + } + +} + +#pragma NDIS_INIT_FUNCTION(NE3200InitializeGlobals) + +STATIC +BOOLEAN +NE3200InitializeGlobals( + OUT PNE3200_GLOBAL_DATA Globals, + IN NDIS_HANDLE MiniportAdapterHandle + ) + +/*++ + +Routine Description: + + This routine will initialize the global data structure used + by all adapters managed by this driver. This routine is only + called once, when the driver is initializing the first + adapter. + +Arguments: + + Globals - Pointer to the global data structure to initialize. + + AdapterHandle - The handle to be used to allocate shared memory. + +Return Value: + + None. + +--*/ + +{ + // + // File with the download code. + // + NDIS_STRING FileName=NDIS_STRING_CONST("ne3200.bin"); + + // + // Handle for the file. + // + NDIS_HANDLE FileHandle; + + // + // Length of the file. + // + UINT FileLength; + + // + // Status of NDIS calls + // + NDIS_STATUS Status; + + // + // Virtual address of the download software in the file. + // + PVOID ImageBuffer; + + // + // The value to return + // + BOOLEAN ReturnValue = TRUE; + + // + // Save the adpater handle that did the allocations + // + Globals->MacBinAdapterHandle = MiniportAdapterHandle; + + // + // Allocate the buffer. + // + NdisMAllocateSharedMemory( + MiniportAdapterHandle, + NE3200_MACBIN_LENGTH, + FALSE, + &Globals->MacBinVirtualAddress, + &Globals->MacBinPhysicalAddress + ); + + if (Globals->MacBinVirtualAddress == NULL) { + NE3200DestroyGlobals(Globals); + return FALSE; + } + + // + // Store the length + // + Globals->MacBinLength = NE3200_MACBIN_LENGTH; + + + // + // Open the file with the download code + // + NdisOpenFile( + &Status, + &FileHandle, + &FileLength, + &FileName, + MinusOne + ); + + if (Status==NDIS_STATUS_SUCCESS) { + + // + // Map the file into virtual memory + // + NdisMapFile( + &Status, + &ImageBuffer, + FileHandle + ); + + if (Status==NDIS_STATUS_SUCCESS) { + + // + // Copy the download code into the shared memory space + // + NdisMoveMemory(Globals->MacBinVirtualAddress,ImageBuffer,FileLength); + + // + // Done with the file + // + NdisUnmapFile(FileHandle); + + } else { + + ReturnValue = FALSE; + + } + + // + // Close the file + // + NdisCloseFile(FileHandle); + + } else { + + ReturnValue = FALSE; + + } + + // + // AdapterListHead is initially empty + // + InitializeListHead(&Globals->AdapterList); + + // + // All done. + // + return ReturnValue; + +} + + +STATIC +VOID +NE3200DestroyGlobals( + IN PNE3200_GLOBAL_DATA Globals + ) + +/*++ + +Routine Description: + + This routine frees all global data allocated with + NE3200InitializeGlobals. This routine is called just before + the driver is unloaded. + +Arguments: + + Globals - Pointer to the global data structure to destroy. + +Return Value: + + None. + +--*/ + +{ + + // + // Free the memory with the download software in it. + // + if (Globals->MacBinVirtualAddress != NULL) { + + NdisMFreeSharedMemory( + Globals->MacBinAdapterHandle, + NE3200_MACBIN_LENGTH, + FALSE, + Globals->MacBinVirtualAddress, + Globals->MacBinPhysicalAddress + ); + + } + +} + +#pragma NDIS_INIT_FUNCTION(NE3200Initialize) + +NDIS_STATUS +NE3200Initialize( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE ConfigurationHandle + ) + +/*++ + +Routine Description: + + NE3200Initialize starts an adapter. + +Arguments: + + See NDIS 3.0 Miniport spec. + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_PENDING + +--*/ + +{ + // + // Handle returned by NdisOpenConfiguration + // + NDIS_HANDLE ConfigHandle; + + // + // For changing the network address of this adapter. + // + NDIS_STRING NetAddrStr = NETWORK_ADDRESS; + UCHAR NetworkAddress[NE3200_LENGTH_OF_ADDRESS]; + PUCHAR CurrentAddress; + PVOID NetAddress; + ULONG Length; + + // + // The type of interrupt the adapter is set to use, level + // sensitive, or edged. + // + NDIS_INTERRUPT_MODE InterruptType; + + // + // The interrupt number to use. + // + UINT InterruptVector; + + // + // The slot number the adapter is located in + // + UINT EisaSlot; + + // + // The port to look for in the EISA slot information + // + USHORT Portz800; + + // + // The default value to use. + // + UCHAR z800Value; + + // + // The mast to apply to the default values + // + UCHAR Mask; + + // + // The type of initialization described in the EISA slot information. + // + UCHAR InitType; + + // + // The port value for this iteration + // + UCHAR PortValue; + + // + // The current port address to initialize + // + USHORT PortAddress; + + // + // The location in the EISA slot information buffer + // + PUCHAR CurrentChar; + + // + // Set to TRUE when done processing EISA slot information + // + BOOLEAN LastEntry; + + // + // The EISA data + // + NDIS_EISA_FUNCTION_INFORMATION EisaData; + + // + // Temporary looping variable + // + ULONG i; + + // + // For signalling a configuration error + // + BOOLEAN ConfigError = FALSE; + NDIS_STATUS ConfigErrorCode; + + // + // Status of NDIS calls + // + NDIS_STATUS Status; + + // + // Search for the medium type (802.3) + // + for (i = 0; i < MediumArraySize; i++){ + + if (MediumArray[i] == NdisMedium802_3){ + + break; + + } + + } + + // + // Ethernet was not found. Return an error. + // + if (i == MediumArraySize){ + + return NDIS_STATUS_UNSUPPORTED_MEDIA; + + } + + // + // Select ethernet + // + *SelectedMediumIndex = i; + + // + // Open the configuration handle + // + NdisOpenConfiguration( + &Status, + &ConfigHandle, + ConfigurationHandle + ); + + if (Status != NDIS_STATUS_SUCCESS) { + return Status; + } + + // + // Set address to default, using the burned in adapter address + // + CurrentAddress = NULL; + + // + // Read an overriding net address + // + NdisReadNetworkAddress( + &Status, + &NetAddress, + &Length, + ConfigHandle + ); + + if ((Length == NE3200_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) { + + // + // Save overriding net address + // + NdisMoveMemory( + NetworkAddress, + NetAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + CurrentAddress = NetworkAddress; + + } + + // + // Read the EISA configuration information + // + NdisReadEisaSlotInformation( + &Status, + ConfigurationHandle, + &EisaSlot, + &EisaData + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + ConfigError = TRUE; + ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; + + goto RegisterAdapter; + + } + + // + // Start at the beginning of the buffer + // + CurrentChar = EisaData.InitializationData; + + // + // This is the port to look for + // + Portz800 = (EisaSlot << 12) + 0x800; + + LastEntry = FALSE; + + while (!LastEntry) { + + + InitType = *(CurrentChar++); + PortAddress = *((USHORT UNALIGNED *) CurrentChar++); + CurrentChar++; + + // + // Check for last entry in EISA information + // + if ((InitType & 0x80) == 0) { + LastEntry = TRUE; + } + + // + // Is this the port we are interested in? + // + if (PortAddress != Portz800) { + continue; + } + + // + // Yes, get the port value to use + // + PortValue = *(CurrentChar++); + + // + // Get the mask to use. + // + if (InitType & 0x40) { + Mask = *(CurrentChar++); + } else { + Mask = 0; + } + + // + // Mask old value and or on new value. + // + z800Value &= Mask; + z800Value |= PortValue; + } + + // + // Now, interpret the port data + // + // Get interrupt + // + + switch (z800Value & 0x07) { + case 0x00: + + ConfigError = TRUE; + ConfigErrorCode = NDIS_ERROR_CODE_HARDWARE_FAILURE; + + goto RegisterAdapter; + + case 0x01: + InterruptVector = 5; + break; + case 0x02: + InterruptVector = 9; + break; + case 0x03: + InterruptVector = 10; + break; + case 0x04: + InterruptVector = 11; + break; + case 0x05: + InterruptVector = 15; + break; + default: + + ConfigError = TRUE; + ConfigErrorCode = NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION; + + goto RegisterAdapter; + + } + + // + // Get interrupt mode + // + + if (z800Value & 0x20) { + InterruptType = NdisInterruptLatched; + } else { + InterruptType = NdisInterruptLevelSensitive; + } + +RegisterAdapter: + + // + // Were there any errors? + // + if (ConfigError) { + + NdisWriteErrorLogEntry( + MiniportAdapterHandle, + ConfigErrorCode, + 0 + ); + + Status = NDIS_STATUS_FAILURE; + + } else if (NE3200RegisterAdapter( + MiniportAdapterHandle, + EisaSlot, + InterruptVector, + InterruptType, + CurrentAddress + )) { + + Status = NDIS_STATUS_SUCCESS; + + } else { + + Status = NDIS_STATUS_FAILURE; + + } + + // + // All done + // + NdisCloseConfiguration(ConfigHandle); + + return Status; +} + + +VOID +NE3200Halt( + IN NDIS_HANDLE MiniportAdapterContext + ) + +/*++ + +Routine Description: + + NE3200Halts removes an adapter previously initialized. + +Arguments: + + MacAdapterContext - The context value that the Miniport returned + from Ne3200Initialize; actually as pointer to an NE3200_ADAPTER. + +Return Value: + + None. + +--*/ + +{ + // + // The adapter to halt + // + PNE3200_ADAPTER Adapter; + + Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + // + // Shut down the h/w + // + NE3200Shutdown(Adapter); + + // + // Disconnect the interrupt + // + NdisMDeregisterInterrupt(&Adapter->Interrupt); + + // + // Delete all resources + // + NE3200DeleteAdapterMemory(Adapter); + + // + // Free map registers + // + NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); + + // + // Remove ports + // + NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, + Adapter->AdapterIoBase, + 4, + (PVOID)Adapter->ResetPort + ); + + // + // Remove ports + // + NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, + Adapter->AdapterIoBase + NE3200_ID_PORT, + 0x20, + (PVOID)(Adapter->SystemInterruptPort - + NE3200_SYSTEM_INTERRUPT_PORT + NE3200_ID_PORT) + ); + + // + // Remove from global adapter list + // + RemoveEntryList(&Adapter->AdapterList); + + // + // Free the adapter structure + // + NE3200_FREE_PHYS(Adapter); + + return; +} + + +VOID +NE3200Shutdown( + IN NDIS_HANDLE MiniportAdapterContext + ) + +/*++ + +Routine Description: + + NE3200Shutdown shuts down the h/w. + +Arguments: + + MacAdapterContext - The context value that the Miniport returned + from Ne3200Initialize; actually as pointer to an NE3200_ADAPTER. + +Return Value: + + None. + +--*/ + +{ + // + // The adapter to halt + // + PNE3200_ADAPTER Adapter; + + // + // Temporary looping variable + // + ULONG i; + + Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + // + // Shut down the chip. + // + NE3200StopChip(Adapter); + + // + // Pause, waiting for the chip to stop. + // + NdisStallExecution(500000); + + // + // Unfortunately, a hardware reset to the NE3200 does *not* + // reset the BMIC chip. To ensure that we read a proper status, + // we'll clear all of the BMIC's registers. + // + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + 0 + ); + + // + // I changed this to ff since the original 0 didn't work for + // some cases. since we don't have the specs.... + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + 0xff + ); + + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + SyncNE3200ClearDoorbellInterrupt(Adapter); + + for (i = 0 ; i < 16 ; i += 4 ) { + + NE3200_WRITE_MAILBOX_ULONG( + Adapter, + i, + 0L + ); + } + + // + // Toggle the NE3200's reset line. + // + NE3200_WRITE_RESET( + Adapter, + NE3200_RESET_BIT_ON + ); +} + + +NDIS_STATUS +NE3200TransferData( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE MiniportReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ) + +/*++ + +Routine Description: + + A protocol calls the NE3200TransferData request (indirectly via + NdisTransferData) from within its Receive event handler + to instruct the Miniport to copy the contents of the received packet + a specified paqcket buffer. + +Arguments: + + MiniportAdapterContext - The context value returned by the driver when the + adapter was initialized. In reality this is a pointer to NE3200_ADAPTER. + + MiniportReceiveContext - The context value passed by the driver on its call + to NdisMIndicateReceive. The driver can use this value to determine + which packet, on which adapter, is being received. + + ByteOffset - An unsigned integer specifying the offset within the + received packet at which the copy is to begin. If the entire packet + is to be copied, ByteOffset must be zero. + + BytesToTransfer - An unsigned integer specifying the number of bytes + to copy. It is legal to transfer zero bytes; this has no effect. If + the sum of ByteOffset and BytesToTransfer is greater than the size + of the received packet, then the remainder of the packet (starting from + ByteOffset) is transferred, and the trailing portion of the receive + buffer is not modified. + + Packet - A pointer to a descriptor for the packet storage into which + the MAC is to copy the received packet. + + BytesTransfered - A pointer to an unsigned integer. The MAC writes + the actual number of bytes transferred into this location. This value + is not valid if the return status is STATUS_PENDING. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + // + // The adapter to transfer from + // + PNE3200_ADAPTER Adapter; + + // + // Holds the count of the number of ndis buffers comprising the + // destination packet. + // + UINT DestinationBufferCount; + + // + // Points to the buffer into which we are putting data. + // + PNDIS_BUFFER DestinationCurrentBuffer; + + // + // Points to the location in Buffer from which we are extracting data. + // + PUCHAR SourceCurrentAddress; + + // + // Holds the virtual address of the current destination buffer. + // + PVOID DestinationVirtualAddress; + + // + // Holds the length of the current destination buffer. + // + UINT DestinationCurrentLength; + + // + // Keep track of the bytes transferred so far. + // + UINT LocalBytesCopied = 0; + + // + // Get the adapter structure + // + Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + *BytesTransferred = 0; + + // + // Take care of boundary condition of zero length copy. + // + if (!BytesToTransfer) { + return NDIS_STATUS_SUCCESS; + } + + // + // Get the first buffer of the destination. + // + NdisQueryPacket( + Packet, + NULL, + &DestinationBufferCount, + &DestinationCurrentBuffer, + NULL + ); + + // + // Could have a null packet. + // + if (!DestinationBufferCount) { + return NDIS_STATUS_SUCCESS; + } + + // + // Get first buffer information + // + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + // + // Set up the source address. + // + SourceCurrentAddress = (PUCHAR)(MiniportReceiveContext) + ByteOffset + NE3200_HEADER_SIZE; + + // + // While there is still data to copy + // + while (LocalBytesCopied < BytesToTransfer) { + + // + // Check to see whether we've exhausted the current destination + // buffer. If so, move onto the next one. + // + if (!DestinationCurrentLength) { + + // + // Get the next buffer + // + NdisGetNextBuffer( + DestinationCurrentBuffer, + &DestinationCurrentBuffer + ); + + if (!DestinationCurrentBuffer) { + + // + // We've reached the end of the packet. We return + // with what we've done so far. (Which must be shorter + // than requested.) + // + break; + + } + + // + // Get this buffers information + // + NdisQueryBuffer( + DestinationCurrentBuffer, + &DestinationVirtualAddress, + &DestinationCurrentLength + ); + + continue; + + } + + // + // Copy the data. + // + { + + // + // Holds the amount of data to move. + // + UINT AmountToMove; + + // + // Holds the amount desired remaining. + // + UINT Remaining = BytesToTransfer - LocalBytesCopied; + + + AmountToMove = DestinationCurrentLength; + + AmountToMove = ((Remaining < AmountToMove)? + (Remaining):(AmountToMove)); + + NE3200_MOVE_MEMORY( + DestinationVirtualAddress, + SourceCurrentAddress, + AmountToMove + ); + + SourceCurrentAddress += AmountToMove; + LocalBytesCopied += AmountToMove; + DestinationCurrentLength -= AmountToMove; + + } + + } + + *BytesTransferred = LocalBytesCopied; + + return NDIS_STATUS_SUCCESS; + +} + +STATIC +NDIS_STATUS +NE3200Reset( + OUT PBOOLEAN AddressingReset, + IN NDIS_HANDLE MiniportAdapterContext + ) +/*++ + +Routine Description: + + The NE3200Reset request instructs the Miniport to issue a hardware reset + to the network adapter. The driver also resets its software state. See + the description of NdisMReset for a detailed description of this request. + +Arguments: + + MiniportAdapterContext - Pointer to the adapter structure. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + // + // The adapter to reset + // + PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + IF_LOG('w'); + + // + // Start the reset process + // + NE3200SetupForReset( + Adapter + ); + + // + // Call Handle interrupt to continue the reset process + // + NE3200HandleInterrupt( + (NDIS_HANDLE)Adapter + ); + + IF_LOG('W'); + + return NDIS_STATUS_PENDING; +} + +BOOLEAN +NE3200CheckForHang( + IN NDIS_HANDLE MiniportAdapterContext + ) + +/*++ + +Routine Description: + + This routine is called to check on the head of the command + block queue. It will fire off the queue if the head has + been sleeping on the job. + + It also detects when the ne3200 adapter has failed, where the + symptoms are that the adapter will transmit packets, but will + not receive them. + +Arguments: + + Context - Really a pointer to the adapter. + +Return Value: + + None. + +--*/ +{ + // + // The adapter to check over + // + PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + // + // The first command that is outstanding + // + PNE3200_SUPER_COMMAND_BLOCK FirstPending = Adapter->FirstCommandOnCard; + + // + // Check if the command is stalled + // + if( (FirstPending != NULL) && + (FirstPending->Hardware.State == NE3200_STATE_WAIT_FOR_ADAPTER) ) { + + // + // See if the command block has timed-out. + // + + if ( FirstPending->Timeout ) { + + if ( FirstPending->TimeoutCount >= 2) { + + // + // Give up, the card appears dead. + // + Adapter->ResetAsynchronous = TRUE; + Adapter->SendInterrupt = FALSE; + Adapter->NoReceiveInterruptCount = 0; + + return TRUE; + + } else { + + // + // Re-sumbit the block. + // + NE3200_WRITE_COMMAND_POINTER( + Adapter, + NdisGetPhysicalAddressLow(FirstPending->Self) + ); + + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_COMMAND + ); + + IF_LOG('+'); + + FirstPending->TimeoutCount++; + + } + + } else { + + IF_LOG('0'); + + // + // Let the next call find the stall + // + FirstPending->Timeout = TRUE; + FirstPending->TimeoutCount = 0; + + } + + } + + // + // Check if the receive side has died. + // + if ((!Adapter->ReceiveInterrupt) && (Adapter->SendInterrupt)) { + + // + // If we go five times with no receives, but we are sending then + // we will reset the adapter. + // + if ((Adapter->NoReceiveInterruptCount == 5) && !Adapter->ResetInProgress) { + + // + // We've waited long enough + // + Adapter->ResetAsynchronous = TRUE; + Adapter->SendInterrupt = FALSE; + Adapter->NoReceiveInterruptCount = 0; + + return(TRUE); + + } else { + + Adapter->NoReceiveInterruptCount++; + + } + + } else { + + // + // If we got a receive or there are no sends, doesn't matter. Reset + // the state. + // + Adapter->SendInterrupt = FALSE; + Adapter->ReceiveInterrupt = FALSE; + Adapter->NoReceiveInterruptCount = 0; + + } + + return(FALSE); + +} diff --git a/private/ntos/ndis/ne3200/ne3200.ini b/private/ntos/ndis/ne3200/ne3200.ini new file mode 100644 index 000000000..356d754e9 --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200.ini @@ -0,0 +1,18 @@ +// +// This section is used to configure the Novell NE3200 Ethernet adapter for +// non-Compaq machines. This section will be removed when the registry +// becomes available. These values must matched the ones configured using +// the EISA configuration utility. +// +// Defaults are shown below. +// + + +[NE3200Sys] + Bind1=\Device\NE32001 + +[NE32001] + InterruptNumber = 9 + InterruptType = EdgeTriggered + SlotNumber = 3 + diff --git a/private/ntos/ndis/ne3200/ne3200.prf b/private/ntos/ndis/ne3200/ne3200.prf new file mode 100644 index 000000000..814c0d1ff --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200.prf @@ -0,0 +1,40 @@ +NE3200ChangeClass@8 +@NE3200RelinquishCommandBlock@8 +NE3200CheckForHang@4 +NE3200DisableInterrupt@4 +NE3200HandleInterrupt@4 +NE3200TransmitPacket@20 +@NE3200ProcessCommandInterrupts@4 +@Ne3200Stall@4 +NE3200EnableInterrupt@4 +NE3200Send@12 +@NE3200ProcessReceiveInterrupts@4 +NE3200UpdateMulticastTable@12 +NE3200EnableAdapter@4 +NE3200ChangeCurrentAddress@4 +NE3200FinishQueryInformation@4 +NE3200QueryInformation@24 +NE3200SetConfigurationBlock@4 +NE3200DoAdapterReset@4 +NE3200ConstrainPacket@8 +NE3200SetupForReset@4 +NE3200ResetHandler@16 +NE3200Reset@8 +NE3200TransmitMergedPacket@8 +NE3200GetStationAddress@4 +NE3200SetInformation@24 +NE3200ResetCommandBlocks@4 +SyncNE3200ClearDoorbellInterrupt@4 +NE3200StartChipAndDisableInterrupts@8 +NE3200DoResetIndications@8 +NE3200AcquirePublicCommandBlock@8 +NE3200Isr@12 +NE3200SetConfigurationBlockAndInit@4 +NE3200ResetVariables@4 +NE3200Initialize@24 +NE3200StopChip@4 +NE3200AllocateAdapterMemory@4 +NE3200InitialInit@12 +NE3200RegisterAdapter@20 +NE3200InitializeGlobals@8 +DriverEntry@8 diff --git a/private/ntos/ndis/ne3200/ne3200.rc b/private/ntos/ndis/ne3200/ne3200.rc new file mode 100644 index 000000000..14c68c9ad --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200.rc @@ -0,0 +1,39 @@ +#include <windows.h> +#include <ntverp.h> + +/*-----------------------------------------------*/ +/* the following lines are specific to this file */ +/*-----------------------------------------------*/ + +/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR + * and VER_INTERNALNAME_STR must be defined before including COMMON.VER + * The strings don't need a '\0', since common.ver has them. + */ +#define VER_FILETYPE VFT_DRV +/* possible values: VFT_UNKNOWN + VFT_APP + VFT_DLL + VFT_DRV + VFT_FONT + VFT_VXD + VFT_STATIC_LIB +*/ +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +/* possible values VFT2_UNKNOWN + VFT2_DRV_PRINTER + VFT2_DRV_KEYBOARD + VFT2_DRV_LANGUAGE + VFT2_DRV_DISPLAY + VFT2_DRV_MOUSE + VFT2_DRV_NETWORK + VFT2_DRV_SYSTEM + VFT2_DRV_INSTALLABLE + VFT2_DRV_SOUND + VFT2_DRV_COMM +*/ +#define VER_FILEDESCRIPTION_STR "Novell NE3200 network driver" +#define VER_INTERNALNAME_STR "NE3200.SYS" +#define VER_ORIGINALFILENAME_STR "NE3200.SYS" + +#include "common.ver" + diff --git a/private/ntos/ndis/ne3200/ne3200hw.h b/private/ntos/ndis/ne3200/ne3200hw.h new file mode 100644 index 000000000..ab640b819 --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200hw.h @@ -0,0 +1,964 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + ne3200hw.h + +Abstract: + + Hardware specific values for the Novell NE3200 NDIS 3.0 driver. + +Author: + + Keith Moore (KeithMo) 08-Jan-1991 + +Environment: + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + +--*/ + +#ifndef _NE3200HARDWARE_ +#define _NE3200HARDWARE_ + +// +// Defines for the packet and media specific information +// +#define MINIMUM_ETHERNET_PACKET_SIZE ((UINT)60) +#define MAXIMUM_ETHERNET_PACKET_SIZE ((UINT)1514) +#define NE3200_LENGTH_OF_ADDRESS 6 + +// +// The default interrupt number. +// +#define NE3200_DEFAULT_INTERRUPT_VECTOR ((CCHAR)11) + +// +// The following parameters *MUST* each be a greater than one! +// +// The number of receive buffers to allocate. +// The number of transmit buffers to allocate. +// The number of command blocks for transmits that the driver has available. +// The number of command blocks for requests the driver has availabale. +// +#define NE3200_NUMBER_OF_RECEIVE_BUFFERS ((UINT)16) +#define NE3200_NUMBER_OF_TRANSMIT_BUFFERS ((UINT)4) +#define NE3200_NUMBER_OF_COMMAND_BLOCKS ((UINT)8) +#define NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS ((UINT)3) + + +// +// MAC.BIN info. +// +#define NE3200_MAXIMUM_MACBIN_SIZE ((ULONG)16384) +#define NE3200_MACBIN_LENGTH 4096 + + +// +// This is the number of bytes per entry in the multicast table +// as presented to the NE3200. Note that this is *not* the number +// of bytes in a multicast address, just the number of bytes per +// table entry. For some goofy reason, MAC.BIN requires the table +// used in the NE3200_COMMAND_SET_MULTICAST_ADDRESS command to have +// 16 bytes per entry. +// +#define NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY ((UINT)16) +#define NE3200_MAXIMUM_MULTICAST ((UINT)50) + + +// +// Our buffer sizes. +// +// These are *not* configurable. Portions of the code assumes +// that these buffers can contain *any* legal Ethernet packet. +// +#define NE3200_SIZE_OF_TRANSMIT_BUFFERS (MAXIMUM_ETHERNET_PACKET_SIZE) +#define NE3200_SIZE_OF_RECEIVE_BUFFERS (MAXIMUM_ETHERNET_PACKET_SIZE) + + +// +// I/O Port Address. +// +// Note that the NE3200 uses EISA Slot-Specific Addressing. In +// this method, each slot has its own I/O address space. This space +// begins at the slot number shifted left 12 bits. For example, +// the I/O space for slot number 6 begins at I/O address 6000h. +// +// Each of the following addresses are offset from the start of +// slot-specific I/O space. +// +#define NE3200_RESET_PORT ((USHORT)0x0000) +#define NE3200_ID_PORT ((USHORT)0x0C80) +#define NE3200_GLOBAL_CONFIGURATION_PORT ((USHORT)0x0C88) +#define NE3200_SYSTEM_INTERRUPT_PORT ((USHORT)0x0C89) +#define NE3200_LOCAL_DOORBELL_MASK_PORT ((USHORT)0x0C8C) +#define NE3200_LOCAL_DOORBELL_INTERRUPT_PORT ((USHORT)0x0C8D) +#define NE3200_SYSTEM_DOORBELL_MASK_PORT ((USHORT)0x0C8E) +#define NE3200_SYSTEM_DOORBELL_INTERRUPT_PORT ((USHORT)0x0C8F) +#define NE3200_BASE_MAILBOX_PORT ((USHORT)0x0C90) + + +// +// Definitions for NE3200_RESET_PORT. +// +#define NE3200_RESET_BIT_ON ((UCHAR)1) +#define NE3200_RESET_BIT_OFF ((UCHAR)0) + + +// +// Mailbox Registers +// +#define NE3200_MAILBOX_RESET_STATUS ((USHORT)0x0000) +#define NE3200_MAILBOX_COMMAND_POINTER ((USHORT)0x0000) +#define NE3200_MAILBOX_MACBIN_LENGTH ((USHORT)0x0001) +#define NE3200_MAILBOX_MACBIN_DOWNLOAD_MODE ((USHORT)0x0003) +#define NE3200_MAILBOX_RECEIVE_POINTER ((USHORT)0x0004) +#define NE3200_MAILBOX_MACBIN_POINTER ((USHORT)0x0004) +#define NE3200_MAILBOX_STATUS ((USHORT)0x0008) +#define NE3200_MAILBOX_MACBIN_TARGET ((USHORT)0x0008) +#define NE3200_MAILBOX_STATION_ID ((USHORT)0x000A) + + +// +// Values for MAC.BIN download +// +#define NE3200_MACBIN_DIRECT ((UCHAR)0x80) +#define NE3200_MACBIN_TARGET_ADDRESS ((USHORT)0x0400) + + +// +// Status read from NE3200_MAILBOX_RESET_STATUS after hardware reset +// +#define NE3200_RESET_FAILED ((UCHAR)0x40) +#define NE3200_RESET_PASSED ((UCHAR)0x80) + + +// +// Status read from NE3200_MAILBOX_STATUS after initialization +// +#define NE3200_INITIALIZATION_FAILED ((UCHAR)0x20) +#define NE3200_INITIALIZATION_PASSED ((UCHAR)0x60) + + +// +// Local DoorBell bits +// +#define NE3200_LOCAL_DOORBELL_NEW_COMMAND ((UCHAR)0x01) +#define NE3200_LOCAL_DOORBELL_RESET ((UCHAR)0x04) +#define NE3200_LOCAL_DOORBELL_INITIALIZE ((UCHAR)0x10) +#define NE3200_LOCAL_DOORBELL_NEW_RECEIVE ((UCHAR)0x20) + +#define NE3200_LOCAL_DOORBELL_MASK \ + ( NE3200_LOCAL_DOORBELL_NEW_COMMAND \ + | NE3200_LOCAL_DOORBELL_RESET \ + | NE3200_LOCAL_DOORBELL_INITIALIZE \ + | NE3200_LOCAL_DOORBELL_NEW_RECEIVE ) + + +// +// System DoorBell bits +// +#define NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED ((UCHAR)0x01) +#define NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE ((UCHAR)0x02) +#define NE3200_SYSTEM_DOORBELL_RESET_COMPLETE ((UCHAR)0x04) +#define NE3200_SYSTEM_DOORBELL_INIT_COMPLETE ((UCHAR)0x08) +#define NE3200_SYSTEM_DOORBELL_SELF_RESET ((UCHAR)0x10) + +#define NE3200_SYSTEM_DOORBELL_MASK \ + ( NE3200_SYSTEM_DOORBELL_PACKET_RECEIVED \ + | NE3200_SYSTEM_DOORBELL_COMMAND_COMPLETE) + + +// +// System Interrupt Mask/Control bits +// +#define NE3200_SYSTEM_INTERRUPT_ENABLE ((UCHAR)0x01) +#define NE3200_SYSTEM_INTERRUPT_PENDING ((UCHAR)0x02) + + +// +// NE3200 Command Codes +// +#define NE3200_COMMAND_NOP ((UCHAR)0x00) +#define NE3200_COMMAND_SET_STATION_ADDRESS ((UCHAR)0x01) +#define NE3200_COMMAND_CONFIGURE_82586 ((UCHAR)0x02) +#define NE3200_COMMAND_SET_MULTICAST_ADDRESS ((UCHAR)0x03) +#define NE3200_COMMAND_TRANSMIT ((UCHAR)0x04) +#define NE3200_COMMAND_READ_ADAPTER_STATISTICS ((UCHAR)0x08) +#define NE3200_COMMAND_INITIALIZE_ADAPTER ((UCHAR)0x09) +#define NE3200_COMMAND_CLEAR_ADAPTER_STATISTICS ((UCHAR)0x0A) + + +// +// NE3200 Receive/Command Block States +// +#define NE3200_STATE_FREE ((USHORT)0x0000) +#define NE3200_STATE_EXECUTION_COMPLETE ((USHORT)0x0001) +#define NE3200_STATE_WAIT_FOR_ADAPTER ((USHORT)0x0002) + + +// +// NE3200 Command Block Status +// + +// +// These apply to all commands. +// +#define NE3200_STATUS_COMPLETE ((USHORT)0x8000) +#define NE3200_STATUS_BUSY ((USHORT)0x4000) +#define NE3200_STATUS_SUCCESS ((USHORT)0x2000) +#define NE3200_STATUS_ABORTED ((USHORT)0x1000) +#define NE3200_STATUS_GENERIC_MASK ((USHORT)0xF000) + +// +// These apply to transmit only. +// +#define NE3200_STATUS_NO_CARRIER ((USHORT)0x0400) +#define NE3200_STATUS_NO_CLEAR_TO_SEND ((USHORT)0x0200) +#define NE3200_STATUS_DMA_UNDERRUN ((USHORT)0x0100) +#define NE3200_STATUS_TRANSMIT_DEFERRED ((USHORT)0x0080) +#define NE3200_STATUS_HEART_BEAT ((USHORT)0x0040) +#define NE3200_STATUS_MAXIMUM_COLLISIONS ((USHORT)0x0020) +#define NE3200_STATUS_COLLISION_MASK ((USHORT)0x000F) +#define NE3200_STATUS_FATALERROR_MASK (NE3200_STATUS_NO_CARRIER | \ + NE3200_STATUS_NO_CLEAR_TO_SEND | \ + NE3200_STATUS_DMA_UNDERRUN | \ + NE3200_STATUS_HEART_BEAT | \ + NE3200_STATUS_MAXIMUM_COLLISIONS) + +// +// This defines a "proper" command complete status. +// +#define NE3200_STATUS_COMMAND_COMPLETE (NE3200_STATUS_COMPLETE | \ + NE3200_STATUS_SUCCESS) + + +// +// Timeout constants +// +// Each of these timeout constants represents the time to wait +// for a particular event to occur. For example, NE3200_TIMEOUT_RESET +// represents the amount of time to wait for an adapter reset to +// complete. Each of these values is in units of 1/100 of a second. +// Therefore, a value of 200 would be approximately 2 seconds. +// +#define NE3200_TIMEOUT_RESET 200 +#define NE3200_TIMEOUT_DOWNLOAD 100 + +// +// This timeout represents the maximum amount of time we'll wait +// for an NE3200 command to complete. This value is in units of +// 1/1000 of a second. Therefore, a value of 2000 would be approximately +// 2 seconds. +// +#define NE3200_TIMEOUT_COMMAND 2000 + + +// +// This type defines the physical addresses used by the NE3200 +// card itself. This should always be four bytes. +// +typedef ULONG NE3200_PHYSICAL_ADDRESS, *PNE3200_PHYSICAL_ADDRESS; + + +// +// Miscellaneous Constants +// +#define NE3200_NULL ((NE3200_PHYSICAL_ADDRESS)(-1L)) +#define NE3200_MAXIMUM_BLOCKS_PER_PACKET ((UINT)4) +#define NE3200_IMMEDIATE_DATA_LENGTH ((UINT)64) + + + +// +// Force misalignment of the following structures +// +#include <pshpack1.h> + + +// +// NE3200 Data Block Descriptor +// +typedef struct _NE3200_DATA_BLOCK { + + // + // This is the length (in bytes) of this block. + // + USHORT BlockLength; + + // + // This is the physical address of this block. + // + NE3200_PHYSICAL_ADDRESS PhysicalAddress; + +} NE3200_DATA_BLOCK, *PNE3200_DATA_BLOCK; + + +// +// NE3200 Receive Ring Entry +// +typedef struct _NE3200_RECEIVE_ENTRY { + + // + // This 4-byte field is unused by MAC.BIN and is + // available for use by the driver. We'll use + // this field as . . . + // + UCHAR Available1[4]; + + // + // This is the state of this Receive Ring entry. + // + USHORT State; + + // + // This is the total size of the received frame. + // + USHORT FrameSize; + + // + // This is the physical address of the next entry + // in the Receive Ring. + // + NE3200_PHYSICAL_ADDRESS NextPending; + + // + // This 6-byte field is unused by MAC.BIN and is + // available for use by the driver. We'll use + // this field as . . . + // + UCHAR Available2[6]; + + // + // This is the descriptor which specifies the + // receive buffer used by this entry. + // + NE3200_DATA_BLOCK BufferDescriptor; + +} NE3200_RECEIVE_ENTRY, *PNE3200_RECEIVE_ENTRY; + + +// +// NE3200 Command Block +// +typedef struct _NE3200_COMMAND_BLOCK { + + // + // This 4-byte field is unused by MAC.BIN and is + // available for use by the driver. We'll use + // this field as . . . + // + UCHAR Available1[4]; + + // + // This is the state of this Command Block. + // + USHORT State; + + // + // This is the status of this Command Block. + // + USHORT Status; + + // + // This is the physical address of the next Command Block + // to be executed. If this address == -1, then there are + // no more commands to be executed. + // + NE3200_PHYSICAL_ADDRESS NextPending; + + // + // This 1-byte field is unused by MAC.BIN and is + // available for use by the driver. We'll use + // this field as . . . + // + UCHAR Available2[1]; + + // + // This is the NE3200 Command Code. + // + UCHAR CommandCode; + + // + // This 1-byte field is unused by MAC.BIN and is + // available for use by the driver. We'll use + // this field as . . . + // + UCHAR Available3[1]; + + // + // The following eight bytes are used as parameters + // by various NE3200 commands. + // + union _PARAMETERS { + + // + // Parameters for NE3200_COMMAND_SET_STATION_ADDRESS. + // + struct _SET_ADDRESS { + + // + // This field contains the new station address. + // + IN UCHAR NewStationAddress[NE3200_LENGTH_OF_ADDRESS]; + + } SET_ADDRESS; + + // + // Parameters for NE3200_COMMAND_CONFIGURE_82586. + // + struct _CONFIGURE { + + // + // This field holds the physical address of + // the configuration block. + // + IN NE3200_PHYSICAL_ADDRESS ConfigurationBlock; + + } CONFIGURE; + + // + // Parameters for NE3200_COMMAND_SET_MULTICAST_ADDRESS. + // + struct _MULTICAST { + + // + // This field holds the physical address of + // the multicast address table. + // + IN NE3200_PHYSICAL_ADDRESS MulticastAddressTable; + + // + // This field holds the number of multicast + // address in the multicast address table. + // + IN USHORT NumberOfMulticastAddresses; + + } MULTICAST; + + // + // Parameters for NE3200_COMMAND_TRANSMIT. + // + struct _TRANSMIT { + + // + // This field holds the length of "immediate data" + // to be transmitted. + // + IN USHORT ImmediateDataLength; + + } TRANSMIT; + + // + // Parameters for NE3200_READ_ADAPTER_STATISTICS. + // + struct _STATISTICS { + + // + // The following fields are filled in by the adapter + // when it executes the NE3200_READ_ADAPTER_STATISTICS + // command. + // + + // + // This field holds the number of properly aligned + // frames received with a CRC error. + // + OUT USHORT CrcErrors; + + // + // This field holds the number of misaligned frames + // received. + // + OUT USHORT AlignmentErrors; + + // + // This field holds the number of resource errors + // (the number of frames which were discarded due + // to lack of memory resources such as buffer space + // or receive frame descriptors). + // + OUT USHORT ResourceErrors; + + // + // This field holds the number of received frame + // sequeneces lost because the memory bus was + // not available in time for the transfer. + // + OUT USHORT OverrunErrors; + + } STATISTICS; + + // + // This field holds the raw data. + // + IN OUT USHORT RawParameters[4]; + + } PARAMETERS; + + // + // This is the total size of the frame to be transmitted. + // + USHORT TransmitFrameSize; + + // + // This is the number of data blocks in the frame to be + // transmitted. + // + UCHAR NumberOfDataBlocks; + + // + // These are the descriptors describing the transmit packet. + // + NE3200_DATA_BLOCK TransmitDataBlocks[NE3200_MAXIMUM_BLOCKS_PER_PACKET]; + + // + // This is the immediate data to be used by all commands + // other than transmit. + // + UCHAR ImmediateData[NE3200_IMMEDIATE_DATA_LENGTH]; + +} NE3200_COMMAND_BLOCK, *PNE3200_COMMAND_BLOCK; + + +// +// NE3200 Configuration Block +// +// This structure contains configuration data for the NE3200's +// on-board 82586 Lan Coprocessor. The majority of this data +// will not change during operation of the driver. +// +typedef struct _NE3200_CONFIGURATION_BLOCK { + + // + // This field contains the number of bytes in the + // Configuration Block. + // + // In this implementation, this will always be 12. + // + USHORT ByteCount:4; + + // + // This field is undefined by the 82586. + // + USHORT Undefined1:4; + + // + // This field contains the FIFO threshold. + // + // In this implementation, this will always be 8. + // + USHORT FifoThreshold:4; + + // + // This field is undefined by the 82586. + // + USHORT Undefined2:4; + + // + // This field is undefined by the 82586. + // + USHORT Undefined3:6; + + // + // If this field is set to 0, the 82586 operates with + // internal synchronization. If set to 1, the 82586 + // uses external synchronization. + // + // This will always be set to 0 in this implementation + // (internal synchronization). + // + USHORT Synchronization:1; + + // + // If this field is set to 0, the 82586 will not save + // bad frames in memory. If set to 1, the 82856 will + // save bad frames. + // + // In this implementation, this will always be 0 + // (don't save bad frames). + // + USHORT SaveBadFrames:1; + + // + // This field contains the number of bytes in a + // network address. + // + // In this implementation, this will always be 6. + // + USHORT AddressLength:3; + + // + // If this field is set to 0, then the Destination + // Network Address is part of the Transmit Command Block + // and the Source Address is inserted by the 82586. If + // set to 1, then the Destination and Source Addresses + // are part of the Transmit/Receive data buffers. + // + // In this implementation, this is always set to 1 + // (Addresses are part of the data buffers). + // + USHORT SeparateAddressAndLength:1; + + // + // These two bits determine the length of the packet + // preamble according to the following table: + // + // Bits Preamble Length + // ---- --------------- + // 00 2 bytes + // 01 4 bytes + // 10 8 bytes + // 11 16 bytes + // + // In this implementation, these bits will always be + // set to 10 (8 byte preamble). + // + USHORT PreambleLength:2; + + // + // These two field control internal/external loopback on + // the 82586. + // + // In this implementation, these two fields should be set to 0. + // + USHORT InternalLoopback:1; + USHORT ExternalLoopback:1; + + // + // This field contains the linear backoff priority. + // + // In this implementation, this field will always be 0. + // + USHORT LinearPriority:3; + + // + // This field is undefined by the 82586. + // + USHORT Undefined4:1; + + // + // This field contains the exponential backoff priority. + // + // In this implementation, this field will always be 0. + // + USHORT ExponentialPriority:3; + + // + // If this field is set to 0, the 82586 will use the + // IEEE 802.3/Ethernet exponential backoff method. If + // set to 1, the 82586 will use an alternate backoff + // method. + // + // In this implementation, this field will always be 0 + // (use the IEEE 802.3/Ethernet backoff method). + // + USHORT ExponentialBackoffMethod:1; + + // + // This field contains the Interframe Spacing in TxC units. + // + // In this implementation, this field will always be 96. + // + USHORT InterframeSpacing:8; + + // + // This field contains the Slot Time Number. + // + // In this implementation, this field will always be 512. + // + USHORT SlotTime:11; + + // + // This field is undefined by the 82586. + // + USHORT Undefined5:1; + + // + // This field contains the maximum number of transmission + // retries on collisions. + // + // In this implementation, this field will always be 15. + // + USHORT MaximumRetries:4; + + // + // If this field is set to 0, Promiscuous Mode will be disabled. + // If set to 1, then Promiscuous Mode will be enabled and the + // 82586 will receive *all* packets. + // + // This field will initially be set to 0 (disable Promiscuous + // Mode) but may be changed when a protocol requests a change + // to the packet filter. + // + USHORT PromiscuousMode:1; + + // + // If this field is set to 0, then all Broadcast Packets will be + // received. If set to 1, then Broadcast reception is disabled. + // + // This field will initially be set to 1 (disable Broadcast + // reception) but may be changed when a protocol requests a change + // to the packet filter. + // + USHORT DisableBroadcast:1; + + // + // If this field is set to 0, then the 82586 will use NRZ encoding + // and decoding. If set to 1, the 82586 will use Manchester + // encoding and decoding. + // + // In this implementation, this field will always be set to 0 + // (use NRZ encoding). + // + USHORT EncodingMethod:1; + + // + // If this field is set to 0, then the 82586 will cease transmission + // if CRS goes inactive during frame transmission. If set to 1, + // the 82586 will continue transmission even if there is no carrier + // sense. + // + // In this implementation, this field will always be set to 0 + // (cease transmission if carrier lost). + // + USHORT TransmitOnNoCarrier:1; + + // + // If this field is set to 0, then the 82586 will insert a CRC + // field into the packet. If set to 1, then no CRC will be + // inserted + // + // In this implementation, this field will always be set to 0 + // (insert CRC field). + // + USHORT DisableCrcInsertion:1; + + // + // If this field is set to 0, then the 82856 will use the + // 32-bit Autodin II CRC polynomial. If set to 1 then the + // 16-bit CCITT CRC polynomial will be used. + // + // In this implementation, this field will always be set to 0 + // (use the 32-bit Autodin II CRC polynomial). + // + USHORT CrcType:1; + + // + // If this field is set to 0, then the 82586 will use the + // Ethernet bitstuffing method. If set to 1 then the 82586 will + // use an HDLC-like bitstuffing method. + // + // In this implementation, this field will always be set to 0 + // (use the Ethernet bitstuffing method). + // + USHORT BitStuffingMethod:1; + + // + // If this field is set to 0, then the 82586 will perform no + // padding. If set to 1 then the 82586 will pad transmits + // out to the full slot time. + // + // In this implementation, this field will always be set to 0 + // (no padding). + // + USHORT EnablePadding:1; + + // + // This field contains the Carrier Sense Filter (in bit times). + // + // In this implementation, this field will always be set to 0. + // + USHORT CarrierSenseFilter:2; + + // + // If this field is set to 0, then the 82586 will use an external + // carrier sense source. If set to 1 than an internal carrier + // sense source is used. + // + // In this implementation, this field will always be set to 0 + // (external carrier sense source). + // + USHORT CarrierSenseSource:1; + + // + // This field contains the Collision Detect Filter (in bit times). + // + // In this implementation, this field will always be set to 0. + // + USHORT CollisionDetectFilter:2; + + // + // If this field is set to 0, then the 82586 will use an external + // collision detect source. If set to 1 then an internal + // collision detect source is used. + // + // In this implementation, this field will always be set to 0 + // (external collision detect source). + // + USHORT CollisionDetectSource:1; + + // + // Padding bits to align MinimumFrameLength + // + USHORT TempPadding:2; + + // + // This field contains the minimum number of bytes in a frame. + // + // In this implementation, this field will always be 64. + // + USHORT MinimumFrameLength:8; + + // + // The following three bits are technically undefined by the + // 82586, but are used by MAC.BIN. + // + + // + // This bit must be set to 1 to enable packet reception. If + // this bit is not set, then no packets will be received. + // + USHORT MacBinEnablePacketReception:1; + + // + // This bit is unused. + // + USHORT MacBinUnused:1; + + // + // If promiscuous mode is enabled, then this but must also + // be set. This short-circuits MAC.BIN's multicast filtering. + // + USHORT MacBinPromiscuous:1; + + // + // This field is (honest!) unused. + // + USHORT Undefined6:5; + +} NE3200_CONFIGURATION_BLOCK, *PNE3200_CONFIGURATION_BLOCK; + +#include <poppack.h> + + + +// +// Macros to read/write BMIC registers +// +#define NE3200_READ_MAILBOX_UCHAR(_Adapter, _MailboxIndex, _pValue) \ + NdisRawReadPortUchar( \ + (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \ + (PUCHAR)(_pValue) \ + ) + +#define NE3200_READ_MAILBOX_USHORT(_Adapter, _MailboxIndex, _pValue) \ + NdisRawReadPortUshort( \ + (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \ + (PUSHORT)(_pValue) \ + ) + +#define NE3200_READ_MAILBOX_ULONG(_Adapter, _MailboxIndex, _pValue) \ + NdisRawReadPortUlong( \ + (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \ + (PULONG)(_pValue) \ + ) + +#define NE3200_WRITE_MAILBOX_UCHAR(_Adapter, _MailboxIndex, _Value) \ + NdisRawWritePortUchar( \ + (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \ + (UCHAR)(_Value) \ + ) + +#define NE3200_WRITE_MAILBOX_USHORT(_Adapter, _MailboxIndex, _Value) \ + NdisRawWritePortUshort( \ + (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \ + (USHORT)(_Value) \ + ) + +#define NE3200_WRITE_MAILBOX_ULONG(_Adapter, _MailboxIndex, _Value) \ + NdisRawWritePortUlong( \ + (ULONG)(_Adapter)->BaseMailboxPort+(_MailboxIndex), \ + (ULONG)(_Value) \ + ) + +#define NE3200_WRITE_COMMAND_POINTER(_Adapter, _Address) \ + NE3200_WRITE_MAILBOX_ULONG( \ + _Adapter, \ + NE3200_MAILBOX_COMMAND_POINTER, \ + (_Address) \ + ) + +#define NE3200_WRITE_RECEIVE_POINTER(_Adapter, _Address) \ + NE3200_WRITE_MAILBOX_ULONG( \ + _Adapter, \ + NE3200_MAILBOX_RECEIVE_POINTER, \ + (_Address) \ + ) + +#define NE3200_READ_LOCAL_DOORBELL_INTERRUPT(_Adapter, _pValue) \ + NdisRawReadPortUchar( \ + (ULONG)(_Adapter)->LocalDoorbellInterruptPort, \ + (PUCHAR)(_pValue) \ + ) + +#define NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(_Adapter, _Value) \ + NdisRawWritePortUchar( \ + (ULONG)(_Adapter)->LocalDoorbellInterruptPort, \ + (UCHAR)(_Value) \ + ) + +#define NE3200_READ_SYSTEM_DOORBELL_INTERRUPT(_Adapter, _pValue) \ + NdisRawReadPortUchar( \ + (ULONG)(_Adapter)->SystemDoorbellInterruptPort, \ + (PUCHAR)(_pValue) \ + ) + +#define NE3200_SYNC_CLEAR_SYSTEM_DOORBELL_INTERRUPT(_Adapter) \ + NdisMSynchronizeWithInterrupt(\ + &(_Adapter)->Interrupt,\ + SyncNE3200ClearDoorbellInterrupt,\ + (PVOID)(_Adapter)\ + ) + +#define NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT(_Adapter, _Value) \ + NdisRawWritePortUchar( \ + (ULONG)(_Adapter)->SystemDoorbellInterruptPort, \ + (UCHAR)(_Value) \ + ) + +#define NE3200_READ_SYSTEM_DOORBELL_MASK(_Adapter, _pValue) \ + NdisRawReadPortUchar( \ + (ULONG)(_Adapter)->SystemDoorbellMaskPort, \ + (PUCHAR)(_pValue) \ + ) + +#define NE3200_WRITE_SYSTEM_DOORBELL_MASK(_Adapter, _Value) \ + NdisRawWritePortUchar( \ + (ULONG)(_Adapter)->SystemDoorbellMaskPort, \ + (UCHAR)(_Value) \ + ) + +#define NE3200_WRITE_SYSTEM_INTERRUPT(_Adapter, _Value) \ + NdisRawWritePortUchar( \ + (ULONG)(_Adapter)->SystemInterruptPort, \ + (UCHAR)(_Value) \ + ) + +#define NE3200_WRITE_RESET(_Adapter, _Value) \ + NdisRawWritePortUchar( \ + (ULONG)(_Adapter)->ResetPort, \ + (UCHAR)(_Value) \ + ) + +#endif // _NE3200HARDWARE_ diff --git a/private/ntos/ndis/ne3200/ne3200pr.h b/private/ntos/ndis/ne3200/ne3200pr.h new file mode 100644 index 000000000..68485cf0e --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200pr.h @@ -0,0 +1,273 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + ne3200proc.h + +Abstract: + + Procedure declarations for the Novell NE3200 NDIS 3.0 driver. + Moved most of these from ne3200sw.h + +Author: + + Johnson R. Apacible (johnsona) 21-Aug-1991 + +Environment: + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + +--*/ + +#ifndef _NE3200PROC_ +#define _NE3200PROC_ + +// +// We define the external interfaces to the NE3200 driver. +// These routines are only external to permit separate +// compilation. Given a truely fast compiler they could +// all reside in a single file and be static. +// +extern +BOOLEAN +NE3200CheckForHang( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +VOID +NE3200DisableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +VOID +NE3200EnableInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +VOID +NE3200Halt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +VOID +NE3200HandleInterrupt( + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +NDIS_STATUS +NE3200Initialize( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ); + +extern +VOID +NE3200Isr( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueDpc, + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +NDIS_STATUS +NE3200QueryInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded + ); + +extern +NDIS_STATUS +NE3200Reset( + OUT PBOOLEAN AddressingReset, + IN NDIS_HANDLE MiniportAdapterContext + ); + +extern +NDIS_STATUS +NE3200Send( + IN NDIS_HANDLE MiniportAdapterContext, + IN PNDIS_PACKET Packet, + IN UINT Flags + ); + +extern +NDIS_STATUS +NE3200SetInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ); + +extern +NDIS_STATUS +NE3200TransferData( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE MiniportReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ); + +VOID +NE3200StartChipAndDisableInterrupts( + IN PNE3200_ADAPTER Adapter, + IN PNE3200_SUPER_RECEIVE_ENTRY FirstReceiveEntry + ); + +VOID +NE3200FinishQueryInformation( + IN PNE3200_ADAPTER Adapter + ); + + +VOID +NE3200GetStationAddress( + IN PNE3200_ADAPTER Adapter + ); + +VOID +NE3200StopChip( + IN PNE3200_ADAPTER Adapter + ); + +BOOLEAN +NE3200RegisterAdapter( + IN NDIS_HANDLE MiniportAdapterHandle, + IN UINT EisaSlot, + IN UINT InterruptVector, + IN NDIS_INTERRUPT_MODE InterruptMode, + IN PUCHAR CurrentAddress + ); + +VOID +NE3200AcquirePublicCommandBlock( + IN PNE3200_ADAPTER Adapter, + OUT PNE3200_SUPER_COMMAND_BLOCK * CommandBlock + ); + +VOID +FASTCALL +NE3200RelinquishCommandBlock( + IN PNE3200_ADAPTER Adapter, + IN PNE3200_SUPER_COMMAND_BLOCK CommandBlock + ); + +VOID +NE3200DoAdapterReset( + IN PNE3200_ADAPTER Adapter + ); + +VOID +NE3200SetupForReset( + IN PNE3200_ADAPTER Adapter + ); + +NDIS_STATUS +NE3200UpdateMulticastTable( + IN PNE3200_ADAPTER Adapter, + IN UINT CurrentAddressCount, + IN CHAR CurrentAddresses[][NE3200_LENGTH_OF_ADDRESS] + ); + +VOID +NE3200ResetVariables( + IN PNE3200_ADAPTER Adapter + ); + +BOOLEAN +SyncNE3200ClearDoorbellInterrupt( + IN PVOID SyncContext + ); + +VOID +NE3200ResetHandler( + IN PVOID SystemSpecific1, + IN PNE3200_ADAPTER Adapter, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +VOID +NE3200DeferredTimer( + IN PVOID SystemSpecific1, + IN PNE3200_ADAPTER Adapter, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +VOID +FASTCALL +Ne3200Stall( + PULONG Dummy + ); + +#define NE3200SubmitCommandBlock( _Adapter, _CommandBlock ) \ +{ \ + ASSERT(!(NdisGetPhysicalAddressLow(_CommandBlock->Self) & 1)); \ + _CommandBlock->Timeout = FALSE; \ + if (_Adapter->FirstCommandOnCard != NULL) { \ + if (_Adapter->FirstWaitingCommand == NULL) { \ + _Adapter->FirstWaitingCommand = _CommandBlock; \ + } else { \ + PNE3200_SUPER_COMMAND_BLOCK PreviousCommandBlock; \ + PreviousCommandBlock = _Adapter->LastWaitingCommand; \ + PreviousCommandBlock->Hardware.NextPending = \ + NdisGetPhysicalAddressLow(_CommandBlock->Self); \ + PreviousCommandBlock->NextCommand = _CommandBlock; \ + } \ + _Adapter->LastWaitingCommand = _CommandBlock; \ + IF_LOG('2'); \ + } else { \ + ASSERT(_Adapter->FirstWaitingCommand == NULL); \ + IF_LOG('1'); \ + _Adapter->FirstCommandOnCard = _CommandBlock; \ + _Adapter->LastCommandOnCard = _CommandBlock; \ + NE3200_WRITE_COMMAND_POINTER(_Adapter,NdisGetPhysicalAddressLow(_CommandBlock->Self)); \ + { ULONG i; Ne3200Stall(&i); } \ + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT(_Adapter,NE3200_LOCAL_DOORBELL_NEW_COMMAND); \ + } \ +} + +#define NE3200AcquireCommandBlock( _Adapter, _CommandBlock ) \ +{ \ + if (_Adapter->NumberOfAvailableCommandBlocks) { \ + IF_LOG('a'); \ + _Adapter->NumberOfAvailableCommandBlocks--; \ + *(_CommandBlock) = _Adapter->NextCommandBlock; \ + _Adapter->NextCommandBlock++; \ + if (_Adapter->NextCommandBlock >= _Adapter->LastCommandBlockAllocated ) {\ + Adapter->NextCommandBlock = Adapter->CommandQueue; \ + } \ + } else { \ + *(_CommandBlock) = NULL; \ + } \ +} + +#endif //_NE3200PROC_ diff --git a/private/ntos/ndis/ne3200/ne3200sw.h b/private/ntos/ndis/ne3200/ne3200sw.h new file mode 100644 index 000000000..28300334f --- /dev/null +++ b/private/ntos/ndis/ne3200/ne3200sw.h @@ -0,0 +1,805 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + ne3200sw.h + +Abstract: + + Software specific values for the Novell NE3200 NDIS 3.0 driver. + +Author: + + Keith Moore (KeithMo) 08-Jan-1991 + +Environment: + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + +--*/ + +#ifndef _NE3200SOFTWARE_ +#define _NE3200SOFTWARE_ + +#include <ndis.h> +#include <ne3200hw.h> + +// +// Debugging flags. This buffer is used to record whenever the driver +// does something important. If there is a bug, then this buffer +// can be viewed from the debugger and an effective trace of events +// can be found. +// + +#if DBG + +#define IF_NE3200DBG(flag) if (NE3200Debug & (NE3200_DEBUG_ ## flag)) + +// +// Macro for putting a character in the buffer. +// +#define IF_LOG(ch) { \ + UCHAR lp = Adapter->LogPlace; \ + Adapter->LogPlace++; \ + Adapter->Log[(UCHAR)(lp+3)] = (UCHAR)'\0'; \ + Adapter->Log[lp] = (ch); \ + } + +// +// Debug flag, determines what debug information is kept around +// +extern ULONG NE3200Debug; + +// +// Possible values for the above flag +// +#define NE3200_DEBUG_DUMP_LOOKAHEAD 0x00000001 // dump lookahead buffer +#define NE3200_DEBUG_DUMP_TRANSFER 0x00000002 // dump transfer buffer +#define NE3200_DEBUG_DUMP_SEND 0x00000004 // dump send packet +#define NE3200_DEBUG_DUMP_COMMAND 0x00000008 // dump command block & buffer + +#define NE3200_DEBUG_ACQUIRE 0x00000010 // NE3200AcquireCommandBlock activity +#define NE3200_DEBUG_SUBMIT 0x00000020 // NE3200SubmitCommandBlock activity +#define NE3200_DEBUG_ASSIGN 0x00000040 // NE3200AssignPacketToCommandBlock activity +#define NE3200_DEBUG_RECEIVE 0x00000080 // ProcessReceiveInterrupts activity + +#define NE3200_DEBUG_LOUD 0x00000100 // print things +#define NE3200_DEBUG_VERY_LOUD 0x00000200 // print lots of things + +#define DPrint1(fmt) DbgPrint(fmt) +#define DPrint2(fmt,v1) DbgPrint(fmt,v1) +#define DPrint3(fmt,v1,v2) DbgPrint(fmt,v1,v2) +#define DPrint4(fmt,v1,v2,v3) DbgPrint(fmt,v1,v2,v3) + +#else // DBG + +#define IF_LOG(ch) + +#define IF_NE3200DBG(flag) if (0) +#define DPrint1(fmt) +#define DPrint2(fmt,v1) +#define DPrint3(fmt,v1,v2) +#define DPrint4(fmt,v1,v2,v3) + +#endif // DBG + +// +// Keep symbols for internal functions +// +#define STATIC + +// +// NDIS version of this driver +// +#define NE3200_NDIS_MAJOR_VERSION 3 +#define NE3200_NDIS_MINOR_VERSION 0 + + +extern NDIS_PHYSICAL_ADDRESS MinusOne; + +// +// Macro for allocating memory +// +#define NE3200_ALLOC_PHYS(_Status, _pBuffer, _Length) \ +{ \ + *(_Status) = NdisAllocateMemory( \ + (PVOID*)(_pBuffer), \ + (_Length), \ + 0, \ + MinusOne); \ +} + +// +// Macro for freeing memory +// +#define NE3200_FREE_PHYS(_Buffer) NdisFreeMemory((_Buffer), 0, 0) + + +// +// Macro for moving memory around +// +#define NE3200_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory(Destination,Source,Length) + +// +// Size of ethernet header +// +#define NE3200_HEADER_SIZE 14 + +// +// Size of lookahead buffer for loopback packets +// +#define NE3200_SIZE_OF_LOOPBACK 256 + + +// +// The implementation of RESET. +// +// The NE3200 must be "held by the hand" during the reset & download +// operations. Typically, the reset (or download) is initiated and +// the status ports are POLLED, waiting for pass/fail status. This +// is unacceptable in NT. +// +// To handle this cleanly in NT, the reset & download operations will +// be controlled by a state machine. This state machine will be +// contained by a flag and driven by a Timer Object. +// +// This ENUM represents the current state of the reset operation. +// +typedef enum _NE3200_RESET_STATE { + + NE3200ResetStateStarting, + NE3200ResetStateResetting, + NE3200ResetStateDownloading, + NE3200ResetStateReloadAddress, + NE3200ResetStateComplete + +} NE3200_RESET_STATE, *PNE3200_RESET_STATE; + +// +// This ENUM represents the result of the reset operation. +// +typedef enum _NE3200_RESET_RESULT { + + NE3200ResetResultSuccessful, + NE3200ResetResultResetFailure, + NE3200ResetResultResetTimeout, + NE3200ResetResultInitializationFailure, + NE3200ResetResultInitializationTimeout, + NE3200ResetResultInvalidState, + NE3200ResetResultResources + +} NE3200_RESET_RESULT, *PNE3200_RESET_RESULT; + + +struct _NE3200_ADAPTER; + +// +// This structure defines the global data needed by the driver. +// +typedef struct _NE3200_GLOBAL_DATA { + + // + // We need to allocate a buffer to contain the MAC.BIN code to be + // downloaded to the NE3200 adapter(s). This field will contain + // the virtual address of this buffer. + // + PVOID MacBinVirtualAddress; + NDIS_PHYSICAL_ADDRESS MacBinPhysicalAddress; + + // + // Chain of Adapters + // + LIST_ENTRY AdapterList; + + // + // The handle of the adapter used for the allocaton of + // the MAC.BIN buffer (the first one added for this MAC). + // + NDIS_HANDLE MacBinAdapterHandle; + + // + // Handle to our driver + // + NDIS_HANDLE NE3200DriverHandle; + + // + // Handle for NdisTerminateWrapper + // + NDIS_HANDLE NE3200NdisWrapperHandle; + + // + // This field contains the actual length (in bytes) of MAC.BIN. + // + USHORT MacBinLength; + +} NE3200_GLOBAL_DATA, *PNE3200_GLOBAL_DATA; + +// +// In addition to the Command Block fields which the NE3200 +// defines, we need some additional fields for our own purposes. +// To ensure that these fields are properly aligned (and to +// ensure that the actual Command Block is properly aligned) +// we'll defined a Super Command Block. This structure will +// contain a "normal" NE3200 Command Block plus some additional +// fields. +// +typedef struct _NE3200_SUPER_COMMAND_BLOCK { + + // + // The actual NE3200 Command Block. + // + NE3200_COMMAND_BLOCK Hardware; + + // + // This contains the physical address of the above Command Block. + // + NDIS_PHYSICAL_ADDRESS Self; + + // + // Points to the packet from which data is being transmitted + // through this Command Block. + // + PNDIS_PACKET OwningPacket; + + // + // This tells if the command block is a public or private command block. + // + PUINT AvailableCommandBlockCounter; + + // + // This contains the virtual address of the next pending command. + // + struct _NE3200_SUPER_COMMAND_BLOCK *NextCommand; + + // + // Is this from a set + // + BOOLEAN Set; + + // + // This field is used to timestamp the command blocks + // as they are placed into the command queue. If a + // block fails to execute, the adapter will get a kick in the ass to + // start it up again. + // + BOOLEAN Timeout; + + // + // If this is a public (adapter-wide) command block, then + // this will contain this block's index into the adapter's + // command queue. + // + USHORT CommandBlockIndex; + + // + // Count of the number of times we have retried a command. + // + UCHAR TimeoutCount; + + // + // When a packet is submitted to the hardware we record + // here whether it used adapter buffers and if so, the buffer + // index. + // + BOOLEAN UsedNE3200Buffer; + UINT NE3200BuffersIndex; + +} NE3200_SUPER_COMMAND_BLOCK, *PNE3200_SUPER_COMMAND_BLOCK; + +// +// In addition to the Receive Entry fields which the NE3200 +// defines, we need some additional fields for our own purposes. +// To ensure that these fields are properly aligned (and to +// ensure that the actual Receive Entry is properly aligned) +// we'll defined a Super Receive Entry. This structure will +// contain a "normal" NE3200 Receive Entry plus some additional +// fields. +// +typedef struct _NE3200_SUPER_RECEIVE_ENTRY { + + // + // The actual NE3200 Receive Entry. + // + NE3200_RECEIVE_ENTRY Hardware; + + // + // This contains the physical address of the above Receive Entry. + // + NDIS_PHYSICAL_ADDRESS Self; + + // + // This contains the virtual address of the next + // Receive Entry in the Receive Queue. + // + struct _NE3200_SUPER_RECEIVE_ENTRY *NextEntry; + + // + // This contains the virtual address of this Receive Entry's + // frame buffer. + // + PVOID ReceiveBuffer; + NDIS_PHYSICAL_ADDRESS ReceiveBufferPhysical; + + // + // Points to an NDIS buffer which describes this buffer + // + PNDIS_BUFFER FlushBuffer; + +} NE3200_SUPER_RECEIVE_ENTRY, *PNE3200_SUPER_RECEIVE_ENTRY; + + + +// +// This record type is inserted into the MiniportReserved portion +// of the packet header when the packet is going through the +// staged allocation of buffer space prior to the actual send. +// +typedef struct _NE3200_RESERVED { + + // + // Points to the next packet in the chain of queued packets + // being allocated or waiting for the finish of transmission. + // + PNDIS_PACKET Next; + + // + // If TRUE then the packet caused an adapter buffer to + // be allocated. + // + BOOLEAN UsedNE3200Buffer; + + // + // If the previous field was TRUE then this gives the + // index into the array of adapter buffer descriptors that + // contains the old packet information. + // + UCHAR NE3200BuffersIndex; + + // + // Gives the index of the Command Block as well as the + // command block to packet structure. + // + USHORT CommandBlockIndex; + +} NE3200_RESERVED,*PNE3200_RESERVED; + +// +// This macro will return a pointer to the NE3200 reserved portion +// of a packet given a pointer to a packet. +// +#define PNE3200_RESERVED_FROM_PACKET(Packet) \ + ((PNE3200_RESERVED)((Packet)->MiniportReserved)) + +// +// If an ndis packet does not meet the hardware contraints then +// an adapter buffer will be allocated. Enough data will be copied +// out of the ndis packet so that by using a combination of the +// adapter buffer and remaining ndis buffers the hardware +// constraints are satisfied. +// +// In the NE3200_ADAPTER structure three threaded lists are kept in +// one array. One points to a list of NE3200_BUFFER_DESCRIPTORS +// that point to small adapter buffers. Another is for medium sized +// buffers and the last for full sized (large) buffers. +// +// The allocation is controlled via a free list head and +// the free lists are "threaded" by a field in the adapter buffer +// descriptor. +// +typedef struct _NE3200_BUFFER_DESCRIPTOR { + + // + // A physical pointer to a small, medium, or large buffer. + // + NDIS_PHYSICAL_ADDRESS PhysicalNE3200Buffer; + + // + // A virtual pointer to a small, medium, or large buffer. + // + PVOID VirtualNE3200Buffer; + + // + // Flush buffer + // + PNDIS_BUFFER FlushBuffer; + + // + // Threads the elements of an array of these descriptors into + // a free list. -1 implies no more entries in the list. + // + INT Next; + + // + // Holds the amount of space (in bytes) available in the buffer + // + UINT BufferSize; + + // + // Holds the length of data placed into the buffer. This + // can (and likely will) be less that the actual buffers + // length. + // + UINT DataLength; + +} NE3200_BUFFER_DESCRIPTOR,*PNE3200_BUFFER_DESCRIPTOR; + +// +// This is the main structure for each adapter. +// +typedef struct _NE3200_ADAPTER { + +#if DBG + PUCHAR LogAddress; +#endif + + PUCHAR SystemDoorbellInterruptPort; + PUCHAR SystemDoorbellMaskPort; + + // + // Flag that when enabled lets routines know that a reset + // is in progress. + // + BOOLEAN ResetInProgress; + + // + // TRUE when a receive interrupt is received + // + BOOLEAN ReceiveInterrupt; + + BOOLEAN InterruptsDisabled; + + // + // Handle given by NDIS when the widget was initialized. + // + NDIS_HANDLE MiniportAdapterHandle; + + // + // Pointer to the head of the Receive Queue. + // + PNE3200_SUPER_RECEIVE_ENTRY ReceiveQueueHead; + + // + // Pointer to the tail of the Receive Queue. + // + PNE3200_SUPER_RECEIVE_ENTRY ReceiveQueueTail; + + // + // Packet counts + // + UINT GoodReceives; + + // + // Pointer to the next command to complete execution. + // + PNE3200_SUPER_COMMAND_BLOCK FirstCommandOnCard; + + // + // Pointers to an array of adapter buffer descriptors. + // The array will actually be threaded together by + // three free lists. The lists will be for small, + // medium and full sized packets. + // + PNE3200_BUFFER_DESCRIPTOR NE3200Buffers; + + // + // List head for the adapters buffers. If the list + // head is equal to -1 then there are no free elements + // on the list. + // + INT NE3200BufferListHead; + + UINT GoodTransmits; + + // + // Is there an outstanding request + // + BOOLEAN RequestInProgress; + + // + // Is this a packet resubmission? + // + BOOLEAN PacketResubmission; + + // + // Pointer to the most recently submitted command. + // + PNE3200_SUPER_COMMAND_BLOCK LastCommandOnCard; + + // + // Pointer to the first command waiting to be put on the list to the card. + // + PNE3200_SUPER_COMMAND_BLOCK FirstWaitingCommand; + + // + // Pointer to the last command waiting to be put on the list to the card. + // + PNE3200_SUPER_COMMAND_BLOCK LastWaitingCommand; + + PUCHAR BaseMailboxPort; + + // + // Total number of Command Blocks in the PublicCommandQueue. + // + UINT NumberOfPublicCommandBlocks; + + // + // Number of available Command Blocks in the Command Queue. + // + UINT NumberOfAvailableCommandBlocks; + + // + // Pointer to the next available Command Block. + // + PNE3200_SUPER_COMMAND_BLOCK NextCommandBlock; + + PNE3200_SUPER_COMMAND_BLOCK LastCommandBlockAllocated; +//---- + // + // Used for filter and statistics operations + // + PNE3200_SUPER_COMMAND_BLOCK PublicCommandQueue; + NDIS_PHYSICAL_ADDRESS PublicCommandQueuePhysical; + + // + // Used for padding short packets + // + PUCHAR PaddingVirtualAddress; + NDIS_PHYSICAL_ADDRESS PaddingPhysicalAddress; + + // + // Points to the card multicast entry table + // + PUCHAR CardMulticastTable; + NDIS_PHYSICAL_ADDRESS CardMulticastTablePhysical; + + // + // Holds the interrupt object for this adapter. + // + NDIS_MINIPORT_INTERRUPT Interrupt; + + // + // Current packet filter on adapter + // + UINT CurrentPacketFilter; + + // + // Is this the initial initialization reset? + // + BOOLEAN InitialInit; + + // + // These variables hold information about a pending request. + // + PUINT BytesWritten; + PUINT BytesNeeded; + NDIS_OID Oid; + PVOID InformationBuffer; + UINT InformationBufferLength; + + // + // The EISA Slot Number for this adapter. + // + USHORT EisaSlot; + + // + // The I/O Base address of the adapter. + // + ULONG AdapterIoBase; + + // + // Various mapped I/O Port Addresses for this adapter. + // + PUCHAR ResetPort; + PUCHAR SystemInterruptPort; + PUCHAR LocalDoorbellInterruptPort; + + // + // Count of CheckForHang calls that have occurred without + // a receive interrupt. + // + UCHAR NoReceiveInterruptCount; + + // + // TRUE when a send interrupt is received + // + BOOLEAN SendInterrupt; + + // + // Should we use an alternative address + // + BOOLEAN AddressChanged; + + // + // The network address from the hardware. + // + CHAR NetworkAddress[NE3200_LENGTH_OF_ADDRESS]; + CHAR CurrentAddress[NE3200_LENGTH_OF_ADDRESS]; + + // + // Pointer to the Receive Queue. + // + PNE3200_SUPER_RECEIVE_ENTRY ReceiveQueue; + NDIS_PHYSICAL_ADDRESS ReceiveQueuePhysical; + + // + // Pointer to the Command Queue. + // + PNE3200_SUPER_COMMAND_BLOCK CommandQueue; + NDIS_PHYSICAL_ADDRESS CommandQueuePhysical; + + // + // Next free public command block + // + UINT NextPublicCommandBlock; + + // + // Total number of Command Blocks in the Command Queue. + // + UINT NumberOfCommandBlocks; + + // + // Total number of Receive Buffers. + // + UINT NumberOfReceiveBuffers; + + // + // Total number of Transmit Buffers. + // + UINT NumberOfTransmitBuffers; + + // + // The Flush buffer pool + // + PNDIS_HANDLE FlushBufferPoolHandle; + + // + // Is the reset to be done asynchronously? + // + BOOLEAN ResetAsynchronous; + + // + // Used to store the command block for asynchronous resetting. + // + PNE3200_SUPER_COMMAND_BLOCK ResetHandlerCommandBlock; + + // + // Index of the receive ring descriptor that started the + // last packet not completely received by the hardware. + // + UINT CurrentReceiveIndex; + + // + // Counters to hold the various number of errors/statistics for both + // reception and transmission. + // + + // + // Packet counts + // + UINT TransmitsQueued; + + // + // Count of transmit errors + // + UINT RetryFailure; + UINT LostCarrier; + UINT UnderFlow; + UINT NoClearToSend; + UINT Deferred; + UINT OneRetry; + UINT MoreThanOneRetry; + + // + // Count of receive errors + // + UINT CrcErrors; + UINT AlignmentErrors; + UINT OutOfResources; + UINT DmaOverruns; + + // + // This holds the current state of the reset operation. + // + NE3200_RESET_STATE ResetState; + + // + // This hold the result of the reset operation. + // + NE3200_RESET_RESULT ResetResult; + + // + // This is a timeout counter. Before a timed operation is + // started, a positive value is placed in this field. Every + // time the particular state is entered in the ResetDpc, this + // value is decremented. If this value becomes zero, then + // the operation has timed-out and the adapter is toast. + // + UINT ResetTimeoutCounter; + + // + // This timer object will be used to queue the deferred processing routine + // + NDIS_MINIPORT_TIMER DeferredTimer; + + // + // This timer is for handling resets from when the card is dead. + // + NDIS_MINIPORT_TIMER ResetTimer; + + // + // Place for holding command block for pending commands during + // reset processing. + // + PNE3200_SUPER_COMMAND_BLOCK ResetCommandBlock; + + // + // This is a pointer to the Configuration Block for this + // adapter. The Configuration Block will be modified during + // changes to the packet filter. + // + PNE3200_CONFIGURATION_BLOCK ConfigurationBlock; + NDIS_PHYSICAL_ADDRESS ConfigurationBlockPhysical; + + // + // This points to the next adapter registered for the same Mac + // + LIST_ENTRY AdapterList; + +#if DBG + UCHAR Log[256]; + UCHAR LogPlace; +#endif + +} NE3200_ADAPTER,*PNE3200_ADAPTER; + +// +// Given a MiniportContextHandle return the PNE3200_ADAPTER +// it represents. +// +#define PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \ + ((PNE3200_ADAPTER)(Handle)) + +// +// Procedures which do error logging +// + +typedef enum _NE3200_PROC_ID{ + allocateAdapterMemory, + initialInit, + setConfigurationBlockAndInit, + registerAdapter, + openAdapter, + wakeUpDpc, + resetDpc +}NE3200_PROC_ID; + +// +// Error log codes. +// +#define NE3200_ERRMSG_ALLOC_MEM (ULONG)0x01 +#define NE3200_ERRMSG_INIT_INTERRUPT (ULONG)0x02 +#define NE3200_ERRMSG_NO_DELAY (ULONG)0x03 +#define NE3200_ERRMSG_INIT_DB (ULONG)0x04 +#define NE3200_ERRMSG_OPEN_DB (ULONG)0x05 +#define NE3200_ERRMSG_BAD_STATE (ULONG)0x06 +#define NE3200_ERRMSG_ (ULONG)0x06 + + +// +// Define our block of global data. The actual data resides in NE3200.C. +// +extern NE3200_GLOBAL_DATA NE3200Globals; + +#include <ne3200pr.h> + +#endif // _NE3200SOFTWARE_ diff --git a/private/ntos/ndis/ne3200/request.c b/private/ntos/ndis/ne3200/request.c new file mode 100644 index 000000000..5c294ce9d --- /dev/null +++ b/private/ntos/ndis/ne3200/request.c @@ -0,0 +1,954 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + request.c + +Abstract: + + This file contains code to implement request processing. + This driver conforms to the NDIS 3.0 miniport interface. + +Author: + + Johnson R. Apacible (JohnsonA) 10-June-1991 + +Environment: + +Revision History: + +--*/ + +#include <ne3200sw.h> + +extern +NDIS_STATUS +NE3200ChangeClass( + PNE3200_ADAPTER Adapter, + IN UINT NewFilterClasses + ) + +/*++ + +Routine Description: + + Action routine that will get called when a particular filter + class is first used or last cleared. + +Arguments: + + NewFilterClasses - The current value of the class filter + +Return Value: + + None. + + +--*/ + +{ + // + // Holds the change that should be returned to the filtering package. + // + NDIS_STATUS StatusOfChange; + + // + // Holds the list of changes; + // + UINT PacketChanges; + + // + // This points to the public Command Block. + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // This points to the adapter's configuration block. + // + PNE3200_CONFIGURATION_BLOCK ConfigurationBlock = + Adapter->ConfigurationBlock; + + // + // The NE3200 has no method for easily disabling multicast + // packets. Therefore, we'll only reconfigure the 82586 + // when there is a change in either directed, broadcast, or + // promiscuous filtering. + // + PacketChanges = (Adapter->CurrentPacketFilter ^ NewFilterClasses) & + (NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_DIRECTED); + + if (!PacketChanges) { + + return(NDIS_STATUS_SUCCESS); + + } + + // + // Use the generic command block + // + IF_LOG('F'); + + NE3200AcquirePublicCommandBlock( + Adapter, + &CommandBlock + ); + + // + // This from a set. + // + CommandBlock->Set = TRUE; + + // + // Setup the command block. + // + CommandBlock->NextCommand = NULL; + + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = + NE3200_COMMAND_CONFIGURE_82586; + CommandBlock->Hardware.PARAMETERS.CONFIGURE.ConfigurationBlock = + NdisGetPhysicalAddressLow(Adapter->ConfigurationBlockPhysical); + + // + // Update the configuration block to reflect the new + // packet filtering. + // + if (NewFilterClasses == 0) { + + ConfigurationBlock->PromiscuousMode = 0; + ConfigurationBlock->MacBinPromiscuous = 0; + ConfigurationBlock->DisableBroadcast = 1; + + } else { + + ConfigurationBlock->MacBinEnablePacketReception = 1; + + if (PacketChanges & NDIS_PACKET_TYPE_PROMISCUOUS) { + + ConfigurationBlock->PromiscuousMode = 1; + ConfigurationBlock->MacBinPromiscuous = 1; + + } else { + + ConfigurationBlock->PromiscuousMode = 0; + ConfigurationBlock->MacBinPromiscuous = 0; + + } + + if (PacketChanges & NDIS_PACKET_TYPE_BROADCAST) { + + ConfigurationBlock->DisableBroadcast = 0; + + } else { + + ConfigurationBlock->DisableBroadcast = 1; + + } + + } + + // + // Now that we've got the command block built, + // let's do it! + // + NE3200SubmitCommandBlock(Adapter, CommandBlock); + + StatusOfChange = NDIS_STATUS_PENDING; + + return StatusOfChange; +} + + +STATIC +NDIS_STATUS +NE3200UpdateMulticastTable( + IN PNE3200_ADAPTER Adapter, + IN UINT CurrentAddressCount, + IN CHAR CurrentAddresses[][NE3200_LENGTH_OF_ADDRESS] + ) + +/*++ + +Routine Description: + + This routine is called to update the list of multicast addreses + on the adapter. + +Arguments: + + Adapter - The adapter where the multicast is to be changed. + + CurrentAddressCount - The number of addresses in the address array. + + CurrentAddresses - An array of multicast addresses. Note that this + array already contains the new address. + +Return Value: + + None. + + +--*/ + +{ + + // + // This points to the public Command Block. + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // Holds the status that should be returned to the filtering package. + // + NDIS_STATUS StatusOfUpdate; + + // + // Multicast address table + // + PUCHAR MulticastAddressTable; + + IF_LOG('f'); + + // + // See if we can acquire a private command block. + // + NE3200AcquirePublicCommandBlock(Adapter, &CommandBlock); + + // + // Store the request that uses this command block. + // + CommandBlock->Set = TRUE; + + // + // Get the multicast address table. + // + MulticastAddressTable = Adapter->CardMulticastTable; + + // + // Clear out the old address + // + NdisZeroMemory( + MulticastAddressTable, + CurrentAddressCount * NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY + ); + + { + + // + // Simple iteration counter. + // + UINT i; + + // + // Pointer into the multicast address table. + // + PCHAR OriginalAddress; + + // + // Pointer into our temporary buffer. + // + PCHAR MungedAddress; + + // + // Munge the address to 16 bytes per entry. + // + OriginalAddress = &CurrentAddresses[0][0]; + MungedAddress = MulticastAddressTable; + + for ( i = CurrentAddressCount ; i > 0 ; i-- ) { + + NdisMoveMemory( + MungedAddress, + OriginalAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + OriginalAddress += NE3200_LENGTH_OF_ADDRESS; + MungedAddress += NE3200_SIZE_OF_MULTICAST_TABLE_ENTRY; + + } + + + // + // Setup the command block. + // + CommandBlock->NextCommand = NULL; + + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = NE3200_COMMAND_SET_MULTICAST_ADDRESS; + CommandBlock->Hardware.PARAMETERS.MULTICAST.NumberOfMulticastAddresses = + (USHORT)CurrentAddressCount; + + if (CurrentAddressCount == 0) { + + CommandBlock->Hardware.PARAMETERS.MULTICAST.MulticastAddressTable = + (NE3200_PHYSICAL_ADDRESS)NULL; + + } else { + + CommandBlock->Hardware.PARAMETERS.MULTICAST.MulticastAddressTable = + NdisGetPhysicalAddressLow(Adapter->CardMulticastTablePhysical); + + } + + // + // Now that we've got the command block built, + // let's do it! + // + NE3200SubmitCommandBlock(Adapter, CommandBlock); + + StatusOfUpdate = NDIS_STATUS_PENDING; + + } + + return StatusOfUpdate; + +} + +extern +NDIS_STATUS +NE3200SetInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ) + +/*++ + +Routine Description: + + NE3200SetInformation handles a set operation for a + single OID. + +Arguments: + + MiniportAdapterContext - The adapter that the set is for. + + Oid - The OID of the set. + + InformationBuffer - Holds the data to be set. + + InformationBufferLength - The length of InformationBuffer. + + BytesRead - If the call is successful, returns the number + of bytes read from InformationBuffer. + + BytesNeeded - If there is not enough data in OvbBuffer + to satisfy the OID, returns the amount of storage needed. + +Return Value: + + NDIS_STATUS_SUCCESS + NDIS_STATUS_PENDING + NDIS_STATUS_INVALID_LENGTH + NDIS_STATUS_INVALID_OID + +--*/ + +{ + // + // Variable to hold the new packet filter + // + ULONG PacketFilter; + + // + // The adapter to process the request for. + // + PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + // + // Status of NDIS operation + // + NDIS_STATUS Status; + + IF_LOG('w'); + + // + // Now check for the most common OIDs + // + switch (Oid) { + + case OID_802_3_MULTICAST_LIST: + + if (InformationBufferLength % NE3200_LENGTH_OF_ADDRESS != 0) { + + // + // The data must be a multiple of the Ethernet + // address size. + // + return(NDIS_STATUS_INVALID_DATA); + + } + + // + // Now call the routine that does this. + // + Status = NE3200UpdateMulticastTable( + Adapter, + InformationBufferLength / + NE3200_LENGTH_OF_ADDRESS, + InformationBuffer + ); + + *BytesRead = InformationBufferLength; + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + + if (InformationBufferLength != 4) { + + return NDIS_STATUS_INVALID_DATA; + + } + + // + // Now call the filter package to set the packet filter. + // + NdisMoveMemory ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG)); + + // + // Verify bits + // + if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING | + NDIS_PACKET_TYPE_SMT | + NDIS_PACKET_TYPE_MAC_FRAME | + NDIS_PACKET_TYPE_FUNCTIONAL | + NDIS_PACKET_TYPE_ALL_FUNCTIONAL | + NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_GROUP + )) { + + Status = NDIS_STATUS_NOT_SUPPORTED; + + *BytesRead = 4; + *BytesNeeded = 0; + + break; + + } + + // + // Submit the change + // + Status = NE3200ChangeClass( + Adapter, + PacketFilter + ); + + *BytesRead = InformationBufferLength; + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + *BytesRead = 4; + Status = NDIS_STATUS_SUCCESS; + break; + + default: + + Status = NDIS_STATUS_INVALID_OID; + break; + + } + + if (Status == NDIS_STATUS_PENDING) { + + Adapter->RequestInProgress = TRUE; + + } + + IF_LOG('W'); + return Status; +} + +STATIC +NDIS_STATUS +NE3200QueryInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded +) + +/*++ + +Routine Description: + + The NE3200QueryInformation process a Query request for + NDIS_OIDs that are specific about the Driver. + +Arguments: + + MiniportAdapterContext - a pointer to the adapter. + + Oid - the NDIS_OID to process. + + InformationBuffer - a pointer into the + NdisRequest->InformationBuffer into which store the result of the query. + + InformationBufferLength - a pointer to the number of bytes left in the + InformationBuffer. + + BytesWritten - a pointer to the number of bytes written into the + InformationBuffer. + + BytesNeeded - If there is not enough room in the information buffer + then this will contain the number of bytes needed to complete the + request. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + // + // The command block for getting the statistics from the adapter. + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // The adapter to process the request for. + // + PNE3200_ADAPTER Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + // + // Save the information about the request + // + Adapter->BytesWritten = BytesWritten; + Adapter->BytesNeeded = BytesNeeded; + Adapter->Oid = Oid; + Adapter->InformationBuffer = InformationBuffer; + Adapter->InformationBufferLength = InformationBufferLength; + + IF_LOG('?'); + + // + // Get a public command block. This will succeed since + // the wrapper will only give one request at a time, and + // there are more than 1 public command block. + // + NE3200AcquirePublicCommandBlock(Adapter, + &CommandBlock + ); + + // + // Store the request that uses this CB + // + CommandBlock->Set = TRUE; + + // + // Setup the command block. + // + CommandBlock->NextCommand = NULL; + + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = NE3200_COMMAND_READ_ADAPTER_STATISTICS; + + // + // Now that we're set up, let's do it! + // + Adapter->RequestInProgress = TRUE; + NE3200SubmitCommandBlock(Adapter, CommandBlock); + + // + // Catch the ball at the interrupt handler + // + + IF_LOG('/'); + return NDIS_STATUS_PENDING; +} + +STATIC +VOID +NE3200FinishQueryInformation( + IN PNE3200_ADAPTER Adapter +) + +/*++ + +Routine Description: + + The NE3200FinishQueryInformation finish processing a Query request for + NDIS_OIDs that are specific about the Driver. + +Arguments: + + Adapter - a pointer to the adapter. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + +static +NDIS_OID NE3200GlobalSupportedOids[] = { + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_GEN_RCV_CRC_ERROR, + OID_GEN_TRANSMIT_QUEUE_LENGTH, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS, + OID_802_3_XMIT_DEFERRED, + OID_802_3_XMIT_MAX_COLLISIONS, + OID_802_3_RCV_OVERRUN, + OID_802_3_XMIT_UNDERRUN, + OID_802_3_XMIT_HEARTBEAT_FAILURE, + OID_802_3_XMIT_TIMES_CRS_LOST, + OID_802_3_XMIT_LATE_COLLISIONS + }; + + // + // Get the saved information about the request. + // + PUINT BytesWritten = Adapter->BytesWritten; + PUINT BytesNeeded = Adapter->BytesNeeded; + NDIS_OID Oid = Adapter->Oid; + PVOID InformationBuffer = Adapter->InformationBuffer; + UINT InformationBufferLength = Adapter->InformationBufferLength; + + + // + // Variables for holding the data that satisfies the request. + // + NDIS_MEDIUM Medium = NdisMedium802_3; + UINT GenericUlong; + USHORT GenericUShort; + UCHAR GenericArray[6]; + NDIS_HARDWARE_STATUS HardwareStatus; + + // + // Common variables for pointing to result of query + // + PVOID MoveSource = (PVOID)(&GenericUlong); + ULONG MoveBytes = sizeof(ULONG); + + // + // The status of the request. + // + NDIS_STATUS Status = NDIS_STATUS_SUCCESS; + + // + // Initialize the result + // + *BytesWritten = 0; + *BytesNeeded = 0; + + IF_LOG('!'); + + // + // Switch on request type + // + switch(Oid){ + + case OID_GEN_MAC_OPTIONS: + + GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_RECEIVE_SERIALIZED | + NDIS_MAC_OPTION_NO_LOOPBACK + ); + + break; + + case OID_GEN_SUPPORTED_LIST: + + MoveSource = (PVOID)(NE3200GlobalSupportedOids); + MoveBytes = sizeof(NE3200GlobalSupportedOids); + break; + + case OID_GEN_HARDWARE_STATUS: + + if (Adapter->ResetInProgress){ + + HardwareStatus = NdisHardwareStatusReset; + + } else { + + HardwareStatus = NdisHardwareStatusReady; + + } + + + MoveSource = (PVOID)(&HardwareStatus); + MoveBytes = sizeof(NDIS_HARDWARE_STATUS); + + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + + MoveSource = (PVOID) (&Medium); + MoveBytes = sizeof(NDIS_MEDIUM); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + case OID_GEN_CURRENT_LOOKAHEAD: + case OID_GEN_MAXIMUM_FRAME_SIZE: + + GenericUlong = (ULONG) (MAXIMUM_ETHERNET_PACKET_SIZE - NE3200_HEADER_SIZE); + + break; + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + case OID_GEN_TRANSMIT_BLOCK_SIZE: + case OID_GEN_RECEIVE_BLOCK_SIZE: + + GenericUlong = (ULONG) (MAXIMUM_ETHERNET_PACKET_SIZE); + + break; + + + case OID_GEN_LINK_SPEED: + + // + // 10 Mbps + // + GenericUlong = (ULONG)100000; + + break; + + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + + GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE * + NE3200_NUMBER_OF_TRANSMIT_BUFFERS; + + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + + GenericUlong = (ULONG) MAXIMUM_ETHERNET_PACKET_SIZE * + NE3200_NUMBER_OF_RECEIVE_BUFFERS; + + break; + + + case OID_GEN_VENDOR_ID: + + NdisMoveMemory( + (PVOID)&GenericUlong, + Adapter->NetworkAddress, + 3 + ); + GenericUlong &= 0xFFFFFF00; + MoveSource = (PVOID)(&GenericUlong); + MoveBytes = sizeof(GenericUlong); + break; + + case OID_GEN_VENDOR_DESCRIPTION: + + MoveSource = (PVOID)"NE3200 Adapter"; + MoveBytes = 15; + break; + + case OID_GEN_DRIVER_VERSION: + + GenericUShort = (USHORT)0x0300; + + MoveSource = (PVOID)(&GenericUShort); + MoveBytes = sizeof(GenericUShort); + break; + + case OID_802_3_PERMANENT_ADDRESS: + + NdisMoveMemory( + (PCHAR)GenericArray, + Adapter->NetworkAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = NE3200_LENGTH_OF_ADDRESS; + break; + + case OID_802_3_CURRENT_ADDRESS: + NdisMoveMemory( + (PCHAR)GenericArray, + Adapter->CurrentAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = NE3200_LENGTH_OF_ADDRESS; + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + + GenericUlong = (ULONG) NE3200_MAXIMUM_MULTICAST; + + break; + + default: + + switch(Oid){ + + case OID_GEN_XMIT_OK: + GenericUlong = (ULONG) Adapter->GoodTransmits; + break; + + case OID_GEN_RCV_OK: + GenericUlong = (ULONG) Adapter->GoodReceives; + break; + + case OID_GEN_XMIT_ERROR: + GenericUlong = (ULONG) (Adapter->RetryFailure + + Adapter->LostCarrier + + Adapter->UnderFlow + + Adapter->NoClearToSend); + break; + + case OID_GEN_RCV_ERROR: + GenericUlong = (ULONG) (Adapter->CrcErrors + + Adapter->AlignmentErrors + + Adapter->OutOfResources + + Adapter->DmaOverruns); + break; + + case OID_GEN_RCV_NO_BUFFER: + GenericUlong = (ULONG) Adapter->OutOfResources; + break; + + case OID_GEN_RCV_CRC_ERROR: + GenericUlong = (ULONG) Adapter->CrcErrors; + break; + + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + GenericUlong = (ULONG) Adapter->TransmitsQueued; + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + GenericUlong = (ULONG) Adapter->AlignmentErrors; + break; + + case OID_802_3_XMIT_ONE_COLLISION: + GenericUlong = (ULONG) Adapter->OneRetry; + break; + + case OID_802_3_XMIT_MORE_COLLISIONS: + GenericUlong = (ULONG) Adapter->MoreThanOneRetry; + break; + + case OID_802_3_XMIT_DEFERRED: + GenericUlong = (ULONG) Adapter->Deferred; + break; + + case OID_802_3_XMIT_MAX_COLLISIONS: + GenericUlong = (ULONG) Adapter->RetryFailure; + break; + + case OID_802_3_RCV_OVERRUN: + GenericUlong = (ULONG) Adapter->DmaOverruns; + break; + + case OID_802_3_XMIT_UNDERRUN: + GenericUlong = (ULONG) Adapter->UnderFlow; + break; + + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + GenericUlong = (ULONG) Adapter->NoClearToSend; + break; + + case OID_802_3_XMIT_TIMES_CRS_LOST: + GenericUlong = (ULONG) Adapter->LostCarrier; + break; + + default: + Status = NDIS_STATUS_NOT_SUPPORTED; + break; + + } + + } + + if (Status == NDIS_STATUS_SUCCESS) { + + if (MoveBytes > InformationBufferLength) { + + // + // Not enough room in InformationBuffer. Punt + // + *BytesNeeded = MoveBytes; + + Status = NDIS_STATUS_INVALID_LENGTH; + + } else { + + // + // Copy result into InformationBuffer + // + *BytesWritten = MoveBytes; + + if (MoveBytes > 0) { + + NE3200_MOVE_MEMORY( + InformationBuffer, + MoveSource, + MoveBytes + ); + } + } + } + + Adapter->RequestInProgress = FALSE; + + // + // Complete the request + // + NdisMQueryInformationComplete( + Adapter->MiniportAdapterHandle, + Status + ); + + IF_LOG('@'); + + return; +} + diff --git a/private/ntos/ndis/ne3200/reset.c b/private/ntos/ndis/ne3200/reset.c new file mode 100644 index 000000000..1da22a03e --- /dev/null +++ b/private/ntos/ndis/ne3200/reset.c @@ -0,0 +1,1805 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + reset.c + +Abstract: + + This is the file containing the reset code for the Novell NE3200 EISA + Ethernet adapter. This driver conforms to the NDIS 3.0 miniport + interface. + +Author: + + Keith Moore (KeithMo) 08-Jan-1991 + +Environment: + +Revision History: + +--*/ + +#include <ne3200sw.h> + +// +// Global information stored in ne3200.c. This is used for +// getting at the download software +// +extern NE3200_GLOBAL_DATA NE3200Globals; + +// +// Forward declarations of functions in this file +// +extern +VOID +NE3200ProcessRequestQueue( + IN PNE3200_ADAPTER Adapter, + IN BOOLEAN StatisticsUpdated + ); + +STATIC +VOID +NE3200SetConfigurationBlock( + IN PNE3200_ADAPTER Adapter + ); + +STATIC +BOOLEAN +NE3200SetConfigurationBlockAndInit( + IN PNE3200_ADAPTER Adapter + ); + +NDIS_STATUS +NE3200ChangeCurrentAddress( + IN PNE3200_ADAPTER Adapter + ); + +VOID +NE3200ResetCommandBlocks( + IN PNE3200_ADAPTER Adapter + ); + +extern +VOID +NE3200GetStationAddress( + IN PNE3200_ADAPTER Adapter + ); + +extern +VOID +NE3200SetupForReset( + IN PNE3200_ADAPTER Adapter + ); + +STATIC +VOID +NE3200DoResetIndications( + IN PNE3200_ADAPTER Adapter, + IN NDIS_STATUS Status + ); + +VOID +NE3200ResetHandler( + IN PVOID SystemSpecific1, + IN PNE3200_ADAPTER Adapter, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ); + +BOOLEAN +NE3200InitialInit( + IN PNE3200_ADAPTER Adapter, + IN UINT NE3200InterruptVector, + IN NDIS_INTERRUPT_MODE NE3200InterruptMode + ); + + +#pragma NDIS_INIT_FUNCTION(NE3200InitialInit) + +BOOLEAN +NE3200InitialInit( + IN PNE3200_ADAPTER Adapter, + IN UINT NE3200InterruptVector, + IN NDIS_INTERRUPT_MODE NE3200InterruptMode + ) + +/*++ + +Routine Description: + + This routine sets up the initial init of the driver, by + stopping the adapter, connecting the interrupt and initializing + the adapter. + +Arguments: + + Adapter - The adapter for the hardware. + +Return Value: + + TRUE if the initialization succeeds, else FALSE. + +--*/ + +{ + // + // Status of NDIS calls + // + NDIS_STATUS Status; + + // + // First we make sure that the device is stopped. + // + NE3200StopChip(Adapter); + + // + // The ISR will set this to FALSE if we get an interrupt + // + Adapter->InitialInit = TRUE; + + // + // Initialize the interrupt. + // + Status = NdisMRegisterInterrupt( + &Adapter->Interrupt, + Adapter->MiniportAdapterHandle, + NE3200InterruptVector, + NE3200InterruptVector, + FALSE, + FALSE, + NE3200InterruptMode + ); + + // + // So far so good + // + if (Status == NDIS_STATUS_SUCCESS) { + + // + // Now try to initialize the adapter + // + if (!NE3200SetConfigurationBlockAndInit(Adapter)) { + + // + // Failed. Write out an error log entry. + // + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_TIMEOUT, + 2, + initialInit, + NE3200_ERRMSG_NO_DELAY + ); + + // + // Unhook the interrupt + // + NdisMDeregisterInterrupt(&Adapter->Interrupt); + + Adapter->InitialInit = FALSE; + + return FALSE; + + } + + // + // Get hardware assigned network address. + // + NE3200GetStationAddress( + Adapter + ); + + // + // We can start the chip. We may not + // have any bindings to indicate to but this + // is unimportant. + // + Status = NE3200ChangeCurrentAddress(Adapter); + + Adapter->InitialInit = FALSE; + + return(Status == NDIS_STATUS_SUCCESS); + + } else { + + // + // Interrupt line appears to be taken. Notify user. + // + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_INTERRUPT_CONNECT, + 2, + initialInit, + NE3200_ERRMSG_INIT_INTERRUPT + ); + + Adapter->InitialInit = FALSE; + + return(FALSE); + } + +} + +VOID +NE3200StartChipAndDisableInterrupts( + IN PNE3200_ADAPTER Adapter, + IN PNE3200_SUPER_RECEIVE_ENTRY FirstReceiveEntry + ) + +/*++ + +Routine Description: + + This routine is used to start an already initialized NE3200, + but to keep the interrupt line masked. + +Arguments: + + Adapter - The adapter for the NE3200 to start. + + FirstReceiveEntry - Pointer to the first receive entry to be + used by the adapter. + +Return Value: + + None. + +--*/ + +{ + + IF_LOG('%'); + + // + // Write the new receive pointer. + // + NE3200_WRITE_RECEIVE_POINTER( + Adapter, + NdisGetPhysicalAddressLow(FirstReceiveEntry->Self) + ); + + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_RECEIVE + ); + + // + // Initialize the doorbell & system interrupt masks + // + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + NE3200_SYSTEM_INTERRUPT_ENABLE + ); + + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATUS, + 0 + ); + +} + +VOID +NE3200EnableAdapter( + IN NDIS_HANDLE Context + ) + +/*++ + +Routine Description: + + This routine is used to start an already initialized NE3200. + +Arguments: + + Context - The adapter for the NE3200 to start. + +Return Value: + + None. + +--*/ + +{ + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context; + + IF_LOG('#'); + + // + // Initialize the doorbell & system interrupt masks + // + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + NE3200_SYSTEM_INTERRUPT_ENABLE + ); + + if (!Adapter->InterruptsDisabled) { + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + NE3200_SYSTEM_DOORBELL_MASK + ); + } + + NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT( + Adapter, + NE3200_SYSTEM_DOORBELL_MASK + ); + + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATUS, + 0 + ); + +} + +VOID +NE3200EnableInterrupt( + IN NDIS_HANDLE Context + ) + +/*++ + +Routine Description: + + This routine is used to turn on the interrupt mask. + +Arguments: + + Context - The adapter for the NE3200 to start. + +Return Value: + + None. + +--*/ + +{ + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context; + + IF_LOG('E'); + + // + // Enable further interrupts. + // + Adapter->InterruptsDisabled = FALSE; + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + NE3200_SYSTEM_DOORBELL_MASK + ); + +} + +VOID +NE3200DisableInterrupt( + IN NDIS_HANDLE Context + ) + +/*++ + +Routine Description: + + This routine is used to turn off the interrupt mask. + +Arguments: + + Context - The adapter for the NE3200 to start. + +Return Value: + + None. + +--*/ + +{ + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)Context; + + // + // Initialize the doorbell mask + // + Adapter->InterruptsDisabled = TRUE; + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + IF_LOG('D'); +} + +VOID +NE3200StopChip( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to stop the NE3200. + +Arguments: + + Adapter - The NE3200 adapter to stop. + +Return Value: + + None. + +--*/ + +{ + + IF_LOG('h'); + + // + // Packet reception can be stopped by writing a + // (ULONG)-1 to the Receive Packet Mailbox port. + // Also, commands can be stopped by writing a -1 + // to the Command Pointer Mailbox port. + // + NE3200_WRITE_RECEIVE_POINTER( + Adapter, + NE3200_NULL + ); + + NE3200_WRITE_COMMAND_POINTER( + Adapter, + NE3200_NULL + ); + + // + // Ack any outstanding interrupts + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_RECEIVE | NE3200_LOCAL_DOORBELL_NEW_COMMAND + ); + + // + // Disable the doorbell & system interrupt masks. + // + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + 0 + ); + + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + NE3200_WRITE_SYSTEM_DOORBELL_INTERRUPT( + Adapter, + 0 + ); + +} + +STATIC +VOID +NE3200SetConfigurationBlock( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine simply fills the configuration block + with the information necessary for initialization. + +Arguments: + + Adapter - The adapter which holds the initialization block + to initialize. + +Return Value: + + None. + + +--*/ + +{ + + PNE3200_CONFIGURATION_BLOCK Configuration; + + // + // Get the configuration block + // + Configuration = Adapter->ConfigurationBlock; + + // + // Initialize it to zero + // + NdisZeroMemory( + Configuration, + sizeof(NE3200_CONFIGURATION_BLOCK) + ); + + // + // Set up default values + // + Configuration->ByteCount = 12; + Configuration->FifoThreshold = 8; + Configuration->AddressLength = 6; + Configuration->SeparateAddressAndLength = 1; + Configuration->PreambleLength = 2; + Configuration->InterframeSpacing = 96; + Configuration->SlotTime = 512; + Configuration->MaximumRetries = 15; + Configuration->DisableBroadcast = 1; + Configuration->MinimumFrameLength = 64; + +} + +VOID +NE3200DoAdapterReset( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This is the resetting the adapter hardware. + + It makes the following assumptions: + + 1) That the hardware has been stopped. + + 2) That no other adapter activity can occur. + + When this routine is finished all of the adapter information + will be as if the driver was just initialized. + +Arguments: + + Adapter - The adapter whose hardware is to be reset. + +Return Value: + + not. + +--*/ +{ + + // + // Recover all of the adapter transmit merge buffers. + // + { + + UINT i; + + for ( + i = 0; + i < NE3200_NUMBER_OF_TRANSMIT_BUFFERS; + i++ + ) { + + Adapter->NE3200Buffers[i].Next = i+1; + + } + + Adapter->NE3200BufferListHead = 0; + Adapter->NE3200Buffers[NE3200_NUMBER_OF_TRANSMIT_BUFFERS-1].Next = -1; + + } + + // + // Reset all state variables + // + NE3200ResetVariables(Adapter); + + // + // Recover all command blocks + // + NE3200ResetCommandBlocks(Adapter); + + // + // Initialize the adapter + // + NE3200SetConfigurationBlockAndInit(Adapter); + + +} + +STATIC +BOOLEAN +NE3200SetConfigurationBlockAndInit( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + It is this routine's responsibility to make sure that the + Configuration block is filled and the adapter is initialized + *but not* started. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + If ResetAsynchoronous is FALSE, then returns TRUE if reset successful, + FALSE if reset unsuccessful. + + If ResetAsynchoronous is TRUE, then always returns TRUE. + +--*/ +{ + + // + // Fill in the adapter's initialization block. + // + NE3200SetConfigurationBlock(Adapter); + + // + // Set the initial state for the ResetDpc state machine. + // + Adapter->ResetState = NE3200ResetStateStarting; + + // + // Go through the reset + // + NE3200ResetHandler(NULL, Adapter, NULL, NULL); + + // + // Is Synchronous resets, then check the final result + // + if (!Adapter->ResetAsynchronous) { + + return((Adapter->ResetResult == NE3200ResetResultSuccessful)); + + } else { + + return(TRUE); + + } + +} + +VOID +NE3200ResetHandler( + IN PVOID SystemSpecific1, + IN PNE3200_ADAPTER Adapter, + IN PVOID SystemSpecific2, + IN PVOID SystemSpecific3 + ) + +/*++ + +Routine Description: + + This manages the reset/download process. It is + responsible for resetting the adapter, waiting for proper + status, downloading MAC.BIN, waiting for MAC.BIN initialization, + and optionally sending indications to the appropriate protocol. + + Since the NE3200's status registers must be polled during the + reset/download process, this is implemented as a state machine. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + None. + +--*/ +{ + + // + // Physical address of the MAC.BIN buffer. + // + NDIS_PHYSICAL_ADDRESS MacBinPhysicalAddress; + + // + // Status from the adapter. + // + UCHAR Status; + + // + // Simple iteration counter. + // + UINT i; + + // + // Loop until the reset has completed. + // + while (Adapter->ResetState != NE3200ResetStateComplete) { + + switch (Adapter->ResetState) { + + // + // The first stage of resetting an NE3200 + // + case NE3200ResetStateStarting : + + // + // Unfortunately, a hardware reset to the NE3200 does *not* + // reset the BMIC chip. To ensure that we read a proper status, + // we'll clear all of the BMIC's registers. + // + NE3200_WRITE_SYSTEM_INTERRUPT( + Adapter, + 0 + ); + + // + // I changed this to ff since the original 0 didn't work for + // some cases. since we don't have the specs.... + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + 0xff + ); + + NE3200_WRITE_SYSTEM_DOORBELL_MASK( + Adapter, + 0 + ); + + NE3200_SYNC_CLEAR_SYSTEM_DOORBELL_INTERRUPT( + Adapter + ); + + for (i = 0 ; i < 16 ; i += 4 ) { + + NE3200_WRITE_MAILBOX_ULONG( + Adapter, + i, + 0L + ); + + } + + // + // Toggle the NE3200's reset line. + // + NE3200_WRITE_RESET( + Adapter, + NE3200_RESET_BIT_ON + ); + + NE3200_WRITE_RESET( + Adapter, + NE3200_RESET_BIT_OFF + ); + + // + // Switch to the next state. + // + Adapter->ResetState = NE3200ResetStateResetting; + Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_RESET; + + // + // Loop to the next processing + // + break; + + // + // Part Deux. The actual downloading of the software. + // + case NE3200ResetStateResetting : + + // + // Read the status mailbox. + // + NE3200_READ_MAILBOX_UCHAR(Adapter, NE3200_MAILBOX_RESET_STATUS, &Status); + + if (Status == NE3200_RESET_PASSED) { + + // + // We have good reset. Initiate the MAC.BIN download. + // + + // + // The station address for this adapter can be forced to + // a specific value at initialization time. When MAC.BIN + // first gets control, it reads mailbox 10. If this mailbox + // contains a 0xFF, then the burned-in PROM station address + // is used. If this mailbox contains any value other than + // 0xFF, then mailboxes 10-15 are read. The six bytes + // stored in these mailboxes then become the station address. + // + // Since we have no need for this feature, we will always + // initialize mailbox 10 with a 0xFF. + // + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID, + 0xFF + ); + + + // + // Get the MAC.BIN buffer. + // + MacBinPhysicalAddress = NE3200Globals.MacBinPhysicalAddress; + + // + // Download MAC.BIN to the card. + // + NE3200_WRITE_MAILBOX_USHORT( + Adapter, + NE3200_MAILBOX_MACBIN_LENGTH, + NE3200Globals.MacBinLength + ); + + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_MACBIN_DOWNLOAD_MODE, + NE3200_MACBIN_DIRECT + ); + + NE3200_WRITE_MAILBOX_ULONG( + Adapter, + NE3200_MAILBOX_MACBIN_POINTER, + NdisGetPhysicalAddressLow(MacBinPhysicalAddress) + ); + + NE3200_WRITE_MAILBOX_USHORT( + Adapter, + NE3200_MAILBOX_MACBIN_TARGET, + NE3200_MACBIN_TARGET_ADDRESS >> 1 + ); + + // + // This next OUT "kicks" the loader into action. + // + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_RESET_STATUS, + 0 + ); + + // + // Switch to the next state. + // + Adapter->ResetState = NE3200ResetStateDownloading; + Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_DOWNLOAD; + + // + // Loop to the next state. + // + + } else if (Status == NE3200_RESET_FAILED) { + + // + // Reset failure. Notify the authorities and + // next of kin. + // + Adapter->ResetResult = NE3200ResetResultResetFailure; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // Still waiting for results, check if we have + // timed out waiting. + // + Adapter->ResetTimeoutCounter--; + + if (Adapter->ResetTimeoutCounter == 0) { + + // + // We've timed-out. Bad news. Notify the death. + // + Adapter->ResetResult = NE3200ResetResultResetTimeout; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // For Synchronous resets, we stall. For async, + // we set a timer to check later. + // + if (!Adapter->ResetAsynchronous) { + + // + // Otherwise, wait and try again. + // + NdisStallExecution(10000); + + } else{ + + // + // Try again later. + // + NdisMSetTimer(&Adapter->ResetTimer, 100); + + return; + + } + + } + + } + + break; + + // + // Part Three: The download was started. Check for completion, + // and reload the current station address. + // + case NE3200ResetStateDownloading : + + // + // Read the download status. + // + NE3200_READ_MAILBOX_UCHAR(Adapter, NE3200_MAILBOX_STATUS, &Status); + + if (Status == NE3200_INITIALIZATION_PASSED) { + + // + // According to documentation from Compaq, this next port + // write will (in a future MAC.BIN) tell MAC.BIN whether or + // not to handle loopback internally. This value is currently + // not used, but must still be written to the port. + // + NE3200_WRITE_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATUS, + 1 + ); + + // + // Initialization is good, the card is ready. + // + NE3200StartChipAndDisableInterrupts(Adapter, + Adapter->ReceiveQueueHead + ); + + { + + // + // Do the work for updating the current address + // + + // + // This points to the public Command Block. + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // This points to the adapter's configuration block. + // + PNE3200_CONFIGURATION_BLOCK ConfigurationBlock = + Adapter->ConfigurationBlock; + + // + // Get a public command block. + // + NE3200AcquirePublicCommandBlock(Adapter, + &CommandBlock + ); + + Adapter->ResetHandlerCommandBlock = CommandBlock; + + // + // Setup the command block. + // + + CommandBlock->NextCommand = NULL; + + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = + NE3200_COMMAND_CONFIGURE_82586; + CommandBlock->Hardware.PARAMETERS.CONFIGURE.ConfigurationBlock = + NdisGetPhysicalAddressLow(Adapter->ConfigurationBlockPhysical); + + // + // Now that we've got the command block built, + // let's do it! + // + NE3200SubmitCommandBlock(Adapter, CommandBlock); + + Adapter->ResetState = NE3200ResetStateReloadAddress; + Adapter->ResetTimeoutCounter = NE3200_TIMEOUT_DOWNLOAD; + + } + + } else if (Status == NE3200_INITIALIZATION_FAILED) { + + // + // Initialization failed. Notify the wrapper. + // + Adapter->ResetResult = NE3200ResetResultInitializationFailure; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // See if we've timed-out waiting for the download to + // complete. + // + Adapter->ResetTimeoutCounter--; + + if (Adapter->ResetTimeoutCounter == 0) { + + // + // We've timed-out. Bad news. + // + Adapter->ResetResult = NE3200ResetResultInitializationTimeout; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + // + // For Synchronous resets, we stall. For async, + // we set a timer to check later. + // + if (!Adapter->ResetAsynchronous) { + + // + // Otherwise, wait and try again. + // + NdisStallExecution(10000); + + } else{ + + // + // Try again later. + // + NdisMSetTimer(&Adapter->ResetTimer, 100); + return; + + } + + } + + } + + break; + + // + // Part Last: Waiting for the configuring of the adapter + // to complete + // + case NE3200ResetStateReloadAddress : + + // + // Read the command block status. + // + if (Adapter->ResetHandlerCommandBlock->Hardware.State == + NE3200_STATE_EXECUTION_COMPLETE) { + + // + // return this command block + // + NE3200RelinquishCommandBlock(Adapter, + Adapter->ResetHandlerCommandBlock + ); + + // + // Reset is complete. Do those indications. + // + Adapter->ResetResult = NE3200ResetResultSuccessful; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_SUCCESS); + + } else { + + // + // See if we've timed-out. + // + Adapter->ResetTimeoutCounter--; + + if (Adapter->ResetTimeoutCounter == 0) { + + // + // We've timed-out. Bad news. + // + + // + // return this command block + // + NE3200RelinquishCommandBlock(Adapter, + Adapter->ResetHandlerCommandBlock + ); + + Adapter->ResetResult = NE3200ResetResultInitializationTimeout; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + } else { + + if ( Adapter->ResetTimeoutCounter == + (NE3200_TIMEOUT_DOWNLOAD/2) ) { + + // + // The command may have stalled, try again. + // + NE3200_WRITE_LOCAL_DOORBELL_INTERRUPT( + Adapter, + NE3200_LOCAL_DOORBELL_NEW_COMMAND + ); + + } + + // + // For Synchronous resets, we stall. For async, + // we set a timer to check later. + // + if (!Adapter->ResetAsynchronous) { + + // + // Otherwise, wait and try again. + // + NdisStallExecution(10000); + + } else{ + + // + // Check again later + // + NdisMSetTimer(&Adapter->ResetTimer, 100); + return; + + } + + } + + } + + break; + + default : + + // + // Somehow, we reached an invalid state. + // + + // + // We'll try to salvage our way out of this. + // + Adapter->ResetResult = NE3200ResetResultInvalidState; + Adapter->ResetState = NE3200ResetStateComplete; + + NE3200DoResetIndications(Adapter, NDIS_STATUS_HARD_ERRORS); + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 3, + resetDpc, + NE3200_ERRMSG_BAD_STATE, + (ULONG)(Adapter->ResetState) + ); + + break; + } + + } + +} + +STATIC +VOID +NE3200DoResetIndications( + IN PNE3200_ADAPTER Adapter, + IN NDIS_STATUS Status + ) + +/*++ + +Routine Description: + + This routine is called by NE3200ResetHandler to perform any + indications which need to be done after a reset. Note that + this routine will be called after either a successful reset + or a failed reset. + +Arguments: + + Adapter - The adapter whose hardware has been initialized. + + Status - The status of the reset to send to the protocol(s). + +Return Value: + + None. + +--*/ +{ + // + // Re-start the card if the reset was successful, else stop it. + // + if (Status == NDIS_STATUS_SUCCESS) { + + NdisMSynchronizeWithInterrupt( + &(Adapter->Interrupt), + NE3200EnableAdapter, + (PVOID)(Adapter) + ); + + } else { + + // + // Reset has failed. + // + + NE3200StopChip(Adapter); + + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 0 + ); + } + + // + // Setup the network address. + // + NE3200ChangeCurrentAddress(Adapter); + + Adapter->ResetInProgress = FALSE; + + // + // Reset default reset method + // + Adapter->ResetAsynchronous = FALSE; + + if (!Adapter->InitialInit) { + + // + // Signal the end of the reset + // + NdisMResetComplete( + Adapter->MiniportAdapterHandle, + Status, + TRUE + ); + + } + +} + +extern +VOID +NE3200SetupForReset( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to fill in the who and why a reset is + being set up as well as setting the appropriate fields in the + adapter. + + NOTE: This routine must be called with the lock acquired. + +Arguments: + + Adapter - The adapter whose hardware is to be initialized. + +Return Value: + + None. + +--*/ +{ + // + // Ndis buffer mapped + // + PNDIS_BUFFER CurrentBuffer; + + // + // Map register that was used + // + UINT CurMapRegister; + + // + // Packet to abort + // + PNDIS_PACKET Packet; + + // + // Reserved portion of the packet. + // + PNE3200_RESERVED Reserved; + + // + // Pointer to command block being processed. + // + PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock = Adapter->FirstCommandOnCard; + + + + Adapter->ResetInProgress = TRUE; + + // + // Shut down the chip. We won't be doing any more work until + // the reset is complete. + // + NE3200StopChip(Adapter); + + // + // Un-map all outstanding transmits + // + while (CurrentCommandBlock != NULL) { + + if (CurrentCommandBlock->Hardware.CommandCode == NE3200_COMMAND_TRANSMIT) { + + // + // Remove first packet from the queue + // + Packet = CurrentCommandBlock->OwningPacket; + Reserved = PNE3200_RESERVED_FROM_PACKET(Packet); + + if (Reserved->UsedNE3200Buffer) { + goto GetNextCommandBlock; + } + + // + // The transmit is finished, so we can release + // the physical mapping used for it. + // + NdisQueryPacket( + Packet, + NULL, + NULL, + &CurrentBuffer, + NULL + ); + + // + // Get starting map register + // + CurMapRegister = Reserved->CommandBlockIndex * + NE3200_MAXIMUM_BLOCKS_PER_PACKET; + + // + // For each buffer + // + while (CurrentBuffer) { + + // + // Finish the mapping + // + NdisMCompleteBufferPhysicalMapping( + Adapter->MiniportAdapterHandle, + CurrentBuffer, + CurMapRegister + ); + + ++CurMapRegister; + + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + } + + } + +GetNextCommandBlock: + + CurrentCommandBlock = CurrentCommandBlock->NextCommand; + + // + // Now do the pending queue + // + if (CurrentCommandBlock == NULL) { + + if (Adapter->FirstWaitingCommand != NULL) { + + CurrentCommandBlock = Adapter->FirstWaitingCommand; + Adapter->FirstWaitingCommand = NULL; + + } + + } + + } + +} + + +#pragma NDIS_INIT_FUNCTION(NE3200GetStationAddress) + +VOID +NE3200GetStationAddress( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine gets the network address from the hardware. + + NOTE: This routine assumes that it is called *immediately* + after MAC.BIN has been downloaded. It should only be called + immediately after SetConfigurationBlockAndInit() has completed. + +Arguments: + + Adapter - Where to store the network address. + +Return Value: + + None. + +--*/ + +{ + // + // Read the station address from the ports + // + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID, + &Adapter->NetworkAddress[0] + ); + + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 1, + &Adapter->NetworkAddress[1] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 2, + &Adapter->NetworkAddress[2] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 3, + &Adapter->NetworkAddress[3] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID + 4, + &Adapter->NetworkAddress[4] + ); + NE3200_READ_MAILBOX_UCHAR( + Adapter, + NE3200_MAILBOX_STATION_ID +5, + &Adapter->NetworkAddress[5] + ); + + if (!Adapter->AddressChanged) { + + // + // Copy the real address to be used as the current address. + // + NdisMoveMemory( + Adapter->CurrentAddress, + Adapter->NetworkAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + } + +} + + +VOID +NE3200ResetVariables( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets variables to their proper value after a reset. + +Arguments: + + Adapter - Adapter we are resetting. + +Return Value: + + None. + +--*/ + +{ + // + // Clear the command queues + // + Adapter->FirstCommandOnCard = NULL; + Adapter->FirstWaitingCommand = NULL; + + // + // Reset the receive buffer ring + // + Adapter->ReceiveQueueHead = Adapter->ReceiveQueue; + Adapter->ReceiveQueueTail = + Adapter->ReceiveQueue + Adapter->NumberOfReceiveBuffers - 1; + + // + // Reset count of available command blocks + // + Adapter->NumberOfAvailableCommandBlocks = Adapter->NumberOfCommandBlocks; + Adapter->NumberOfPublicCommandBlocks = NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS; + Adapter->NextPublicCommandBlock = 0; + Adapter->NextCommandBlock = Adapter->CommandQueue; + + // + // Reset transmitting and receiving states + // + Adapter->PacketResubmission = FALSE; + Adapter->TransmitsQueued = 0; + Adapter->CurrentReceiveIndex = 0; + +} + +VOID +NE3200ResetCommandBlocks( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine sets command block elementsto their proper value after a reset. + +Arguments: + + Adapter - Adapter we are resetting. + +Return Value: + + None. + +--*/ + +{ + // + // Pointer to a Receive Entry. Used while initializing + // the Receive Queue. + // + PNE3200_SUPER_RECEIVE_ENTRY CurrentReceiveEntry; + + // + // Pointer to a Command Block. Used while initializing + // the Command Queue. + // + PNE3200_SUPER_COMMAND_BLOCK CurrentCommandBlock; + + // + // Simple iteration variable. + // + UINT i; + + // + // Put the Command Blocks into a known state. + // + for( + i = 0, CurrentCommandBlock = Adapter->CommandQueue; + i < Adapter->NumberOfCommandBlocks; + i++, CurrentCommandBlock++ + ) { + + CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE; + CurrentCommandBlock->Hardware.NextPending = NE3200_NULL; + + CurrentCommandBlock->NextCommand = NULL; + CurrentCommandBlock->AvailableCommandBlockCounter = + &Adapter->NumberOfAvailableCommandBlocks; + CurrentCommandBlock->Timeout = FALSE; + } + + // + // Now do the same for the public command queue. + // + for( + i = 0, CurrentCommandBlock = Adapter->PublicCommandQueue; + i < NE3200_NUMBER_OF_PUBLIC_CMD_BLOCKS; + i++, CurrentCommandBlock++ + ) { + + CurrentCommandBlock->Hardware.State = NE3200_STATE_FREE; + CurrentCommandBlock->Hardware.NextPending = NE3200_NULL; + CurrentCommandBlock->NextCommand = NULL; + CurrentCommandBlock->AvailableCommandBlockCounter = + &Adapter->NumberOfPublicCommandBlocks; + CurrentCommandBlock->CommandBlockIndex = (USHORT)i; + CurrentCommandBlock->Timeout = FALSE; + } + + // + // Reset the receive buffers. + // + for( + i = 0, CurrentReceiveEntry = Adapter->ReceiveQueue; + i < Adapter->NumberOfReceiveBuffers; + i++, CurrentReceiveEntry++ + ) { + + + // + // Initialize receive buffers + // + CurrentReceiveEntry->Hardware.State = NE3200_STATE_FREE; + CurrentReceiveEntry->Hardware.NextPending = + NdisGetPhysicalAddressLow(Adapter->ReceiveQueuePhysical) + + (i + 1) * sizeof(NE3200_SUPER_RECEIVE_ENTRY); + CurrentReceiveEntry->NextEntry = CurrentReceiveEntry + 1; + + } + + // + // Make sure the last entry is properly terminated. + // + (CurrentReceiveEntry - 1)->Hardware.NextPending = NE3200_NULL; + (CurrentReceiveEntry - 1)->NextEntry = Adapter->ReceiveQueue; + +} + + +NDIS_STATUS +NE3200ChangeCurrentAddress( + IN PNE3200_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine is used to modify the card address. + +Arguments: + + Adapter - The adapter for the NE3200 to change address. + +Return Value: + + NDIS_STATUS_SUCCESS, if everything went ok + NDIS_STATUS_FAILURE, otherwise + +--*/ +{ + + // + // Modify the card address if needed + // + + if (Adapter->AddressChanged) { + + // + // The command block for submitting the change + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // Temporary looping variable + // + UINT i; + + // + // Get a public command block for the request + // + NE3200AcquirePublicCommandBlock(Adapter, + &CommandBlock + ); + + // + // Setup the command block. + // + CommandBlock->NextCommand = NULL; + + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = NE3200_COMMAND_SET_STATION_ADDRESS; + + // + // Copy in the address + // + NdisMoveMemory( + CommandBlock->Hardware.PARAMETERS.SET_ADDRESS.NewStationAddress, + Adapter->CurrentAddress, + NE3200_LENGTH_OF_ADDRESS + ); + + // + // Now that we've got the command block built, + // let's do it! + // + NE3200SubmitCommandBlock(Adapter, CommandBlock); + + // + // Wait for the command block to finish + // + for (i = 0; i < 100000; i++) { + NdisStallExecution(100); + if (CommandBlock->Hardware.State == NE3200_STATE_EXECUTION_COMPLETE) { + break; + } + } + + // + // Check the status of the command. + // + if (CommandBlock->Hardware.State != NE3200_STATE_EXECUTION_COMPLETE) { + + // + // Failed + // + NdisWriteErrorLogEntry( + Adapter->MiniportAdapterHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 0 + ); + + return NDIS_STATUS_FAILURE; + + } + + // + // return this command block + // + NE3200RelinquishCommandBlock(Adapter, CommandBlock); + + } + return NDIS_STATUS_SUCCESS; +} + +BOOLEAN +SyncNE3200ClearDoorbellInterrupt( + IN PVOID SyncContext + ) +/*++ + +Routine Description: + + Clears the Doorbell Interrupt Port. + +Arguments: + + SyncContext - pointer to the adapter block + +Return Value: + + Always TRUE + +--*/ + +{ + + PNE3200_ADAPTER Adapter = (PNE3200_ADAPTER)SyncContext; + + // + // Clear the value + // + NdisRawWritePortUchar( + (ULONG)(Adapter->SystemDoorbellInterruptPort), + (UCHAR)0 + ); + + return(FALSE); +} + diff --git a/private/ntos/ndis/ne3200/send.c b/private/ntos/ndis/ne3200/send.c new file mode 100644 index 000000000..e2eee44bb --- /dev/null +++ b/private/ntos/ndis/ne3200/send.c @@ -0,0 +1,816 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + send.c + +Abstract: + + This file contains the code for putting a packet through the + staged allocation for transmission. + + This is a process of + + 1) Calculating the what would need to be done to the + packet so that the packet can be transmitted on the hardware. + + 2) Potentially allocating adapter buffers and copying user data + to those buffers so that the packet data is transmitted under + the hardware constraints. + + 3) Allocating enough hardware ring entries so that the packet + can be transmitted. + + 4) Relinquish those ring entries to the hardware. + +Author: + + Anthony V. Ercolano (Tonye) 12-Sept-1990 + Keith Moore (KeithMo) 08-Jan-1991 + +Environment: + + Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. + +Revision History: + + +--*/ + +#include <ne3200sw.h> + +// +// Forward declarations of functions in this file. +// +VOID +NE3200ConstrainPacket( + IN PNE3200_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ); + +NDIS_STATUS +NE3200TransmitPacket( + IN PNE3200_ADAPTER Adapter, + PNDIS_PACKET FirstPacket, + UINT TotalDataLength, + UINT NdisBufferCount, + PNDIS_BUFFER CurrentBuffer + ); + +NDIS_STATUS +NE3200TransmitMergedPacket( + IN PNE3200_ADAPTER Adapter, + PNDIS_PACKET FirstPacket + ); + + +NDIS_STATUS +NE3200Send( + IN NDIS_HANDLE MiniportAdapterContext, + IN PNDIS_PACKET Packet, + IN UINT Flags + ) + +/*++ + +Routine Description: + + The NE3200Send request instructs a Miniport to transmit a packet through + the adapter onto the medium. + +Arguments: + + MiniportAdapterContext - The context value returned by the Miniport when the + adapter was initialized. In reality, it is a pointer to NE3200_ADAPTER. + + Packet - A pointer to a descriptor for the packet that is to be + transmitted. + + Flags - The send options to use. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + // + // Pointer to the adapter. + // + PNE3200_ADAPTER Adapter; + + // + // The number of physical buffers in the entire packet. + // + UINT PhysicalBufferCount; + + // + // The total amount of data in the ndis packet. + // + UINT TotalDataLength; + + // + // The number of ndis buffers in the packet. + // + UINT NdisBufferCount; + + // + // Points to the current ndis buffer being walked. + // + PNDIS_BUFFER CurrentBuffer; + + // + // Points to the miniport reserved portion of this packet. This + // interpretation of the reserved section is only valid during + // the allocation phase of the packet. + // + PNE3200_RESERVED Reserved = PNE3200_RESERVED_FROM_PACKET(Packet); + + // + // Status of the transmit. + // + NDIS_STATUS Status; + + // + // The adapter upon which to transmit the packet. + // + Adapter = PNE3200_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext); + + IF_LOG('s'); + + // + // Check if this is a packet we rejected earlier due to a lack + // of resources. If so, we don't have to recalculate all the + // constraints. + // + if (!Adapter->PacketResubmission) { + + ASSERT(sizeof(NE3200_RESERVED) <= sizeof(Packet->MiniportReserved)); + + // + // Determine if and how much adapter space would need to be allocated + // to meet hardware constraints. + // + NdisQueryPacket( + Packet, + &PhysicalBufferCount, + &NdisBufferCount, + &CurrentBuffer, + &TotalDataLength + ); + + + // + // See if the packet exceeds NE3200_MAXIMUM_BLOCKS_PER_PACKET. + // Keep in mind that if the total virtual packet length is less than + // MINIMUM_ETHERNET_PACKET_SIZE then we'll have to chain on an + // additional buffer to pad the packet out to the minimum size. + // + if ( PhysicalBufferCount < NE3200_MAXIMUM_BLOCKS_PER_PACKET ) { + + // + // This packet will not need a merge buffer + // + Reserved->UsedNE3200Buffer = FALSE; + + // + // See if we can send it now. + // + Status = NE3200TransmitPacket( + Adapter, + Packet, + TotalDataLength, + NdisBufferCount, + CurrentBuffer + ); + + Adapter->PacketResubmission = + (BOOLEAN)(Status == NDIS_STATUS_RESOURCES); + + IF_LOG('S'); + + return(Status); + + } else { + + // + // We will have to use a merge buffer. Let the processing + // below handle this. + // + if ( (PhysicalBufferCount > NE3200_MAXIMUM_BLOCKS_PER_PACKET) || + (TotalDataLength < MINIMUM_ETHERNET_PACKET_SIZE) ) { + + Reserved->UsedNE3200Buffer = TRUE; + + } else { + + Reserved->UsedNE3200Buffer = FALSE; + + } + + } + + } + + // + // Check if we have to merge this packet. + // + if ( Reserved->UsedNE3200Buffer ) { + + // + // Try and send it now. + // + Status = NE3200TransmitMergedPacket(Adapter, Packet); + + } else { + + // + // Determine if and how much adapter space would need to be allocated + // to meet hardware constraints. + // + + NdisQueryPacket( + Packet, + NULL, + &NdisBufferCount, + &CurrentBuffer, + &TotalDataLength + ); + + + Status = NE3200TransmitPacket( + Adapter, + Packet, + TotalDataLength, + NdisBufferCount, + CurrentBuffer); + + } + + // + // Save if this packet was rejected due to lack of resources. + // + Adapter->PacketResubmission = (BOOLEAN)(Status == NDIS_STATUS_RESOURCES); + + IF_LOG('S'); + + return(Status); +} + + +// +// Put this code inline to save the overhead of the function call. +// +#ifdef _X86_ +__inline +#endif + +NDIS_STATUS +NE3200TransmitPacket( + IN PNE3200_ADAPTER Adapter, + PNDIS_PACKET FirstPacket, + UINT TotalDataLength, + UINT NdisBufferCount, + PNDIS_BUFFER CurrentBuffer + ) + +/*++ + +Routine Description: + + This routine attempts to take a packet through a stage of allocation + and transmit it. + +Arguments: + + Adapter - The adapter that the packets are coming through. + +Return Value: + + NDIS_STATUS_RESOURCES - if there are not enough resources + NDIS_STATUS_PENDING - if sending. + +--*/ + +{ + // + // If we successfully acquire a command block, this + // is a pointer to it. + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // Pointer to the NE3200 data block descriptor being filled. + // + PNE3200_DATA_BLOCK DataBlock; + + // + // Array to hold the physical segments + // + NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[NE3200_MAXIMUM_BLOCKS_PER_PACKET]; + + // + // Number of physical segments in the buffer + // + UINT BufferPhysicalSegments; + + // + // map register to use for this buffer + // + UINT CurMapRegister; + + // + // Iteration variable + // + UINT i; + + // + // We look to see if there is an available Command Block. + // If there isn't then stage 3 will close. + // + + NE3200AcquireCommandBlock( + Adapter, + &CommandBlock + ); + + if (CommandBlock != NULL) { + + // + // We have a command block. Assign all packet + // buffers to the command block. + // + + // + // Get a pointer to the the first data block descriptor + // in the Command Block. + // + DataBlock = &CommandBlock->Hardware.TransmitDataBlocks[0]; + + // + // We record the owning packet information in the ring packet packet + // structure. + // + CommandBlock->OwningPacket = FirstPacket; + CommandBlock->UsedNE3200Buffer = FALSE; + CommandBlock->NextCommand = NULL; + + // + // Initialize the various fields of the Command Block. + // + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = NE3200_COMMAND_TRANSMIT; + CommandBlock->Hardware.PARAMETERS.TRANSMIT.ImmediateDataLength = 0; + + CommandBlock->Hardware.NumberOfDataBlocks = 0; + CommandBlock->Hardware.TransmitFrameSize = (USHORT)TotalDataLength; + + // + // Set the map registers to use + // + CurMapRegister = CommandBlock->CommandBlockIndex * + NE3200_MAXIMUM_BLOCKS_PER_PACKET; + + // + // Go through all of the buffers in the packet getting + // the actual physical buffers from each NDIS_BUFFER. + // + do { + + NdisMStartBufferPhysicalMapping( + Adapter->MiniportAdapterHandle, + CurrentBuffer, + CurMapRegister, + TRUE, + PhysicalSegmentArray, + &BufferPhysicalSegments + ); + + // + // Go to the next map register + // + CurMapRegister++; + + // + // Store segments into command block + // + for (i = 0; i < BufferPhysicalSegments ; i++, DataBlock++ ) { + + DataBlock->BlockLength = (USHORT)PhysicalSegmentArray[i].Length; + DataBlock->PhysicalAddress = NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress); + + } + + // + // Update the number of fragments. + // + CommandBlock->Hardware.NumberOfDataBlocks += BufferPhysicalSegments; + + NdisFlushBuffer(CurrentBuffer, TRUE); + + // + // Go to the next buffer. + // + NdisGetNextBuffer( + CurrentBuffer, + &CurrentBuffer + ); + + } while (CurrentBuffer != NULL); + + // + // If the total packet length is less than MINIMUM_ETHERNET_PACKET_SIZE + // then we must chain the Padding buffer onto the end and update + // the transfer size. + // + if (TotalDataLength >= MINIMUM_ETHERNET_PACKET_SIZE) { + + PNE3200_RESERVED_FROM_PACKET(FirstPacket)->CommandBlockIndex = + CommandBlock->CommandBlockIndex; + + IF_LOG('x'); + + NE3200SubmitCommandBlock( + Adapter, + CommandBlock + ); + + return(NDIS_STATUS_PENDING); + } + + // + // Must do padding + // + DataBlock->BlockLength = + (USHORT)(MINIMUM_ETHERNET_PACKET_SIZE - TotalDataLength); + + DataBlock->PhysicalAddress = NdisGetPhysicalAddressLow(Adapter->PaddingPhysicalAddress); + + DataBlock++; + CommandBlock->Hardware.NumberOfDataBlocks++; + + CommandBlock->Hardware.TransmitFrameSize = MINIMUM_ETHERNET_PACKET_SIZE; + + PNE3200_RESERVED_FROM_PACKET(FirstPacket)->CommandBlockIndex = + CommandBlock->CommandBlockIndex; + + IF_LOG('x'); + + NE3200SubmitCommandBlock( + Adapter, + CommandBlock + ); + + return(NDIS_STATUS_PENDING); + + } else { + + // + // Not enough resources + // + return(NDIS_STATUS_RESOURCES); + + } + +} + + +NDIS_STATUS +NE3200TransmitMergedPacket( + IN PNE3200_ADAPTER Adapter, + PNDIS_PACKET FirstPacket + ) + +/*++ + +Routine Description: + + This routine attempts to take a packet through a stage of allocation + and tranmit it. The packet needs to be merged into a single + before transmitting because it contains more fragments than the + adapter can handle. + +Arguments: + + Adapter - The adapter that the packets are coming through. + +Return Value: + + NDIS_STATUS_RESOURCES - if there are not enough resources + NDIS_STATUS_PENDING - if sending. + +--*/ + +{ + // + // If we successfully acquire a command block, this + // is a pointer to it. + // + PNE3200_SUPER_COMMAND_BLOCK CommandBlock; + + // + // Points to the reserved portion of the packet. + // + PNE3200_RESERVED Reserved; + + // + // Pointer to the NE3200 data block descriptor being filled. + // + PNE3200_DATA_BLOCK DataBlock; + + // + // Points to the adapter buffer descriptor allocated + // for this packet. + // + PNE3200_BUFFER_DESCRIPTOR BufferDescriptor; + + // + // Check that we have a merge buffer if one will be necessary. + // + if ( Adapter->NE3200BufferListHead == -1 ) { + + // + // Not enough space for the packet -- save state + // + return NDIS_STATUS_RESOURCES; + + } + + // + // We look to see if there is an available Command Block. + // If there isn't then stage 3 will close. + // + NE3200AcquireCommandBlock( + Adapter, + &CommandBlock + ); + + if (CommandBlock != NULL) { + + // + // We have a command block. Assign all packet + // buffers to the command block. + // + Reserved = PNE3200_RESERVED_FROM_PACKET(FirstPacket); + + // + // Get a pointer to the the first data block descriptor + // in the Command Block. + // + DataBlock = &CommandBlock->Hardware.TransmitDataBlocks[0]; + + // + // Now we merge the packet into a buffer + // + NE3200ConstrainPacket(Adapter, FirstPacket); + + // + // We record the owning packet information in the ring packet packet + // structure. + // + CommandBlock->OwningPacket = FirstPacket; + CommandBlock->UsedNE3200Buffer = TRUE; + CommandBlock->NE3200BuffersIndex = Reserved->NE3200BuffersIndex; + CommandBlock->NextCommand = NULL; + + // + // Initialize the various fields of the Command Block. + // + CommandBlock->Hardware.State = NE3200_STATE_WAIT_FOR_ADAPTER; + CommandBlock->Hardware.Status = 0; + CommandBlock->Hardware.NextPending = NE3200_NULL; + CommandBlock->Hardware.CommandCode = NE3200_COMMAND_TRANSMIT; + CommandBlock->Hardware.PARAMETERS.TRANSMIT.ImmediateDataLength = 0; + + // + // Get the buffer descriptor + // + BufferDescriptor = Adapter->NE3200Buffers + Reserved->NE3200BuffersIndex; + + // + // Since this packet used one of the adapter buffers, the + // following is known: + // + // o There is exactly one physical buffer for this packet. + // o The buffer's length is the transmit frame size. + // + + // + // Set the number of data blocks and the transmit frame size. + // + NdisFlushBuffer(BufferDescriptor->FlushBuffer, TRUE); + CommandBlock->Hardware.NumberOfDataBlocks = 1; + CommandBlock->Hardware.TransmitFrameSize = + (USHORT)BufferDescriptor->DataLength; + + // + // Initialize the (one) data block for this transmit. + // + DataBlock->BlockLength = (USHORT)BufferDescriptor->DataLength; + DataBlock->PhysicalAddress = NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalNE3200Buffer); + + Adapter->TransmitsQueued++; + + Reserved->CommandBlockIndex = CommandBlock->CommandBlockIndex; + + IF_LOG('x'); + + // + // Start the transmit. + // + NE3200SubmitCommandBlock( + Adapter, + CommandBlock + ); + + return(NDIS_STATUS_PENDING); + } + + return(NDIS_STATUS_RESOURCES); + +} + +STATIC +VOID +NE3200ConstrainPacket( + IN PNE3200_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + Given a packet and if necessary attempt to acquire adapter + buffer resources so that the packet meets NE3200 hardware/MAC.BIN + contraints. + + NOTE : MUST BE CALLED WITH NE3200BufferListHead != -1!! + +Arguments: + + Adapter - The adapter the packet is coming through. + + Packet - The packet whose buffers are to be constrained. + The packet reserved section is filled with information + detailing how the packet needs to be adjusted. + +Return Value: + + None. + +--*/ + +{ + + // + // Holds the adapter buffer index available for allocation. + // + INT NE3200BuffersIndex; + + // + // Points to a successfully allocated adapter buffer descriptor. + // + PNE3200_BUFFER_DESCRIPTOR BufferDescriptor; + + // + // Will point into the virtual address space addressed + // by the adapter buffer if one was successfully allocated. + // + PCHAR CurrentDestination; + + // + // Will hold the total amount of data copied to the + // adapter buffer. + // + UINT TotalDataMoved = 0; + + // + // Will point to the current source buffer. + // + PNDIS_BUFFER SourceBuffer; + + // + // Points to the virtual address of the source buffers data. + // + PVOID SourceData; + + // + // The number of ndis buffers in the packet. + // + UINT NdisBufferCount; + + // + // Will point to the number of bytes of data in the source + // buffer. + // + UINT SourceLength; + + // + // The total amount of data contained within the ndis packet. + // + UINT TotalVirtualLength; + + // + // Simple iteration variable. + // + INT i; + + NE3200BuffersIndex = Adapter->NE3200BufferListHead; + + BufferDescriptor = Adapter->NE3200Buffers + NE3200BuffersIndex; + Adapter->NE3200BufferListHead = BufferDescriptor->Next; + + // + // Fill in the adapter buffer with the data from the users + // buffers. + // + CurrentDestination = BufferDescriptor->VirtualNE3200Buffer; + + NdisQueryPacket( + Packet, + NULL, + &NdisBufferCount, + &SourceBuffer, + &TotalVirtualLength + ); + + NdisQueryBuffer( + SourceBuffer, + &SourceData, + &SourceLength + ); + + BufferDescriptor->DataLength = TotalVirtualLength; + + for ( + i = NdisBufferCount; + i; + i-- + ) { + + // + // Copy this buffer + // + NE3200_MOVE_MEMORY( + CurrentDestination, + SourceData, + SourceLength + ); + + // + // Update destination address + // + CurrentDestination = (PCHAR)CurrentDestination + SourceLength; + + // + // Update count of packet length. + // + TotalDataMoved += SourceLength; + + if (i > 1) { + + // + // Get the next buffers information + // + NdisGetNextBuffer( + SourceBuffer, + &SourceBuffer + ); + + NdisQueryBuffer( + SourceBuffer, + &SourceData, + &SourceLength + ); + + } + + } + + // + // If the packet is less than the minimum Ethernet + // packet size, then clear the remaining part of + // the buffer up to the minimum packet size. + // + if (TotalVirtualLength < MINIMUM_ETHERNET_PACKET_SIZE) { + + NdisZeroMemory( + CurrentDestination, + MINIMUM_ETHERNET_PACKET_SIZE - TotalVirtualLength + ); + + } + + // + // We need to save in the packet which adapter buffer descriptor + // it is using so that we can deallocate it later. + // + PNE3200_RESERVED_FROM_PACKET(Packet)->NE3200BuffersIndex = NE3200BuffersIndex; +} + diff --git a/private/ntos/ndis/ne3200/sources b/private/ntos/ndis/ne3200/sources new file mode 100644 index 000000000..a10b25497 --- /dev/null +++ b/private/ntos/ndis/ne3200/sources @@ -0,0 +1,51 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=ndis + +TARGETNAME=ne3200 +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER + +NTPROFILEINPUT=yes + +INCLUDES=..\..\inc;..\..\..\inc + +SOURCES=command.c \ + interrup.c \ + ne3200.c \ + request.c \ + reset.c \ + send.c \ + ne3200.rc + +RELATIVE_DEPTH=..\.. + +MSC_WARNING_LEVEL=/W3 /WX + +NTTARGETFILES=ne3200.bin |