You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1982 lines
45 KiB
1982 lines
45 KiB
/*++
|
|
|
|
Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved.
|
|
|
|
Module Name:
|
|
|
|
ne2000.c
|
|
|
|
Abstract:
|
|
|
|
This is the main file for the Novel 2000 Ethernet controller.
|
|
This driver conforms to the NDIS 3.0 miniport interface.
|
|
|
|
Author:
|
|
|
|
Sean Selitrennikoff (Dec 1993)
|
|
|
|
Environment:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
//
|
|
// On debug builds tell the compiler to keep the symbols for
|
|
// internal functions, otw throw them out.
|
|
//
|
|
#if DBG
|
|
#define STATIC
|
|
#else
|
|
#define STATIC static
|
|
#endif
|
|
|
|
//
|
|
// Debugging definitions
|
|
//
|
|
#if DBG
|
|
|
|
//
|
|
// Default debug mode
|
|
//
|
|
ULONG Ne2000DebugFlag = NE2000_DEBUG_LOG;
|
|
|
|
//
|
|
// Debug tracing defintions
|
|
//
|
|
#define NE2000_LOG_SIZE 256
|
|
UCHAR Ne2000LogBuffer[NE2000_LOG_SIZE]={0};
|
|
UINT Ne2000LogLoc = 0;
|
|
|
|
extern
|
|
VOID
|
|
Ne2000Log(UCHAR c) {
|
|
|
|
Ne2000LogBuffer[Ne2000LogLoc++] = c;
|
|
|
|
Ne2000LogBuffer[(Ne2000LogLoc + 4) % NE2000_LOG_SIZE] = '\0';
|
|
|
|
if (Ne2000LogLoc >= NE2000_LOG_SIZE)
|
|
Ne2000LogLoc = 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// The global Miniport driver block.
|
|
//
|
|
|
|
DRIVER_BLOCK Ne2000MiniportBlock={0};
|
|
|
|
//
|
|
// List of supported OID for this driver.
|
|
//
|
|
STATIC UINT Ne2000SupportedOids[] = {
|
|
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_DESCRIPTION,
|
|
OID_GEN_VENDOR_ID,
|
|
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_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
|
|
};
|
|
|
|
//
|
|
// Determines whether failing the initial card test will prevent
|
|
// the adapter from being registered.
|
|
//
|
|
#ifdef CARD_TEST
|
|
|
|
BOOLEAN InitialCardTest = TRUE;
|
|
|
|
#else // CARD_TEST
|
|
|
|
BOOLEAN InitialCardTest = FALSE;
|
|
|
|
#endif // CARD_TEST
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
#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 NE2000 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.
|
|
|
|
RegistryPath - Path to the parameters for this driver in the registry.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
//
|
|
// Receives the status of the NdisMRegisterMiniport operation.
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
//
|
|
// Characteristics table for this driver.
|
|
//
|
|
NDIS_MINIPORT_CHARACTERISTICS NE2000Char;
|
|
|
|
//
|
|
// Pointer to the global information for this driver
|
|
//
|
|
PDRIVER_BLOCK NewDriver = &Ne2000MiniportBlock;
|
|
|
|
//
|
|
// Handle for referring to the wrapper about this driver.
|
|
//
|
|
NDIS_HANDLE NdisWrapperHandle;
|
|
|
|
//
|
|
// Initialize the wrapper.
|
|
//
|
|
NdisMInitializeWrapper(
|
|
&NdisWrapperHandle,
|
|
DriverObject,
|
|
RegistryPath,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Save the global information about this driver.
|
|
//
|
|
NewDriver->NdisWrapperHandle = NdisWrapperHandle;
|
|
NewDriver->AdapterQueue = (PNE2000_ADAPTER)NULL;
|
|
|
|
//
|
|
// Initialize the Miniport characteristics for the call to
|
|
// NdisMRegisterMiniport.
|
|
//
|
|
NE2000Char.MajorNdisVersion = NE2000_NDIS_MAJOR_VERSION;
|
|
NE2000Char.MinorNdisVersion = NE2000_NDIS_MINOR_VERSION;
|
|
NE2000Char.CheckForHangHandler = NULL;
|
|
NE2000Char.DisableInterruptHandler = Ne2000DisableInterrupt;
|
|
NE2000Char.EnableInterruptHandler = Ne2000EnableInterrupt;
|
|
NE2000Char.HaltHandler = Ne2000Halt;
|
|
NE2000Char.HandleInterruptHandler = Ne2000HandleInterrupt;
|
|
NE2000Char.InitializeHandler = Ne2000Initialize;
|
|
NE2000Char.ISRHandler = Ne2000Isr;
|
|
NE2000Char.QueryInformationHandler = Ne2000QueryInformation;
|
|
NE2000Char.ReconfigureHandler = NULL;
|
|
NE2000Char.ResetHandler = Ne2000Reset;
|
|
NE2000Char.SendHandler = Ne2000Send;
|
|
NE2000Char.SetInformationHandler = Ne2000SetInformation;
|
|
NE2000Char.TransferDataHandler = Ne2000TransferData;
|
|
|
|
Status = NdisMRegisterMiniport(
|
|
NdisWrapperHandle,
|
|
&NE2000Char,
|
|
sizeof(NE2000Char)
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
#pragma NDIS_PAGEABLE_FUNCTION(Ne2000Initialize)
|
|
extern
|
|
NDIS_STATUS
|
|
Ne2000Initialize(
|
|
OUT PNDIS_STATUS OpenErrorStatus,
|
|
OUT PUINT SelectedMediumIndex,
|
|
IN PNDIS_MEDIUM MediumArray,
|
|
IN UINT MediumArraySize,
|
|
IN NDIS_HANDLE MiniportAdapterHandle,
|
|
IN NDIS_HANDLE ConfigurationHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ne2000Initialize starts an adapter and registers resources with the
|
|
wrapper.
|
|
|
|
Arguments:
|
|
|
|
OpenErrorStatus - Extra status bytes for opening token ring adapters.
|
|
|
|
SelectedMediumIndex - Index of the media type chosen by the driver.
|
|
|
|
MediumArray - Array of media types for the driver to chose from.
|
|
|
|
MediumArraySize - Number of entries in the array.
|
|
|
|
MiniportAdapterHandle - Handle for passing to the wrapper when
|
|
referring to this adapter.
|
|
|
|
ConfigurationHandle - A handle to pass to NdisOpenConfiguration.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS
|
|
NDIS_STATUS_PENDING
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Pointer to our newly allocated adapter.
|
|
//
|
|
PNE2000_ADAPTER Adapter;
|
|
|
|
//
|
|
// The handle for reading from the registry.
|
|
//
|
|
NDIS_HANDLE ConfigHandle;
|
|
|
|
//
|
|
// The value read from the registry.
|
|
//
|
|
PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
|
|
|
|
//
|
|
// String names of all the parameters that will be read.
|
|
//
|
|
NDIS_STRING IOAddressStr = NDIS_STRING_CONST("IoBaseAddress");
|
|
NDIS_STRING InterruptStr = NDIS_STRING_CONST("InterruptNumber");
|
|
NDIS_STRING MaxMulticastListStr = NDIS_STRING_CONST("MaximumMulticastList");
|
|
NDIS_STRING NetworkAddressStr = NDIS_STRING_CONST("NetworkAddress");
|
|
NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
|
|
NDIS_STRING CardTypeStr = NDIS_STRING_CONST("CardType");
|
|
|
|
//
|
|
// TRUE if there is a configuration error.
|
|
//
|
|
BOOLEAN ConfigError = FALSE;
|
|
|
|
//
|
|
// A special value to log concerning the error.
|
|
//
|
|
ULONG ConfigErrorValue = 0;
|
|
|
|
//
|
|
// The slot number the adapter is located in, used for
|
|
// Microchannel adapters.
|
|
//
|
|
UINT SlotNumber = 0;
|
|
|
|
//
|
|
// TRUE if it is unnecessary to read the Io Base Address
|
|
// and Interrupt from the registry. Used for Microchannel
|
|
// adapters, which get this information from the slot
|
|
// information.
|
|
//
|
|
BOOLEAN SkipIobaseAndInterrupt = FALSE;
|
|
|
|
//
|
|
// The network address the adapter should use instead of the
|
|
// the default burned in address.
|
|
//
|
|
PVOID NetAddress;
|
|
|
|
//
|
|
// The number of bytes in the address. It should be
|
|
// NE2000_LENGTH_OF_ADDRESS
|
|
//
|
|
ULONG Length;
|
|
|
|
//
|
|
// These are used when calling Ne2000RegisterAdapter.
|
|
//
|
|
|
|
//
|
|
// The physical address of the base I/O port.
|
|
//
|
|
PVOID IoBaseAddr;
|
|
|
|
//
|
|
// The interrupt number to use.
|
|
//
|
|
CCHAR InterruptNumber;
|
|
|
|
//
|
|
// The number of multicast address to be supported.
|
|
//
|
|
UINT MaxMulticastList;
|
|
|
|
//
|
|
// Temporary looping variable.
|
|
//
|
|
ULONG i;
|
|
|
|
//
|
|
// Status of Ndis calls.
|
|
//
|
|
NDIS_STATUS Status;
|
|
|
|
NDIS_MCA_POS_DATA McaData;
|
|
|
|
//
|
|
// Search for the medium type (802.3) in the given array.
|
|
//
|
|
for (i = 0; i < MediumArraySize; i++){
|
|
|
|
if (MediumArray[i] == NdisMedium802_3){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i == MediumArraySize){
|
|
|
|
return( NDIS_STATUS_UNSUPPORTED_MEDIA );
|
|
|
|
}
|
|
|
|
*SelectedMediumIndex = i;
|
|
|
|
|
|
//
|
|
// Set default values.
|
|
//
|
|
IoBaseAddr = DEFAULT_IOBASEADDR;
|
|
InterruptNumber = DEFAULT_INTERRUPTNUMBER;
|
|
MaxMulticastList = DEFAULT_MULTICASTLISTMAX;
|
|
|
|
//
|
|
// Allocate memory for the adapter block now.
|
|
//
|
|
Status = NdisAllocateMemoryWithTag( (PVOID *)&Adapter,
|
|
sizeof(NE2000_ADAPTER),
|
|
'k2EN'
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
//
|
|
// Clear out the adapter block, which sets all default values to FALSE,
|
|
// or NULL.
|
|
//
|
|
NdisZeroMemory (Adapter, sizeof(NE2000_ADAPTER));
|
|
|
|
//
|
|
// Open the configuration space.
|
|
//
|
|
NdisOpenConfiguration(
|
|
&Status,
|
|
&ConfigHandle,
|
|
ConfigurationHandle
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS) {
|
|
|
|
NdisFreeMemory(Adapter, sizeof(NE2000_ADAPTER), 0);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
//
|
|
// Read in the card type.
|
|
//
|
|
Adapter->CardType = NE2000_ISA;
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&CardTypeStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
Adapter->CardType = (UINT)ReturnedValue->ParameterData.IntegerData;
|
|
|
|
//
|
|
// Read net address
|
|
//
|
|
NdisReadNetworkAddress(
|
|
&Status,
|
|
&NetAddress,
|
|
&Length,
|
|
ConfigHandle
|
|
);
|
|
|
|
if ((Length == NE2000_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {
|
|
|
|
//
|
|
// Save the address that should be used.
|
|
//
|
|
NdisMoveMemory(
|
|
Adapter->StationAddress,
|
|
NetAddress,
|
|
NE2000_LENGTH_OF_ADDRESS
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Disallow multiple adapters in the same MP machine because of hardware
|
|
// problems this results in random packet corruption.
|
|
//
|
|
if ((NdisSystemProcessorCount() > 1) && (Ne2000MiniportBlock.AdapterQueue != NULL)) {
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorValue = (ULONG)NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION;
|
|
goto RegisterAdapter;
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Read Bus Type (for NE2/AE2 support)
|
|
//
|
|
Adapter->BusType = NdisInterfaceIsa;
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&BusTypeStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
Adapter->BusType = (UCHAR)ReturnedValue->ParameterData.IntegerData;
|
|
|
|
}
|
|
|
|
if (!SkipIobaseAndInterrupt) {
|
|
//
|
|
// Read I/O Address
|
|
//
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&IOAddressStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
IoBaseAddr = UlongToPtr(ReturnedValue->ParameterData.IntegerData);
|
|
|
|
}
|
|
|
|
if (Adapter->BusType != NdisInterfacePcMcia)
|
|
{
|
|
//
|
|
// Check that the value is valid.
|
|
//
|
|
if ((IoBaseAddr < (PVOID)MIN_IOBASEADDR) ||
|
|
(IoBaseAddr > (PVOID)MAX_IOBASEADDR)) {
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorValue = PtrToUlong(IoBaseAddr);
|
|
goto RegisterAdapter;
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read interrupt number
|
|
//
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&InterruptStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData);
|
|
|
|
}
|
|
|
|
//
|
|
// Verify that the value is valid.
|
|
//
|
|
if ((InterruptNumber < MIN_IRQ) ||
|
|
(InterruptNumber > MAX_IRQ)) {
|
|
|
|
ConfigError = TRUE;
|
|
ConfigErrorValue = (ULONG)InterruptNumber;
|
|
goto RegisterAdapter;
|
|
|
|
}
|
|
|
|
//
|
|
// If the adapter is a pcmcia card then get the memory window
|
|
// address for later use.
|
|
//
|
|
if (NE2000_PCMCIA == Adapter->CardType)
|
|
{
|
|
#if 0
|
|
NDIS_STRING AttributeMemoryAddrStr =
|
|
NDIS_STRING_CONST("MemoryMappedBaseAddress");
|
|
NDIS_STRING AttributeMemorySizeStr =
|
|
NDIS_STRING_CONST("PCCARDAttributeMemorySize");
|
|
|
|
//
|
|
// Read the attribute memory address.
|
|
//
|
|
Adapter->AttributeMemoryAddress = 0xd4000;
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&AttributeMemoryAddrStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
if (NDIS_STATUS_SUCCESS == Status)
|
|
{
|
|
Adapter->AttributeMemoryAddress =
|
|
(ULONG)ReturnedValue->ParameterData.IntegerData;
|
|
}
|
|
|
|
//
|
|
// Read the size of the attribute memory range.
|
|
//
|
|
Adapter->AttributeMemorySize = 0x1000;
|
|
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&AttributeMemorySizeStr,
|
|
NdisParameterHexInteger
|
|
);
|
|
if (NDIS_STATUS_SUCCESS == Status)
|
|
{
|
|
Adapter->AttributeMemorySize =
|
|
(ULONG)ReturnedValue->ParameterData.IntegerData;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read MaxMulticastList
|
|
//
|
|
NdisReadConfiguration(
|
|
&Status,
|
|
&ReturnedValue,
|
|
ConfigHandle,
|
|
&MaxMulticastListStr,
|
|
NdisParameterInteger
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS) {
|
|
|
|
MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
|
|
if (ReturnedValue->ParameterData.IntegerData <= DEFAULT_MULTICASTLISTMAX)
|
|
MaxMulticastList = ReturnedValue->ParameterData.IntegerData;
|
|
}
|
|
|
|
|
|
RegisterAdapter:
|
|
|
|
//
|
|
// Now to use this information and register with the wrapper
|
|
// and initialize the adapter.
|
|
//
|
|
|
|
//
|
|
// First close the configuration space.
|
|
//
|
|
NdisCloseConfiguration(ConfigHandle);
|
|
|
|
IF_LOUD( DbgPrint(
|
|
"Registering adapter # buffers %ld\n"
|
|
"Card type: 0x%x\n"
|
|
"I/O base addr 0x%lx\n"
|
|
"interrupt number %ld\n"
|
|
"max multicast %ld\nattribute memory address 0x%X\n"
|
|
"attribute memory size 0x%X\n"
|
|
"CardType: %d\n",
|
|
DEFAULT_NUMBUFFERS,
|
|
Adapter->CardType,
|
|
IoBaseAddr,
|
|
InterruptNumber,
|
|
DEFAULT_MULTICASTLISTMAX,
|
|
Adapter->AttributeMemoryAddress,
|
|
Adapter->AttributeMemorySize,
|
|
Adapter->CardType );)
|
|
|
|
|
|
|
|
//
|
|
// Set up the parameters.
|
|
//
|
|
Adapter->NumBuffers = DEFAULT_NUMBUFFERS;
|
|
Adapter->IoBaseAddr = IoBaseAddr;
|
|
|
|
Adapter->InterruptNumber = InterruptNumber;
|
|
|
|
Adapter->MulticastListMax = MaxMulticastList;
|
|
Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
|
|
|
|
Adapter->MaxLookAhead = NE2000_MAX_LOOKAHEAD;
|
|
|
|
//
|
|
// Now do the work.
|
|
//
|
|
if (Ne2000RegisterAdapter(Adapter,
|
|
ConfigurationHandle,
|
|
ConfigError,
|
|
ConfigErrorValue
|
|
) != NDIS_STATUS_SUCCESS) {
|
|
|
|
//
|
|
// Ne2000RegisterAdapter failed.
|
|
//
|
|
NdisFreeMemory(Adapter, sizeof(NE2000_ADAPTER), 0);
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
IF_LOUD( DbgPrint( "Ne2000RegisterAdapter succeeded\n" );)
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
#pragma NDIS_PAGEABLE_FUNCTION(Ne2000RegisterAdapter)
|
|
NDIS_STATUS
|
|
Ne2000RegisterAdapter(
|
|
IN PNE2000_ADAPTER Adapter,
|
|
IN NDIS_HANDLE ConfigurationHandle,
|
|
IN BOOLEAN ConfigError,
|
|
IN ULONG ConfigErrorValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called when a new adapter should be registered. It allocates space for
|
|
the adapter, initializes the adapter's block, registers resources
|
|
with the wrapper and initializes the physical adapter.
|
|
|
|
Arguments:
|
|
|
|
Adapter - The adapter structure.
|
|
|
|
ConfigurationHandle - Handle passed to Ne2000Initialize.
|
|
|
|
ConfigError - Was there an error during configuration reading.
|
|
|
|
ConfigErrorValue - Value to log if there is an error.
|
|
|
|
Return Value:
|
|
|
|
Indicates the success or failure of the registration.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Temporary looping variable.
|
|
//
|
|
UINT i;
|
|
|
|
//
|
|
// General purpose return from NDIS calls
|
|
//
|
|
NDIS_STATUS status;
|
|
|
|
//
|
|
// check that NumBuffers <= MAX_XMIT_BUFS
|
|
//
|
|
|
|
if (Adapter->NumBuffers > MAX_XMIT_BUFS)
|
|
return(NDIS_STATUS_RESOURCES);
|
|
|
|
//
|
|
// Check for a configuration error
|
|
//
|
|
if (ConfigError)
|
|
{
|
|
//
|
|
// Log Error and exit.
|
|
//
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
|
|
1,
|
|
ConfigErrorValue
|
|
);
|
|
|
|
return(NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
//
|
|
// Inform the wrapper of the physical attributes of this adapter.
|
|
//
|
|
NdisMSetAttributes(
|
|
Adapter->MiniportAdapterHandle,
|
|
(NDIS_HANDLE)Adapter,
|
|
FALSE,
|
|
Adapter->BusType
|
|
);
|
|
|
|
//
|
|
// Register the port addresses.
|
|
//
|
|
status = NdisMRegisterIoPortRange(
|
|
(PVOID *)(&(Adapter->IoPAddr)),
|
|
Adapter->MiniportAdapterHandle,
|
|
PtrToUint(Adapter->IoBaseAddr),
|
|
0x20
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
return(status);
|
|
|
|
if (NE2000_ISA == Adapter->CardType)
|
|
{
|
|
//
|
|
// Check that the IoBaseAddress seems to be correct.
|
|
//
|
|
IF_VERY_LOUD( DbgPrint("Checking Parameters\n"); )
|
|
|
|
if (!CardCheckParameters(Adapter))
|
|
{
|
|
//
|
|
// The card does not seem to be there, fail silently.
|
|
//
|
|
IF_VERY_LOUD( DbgPrint(" -- Failed\n"); )
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
|
|
goto fail2;
|
|
}
|
|
|
|
IF_VERY_LOUD( DbgPrint(" -- Success\n"); )
|
|
}
|
|
|
|
//
|
|
// Initialize the card.
|
|
//
|
|
IF_VERY_LOUD( DbgPrint("CardInitialize\n"); )
|
|
|
|
if (!CardInitialize(Adapter))
|
|
{
|
|
//
|
|
// Card seems to have failed.
|
|
//
|
|
|
|
IF_VERY_LOUD( DbgPrint(" -- Failed\n"); )
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
|
|
goto fail2;
|
|
}
|
|
|
|
IF_VERY_LOUD( DbgPrint(" -- Success\n"); )
|
|
|
|
//
|
|
//
|
|
// For programmed I/O, we will refer to transmit/receive memory in
|
|
// terms of offsets in the card's 64K address space.
|
|
//
|
|
Adapter->XmitStart = Adapter->RamBase;
|
|
|
|
//
|
|
// For the NicXXX fields, always use the addressing system
|
|
// containing the MSB only).
|
|
//
|
|
Adapter->NicXmitStart = (UCHAR)((PtrToUlong(Adapter->XmitStart)) >> 8);
|
|
|
|
//
|
|
// The start of the receive space.
|
|
//
|
|
Adapter->PageStart = Adapter->XmitStart +
|
|
(Adapter->NumBuffers * TX_BUF_SIZE);
|
|
|
|
Adapter->NicPageStart = Adapter->NicXmitStart +
|
|
(UCHAR)(Adapter->NumBuffers * BUFS_PER_TX);
|
|
|
|
ASSERT(Adapter->PageStart < (Adapter->RamBase + Adapter->RamSize));
|
|
|
|
//
|
|
// The end of the receive space.
|
|
//
|
|
Adapter->PageStop = Adapter->XmitStart + Adapter->RamSize;
|
|
Adapter->NicPageStop = Adapter->NicXmitStart + (UCHAR)(Adapter->RamSize >> 8);
|
|
|
|
ASSERT(Adapter->PageStop <= (Adapter->RamBase + Adapter->RamSize));
|
|
|
|
IF_LOUD( DbgPrint("Xmit Start (0x%x, 0x%x) : Rcv Start (0x%x, 0x%x) : Rcv End (0x%x, 0x%x)\n",
|
|
Adapter->XmitStart,
|
|
Adapter->NicXmitStart,
|
|
Adapter->PageStart,
|
|
Adapter->NicPageStart,
|
|
(ULONG_PTR)Adapter->PageStop,
|
|
Adapter->NicPageStop
|
|
);
|
|
)
|
|
|
|
|
|
//
|
|
// Initialize the receive variables.
|
|
//
|
|
Adapter->NicReceiveConfig = RCR_REJECT_ERR;
|
|
|
|
//
|
|
// Initialize the transmit buffer control.
|
|
//
|
|
Adapter->CurBufXmitting = (XMIT_BUF)-1;
|
|
|
|
//
|
|
// Initialize the transmit buffer states.
|
|
//
|
|
for (i = 0; i < Adapter->NumBuffers; i++)
|
|
Adapter->BufferStatus[i] = EMPTY;
|
|
|
|
//
|
|
// Read the Ethernet address off of the PROM.
|
|
//
|
|
if (!CardReadEthernetAddress(Adapter))
|
|
{
|
|
IF_LOUD(DbgPrint("Could not read the ethernet address\n");)
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
0
|
|
);
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
|
|
goto fail2;
|
|
}
|
|
|
|
//
|
|
// Now initialize the NIC and Gate Array registers.
|
|
//
|
|
Adapter->NicInterruptMask = IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
|
|
|
|
//
|
|
// Link us on to the chain of adapters for this driver.
|
|
//
|
|
Adapter->NextAdapter = Ne2000MiniportBlock.AdapterQueue;
|
|
Ne2000MiniportBlock.AdapterQueue = Adapter;
|
|
|
|
|
|
//
|
|
// Setup the card based on the initialization information
|
|
//
|
|
|
|
IF_VERY_LOUD( DbgPrint("Setup\n"); )
|
|
|
|
if (!CardSetup(Adapter))
|
|
{
|
|
//
|
|
// The NIC could not be written to.
|
|
//
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
|
|
0
|
|
);
|
|
|
|
IF_VERY_LOUD( DbgPrint(" -- Failed\n"); )
|
|
|
|
status = NDIS_STATUS_ADAPTER_NOT_FOUND;
|
|
|
|
goto fail3;
|
|
}
|
|
|
|
IF_VERY_LOUD( DbgPrint(" -- Success\n"); )
|
|
|
|
//
|
|
// Initialize the interrupt.
|
|
//
|
|
|
|
Adapter->InterruptMode = NdisInterruptLatched;
|
|
|
|
status = NdisMRegisterInterrupt(
|
|
&Adapter->Interrupt,
|
|
Adapter->MiniportAdapterHandle,
|
|
Adapter->InterruptNumber,
|
|
Adapter->InterruptNumber,
|
|
FALSE,
|
|
FALSE,
|
|
Adapter->InterruptMode
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Maybe it is a level interrupt
|
|
//
|
|
|
|
Adapter->InterruptMode = NdisInterruptLevelSensitive;
|
|
Adapter->InterruptsEnabled = TRUE;
|
|
|
|
status = NdisMRegisterInterrupt(
|
|
&Adapter->Interrupt,
|
|
Adapter->MiniportAdapterHandle,
|
|
Adapter->InterruptNumber,
|
|
Adapter->InterruptNumber,
|
|
TRUE,
|
|
TRUE,
|
|
Adapter->InterruptMode
|
|
);
|
|
|
|
if (status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
|
|
NdisWriteErrorLogEntry(
|
|
Adapter->MiniportAdapterHandle,
|
|
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
|
|
0
|
|
);
|
|
|
|
goto fail3;
|
|
}
|
|
}
|
|
|
|
IF_LOUD( DbgPrint("Interrupt Connected\n");)
|
|
|
|
//
|
|
// Start up the adapter.
|
|
//
|
|
CardStart(Adapter);
|
|
|
|
//
|
|
// Initialization completed successfully. Register a shutdown handler.
|
|
//
|
|
|
|
NdisMRegisterAdapterShutdownHandler(
|
|
Adapter->MiniportAdapterHandle,
|
|
(PVOID)Adapter,
|
|
Ne2000Shutdown
|
|
);
|
|
|
|
IF_LOUD( DbgPrint(" [ Ne2000 ] : OK\n");)
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
|
|
//
|
|
// Code to unwind what has already been set up when a part of
|
|
// initialization fails, which is jumped into at various
|
|
// points based on where the failure occured. Jumping to
|
|
// a higher-numbered failure point will execute the code
|
|
// for that block and all lower-numbered ones.
|
|
//
|
|
|
|
fail3:
|
|
|
|
//
|
|
// Take us out of the AdapterQueue.
|
|
//
|
|
|
|
if (Ne2000MiniportBlock.AdapterQueue == Adapter)
|
|
{
|
|
Ne2000MiniportBlock.AdapterQueue = Adapter->NextAdapter;
|
|
}
|
|
else
|
|
{
|
|
PNE2000_ADAPTER TmpAdapter = Ne2000MiniportBlock.AdapterQueue;
|
|
|
|
while (TmpAdapter->NextAdapter != Adapter)
|
|
{
|
|
TmpAdapter = TmpAdapter->NextAdapter;
|
|
}
|
|
|
|
TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
|
|
}
|
|
|
|
//
|
|
// We already enabled the interrupt on the card, so
|
|
// turn it off.
|
|
//
|
|
NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_STOP);
|
|
|
|
fail2:
|
|
|
|
NdisMDeregisterIoPortRange(
|
|
Adapter->MiniportAdapterHandle,
|
|
PtrToUint(Adapter->IoBaseAddr),
|
|
0x20,
|
|
(PVOID)Adapter->IoPAddr
|
|
);
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
extern
|
|
VOID
|
|
Ne2000Halt(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NE2000Halt removes an adapter that was previously initialized.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - The context value that the Miniport returned
|
|
from Ne2000Initialize; actually as pointer to an NE2000_ADAPTER.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNE2000_ADAPTER Adapter;
|
|
|
|
Adapter = PNE2000_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
|
|
|
|
//
|
|
// Shut down the chip.
|
|
//
|
|
CardStop(Adapter);
|
|
|
|
//
|
|
// Deregister the adapter shutdown handler.
|
|
//
|
|
NdisMDeregisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle);
|
|
|
|
//
|
|
// Disconnect the interrupt line.
|
|
//
|
|
NdisMDeregisterInterrupt(&Adapter->Interrupt);
|
|
|
|
//
|
|
// Pause, waiting for any DPC stuff to clear.
|
|
//
|
|
NdisStallExecution(250000);
|
|
|
|
NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle,
|
|
PtrToUint(Adapter->IoBaseAddr),
|
|
0x20,
|
|
(PVOID)Adapter->IoPAddr
|
|
);
|
|
|
|
//
|
|
// Remove the adapter from the global queue of adapters.
|
|
//
|
|
if (Ne2000MiniportBlock.AdapterQueue == Adapter) {
|
|
|
|
Ne2000MiniportBlock.AdapterQueue = Adapter->NextAdapter;
|
|
|
|
} else {
|
|
|
|
PNE2000_ADAPTER TmpAdapter = Ne2000MiniportBlock.AdapterQueue;
|
|
|
|
while (TmpAdapter->NextAdapter != Adapter) {
|
|
|
|
TmpAdapter = TmpAdapter->NextAdapter;
|
|
|
|
}
|
|
|
|
TmpAdapter->NextAdapter = TmpAdapter->NextAdapter->NextAdapter;
|
|
}
|
|
|
|
//
|
|
// Free up the memory
|
|
//
|
|
NdisFreeMemory(Adapter, sizeof(NE2000_ADAPTER), 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
Ne2000Shutdown(
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called by NDIS when the system is shutting down or restarting
|
|
on an unrecoverable error. Do the minimum set of operations to make the
|
|
card silent.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - pointer to our adapter structure
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Pointer to the adapter structure.
|
|
//
|
|
PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)MiniportAdapterContext;
|
|
|
|
(VOID)SyncCardStop(Adapter);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
Ne2000Reset(
|
|
OUT PBOOLEAN AddressingReset,
|
|
IN NDIS_HANDLE MiniportAdapterContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The NE2000Reset 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:
|
|
|
|
AddressingReset - Does the adapter need the addressing information reloaded.
|
|
|
|
MiniportAdapterContext - Pointer to the adapter structure.
|
|
|
|
Return Value:
|
|
|
|
The function value is the status of the operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Pointer to the adapter structure.
|
|
//
|
|
PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)MiniportAdapterContext;
|
|
|
|
//
|
|
// Temporary looping variable
|
|
//
|
|
UINT i;
|
|
|
|
//
|
|
// Clear the values for transmits, they will be reset these for after
|
|
// the reset is completed.
|
|
//
|
|
Adapter->NextBufToFill = 0;
|
|
Adapter->NextBufToXmit = 0;
|
|
Adapter->CurBufXmitting = (XMIT_BUF)-1;
|
|
|
|
Adapter->FirstPacket = NULL;
|
|
Adapter->LastPacket = NULL;
|
|
|
|
for (i=0; i<Adapter->NumBuffers; i++) {
|
|
Adapter->BufferStatus[i] = EMPTY;
|
|
}
|
|
|
|
//
|
|
// Physically reset the card.
|
|
//
|
|
Adapter->NicInterruptMask = IMR_RCV | IMR_XMIT | IMR_XMIT_ERR | IMR_OVERFLOW;
|
|
|
|
return (CardReset(Adapter) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
Ne2000QueryInformation(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength,
|
|
OUT PULONG BytesWritten,
|
|
OUT PULONG BytesNeeded
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The NE2000QueryInformation 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.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Pointer to the adapter structure.
|
|
//
|
|
PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)MiniportAdapterContext;
|
|
|
|
//
|
|
// General Algorithm:
|
|
//
|
|
// Switch(Request)
|
|
// Get requested information
|
|
// Store results in a common variable.
|
|
// default:
|
|
// Try protocol query information
|
|
// If that fails, fail query.
|
|
//
|
|
// Copy result in common variable to result buffer.
|
|
// Finish processing
|
|
|
|
UINT BytesLeft = InformationBufferLength;
|
|
PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;
|
|
NDIS_MEDIUM Medium = NdisMedium802_3;
|
|
|
|
//
|
|
// This variable holds result of query
|
|
//
|
|
ULONG GenericULong;
|
|
USHORT GenericUShort;
|
|
UCHAR GenericArray[6];
|
|
UINT MoveBytes = sizeof(ULONG);
|
|
PVOID MoveSource = (PVOID)(&GenericULong);
|
|
|
|
//
|
|
// Make sure that int is 4 bytes. Else GenericULong must change
|
|
// to something of size 4.
|
|
//
|
|
ASSERT(sizeof(ULONG) == 4);
|
|
|
|
//
|
|
// Switch on request type
|
|
//
|
|
|
|
switch (Oid) {
|
|
|
|
case OID_GEN_MAC_OPTIONS:
|
|
|
|
GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
|
|
NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
|
|
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
|
|
NDIS_MAC_OPTION_NO_LOOPBACK
|
|
);
|
|
|
|
break;
|
|
|
|
case OID_GEN_SUPPORTED_LIST:
|
|
|
|
MoveSource = (PVOID)(Ne2000SupportedOids);
|
|
MoveBytes = sizeof(Ne2000SupportedOids);
|
|
break;
|
|
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
|
|
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:
|
|
|
|
GenericULong = NE2000_MAX_LOOKAHEAD;
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
|
|
GenericULong = (ULONG)(1514 - NE2000_HEADER_SIZE);
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
|
|
GenericULong = (ULONG)(1514);
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_LINK_SPEED:
|
|
|
|
GenericULong = (ULONG)(100000);
|
|
|
|
break;
|
|
|
|
|
|
case OID_GEN_TRANSMIT_BUFFER_SPACE:
|
|
|
|
GenericULong = (ULONG)(Adapter->NumBuffers * TX_BUF_SIZE);
|
|
|
|
break;
|
|
|
|
case OID_GEN_RECEIVE_BUFFER_SPACE:
|
|
|
|
GenericULong = (ULONG)(0x2000 - (Adapter->NumBuffers * TX_BUF_SIZE));
|
|
|
|
break;
|
|
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
|
|
GenericULong = (ULONG)(TX_BUF_SIZE);
|
|
|
|
break;
|
|
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
|
|
GenericULong = (ULONG)(256);
|
|
|
|
break;
|
|
|
|
#ifdef NE2000
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
|
|
NdisMoveMemory(
|
|
(PVOID)&GenericULong,
|
|
Adapter->PermanentAddress,
|
|
3
|
|
);
|
|
GenericULong &= 0xFFFFFF00;
|
|
MoveSource = (PVOID)(&GenericULong);
|
|
MoveBytes = sizeof(GenericULong);
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
|
|
MoveSource = (PVOID)"Novell 2000 Adapter.";
|
|
MoveBytes = 21;
|
|
|
|
break;
|
|
|
|
#else
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
|
|
NdisMoveMemory(
|
|
(PVOID)&GenericULong,
|
|
Adapter->PermanentAddress,
|
|
3
|
|
);
|
|
GenericULong &= 0xFFFFFF00;
|
|
GenericULong |= 0x01;
|
|
MoveSource = (PVOID)(&GenericULong);
|
|
MoveBytes = sizeof(GenericULong);
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
|
|
MoveSource = (PVOID)"Novell 1000 Adapter.";
|
|
MoveBytes = 21;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case OID_GEN_DRIVER_VERSION:
|
|
|
|
GenericUShort = ((USHORT)NE2000_NDIS_MAJOR_VERSION << 8) |
|
|
NE2000_NDIS_MINOR_VERSION;
|
|
|
|
MoveSource = (PVOID)(&GenericUShort);
|
|
MoveBytes = sizeof(GenericUShort);
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
GenericULong = (ULONG)(Adapter->MaxLookAhead);
|
|
break;
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
|
|
NE2000_MOVE_MEM((PCHAR)GenericArray,
|
|
Adapter->PermanentAddress,
|
|
NE2000_LENGTH_OF_ADDRESS);
|
|
|
|
MoveSource = (PVOID)(GenericArray);
|
|
MoveBytes = sizeof(Adapter->PermanentAddress);
|
|
|
|
break;
|
|
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
|
|
NE2000_MOVE_MEM((PCHAR)GenericArray,
|
|
Adapter->StationAddress,
|
|
NE2000_LENGTH_OF_ADDRESS);
|
|
|
|
MoveSource = (PVOID)(GenericArray);
|
|
MoveBytes = sizeof(Adapter->StationAddress);
|
|
|
|
break;
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
|
|
GenericULong = (ULONG) (Adapter->MulticastListMax);
|
|
break;
|
|
|
|
case OID_GEN_XMIT_OK:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitGood);
|
|
break;
|
|
|
|
case OID_GEN_RCV_OK:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesRcvGood);
|
|
break;
|
|
|
|
case OID_GEN_XMIT_ERROR:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitBad);
|
|
break;
|
|
|
|
case OID_GEN_RCV_ERROR:
|
|
|
|
GenericULong = (UINT)(Adapter->CrcErrors);
|
|
break;
|
|
|
|
case OID_GEN_RCV_NO_BUFFER:
|
|
|
|
GenericULong = (UINT)(Adapter->MissedPackets);
|
|
break;
|
|
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
|
|
GenericULong = (UINT)(Adapter->FrameAlignmentErrors);
|
|
break;
|
|
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitOneCollision);
|
|
break;
|
|
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
|
|
GenericULong = (UINT)(Adapter->FramesXmitManyCollisions);
|
|
break;
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_OID;
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
|
|
|
|
if (MoveBytes > BytesLeft) {
|
|
|
|
//
|
|
// Not enough room in InformationBuffer. Punt
|
|
//
|
|
|
|
*BytesNeeded = MoveBytes;
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Store result.
|
|
//
|
|
|
|
NE2000_MOVE_MEM(InfoBuffer, MoveSource, MoveBytes);
|
|
|
|
(*BytesWritten) = MoveBytes;
|
|
|
|
}
|
|
}
|
|
|
|
return StatusToReturn;
|
|
}
|
|
|
|
|
|
extern
|
|
NDIS_STATUS
|
|
Ne2000SetInformation(
|
|
IN NDIS_HANDLE MiniportAdapterContext,
|
|
IN NDIS_OID Oid,
|
|
IN PVOID InformationBuffer,
|
|
IN ULONG InformationBufferLength,
|
|
OUT PULONG BytesRead,
|
|
OUT PULONG BytesNeeded
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
NE2000SetInformation handles a set operation for a
|
|
single OID.
|
|
|
|
Arguments:
|
|
|
|
MiniportAdapterContext - Context registered with the wrapper, really
|
|
a pointer to the adapter.
|
|
|
|
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 InformationBuffer
|
|
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
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Pointer to the adapter structure.
|
|
//
|
|
PNE2000_ADAPTER Adapter = (PNE2000_ADAPTER)MiniportAdapterContext;
|
|
|
|
//
|
|
// General Algorithm:
|
|
//
|
|
// Verify length
|
|
// Switch(Request)
|
|
// Process Request
|
|
//
|
|
|
|
UINT BytesLeft = InformationBufferLength;
|
|
PUCHAR InfoBuffer = (PUCHAR)(InformationBuffer);
|
|
|
|
//
|
|
// Variables for a particular request
|
|
//
|
|
UINT OidLength;
|
|
|
|
//
|
|
// Variables for holding the new values to be used.
|
|
//
|
|
ULONG LookAhead;
|
|
ULONG Filter;
|
|
|
|
//
|
|
// Status of the operation.
|
|
//
|
|
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
|
|
|
|
IF_LOUD( DbgPrint("In SetInfo\n");)
|
|
|
|
//
|
|
// Get Oid and Length of request
|
|
//
|
|
OidLength = BytesLeft;
|
|
|
|
switch (Oid) {
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
|
|
//
|
|
// Verify length
|
|
//
|
|
if ((OidLength % NE2000_LENGTH_OF_ADDRESS) != 0){
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the new list on the adapter.
|
|
//
|
|
NdisMoveMemory(Adapter->Addresses, InfoBuffer, OidLength);
|
|
|
|
//
|
|
// If we are currently receiving all multicast or
|
|
// we are promsicuous then we DO NOT call this, or
|
|
// it will reset thoes settings.
|
|
//
|
|
if
|
|
(
|
|
!(Adapter->PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
|
|
NDIS_PACKET_TYPE_PROMISCUOUS))
|
|
)
|
|
{
|
|
StatusToReturn = DispatchSetMulticastAddressList(Adapter);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Our list of multicast addresses is kept by the
|
|
// wrapper.
|
|
//
|
|
StatusToReturn = NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
|
|
//
|
|
// Verify length
|
|
//
|
|
|
|
if (OidLength != 4 ) {
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
NE2000_MOVE_MEM(&Filter, InfoBuffer, 4);
|
|
|
|
//
|
|
// Verify bits
|
|
//
|
|
if (!(Filter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
|
|
NDIS_PACKET_TYPE_PROMISCUOUS |
|
|
NDIS_PACKET_TYPE_MULTICAST |
|
|
NDIS_PACKET_TYPE_BROADCAST |
|
|
NDIS_PACKET_TYPE_DIRECTED)) &&
|
|
(Filter != 0))
|
|
{
|
|
StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
|
|
|
|
*BytesRead = 4;
|
|
*BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the new value on the adapter.
|
|
//
|
|
Adapter->PacketFilter = Filter;
|
|
StatusToReturn = DispatchSetPacketFilter(Adapter);
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_LOOKAHEAD:
|
|
|
|
//
|
|
// Verify length
|
|
//
|
|
|
|
if (OidLength != 4) {
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 4;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
//
|
|
// Store the new value.
|
|
//
|
|
|
|
NE2000_MOVE_MEM(&LookAhead, InfoBuffer, 4);
|
|
|
|
if (LookAhead <= NE2000_MAX_LOOKAHEAD) {
|
|
Adapter->MaxLookAhead = LookAhead;
|
|
} else {
|
|
StatusToReturn = NDIS_STATUS_INVALID_LENGTH;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
StatusToReturn = NDIS_STATUS_INVALID_OID;
|
|
|
|
*BytesRead = 0;
|
|
*BytesNeeded = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
|
|
|
|
*BytesRead = BytesLeft;
|
|
*BytesNeeded = 0;
|
|
|
|
}
|
|
|
|
return(StatusToReturn);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
DispatchSetPacketFilter(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the appropriate bits in the adapter filters
|
|
and modifies the card Receive Configuration Register if needed.
|
|
|
|
Arguments:
|
|
|
|
Adapter - Pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
The final status (always NDIS_STATUS_SUCCESS).
|
|
|
|
Notes:
|
|
|
|
- Note that to receive all multicast packets the multicast
|
|
registers on the card must be filled with 1's. To be
|
|
promiscuous that must be done as well as setting the
|
|
promiscuous physical flag in the RCR. This must be done
|
|
as long as ANY protocol bound to this adapter has their
|
|
filter set accordingly.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
//
|
|
// See what has to be put on the card.
|
|
//
|
|
|
|
if
|
|
(
|
|
Adapter->PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
|
|
NDIS_PACKET_TYPE_PROMISCUOUS)
|
|
)
|
|
{
|
|
//
|
|
// need "all multicast" now.
|
|
//
|
|
CardSetAllMulticast(Adapter); // fills it with 1's
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No longer need "all multicast".
|
|
//
|
|
DispatchSetMulticastAddressList(Adapter);
|
|
}
|
|
|
|
//
|
|
// The multicast bit in the RCR should be on if ANY protocol wants
|
|
// multicast/all multicast packets (or is promiscuous).
|
|
//
|
|
if
|
|
(
|
|
Adapter->PacketFilter & (NDIS_PACKET_TYPE_ALL_MULTICAST |
|
|
NDIS_PACKET_TYPE_MULTICAST |
|
|
NDIS_PACKET_TYPE_PROMISCUOUS)
|
|
)
|
|
{
|
|
Adapter->NicReceiveConfig |= RCR_MULTICAST;
|
|
}
|
|
else
|
|
{
|
|
Adapter->NicReceiveConfig &= ~RCR_MULTICAST;
|
|
}
|
|
|
|
//
|
|
// The promiscuous physical bit in the RCR should be on if ANY
|
|
// protocol wants to be promiscuous.
|
|
//
|
|
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
|
|
{
|
|
Adapter->NicReceiveConfig |= RCR_ALL_PHYS;
|
|
}
|
|
else
|
|
{
|
|
Adapter->NicReceiveConfig &= ~RCR_ALL_PHYS;
|
|
}
|
|
|
|
//
|
|
// The broadcast bit in the RCR should be on if ANY protocol wants
|
|
// broadcast packets (or is promiscuous).
|
|
//
|
|
if
|
|
(
|
|
Adapter->PacketFilter & (NDIS_PACKET_TYPE_BROADCAST |
|
|
NDIS_PACKET_TYPE_PROMISCUOUS)
|
|
)
|
|
{
|
|
Adapter->NicReceiveConfig |= RCR_BROADCAST;
|
|
}
|
|
else
|
|
{
|
|
Adapter->NicReceiveConfig &= ~RCR_BROADCAST;
|
|
}
|
|
|
|
CardSetReceiveConfig(Adapter);
|
|
|
|
return(NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
DispatchSetMulticastAddressList(
|
|
IN PNE2000_ADAPTER Adapter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the multicast list for this open
|
|
|
|
Arguments:
|
|
|
|
Adapter - Pointer to the adapter block
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCESS
|
|
|
|
Implementation Note:
|
|
|
|
When invoked, we are to make it so that the multicast list in the filter
|
|
package becomes the multicast list for the adapter. To do this, we
|
|
determine the required contents of the NIC multicast registers and
|
|
update them.
|
|
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Update the local copy of the NIC multicast regs and copy them to the NIC
|
|
//
|
|
CardFillMulticastRegs(Adapter);
|
|
CardCopyMulticastRegs(Adapter);
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|