File:  [WindowsNT SDKs] / ntddk / src / network / ibmtok / ibmtok.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/*++

Copyright (c) 1990  Microsoft Corporation

Module Name:

    ibmtok.c

Abstract:

    This is the main file for the IBM Token-Ring 16/4 Adapter.
    This driver conforms to the NDIS 3.0 interface.

    The overall structure and much of the code is taken from
    the Lance NDIS driver by Tony Ercolano.

Author:

    Anthony V. Ercolano (Tonye) 20-Jul-1990
    Adam Barr (adamba) 15-Feb-1990

Environment:

    Kernel Mode - Or whatever is the equivalent.

Revision History:

    Sean Selitrennikoff -- 9/15/91:
      Added code to handle Microchannel with PC I/O bus handling.
      Fixed bugs.
    Sean Selitrennikoff -- 10/15/91:
      Converted to Ndis 3.0 spec.
    George Joy -- 12/1/91
      Changed for compilation under DOS as well as NT
    Sean Selitrennikoff -- 1/8/92:
      Added error logging

--*/

#pragma optimize("",off)

#include <ndis.h>


#include <tfilter.h>
#include <tokhrd.h>
#include <toksft.h>


#if LOG

//
// Place in the circular buffer.
//
extern UCHAR IbmtokLogPlace;

//
// Circular buffer for storing log information.
//
extern UCHAR IbmtokLog[];

#define IF_LOG(A) {IbmtokLog[IbmtokLogPlace++] = (A); IbmtokLog[IbmtokLogPlace+2] = '.';}

#else

#define IF_LOG(A)

#endif

//
// This constant is used for places where NdisAllocateMemory
// needs to be called and the HighestAcceptableAddress does
// not matter.
//

const NDIS_PHYSICAL_ADDRESS HighestAcceptableMax =
    NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);


//
// If you add to this, make sure to add the
// a case in IbmtokFillInGlobalData() and in
// IbmtokQueryGlobalStatistics()
//
static const UINT IbmtokGlobalSupportedOids[] = {
    OID_GEN_SUPPORTED_LIST,
    OID_GEN_HARDWARE_STATUS,
    OID_GEN_MEDIA_SUPPORTED,
    OID_GEN_MEDIA_IN_USE,
    OID_GEN_MAXIMUM_LOOKAHEAD,
    OID_GEN_MAXIMUM_FRAME_SIZE,
    OID_GEN_MAXIMUM_TOTAL_SIZE,
    OID_GEN_MAC_OPTIONS,
    OID_GEN_PROTOCOL_OPTIONS,
    OID_GEN_LINK_SPEED,
    OID_GEN_TRANSMIT_BUFFER_SPACE,
    OID_GEN_RECEIVE_BUFFER_SPACE,
    OID_GEN_TRANSMIT_BLOCK_SIZE,
    OID_GEN_RECEIVE_BLOCK_SIZE,
    OID_GEN_VENDOR_ID,
    OID_GEN_VENDOR_DESCRIPTION,
    OID_GEN_DRIVER_VERSION,
    OID_GEN_CURRENT_PACKET_FILTER,
    OID_GEN_CURRENT_LOOKAHEAD,
    OID_GEN_XMIT_OK,
    OID_GEN_RCV_OK,
    OID_GEN_XMIT_ERROR,
    OID_GEN_RCV_ERROR,
    OID_GEN_RCV_NO_BUFFER,
    OID_802_5_PERMANENT_ADDRESS,
    OID_802_5_CURRENT_ADDRESS,
    OID_802_5_CURRENT_FUNCTIONAL,
    OID_802_5_CURRENT_GROUP,
    OID_802_5_LAST_OPEN_STATUS,
    OID_802_5_CURRENT_RING_STATUS,
    OID_802_5_CURRENT_RING_STATE,
    OID_802_5_LINE_ERRORS,
    OID_802_5_LOST_FRAMES
    };

//
// If you add to this, make sure to add the
// a case in IbmtokQueryGlobalStatistics() and in
// IbmtokQueryProtocolInformation()
//
static const UINT IbmtokProtocolSupportedOids[] = {
    OID_GEN_SUPPORTED_LIST,
    OID_GEN_HARDWARE_STATUS,
    OID_GEN_MEDIA_SUPPORTED,
    OID_GEN_MEDIA_IN_USE,
    OID_GEN_MAXIMUM_LOOKAHEAD,
    OID_GEN_MAXIMUM_FRAME_SIZE,
    OID_GEN_MAXIMUM_TOTAL_SIZE,
    OID_GEN_MAC_OPTIONS,
    OID_GEN_PROTOCOL_OPTIONS,
    OID_GEN_LINK_SPEED,
    OID_GEN_TRANSMIT_BUFFER_SPACE,
    OID_GEN_RECEIVE_BUFFER_SPACE,
    OID_GEN_TRANSMIT_BLOCK_SIZE,
    OID_GEN_RECEIVE_BLOCK_SIZE,
    OID_GEN_VENDOR_ID,
    OID_GEN_VENDOR_DESCRIPTION,
    OID_GEN_DRIVER_VERSION,
    OID_GEN_CURRENT_PACKET_FILTER,
    OID_GEN_CURRENT_LOOKAHEAD,
    OID_802_5_PERMANENT_ADDRESS,
    OID_802_5_CURRENT_ADDRESS,
    OID_802_5_CURRENT_FUNCTIONAL,
    OID_802_5_CURRENT_GROUP
    };


//
// On a development build, don't define functions as static
// so we can set breakpoints on them.
//

#if DEVL
#define STATIC
#else
#define STATIC static
#endif

#if DBG
INT IbmtokDbg = 0;
#define LOG 1
#else
#define LOG 0
#endif


//
// Get from configuration file.
//

#define MAX_MULTICAST_ADDRESS ((UINT)16)
#define MAX_ADAPTERS ((UINT)4)


//
// This macro determines if the directed address
// filtering in the CAM is actually necessary given
// the current filter.
//
#define CAM_DIRECTED_SIGNIFICANT(_Filter) \
    ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \
    (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0)


//
// This macro determines if the multicast filtering in
// the CAM are actually necessary given the current filter.
//
#define CAM_MULTICAST_SIGNIFICANT(_Filter) \
    ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \
    (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \
                    NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0)


STATIC
NDIS_STATUS
IbmtokOpenAdapter(
    OUT PNDIS_STATUS OpenErrorStatus,
    OUT NDIS_HANDLE *MacBindingHandle,
    OUT PUINT SelectedMediumIndex,
    IN PNDIS_MEDIUM MediumArray,
    IN UINT MediumArraySize,
    IN NDIS_HANDLE NdisBindingContext,
    IN NDIS_HANDLE MacAdapterContext,
    IN UINT OpenOptions,
    IN PSTRING AddressingInformation OPTIONAL
    );

STATIC
NDIS_STATUS
IbmtokCloseAdapter(
    IN NDIS_HANDLE MacBindingHandle
    );


STATIC
NDIS_STATUS
IbmtokRequest(
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest
    );

STATIC
NDIS_STATUS
IbmtokQueryInformation(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest
    );


STATIC
NDIS_STATUS
IbmtokSetInformation(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest
    );

STATIC
NDIS_STATUS
IbmtokQueryGlobalStatistics(
    IN NDIS_HANDLE MacAdapterContext,
    IN PNDIS_REQUEST NdisRequest
    );

NDIS_STATUS
IbmtokAddAdapter(
    IN NDIS_HANDLE MacMacContext,
    IN NDIS_HANDLE ConfigurationHandle,
    IN PNDIS_STRING AdaptName
    );

VOID
IbmtokRemoveAdapter(
    IN PVOID MacAdapterContext
    );

STATIC
NDIS_STATUS
IbmtokSetPacketFilter(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest,
    IN UINT PacketFilter
    );

STATIC
NDIS_STATUS
IbmtokSetGroupAddress(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest,
    IN PUCHAR Address
    );

STATIC
NDIS_STATUS
IbmtokChangeFunctionalAddress(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest,
    IN PUCHAR Address
    );

STATIC
NDIS_STATUS
IbmtokReset(
    IN NDIS_HANDLE MacBindingHandle
    );

STATIC
NDIS_STATUS
IbmtokTest(
    IN NDIS_HANDLE MacBindingHandle
    );

STATIC
NDIS_STATUS
IbmtokChangeFilter(
    IN UINT OldFilterClasses,
    IN UINT NewFilterClasses,
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN BOOLEAN Set
    );

STATIC
NDIS_STATUS
IbmtokChangeAddress(
    IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
    IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN BOOLEAN Set
    );

STATIC
NDIS_STATUS
IbmtokChangeGroupAddress(
    IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
    IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN BOOLEAN Set
    );

STATIC
BOOLEAN
IbmtokHardwareDetails(
    IN PIBMTOK_ADAPTER Adapter
    );

STATIC
NDIS_STATUS
IbmtokRegisterAdapter(
    IN PIBMTOK_ADAPTER Adapter,
    IN NDIS_HANDLE ConfigurationHandle,
    IN PNDIS_STRING DeviceName,
    IN BOOLEAN McaCard,
    IN BOOLEAN ConfigError
    );

STATIC
VOID
SetInitializeVariables(
    IN PIBMTOK_ADAPTER Adapter
    );

VOID
SetResetVariables(
    IN PIBMTOK_ADAPTER Adapter
    );

extern
VOID
IbmtokStartAdapterReset(
    IN PIBMTOK_ADAPTER Adapter
    );

STATIC
VOID
IbmtokCloseAction(
    IN NDIS_HANDLE MacBindingHandle
    );

STATIC
VOID
IbmtokSetupRegistersAndInit(
    IN PIBMTOK_ADAPTER Adapter
    );

STATIC
NDIS_STATUS
IbmtokInitialInit(
    IN PIBMTOK_ADAPTER Adapter
    );

VOID
IbmtokUnload(
    IN NDIS_HANDLE MacMacContext
    );


NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    This is the primary initialization routine for the ibmtok driver.
    It is simply responsible for the intializing the wrapper and registering
    the MAC.  It then calls a system and architecture specific routine that
    will initialize and register each adapter.

Arguments:

    DriverObject - Pointer to driver object created by the system.

Return Value:

    The status of the operation.

--*/

{


    //
    // Receives the status of the NdisRegisterMac operation.
    //
    NDIS_STATUS InitStatus;
    PIBMTOK_MAC IbmtokMac;
    NDIS_HANDLE NdisWrapperHandle;
    char Tmp[sizeof(NDIS_MAC_CHARACTERISTICS)];
    PNDIS_MAC_CHARACTERISTICS IbmtokChar = (PNDIS_MAC_CHARACTERISTICS)(PVOID)Tmp;
    NDIS_STRING MacName = NDIS_STRING_CONST("IbmTok");

    //
    // Initialize the wrapper.
    //

    NdisInitializeWrapper(
                &NdisWrapperHandle,
                DriverObject,
                RegistryPath,
                NULL
                );

    //
    // Now allocate memory for our global structure.
    //

    InitStatus = IBMTOK_ALLOC_PHYS(&IbmtokMac, sizeof(IBMTOK_MAC));

    if (InitStatus != NDIS_STATUS_SUCCESS) {

         return NDIS_STATUS_RESOURCES;

    }

    IbmtokMac->NdisWrapperHandle = NdisWrapperHandle;

    //
    // Initialize the MAC characteristics for the call to
    // NdisRegisterMac.
    //


    IbmtokChar->MajorNdisVersion = IBMTOK_NDIS_MAJOR_VERSION;
    IbmtokChar->MinorNdisVersion = IBMTOK_NDIS_MINOR_VERSION;
    IbmtokChar->OpenAdapterHandler = (OPEN_ADAPTER_HANDLER) IbmtokOpenAdapter;
    IbmtokChar->CloseAdapterHandler = (CLOSE_ADAPTER_HANDLER) IbmtokCloseAdapter;
    IbmtokChar->RequestHandler = IbmtokRequest;
    IbmtokChar->SendHandler = IbmtokSend;
    IbmtokChar->TransferDataHandler = IbmtokTransferData;
    IbmtokChar->ResetHandler = IbmtokReset;
    IbmtokChar->UnloadMacHandler = IbmtokUnload;
    IbmtokChar->QueryGlobalStatisticsHandler = IbmtokQueryGlobalStatistics;
    IbmtokChar->AddAdapterHandler      = IbmtokAddAdapter;
    IbmtokChar->RemoveAdapterHandler   = IbmtokRemoveAdapter;

    IbmtokChar->Name = MacName;

    NdisRegisterMac(
        &InitStatus,
        &IbmtokMac->NdisMacHandle,
        NdisWrapperHandle,
        (PVOID)IbmtokMac,
        IbmtokChar,
        sizeof(*IbmtokChar)
        );

    if (InitStatus != NDIS_STATUS_SUCCESS) {

        NdisTerminateWrapper(NdisWrapperHandle, NULL);

        return NDIS_STATUS_FAILURE;

    }

    return NDIS_STATUS_SUCCESS;

}


STATIC
NDIS_STATUS
IbmtokRegisterAdapter(
    IN PIBMTOK_ADAPTER Adapter,
    IN NDIS_HANDLE ConfigurationHandle,
    IN PNDIS_STRING DeviceName,
    IN BOOLEAN McaCard,
    IN BOOLEAN ConfigError
    )

/*++

Routine Description:

    This routine (and its interface) are not portable.  They are
    defined by the OS, the architecture, and the particular IBMTOK
    implementation.

    This routine is responsible for the allocation of the datastructures
    for the driver as well as any hardware specific details necessary
    to talk with the device.

Arguments:

    Adapter - Pointer to the adapter block.

    ConfigurationHandle - Handle passed to MacAddAdapter, to be passed to
    NdisRegisterAdapter.

    DeviceName - Name of this adapter.

    McaCard - This is an MCA bus.

    ConfigError - TRUE if a configuration error was found earlier.

Return Value:

    Returns NDIS_STATUS_SUCCESS if everything goes ok, else
    if anything occurred that prevents the initialization
    of the adapter it returns an appropriate NDIS error.

--*/

