From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/ndis/madge/driver/madge.c | 3393 ++++++++++++++++++++++++++++++++ 1 file changed, 3393 insertions(+) create mode 100644 private/ntos/ndis/madge/driver/madge.c (limited to 'private/ntos/ndis/madge/driver/madge.c') diff --git a/private/ntos/ndis/madge/driver/madge.c b/private/ntos/ndis/madge/driver/madge.c new file mode 100644 index 000000000..9e3e22dda --- /dev/null +++ b/private/ntos/ndis/madge/driver/madge.c @@ -0,0 +1,3393 @@ +/*************************************************************************** +* +* MADGE.C +* +* FastMAC Plus based NDIS3 miniport driver entry, initialisation and +* closedown module. +* +* Copyright (c) Madge Networks Ltd 1994 +* +* COMPANY CONFIDENTIAL +* +* Created: PBA 21/06/1994 +* +****************************************************************************/ + +#include + +#include "ftk_defs.h" +#include "ftk_extr.h" +#include "ftk_intr.h" + +#include "mdgmport.upd" +#include "ndismod.h" + +/*--------------------------------------------------------------------------- +| +| Identification string for MVER. +| +---------------------------------------------------------------------------*/ + +char MVerString[] = MVER_STRING; + + +/*--------------------------------------------------------------------------- +| +| Option strings for registry queries. +| +| There is a lot of fuss here to get the various strings defined in the +| correct way - those that are optional need to be defined in the parm. +| table as string constants, while those that are passed directly to the +| registry query functions need to be explicitly defined outside any +| structures. +| +|--------------------------------------------------------------------------*/ + +#define HIDDEN_OFFS 0x80 + +#define EmptyString NDIS_STRING_CONST("") + +// +// These are the NT versions of the option strings. +// + +#define IOAddrString NDIS_STRING_CONST("IoLocation") +#define IOBaseString NDIS_STRING_CONST("IoBaseAddress") +#define InterruptNumString NDIS_STRING_CONST("InterruptNumber") +#define DMAChanString NDIS_STRING_CONST("DmaChannel") +#define TxSlotNumString NDIS_STRING_CONST("TxSlots") +#define RxSlotNumString NDIS_STRING_CONST("RxSlots") +#define MaxFrameSizeString NDIS_STRING_CONST("MaxFrameSize") +#define CardBuffSizeString NDIS_STRING_CONST("CardBufferSize") +#define AlternateIoString NDIS_STRING_CONST("Alternate") +#define TestAndXIDString NDIS_STRING_CONST("TestAndXIDEnabled") +#define RxTxSlotsString NDIS_STRING_CONST("RxTxSlots") +#define ForceOpenString NDIS_STRING_CONST("ForceOpen") +#define Force4String NDIS_STRING_CONST("Force4") +#define Force16String NDIS_STRING_CONST("Force16") +#define SlotNumString NDIS_STRING_CONST("SlotNumber") +#define NoPciMmioString NDIS_STRING_CONST("NoMmio") +#define RingSpeedString NDIS_STRING_CONST("RingSpeed") +#define AdapterTypeString NDIS_STRING_CONST("AdapterType") +#define MmioAddrString NDIS_STRING_CONST("MemBase") +#define PlatformTypeString NDIS_STRING_CONST("PlatformType") +#define TransferTypeString NDIS_STRING_CONST("TransferType") + +WCHAR PromModeString[] = + { L'P' + HIDDEN_OFFS, L'r' + HIDDEN_OFFS, L'o' + HIDDEN_OFFS, + L'm' + HIDDEN_OFFS, L'i' + HIDDEN_OFFS, L's' + HIDDEN_OFFS, + L'c' + HIDDEN_OFFS, L'u' + HIDDEN_OFFS, L'o' + HIDDEN_OFFS, + L'u' + HIDDEN_OFFS, L's' + HIDDEN_OFFS, L'M' + HIDDEN_OFFS, + L'o' + HIDDEN_OFFS, L'd' + HIDDEN_OFFS, L'e' + HIDDEN_OFFS, + L'X' + HIDDEN_OFFS, 000 }; + +#define PromiscuousString { sizeof(PromModeString) - 2, \ + sizeof(PromModeString), \ + PromModeString } + +// +// These strings are passed direct to NdisReadConfiguration. +// + +STATIC NDIS_STRING BusTypeString = NDIS_STRING_CONST("BusType"); +STATIC NDIS_STRING BusNumberString = NDIS_STRING_CONST("BusNumber"); +STATIC NDIS_STRING IOAddressString = IOAddrString; +STATIC NDIS_STRING IOBaseAddrString = IOBaseString; +STATIC NDIS_STRING InterruptNumberString = InterruptNumString; +STATIC NDIS_STRING DMAChannelString = DMAChanString; +STATIC NDIS_STRING SlotNumberString = SlotNumString; +STATIC NDIS_STRING NoMmioString = NoPciMmioString; +STATIC NDIS_STRING AdapterString = AdapterTypeString; +STATIC NDIS_STRING MmioAddressString = MmioAddrString; +STATIC NDIS_STRING PlatformString = PlatformTypeString; +STATIC NDIS_STRING TransferModeString = TransferTypeString; + +STATIC NDIS_STRING NullString = EmptyString; + + +/*--------------------------------------------------------------------------- +| +| Optional parameter structure. +| +|--------------------------------------------------------------------------*/ + +// +// The Keyword parameters here use the #define's above, so the compiler is +// kept happy about string initialisers. +// + +STATIC struct +{ + MADGE_PARM_DEFINITION TxSlots; + MADGE_PARM_DEFINITION RxSlots; + MADGE_PARM_DEFINITION MaxFrameSize; + MADGE_PARM_DEFINITION CardBufferSize; + MADGE_PARM_DEFINITION PromiscuousMode; + MADGE_PARM_DEFINITION AlternateIo; + MADGE_PARM_DEFINITION TestAndXIDEnabled; + MADGE_PARM_DEFINITION RxTxSlots; + MADGE_PARM_DEFINITION ForceOpen; + MADGE_PARM_DEFINITION Force4; + MADGE_PARM_DEFINITION Force16; + MADGE_PARM_DEFINITION RingSpeed; + MADGE_PARM_DEFINITION NullParm; +} +MadgeParmTable = +{ + {TxSlotNumString, 2, 32, {NdisParameterInteger, 0}}, + {RxSlotNumString, 2, 32, {NdisParameterInteger, 0}}, + {MaxFrameSizeString, 1024, 17839, {NdisParameterInteger, 4096}}, + {CardBuffSizeString, 0, 0xFFFF, {NdisParameterInteger, 0}}, + {PromiscuousString, 0, 1, {NdisParameterInteger, 0}}, + {AlternateIoString, 0, 1, {NdisParameterInteger, 0}}, + {TestAndXIDString, 0, 1, {NdisParameterInteger, 0}}, + {RxTxSlotsString, 0, 5, {NdisParameterInteger, 2}}, + {ForceOpenString, 0, 1, {NdisParameterInteger, 0}}, + {Force4String, 0, 1, {NdisParameterInteger, 0}}, + {Force16String, 0, 1, {NdisParameterInteger, 0}}, + {RingSpeedString, 0, 2, {NdisParameterInteger, 0}}, + {EmptyString} +}; + + +/*--------------------------------------------------------------------------- +| +| Name of the FastMAC Plus image file. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STRING FmpImageFileName = MADGE_FMP_NAME; + + +/*--------------------------------------------------------------------------- +| +| List of PCI adapters in use. +| +---------------------------------------------------------------------------*/ + +STATIC struct +{ + UINT BusNumber; + UINT SlotNumber; +} +PciSlotsUsedList[MAX_NUMBER_OF_ADAPTERS]; + +STATIC int +PciSlotsUsedCount = 0; + + +/**************************************************************************** +* +* NDIS3 level adapter structure pointer table. +* +****************************************************************************/ + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeReadRegistryForMC +| +| Parameters - wrapperConfigHandle -> Wrapper context handle. +| registryConfigHandle -> Already open registry query handle. +| ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +| +| Purpose - Read configuration information for MC adapters out of +Ý the registry. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeReadRegistryForMC( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap + ); + +#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForMC) + +STATIC NDIS_STATUS +MadgeReadRegistryForMC( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap + ) +{ + static WORD mcaIrqMap[4] = { 0, 3, 9, 10}; + static WORD mcaIoMap[8] = {0x0a20, 0x1a20, 0x2a20, 0x3a20, + 0x0e20, 0x1e20, 0x2e20, 0x3e20}; + + NDIS_STATUS status; + PNDIS_CONFIGURATION_PARAMETER configParam; + UINT slotNumber; + NDIS_MCA_POS_DATA mcaData; + BYTE iOSelect; + + // + // Note the information that is always true for MC adapters. + // + + ndisAdap->NTCardBusType = NdisInterfaceMca; + ndisAdap->FTKCardBusType = ADAPTER_CARD_MC_BUS_TYPE; + ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE; + + // + // MicroChannel is easy - the POS registers contain all the info + // we need, so read those and save the information. + // + + NdisReadMcaPosInformation( + &status, + wrapperConfigHandle, + &slotNumber, + &mcaData + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_MCA_POS + ); + + return status; + } + + // + // Decode the Interrupt Number. Note: the FTK will throw + // IRQ 0 out as invalid. + // + + ndisAdap->UsedInISR.InterruptNumber = mcaIrqMap[mcaData.PosData1 >> 6]; + + // + // NB: Arbitration Level 15 => PIO, which we do not allow - + // the FTK will throw this out as an invalid DMA channel. + // NB: We call it DmaChannel to be compatible with ISA cards. + // + + ndisAdap->DmaChannel = (mcaData.PosData1 >> 1) & 0x0F; + + // + // Build the IO Location select value from several sources. + // + + iOSelect = (mcaData.PosData1 >> 5) & 0x01; + iOSelect |= (mcaData.PosData4 >> 4) & 0x02; + iOSelect |= (mcaData.PosData3 >> 0) & 0x04; + + // + // NB: IO locations 0x2e20 and 0x3e20 are only valid for + // MC32 cards, but the .ADF file will have prevented them + // being set for MC16s. + // + + ndisAdap->IoLocation1 = mcaIoMap[iOSelect]; + ndisAdap->UsedInISR.InterruptMode = NdisInterruptLevelSensitive; + ndisAdap->UsedInISR.InterruptShared = TRUE; + ndisAdap->IORange1 = MC_IO_RANGE; + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeReadRegistryForEISA +| +| Parameters - wrapperConfigHandle -> Wrapper context handle. +| registryConfigHandle -> Already open registry query handle. +| ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +| +| Purpose - Read configuration information for an EISA adapter +Ý out of the registry. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeReadRegistryForEISA( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap + ); + +#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForEISA) + +STATIC NDIS_STATUS +MadgeReadRegistryForEISA( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap + ) +{ + NDIS_STATUS status; + PNDIS_CONFIGURATION_PARAMETER configParam; + UINT slotNumber; + NDIS_EISA_FUNCTION_INFORMATION eisaData; + + // + // For Eisa bus systems, we could have an Isa card or an Eisa + // card - try to read the Eisa information, and if that fails + // MadgeReadRegistry will assume it is an Isa card instead. + // + + NdisReadEisaSlotInformation( + &status, + wrapperConfigHandle, + &slotNumber, + &eisaData + ); + + if (status != NDIS_STATUS_SUCCESS) + { + return status; + } + + // + // Note the information that is always true for EISA + // adapters. + // + + ndisAdap->NTCardBusType = NdisInterfaceEisa; + ndisAdap->FTKCardBusType = ADAPTER_CARD_EISA_BUS_TYPE; + ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE; + + // + // Got EISA configuration data - decode the relevant bits. + // + + ndisAdap->IoLocation1 = slotNumber << 12; + + // + // Get the Interrupt number from the NVRAM data - we know it + // is going to be the first Irq element in the Irq array + // because the card only uses one interrupt. + // + + ndisAdap->UsedInISR.InterruptNumber = + eisaData.EisaIrq[0].ConfigurationByte.Interrupt; + + ndisAdap->UsedInISR.InterruptMode = (NDIS_INTERRUPT_MODE) + (eisaData.EisaIrq[0].ConfigurationByte.LevelTriggered + ? NdisInterruptLevelSensitive + : NdisInterruptLatched); + + ndisAdap->UsedInISR.InterruptShared = (BOOLEAN) + eisaData.EisaIrq[0].ConfigurationByte.Shared; + + // + // For EISA cards we don't care what the DMA setting is. So + // we leave it set to 0 forget about it. + // + + ndisAdap->IORange1 = EISA_IO_RANGE; + ndisAdap->IoLocation2 = ndisAdap->IoLocation1 + EISA_IO_RANGE2_BASE; + ndisAdap->IORange2 = EISA_IO_RANGE2; + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeReadRegistryForISA +| +| Parameters - wrapperConfigHandle -> Wrapper context handle. +| registryConfigHandle -> Already open registry query handle. +| ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +Ý adapterType -> Adapter type. +| +| Purpose - Read configuration information for ISA adapters out +Ý of the registry. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeReadRegistryForISA( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + ULONG adapterType + ); + +#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForISA) + +STATIC NDIS_STATUS +MadgeReadRegistryForISA( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + ULONG adapterType + ) +{ + NDIS_STATUS status; + PNDIS_CONFIGURATION_PARAMETER configParam; + + // + // Note the information that is always TRUE for ISA adapters. + // + + ndisAdap->NTCardBusType = NdisInterfaceIsa; + + // + // Do some adapter type specific setup. If we don't + // know what sort of adapter it is we'll assume it's + // an ATULA adapter so we are backwards compatible. + // + + switch (adapterType) + { + case MADGE_ADAPTER_UNKNOWN: + case MADGE_ADAPTER_ATULA: + + ndisAdap->FTKCardBusType = ADAPTER_CARD_ATULA_BUS_TYPE; + ndisAdap->IORange1 = ATULA_IO_RANGE; + ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE; + break; + + case MADGE_ADAPTER_SMART16: + + ndisAdap->FTKCardBusType = ADAPTER_CARD_SMART16_BUS_TYPE; + ndisAdap->IORange1 = SMART16_IO_RANGE; + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + break; + + case MADGE_ADAPTER_PCMCIA: + + ndisAdap->FTKCardBusType = ADAPTER_CARD_PCMCIA_BUS_TYPE; + ndisAdap->IORange1 = PCMCIA_IO_RANGE; + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + break; + + case MADGE_ADAPTER_PNP: + + ndisAdap->FTKCardBusType = ADAPTER_CARD_PNP_BUS_TYPE; + ndisAdap->IORange1 = PNP_IO_RANGE; + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + break; + + default: + + return NDIS_STATUS_FAILURE; + } + + // + // Get the IO location - must have this. First try + // "IoLocation" and then "IoBaseAddress". + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &IOAddressString, + NdisParameterHexInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &IOBaseAddrString, + NdisParameterHexInteger + ); + } + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_ISA_IO + ); + + return status; + } + + ndisAdap->IoLocation1 = configParam->ParameterData.IntegerData; + + // + // Er, slight hack here. We used to pretend that Smart16 + // adapters were ATULA adapters. We now don't. So to + // be backwards compatible, if we have an unknown adapter + // with an IO base >= 0x4a20 and <= 0x6e20 we'll assume it's + // really a Smart16. + // + + if (adapterType == MADGE_ADAPTER_UNKNOWN && + ndisAdap->IoLocation1 >= 0x4a20 && + ndisAdap->IoLocation1 <= 0x6e20) + { + adapterType = MADGE_ADAPTER_SMART16; + ndisAdap->FTKCardBusType = ADAPTER_CARD_SMART16_BUS_TYPE; + ndisAdap->IORange1 = SMART16_IO_RANGE; + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + } + + // + // Get the IRQ number - we must have this. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &InterruptNumberString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_ISA_IRQ + ); + + return status; + } + + ndisAdap->UsedInISR.InterruptNumber = + configParam->ParameterData.IntegerData; + + ndisAdap->UsedInISR.InterruptMode = NdisInterruptLatched; + ndisAdap->UsedInISR.InterruptShared = FALSE; + + // + // Read the TransferType parameter and switch into PIO + // mode if specified. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &TransferModeString, + NdisParameterInteger + ); + + if (status == NDIS_STATUS_SUCCESS) + { + if (configParam->ParameterData.IntegerData == MADGE_PIO_MODE) + { + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + } + } + + // + // Get the DMA channel (PIO is specified as channel 0, + // multiprocessor safe PIO is specified as 0x8000). We + // don't need a DMA channel if the adapter isn't an ATULA so + // the only reason for reading the DMA channel for none + // ATULA adapters is to allow backwards compatability with old + // registry set ups that specify multiprocessor safe PIO + // with the DmaChannel == 0x8000. Using the DMA channel + // to specify PIO is retained for backwards compatibility + // the correct way is to set the TransferType parameter. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &DMAChannelString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + ndisAdap->DmaChannel = 0; + } + else + { + ndisAdap->DmaChannel = configParam->ParameterData.IntegerData; + } + + // + // Note if we should be using multiprocessor safe PIO. + // + + if (ndisAdap->DmaChannel == 0x8000) + { + ndisAdap->DmaChannel = 0; + ndisAdap->UseMPSafePIO = TRUE; + } + + // + // If we did not get a DMA channel then we must use PIO. + // + + if (ndisAdap->DmaChannel == 0) + { + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + } + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeFindPciInfoForWin95 +| +| Parameters - wrapperConfigHandle -> Wrapper context handle. +| registryConfigHandle -> Already open registry query handle. +| ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +Ý pciSlotInfo -> Pointer to a buffer that will +Ý be filled with the configuration +Ý data for the adapter. +| +| Purpose - Read configuration information for PCI adapters out +Ý of the registry when running on Windows95. The slot +Ý containing the adapter is also found and the configuration +Ý data from the slot returned in the pciSlotInfo buffer. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeFindPciInfoForWin95( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + BYTE * pciSlotInfo + ); + +#pragma FTK_INIT_FUNCTION(MadgeFindPciInfoForWin95) + +STATIC NDIS_STATUS +MadgeFindPciInfoForWin95( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + BYTE * pciSlotInfo + + ) +{ + NDIS_STATUS status; + PNDIS_CONFIGURATION_PARAMETER configParam; + UINT i; + + // + // Unfortunately Windows95 (M7) and NT handle PCI configuration + // in different ways. Under NT one has to read the slot + // configuration. Under Windows95 the resource information + // is faked up by the configuration manager and can be read + // directly from the wrapper. + // + + // + // Get the IO location - must have this. First try + // "IoLocation" and then "IoBaseAddress". + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &IOAddressString, + NdisParameterHexInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &IOBaseAddrString, + NdisParameterHexInteger + ); + } + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_PCI_IO + ); + + return status; + } + + ndisAdap->IoLocation1 = configParam->ParameterData.IntegerData; + + // + // Get the IRQ number - we must have this. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &InterruptNumberString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_PCI_IRQ + ); + + return status; + } + + ndisAdap->UsedInISR.InterruptNumber = + configParam->ParameterData.IntegerData; + + // + // Get the MMIO base address - optional. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &MmioAddressString, + NdisParameterInteger + ); + + if (status == NDIS_STATUS_SUCCESS) + { + ndisAdap->MmioRawAddress = + configParam->ParameterData.IntegerData; + } + + // + // We also need to know which slot the adapter is in so we can + // read and write configuration space directly. We'll search for + // a slot which contains a Madge adapter which the correct I/O + // location. As a side effect we'll store the configuration data + // for the slot in pciSlotInfo. Note: Under Windows 95 (build 490) + // NdisReadPciSlotInformation does appear to return the number + // of bytes read as it does under NT - not sure what it returns ... + // + + ndisAdap->SlotNumber = PCI_FIND_ADAPTER; + + for (i = 0; i < MAX_PCI_SLOTS; i++) + { + NdisReadPciSlotInformation( + ndisAdap->UsedInISR.MiniportHandle, + i, + 0, + (VOID *) pciSlotInfo, + PCI_CONFIG_SIZE + ); + + if (PCI_VENDOR_ID(pciSlotInfo) == MADGE_PCI_VENDOR_ID && + PCI_IO_BASE(pciSlotInfo) == ndisAdap->IoLocation1) + { + ndisAdap->SlotNumber = i; + break; + } + } + + if (ndisAdap->SlotNumber == PCI_FIND_ADAPTER) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + readRegistry, + MADGE_ERRMSG_BAD_PCI_SLOTNUMBER + ); + + return NDIS_STATUS_FAILURE; + } + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +Ý +Ý Function - MadgePciSlotUsed +Ý +Ý Parameters - busNumber -> Bus number containing the adapter. +Ý slotNumber -> Slot number containing the adapter. +Ý +Ý Purpose - Check if a PCI slot is already in use. +Ý +Ý Returns - TRUE if the slot is in use or FALSE if not. +Ý +Ý--------------------------------------------------------------------------*/ + +STATIC BOOLEAN +MadgePciSlotUsed( + UINT busNumber, + UINT slotNumber + ); + +#pragma FTK_INIT_FUNCTION(MadgePciSlotUsed) + +STATIC BOOLEAN +MadgePciSlotUsed( + UINT busNumber, + UINT slotNumber + ) +{ + int i; + + for (i = 0; i < PciSlotsUsedCount; i++) + { + if (PciSlotsUsedList[i].BusNumber == busNumber && + PciSlotsUsedList[i].SlotNumber == slotNumber) + { + return TRUE; + } + } + + return FALSE; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeFindPciInfoForNt +| +| Parameters - wrapperConfigHandle -> Wrapper context handle. +| registryConfigHandle -> Already open registry query handle. +| ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +Ý pciSlotInfo -> Pointer to a buffer that will +Ý be filled with the configuration +Ý data for the adapter. +| +| Purpose - Read configuration information for PCI adapters out +Ý of the registry when running on Windows95. The slot +Ý containing the adapter is also found and the configuration +Ý data from the slot returned in the pciSlotInfo buffer. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeFindPciInfoForNt( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + BYTE * pciSlotInfo + ); + +#pragma FTK_INIT_FUNCTION(MadgeFindPciInfoForNt) + +STATIC NDIS_STATUS +MadgeFindPciInfoForNt( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + BYTE * pciSlotInfo + ) +{ + NDIS_STATUS status; + PNDIS_CONFIGURATION_PARAMETER configParam; + UINT slotNumber; + BOOLEAN pciSlotRead; + BOOLEAN useMmio; + UINT i; + PNDIS_RESOURCE_LIST pciResources; + PCM_PARTIAL_RESOURCE_DESCRIPTOR resDesc; + UINT busNumber; + + // + // Unfortunately Windows95 (M7) and NT handle PCI configuration + // in different ways. Under NT one has to read the slot + // configuration. Under Windows95 the resource information + // is faked up by the configuration manager and can be read + // directly from the wrapper. + // + + // + // Find out what the slot number is. This is in fact the + // PCI device number. Values 0 through 31 represent real + // slot numbers. 0xffff means we should search for the + // first unused Madge PCI adapter. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &SlotNumberString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_PCI_SLOTNUMBER + ); + + return status; + } + + slotNumber = configParam->ParameterData.IntegerData; + pciSlotRead = FALSE; + + // + // Read the bus number. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &BusNumberString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_PCI_SLOTNUMBER + ); + + return status; + } + + busNumber = configParam->ParameterData.IntegerData; + + // + // If the slot number is PCI_FIND_ADAPTER (0xffff) then we + // will attempt to search for the first Madge PCI adapter + // that is not already in use. + // + + if (slotNumber == PCI_FIND_ADAPTER) + { + for (i = 0; !pciSlotRead && i < MAX_PCI_SLOTS; i++) + { + if (!MadgePciSlotUsed(busNumber, i)) + { + // + // Extract the PCI configuration information from + // the slot. + // + + status = NdisReadPciSlotInformation( + ndisAdap->UsedInISR.MiniportHandle, + i, + 0, + (VOID *) pciSlotInfo, + PCI_CONFIG_SIZE + ); + // + // Check if the slot contains a Madge adapter and + // break out of the loop if it does. + // + + if (status == PCI_CONFIG_SIZE && + PCI_VENDOR_ID(pciSlotInfo) == MADGE_PCI_VENDOR_ID) + { + slotNumber = i; + pciSlotRead = TRUE; + } + } + } + } + + // + // Check if the slotNumber is valid. This will fail if the + // above adapter search failed. + // + + if (slotNumber < 0 || + slotNumber >= MAX_PCI_SLOTS || + MadgePciSlotUsed(busNumber, slotNumber)) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + readRegistry, + MADGE_ERRMSG_BAD_PCI_SLOTNUMBER + ); + + return NDIS_STATUS_FAILURE; + } + + // + // Note that the PCI slot is in use. + // + + PciSlotsUsedList[PciSlotsUsedCount].BusNumber = busNumber; + PciSlotsUsedList[PciSlotsUsedCount].SlotNumber = slotNumber; + PciSlotsUsedCount++; + + ndisAdap->SlotNumber = slotNumber; + + // + // There two methods for getting the PCI configuration. One is + // to read it directly from the PCI configuration space. This + // works for Intel patforms where a PCI BIOS has configured + // all of the adapters at boot time. It does not work for + // none Intel platforms where the PCI devices are not + // configured at boot time. Unfortunately the call which + // provokes NT to configure a PCI device, NdisMPciAssignResources + // is not available in the NT 3.5 wrapper. So, until NT 3.51 + // becomes dominant we must support both configuration methods. + // + + // + // If we haven't already extracted the PCI configuration + // information from the slot and check that it is valid. + // + + if (!pciSlotRead) + { + status = NdisReadPciSlotInformation( + ndisAdap->UsedInISR.MiniportHandle, + slotNumber, + 0, + (VOID *) pciSlotInfo, + PCI_CONFIG_SIZE + ); + + if (status != PCI_CONFIG_SIZE || + PCI_VENDOR_ID(pciSlotInfo) != MADGE_PCI_VENDOR_ID) + { + MadgePrint1("No Madge adapter in slot\n"); + + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + readRegistry, + MADGE_ERRMSG_BAD_PCI_SLOTNUMBER + ); + + return NDIS_STATUS_FAILURE; + } + } + + // + // Call NdisMPciAssignResources for the specified slot to + // get the adapter configuration. + // + + status = NdisMPciAssignResources( + ndisAdap->UsedInISR.MiniportHandle, + slotNumber, + &pciResources + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + readRegistry, + MADGE_ERRMSG_BAD_PCI_SLOTNUMBER + ); + + return NDIS_STATUS_FAILURE; + } + + // + // Iterate through the returned resource list recording the values + // in the PCI configuration + // + + for (i = 0; i < pciResources->Count; i++) + { + resDesc = &pciResources->PartialDescriptors[i]; + + switch (resDesc->Type) + { + case CmResourceTypeInterrupt: + + ndisAdap->UsedInISR.InterruptNumber = + (ULONG) resDesc->u.Interrupt.Vector; + break; + + case CmResourceTypePort: + + ndisAdap->IoLocation1 = + (UINT) NdisGetPhysicalAddressLow(resDesc->u.Port.Start); + break; + + case CmResourceTypeMemory: + + ndisAdap->MmioRawAddress = + (DWORD) NdisGetPhysicalAddressLow(resDesc->u.Memory.Start); + break; + } + } + + + // + // On none-Intel platforms it's possible for the PCI adapter's I/O + // base to be greater than 0xffff. Since the FTK uses 16bit + // I/O locations we make a note of the I/O base in a 32bit cell + // that we can add in inside the I/O functions in sys_mem.c + // + +#ifndef _M_IX86 + + ndisAdap->IoLocationBase = ndisAdap->IoLocation1; + ndisAdap->IoLocation1 = 0; + +#endif + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeReadRegistryForPCI +| +| Parameters - wrapperConfigHandle -> Wrapper context handle. +| registryConfigHandle -> Already open registry query handle. +| ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +Ý platformType -> Type of platform: NT or Win95. +| +| Purpose - Read configuration information for PCI. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeReadRegistryForPCI( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + UINT platformType + ); + +#pragma FTK_INIT_FUNCTION(MadgeReadRegistryForPCI) + +STATIC NDIS_STATUS +MadgeReadRegistryForPCI( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap, + UINT platformType + ) +{ + NDIS_STATUS status; + PNDIS_CONFIGURATION_PARAMETER configParam; + BYTE pciSlotInfo[PCI_CONFIG_SIZE]; + BOOLEAN useMmio; + + // + // Note the information that is always true for PCI adapters. + // + + ndisAdap->NTCardBusType = NdisInterfacePci; + + // + // Set up the fixed configuration information. + // + + ndisAdap->UsedInISR.InterruptMode = NdisInterruptLevelSensitive; + ndisAdap->UsedInISR.InterruptShared = TRUE; + + // + // We know need to find the PCI adapter and read in the configuration + // information for the slot. Unfortunatetly the method we have to use + // is different for NT and Win95. + // + + if (platformType == MADGE_OS_WIN95) + { + status = MadgeFindPciInfoForWin95( + wrapperConfigHandle, + registryConfigHandle, + ndisAdap, + pciSlotInfo + ); + } + else + { + status = MadgeFindPciInfoForNt( + wrapperConfigHandle, + registryConfigHandle, + ndisAdap, + pciSlotInfo + ); + } + + if (status != NDIS_STATUS_SUCCESS) + { + return status; + } + + // + // Now we know we have a Madge PCI adapter of some sort but + // as yet we don't know what type. We'll work this out by + // looking at the device/revision ID in the slot's configuration + // data. At the same time we'll note the default transfer type + // for the adapter. + // + + switch (PCI_REVISION(pciSlotInfo)) + { + case MADGE_PCI_RAP1B_REVISION: + + ndisAdap->FTKCardBusType = ADAPTER_CARD_PCI_BUS_TYPE; + ndisAdap->TransferMode = MMIO_DATA_TRANSFER_MODE; + ndisAdap->IORange1 = PCI_IO_RANGE; + break; + + case MADGE_PCI_PCI2_REVISION: + + ndisAdap->FTKCardBusType = ADAPTER_CARD_PCI2_BUS_TYPE; + ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE; + ndisAdap->IORange1 = PCI2_IO_RANGE; + break; + + case MADGE_PCI_PCIT_REVISION: + + ndisAdap->FTKCardBusType = ADAPTER_CARD_TI_PCI_BUS_TYPE; + ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE; + ndisAdap->IORange1 = SIF_IO_RANGE; + break; + + default: + + return NDIS_STATUS_FAILURE; + } + + // + // Now we need to work out the transfer type. There are three + // things that affect the transfer type: the setting of + // the TransferType registry parameter, the setting of the + // NoMmio registry flag and whether we have been allocated any + // MMIO memory. Ideally we would just use the TransferType flag. + // The NoMmio flag is to preserve backwards compatibility with old + // registry set ups. + // + + // + // Read the transfer type flag if possible. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &TransferModeString, + NdisParameterInteger + ); + + if (status == NDIS_STATUS_SUCCESS) + { + // + // Set the transfer type depending on the TransferType parameter + // and the adapter type. + // + + if (configParam->ParameterData.IntegerData == MADGE_DMA_MODE) + { + if (ndisAdap->FTKCardBusType == ADAPTER_CARD_PCI2_BUS_TYPE || + ndisAdap->FTKCardBusType == ADAPTER_CARD_TI_PCI_BUS_TYPE) + { + ndisAdap->TransferMode = DMA_DATA_TRANSFER_MODE; + } + } + + if (configParam->ParameterData.IntegerData == MADGE_PIO_MODE) + { + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + } + + if (configParam->ParameterData.IntegerData == MADGE_MMIO_MODE) + { + if (ndisAdap->FTKCardBusType == ADAPTER_CARD_PCI_BUS_TYPE) + { + ndisAdap->TransferMode = MMIO_DATA_TRANSFER_MODE; + } + } + } + + // + // To preserve backwards compatibility if we find the NoMmio flag + // set then switch to PIO mode. + // + + if (ndisAdap->TransferMode == MMIO_DATA_TRANSFER_MODE) + { + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &NoMmioString, + NdisParameterInteger + ); + + if (status == NDIS_STATUS_SUCCESS) + { + if (configParam->ParameterData.IntegerData != 0) + { + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + } + } + } + + // + // If we are in MMIO mode then check that we were allocated some MMIO + // memory. If not switch to PIO mode. + // + + if (ndisAdap->TransferMode == MMIO_DATA_TRANSFER_MODE) + { + if (ndisAdap->MmioRawAddress == 0) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MEMORY_CONFLICT, + 2, + readRegistry, + MADGE_ERRMSG_BAD_PCI_MMIO + ); + + ndisAdap->TransferMode == PIO_DATA_TRANSFER_MODE; + + } + } + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeReadRegistry +| +| Parameters - wrapperConfigHandle -> Wrapper context handle. +| registryConfigHandle -> Already open registry query handle. +| ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +| +| Purpose - Read configuration information out of the registry. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeReadRegistry( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap + ); + +#pragma FTK_INIT_FUNCTION(MadgeReadRegistry) + +STATIC NDIS_STATUS +MadgeReadRegistry( + NDIS_HANDLE wrapperConfigHandle, + NDIS_HANDLE registryConfigHandle, + PMADGE_ADAPTER ndisAdap + ) +{ + NDIS_STATUS status; + PNDIS_CONFIGURATION_PARAMETER configParam; + MADGE_PARM_DEFINITION * pMadgeParmTable; + PVOID networkAddress; + ULONG networkAddressLength; + UINT adapterType; + UINT platformType; + + // + // Try to read the OS platform type. If we don't find one then + // assume we are running on NT. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &PlatformString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + platformType = MADGE_OS_NT; + } + else + { + platformType = configParam->ParameterData.IntegerData; + } + + // + // Read the system bus type - that will give us a direction + // in which to search for further details. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &BusTypeString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MISSING_CONFIGURATION_PARAMETER, + 2, + readRegistry, + MADGE_ERRMSG_NO_BUS_TYPE + ); + + return status; + } + + ndisAdap->BusType = configParam->ParameterData.IntegerData; + + // + // Originally we determined what sort of adapter we had based + // on the bus type returned by the configuration call to the + // wrapper. This works for NT but doesn't for Windows95 (M7) + // which seems to fail to identify a card as being in a PCI + // bus. We also cannot tell between the various sorts of ISA + // adapter now available. To fix this we look in the registry + // for an adapter type parameter. We use this and the bus type + // returned by the wrapper to work out where to start. We don't + // fail if we can't read an adapter type so that we will work with + // old registry set ups. + // + // Build 310 of Windows95 seems to return the native bus type of the + // PC. This means on a PCI machine we always get NdisInterfacePci. + // To get around this problem we will work out the bus type from + // the adapter type parameter if one is present. + // + // Unfortunately we can't just abandon the bus type de-multiplexing + // if we are to work with old NT registry set ups. + // + + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &AdapterString, + NdisParameterInteger + ); + + if (status != NDIS_STATUS_SUCCESS) + { + adapterType = MADGE_ADAPTER_UNKNOWN; + } + else + { + adapterType = configParam->ParameterData.IntegerData; + } + + switch (adapterType) + { + case MADGE_ADAPTER_ATULA: + case MADGE_ADAPTER_PCMCIA: + case MADGE_ADAPTER_PNP: + case MADGE_ADAPTER_SMART16: + + ndisAdap->BusType = NdisInterfaceIsa; + break; + + case MADGE_ADAPTER_EISA: + + ndisAdap->BusType = NdisInterfaceEisa; + break; + + case MADGE_ADAPTER_MC: + + ndisAdap->BusType = NdisInterfaceMca; + break; + + case MADGE_ADAPTER_PCI: + + ndisAdap->BusType = NdisInterfacePci; + break; + + default: + + // + // We don't have a valid adapter type parameter so we'll + // just have to beleive the bus type the wrapper passed + // us. + // + + break; + } + + // + // Based on the determined Bus Type, try to find details of the card. + // + + // + // Remember, all fields of the MADGE_ADAPTER structure were zeroed + // after the structure's allocation. + // + + switch (ndisAdap->BusType) + { + case NdisInterfaceMca: + + status = MadgeReadRegistryForMC( + wrapperConfigHandle, + registryConfigHandle, + ndisAdap + ); + + if (status != NDIS_STATUS_SUCCESS) + { + return status; + } + + break; + + case NdisInterfaceEisa: + + // + // For Eisa bus systems, we could have an Isa card or an Eisa + // card - try to read the Eisa information, and if that fails + // assume it is an Isa card instead. + // + + status = MadgeReadRegistryForEISA( + wrapperConfigHandle, + registryConfigHandle, + ndisAdap + ); + + if (status == NDIS_STATUS_SUCCESS) + { + break; + } + + // + // Failed to read EISA data for this card, so it is unlikely + // to be one - try ISA instead - fall through. + // + + case NdisInterfaceIsa: + + status = MadgeReadRegistryForISA( + wrapperConfigHandle, + registryConfigHandle, + ndisAdap, + adapterType + ); + + if (status != NDIS_STATUS_SUCCESS) + { + return status; + } + + break; + + case NdisInterfacePci: + + status = MadgeReadRegistryForPCI( + wrapperConfigHandle, + registryConfigHandle, + ndisAdap, + platformType + ); + + if (status != NDIS_STATUS_SUCCESS) + { + return status; + } + + break; + + + default: + + // + // Unsupported Bus Type, so return failure - no point being more + // explicit than that at the moment since any of the bits above + // could have failed too, and they do not return anything more + // meaningful either. + // + + return NDIS_STATUS_FAILURE; + } + + MadgePrint2("FTKCardBusType = %d\n", ndisAdap->FTKCardBusType); + MadgePrint2("SlotNumber = %d\n", ndisAdap->SlotNumber); + MadgePrint2("IoLocation1 = %lx\n", ndisAdap->IoLocation1); + MadgePrint2("MmioAddress = %lx\n", ndisAdap->MmioRawAddress); + MadgePrint2("InterruptNumber = %lx\n", ndisAdap->UsedInISR.InterruptNumber); + MadgePrint2("TransferMode = %d\n", ndisAdap->TransferMode); + MadgePrint2("DmaChannel = %d\n", ndisAdap->DmaChannel); + + // + // To get here, we must have worked out the IO Address, IRQ number, DMA + // channel/arbitration level, and all the interrupt details. This just + // leaves the optional parameters for tuning the performance of the MAC + // code. + // + + pMadgeParmTable = (MADGE_PARM_DEFINITION *) &MadgeParmTable; + + while (!NdisEqualString(&pMadgeParmTable->Keyword, &NullString, TRUE)) + { + NdisReadConfiguration( + &status, + &configParam, + registryConfigHandle, + &pMadgeParmTable->Keyword, + pMadgeParmTable->DefaultValue.ParameterType + ); + + if (status == NDIS_STATUS_SUCCESS) + { + // + // Did read something. Check bounds. We assume all are Integers. + // + + if (configParam->ParameterData.IntegerData < + pMadgeParmTable->Minimum || + configParam->ParameterData.IntegerData > + pMadgeParmTable->Maximum) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_DRIVER_FAILURE, + 2, + readRegistry, + MADGE_ERRMSG_BAD_PARAMETER + ); + + pMadgeParmTable->ActualValue = pMadgeParmTable->DefaultValue; + } + else + { + pMadgeParmTable->ActualValue = *configParam; + } + } + else + { + // + // We didn't read anything, so use the default value. + // + + pMadgeParmTable->ActualValue = pMadgeParmTable->DefaultValue; + } + + pMadgeParmTable++; + } + + // + // We have successfully read any optional keywords and none of them is + // too small or big. The other thing we need the registry for is the + // locally administered address, for which there is a specific NDIS call + // + + NdisReadNetworkAddress( + &status, + &networkAddress, + &networkAddressLength, + registryConfigHandle + ); + + if (status == NDIS_STATUS_SUCCESS && + networkAddressLength == TR_LENGTH_OF_ADDRESS) + { + // + // We read a valid length TR address, but if the + // top two bits are not "01", it is not legal. + // + + if ((((BYTE *) networkAddress)[0] & 0xc0) == 0x40) + { + ndisAdap->OpeningNodeAddress = + *((NODE_ADDRESS *) networkAddress); + } + } + + return NDIS_STATUS_SUCCESS; +} + + +/**************************************************************************** +* +* Function - MadgeShutdown +* +* Parameters - context -> Adapter context. +* +* Purpose - Quickly shutdown the adapter. +* +* Returns - Nothing. +* +****************************************************************************/ + +VOID +MadgeShutdown( + NDIS_HANDLE context + ) +{ + MADGE_ADAPTER * ndisAdap; + + ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(context); + + MadgePrint1("MadgeShutdown called\n"); + + if (ndisAdap->TimerInitialized) + { + BOOLEAN timerOutstanding; + + NdisMCancelTimer(&ndisAdap->WakeUpTimer, &timerOutstanding); + NdisMCancelTimer(&ndisAdap->CompletionTimer, &timerOutstanding); + + ndisAdap->TimerInitialized = FALSE; + } + + // + // Just call the FTK to shutdown the adapter. + // + + if (ndisAdap->FtkInitialized) + { + rxtx_await_empty_tx_slots(ndisAdap->FtkAdapterHandle); + driver_remove_adapter(ndisAdap->FtkAdapterHandle); + ndisAdap->FtkInitialized = FALSE; + ndisAdap->AdapterRemoved = TRUE; + } + + MadgePrint1("MadgeShutdown ended\n"); +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeRegisterAdapter +| +| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter +| structure. +| wrapperConfigHandle -> Wrapper context handle. +| +| Purpose - Register an adapter instance with the NDIS3 wrapper. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeRegisterAdapter( + PMADGE_ADAPTER ndisAdap, + NDIS_HANDLE wrapperConfigHandle + ); + +#pragma FTK_INIT_FUNCTION(MadgeRegisterAdapter) + +STATIC NDIS_STATUS +MadgeRegisterAdapter( + PMADGE_ADAPTER ndisAdap, + NDIS_HANDLE wrapperConfigHandle + ) +{ + NDIS_STATUS status; + BOOLEAN busMaster; + + MadgePrint1("MadgeRegisterAdapter started\n"); + + // + // Register a shutdown handler with the wrapper. + // + + NdisMRegisterAdapterShutdownHandler( + ndisAdap->UsedInISR.MiniportHandle, + ndisAdap, + MadgeShutdown + ); + + ndisAdap->ShutdownHandlerRegistered = TRUE; + + // + // Register our attributes with the wrapper. These are our adapter + // context (i.e. a pointer to our adapter structure), whether we + // are a bus master device and our bus type. + // + + busMaster = (ndisAdap->TransferMode == DMA_DATA_TRANSFER_MODE); + + MadgePrint1("NdisMSetAttributes called\n"); + MadgePrint2("busMaster = %d\n", (UINT) busMaster); + + NdisMSetAttributes( + ndisAdap->UsedInISR.MiniportHandle, + (NDIS_HANDLE) ndisAdap, + busMaster, + ndisAdap->NTCardBusType + ); + + MadgePrint1("NdisMSetAttributes returned\n"); + + // + // Register our IO port usage. + // + + MadgePrint1("NdisMRegisterIoPortRange called\n"); + + status = NdisMRegisterIoPortRange( + &ndisAdap->MappedIOLocation1, + ndisAdap->UsedInISR.MiniportHandle, + ndisAdap->IoLocation1 + ndisAdap->IoLocationBase, + ndisAdap->IORange1 + ); + + MadgePrint1("NdisMRegisterIoPortRange returned\n"); + MadgePrint2("MappedIORange1 = %x\n", (UINT) ndisAdap->MappedIOLocation1); + + if (status != NDIS_STATUS_SUCCESS) + { + MadgePrint2("NdisMRegisterIoPortRange failed rc = %x\n", status); + return status; + } + + ndisAdap->IORange1Initialized = TRUE; + + // + // If we are using an EISA card then we have a second range of IO + // locations. + // + + if (ndisAdap->IORange2 > 0) + { + MadgePrint1("NdisMRegisterIoPortRange called\n"); + + status = NdisMRegisterIoPortRange( + &ndisAdap->MappedIOLocation2, + ndisAdap->UsedInISR.MiniportHandle, + ndisAdap->IoLocation2 + ndisAdap->IoLocationBase, + ndisAdap->IORange2 + ); + + MadgePrint1("NdisMRegisterIoPortRange returned\n"); + MadgePrint2("MappedIORange2 = %x\n", (UINT) ndisAdap->MappedIOLocation2); + + if (status != NDIS_STATUS_SUCCESS) + { + MadgePrint2("NdisMRegisterIoPortRange failed rc = %x\n", status); + return status; + } + + ndisAdap->IORange2Initialized = TRUE; + } + + MadgePrint1("MadgeRegisterAdapter finished\n"); + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +| +| Function - FlagIsTrue +| +| Parameters - flag -> Pointer to a flag to find the value of. +| +| Purpose - Return the value of a flag. Can be called by a function +Ý that polls a flag to avoid the compiler optimising out +Ý the test of the flag. +| +| Returns - The value of the flag. +| +|--------------------------------------------------------------------------*/ + +STATIC BOOLEAN +FlagIsTrue(BOOLEAN * flag); + +#pragma FTK_INIT_FUNCTION(FlagIsTrue) + +STATIC BOOLEAN +FlagIsTrue(BOOLEAN * flag) +{ + MadgePrint1("FlagIsTrue\n"); + + return *flag; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeMapMmioMemory +| +| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure. +| +| Purpose - Attempt to map in our MMIO memory. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeMapMmioMemory(PMADGE_ADAPTER ndisAdap); + +#pragma FTK_INIT_FUNCTION(MadgeMapMmioMemory) + +STATIC NDIS_STATUS +MadgeMapMmioMemory(PMADGE_ADAPTER ndisAdap) +{ + NDIS_PHYSICAL_ADDRESS mmioPhysAddr = NDIS_PHYSICAL_ADDRESS_CONST(0, 0); + UINT status; + + NdisSetPhysicalAddressLow( + mmioPhysAddr, + ndisAdap->MmioRawAddress + ); + + status = NdisMMapIoSpace( + &ndisAdap->MmioVirtualAddress, + ndisAdap->UsedInISR.MiniportHandle, + mmioPhysAddr, + PCI_MMIO_SIZE + ); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_MEMORY_CONFLICT, + 2, + initAdapter, + MADGE_ERRMSG_MAPPING_PCI_MMIO + ); + } + else + { + ndisAdap->MmioMapped = TRUE; + } + + return status; +} + + +#ifndef LINK_FMPLUS + +/*--------------------------------------------------------------------------- +| +| Function - MadgeReadDownload +| +| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure. +Ý downloadFile -> Pointer to as handle for the download file. +| download -> Pointer to a holder for a pointer to the +Ý download image read into memory. +Ý +| Purpose - Read the download into memory. If the function returns +Ý success then must unmap and close *downloadFile. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeReadDownload( + PMADGE_ADAPTER ndisAdap, + NDIS_HANDLE * downloadFile, + void * * download + ); + +#pragma FTK_INIT_FUNCTION(MadgeReadDownload) + +STATIC NDIS_STATUS +MadgeReadDownload( + PMADGE_ADAPTER ndisAdap, + NDIS_HANDLE * downloadFile, + void * * download + ) +{ + NDIS_STATUS status; + NDIS_HANDLE imageFile; + UINT imageLength; + PVOID imagePtr; + NDIS_PHYSICAL_ADDRESS highestAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); + DOWNLOAD_FILE_HEADER * downHdrPtr; + UCHAR * chkPtr; + ULONG chkSum; + UINT i; + + // + // Open the FastMAC Plus image file. + // + + MadgePrint1("NdisOpenFile called\n"); + + NdisOpenFile( + &status, + &imageFile, + &imageLength, + &FmpImageFileName, + highestAddress + ); + + MadgePrint1("NdisOpenFile returned\n"); + + if (status != NDIS_STATUS_SUCCESS) + { + MadgePrint2("NdisOpenFile failed rc= %x\n", status); + + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR, + 2, + initAdapter, + MADGE_ERRMSG_OPEN_IMAGE_FILE + ); + + return NDIS_STATUS_RESOURCES; + } + + // + // Map in the FastMAC Plus image file. + // + + NdisMapFile(&status, &imagePtr, imageFile); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_OUT_OF_RESOURCES, + 2, + initAdapter, + MADGE_ERRMSG_MAP_IMAGE_FILE + ); + + NdisCloseFile(imageFile); + + return NDIS_STATUS_RESOURCES; + } + + // + // Make sure that the image file is valid by checking its checksum, + // version number and signature. + // + + downHdrPtr = (DOWNLOAD_FILE_HEADER *) imagePtr; + chkPtr = ((UCHAR *) imagePtr) + DOWNLOAD_CHECKSUM_SKIP; + chkSum = 0; + + for (i = DOWNLOAD_CHECKSUM_SKIP; i < imageLength; i++) + { + DOWNLOAD_CHECKSUM_BYTE(chkSum, *chkPtr); + chkPtr++; + } + + if (!IS_DOWNLOAD_OK(downHdrPtr, chkSum)) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_INVALID_DOWNLOAD_FILE_ERROR, + 2, + initAdapter, + MADGE_ERRMSG_BAD_IMAGE_FILE + ); + + NdisUnmapFile(imageFile); + NdisCloseFile(imageFile); + + return NDIS_STATUS_RESOURCES; + } + + *downloadFile = imageFile; + *download = imagePtr; + + return NDIS_STATUS_SUCCESS; +} + +#else + +#include "fmplus.c" + +#endif + +#ifdef _M_IX86 + +/*--------------------------------------------------------------------------- +| +| Function - MadgeArbitrateBufferMemory +| +| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure. +| +| Purpose - Determine if we can allocate all the shared memory +Ý we need for DMA buffer space and if we can't then +Ý reduce our requirements until we can or we reach +Ý our minimum requirements. If the buffer space cannot +Ý be aribtrated then the requirements are left as is and +Ý it is assumed that the FTK initialisation will fail +Ý and generate an out of memory error. +| +| Returns - Nothing. +| +|--------------------------------------------------------------------------*/ + +STATIC VOID +MadgeArbitrateBufferMemory(PMADGE_ADAPTER ndisAdap); + +#pragma FTK_INIT_FUNCTION(MadgeArbitrateBufferMemory) + +STATIC VOID +MadgeArbitrateBufferMemory(PMADGE_ADAPTER ndisAdap) +{ + VOID * testVirt; + VOID * rxVirt; + VOID * txVirt; + NDIS_PHYSICAL_ADDRESS testPhys; + NDIS_PHYSICAL_ADDRESS rxPhys; + NDIS_PHYSICAL_ADDRESS txPhys; + ULONG rxBufferSize; + ULONG txBufferSize; + UINT maxFrameSize; + UINT rxSlots; + UINT txSlots; + BOOLEAN succeeded; + BOOLEAN failed; + BOOLEAN arbitrated; + + // + // There doesn't seem to be a problem allocating none + // shared memory so if we aren't in DMA mode then + // don't do anything. + // + + if (ndisAdap->TransferMode != DMA_DATA_TRANSFER_MODE) + { + return; + } + + // + // The first bit of shared memory we must have is for the DMA + // test buffers. + // + + testVirt = NULL; + + NdisMAllocateSharedMemory( + ndisAdap->UsedInISR.MiniportHandle, + SCB_TEST_PATTERN_LENGTH + SSB_TEST_PATTERN_LENGTH, + FALSE, + &testVirt, + &testPhys + ); + + // + // If we can't allocate the test buffer then just give up. + // + + if (testVirt == NULL) + { + return; + } + + // + // We've got the test buffer memory so now arbitrate the + // RX/TX buffers. Note: the buffer allocation MUST MATCH + // THAT IN FTK_USER.C. + // + + maxFrameSize = ndisAdap->MaxFrameSize; + rxSlots = ndisAdap->FastmacRxSlots; + txSlots = ndisAdap->FastmacTxSlots; + + failed = FALSE; + succeeded = FALSE; + arbitrated = FALSE; + + while (!failed && !succeeded) + { + rxVirt = NULL; + txVirt = NULL; + + // + // Try to allocate the receive buffer. + // + + rxBufferSize = ((maxFrameSize + 4 + 32 + 3) & ~3) * rxSlots; + + NdisMAllocateSharedMemory( + ndisAdap->UsedInISR.MiniportHandle, + rxBufferSize, + FALSE, + &rxVirt, + &rxPhys + ); + + // + // If we allocated the RX buffer space then try to allocate + // the TX buffer space. + // + + if (rxVirt != NULL) + { + txBufferSize = ((maxFrameSize + 3) & ~3) * txSlots; + + NdisMAllocateSharedMemory( + ndisAdap->UsedInISR.MiniportHandle, + txBufferSize, + FALSE, + &txVirt, + &txPhys + ); + } + + // + // Free any buffers we managed to allocate. + // + + if (rxVirt != NULL) + { + NdisMFreeSharedMemory( + ndisAdap->UsedInISR.MiniportHandle, + rxBufferSize, + FALSE, + rxVirt, + rxPhys + ); + } + + if (txVirt != NULL) + { + NdisMFreeSharedMemory( + ndisAdap->UsedInISR.MiniportHandle, + txBufferSize, + FALSE, + txVirt, + txPhys + ); + } + + // + // If we managed to allocate both buffers then we have + // succeeded. + // + + if (rxVirt != NULL && txVirt != NULL) + { + succeeded = TRUE; + } + + // + // Otherwise we must reduce our memory requirements. + // + + else + { + arbitrated = TRUE; + + // + // First try reducing the number of transmit slots. + // + + if (txSlots > FMPLUS_MIN_TX_SLOTS) + { + txSlots--; + } + + // + // Next try reducing the number of receive slots. + // + + else if (rxSlots > FMPLUS_MIN_RX_SLOTS) + { + rxSlots--; + } + + // + // Finally try reducing the frame size. 1800 bytes has + // empirically shown to be the minimum value required + // for the DOMAIN server startup to work at NT installation. + // + + else if (maxFrameSize > 1800) + { + maxFrameSize -= 512; + + if (maxFrameSize < 1800) + { + maxFrameSize = 1800; + } + } + + // + // If we can't reduce our buffer requirements any further + // then fail. + // + + else + { + failed = TRUE; + } + } + } + + // + // Free the memory for the DMA test buffer. + // + + NdisMFreeSharedMemory( + ndisAdap->UsedInISR.MiniportHandle, + SCB_TEST_PATTERN_LENGTH + SSB_TEST_PATTERN_LENGTH, + FALSE, + testVirt, + testPhys + ); + + // + // If we have succeded then we must update the requirements in + // adapter structure and if we have changed any values we must + // write a message to the event log. + // + + if (succeeded && arbitrated) + { + ndisAdap->MaxFrameSize = maxFrameSize; + ndisAdap->FastmacRxSlots = rxSlots; + ndisAdap->FastmacTxSlots = txSlots; + + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, + 1, + initAdapter + ); + } +} + +#endif + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeInitAdapter +| +| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure. +| +| Purpose - Initialise an adapter. +| +| Returns - An NDIS3 status code. +| +|--------------------------------------------------------------------------*/ + +STATIC NDIS_STATUS +MadgeInitAdapter(PMADGE_ADAPTER ndisAdap); + +#pragma FTK_INIT_FUNCTION(MadgeInitAdapter) + +STATIC NDIS_STATUS +MadgeInitAdapter(PMADGE_ADAPTER ndisAdap) +{ + WORD ftkStatus; + NDIS_STATUS status; + PREPARE_ARGS prepare; + START_ARGS start; + +#ifndef LINK_FMPLUS + + NDIS_HANDLE imageFile; + PVOID imagePtr; + +#endif + + MadgePrint1("MadgeInitAdapter started\n"); + + // + // If we are doing MMIO then we need to map in the MMIO memory. + // If we fail to map in the memory then default ti PIO. + // + + if (ndisAdap->TransferMode == MMIO_DATA_TRANSFER_MODE) + { + if (MadgeMapMmioMemory(ndisAdap) != NDIS_STATUS_SUCCESS) + { + ndisAdap->TransferMode = PIO_DATA_TRANSFER_MODE; + } + } + +#ifdef _M_IX86 + + // + // Arbitrate "DMA" buffer memory. + // + + MadgeArbitrateBufferMemory(ndisAdap); + +#endif + + // + // Set up the arguments to pass to driver_prepare_adapter. + // + + MADGE_ZERO_MEMORY(&prepare, sizeof(PREPARE_ARGS)); + + prepare.user_information = (void *) ndisAdap; + prepare.number_of_rx_slots = (WORD) ndisAdap->FastmacRxSlots; + prepare.number_of_tx_slots = (WORD) ndisAdap->FastmacTxSlots; + prepare.max_frame_size = (WORD) ndisAdap->MaxFrameSize; + + // + // Try to prepare the adapter for use. + // + + // + // Mark the fact that the FTK has been called, so that we know if we + // have to call driver_remove_adapter() when doing clean up. + // + + ndisAdap->FtkInitialized = TRUE; + + MadgePrint1("driver_prepare_adapter called\n"); + + if (!driver_prepare_adapter(&prepare, &(ndisAdap->FtkAdapterHandle))) + { + return NDIS_STATUS_FAILURE; + } + + MadgePrint1("driver_prepare_adapter returned\n"); + MadgePrint2("adapter_handle = %d\n", ndisAdap->FtkAdapterHandle); + +#ifndef LINK_FMPLUS + + // + // Read in the download file. + // + + status = MadgeReadDownload(ndisAdap, &imageFile, &imagePtr); + + if (status != NDIS_STATUS_SUCCESS) + { + return status; + } + +#endif + + // + // Set up the arguments to driver_start_adapter. + // + + MADGE_ZERO_MEMORY(&start, sizeof(START_ARGS)); + + start.adapter_card_bus_type = (UINT) ndisAdap->FTKCardBusType; + + start.io_location = (WORD) ndisAdap->IoLocation1; + start.transfer_mode = (UINT) ndisAdap->TransferMode; + start.dma_channel = (WORD) ndisAdap->DmaChannel; + start.interrupt_number = (WORD) ndisAdap->UsedInISR.InterruptNumber; + start.set_dma_channel = TRUE; + start.set_interrupt_number = TRUE; + start.mmio_base_address = (DWORD) ndisAdap->MmioVirtualAddress; + start.pci_handle = (DWORD) ndisAdap->SlotNumber; + + if (ndisAdap->Force16) + { + start.set_ring_speed = 16; + } + else if (ndisAdap->Force4) + { + start.set_ring_speed = 4; + } + + start.opening_node_address = ndisAdap->OpeningNodeAddress; + start.auto_open_option = TRUE; + + if (ndisAdap->ForceOpen) + { + ndisAdap->OpenOptions |= OPEN_OPT_FORCE_OPEN; + } + + start.open_options = (WORD) ndisAdap->OpenOptions; + + start.rx_tx_buffer_size = (WORD) ndisAdap->CardBufferSize; + +#ifndef LINK_FMPLUS + + start.code = (DOWNLOAD_IMAGE *) + (((UCHAR *) imagePtr) + sizeof(DOWNLOAD_FILE_HEADER)); + +#else + + start.code = (DOWNLOAD_IMAGE *) fmplus_image; + +#endif + + MadgePrint1("driver_start_adapter called\n"); + + ftkStatus = driver_start_adapter( + ndisAdap->FtkAdapterHandle, + &start, + &ndisAdap->PermanentNodeAddress + ); + + MadgePrint1("driver_start_adapter returned\n"); + MadgePrint2("MAC buffer size = %d\n", + adapter_record[ndisAdap->FtkAdapterHandle + ]->init_block->smart_parms.rx_tx_buffer_size + ); + +#ifndef LINK_FMPLUS + + // + // No matter what we have finished with the FastMAC Plus image file. + // + + NdisUnmapFile(imageFile); + NdisCloseFile(imageFile); + +#endif + + if (!ftkStatus) + { + MadgePrint1("driver_start_adapter failed\n"); + + // + // Were it not for the fact that we are going to clean up and fail + // as soon as we return, we ought to set the CurrentRingState to + // NdisRingStateOpenFailure here if AutoOpen was selected. + // + + return NDIS_STATUS_FAILURE; + } + + // + // Warn the user if FastMAC Plus had to reduce the frame size. + // + + if (ndisAdap->MaxFrameSize > start.max_frame_size) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, + 3, + initAdapter, + MADGE_ERRMSG_REDUCE_MAX_FSIZE, + ndisAdap->MaxFrameSize + ); + } + + ndisAdap->MaxFrameSize = start.max_frame_size; + + // + // If we did not specify a locally administered address then copy the + // permanent one across to the local one. + // + + if (ndisAdap->OpeningNodeAddress.byte[0] == 0) + { + MADGE_MOVE_MEMORY( + &ndisAdap->OpeningNodeAddress, + &ndisAdap->PermanentNodeAddress, + sizeof(ndisAdap->PermanentNodeAddress) + ); + } + + // + // Note that the adapter is open. + // + + ndisAdap->CurrentRingState = NdisRingStateOpened; + ndisAdap->LastOpenStatus = start.open_status; + + // + // Nasty hack. If we have a PciT atapter with broken dma and we are + // running on a multiprocessor we need set the multiprocessor safe + // PIO flag to make sure that we don't do DIO whilst our interrupt + // hander is running. Unfortunately we don't know if we have + // broken DMA until after we've started the adapter. + // + + if (ndisAdap->Multiprocessor && + adapter_record[ndisAdap->FtkAdapterHandle]->mc32_config == + TRN_PCIT_BROKEN_DMA) + { + MadgePrint1("Using MP sfae PIO because of PCIT DMA.\n"); + ndisAdap->UseMPSafePIO = TRUE; + } + + // + // Note that we MUST start the receive process, even if we are NOT using + // auto-open, because FastmacPlus ignores SRBs (including OPEN SRBs) if + // this has not been done. + // + + driver_start_receive_process(ndisAdap->FtkAdapterHandle); + + // + // We now need to set the product instance ID. The product instance + // ID will be set to the contents of ftk_product_inst_id[] if we + // issue an open SRB, but since Miniports always auto-open we + // need to generate a set product instance SRB to set it. + // + + // + // Note that we are generating a private SRB (not to be treated + // as a normal NDIS request), generate the SRB and then wait + // for it to finish. + // + + ndisAdap->PrivateSrbInProgress = TRUE; + + MadgePrint1("Calling driver_set_product_instance_id\n"); + + driver_set_product_instance_id( + ndisAdap->FtkAdapterHandle, + NT_PRODUCT_INSTANCE_ID + ); + + MadgePrint1("Waiting for SRB to complete\n"); + + while (FlagIsTrue(&ndisAdap->PrivateSrbInProgress)) + NdisMSleep(100); + + MadgePrint1("MadgeInitAdapter finished\n"); + + return NDIS_STATUS_SUCCESS; +} + + +/*--------------------------------------------------------------------------- +| +| Function - MadgeCleanupAdapter +| +| Parameters - ndisAdap -> Pointer to an NDIS3 level adapter structure. +| +| Purpose - Deallocate the resources associated with an adapter. +| +| Returns - Nothing. +| +|--------------------------------------------------------------------------*/ + +STATIC VOID +MadgeCleanupAdapter(PMADGE_ADAPTER ndisAdap) +{ + BOOLEAN timerOutstanding; + + MadgePrint1("MadgeCleanupAdapter 1\n"); + + if (ndisAdap->TimerInitialized) + { + NdisMCancelTimer(&ndisAdap->WakeUpTimer, &timerOutstanding); + NdisMCancelTimer(&ndisAdap->CompletionTimer, &timerOutstanding); + ndisAdap->TimerInitialized = FALSE; + } + + MadgePrint1("MadgeCleanupAdapter 2\n"); + + if (ndisAdap->FtkInitialized) + { + rxtx_await_empty_tx_slots(ndisAdap->FtkAdapterHandle); + driver_remove_adapter(ndisAdap->FtkAdapterHandle); + ndisAdap->FtkInitialized = FALSE; + } + + if (ndisAdap->MapRegistersAllocated > 0) + { + NdisMFreeMapRegisters(ndisAdap->UsedInISR.MiniportHandle); + ndisAdap->MapRegistersAllocated = 0; + } + + MadgePrint1("MadgeCleanupAdapter 3\n"); + + if (ndisAdap->MmioMapped) + { + NdisMUnmapIoSpace( + ndisAdap->UsedInISR.MiniportHandle, + ndisAdap->MmioVirtualAddress, + PCI_MMIO_SIZE + ); + ndisAdap->MmioMapped = FALSE; + } + + MadgePrint1("MadgeCleanupAdapter 4\n"); + + if (ndisAdap->IORange1Initialized) + { + NdisMDeregisterIoPortRange( + ndisAdap->UsedInISR.MiniportHandle, + ndisAdap->IoLocation1 + ndisAdap->IoLocationBase, + ndisAdap->IORange1, + ndisAdap->MappedIOLocation1 + ); + ndisAdap->IORange1Initialized = FALSE; + } + + MadgePrint1("MadgeCleanupAdapter 5\n"); + + if (ndisAdap->IORange2Initialized) + { + NdisMDeregisterIoPortRange( + ndisAdap->UsedInISR.MiniportHandle, + ndisAdap->IoLocation2 + ndisAdap->IoLocationBase, + ndisAdap->IORange2, + ndisAdap->MappedIOLocation2 + ); + ndisAdap->IORange2Initialized = FALSE; + } + + MadgePrint1("MadgeCleanupAdapter 6\n"); + + if (ndisAdap->ShutdownHandlerRegistered) + { + NdisMDeregisterAdapterShutdownHandler( + ndisAdap->UsedInISR.MiniportHandle + ); + ndisAdap->ShutdownHandlerRegistered = FALSE; + + MadgePrint1("De-registered shutdown handler\n"); + } + + MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER)); +} + + +/*************************************************************************** +* +* Function - MadgeHalt +* +* Parameters - adapterContext -> Pointer to our NDIS level adapter +* structure. +* +* Purpose - Process a call from the NDIS3 wrapper to remove an +* adapter instance. +* +* Returns - Nothing. +* +****************************************************************************/ + +VOID +MadgeHalt(NDIS_HANDLE adapterContext) +{ + PMADGE_ADAPTER ndisAdap; + + MadgePrint1("MadgeHalt started\n"); + + ndisAdap = PMADGE_ADAPTER_FROM_CONTEXT(adapterContext); + + // + // The NDIS interface guarantees that all bindings are closed, i.e. all + // MadgeCloseAdapter calls have completed successfully. + // + + ndisAdap->HardwareStatus = NdisHardwareStatusClosing; + + MadgeCleanupAdapter(ndisAdap); + + MadgePrint1("MadgeHalt finished\n"); +} + + +/**************************************************************************** +* +* Function - MadgeTxCompletion +* +* Parameters - systemSpecific1 -> Unused. +* context -> Actually a pointer to our NDIS3 level +* adapter structure. +* systemSpecific2 -> Unused. +* systemSpecific3 -> Unused. +* +* Purpose - Call our TX competion routine as a result of a timer. +* +* Returns - Nothing. +* +****************************************************************************/ + +VOID +MadgeTxCompletion( + PVOID systemSpecific1, + PVOID context, + PVOID systemSpecific2, + PVOID systemSpecific3 + ) +{ + PMADGE_ADAPTER ndisAdap = (PMADGE_ADAPTER) context; + + // + // Call the TX completion function. + // + + rxtx_irq_tx_completion_check( + ndisAdap->FtkAdapterHandle, + adapter_record[ndisAdap->FtkAdapterHandle] + ); +} + + +/*************************************************************************** +* +* Function - MadgeInitialise +* +* Parameters - openErrorStatus -> Pointer to a holder for an open +* error status. +* selectedMediumIndex -> Pointer to a holder for the index +* of the medium selected. +* mediumArray -> Array of media types. +* mediumArraySize -> Size of the media array. +* miniportHandle -> Miniport adapter handle. +* wrapperConfigContext -> Handle used when querying the +* registry. +* +* Purpose - Carry out adapter instance initialisation. +* +* Returns - An NDIS3 status code. +* +***************************************************************************/ + +NDIS_STATUS +MadgeInitialize( + PNDIS_STATUS openErrorStatus, + PUINT selectedMediumIndex, + PNDIS_MEDIUM mediumArray, + UINT mediumArraySize, + NDIS_HANDLE miniportHandle, + NDIS_HANDLE wrapperConfigContext + ); + +#pragma FTK_INIT_FUNCTION(MadgeInitialize) + +NDIS_STATUS +MadgeInitialize( + PNDIS_STATUS openErrorStatus, + PUINT selectedMediumIndex, + PNDIS_MEDIUM mediumArray, + UINT mediumArraySize, + NDIS_HANDLE miniportHandle, + NDIS_HANDLE wrapperConfigContext + ) +{ + NDIS_STATUS status; + PMADGE_ADAPTER ndisAdap; + NDIS_HANDLE configHandle; + UINT i; + + MadgePrint1("MadgeInitialize started\n"); + + // + // --------------------------------------------------------------------- + // Check that the upper protocol knows about token ring and if + // it does set the index. + // + + for (i = 0; i < mediumArraySize; i++) + { + if (mediumArray[i] == NdisMedium802_5) + { + break; + } + } + + if (i == mediumArraySize) + { + return NDIS_STATUS_UNSUPPORTED_MEDIA; + } + + *selectedMediumIndex = i; + + // + // --------------------------------------------------------------------- + // Doing basic sanity checks and allocating some memory for our + // per-adapter structure. + // + + if (wrapperConfigContext == NULL) + { + // + // No registry config. information found by NDIS library for us. + // We cannot proceed without it. + // + + return NDIS_STATUS_FAILURE; + } + + // + // Allocate memory for the adapter structure. + // + + MADGE_ALLOC_MEMORY(&status, &ndisAdap, sizeof(MADGE_ADAPTER)); + + if (status != NDIS_STATUS_SUCCESS) + { + // + // Failed to allocate adapter structure. Can't go on without it. + // + + return status; + } + + MADGE_ZERO_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER)); + + MadgePrint2("ndisAdap = %x\n", ndisAdap); + + // + // We need the mini port handle early on. + // + + ndisAdap->UsedInISR.MiniportHandle = miniportHandle; + + // + // --------------------------------------------------------------------- + // Read the registry: open the registry, read the contents, and close it + // again. This will handle adapter parameters and LAAs, and also working + // out various values to do with interrupt modes. + // + + MadgePrint1("NdisOpenConfiguration called\n"); + + NdisOpenConfiguration( + &status, + &configHandle, + wrapperConfigContext + ); + + MadgePrint1("NdisOpenConfiguration returned\n"); + + if (status != NDIS_STATUS_SUCCESS) + { + MadgePrint2("NdisOpenConfiguration failed rc=%x\n", status); + MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER)); + return status; + } + + status = MadgeReadRegistry( + wrapperConfigContext, + configHandle, + ndisAdap + ); + + NdisCloseConfiguration(configHandle); + + // + // We have gleaned all we can from the registry - was it all OK? + // + + if (status != NDIS_STATUS_SUCCESS) + { + // + // If Status is not success, it will be either NDIS_STATUS_FAILURE + // if a parameter was out of range, or it will be the error code + // returned by NdisReadConfiguration(). + // + + MadgePrint2("MadgeReadRegistry failed rc = %x\n", status); + MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER)); + return status; + } + + // + // --------------------------------------------------------------------- + // Having read the registry, we can initialize the rest of the fields in + // the adapter structure. + // + + #define I_DATA ActualValue.ParameterData.IntegerData + + // + // Copy the values from the Parameter table into the per-adapter struct. + // This is necessary because the Parameter table will be used again for + // the next card that is added. + // + // Note that we handle the rx/tx slots configuration in a special way. + // The value of rx/tx slots is set by indexing into a table with the + // single paramter RxTxSlots, unless RxSlots or TxSlots have been set in + // which case these values override the values derived from RxTxSlots. + // + + switch (MadgeParmTable.RxTxSlots.I_DATA) + { + case 0: + ndisAdap->FastmacTxSlots = 2; + ndisAdap->FastmacRxSlots = 2; + break; + case 1: + ndisAdap->FastmacTxSlots = 3; + ndisAdap->FastmacRxSlots = 3; + break; + case 2: + ndisAdap->FastmacTxSlots = 4; + ndisAdap->FastmacRxSlots = 4; + break; + case 3: + ndisAdap->FastmacTxSlots = 6; + ndisAdap->FastmacRxSlots = 6; + break; + case 4: + ndisAdap->FastmacTxSlots = 8; + ndisAdap->FastmacRxSlots = 8; + break; + case 5: + ndisAdap->FastmacTxSlots = 10; + ndisAdap->FastmacRxSlots = 10; + break; + default: + ndisAdap->FastmacTxSlots = 4; + ndisAdap->FastmacRxSlots = 4; + break; + } + + if (MadgeParmTable.TxSlots.I_DATA != 0) + { + ndisAdap->FastmacTxSlots = MadgeParmTable.TxSlots.I_DATA; + } + + if (MadgeParmTable.RxSlots.I_DATA != 0) + { + ndisAdap->FastmacRxSlots = MadgeParmTable.RxSlots.I_DATA; + } + + MadgePrint3("TX slots = %d RX slots = %d\n", + ndisAdap->FastmacTxSlots, + ndisAdap->FastmacRxSlots + ); + + ndisAdap->MaxFrameSize = MadgeParmTable.MaxFrameSize.I_DATA; + ndisAdap->CardBufferSize = MadgeParmTable.CardBufferSize.I_DATA; + ndisAdap->PromiscuousMode = (MadgeParmTable.PromiscuousMode.I_DATA == 1); + ndisAdap->AlternateIo = (MadgeParmTable.AlternateIo.I_DATA == 1); + ndisAdap->TestAndXIDEnabled = (MadgeParmTable.TestAndXIDEnabled.I_DATA == 1); + ndisAdap->ForceOpen = (MadgeParmTable.ForceOpen.I_DATA == 1); + ndisAdap->Force4 = (MadgeParmTable.Force4.I_DATA == 1); + ndisAdap->Force16 = (MadgeParmTable.Force16.I_DATA == 1); + ndisAdap->Multiprocessor = (NdisSystemProcessorCount() > 1); + + if (ndisAdap->TransferMode != DMA_DATA_TRANSFER_MODE && + ndisAdap->Multiprocessor) + { + ndisAdap->UseMPSafePIO = TRUE; + } + + // + // If the RingSpeed parameter is present then this overrides the + // Force4 and Force16 parameters. RingSpeed == 0 means either not + // present or don't care. RingSpeed == 1 means 4MBits. RingSpeed == 2 + // means 16MBits. + // + + switch (MadgeParmTable.RingSpeed.I_DATA) + { + case 1: + ndisAdap->Force4 = TRUE; + ndisAdap->Force16 = FALSE; + break; + + case 2: + ndisAdap->Force4 = FALSE; + ndisAdap->Force16 = TRUE; + + default: + break; + } + + // + // Initialize the rest of the Adapter structure. + // + + ndisAdap->UsedInISR.MiniportHandle = miniportHandle; + ndisAdap->CurrentLookahead = ndisAdap->MaxFrameSize - FRAME_HEADER_SIZE; + ndisAdap->CurrentRingState = NdisRingStateClosed; + ndisAdap->HardwareStatus = NdisHardwareStatusNotReady; + + // + // These next few lines are strictly unnecessary because their fields in + // the structure are already zero from our earlier ZERO_MEMORY() call. + // + + ndisAdap->UsedInISR.SrbRequestCompleted = FALSE; + ndisAdap->UsedInISR.SrbRequestStatus = FALSE; + ndisAdap->DprInProgress = FALSE; + + // + // One nasty piece of hackery for Smart16 cards, whereby we must add to + // the IoLocation 0x1000 if the Alternate switch is true. + // + + if (ndisAdap->NTCardBusType == NdisInterfaceIsa && + ndisAdap->IoLocation1 > 0x3a20 && + ndisAdap->AlternateIo) + { + ndisAdap->IoLocation1 += 0x1000; + } + + // + // We need to know where the end of the first range of IO locations + // we use is. + // + + ndisAdap->IORange1End = ndisAdap->IoLocation1 + ndisAdap->IORange1 - 1; + + // + // --------------------------------------------------------------------- + // We can now try to register the adapter. This involves filling in the + // AdapterInformation structure and calling NdisRegisterAdapter(). See + // the function MadgeRegisterAdapter for details. + // + + if ((status = MadgeRegisterAdapter( + ndisAdap, + wrapperConfigContext + )) != NDIS_STATUS_SUCCESS) + { + // + // Either we failed to allocate memory for the adapter information + // structure, or the NdisRegisterAdapter() call failed. + // + + MadgePrint2("MadgeRegisterAdapter failed rc = %x\n", status); + MADGE_FREE_MEMORY(ndisAdap, sizeof(MADGE_ADAPTER)); + return status; + } + + // + // --------------------------------------------------------------------- + // We are now into the last stages of initialization. This is going to + // cause to be allocated several more resources (in the form of kernel + // objects, filter databases, FTK structures, interrupt channels, ...) + // so from here on we have to be a lot more careful about cleaning up. + // + + ndisAdap->HardwareStatus = NdisHardwareStatusInitializing; + + // + // Call the FTK to download the MAC code to the card and initialize it. + // + + status = MadgeInitAdapter(ndisAdap); + + if (status != NDIS_STATUS_SUCCESS) + { + // + // If it was an FTK generated error then log an appropriate event. + // + + if (status == NDIS_STATUS_FAILURE) + { + BYTE error_type; + BYTE error_value; + char * error_message; + + driver_explain_error( + ndisAdap->FtkAdapterHandle, + &error_type, + &error_value, + &error_message + ); + + MadgePrint3("FTK error %02x, %02x\n", error_type, error_value); + + // + // To keep Microsoft happy we will generate special error + // messages for some of the more common error conditions. + // + + // + // An open error is probably because the cable isn't plugged in. + // + + if (error_type == ERROR_TYPE_OPEN || + error_type == ERROR_TYPE_AUTO_OPEN) + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_INVALID_VALUE_FROM_ADAPTER, + 4, + madgeInitialize, + MADGE_ERRMSG_INITIAL_INIT, + (ULONG) error_type, + (ULONG) error_value + ); + } + else + { + NdisWriteErrorLogEntry( + ndisAdap->UsedInISR.MiniportHandle, + NDIS_ERROR_CODE_HARDWARE_FAILURE, + 4, + madgeInitialize, + MADGE_ERRMSG_INITIAL_INIT, + (ULONG) error_type, + (ULONG) error_value + ); + } + } + + // + // In any case, tidy up the adapter and abort. + // + + MadgeCleanupAdapter(ndisAdap); + return status; + } + + ndisAdap->HardwareStatus = NdisHardwareStatusReady; + + // + // Set up the ring status monitor function. + // + + NdisMInitializeTimer( + &ndisAdap->WakeUpTimer, + ndisAdap->UsedInISR.MiniportHandle, + (PVOID) MadgeGetAdapterStatus, + ndisAdap + ); + + NdisMSetTimer(&ndisAdap->WakeUpTimer, EVERY_2_SECONDS); + + NdisMInitializeTimer( + &ndisAdap->CompletionTimer, + ndisAdap->UsedInISR.MiniportHandle, + (PVOID) MadgeTxCompletion, + ndisAdap + ); + + ndisAdap->TimerInitialized = TRUE; + + MadgePrint1("MadgeInitialize finished\n"); + + return NDIS_STATUS_SUCCESS; +} + + +/*************************************************************************** +* +* Function - DriverEntry +* +* Parameters - driverObject -> Pointer to a driver object. +* registryPath -> Path to our configuration information in +* the registry. +* +* Purpose - Carry out the driver (as opposed to adapter instance) +* initialisation. This is the main entry point. +* +* Returns - An NDIS3 status code. +* +***************************************************************************/ + +NDIS_STATUS +DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath); + +#pragma FTK_INIT_FUNCTION(DriverEntry) + +NDIS_STATUS +DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING registryPath) +{ + NDIS_HANDLE ndisWrapperHandle; + NDIS_STATUS status; + NDIS_MINIPORT_CHARACTERISTICS madgeChar; + UINT i; + + MadgePrint1("DriverEntry starting\n"); + + // + // We are obliged first of all to initialize the NDIS wrapper. + // + + MadgePrint1("NdisMInitializeWrapper called\n"); + + NdisMInitializeWrapper( + &ndisWrapperHandle, + driverObject, + registryPath, + NULL + ); + + MadgePrint1("NdisMInitializeWrapper returned\n"); + + // + // Decode any hidden strings here, for use later in MacAddAdapter. This + // only applies to PromiscuousMode support at the moment. + // + + for (i = 0; + i < MadgeParmTable.PromiscuousMode.Keyword.Length / + sizeof(*(MadgeParmTable.PromiscuousMode.Keyword.Buffer)); + i++) + { + MadgeParmTable.PromiscuousMode.Keyword.Buffer[i] -= HIDDEN_OFFS; + } + + // + // Fill in the characteristics table - this lists all the driver entry + // points that may be called by the NDIS wrapper. + // + + madgeChar.MajorNdisVersion = MADGE_NDIS_MAJOR_VERSION; + madgeChar.MinorNdisVersion = MADGE_NDIS_MINOR_VERSION; + madgeChar.CheckForHangHandler = MadgeCheckForHang; + madgeChar.DisableInterruptHandler = MadgeDisableInterrupts; + madgeChar.EnableInterruptHandler = MadgeEnableInterrupts; + madgeChar.HaltHandler = MadgeHalt; + madgeChar.HandleInterruptHandler = MadgeHandleInterrupt; + madgeChar.InitializeHandler = MadgeInitialize; + madgeChar.ISRHandler = MadgeISR; + madgeChar.QueryInformationHandler = MadgeQueryInformation; + madgeChar.ReconfigureHandler = NULL; + madgeChar.ResetHandler = MadgeReset; + madgeChar.SendHandler = MadgeSend; + madgeChar.SetInformationHandler = MadgeSetInformation; + madgeChar.TransferDataHandler = MadgeTransferData; + + // + // Register the miniport driver with NDIS library. + // + + MadgePrint1("NdisMRegisterMiniport called\n"); + + status = NdisMRegisterMiniport( + ndisWrapperHandle, + &madgeChar, + sizeof(madgeChar) + ); + + MadgePrint1("NdisMRegisterMiniport returned\n"); + + if (status != NDIS_STATUS_SUCCESS) + { + MadgePrint2("NdisMRegisterMiniport failed rc=%x\n", status); + NdisTerminateWrapper(ndisWrapperHandle, NULL); + return NDIS_STATUS_FAILURE; + } + + MadgePrint1("DriverEntry finished\n"); + + return NDIS_STATUS_SUCCESS; +} + + +/******** End of MADGE.C ***************************************************/ + -- cgit v1.2.3