2020-09-30 17:12:29 +02:00

898 lines
18 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
init.c
Abstract:
Ndis 3.0 MAC driver for the 3Com Etherlink III
Author:
Brian Lieuallen (BrianLie) 12/14/92
Environment:
Kernel Mode Operating Systems : NT
Revision History:
Portions borrowed from ELNK3 driver by
Earle R. Horton (EarleH)
--*/
#include <ndis.h>
//#include <efilter.h>
#include "debug.h"
#include "elnk3hrd.h"
#include "elnk3sft.h"
#include "elnk3.h"
#if defined(ALLOC_PRAGMA)
#pragma NDIS_INIT_FUNCTION(DriverEntry)
#pragma NDIS_INIT_FUNCTION(Elnk3Initialize)
#pragma NDIS_INIT_FUNCTION(Elnk3InitializeAdapter)
#pragma NDIS_INIT_FUNCTION(Elnk3Init3C589)
#endif
#if DBG
ULONG Elnk3DebugFlag;
ULONG Elnk3LogArray[ELNK3_MAX_LOG_SIZE+16];
ULONG ElnkLogPointer;
#endif
MAC_BLOCK MacBlock = {0};
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the transfer address of the driver. It initializes all the
appropriate variables used and calls NdisInitializeWrapper() and
NdisRegisterMac().
Arguments:
Return Value:
Indicates the success or failure of the initialization.
--*/
{
NDIS_STATUS InitStatus;
NDIS_MINIPORT_CHARACTERISTICS Characteristics;
NDIS_HANDLE WrapperHandle;
#if DBG
Elnk3DebugFlag = 0;
Elnk3DebugFlag|= ELNK3_DEBUG_LOG;
// Elnk3DebugFlag|= ELNK3_DEBUG_LOUD;
// Elnk3DebugFlag|= ELNK3_DEBUG_VERY_LOUD;
// Elnk3DebugFlag|= ELNK3_DEBUG_INIT;
// Elnk3DebugFlag|= ELNK3_DEBUG_IO;
// Elnk3DebugFlag|= ELNK3_DEBUG_REQ;
// Elnk3DebugFlag|= ELNK3_DEBUG_RCV;
// Elnk3DebugFlag|= ELNK3_DEBUG_SEND;
// Elnk3DebugFlag|= ELNK3_DEBUG_INIT_BREAK;
#endif
IF_INIT_LOUD(DbgPrint("Elnk3: DriverEntry\n");)
#if DBG
if (Elnk3DebugFlag & ELNK3_DEBUG_INIT_BREAK) DbgBreakPoint();
if (Elnk3DebugFlag & ELNK3_DEBUG_INIT_FAIL) return STATUS_UNSUCCESSFUL;
#endif
NdisMInitializeWrapper(
&WrapperHandle,
DriverObject,
RegistryPath,
NULL
);
//
// Prepare to call NdisRegisterMac.
//
Characteristics.MajorNdisVersion = ELNK3_NDIS_MAJOR_VERSION;
Characteristics.MinorNdisVersion = ELNK3_NDIS_MINOR_VERSION;
Characteristics.Reserved = 0;
Characteristics.CheckForHangHandler = Elnk3CheckForHang;
// Characteristics.DisableInterruptHandler = Elnk3DisableInterrupts;
// Characteristics.EnableInterruptHandler = Elnk3EnableInterrupts;
Characteristics.DisableInterruptHandler = NULL;
Characteristics.EnableInterruptHandler = NULL;
Characteristics.SendHandler = Elnk3MacSend;
Characteristics.TransferDataHandler = Elnk3TransferData;
Characteristics.ResetHandler = Elnk3Reset;
Characteristics.SetInformationHandler = Elnk3SetInformation;
Characteristics.QueryInformationHandler = Elnk3QueryInformation;
Characteristics.InitializeHandler = Elnk3Initialize;
Characteristics.HaltHandler = Elnk3Halt;
Characteristics.ISRHandler = Elnk3Isr;
Characteristics.HandleInterruptHandler = Elnk3IsrDpc;
Characteristics.ReconfigureHandler = Elnk3Reconfigure;
InitStatus=NdisMRegisterMiniport(
WrapperHandle,
&Characteristics,
sizeof(Characteristics)
);
#if DBG
if (InitStatus != NDIS_STATUS_SUCCESS) {
IF_LOUD(DbgPrint("Elnk3: NdisMRegisterMiniport failed with code 0x%x\n", InitStatus );)
} else {
IF_INIT_LOUD (DbgPrint("Elnk3: NdisMRegisterMiniport succeeded\n" );)
}
#endif
return InitStatus;
}
NDIS_STATUS
Elnk3Initialize(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE AdapterHandle,
IN NDIS_HANDLE ConfigurationHandle
)
/*++
Routine Description:
This is the Elnk3 MacAddAdapter routine. The system calls this routine
to add support for particular UB adapter. This routine extracts
configuration information from the configuration data base and registers
the adapter with NDIS.
Arguments:
Return Value:
NDIS_STATUS_SUCCESS - Adapter was successfully added.
NDIS_STATUS_FAILURE - Adapter was not added
--*/
{
PELNK3_ADAPTER pAdapter;
NDIS_STATUS status;
*OpenErrorStatus=NDIS_STATUS_SUCCESS;
IF_LOUD (DbgPrint("ELNK3: Initialize\n");)
//
// Scan the media list for our media type (802.3)
//
*SelectedMediumIndex =(UINT) -1;
while (MediumArraySize > 0) {
if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) {
*SelectedMediumIndex = MediumArraySize;
break;
}
}
if (*SelectedMediumIndex == -1) {
return NDIS_STATUS_UNSUPPORTED_MEDIA;
}
status = NdisAllocateMemory(
(PVOID *)&pAdapter,
sizeof(ELNK3_ADAPTER),
0,
HighestAcceptableMax
);
if (status != NDIS_STATUS_SUCCESS) {
IF_LOUD (DbgPrint("Elnk3AddAdapter():NdisAllocateMemory() failed\n");)
return NDIS_STATUS_RESOURCES;
}
NdisZeroMemory(pAdapter,sizeof(ELNK3_ADAPTER));
pAdapter->NdisAdapterHandle=AdapterHandle;
//
// Read Registery information into Adapter structure
//
if (Elnk3ReadRegistry(pAdapter,ConfigurationHandle)==NDIS_STATUS_SUCCESS) {
//
// We got the registry info try to register the adpater
//
if (Elnk3InitializeAdapter(
&MacBlock,
pAdapter,
ConfigurationHandle)== NDIS_STATUS_SUCCESS) {
return NDIS_STATUS_SUCCESS;
}
} else {
IF_LOUD(DbgPrint("Failed to get config info, probably bad Slot number\n");)
}
//
// We failed to register the adapter for some reason, so free the
// memory for the adapter block and return failure
NdisFreeMemory(pAdapter,
sizeof(ELNK3_ADAPTER),
0);
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
Elnk3InitializeAdapter(
IN PMAC_BLOCK pMac,
IN PELNK3_ADAPTER pAdapter,
IN NDIS_HANDLE ConfigurationHandle
)
/*++
Routine Description:
Called when a new adapter should be registered.
Initializes the adapter block, and calls NdisRegisterAdapter().
Arguments:
AdapterName - The name that the system will refer to the adapter by.
Others - Adapter-specific parameters as defined in defaults.h.
Return Value:
Indicates the success or failure of the registration.
--*/
{
NDIS_STATUS Status;
NDIS_INTERFACE_TYPE InterfaceType;
UINT i;
PVOID TranslatedIdPort=NULL;
Elnk3InitAdapterBlock(pAdapter);
//
// Initialize various elments in the Adapter Structure;
//
if ((pAdapter->CardType==ELNK3_3C509) ||
((pAdapter->CardType==ELNK3_3C589))) {
InterfaceType = NdisInterfaceIsa;
} else {
if (pAdapter->CardType==ELNK3_3C579) {
InterfaceType = NdisInterfaceEisa;
} else {
InterfaceType = NdisInterfaceMca;
}
}
NdisMSetAttributes(
pAdapter->NdisAdapterHandle,
pAdapter,
FALSE,
InterfaceType
);
if ((pMac->TranslatedIdPort==0) && (pAdapter->CardType==ELNK3_3C509)) {
IF_INIT_LOUD(DbgPrint("Elnk3: First ISA card claiming Id port\n");)
Status=NdisMRegisterIoPortRange(
&TranslatedIdPort,
pAdapter->NdisAdapterHandle,
pAdapter->IdPortBaseAddr,
1
);
if (Status != NDIS_STATUS_SUCCESS) {
IF_INIT_LOUD(DbgPrint("Elnk3: First ISA card claiming Id port---FAILED\n");)
goto fail0;
}
pAdapter->IdPortOwner=TRUE;
pMac->TranslatedIdPort=TranslatedIdPort;
//
// See if there are any boards around
//
Elnk3FindIsaBoards(pMac);
}
Status=NdisMRegisterIoPortRange(
&pAdapter->TranslatedIoBase,
pAdapter->NdisAdapterHandle,
pAdapter->IoPortBaseAddr,
16
);
if (Status != NDIS_STATUS_SUCCESS) {
IF_INIT_LOUD(DbgPrint("Elnk3: Failed to register i/o ports\n");)
goto fail1;
}
//
// Compute the portaddresses now so we don't have to
// do it on each port access
//
for (i=0;i<16;i++) {
pAdapter->PortOffsets[i]=(PUCHAR)pAdapter->TranslatedIoBase+i;
}
if (pAdapter->CardType==ELNK3_3C509) {
//
// Lets try to find a card at the address specified
//
// Note: this service may change the I/O base aquired
// from the registry. This will happen if we can't
// find a match.
//
if (!Elnk3ActivateIsaBoard(
pMac,
pAdapter,
pAdapter->NdisAdapterHandle,
pAdapter->TranslatedIoBase,
pAdapter->IoPortBaseAddr,
&pAdapter->IrqLevel,
pAdapter->Transceiver,
ConfigurationHandle
)) {
NdisWriteErrorLogEntry(
pAdapter->NdisAdapterHandle,
NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
8,
pAdapter->IoPortBaseAddr,
pMac->IsaCards[0].IOPort,
pMac->IsaCards[1].IOPort,
pMac->IsaCards[2].IOPort,
pMac->IsaCards[3].IOPort,
pMac->IsaCards[4].IOPort,
pMac->IsaCards[5].IOPort,
pMac->IsaCards[6].IOPort
);
Status=NDIS_STATUS_ADAPTER_NOT_FOUND;
goto fail2;
}
}
else if (pAdapter->CardType==ELNK3_3C579) {
//
// Get the Irq from the eisa adapter since the 3com
// CFG put the interrupt information in the second
// function of the EISA info instead of making it
// a sub function.
//
Elnk3GetEisaResources(
pAdapter,
&pAdapter->IrqLevel
);
}
else if (pAdapter->CardType==ELNK3_3C589)
{
Status = Elnk3Init3C589( pAdapter);
if (Status != NDIS_STATUS_SUCCESS) {
IF_INIT_LOUD(DbgPrint("Elnk3: Failed to initialize 3C589\n");)
goto fail1;
}
}
//
// Allocate the Send, LookAhead and LoopBack buffers
//
Status=Elnk3AllocateBuffers(
pAdapter,
pAdapter->NdisAdapterHandle,
TRUE
);
if (Status!=NDIS_STATUS_SUCCESS) {
goto fail2;
}
//
// Make sure the card is inactive
//
CardReset(pAdapter);
pAdapter->AdapterInitializing=TRUE;
//
// Set up the interrupt handlers.
//
NdisZeroMemory (&pAdapter->NdisInterrupt, sizeof(NDIS_MINIPORT_INTERRUPT) );
Status=NdisMRegisterInterrupt(
&pAdapter->NdisInterrupt, // interrupt info str
pAdapter->NdisAdapterHandle, // NDIS adapter handle
(UINT)pAdapter->IrqLevel, // vector or int number
(UINT)pAdapter->IrqLevel, // level or priority
TRUE,
FALSE, // NOT shared
pAdapter->InterruptMode
);
if (Status != NDIS_STATUS_SUCCESS) {
IF_LOUD (DbgPrint("ELNK3: NdisInitializeInterruptFailed\n");)
NdisWriteErrorLogEntry(
pAdapter->NdisAdapterHandle,
NDIS_ERROR_CODE_INTERRUPT_CONNECT,
1,
(ULONG)pAdapter->IrqLevel
);
goto fail3;
}
//
// Perform card tests.
//
if (!CardTest(pAdapter) ) {
IF_LOUD ( DbgPrint("ELNK3: CardTest() failed, game over\n");)
NdisWriteErrorLogEntry(
pAdapter->NdisAdapterHandle,
NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
2,
(ULONG)pAdapter->IrqLevel,
(ULONG)pAdapter->IoPortBaseAddr
);
Status = NDIS_STATUS_FAILURE;
goto fail4;
}
// register a shutdown handler for this card
NdisMRegisterAdapterShutdownHandler(
pAdapter->NdisAdapterHandle, // miniport handle.
pAdapter, // shutdown context.
Elnk3Shutdown // shutdown handler.
);
CardReStart(pAdapter);
CardReStartDone(pAdapter);
IF_LOUD (DbgPrint("Elnk3: Elnk3InitializeAdapter() Succeeded\n");)
return NDIS_STATUS_SUCCESS;
//
// IF WE ARE HERE SOME INITIALIZATION FAILURE OCCURRED
//
//
// 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.
//
fail4:
NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt);
fail3:
Elnk3AllocateBuffers(
pAdapter,
pAdapter->NdisAdapterHandle,
FALSE
);
fail2:
NdisMDeregisterIoPortRange(
pAdapter->NdisAdapterHandle,
pAdapter->IoPortBaseAddr,
16,
pAdapter->TranslatedIoBase
);
fail1:
if (pAdapter->IdPortOwner) {
IF_INIT_LOUD(DbgPrint("Elnk3: Id port owner going away\n");)
NdisMDeregisterIoPortRange(
pAdapter->NdisAdapterHandle,
pAdapter->IdPortBaseAddr,
1,
pMac->TranslatedIdPort
);
pMac->TranslatedIdPort=0;
}
fail0:
IF_LOUD (DbgPrint("Elnk3RegisterAdapter() Failed\n");)
return Status;
}
NDIS_STATUS
Elnk3AllocateBuffers(
IN PELNK3_ADAPTER pAdapter,
IN NDIS_HANDLE NdisAdapterHandle,
BOOLEAN Allocate
)
{
NDIS_STATUS Status;
if (Allocate) {
//
// Allocate the memory to hold the loopback indication
//
Status=NdisAllocateMemory(
(PVOID *)(&pAdapter->TransContext[0].LookAhead),
4096,
0,
HighestAcceptableMax
);
if (Status!=NDIS_STATUS_SUCCESS) {
goto Fail0000;
}
pAdapter->TransContext[1].LookAhead=
(PNIC_RCV_HEADER)((PUCHAR)pAdapter->TransContext[0].LookAhead+2048);
IF_INIT_LOUD(DbgPrint("ELNK3: Lookahead->%08lx\n",pAdapter->TransContext[0].LookAhead);)
return NDIS_STATUS_SUCCESS;
}
NdisFreeMemory(
pAdapter->TransContext[0].LookAhead,
4096,
0
);
Fail0000:
return NDIS_STATUS_RESOURCES;
}
VOID
Elnk3InitAdapterBlock(
IN PELNK3_ADAPTER pAdapter
)
{
UINT i;
//
// BUGBUG: This could probably be smaller, but NBF doesn't currently set a
// lookahead size
//
pAdapter->MaxLookAhead=60 ; //ELNK3_MAX_LOOKAHEAD_SIZE;
Elnk3AdjustMaxLookAhead(pAdapter);
for (i=0; i<TIMER_ARRAY_SIZE; i++) {
pAdapter->TimerValues[i]=25;
}
pAdapter->TransContext[0].pAdapter = pAdapter;
pAdapter->TransContext[1].pAdapter = pAdapter;
if (pAdapter->CardType==ELNK3_3C529) {
//
// MCA card does not hide bytes
//
pAdapter->RxHiddenBytes=0;
} else {
//
// ISA hides 16
//
pAdapter->RxHiddenBytes=16;
}
pAdapter->RxMinimumThreshold=8;
//
// Set the minimum amount that needs to be in the fifo
// before we draw out some of an incomplete packet
//
pAdapter->LowWaterMark=64;
return;
}
VOID
Elnk3Shutdown(
IN NDIS_HANDLE MiniportHandle
)
{
PELNK3_ADAPTER pAdapter=MiniportHandle;
IF_INIT_LOUD(DbgPrint("Elnk3: Shutdown\n");)
//
// It's time to rock and roll
//
CardReStart(pAdapter);
}
VOID
Elnk3Halt(
IN NDIS_HANDLE MiniportHandle
)
{
PELNK3_ADAPTER pAdapter=MiniportHandle;
IF_INIT_LOUD(DbgPrint("Elnk3: Halt\n");)
//
// It's time to rock and roll
//
CardReStart(pAdapter);
NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt);
if (pAdapter->IdPortOwner) {
IF_INIT_LOUD(DbgPrint("Elnk3: Id port owner going away\n");)
NdisMDeregisterIoPortRange(
pAdapter->NdisAdapterHandle,
pAdapter->IdPortBaseAddr,
1,
MacBlock.TranslatedIdPort
);
MacBlock.TranslatedIdPort=0;
}
NdisMDeregisterIoPortRange(
pAdapter->NdisAdapterHandle,
pAdapter->IoPortBaseAddr,
16,
pAdapter->TranslatedIoBase
);
Elnk3AllocateBuffers(
pAdapter,
pAdapter->NdisAdapterHandle,
FALSE
);
NdisFreeMemory(
pAdapter,
sizeof(ELNK3_ADAPTER),
0
);
}
NDIS_STATUS
Elnk3Reconfigure(
OUT PNDIS_STATUS OpenErrorStatus,
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_HANDLE ConfigurationHandle
)
{
IF_INIT_LOUD(DbgPrint("Elnk3: Reconfigure\n");)
return NDIS_STATUS_NOT_SUPPORTED;
}
NDIS_STATUS
Elnk3Init3C589(
IN OUT PELNK3_ADAPTER pAdapter
)
{
ELNK3_Address_Configuration_Register acr;
ELNK3_Resource_Configuration_Register rcr;
USHORT i, window;
NDIS_STATUS Status;
Status = NDIS_STATUS_SUCCESS;
ELNK3ReadAdapterUshort ( pAdapter , PORT_CmdStatus , &window );
window &= 0xE000; // Current window - high 3 bits
ELNK3_SELECT_WINDOW( pAdapter, WNO_SETUP );
//
// init address configuration
//
acr.eacf_contents = 0;
if ( pAdapter->Transceiver == TRANSCEIVER_BNC ) {
acr.eacf_XCVR = TRANSCEIVER_BNC;
}
ELNK3WriteAdapterUshort(pAdapter,PORT_CfgAddress,acr.eacf_contents);
// Believe it or not, to make the 3C589 (not 3C589B) the IRQ have to be set
// to 3 (it can be anything - the card must be told 3).
rcr.ercf_contents = 0;
// rcr.ercf_IRQ = (USHORT)pAdapter->IrqLevel;
rcr.ercf_IRQ = 3;
rcr.ercf_reserved_F = 0xF;
ELNK3WriteAdapterUshort(pAdapter,PORT_CfgResource,rcr.ercf_contents);
// read in product ID
i = ELNK3ReadEEProm( pAdapter, EEPROM_PRODUCT_ID );
ELNK3WriteAdapterUshort( pAdapter, PORT_ProductID, i );
// Enable the adapter by setting the bit in the configuration control register
ELNK3WriteAdapterUchar(pAdapter,PORT_CfgControl,CCR_ENABLE);
// restore to whatever it used to be
ELNK3_SELECT_WINDOW( pAdapter, window);
return (Status);
}