{

    NDIS_STATUS Status;

    //
    // Holds information needed when registering the adapter.
    //

    NDIS_ADAPTER_INFORMATION AdapterInformation;

    // We put in this assertion to make sure that ushort are 2 bytes.
    // if they aren't then the initialization block definition needs
    // to be changed.
    //
    // Also all of the logic that deals with status registers assumes
    // that control registers are only 2 bytes.
    //

    ASSERT(sizeof(USHORT) == 2);

    //
    // Get the interrupt number and MMIO address.
    //

    //
    // Set the adapter state.
    //

    SetInitializeVariables(Adapter);

    SetResetVariables(Adapter);

    //
    // Set up the AdapterInformation structure; zero it
    // first in case it is extended later.
    //

    IBMTOK_ZERO_MEMORY (&AdapterInformation, sizeof(NDIS_ADAPTER_INFORMATION));
    AdapterInformation.AdapterType = (McaCard ? NdisInterfaceMca : NdisInterfaceIsa);
    AdapterInformation.NumberOfPortDescriptors = 1;
    AdapterInformation.PortDescriptors[0].InitialPort = Adapter->IbmtokPortAddress;
    AdapterInformation.PortDescriptors[0].NumberOfPorts = 4;

    //
    // Register the adapter with Ndis.
    //

    Status = NdisRegisterAdapter(
                                &Adapter->NdisAdapterHandle,
                                Adapter->NdisMacHandle,
                                Adapter,
                                ConfigurationHandle,
                                DeviceName,
                                &AdapterInformation
                                );

    if (Status != NDIS_STATUS_SUCCESS) {

        return(Status);

    }

    if (ConfigError) {

        //
        // Error and quit
        //

        NdisWriteErrorLogEntry(
            Adapter->NdisAdapterHandle,
            NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
            0
            );

        NdisDeregisterAdapter(Adapter->NdisAdapterHandle);

        return(NDIS_STATUS_FAILURE);

    }



    if (!IbmtokHardwareDetails(Adapter)) {

        NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
        return NDIS_STATUS_ADAPTER_NOT_FOUND;

    }


    //
    // Reset the card to put it in a valid state.
    //

    if (Adapter->SharedRamPaging) {

        WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, 0xc0);

    }

    //
    // OK, do the reset as detailed in the Tech Ref...
    //

    WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0);

    NdisStallExecution(50000);

    WRITE_ADAPTER_PORT(Adapter, RESET_RELEASE, 0);

    //
    // Initialize the interrupt.
    //

    NdisAllocateSpinLock(&Adapter->InterruptLock);

    NdisInitializeInterrupt(
            &Status,
            &Adapter->Interrupt,
            Adapter->NdisAdapterHandle,
            IbmtokISR,
            Adapter,
            IbmtokDPC,
            Adapter->InterruptLevel,
            Adapter->InterruptLevel,
            FALSE,
            (Adapter->UsingPcIoBus)?NdisInterruptLatched:
                                    NdisInterruptLevelSensitive
            );

    if (Status == NDIS_STATUS_SUCCESS){

        //
        // Set up the Adapter variables. (We have to do the
        // initial init to get the network address before we
        // create the filter DB.)
        //
        if (IbmtokInitialInit(Adapter) != NDIS_STATUS_SUCCESS) {

            NdisWriteErrorLogEntry(
                Adapter->NdisAdapterHandle,
                NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
                2,
                registerAdapter,
                IBMTOK_ERRMSG_NOT_FOUND
                );

            NdisRemoveInterrupt(&Adapter->Interrupt);

            NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
            NdisFreeSpinLock(&(Adapter->Lock));
            return NDIS_STATUS_ADAPTER_NOT_FOUND;

        } else {

            if (!TrCreateFilter(
                 IbmtokChangeAddress,
                 IbmtokChangeGroupAddress,
                 IbmtokChangeFilter,
                 IbmtokCloseAction,
                 Adapter->NetworkAddress,
                 &Adapter->Lock,
                 &Adapter->FilterDB
                 )) {

                NdisWriteErrorLogEntry(
                    Adapter->NdisAdapterHandle,
                    NDIS_ERROR_CODE_OUT_OF_RESOURCES,
                    2,
                    registerAdapter,
                    IBMTOK_ERRMSG_CREATE_DB
                    );

                NdisRemoveInterrupt(&Adapter->Interrupt);
                NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
                NdisFreeSpinLock(&(Adapter->Lock));
                return NDIS_STATUS_RESOURCES;

            } else {

                //
                // Initialize the wake up timer to catch interrupts that
                // don't complete. It fires continuously
                // every thirty seconds, and we check if there are any
                // uncompleted operations from the previous two-second
                // period.
                //

                Adapter->WakeUpDpc = (PVOID)IbmtokWakeUpDpc;

                NdisInitializeTimer(&Adapter->WakeUpTimer,
                                    (PVOID)(Adapter->WakeUpDpc),
                                    Adapter );

                NdisSetTimer(
                    &Adapter->WakeUpTimer,
                    30000
                    );

                return(NDIS_STATUS_SUCCESS);

            }

        }

    } else {

        NdisWriteErrorLogEntry(
            Adapter->NdisAdapterHandle,
            NDIS_ERROR_CODE_INTERRUPT_CONNECT,
            2,
            registerAdapter,
            IBMTOK_ERRMSG_INIT_INTERRUPT
            );

        NdisDeregisterAdapter(Adapter->NdisAdapterHandle);
        NdisFreeSpinLock(&(Adapter->Lock));
        return(Status);
    }

}

STATIC
VOID
SetInitializeVariables(
    IN PIBMTOK_ADAPTER Adapter
    )

/*++

Routine Description:

    This routine initializes all the variables in the Adapter
    structure that should only be set during adapter initialization
    (i.e. not during a reset).

Arguments:

    Adapter - The adapter for the hardware.

Return Value:

    None.

--*/

{
    InitializeListHead(&Adapter->OpenBindings);
    InitializeListHead(&Adapter->CloseList);
    InitializeListHead(&Adapter->CloseDuringResetList);

    NdisAllocateSpinLock(&Adapter->Lock);

    //
    // If this is not true, then uncomment below
    //

    ASSERT(FALSE == (BOOLEAN)0);

    // Adapter->HandleSrbRunning = FALSE;
    // Adapter->HandleArbRunning = FALSE;

    // Adapter->OpenInProgress = FALSE;

    Adapter->AdapterNotOpen = TRUE;
    Adapter->NotAcceptingRequests = TRUE;

    // Adapter->ResetInProgress = FALSE;
    // Adapter->ResettingOpen = NULL;
    // Adapter->ResetInterruptAllowed = FALSE;
    // Adapter->ResetInterruptHasArrived = FALSE;

    // Adapter->BringUp = FALSE;

    //
    // Note: These assume that the SAP info will not
    // take up more than 218 bytes.  This is ok, for now, since
    // we open the card with 0 SAPs allowed.
    //

    Adapter->ReceiveBufferLength = 256;
    Adapter->NumberOfTransmitBuffers = 1;

    //
    // Note: The following fields are set in the interrupt handler after
    // the card tells us if the ring is 16 or 4 Mbps.
    //
    //
    // TransmitBufferLength
    // NumberOfReceiveBuffers
    // MaximumTransmittablePacket
    //

    // Adapter->IsrpDeferredBits = 0;

    Adapter->FirstInitialization = TRUE;

    // Adapter->OutstandingAsbFreeRequest = FALSE;
}

VOID
SetResetVariables(
    IN PIBMTOK_ADAPTER Adapter
    )

/*++

Routine Description:

    This routine initializes all the variables in the Adapter
    structure that are set both during an initialization and
    after a reset.

Arguments:

    Adapter - The adapter for the hardware.

Return Value:

    None.

--*/

{
    Adapter->FirstTransmit = NULL;
    Adapter->LastTransmit = NULL;
    Adapter->FirstWaitingForAsb = NULL;
    Adapter->LastWaitingForAsb = NULL;
    Adapter->TransmittingPacket = NULL;

    IBMTOK_ZERO_MEMORY(Adapter->CorrelatorArray,
                    sizeof(PNDIS_PACKET) * MAX_COMMAND_CORRELATOR);

    Adapter->PendQueue = NULL;
    Adapter->EndOfPendQueue = NULL;

    Adapter->SrbAvailable = TRUE;
    Adapter->AsbAvailable = TRUE;

    Adapter->IsrpBits = 0;
    Adapter->IsrpLowBits = 0;

    Adapter->NextCorrelatorToComplete = 0;
    Adapter->ReceiveWaitingForAsbList = (USHORT)-1;
    Adapter->ReceiveWaitingForAsbEnd  = (USHORT)-1;
    Adapter->UseNextAsbForReceive = TRUE;
}

extern
NDIS_STATUS
IbmtokInitialInit(
    IN PIBMTOK_ADAPTER Adapter
    )

/*++

Routine Description:

    This routine sets up the initial init of the driver.

Arguments:

    Adapter - The adapter for the hardware.

Return Value:

    None.

--*/

{
    USHORT RegValue;
    UINT Time = 50; // Number of 100 milliseconds to delay while waiting
                    // for the card to initialize.

    IbmtokSetupRegistersAndInit(Adapter);

    //
    // Delay execution for 5 seconds to give the ring
    // time to initialize.
    //

    while((!Adapter->BringUp) && (Time != 0)){

        NdisStallExecution(100000);

        Time--;

    }

    if (!Adapter->BringUp){

        return(NDIS_STATUS_ADAPTER_NOT_FOUND);

    } else {

        //
        // Do remaining initialization.
        //

        USHORT WrbOffset;
        PSRB_BRING_UP_RESULT BringUpSrb;
        PUCHAR EncodedAddress;
        UCHAR Value1, Value2;

        READ_ADAPTER_REGISTER(Adapter, WRBR_LOW,  &Value1);
        READ_ADAPTER_REGISTER(Adapter, WRBR_HIGH, &Value2);

        WrbOffset = (((USHORT)Value1) << 8) + (USHORT)Value2;

        Adapter->InitialWrbOffset = WrbOffset;

#if DBG
        if (IbmtokDbg) {

            DbgPrint("IBMTOK: Initial Offset = 0x%x\n", WrbOffset);

        }
#endif

        BringUpSrb = (PSRB_BRING_UP_RESULT)
                                (Adapter->SharedRam + WrbOffset);

        NdisReadRegisterUshort(&(BringUpSrb->ReturnCode), &RegValue);

        if (RegValue != 0x0000) {

            if (RegValue == 0x30){

                NdisWriteErrorLogEntry(
                    Adapter->NdisAdapterHandle,
                    NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
                    0x32,
                    handleSrbSsb,
                    IBMTOK_ERRMSG_BRINGUP_FAILURE
                    );


                return(NDIS_STATUS_ADAPTER_NOT_FOUND);

            } else {

                NdisWriteErrorLogEntry(
                    Adapter->NdisAdapterHandle,
                    NDIS_ERROR_CODE_HARDWARE_FAILURE,
                    3,
                    handleSrbSsb,
                    IBMTOK_ERRMSG_BRINGUP_FAILURE,
                    (ULONG)RegValue
                    );

                return(NDIS_STATUS_ADAPTER_NOT_FOUND);


            }

        } else {

            Adapter->FirstInitialization = FALSE;
            Adapter->BringUp = TRUE;

        }

        NdisReadRegisterUchar(&(BringUpSrb->InitStatus), &RegValue);

        if (RegValue & 0x01) {

#if DBG
            if (IbmtokDbg) DbgPrint("IBMTOK: 16 Mbps\n");
#endif

            Adapter->Running16Mbps = TRUE;

        } else {

            Adapter->Running16Mbps = FALSE;

        }

        //
        // ZZZ: This code assumes that there is no shared ram paging and
        // that the MappedSharedRam is all that is available.
        //


#if DBG
        if (IbmtokDbg) DbgPrint( "IBMTOK: shared RAM size is %x (%d)\n", Adapter->MappedSharedRam, Adapter->MappedSharedRam );
#endif
        if (Adapter->MappedSharedRam > 0x2000){

            ULONG RamAvailable;
            UCHAR NumTransmitBuffers = (UCHAR)Adapter->NumberOfTransmitBuffers;

            //
            // 2096 is the amount of shared ram that is current sucked
            // up by the areas found on page 7-27 of the Tech. Ref.
            //
            //

            RamAvailable = Adapter->MappedSharedRam;

            if (Adapter->MappedSharedRam == 0x10000){

                //
                // Subtract an extra 8K to account for when we map
                // MMIO space to the top 8K of RAM.
                //

                RamAvailable = RamAvailable - 2096 - 0x2000;

            } else {

                RamAvailable = RamAvailable - 1584;

            }
#if DBG
            if (IbmtokDbg) DbgPrint( "IBMTOK: RAM available is %x (%d)\n", RamAvailable, RamAvailable );
#endif

            //
            // The card has more than 8K of ram, so adjust
            // transmit buffer size to abuse this.
            //

            if (Adapter->Running16Mbps) {

                //
                // Use the maximum allowed
                //

                Adapter->TransmitBufferLength = Adapter->Max16MbpsDhb;
#if DBG
                if (IbmtokDbg) DbgPrint( "IBMTOK: 16 MB ring. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
#endif

            } else {

                //
                // Use the maximum allowed
                //
                Adapter->TransmitBufferLength = Adapter->Max4MbpsDhb;
#if DBG
                if (IbmtokDbg) DbgPrint( "IBMTOK: 4 MB ring. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
#endif

            }

            //
            // First we subtract off buffer space for receiving the
            // maximum sized packet that can be on the wire.  This is
            // the *minimum* number of receive buffers and may be
            // modified below if the transmit space does not take up
            // the rest.
            //

#if DBG
            if (IbmtokDbg) DbgPrint( "IBMTOK: Receive buffer length is %x (%d)\n", Adapter->ReceiveBufferLength, Adapter->ReceiveBufferLength );
#endif
            if (RamAvailable < Adapter->TransmitBufferLength) {

                //
                // There is not enough buffer space for even a single maximum
                // sized frame.  So, just divide the buffer space into two
                // equally sized areas -- receive and transmit.
                //

                Adapter->NumberOfReceiveBuffers = (USHORT)((RamAvailable / 2) /
                                                           Adapter->ReceiveBufferLength)
                                                           + 1;
#if DBG
                if (IbmtokDbg) DbgPrint( "IBMTOK: RAM too small. # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
#endif

            } else {

                Adapter->NumberOfReceiveBuffers = (USHORT)(Adapter->TransmitBufferLength /
                                         Adapter->ReceiveBufferLength) + 1;
#if DBG
                if (IbmtokDbg) DbgPrint( "IBMTOK: RAM large enough. # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
#endif

            }

            RamAvailable = RamAvailable -
                              (Adapter->NumberOfReceiveBuffers * Adapter->ReceiveBufferLength);
#if DBG
            if (IbmtokDbg) {
                DbgPrint( "IBMTOK: RAM available for transmit is %x (%d)\n", RamAvailable, RamAvailable );
                DbgPrint( "IBMTOK: # transmit buffers is %x (%d)\n", NumTransmitBuffers, NumTransmitBuffers );
            }
#endif

            if (Adapter->TransmitBufferLength > (RamAvailable / NumTransmitBuffers)) {

                if ((RamAvailable / NumTransmitBuffers) < 0x1000) {

                    Adapter->TransmitBufferLength = 0x800;

                } else if ((RamAvailable / NumTransmitBuffers) < 0x2000) {

                    Adapter->TransmitBufferLength = 0x1000;

                } else if ((RamAvailable / NumTransmitBuffers) < 0x4000) {

                    Adapter->TransmitBufferLength = 0x2000;

                } else {

                    Adapter->TransmitBufferLength = 0x4000;

                }

#if DBG
                if (IbmtokDbg) DbgPrint( "IBMTOK: RAM too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
#endif
            }


            //
            // If computed value is greater than the value that the
            // registry allows, then use the registry value.
            //

#if DBG
            if (IbmtokDbg) DbgPrint( "IBMTOK: Original max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
#endif
            if (Adapter->TransmitBufferLength > Adapter->MaxTransmittablePacket) {

                Adapter->TransmitBufferLength = Adapter->MaxTransmittablePacket;
#if DBG
                if (IbmtokDbg) DbgPrint( "IBMTOK: Max too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
#endif

            }

            Adapter->MaxTransmittablePacket = Adapter->TransmitBufferLength - 6;
#if DBG
            if (IbmtokDbg) DbgPrint( "IBMTOK: New max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
#endif

            //
            // Remove space taken up by transmit buffers.
            //

            RamAvailable = RamAvailable - ((ULONG)NumTransmitBuffers *
                                   (ULONG)Adapter->TransmitBufferLength);

            //
            // Add in any left over space for receive buffers.
            //

            Adapter->NumberOfReceiveBuffers += (USHORT)(RamAvailable /
                                         Adapter->ReceiveBufferLength);
#if DBG
            if (IbmtokDbg) DbgPrint( "IBMTOK: New # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
#endif

        } else {

            Adapter->TransmitBufferLength = 0x800;
            Adapter->NumberOfTransmitBuffers = 1;
#if DBG
            if (IbmtokDbg) {
                DbgPrint( "IBMTOK: Only 8K shared RAM. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
                DbgPrint( "IBMTOK: Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
            }
#endif

            //
            // There is only 8K of buffer space, which is not enough space for
            // receiving and transmitting packets on even a 4Mbit ring.  So,
            // use some reasonable values for transmit and receive space.
            //

            // If computed value is greater than the value that the
            // registry allows, then use the registry value.
            //

#if DBG
            if (IbmtokDbg) DbgPrint( "IBMTOK: Original max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
#endif
            if (Adapter->TransmitBufferLength > Adapter->MaxTransmittablePacket) {

                Adapter->TransmitBufferLength = Adapter->MaxTransmittablePacket;
#if DBG
                if (IbmtokDbg) DbgPrint( "IBMTOK: Max too small. Transmit buffer length is %x (%d)\n", Adapter->TransmitBufferLength, Adapter->TransmitBufferLength );
#endif

            }

            Adapter->MaxTransmittablePacket = Adapter->TransmitBufferLength - 6;

            Adapter->NumberOfReceiveBuffers = 15;
#if DBG
            if (IbmtokDbg) {
                DbgPrint( "IBMTOK: New max transmit length is %x (%d)\n", Adapter->MaxTransmittablePacket, Adapter->MaxTransmittablePacket );
                DbgPrint( "IBMTOK: # receive buffers is %x (%d)\n", Adapter->NumberOfReceiveBuffers, Adapter->NumberOfReceiveBuffers );
            }
#endif

        }

#if DBG
        if (IbmtokDbg) {
            DbgPrint("IBMTOK: Space: 0x%x, # Rcv: 0x%x, TransmitSize: 0x%x\n",
                 Adapter->RrrLowValue,
                 Adapter->NumberOfReceiveBuffers,
                 Adapter->MaxTransmittablePacket
                );
        }
#endif

        NdisReadRegisterUshort(&(BringUpSrb->EncodedAddressPointer), &RegValue);

        EncodedAddress = (PUCHAR)
            SRAM_PTR_TO_PVOID(Adapter,RegValue);

        IBMTOK_MOVE_FROM_MAPPED_MEMORY(Adapter->PermanentNetworkAddress, EncodedAddress,
                                    TR_LENGTH_OF_ADDRESS);


        if ((Adapter->NetworkAddress[0] == 0x00) &&
            (Adapter->NetworkAddress[1] == 0x00) &&
            (Adapter->NetworkAddress[2] == 0x00) &&
            (Adapter->NetworkAddress[3] == 0x00) &&
            (Adapter->NetworkAddress[4] == 0x00) &&
            (Adapter->NetworkAddress[5] == 0x00)) {


            IBMTOK_MOVE_FROM_MAPPED_MEMORY(Adapter->NetworkAddress, EncodedAddress,
                                    TR_LENGTH_OF_ADDRESS);
        }

        //
        // If required, we have to zero the upper section
        // of the Shared RAM now.
        //
        //
        // THIS DOESN'T WORK! It hangs the system while
        // zeroing the first address. (One gets an infinite number of
        // hardware interrupts w/o any reason)
        //

#if 0
        if (Adapter->UpperSharedRamZero) {

            PUCHAR ZeroPointer;
            UINT i;
            PUCHAR OldSharedRam;
            NDIS_PHYSICAL_ADDRESS PhysicalAddress;

#if DBG
            if (IbmtokDbg) DbgPrint("IBMTOK: Zeroing Memory\n");
#endif


            if (Adapter->MappedSharedRam < 0x10000) {

                //
                // This portion of memory is not currently mapped, so do it.
                //

                OldSharedRam = Adapter->SharedRam;

                NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
                NdisSetPhysicalAddressLow(PhysicalAddress, (Adapter->RrrLowValue << 12) + (0x10000 - 512));

                NdisMapIoSpace(
                   &Status,
                   &(Adapter->SharedRam),
                   Adapter->NdisAdapterHandle,
                   PhysicalAddress,
                   512);

                if (Status != NDIS_STATUS_SUCCESS) {

                    NdisWriteErrorLogEntry(
                        Adapter->NdisAdapterHandle,
                        NDIS_ERROR_CODE_RESOURCE_CONFLICT,
                        0
                        );

                    return(Status);

                }

            }

            if (Adapter->SharedRamPaging){

                SETUP_SRPR(Adapter, SHARED_RAM_ZERO_OFFSET);

#if DBG
                if (IbmtokDbg) DbgPrint("IBMTOK: Shared RAM paging enabled\n");
#endif

                ZeroPointer =
                    SHARED_RAM_ADDRESS(Adapter,
                        SHARED_RAM_LOW_BITS(SHARED_RAM_ZERO_OFFSET));

            } else {

                if (Adapter->MappedSharedRam < 0x10000) {

                    //
                    // No offset for this portion, since we just mapped it.
                    //
                    //

                    ZeroPointer = SHARED_RAM_ADDRESS(Adapter, 0);

                } else {

                    ZeroPointer =
                      SHARED_RAM_ADDRESS(Adapter, SHARED_RAM_ZERO_OFFSET);

                }

            }

            for (i=0; i<SHARED_RAM_ZERO_LENGTH; i++) {

                NdisWriteRegisterUchar(&(ZeroPointer[i]), 0x00);

            }

            if (Adapter->MappedSharedRam < 0x10000) {

                //
                // Unmap it
                //

                NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
                             Adapter->SharedRam,
                             512);

                Adapter->SharedRam = OldSharedRam;

            }

        }
#endif


        //
        // Now set the timer to the maximum...we still need it
        // as a card heartbeat.
        //

        WRITE_ADAPTER_REGISTER(Adapter, TVR_HIGH, 0xff);

        return NDIS_STATUS_SUCCESS;

    }

}

STATIC
NDIS_STATUS
IbmtokOpenAdapter(
    OUT PNDIS_STATUS OpenErrorStatus,
    OUT NDIS_HANDLE *MacBindingHandle,
    OUT PUINT SelectedMediumIndex,
    IN PNDIS_MEDIUM MediumArray,
    IN UINT MediumArraySize,
    IN NDIS_HANDLE NdisBindingContext,
    IN NDIS_HANDLE MacAdapterContext,
    IN UINT OpenOptions,
    IN PSTRING AddressingInformation OPTIONAL
    )

/*++

Routine Description:

    OpenErrorStatus - Returns more information about the error status.  In
    this card it is not used, since this code returns either success or
    pending, no failure is possible.

    This routine is used to create an open instance of an adapter, in effect
    creating a binding between an upper-level module and the MAC module over
    the adapter.

Arguments:

    OpenErrorStatus - Returns more information about the error status.  In
    this card it is not used, since this code returns either success or
    pending, no failure is possible.

    MacBindingHandle - A pointer to a location in which the MAC stores
    a context value that it uses to represent this binding.


    SelectedMediumIndex - An index into the MediumArray of the medium
    typedef that the MAC wishes to viewed as.

    MediumArray - An array of medium types which the protocol supports.

    MediumArraySize - The number of elements in MediumArray.

    NdisBindingContext - A value to be recorded by the MAC and passed as
    context whenever an indication is delivered by the MAC for this binding.

    MacAdapterContext - The value associated with the adapter that is being
    opened when the MAC registered the adapter with NdisRegisterAdapter.

    IN UINT OpenOptions,

    AddressingInformation - An optional pointer to a variable length string
    containing hardware-specific information that can be used to program the
    device.  (This is not used by this MAC.)

Return Value:

    The function value is the status of the operation.  If the MAC does not
    complete this request synchronously, the value would be
    NDIS_STATUS_PENDING.


--*/

{

    //
    // The IBMTOK_ADAPTER that this open binding should belong too.
    //
    PIBMTOK_ADAPTER Adapter;

    //
    // Holds the status that should be returned to the caller.
    //
    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;

    //
    // Pointer to the space allocated for the binding.
    //
    PIBMTOK_OPEN NewOpen;

    //
    // Generic loop variable
    //
    UINT i;


    UNREFERENCED_PARAMETER(AddressingInformation);

    *OpenErrorStatus = (NDIS_STATUS)0;

    //
    // Search for the medium type (token ring)
    //

    for(i=0; i < MediumArraySize; i++){

        if (MediumArray[i] == NdisMedium802_5){

            break;

        }

    }

    if (i == MediumArraySize){

        return(NDIS_STATUS_UNSUPPORTED_MEDIA);

    }

    *SelectedMediumIndex = i;

    Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);

    NdisInterlockedAddUlong((PULONG)&Adapter->References, 1, &Adapter->Lock);

    //
    // Allocate the space for the open binding.  Fill in the fields.
    //

    if (IBMTOK_ALLOC_PHYS(&NewOpen, sizeof(IBMTOK_OPEN)) ==
        NDIS_STATUS_SUCCESS){

        *MacBindingHandle = BINDING_HANDLE_FROM_PIBMTOK_OPEN(NewOpen);
        InitializeListHead(&NewOpen->OpenList);
        NewOpen->NdisBindingContext = NdisBindingContext;
        NewOpen->References = 0;
        NewOpen->BindingShuttingDown = FALSE;
        NewOpen->OwningIbmtok = Adapter;
        NewOpen->OpenPending = FALSE;

        NdisAcquireSpinLock(&Adapter->Lock);
        if (!TrNoteFilterOpenAdapter(
                                     NewOpen->OwningIbmtok->FilterDB,
                                     NewOpen,
                                     NdisBindingContext,
                                     &NewOpen->NdisFilterHandle
                                     )) {

            NdisReleaseSpinLock(&Adapter->Lock);

            NdisWriteErrorLogEntry(
                Adapter->NdisAdapterHandle,
                NDIS_ERROR_CODE_OUT_OF_RESOURCES,
                2,
                openAdapter,
                IBMTOK_ERRMSG_OPEN_DB
                );

            IBMTOK_FREE_PHYS(NewOpen, sizeof(IBMTOK_OPEN));

            StatusToReturn = NDIS_STATUS_FAILURE;
            NdisAcquireSpinLock(&Adapter->Lock);

        } else {

            //
            // Everything has been filled in.  Synchronize access to the
            // adapter block and link the new open adapter in and increment
            // the opens reference count to account for the fact that the
            // filter routines have a "reference" to the open.
            //

            NewOpen->LookAhead = IBMTOK_MAX_LOOKAHEAD;

            Adapter->LookAhead = IBMTOK_MAX_LOOKAHEAD;

            InsertTailList(&Adapter->OpenBindings,&NewOpen->OpenList);
            NewOpen->References++;

            //
            // Now see if the adapter is currently open.
            //

            if (Adapter->AdapterNotOpen) {

                //
                // The adapter is not open, so this has to pend.
                //
                NewOpen->OpenPending = TRUE;

                StatusToReturn = NDIS_STATUS_PENDING;

                if (!Adapter->OpenInProgress) {

                    //
                    // Fill in the SRB for the open if this is the first
                    // one for the card.
                    //

                    PSRB_OPEN_ADAPTER OpenSrb;

                    IF_LOG('o');

                    Adapter->OpenInProgress = TRUE;
                    Adapter->CurrentRingState = NdisRingStateOpening;

                    NdisReleaseSpinLock(&Adapter->Lock);

                    OpenSrb = (PSRB_OPEN_ADAPTER)
                             (Adapter->SharedRam + Adapter->InitialWrbOffset);

                    IBMTOK_ZERO_MAPPED_MEMORY(OpenSrb, sizeof(SRB_OPEN_ADAPTER));

                    NdisWriteRegisterUchar(
                                (PUCHAR)&OpenSrb->Command,
                                SRB_CMD_OPEN_ADAPTER);
                    NdisWriteRegisterUshort(
                                (PUSHORT)&OpenSrb->OpenOptions,
                                OPEN_CONTENDER);

                    for (i=0; i < TR_LENGTH_OF_ADDRESS; i++) {
                        NdisWriteRegisterUchar((PCHAR)&OpenSrb->NodeAddress[i],
                                                Adapter->NetworkAddress[i]
                                                );
                    }

                    WRITE_IBMSHORT(OpenSrb->ReceiveBufferNum,
                                            Adapter->NumberOfReceiveBuffers);
                    WRITE_IBMSHORT(OpenSrb->ReceiveBufferLen,
                                            Adapter->ReceiveBufferLength);

                    WRITE_IBMSHORT(OpenSrb->TransmitBufferLen,
                                            Adapter->TransmitBufferLength);
                    NdisWriteRegisterUchar(
                                (PUCHAR)&OpenSrb->TransmitBufferNum,
                                (UCHAR)Adapter->NumberOfTransmitBuffers);

                    WRITE_ADAPTER_REGISTER(Adapter, ISRA_HIGH_SET,
                                        ISRA_HIGH_COMMAND_IN_SRB);

                    NdisAcquireSpinLock(&Adapter->Lock);

                }

            }

        }

    } else {

        NdisWriteErrorLogEntry(
            Adapter->NdisAdapterHandle,
            NDIS_ERROR_CODE_OUT_OF_RESOURCES,
            2,
            openAdapter,
            IBMTOK_ERRMSG_ALLOC_MEM
            );

        return(NDIS_STATUS_RESOURCES);

    }




    //
    // This macro assumes it is called with the lock held,
    // and releases it.
    //

    IBMTOK_DO_DEFERRED(Adapter);
    return StatusToReturn;
}

VOID
IbmtokAdjustMaxLookAhead(
    IN PIBMTOK_ADAPTER Adapter
    )
/*++

Routine Description:

    This routine finds the open with the maximum lookahead value and
    stores that in the adapter block.

Arguments:

    Adapter - A pointer to the adapter block.

Returns:

    None.

--*/
{
    ULONG CurrentMax = 0;
    PLIST_ENTRY CurrentLink;
    PIBMTOK_OPEN TempOpen;

    CurrentLink = Adapter->OpenBindings.Flink;

    while (CurrentLink != &(Adapter->OpenBindings)){

        TempOpen = CONTAINING_RECORD(
                             CurrentLink,
                             IBMTOK_OPEN,
                             OpenList
                             );

        if (TempOpen->LookAhead > CurrentMax) {

            CurrentMax = TempOpen->LookAhead;

        }

        CurrentLink = CurrentLink->Flink;

    }

    if (CurrentMax == 0) {

        CurrentMax = IBMTOK_MAX_LOOKAHEAD;

    }

    Adapter->LookAhead = CurrentMax;

}

STATIC
NDIS_STATUS
IbmtokCloseAdapter(
    IN NDIS_HANDLE MacBindingHandle
    )

/*++

Routine Description:

    This routine causes the MAC to close an open handle (binding).

Arguments:

    MacBindingHandle - The context value returned by the MAC when the
    adapter was opened.  In reality it is a PIBMTOK_OPEN.

Return Value:

    The function value is the status of the operation.


--*/

{

    PIBMTOK_ADAPTER Adapter;
    PIBMTOK_OPEN Open;

    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;

    Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
    Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);

    //
    // Hold the lock while we update the reference counts for the
    // adapter and the open.
    //

    NdisAcquireSpinLock(&Adapter->Lock);
    Adapter->References++;

    if (!Open->BindingShuttingDown) {

        Open->References++;

        StatusToReturn = TrDeleteFilterOpenAdapter(
                             Adapter->FilterDB,
                             Open->NdisFilterHandle,
                             NULL
                             );

        //
        // If the status is successful that merely implies that
        // we were able to delete the reference to the open binding
        // from the filtering code.  If we have a successful status
        // at this point we still need to check whether the reference
        // count to determine whether we can close.
        //
        //
        // The delete filter routine can return a "special" status
        // that indicates that there is a current NdisIndicateReceive
        // on this binding.
        //


        if (StatusToReturn == NDIS_STATUS_SUCCESS) {

            //
            // Check whether the reference count is two.  If
            // it is then we can get rid of the memory for
            // this open.
            //
            // A count of two indicates one for this routine
            // and one for the filter which we *know* we can
            // get rid of.
            //

            if (Open->References == 2) {

                RemoveEntryList(&Open->OpenList);

                //
                // We are the only reference to the open.  Remove
                // it from the open list and delete the memory.
                //

                RemoveEntryList(&Open->OpenList);

                if (Open->LookAhead == Adapter->LookAhead) {

                    IbmtokAdjustMaxLookAhead(Adapter);

                }

                IBMTOK_FREE_PHYS(Open,sizeof(IBMTOK_OPEN));

            } else {

                Open->BindingShuttingDown = TRUE;

                //
                // Remove the open from the open list and put it on
                // the closing list.
                //

                RemoveEntryList(&Open->OpenList);
                InsertTailList(&Adapter->CloseList,&Open->OpenList);

                //
                // Account for this routines reference to the open
                // as well as reference because of the filtering.
                //

                Open->References -= 2;

                //
                // Change the status to indicate that we will
                // be closing this later.
                //

                StatusToReturn = NDIS_STATUS_PENDING;

            }

        } else if (StatusToReturn == NDIS_STATUS_PENDING) {


            //
            // If it pended, there may be
            // operations queued.
            //

            IbmtokProcessSrbRequests(Adapter);

            //
            // Now start closing down this open.
            //

            Open->BindingShuttingDown = TRUE;

            //
            // Remove the open from the open list and put it on
            // the closing list.
            //

            RemoveEntryList(&Open->OpenList);
            InsertTailList(&Adapter->CloseList,&Open->OpenList);

            //
            // Account for this routines reference to the open
            // as well as reference because of the filtering.
            //

            Open->References -= 2;

        } else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {

            //
            // When we have this status it indicates that the filtering
            // code was currently doing an NdisIndicateReceive.  It
            // would not be wise to delete the memory for the open at
            // this point.  The filtering code will call our close action
            // routine upon return from NdisIndicateReceive and that
            // action routine will decrement the reference count for
            // the open.
            //

            Open->BindingShuttingDown = TRUE;

            //
            // This status is private to the filtering routine.  Just
            // tell the caller the the close is pending.
            //

            StatusToReturn = NDIS_STATUS_PENDING;

            //
            // Remove the open from the open list and put it on
            // the closing list.
            //

            RemoveEntryList(&Open->OpenList);
            InsertTailList(&Adapter->CloseList,&Open->OpenList);

            //
            // Account for this routines reference to the open.
            //

            Open->References--;

        } else if (StatusToReturn == NDIS_STATUS_RESET_IN_PROGRESS) {

            Open->BindingShuttingDown = TRUE;

            //
            // Remove the open from the open list and put it on
            // the closing list.
            //

            RemoveEntryList(&Open->OpenList);
            InsertTailList(&Adapter->CloseDuringResetList,&Open->OpenList);


            //
            // Account for this routines reference to the open.
            //

            Open->References--;

            StatusToReturn = NDIS_STATUS_PENDING;

        } else {

            NdisWriteErrorLogEntry(
                Adapter->NdisAdapterHandle,
                NDIS_ERROR_CODE_DRIVER_FAILURE,
                2,
                IBMTOK_ERRMSG_INVALID_STATUS,
                1
                );

        }

    } else {

        StatusToReturn = NDIS_STATUS_CLOSING;

    }


    //
    // This macro assumes it is called with the lock held,
    // and releases it.
    //

    IBMTOK_DO_DEFERRED(Adapter);
    return StatusToReturn;

}

STATIC
NDIS_STATUS
IbmtokRequest(
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest
    )

/*++

Routine Description:

    The IbmtokRequest allows a protocol to query and set information
    about the MAC.

Arguments:

    MacBindingHandle - The context value returned by the MAC when the
    adapter was opened.  In reality, it is a pointer to IBMTOK_OPEN.

    NdisRequest - A structure which contains the request type (Set or
    Query), an array of operations to perform, and an array for holding
    the results of the operations.

Return Value:

    The function value is the status of the operation.

--*/

{
    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;

    PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
    PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);

    NdisAcquireSpinLock(&(Adapter->Lock));

    Adapter->References++;

    //
    // Process request
    //

    if (NdisRequest->RequestType == NdisRequestQueryInformation) {

        StatusToReturn = IbmtokQueryInformation(Adapter, Open, NdisRequest);

    } else if (NdisRequest->RequestType == NdisRequestSetInformation) {


        //
        // Make sure Adapter is in a valid state.
        //

        if (Adapter->Unplugged) {

            StatusToReturn = NDIS_STATUS_DEVICE_FAILED;

        } else if (!Adapter->NotAcceptingRequests) {

            //
            // Make sure the open instance is valid
            //

            if (!Open->BindingShuttingDown) {

                StatusToReturn = IbmtokSetInformation(Adapter,Open,NdisRequest);

            } else {

                StatusToReturn = NDIS_STATUS_CLOSING;

            }

        } else {

            if (Adapter->ResetInProgress) {

                StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;

            } else if (Adapter->AdapterNotOpen) {

                StatusToReturn = NDIS_STATUS_FAILURE;

            } else {

                NdisWriteErrorLogEntry(
                    Adapter->NdisAdapterHandle,
                    NDIS_ERROR_CODE_DRIVER_FAILURE,
                    2,
                    IBMTOK_ERRMSG_INVALID_STATE,
                    3
                    );

            }
        }
    } else {

        StatusToReturn = NDIS_STATUS_NOT_RECOGNIZED;

    }

    IBMTOK_DO_DEFERRED(Adapter);

    return(StatusToReturn);

}

STATIC
NDIS_STATUS
IbmtokQueryProtocolInformation(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN NDIS_OID Oid,
    IN BOOLEAN GlobalMode,
    IN PVOID  InfoBuffer,
    IN UINT   BytesLeft,
    OUT PUINT BytesNeeded,
    OUT PUINT BytesWritten
)

/*++

Routine Description:

    The IbmtokQueryProtocolInformation process a Query request for
    NDIS_OIDs that are specific to a binding about the MAC.  Note that
    some of the OIDs that are specific to bindings are also queryable
    on a global basis.  Rather than recreate this code to handle the
    global queries, I use a flag to indicate if this is a query for the
    global data or the binding specific data.

Arguments:

    Adapter - a pointer to the adapter.

    Open - a pointer to the open instance.

    Oid - the NDIS_OID to process.

    GlobalMode - Some of the binding specific information is also used
    when querying global statistics.  This is a flag to specify whether
    to return the global value, or the binding specific value.

    InfoBuffer - a pointer into the NdisRequest->InformationBuffer
     into which store the result of the query.

    BytesLeft - the number of bytes left in the InformationBuffer.

    BytesNeeded - If there is not enough room in the information buffer
    then this will contain the number of bytes needed to complete the
    request.

    BytesWritten - a pointer to the number of bytes written into the
    InformationBuffer.

Return Value:

    The function value is the status of the operation.

--*/

{
    NDIS_MEDIUM Medium = NdisMedium802_5;
    ULONG GenericULong;
    USHORT GenericUShort;
    UCHAR GenericArray[6];

    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;

    //
    // Common variables for pointing to result of query
    //

    PVOID MoveSource = (PVOID)(&GenericULong);
    ULONG MoveBytes = sizeof(GenericULong);

    NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady;

    //
    // General Algorithm:
    //
    //      Switch(Request)
    //         Get requested information
    //         Store results in a common variable.
    //      Copy result in common variable to result buffer.
    //

    //
    // Switch on request type
    //

    switch (Oid) {

        case OID_GEN_MAC_OPTIONS:

            GenericULong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND  |
                                   NDIS_MAC_OPTION_RECEIVE_SERIALIZED
                                  );

            break;

        case OID_GEN_SUPPORTED_LIST:

            if (!GlobalMode){
                MoveSource = (PVOID)(IbmtokProtocolSupportedOids);
                MoveBytes = sizeof(IbmtokProtocolSupportedOids);
            } else {
                MoveSource = (PVOID)(IbmtokGlobalSupportedOids);
                MoveBytes = sizeof(IbmtokGlobalSupportedOids);
            }
            break;

        case OID_GEN_HARDWARE_STATUS:


            if (Adapter->ResetInProgress){

                HardwareStatus = NdisHardwareStatusReset;

            } else if ((Adapter->FirstInitialization) ||
                     (Adapter->OpenInProgress)){

                 HardwareStatus = NdisHardwareStatusInitializing;

            } else if (Adapter->NotAcceptingRequests){

                HardwareStatus = NdisHardwareStatusNotReady;

            } else
                HardwareStatus = NdisHardwareStatusReady;


            MoveSource = (PVOID)(&HardwareStatus);
            MoveBytes = sizeof(NDIS_HARDWARE_STATUS);

            break;

        case OID_GEN_MEDIA_SUPPORTED:
        case OID_GEN_MEDIA_IN_USE:

            MoveSource = (PVOID) (&Medium);
            MoveBytes = sizeof(NDIS_MEDIUM);
            break;

        case OID_GEN_MAXIMUM_LOOKAHEAD:

            GenericULong = IBMTOK_MAX_LOOKAHEAD;

            break;


        case OID_GEN_MAXIMUM_FRAME_SIZE:
        case OID_GEN_MAXIMUM_TOTAL_SIZE:

            GenericULong = (ULONG)(Adapter->MaxTransmittablePacket);

            if (Oid == OID_GEN_MAXIMUM_FRAME_SIZE) {

                //
                // For the receive frame size, we subtract the minimum
                // header size from the number.
                //

                GenericULong -= 14;
            }

            break;


        case OID_GEN_LINK_SPEED:

            GenericULong = (ULONG)(Adapter->Running16Mbps? 160000 : 40000);

            break;


        case OID_GEN_TRANSMIT_BUFFER_SPACE:

            GenericULong = (ULONG)(Adapter->NumberOfTransmitBuffers *
                            Adapter->TransmitBufferLength);

            break;

        case OID_GEN_RECEIVE_BUFFER_SPACE:

            GenericULong = (ULONG)(Adapter->NumberOfReceiveBuffers *
                             Adapter->ReceiveBufferLength);

            break;

        case OID_GEN_TRANSMIT_BLOCK_SIZE:

            GenericULong = (ULONG)(Adapter->TransmitBufferLength);

            break;

        case OID_GEN_RECEIVE_BLOCK_SIZE:

            GenericULong = (ULONG)(Adapter->ReceiveBufferLength);

            break;

        case OID_GEN_VENDOR_ID:

            NdisMoveMemory(
                (PVOID)&GenericULong,
                Adapter->PermanentNetworkAddress,
                3
                );
            GenericULong &= 0xFFFFFF00;

            if (Adapter->UsingPcIoBus) {

                GenericULong |= 0x01;

            }

            MoveSource = (PVOID)(&GenericULong);
            MoveBytes = sizeof(GenericULong);
            break;

        case OID_GEN_VENDOR_DESCRIPTION:

            if (Adapter->UsingPcIoBus){
                MoveSource = (PVOID)"Ibm Token Ring Network Card for PC I/O bus.";
                MoveBytes = 44;
            } else {
                MoveSource = (PVOID)"Ibm Token Ring Network Card for MCA bus.";
                MoveBytes = 41;
            }
            break;

        case OID_GEN_DRIVER_VERSION:

            GenericUShort = (USHORT)((IBMTOK_NDIS_MAJOR_VERSION << 8) | IBMTOK_NDIS_MINOR_VERSION);

            MoveSource = (PVOID)(&GenericUShort);
            MoveBytes = sizeof(GenericUShort);
            break;


        case OID_GEN_CURRENT_PACKET_FILTER:

            if (GlobalMode) {

                GenericULong = (ULONG)(Adapter->CurrentPacketFilter);

            } else {

                GenericULong = (ULONG)(TR_QUERY_PACKET_FILTER(
                                                 Adapter->FilterDB,
                                                 Open->NdisFilterHandle));

            }

            break;

        case OID_GEN_CURRENT_LOOKAHEAD:

            if (!GlobalMode){

                GenericULong = Open->LookAhead;

            } else {

                PLIST_ENTRY CurrentLink;
                PIBMTOK_OPEN TempOpen;

                CurrentLink = Adapter->OpenBindings.Flink;

                GenericULong = 0;

                while (CurrentLink != &(Adapter->OpenBindings)){

                    TempOpen = CONTAINING_RECORD(
                             CurrentLink,
                             IBMTOK_OPEN,
                             OpenList
                             );

                    if (TempOpen->LookAhead > GenericULong) {

                        GenericULong = TempOpen->LookAhead;

                        if (GenericULong == IBMTOK_MAX_LOOKAHEAD) {

                            break;

                        }
                    }

                    CurrentLink = CurrentLink->Flink;

                }

            }

            break;

        case OID_802_5_PERMANENT_ADDRESS:

            TR_COPY_NETWORK_ADDRESS((PCHAR)GenericArray,
                                    Adapter->PermanentNetworkAddress);

            MoveSource = (PVOID)(GenericArray);
            MoveBytes = sizeof(Adapter->PermanentNetworkAddress);

            break;

        case OID_802_5_CURRENT_ADDRESS:

            TR_COPY_NETWORK_ADDRESS((PCHAR)GenericArray,
                                    Adapter->NetworkAddress);

            MoveSource = (PVOID)(GenericArray);
            MoveBytes = sizeof(Adapter->NetworkAddress);

            break;

        case OID_802_5_CURRENT_FUNCTIONAL:

            if (!GlobalMode){

                GenericULong = TR_QUERY_FILTER_BINDING_ADDRESS(
                                   Adapter->FilterDB,
                                   Open->NdisFilterHandle);

            } else {

                GenericULong = Adapter->CurrentCardFunctional & 0xffffffff;

            }

            //
            // Now we need to reverse the crazy thing.
            //

            GenericULong = (ULONG)(
                                ((GenericULong >> 24) & 0xFF) |
                                ((GenericULong >> 8)  & 0xFF00) |
                                ((GenericULong << 8)  & 0xFF0000) |
                                ((GenericULong << 24) & 0xFF000000)
                                );

            break;

        case OID_802_5_CURRENT_GROUP:

            GenericULong = Adapter->CurrentCardGroup & 0xffffffff;

            //
            // Now we need to reverse the crazy thing.
            //

            GenericULong = (ULONG)(
                                ((GenericULong >> 24) & 0xFF) |
                                ((GenericULong >> 8)  & 0xFF00) |
                                ((GenericULong << 8)  & 0xFF0000) |
                                ((GenericULong << 24) & 0xFF000000)
                                );

            break;

        default:

            StatusToReturn = NDIS_STATUS_NOT_SUPPORTED;
            break;
    }

    if (StatusToReturn == NDIS_STATUS_SUCCESS){

        if (MoveBytes > BytesLeft){

            //
            // Not enough room in InformationBuffer. Punt
            //

            *BytesNeeded = MoveBytes;

            StatusToReturn = NDIS_STATUS_INVALID_LENGTH;

        } else {

            //
            // Store result.
            //

            IBMTOK_MOVE_MEMORY(InfoBuffer, MoveSource, MoveBytes);

            (*BytesWritten) += MoveBytes;

        }
    }

    return(StatusToReturn);
}

STATIC
NDIS_STATUS
IbmtokQueryInformation(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest
    )
/*++

Routine Description:

    The IbmtokQueryInformation is used by IbmtokRequest to query information
    about the MAC.

Arguments:

    Adapter - A pointer to the adapter.

    Open - A pointer to a particular open instance.

    NdisRequest - A structure which contains the request type (Query),
    an array of operations to perform, and an array for holding
    the results of the operations.

Return Value:

    The function value is the status of the operation.

--*/

{

    UINT BytesWritten = 0;
    UINT BytesNeeded = 0;
    UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
    PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);

    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;


    StatusToReturn = IbmtokQueryProtocolInformation(
                                Adapter,
                                Open,
                                NdisRequest->DATA.QUERY_INFORMATION.Oid,
                                FALSE,
                                InfoBuffer,
                                BytesLeft,
                                &BytesNeeded,
                                &BytesWritten
                                );

    NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;

    NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;

    return(StatusToReturn);
}

STATIC
NDIS_STATUS
IbmtokSetInformation(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest
    )
/*++

Routine Description:

    The IbmtokSetInformation is used by IbmtokRequest to set information
    about the MAC.

Arguments:

    Adapter - A pointer to the adapter.

    Open - A pointer to an open instance.

    NdisRequest - A structure which contains the request type (Set),
    an array of operations to perform, and an array for holding
    the results of the operations.

Return Value:

    The function value is the status of the operation.

--*/

{

    //
    // General Algorithm:
    //
    //     Verify length
    //     Switch(Request)
    //        Process Request
    //

    UINT BytesNeeded = 0;
    UINT BytesLeft = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
    PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);

    //
    // Variables for the request
    //

    NDIS_OID Oid;
    UINT OidLength;

    //
    // Variables for holding the new values to be used.
    //

    ULONG LookAhead;
    ULONG Filter;

    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;


    //
    // Get Oid and Length of request
    //

    Oid = NdisRequest->DATA.SET_INFORMATION.Oid;

    OidLength = BytesLeft;

    //
    // Verify length
    //

    if (OidLength != 4){

        StatusToReturn = NDIS_STATUS_INVALID_LENGTH;

        NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
        NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;

        return(StatusToReturn);
    }

    switch (Oid) {

        case OID_802_5_CURRENT_FUNCTIONAL:

            StatusToReturn = IbmtokChangeFunctionalAddress(
                                        Adapter,
                                        Open,
                                        NdisRequest,
                                        InfoBuffer
                                        );

            break;

        case OID_GEN_CURRENT_PACKET_FILTER:

            IBMTOK_MOVE_MEMORY(&Filter, InfoBuffer, 4);

            StatusToReturn = IbmtokSetPacketFilter(Adapter,
                                                   Open,
                                                   NdisRequest,
                                                   Filter);

            break;

        case OID_802_5_CURRENT_GROUP:

            StatusToReturn = IbmtokSetGroupAddress(
                                        Adapter,
                                        Open,
                                        NdisRequest,
                                        InfoBuffer
                                        );

            break;


        case OID_GEN_PROTOCOL_OPTIONS:

            StatusToReturn = NDIS_STATUS_SUCCESS;

            break;

        case OID_GEN_CURRENT_LOOKAHEAD:

            IBMTOK_MOVE_MEMORY(&LookAhead, InfoBuffer, 4);

            if (LookAhead > IBMTOK_MAX_LOOKAHEAD) {

                StatusToReturn = NDIS_STATUS_INVALID_LENGTH;

            } else {

                if (LookAhead > Adapter->LookAhead) {

                    Open->LookAhead = LookAhead;

                    Adapter->LookAhead = LookAhead;

                } else {

                    if ((Open->LookAhead == Adapter->LookAhead) &&
                        (LookAhead < Open->LookAhead)) {

                        Open->LookAhead = LookAhead;

                        IbmtokAdjustMaxLookAhead(Adapter);

                    } else {

                        Open->LookAhead = LookAhead;

                    }

                }

            }

            break;

        default:

            StatusToReturn = NDIS_STATUS_INVALID_OID;

            NdisRequest->DATA.SET_INFORMATION.BytesRead = 0;
            NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;

            break;
    }

    if (StatusToReturn == NDIS_STATUS_SUCCESS){

        NdisRequest->DATA.SET_INFORMATION.BytesRead = OidLength;
        NdisRequest->DATA.SET_INFORMATION.BytesNeeded = 0;

    }



    return(StatusToReturn);
}

STATIC
NDIS_STATUS
IbmtokSetPacketFilter(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest,
    IN UINT PacketFilter
    )

/*++

Routine Description:

    This routine processes the stages necessary to implement changing
    the packets that a protocol receives from the MAC.

Arguments:

    Adapter - A pointer to the Adapter.

    Open - A pointer to the open instance.

    NdisRequest - A pointer to the request submitting the set command.

    PacketFilter - A bit mask that contains flags that correspond to specific
    classes of received packets.  If a particular bit is set in the mask,
    then packet reception for that class of packet is enabled.  If the
    bit is clear, then packets that fall into that class are not received
    by the client.  A single exception to this rule is that if the promiscuous
    bit is set, then the client receives all packets on the network, regardless
    of the state of the other flags.

Return Value:

    The function value is the status of the operation.

--*/

{

    //
    // Keeps track of the *MAC's* status.  The status will only be
    // reset if the filter change action routine is called.
    //
    NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;

    //
    // Verify bits
    //

    if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
                        NDIS_PACKET_TYPE_MULTICAST |
                        NDIS_PACKET_TYPE_PROMISCUOUS |
                        NDIS_PACKET_TYPE_ALL_MULTICAST |
                        NDIS_PACKET_TYPE_SMT |
                        NDIS_PACKET_TYPE_MAC_FRAME
                       )) {

        return(NDIS_STATUS_NOT_SUPPORTED);

    }

    //
    // Increment the open while it is going through the filtering
    // routines.
    //

    Open->References++;

    StatusOfFilterChange = TrFilterAdjust(
                               Adapter->FilterDB,
                               Open->NdisFilterHandle,
                               NdisRequest,
                               PacketFilter,
                               TRUE
                               );
    Open->References--;

    if (StatusOfFilterChange == NDIS_STATUS_PENDING) {

        //
        // If it pended, it will be in the pend
        // queue so we should start that up.
        //

        IbmtokProcessSrbRequests(Adapter);

    }

    return StatusOfFilterChange;
}

STATIC
NDIS_STATUS
IbmtokChangeFunctionalAddress(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest,
    IN PUCHAR Address
    )

/*++

Routine Description:

    This routine processes the stages necessary to implement changing
    the packets that a protocol receives from the MAC.


    Note: The spin lock must be held before entering this routine.

Arguments:

    Adapter - A pointer to the Adapter.

    Open - A pointer to the open instance.

    NdisRequest - A pointer to the request submitting the set command.

    Address - The new functional address.

Return Value:

    The function value is the status of the operation.

--*/

{

    //
    // Keeps track of the *MAC's* status.  The status will only be
    // reset if the address change action routine is called.
    //
    NDIS_STATUS StatusOfChange = NDIS_STATUS_SUCCESS;

    //
    // Increment the open while it is going through the filtering
    // routines.
    //

    Open->References++;

    StatusOfChange = TrChangeFunctionalAddress(
                              Open->OwningIbmtok->FilterDB,
                              Open->NdisFilterHandle,
                              NdisRequest,
                              Address,
                              TRUE
                              );

    Open->References--;

    if (StatusOfChange == NDIS_STATUS_PENDING) {

        //
        // If it pended, it will be in the pend
        // queue so we should start that up.
        //

        IbmtokProcessSrbRequests(Adapter);

    }

    return StatusOfChange;
}

STATIC
NDIS_STATUS
IbmtokSetGroupAddress(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open,
    IN PNDIS_REQUEST NdisRequest,
    IN PUCHAR Address
    )

/*++

Routine Description:

    This routine processes the stages necessary to implement changing
    the packets that a protocol receives from the MAC.


    Note: The spin lock must be held before entering this routine.

Arguments:

    Adapter - A pointer to the Adapter.

    Open - A pointer to the open instance.

    NdisRequest - A pointer to the request submitting the set command.

    Address - The new group address.

Return Value:

    The function value is the status of the operation.

--*/

{

    //
    // Keeps track of the *MAC's* status.  The status will only be
    // reset if the address change action routine is called.
    //
    NDIS_STATUS StatusOfChange = NDIS_STATUS_SUCCESS;

    //
    // Increment the open while it is going through the filtering
    // routines.
    //

    Open->References++;

    StatusOfChange = TrChangeGroupAddress(
                              Open->OwningIbmtok->FilterDB,
                              Open->NdisFilterHandle,
                              NdisRequest,
                              Address,
                              TRUE
                              );

    Open->References--;

    if (StatusOfChange == NDIS_STATUS_PENDING) {

        //
        // If it pended, it will be in the pend
        // queue so we should start that up.
        //

        IbmtokProcessSrbRequests(Adapter);

    }

    return StatusOfChange;
}

NDIS_STATUS
IbmtokFillInGlobalData(
    IN PIBMTOK_ADAPTER Adapter,
    IN PNDIS_REQUEST NdisRequest
    )

/*++

Routine Description:

    This routine completes a GlobalStatistics request.  It is critical that
    if information is needed from the Adapter->* fields, they have been
    updated before this routine is called.

Arguments:

    Adapter - A pointer to the Adapter.

    NdisRequest - A structure which contains the request type (Global
    Query), an array of operations to perform, and an array for holding
    the results of the operations.

Return Value:

    The function value is the status of the operation.

--*/
{
    //
    //   General Algorithm:
    //
    //      Switch(Request)
    //         Get requested information
    //         Store results in a common variable.
    //      default:
    //         Try protocol query information
    //         If that fails, fail query.
    //
    //      Copy result in common variable to result buffer.
    //   Finish processing

    UINT BytesWritten = 0;
    UINT BytesNeeded = 0;
    UINT BytesLeft = NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength;
    PUCHAR InfoBuffer = (PUCHAR)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer);

    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;

    //
    // This variable holds result of query
    //

    ULONG GenericULong;
    ULONG MoveBytes = sizeof(ULONG) * 2 + sizeof(NDIS_OID);


    StatusToReturn = IbmtokQueryProtocolInformation(
                                    Adapter,
                                    NULL,
                                    NdisRequest->DATA.QUERY_INFORMATION.Oid,
                                    TRUE,
                                    InfoBuffer,
                                    BytesLeft,
                                    &BytesNeeded,
                                    &BytesWritten
                                    );


    if (StatusToReturn == NDIS_STATUS_NOT_SUPPORTED){

        StatusToReturn = NDIS_STATUS_SUCCESS;

        //
        // Switch on request type
        //

        switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {

            case OID_GEN_XMIT_OK:

                GenericULong = (ULONG)(Adapter->FramesTransmitted);

                break;

            case OID_GEN_RCV_OK:

                GenericULong = (ULONG)(Adapter->FramesReceived);

                break;

            case OID_GEN_XMIT_ERROR:

                GenericULong = (ULONG)(Adapter->FrameTransmitErrors);

                break;

            case OID_GEN_RCV_ERROR:

                GenericULong = (ULONG)(Adapter->FrameReceiveErrors);

                break;

            case OID_GEN_RCV_NO_BUFFER:

                GenericULong = (ULONG)(Adapter->ReceiveCongestionCount);

                break;

            case OID_802_5_LINE_ERRORS:

                GenericULong = (ULONG)(Adapter->LineErrors);

                break;

            case OID_802_5_LOST_FRAMES:

                GenericULong = (ULONG)(Adapter->LostFrames);

                break;

            case OID_802_5_LAST_OPEN_STATUS:

                GenericULong = (ULONG)(NDIS_STATUS_TOKEN_RING_OPEN_ERROR |
                                       (NDIS_STATUS)(Adapter->OpenErrorCode));

                break;

            case OID_802_5_CURRENT_RING_STATUS:

                GenericULong = (ULONG)(Adapter->LastNotifyStatus);

                break;

            case OID_802_5_CURRENT_RING_STATE:

                GenericULong = (ULONG)(Adapter->CurrentRingState);

                break;

            default:

                StatusToReturn = NDIS_STATUS_INVALID_OID;

                break;

        }

        if (StatusToReturn == NDIS_STATUS_SUCCESS){

            //
            // Check to make sure there is enough room in the
            // buffer to store the result.
            //

            if (BytesLeft >= sizeof(ULONG)) {

                //
                // Store the result.
                //

                IBMTOK_MOVE_MEMORY(
                           (PVOID)InfoBuffer,
                           (PVOID)(&GenericULong),
                           sizeof(ULONG)
                           );

                BytesWritten += sizeof(ULONG);

            } else {

                BytesNeeded = sizeof(ULONG) - BytesLeft;

                StatusToReturn = NDIS_STATUS_INVALID_LENGTH;

            }

        }

    }

    NdisRequest->DATA.QUERY_INFORMATION.BytesWritten = BytesWritten;

    NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded = BytesNeeded;

    return(StatusToReturn);
}

STATIC
NDIS_STATUS
IbmtokQueryGlobalStatistics(
    IN NDIS_HANDLE MacAdapterContext,
    IN PNDIS_REQUEST NdisRequest
    )

/*++

Routine Description:

    The IbmtokQueryGlobalStatistics is used by the protocol to query
    global information about the MAC.

Arguments:

    MacAdapterContext - The value associated with the adapter that is being
    opened when the MAC registered the adapter with NdisRegisterAdapter.

    NdisRequest - A structure which contains the request type (Query),
    an array of operations to perform, and an array for holding
    the results of the operations.

Return Value:

    The function value is the status of the operation.

--*/

{

    //
    // General Algorithm:
    //
    //
    //   Check if a request is going to pend...
    //      If so, pend the entire operation.
    //
    //   Else
    //      Fill in the request block.
    //
    //

    PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);

    NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;

    //
    //   Check if a request is valid and going to pend...
    //      If so, pend the entire operation.
    //

    NdisInterlockedAddUlong((PULONG)&Adapter->References, 1 ,&(Adapter->Lock));

    //
    // Switch on request type
    //

    switch (NdisRequest->DATA.QUERY_INFORMATION.Oid) {
        case OID_GEN_SUPPORTED_LIST:
        case OID_GEN_HARDWARE_STATUS:
        case OID_GEN_MEDIA_SUPPORTED:
        case OID_GEN_MEDIA_IN_USE:
        case OID_GEN_MAXIMUM_LOOKAHEAD:
        case OID_GEN_MAXIMUM_FRAME_SIZE:
        case OID_GEN_MAXIMUM_TOTAL_SIZE:
        case OID_GEN_MAC_OPTIONS:
        case OID_GEN_LINK_SPEED:
        case OID_GEN_TRANSMIT_BUFFER_SPACE:
        case OID_GEN_RECEIVE_BUFFER_SPACE:
        case OID_GEN_TRANSMIT_BLOCK_SIZE:
        case OID_GEN_RECEIVE_BLOCK_SIZE:
        case OID_GEN_VENDOR_ID:
        case OID_GEN_DRIVER_VERSION:
        case OID_GEN_CURRENT_PACKET_FILTER:
        case OID_GEN_CURRENT_LOOKAHEAD:
        case OID_802_5_CURRENT_GROUP:
        case OID_802_5_LAST_OPEN_STATUS:
        case OID_802_5_CURRENT_RING_STATUS:
        case OID_802_5_CURRENT_RING_STATE:
        case OID_802_5_PERMANENT_ADDRESS:
        case OID_802_5_CURRENT_ADDRESS:
        case OID_802_5_CURRENT_FUNCTIONAL:
            break;

        case OID_GEN_XMIT_OK:
        case OID_GEN_RCV_OK:
        case OID_GEN_XMIT_ERROR:
        case OID_GEN_RCV_ERROR:
        case OID_GEN_RCV_NO_BUFFER:
        case OID_802_5_LINE_ERRORS:
        case OID_802_5_LOST_FRAMES:

            StatusToReturn = NDIS_STATUS_PENDING;

            break;

        default:

            StatusToReturn = NDIS_STATUS_INVALID_OID;

            break;
    }

    if (StatusToReturn == NDIS_STATUS_PENDING) {

        //
        // Build a pending operation
        //

        PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);

        PendOp->Next = NULL;
        PendOp->COMMAND.NDIS.STATISTICS.ReadLogPending = FALSE;

        NdisAcquireSpinLock(&Adapter->Lock);

        if (Adapter->PendQueue == NULL){

            Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;

        } else {

            Adapter->EndOfPendQueue->Next = PendOp;

        }


        //
        // It is now in the pend
        // queue so we should start that up.
        //

        IbmtokProcessSrbRequests(Adapter);

        NdisReleaseSpinLock(&Adapter->Lock);

        //
        // Defer subtracting from Adapter->Reference until the
        // request completes (see IbmtokFinishPendQueueOp()).
        //

        return(StatusToReturn);

    }

    if (StatusToReturn == NDIS_STATUS_SUCCESS){

        StatusToReturn = IbmtokFillInGlobalData(Adapter, NdisRequest);

    }

    NdisAcquireSpinLock(&Adapter->Lock);

    IBMTOK_DO_DEFERRED(Adapter);

    return(StatusToReturn);
}

STATIC
NDIS_STATUS
IbmtokReset(
    IN NDIS_HANDLE MacBindingHandle
    )

/*++

Routine Description:

    The IbmtokReset request instructs the MAC to issue a hardware reset
    to the network adapter.  The MAC also resets its software state.  See
    the description of NdisReset for a detailed description of this request.

Arguments:

    MacBindingHandle - The context value returned by the MAC  when the
    adapter was opened.  In reality, it is a pointer to IBMTOK_OPEN.

Return Value:

    The function value is the status of the operation.


--*/

{

    //
    // Holds the status that should be returned to the caller.
    //
    NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;

    PIBMTOK_ADAPTER Adapter =
        PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);

    PIBMTOK_OPEN Open;

    //
    // Hold the locks while we update the reference counts on the
    // adapter and the open.
    //

    NdisAcquireSpinLock(&Adapter->Lock);
    Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);

    Adapter->References++;

    if (Adapter->ResetInProgress) {

        StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;

    } else if (Adapter->AdapterNotOpen) {

        StatusToReturn = NDIS_STATUS_FAILURE;

    } else {

        if (!Open->BindingShuttingDown) {

            Open->References++;
            IbmtokSetupForReset(
                Adapter,
                PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)
                );
            Open->References--;

        } else {

            StatusToReturn = NDIS_STATUS_CLOSING;

        }

    }

    //
    // This macro assumes it is called with the lock held,
    // and releases it.
    //

    IBMTOK_DO_DEFERRED(Adapter);
    return StatusToReturn;

}

STATIC
NDIS_STATUS
IbmtokChangeFilter(
    IN UINT OldFilterClasses,
    IN UINT NewFilterClasses,
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN BOOLEAN Set
    )

/*++

Routine Description:

    Action routine that will get called when a particular filter
    class is first used or last cleared.

    NOTE: This routine assumes that it is called with the lock
    acquired.

Arguments:

    OldFilterClasses - The values of the class filter before it
    was changed.

    NewFilterClasses - The current value of the class filter

    MacBindingHandle - The context value returned by the MAC  when the
    adapter was opened.  In reality, it is a pointer to IBMTOK_OPEN.

    Set - If true the change resulted from a set, otherwise the
    change resulted from a open closing.

Return Value:

    None.

--*/

{


    PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);

    //
    // The open that made this request.
    //
    PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);

    //
    // Holds the change that should be returned to the filtering package.
    //
    NDIS_STATUS StatusOfChange;

    if (NdisRequest == NULL) {

        NdisRequest = &(Open->CloseRequestChangeFilter);

        NdisRequest->RequestType = NdisRequestClose;


    }


    if (Adapter->ResetInProgress) {

        StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;

    } else {

        //
        // The whole purpose of this routine is to determine whether
        // the filtering changes need to result in the hardware being
        // reset.
        //

        ASSERT(OldFilterClasses != NewFilterClasses);

#if DBG
        if (IbmtokDbg) DbgPrint("IBMTOK: Change filter\n");
#endif

        if (NewFilterClasses &
            (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_SOURCE_ROUTING)) {

            //
            // The adapter cannot support promiscuous mode, or
            // source routing which implies promiscuous.
            //

            StatusOfChange = NDIS_STATUS_FAILURE;

        } else {

            //
            // Queue this request.
            //

            PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);

            //
            // Store open block.
            //

            PendOp->COMMAND.NDIS.SET_FILTER.Open = Open;

            //
            // Hold new Filter value
            //

            if (PendOp->RequestType == NdisRequestClose){

                PendOp->COMMAND.NDIS.CLOSE.NewFilterValue = NewFilterClasses;

            } else {

                PendOp->COMMAND.NDIS.SET_FILTER.NewFilterValue = NewFilterClasses;

            }


            //
            // Insert into queue.
            //

            PendOp->Next = NULL;

            if (Adapter->PendQueue == NULL) {

                Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;

            } else {

                Adapter->EndOfPendQueue->Next = PendOp;

            }

            Open->References++;

            StatusOfChange = NDIS_STATUS_PENDING;


        }

    }

    return StatusOfChange;

}

STATIC
NDIS_STATUS
IbmtokChangeAddress(
    IN TR_FUNCTIONAL_ADDRESS OldFunctionalAddress,
    IN TR_FUNCTIONAL_ADDRESS NewFunctionalAddress,
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN BOOLEAN Set
    )


/*++

Routine Description:

    Action routine that will get called when an address is added to
    the filter that wasn't referenced by any other open binding.

    NOTE: This routine assumes that it is called with the lock
    acquired.

Arguments:

    OldFunctionalAddress - The previous functional address.

    NewFunctionalAddress - The new functional address.

    MacBindingHandle - The context value returned by the MAC  when the
    adapter was opened.  In reality, it is a pointer to IBMTOK_OPEN.

    NdisRequest - A pointer to the Request that submitted the set command.

    Set - If true the change resulted from a set, otherwise the
    change resulted from a open closing.

Return Value:

    None.


--*/

{

    PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);

    //
    // Holds the status that should be returned to the filtering package.
    //
    NDIS_STATUS StatusOfChange;

    //
    // The open that made this request.
    //
    PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);

#if DBG
    if (IbmtokDbg) {
        DbgPrint("IBMTOK: Queueing:\n");
        DbgPrint("   Req  : 0x%x\n", NdisRequest);
        DbgPrint("   Old  : 0x%x\n", OldFunctionalAddress);
        DbgPrint("   New  : 0x%x\n", NewFunctionalAddress);
    }
#endif

    // Check to see if the device is already resetting.  If it is
    // then reject this change.
    //

    if (NdisRequest == NULL) {

        NdisRequest = &(Open->CloseRequestChangeAddress);

        NdisRequest->RequestType = NdisRequestGeneric2;  // Close, set address

    }


    if (Adapter->ResetInProgress) {

#if DBG
        if (IbmtokDbg) {
            DbgPrint("IBMTOK: ResetInProgress\n\n");
        }
#endif

        StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;

    } else {

        //
        // Queue this request.
        //

        PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);


        //
        // Store open block.
        //

        PendOp->COMMAND.NDIS.SET_ADDRESS.Open = Open;

        //
        // Hold new Address value
        //

        PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue = NewFunctionalAddress;


        //
        // Insert into queue.
        //

        PendOp->Next = NULL;

        if (Adapter->PendQueue == NULL) {

            Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;

        } else {

            Adapter->EndOfPendQueue->Next = PendOp;

        }

        Open->References++;

        StatusOfChange = NDIS_STATUS_PENDING;

    }

    return StatusOfChange;

}

STATIC
NDIS_STATUS
IbmtokChangeGroupAddress(
    IN TR_FUNCTIONAL_ADDRESS OldGroupAddress,
    IN TR_FUNCTIONAL_ADDRESS NewGroupAddress,
    IN NDIS_HANDLE MacBindingHandle,
    IN PNDIS_REQUEST NdisRequest,
    IN BOOLEAN Set
    )

/*++

Routine Description:

    Action routine that will get called when a group address is to
    be changed.

    NOTE: This routine assumes that it is called with the lock
    acquired.

Arguments:

    OldGroupAddress - The previous group address.

    NewGroupAddress - The new group address.

    MacBindingHandle - The context value returned by the MAC  when the
    adapter was opened.  In reality, it is a pointer to IBMTOK_OPEN.

    NdisRequest - A pointer to the Request that submitted the set command.

    Set - If true the change resulted from a set, otherwise the
    change resulted from a open closing.

Return Value:

    None.


--*/

{

    PIBMTOK_ADAPTER Adapter = PIBMTOK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);

    //
    // Holds the status that should be returned to the filtering package.
    //
    NDIS_STATUS StatusOfChange;

    //
    // The open that made this request.
    //
    PIBMTOK_OPEN Open = PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);


    if (NdisRequest == NULL) {

        NdisRequest = &(Open->CloseRequestChangeGroupAddress);

        NdisRequest->RequestType = NdisRequestGeneric3;  // Close, set group address

    }


    //
    // Check to see if the device is already resetting.  If it is
    // then reject this change.
    //

    if (Adapter->ResetInProgress) {

        StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;

    } else {

        //
        // Queue this request.
        //

        PIBMTOK_PEND_DATA PendOp = PIBMTOK_PEND_DATA_FROM_PNDIS_REQUEST(NdisRequest);


        //
        // Store open block.
        //

        PendOp->COMMAND.NDIS.SET_ADDRESS.Open = Open;

        //
        // Hold new Address value
        //

        PendOp->COMMAND.NDIS.SET_ADDRESS.NewAddressValue = NewGroupAddress;


        //
        // Insert into queue.
        //

        PendOp->Next = NULL;

        if (Adapter->PendQueue == NULL) {

            Adapter->PendQueue = Adapter->EndOfPendQueue = PendOp;

        } else {

            Adapter->EndOfPendQueue->Next = PendOp;

        }

        Open->References++;

        StatusOfChange = NDIS_STATUS_PENDING;

    }

    return StatusOfChange;

}

STATIC
VOID
IbmtokCloseAction(
    IN NDIS_HANDLE MacBindingHandle
    )

/*++

Routine Description:

    Action routine that will get called when a particular binding
    was closed while it was indicating through NdisIndicateReceive

    All this routine needs to do is to decrement the reference count
    of the binding.

    NOTE: This routine assumes that it is called with the lock acquired.

Arguments:

    MacBindingHandle - The context value returned by the MAC  when the
    adapter was opened.  In reality, it is a pointer to IBMTOK_OPEN.

Return Value:

    None.


--*/

{

    PIBMTOK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;

}

extern
VOID
IbmtokStartAdapterReset(
    IN PIBMTOK_ADAPTER Adapter
    )

/*++

Routine Description:

    This is the first phase of resetting the adapter hardware.

    It makes the following assumptions:

    1) That the hardware has been stopped.

    2) That it can not be preempted.

    3) That no other adapter activity can occur.

    When this routine is finished all of the adapter information
    will be as if the driver was just initialized.

Arguments:

    Adapter - The adapter whose hardware is to be reset.

Return Value:

    None.

--*/
{

    //
    // Disable these so no pending interrupts
    // will fire.
    //
    CLEAR_ISRP_BITS(Adapter);

    //
    // OK, do the reset as detailed in the Tech Ref...
    //

    WRITE_ADAPTER_PORT(Adapter, RESET_LATCH, 0);

    NdisStallExecution(50000);

    WRITE_ADAPTER_PORT(Adapter, RESET_RELEASE, 0);

    //
    // Have to write this now to enable Shared RAM paging.
    //
    if (Adapter->SharedRamPaging) {

        WRITE_ADAPTER_REGISTER(Adapter, SRPR_LOW, 0xc0);

    }



    //
    // If this is a PC I/O Bus....
    // Set up the shared RAM to be right after the MMIO.
    //

    if (Adapter->UsingPcIoBus){
        WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue);
    }



    //
    // Allow the reset complete interrupt to be
    // serviced correctly.
    //
    SET_INTERRUPT_RESET_FLAG(Adapter);

    //
    // Enable card interrupts to get the reset interrupt.
    //

    WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW,
                ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);


    //
    // The remaining processing is done in the
    // interrupt handler.
    //



    //
    // OK, now abort pending requests before we nuke
    // everything.
    //

    NdisDprAcquireSpinLock (&Adapter->Lock);

    IbmtokAbortSends (Adapter, NDIS_STATUS_REQUEST_ABORTED);

    NdisDprReleaseSpinLock (&Adapter->Lock);

}

extern
VOID
IbmtokFinishAdapterReset(
    IN PIBMTOK_ADAPTER Adapter
    )

/*++

Routine Description:

    Called by HandleResetStaging when the last piece
    of the adapter reset is complete and normal
    operation can resume.

    Called with the lock held and returns with it held.

Arguments:

    Adapter - The adapter that the reset is for.

Return Value:

    None.

--*/

{
    PLIST_ENTRY CurrentLink;
    PIBMTOK_OPEN TempOpen;


    SetResetVariables(Adapter);

    if (Adapter->UnpluggedResetInProgress) {
        Adapter->UnpluggedResetInProgress = FALSE;
        Adapter->Unplugged = FALSE;
        Adapter->LobeWireFaultIndicated = FALSE;
    }

    Adapter->ResetInProgress = FALSE;
    Adapter->ResetInterruptAllowed = FALSE;
    Adapter->ResetInterruptHasArrived = FALSE;
    Adapter->NotAcceptingRequests = FALSE;

    //
    // Get any interrupts that have been deferred
    // while NotAcceptingRequests was TRUE.
    //
    IbmtokForceAdapterInterrupt(Adapter);

    if (Adapter->ResettingOpen != NULL) {

        PIBMTOK_OPEN ResettingOpen = Adapter->ResettingOpen;

        //
        // Indicate reset complete to everybody
        //

        CurrentLink = Adapter->OpenBindings.Flink;

        while (CurrentLink != &(Adapter->OpenBindings)){

            TempOpen = CONTAINING_RECORD(
                                 CurrentLink,
                                 IBMTOK_OPEN,
                                 OpenList
                                 );

            NdisReleaseSpinLock(&Adapter->Lock);

            NdisIndicateStatus(TempOpen->NdisBindingContext,
                               NDIS_STATUS_RESET_END,
                               NULL,
                               0
                              );

            NdisIndicateStatusComplete(TempOpen->NdisBindingContext);

            NdisAcquireSpinLock(&Adapter->Lock);

            CurrentLink = CurrentLink->Flink;

        }

        //
        // Decrement the reference count that was incremented
        // in SetupForReset.
        //
        ResettingOpen->References--;

        NdisReleaseSpinLock(&Adapter->Lock);

        NdisCompleteReset(
            ResettingOpen->NdisBindingContext,
            NDIS_STATUS_SUCCESS
            );

        NdisAcquireSpinLock(&Adapter->Lock);

    }

}

STATIC
VOID
IbmtokSetupRegistersAndInit(
    IN PIBMTOK_ADAPTER Adapter
    )

/*++

Routine Description:

    It is this routines responsibility to make sure that the
    initialization block is filled and the chip is initialized
    *but not* started.

    NOTE: This routine assumes that it is called with the lock
    acquired OR that only a single thread of execution is working
    with this particular adapter.

Arguments:

    Adapter - The adapter whose hardware is to be initialized.

Return Value:

    None.

--*/
{

    //
    // Enable card interrupts to get the reset interrupt.
    //

    WRITE_ADAPTER_REGISTER(Adapter, ISRP_LOW,
                ISRP_LOW_NO_CHANNEL_CHECK | ISRP_LOW_INTERRUPT_ENABLE);

    //
    // Set the timer to 10 milliseconds...this seems to
    // be necessary for proper operation (according to
    // ChandanC).
    //

    WRITE_ADAPTER_REGISTER(Adapter, TVR_HIGH, 0x01);


    //
    // Start the timer and set it to reload, but not to
    // interrupt us (TCR_LOW_INTERRUPT_MASK is off). This
    // will still cause bit 4 in the ISRP Low to go on,
    // but it won't cause an interrupt.
    //

#if 0
    WRITE_ADAPTER_REGISTER(Adapter, TCR_LOW,
//              TCR_LOW_INTERRUPT_MASK |
                TCR_LOW_RELOAD_TIMER | TCR_LOW_COUNTER_ENABLE);
#endif
    WRITE_ADAPTER_REGISTER(Adapter, TCR_LOW, 0);



    //
    // If this is a PC I/O Bus...
    // Set up the shared RAM to be right after the MMIO.
    //

    if (Adapter->UsingPcIoBus) {
        WRITE_ADAPTER_REGISTER(Adapter, RRR_LOW, Adapter->RrrLowValue);
    }


    //
    // The remaining initialization processing is done in
    // the interrupt handler.
    //

}

VOID
IbmtokSetupForReset(
    IN PIBMTOK_ADAPTER Adapter,
    IN PIBMTOK_OPEN Open
    )

/*++

Routine Description:

    This routine is used to fill in the who and why a reset is
    being set up as well as setting the appropriate fields in the
    adapter.

    NOTE: This routine must be called with the lock acquired.

Arguments:

    Adapter - The adapter whose hardware is to be initialized.

    Open - A (possibly NULL) pointer to an sonic open structure.
    The reason it could be null is if the adapter is initiating the
    reset on its own.

Return Value:

    None.

--*/
{
    //
    // Notify of reset start
    //

    PLIST_ENTRY CurrentLink;
    PIBMTOK_OPEN TempOpen;

    if (Open != NULL) {

        CurrentLink = Adapter->OpenBindings.Flink;

        while (CurrentLink != &(Adapter->OpenBindings)){

            TempOpen = CONTAINING_RECORD(
                                 CurrentLink,
                                 IBMTOK_OPEN,
                                 OpenList
                                 );

            NdisReleaseSpinLock(&Adapter->Lock);

            NdisIndicateStatus(TempOpen->NdisBindingContext,
                               NDIS_STATUS_RESET_START,
                               NULL,
                               0
                              );

            NdisAcquireSpinLock(&Adapter->Lock);

            CurrentLink = CurrentLink->Flink;

        }
    }


    Adapter->ResetInProgress = TRUE;
    Adapter->NotAcceptingRequests = TRUE;

    Adapter->ResettingOpen = Open;

    //
    // This will go to 1 when StartAdapterReset is called.
    //
    Adapter->CurrentResetStage = 0;

    //
    // If there is a valid open we should up the reference count
    // so that the open can't be deleted before we indicate that
    // their request is finished.
    //

    if (Open != NULL) {

        Open->References++;

    }

}

NDIS_STATUS
IbmtokAddAdapter(
    IN NDIS_HANDLE MacMacContext,
    IN NDIS_HANDLE ConfigurationHandle,
    IN PNDIS_STRING AdapterName
    )

/*++

Routine Description:

    This routine is used to initialize each adapter card/chip.

Arguments:

    see NDIS 3.0 spec...

Return Value:


    NDIS_STATUS_SUCCESS - Adapter was successfully added.
    NDIS_STATUS_FAILURE - Adapter was not added, also MAC deregistered.

--*/

{
    PIBMTOK_ADAPTER Adapter;

    NDIS_HANDLE ConfigHandle;
    PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
    NDIS_STRING BusTypeStr = NDIS_STRING_CONST("BusType");
    NDIS_STRING IOAddressStr = NDIS_STRING_CONST("IoBaseAddress");
    NDIS_STRING NetworkAddressStr = NDIS_STRING_CONST("NetworkAddress");
    NDIS_STRING PacketSizeStr = NDIS_STRING_CONST("MaximumPacketSize");

    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

    BOOLEAN PrimaryAdapter = TRUE;
    BOOLEAN ConfigError = FALSE;
    BOOLEAN McaCard = FALSE;

    UINT SlotNumber;
    NDIS_MCA_POS_DATA McaData;

    PVOID NetAddress;
    ULONG Length;

    //
    // Allocate the Adapter block.
    //

    if (IBMTOK_ALLOC_PHYS(&Adapter, sizeof(IBMTOK_ADAPTER)) !=
        NDIS_STATUS_SUCCESS) {

        return(NDIS_STATUS_RESOURCES);

    }


    IBMTOK_ZERO_MEMORY(
            Adapter,
            sizeof(IBMTOK_ADAPTER)
            );

    Adapter->MaxTransmittablePacket = 17960;
    Adapter->CurrentRingState = NdisRingStateClosed;

    Adapter->NdisMacHandle = ((PIBMTOK_MAC)MacMacContext)->NdisMacHandle;


    NdisOpenConfiguration(
                    &Status,
                    &ConfigHandle,
                    ConfigurationHandle
                    );

    if (Status != NDIS_STATUS_SUCCESS) {

        IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER));

        return NDIS_STATUS_FAILURE;

    }

    //
    // Read Bus Type
    //

    NdisReadConfiguration(
                    &Status,
                    &ReturnedValue,
                    ConfigHandle,
                    &BusTypeStr,
                    NdisParameterHexInteger
                    );

    if (Status == NDIS_STATUS_SUCCESS) {

        if (ReturnedValue->ParameterData.IntegerData == (ULONG)NdisInterfaceMca) {

            McaCard = TRUE;

        }

    }

    //
    // Get I/O Address
    //

    if (McaCard) {

        //
        // Get I/O Address from Mca Pos info.
        //

        NdisReadMcaPosInformation(
                    &Status,
                    ConfigurationHandle,
                    &SlotNumber,
                    &McaData
                    );

        if (Status != NDIS_STATUS_SUCCESS) {

            ConfigError = TRUE;
            goto RegisterAdapter;

        }

        //
        // Now interperet the data
        //

        switch (McaData.PosData2 & 0x1) {
            case 0x00:
                Adapter->IbmtokPortAddress = PRIMARY_ADAPTER_OFFSET;
                break;

            case 0x01:
                Adapter->IbmtokPortAddress = ALTERNATE_ADAPTER_OFFSET;
                break;

        }

    } else {

        //
        // Read I/O Address
        //

        NdisReadConfiguration(
                        &Status,
                        &ReturnedValue,
                        ConfigHandle,
                        &IOAddressStr,
                        NdisParameterInteger
                        );

        if (Status == NDIS_STATUS_SUCCESS) {

            PrimaryAdapter = (ReturnedValue->ParameterData.IntegerData == 1)?TRUE:FALSE;

        }

        if (PrimaryAdapter) {

            Adapter->IbmtokPortAddress = PRIMARY_ADAPTER_OFFSET;

        } else {

            Adapter->IbmtokPortAddress = ALTERNATE_ADAPTER_OFFSET;

        }

    }

    //
    // Read PacketSize
    //

    NdisReadConfiguration(
                    &Status,
                    &ReturnedValue,
                    ConfigHandle,
                    &PacketSizeStr,
                    NdisParameterInteger
                    );

    if (Status == NDIS_STATUS_SUCCESS) {

        Adapter->MaxTransmittablePacket = ReturnedValue->ParameterData.IntegerData;

    }


    //
    // Read net address
    //

    NdisReadNetworkAddress(
                    &Status,
                    &NetAddress,
                    &Length,
                    ConfigHandle
                    );

    if ((Length == TR_LENGTH_OF_ADDRESS) && (Status == NDIS_STATUS_SUCCESS)) {

        TR_COPY_NETWORK_ADDRESS(
                Adapter->NetworkAddress,
                NetAddress
                );

    }

RegisterAdapter:

    NdisCloseConfiguration(ConfigHandle);

    Status = IbmtokRegisterAdapter(
                     Adapter,
                     ConfigurationHandle,
                     AdapterName,
                     McaCard,
                     ConfigError
                     );

    if (Status != NDIS_STATUS_SUCCESS) {

        IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER));

    }

    return Status;

}

VOID
IbmtokRemoveAdapter(
    IN PVOID MacAdapterContext
    )


/*++

Routine Description:

    This routine is called when an adapter is to be removed.

Arguments:

    MacAdapterContext - Pointer to global list of adapter blocks.

Return Value:

    None

--*/

{
    PIBMTOK_ADAPTER Adapter;
    BOOLEAN Canceled;

    Adapter = PIBMTOK_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);

    //
    // There are no opens left, so remove ourselves.
    //

    NdisCancelTimer(&Adapter->WakeUpTimer, &Canceled);

    if ( !Canceled ) {

        NdisStallExecution(500000);
    }

    NdisRemoveInterrupt(&(Adapter->Interrupt));

    NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
                     Adapter->SharedRam,
                     (Adapter->MappedSharedRam == 0x10000) ?
                       0x8000 :
                       Adapter->MappedSharedRam
                    );

    TrDeleteFilter(Adapter->FilterDB);

    NdisFreeSpinLock(&Adapter->Lock);

    NdisDeregisterAdapter(Adapter->NdisAdapterHandle);

    IBMTOK_FREE_PHYS(Adapter, sizeof(IBMTOK_ADAPTER));

    return;

}

VOID
IbmtokUnload(
    IN NDIS_HANDLE MacMacContext
    )

/*++

Routine Description:

    IbmtokUnload is called when the MAC is to unload itself.

Arguments:

    MacMacContext - nothing.

Return Value:

    None.

--*/

{
    NDIS_STATUS InitStatus;

    UNREFERENCED_PARAMETER(MacMacContext);

    NdisDeregisterMac(
            &InitStatus,
            ((PIBMTOK_MAC)MacMacContext)->NdisMacHandle
            );

    NdisTerminateWrapper(
            ((PIBMTOK_MAC)MacMacContext)->NdisWrapperHandle,
            NULL
            );

    return;
}

STATIC
BOOLEAN
IbmtokHardwareDetails(
    IN PIBMTOK_ADAPTER Adapter
    )

/*++

Routine Description:

    This routine gets the MMIO address and interrupt level.
    It also maps the MMIO and Shared RAM.

Arguments:

    Adapter - Where to store the network address.

Return Value:

    TRUE if successful.

--*/

{

    NDIS_STATUS Status;

    //
    // Holds the value read from the SWITCH_READ_1 port.
    //
    UCHAR SwitchRead1;

    //
    // Holds the value read from the SWITCH_READ_2 port in
    // the Microchannel Bus.
    //
    UCHAR SwitchRead2;

    //
    // Holds the physical address of the MMIO region.
    //
    ULONG MmioAddress;

    NDIS_PHYSICAL_ADDRESS PhysicalAddress;

    //
    // The interrupt level;
    //
    UINT InterruptLevel;

    //
    // The RRR bits indicating the Shared RAM size:
    // 0 = 8K, 1 = 16K, 2 = 32K, 3 = 64K.
    //
    UCHAR SharedRamBits;

    //
    // The actual size of Shared RAM from RRR bits 2,3 in
    // the PC I/O Bus adapter.
    //
    UINT RrrSharedRamSize;

    //
    // Common variable for storing total Shared RAM Size.
    //
    UINT SharedRamSize;

    //
    // The actual address of Shared RAM from the SWITCH_READ_2
    // port in the Microchannel adapter.
    //
    UINT McaSharedRam;

    //
    // The boundary needed for the Shared RAM mapping.
    //
    UCHAR BoundaryNeeded;

    //
    // The value read from the Shared RAM paging byte of
    // the AIP.
    //
    UCHAR AipSharedRamPaging;

    UCHAR RegValue;

    //
    // SwitchRead1 contains the interrupt code in the low 2 bits,
    // and bits 18 through 13 of the MMIO address in the high
    // 6 bits.
    //

    READ_ADAPTER_PORT(Adapter, SWITCH_READ_1, &SwitchRead1);

    //
    // SwitchRead2 contains Bit 19 of the MMIO address in the
    // low bit.  It is always 1 for PC I/O Bus and possibly 0
    // for the Microchannel bus
    //

    READ_ADAPTER_PORT(Adapter, SWITCH_READ_2, &SwitchRead2);

    //
    // To compute MmioAddress, we mask off the low 2 bits of
    // SwitchRead1, shift it out by 11 (so that the high 6 bits
    // are moved to the right place), and add in the 19th bit value.
    //

    MmioAddress = ((SwitchRead1 & 0xfc) << 11) | ((SwitchRead2 & 1) << 19);

    NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
    NdisSetPhysicalAddressLow(PhysicalAddress, MmioAddress);

    NdisMapIoSpace(
                   &Status,
                   (PVOID *)&(Adapter->MmioRegion),
                   Adapter->NdisAdapterHandle,
                   PhysicalAddress,
                   0x2000);

    if (Status != NDIS_STATUS_SUCCESS) {

        NdisWriteErrorLogEntry(
           Adapter->NdisAdapterHandle,
           NDIS_ERROR_CODE_RESOURCE_CONFLICT,
           0
           );

        return(FALSE);

    }


    //
    // Now we have mapped the MMIO, look at the AIP. First
    // determine the channel identifier.
    //

    {
        //
        // Will hold the Adapter ID as read from the card.
        //
        ULONG AdapterId[3];

        //
        // What AdapterId should contain for a PC I/O bus card.
        //
        static ULONG PcIoBusId[3] = { 0x5049434f, 0x36313130, 0x39393020 };

        //
        // What AdapterId should contain for a Micro Channel card.
        //
        static ULONG MicroChannelId[3] = { 0x4d415253, 0x36335834, 0x35313820 };

        //
        // Loop counters.
        //
        UINT i, j;

        UCHAR TmpUchar;

        //
        // Read in AdapterId.
        //
        // Turns out that the bytes which identify the card are stored
        // in a very odd manner.  There are 48 bytes on the card.  The
        // even numbered bytes contain 4 bits of the card signature.
        //

        for (i=0; i<3; i++) {

            AdapterId[i] = 0;

            for (j=0; j<16; j+=2) {

                READ_ADAPTER_REGISTER(Adapter,
                                      CHANNEL_IDENTIFIER + (i*16 + j),
                                      &TmpUchar
                                     );

                AdapterId[i] = (AdapterId[i] << 4) + TmpUchar;


            }

        }

        if ((AdapterId[0] == PcIoBusId[0]) &&
            (AdapterId[1] == PcIoBusId[1]) &&
            (AdapterId[2] == PcIoBusId[2])) {

            Adapter->UsingPcIoBus = TRUE;

        } else if ((AdapterId[0] == MicroChannelId[0]) &&
                   (AdapterId[1] == MicroChannelId[1]) &&
                   (AdapterId[2] == MicroChannelId[2])) {

            Adapter->UsingPcIoBus = FALSE;

        } else {

            //
            // Unknown channel type.
            //


            NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
                             Adapter->MmioRegion,
                             0x2000);

            NdisWriteErrorLogEntry(
                Adapter->NdisAdapterHandle,
                NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS,
                0
                );

            return FALSE;

        }

    }

    //
    // We can read the network address from the AIP but we won't,
    // we read it from the bring-up SRB instead.
    //

    //
    // Read the RRR High to get the Shared RAM size (we are
    // only interested in bits 2 and 3).
    //

    READ_ADAPTER_REGISTER(Adapter, RRR_HIGH, &SharedRamBits);

    SharedRamBits = ((SharedRamBits & 0x0c) >> 2);

    if (Adapter->UsingPcIoBus) {

        //
        // Here we have to tell the Adapter where Shared RAM is
        // going to be.  To do this we first find the lowest
        // address it could be at, and then advance the address
        // such that it falls on a correct page boudary.
        //


        //
        // To get value to put in RRR Low, which indicates where
        // the Shared RAM is mapped, we first compute the lowest
        // possible value, which is right after the MMIO region.
        // We take the high six bits of SwitchRead and shift
        // them right one (so bits 18-13 of the address are in
        // bits 6-1), then we turn on bit 7 to indicate that bit
        // 19 of the address is on, and leave bit 0 zero since
        // it must be.
        //

        Adapter->RrrLowValue = (UCHAR)
                              ((((SwitchRead1 & 0xfc) >> 1) | 0x80) + 0x02);

        //
        // We now have to move up to a memory boundary
        // based on the value of SharedRamBits; 0 (8K) = 16K boundary,
        // 1 (16K) = 16K boundary, 2 (32K) = 32K boundary, and
        // 3 (64K) = 64K Boundary. Remember that the way the
        // address bits are shifted over in RrrLowValue, bit 1
        // is really bit 13 of the final address (turning it on
        // adds 8K), bit 2 if bit 14, etc. We compute Boundary
        // Needed in this frame of reference.
        //

        switch (SharedRamBits) {

            case 0:
            case 1:

                //
                // 8K or 16K needs a 16K boundary.
                //

                RrrSharedRamSize = (SharedRamBits == 0) ? 0x2000 : 0x4000;
                BoundaryNeeded = 0x04;
                break;

            case 2:

                //
                // 32K needs a 32K boundary.
                //

                RrrSharedRamSize = 0x8000;
                BoundaryNeeded = 0x08;
                break;

            case 3:

                //
                // 64K needs a 64K boundary.
                //

                RrrSharedRamSize = 0x10000;
                BoundaryNeeded = 0x10;
                break;

        }


        //
        // If RrrLowValue is not on the proper boundary, move it
        // forward until it is.
        //

        if (Adapter->RrrLowValue & (BoundaryNeeded-1)) {

            Adapter->RrrLowValue = (UCHAR)
              ((Adapter->RrrLowValue & ~(BoundaryNeeded-1)) + BoundaryNeeded);

        }

        Adapter->MappedSharedRam = SharedRamSize = RrrSharedRamSize;

        NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
        NdisSetPhysicalAddressLow(PhysicalAddress, Adapter->RrrLowValue << 12);

        NdisMapIoSpace(&Status,
                       (PVOID *)&(Adapter->SharedRam),
                       Adapter->NdisAdapterHandle,
                       PhysicalAddress,
                       RrrSharedRamSize
                      );

        if (Status != NDIS_STATUS_SUCCESS) {

            NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
                             Adapter->MmioRegion,
                             0x2000);

            NdisWriteErrorLogEntry(
                Adapter->NdisAdapterHandle,
                NDIS_ERROR_CODE_RESOURCE_CONFLICT,
                0
                );

            return(FALSE);

        }

    } else {

        //
        // Using Microchannel
        //
        // No need to set Adapter->RrrLowValue since it is not
        // used in the Microchannel adapter.
        //

        switch (SharedRamBits){
            case 0:
                SharedRamSize = 0x2000;
                break;
            case 1:
                SharedRamSize = 0x4000;
                break;
            case 2:
                SharedRamSize = 0x8000;
                break;
            case 3:
                SharedRamSize = 0x10000;
                break;
        }

        McaSharedRam = ((SwitchRead2 & 0xfe) << 12);

        NdisSetPhysicalAddressHigh(PhysicalAddress, 0);
        NdisSetPhysicalAddressLow(PhysicalAddress, McaSharedRam);

        NdisMapIoSpace(&Status,
                       (PVOID *)&(Adapter->SharedRam),
                       Adapter->NdisAdapterHandle,
                       PhysicalAddress,
                       SharedRamSize);

        if (Status != NDIS_STATUS_SUCCESS) {

            NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
                             Adapter->MmioRegion,
                             0x2000);

            NdisWriteErrorLogEntry(
                Adapter->NdisAdapterHandle,
                NDIS_ERROR_CODE_RESOURCE_CONFLICT,
                0
                );

            return(FALSE);

        }

        Adapter->MappedSharedRam = SharedRamSize;

    }



    //
    // Get the interrupt level...note that a switch being
    // "off" shows up as a 1, "on" is 0.
    //

    switch (SwitchRead1 & 0x03) {

        case 0: InterruptLevel = 2; break;
        case 1: InterruptLevel = 3; break;
        case 2: InterruptLevel = (Adapter->UsingPcIoBus)?6:10; break;
        case 3: InterruptLevel = (Adapter->UsingPcIoBus)?7:11; break;

    }

    Adapter->InterruptLevel = InterruptLevel;

    //
    // Now determine how much memory the adapter has, and
    // whether to use Shared RAM paging.
    //

    Adapter->UpperSharedRamZero = FALSE;

    READ_ADAPTER_REGISTER(Adapter, TOTAL_ADAPTER_RAM, &RegValue);

    switch (RegValue) {

        //
        // These values are described on page 7-26 of the
        // Technical Reference.
        //

        case 0xf:

            Adapter->TotalSharedRam = SharedRamSize;
            break;

        case 0xe:

            Adapter->TotalSharedRam = 0x2000;
            break;

        case 0xd:

            Adapter->TotalSharedRam = 0x4000;
            break;

        case 0xc:

            Adapter->TotalSharedRam = 0x8000;
            break;

        case 0xb:

            Adapter->TotalSharedRam = 0x10000;

            Adapter->UpperSharedRamZero = TRUE;
            break;

        case 0xa:

            Adapter->TotalSharedRam = 0x10000;
            break;

        default:

            NdisWriteErrorLogEntry(
                Adapter->NdisAdapterHandle,
                NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION,
                3,
                hardwareDetails,
                IBMTOK_ERRMSG_UNSUPPORTED_RAM,
                (ULONG)RegValue
                );

            NdisUnmapIoSpace(Adapter->NdisAdapterHandle,
                             Adapter->MmioRegion,
                             0x2000);

            if (Adapter->UsingPcIoBus) {
                NdisUnmapIoSpace(
                    Adapter->NdisAdapterHandle,
                    Adapter->SharedRam,
                    SharedRamSize);
            } else {
                NdisUnmapIoSpace(
                    Adapter->NdisAdapterHandle,
                    Adapter->SharedRam,
                    SharedRamSize);
            }

            return FALSE;

    }

    //
    // Only allow Shared RAM paging if we have 16K selected
    // on SharedRamSize, 64K of total adapter memory, and it is allowed
    // as specified on p. 7-26 of the Technical Reference.
    //

    READ_ADAPTER_REGISTER(Adapter, SHARED_RAM_PAGING, &AipSharedRamPaging);

#if 0
    if (SharedRamSize == 0x4000 &&
        Adapter->TotalSharedRam == 0x10000 &&
        (AipSharedRamPaging == 0xe || AipSharedRamPaging == 0xc)) {

        Adapter->SharedRamPaging = TRUE;

    } else {

        Adapter->SharedRamPaging = FALSE;

    }
#else
    Adapter->SharedRamPaging = FALSE;
#endif


    //
    // Read in the maximum sizes allowed for DHBs based on
    // the speed of the adapter (which we don't know yet).
    //

    READ_ADAPTER_REGISTER(Adapter, MAX_4_MBPS_DHB, &RegValue);

    switch (RegValue) {

        case 0xf:
        default:

            Adapter->Max4MbpsDhb = 2048;
            break;

        case 0xe:

            Adapter->Max4MbpsDhb = 4096;
            break;

        case 0xd:

            Adapter->Max4MbpsDhb = 4464;
            break;

    }

    READ_ADAPTER_REGISTER(Adapter, MAX_16_MBPS_DHB, &RegValue);

    switch (RegValue) {

        case 0xf:
        default:

            Adapter->Max16MbpsDhb = 2048;
            break;

        case 0xe:

            Adapter->Max16MbpsDhb = 4096;
            break;

        case 0xd:

            Adapter->Max16MbpsDhb = 8192;
            break;

        case 0xc:

            Adapter->Max16MbpsDhb = 16384;
            break;

        case 0xb:

            Adapter->Max16MbpsDhb = 17960;
            break;

    }


    return TRUE;

}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.