/* §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ (C) Copyright 1999 All rights reserved. §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ Portions of this software are: (C) Copyright 1995 TriplePoint, Inc. -- http://www.TriplePoint.com License to use this software is granted under the same terms outlined in the Microsoft Windows Device Driver Development Kit. (C) Copyright 1992 Microsoft Corp. -- http://www.Microsoft.com License to use this software is granted under the terms outlined in the Microsoft Windows Device Driver Development Kit. §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @doc INTERNAL Adapter Adapter_c @module Adapter.c | This module implements the interface to the . Supports the high-level adapter control functions used by the NDIS WAN Minport driver. @comm This module isolates most the NDIS specific, logical adapter interfaces. It should require very little change if you follow this same overall architecture. You should try to isolate your changes to the that is contained within the logical adapter . @head3 Contents | @index class,mfunc,func,msg,mdata,struct,enum | Adapter_c @end §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ */ #define __FILEID__ MINIPORT_ADAPTER_OBJECT_TYPE // Unique file ID for error logging #include "Miniport.h" // Defines all the miniport objects #if defined(NDIS_LCODE) # pragma NDIS_LCODE // Windows 9x wants this code locked down! # pragma NDIS_LDATA #endif PMINIPORT_ADAPTER_OBJECT g_Adapters[MAX_ADAPTERS] // @globalv // Keeps track of all the s created by the driver. = { 0 }; DBG_STATIC ULONG g_AdapterInstanceCounter // @globalv // Keeps track of how many s are created and // stored in the

array. = 0; DBG_STATIC UCHAR g_AnsiDriverName[] // @globalv // ANSI string used to identify the driver to the system; usually defined // as VER_PRODUCT_STR. = VER_PRODUCT_STR; DBG_STATIC UCHAR g_AnsiVendorDescription[] // @globalv // ANSI string used to identify the vendor's device to the system; usually // defined as VER_DEVICE_STR " Adapter". = VER_DEVICE_STR " Adapter"; /* @doc INTERNAL EXTERNAL Adapter Adapter_c g_AdapterParameters §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @topic 5.1 Adapter Parameters | This section describes the registry parameters read into the . @globalv DBG_STATIC | g_AdapterParameters | This table defines the registry based parameters to be assigned to data members of the . : If you add any registry based data members to you will need to modify and add the parameter definitions to the table. @flag (OPTIONAL) (DEBUG VERSION ONLY) | This DWORD parameter allows you to control how much debug information is displayed to the debug monitor. This is a bit OR'd flag using the values defined in . This value is not used by the released version of the driver. */ DBG_STATIC PARAM_TABLE g_AdapterParameters[] = { #if DBG PARAM_ENTRY(MINIPORT_ADAPTER_OBJECT, DbgFlags, PARAM_DebugFlags, FALSE, NdisParameterHexInteger, 0, DBG_DEFAULTS | DBG_TAPICALL_ON, 0, 0xffffffff), // TODO: Change the debug flags to meet your needs. #endif /* The last entry must be an empty string! */ { { 0 } } }; /* @doc INTERNAL Adapter Adapter_c AdapterReadParameters §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func reads the adapter parameters from the registry and initializes the associated data members. This should only be called by . : If you add any registry based data members to you will need to modify and add the parameter definitions to the table. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ DBG_STATIC NDIS_STATUS AdapterReadParameters( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance return by // . ) { DBG_FUNC("AdapterReadParameters") NDIS_STATUS Result; // Holds the result code returned by this function. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(DbgInfo); /* // Parse the registry parameters. */ Result = ParamParseRegistry( pAdapter->MiniportAdapterHandle, pAdapter->WrapperConfigurationContext, (PUCHAR)pAdapter, g_AdapterParameters ); if (Result == NDIS_STATUS_SUCCESS) { /* // Make sure the parameters are valid. */ if (pAdapter->TODO) { DBG_ERROR(DbgInfo,("Invalid value 'TODO'\n", pAdapter->TODO)); NdisWriteErrorLogEntry( pAdapter->MiniportAdapterHandle, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 3, pAdapter->TODO, __FILEID__, __LINE__ ); Result = NDIS_STATUS_FAILURE; } } DBG_RETURN(DbgInfo, Result); return (Result); } /* @doc INTERNAL Adapter Adapter_c AdapterCreateObjects §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func calls the create routines for all the objects contained in . This should only be called by . : If you add any new objects to you will need to modify and so they will get created and destroyed properly. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ DBG_STATIC NDIS_STATUS AdapterCreateObjects( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance return by // . ) { DBG_FUNC("AdapterCreateObjects") NDIS_STATUS Result; // Holds the result code returned by this function. ULONG Index; // Loop counter. ULONG NumBChannels; // The number of BChannels supported by the NIC. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(DbgInfo); /* // Create the Card object. */ Result = CardCreate(&pAdapter->pCard, pAdapter); /* // Create the DChannel object. */ if (Result == NDIS_STATUS_SUCCESS) { Result = DChannelCreate(&pAdapter->pDChannel, pAdapter); } /* // Allocate space for the BChannels. */ if (Result == NDIS_STATUS_SUCCESS) { NumBChannels = CardNumChannels(pAdapter->pCard); Result = ALLOCATE_MEMORY(pAdapter->pBChannelArray, sizeof(PVOID) * NumBChannels, pAdapter->MiniportAdapterHandle); } /* // Create the BChannel objects. */ InitializeListHead(&pAdapter->BChannelAvailableList); for (Index = 0; Result == NDIS_STATUS_SUCCESS && Index < NumBChannels; Index++) { Result = BChannelCreate(&pAdapter->pBChannelArray[Index], Index, pAdapter); /* // Put entry on available list. */ InsertTailList(&pAdapter->BChannelAvailableList, &pAdapter->pBChannelArray[Index]->LinkList); /* // Keep track of how many are created. */ if (Result == NDIS_STATUS_SUCCESS) { pAdapter->NumBChannels++; } } DBG_RETURN(DbgInfo, Result); return (Result); } /* @doc INTERNAL Adapter Adapter_c AdapterCreate §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func allocates memory for a and then initializes the data members to their starting state. If successful,

will be set to point to the newly created . Otherwise,

will be set to NULL. @comm This function should be called only once when the Miniport is loaded. Before the Miniport is unloaded, must be called to release the created by this function. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS AdapterCreate( OUT PMINIPORT_ADAPTER_OBJECT *ppAdapter, // @parm // Points to a caller-defined memory location to which this function // writes the virtual address of the allocated . IN NDIS_HANDLE MiniportAdapterHandle, // @parm // Specifies a handle identifying the miniport's NIC, which is assigned // by the NDIS library. MiniportInitialize should save this handle; it // is a required parameter in subsequent calls to NdisXxx functions. IN NDIS_HANDLE WrapperConfigurationContext // @parm // Specifies a handle used only during initialization for calls to // NdisXxx configuration and initialization functions. For example, // this handle is a required parameter to NdisOpenConfiguration and // the NdisImmediateReadXxx and NdisImmediateWriteXxx functions. ) { DBG_FUNC("AdapterCreate") NDIS_STATUS Result; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // Pointer to our newly allocated object. DBG_ENTER(DbgInfo); /* // Make sure the caller's object pointer is NULL to begin with. // It will be set later only if everything is successful. */ *ppAdapter = NULL; /* // Allocate memory for the object. */ Result = ALLOCATE_OBJECT(pAdapter, MiniportAdapterHandle); if (Result == NDIS_STATUS_SUCCESS) { /* // Zero everything to begin with. // Then set the object type and assign a unique ID . */ pAdapter->ObjectType = MINIPORT_ADAPTER_OBJECT_TYPE; pAdapter->ObjectID = ++g_AdapterInstanceCounter; ASSERT(g_AdapterInstanceCounter <= MAX_ADAPTERS); if (g_AdapterInstanceCounter <= MAX_ADAPTERS) { g_Adapters[g_AdapterInstanceCounter-1] = pAdapter; } /* // We use the instance number in debug messages to help when debugging // with multiple adapters. */ #if DBG pAdapter->DbgID[0] = (UCHAR) ((pAdapter->ObjectID & 0x0F) + '0'); pAdapter->DbgID[1] = ':'; if (sizeof(VER_TARGET_STR) < sizeof(pAdapter->DbgID)-3) { memcpy(&pAdapter->DbgID[2], VER_TARGET_STR, sizeof(VER_TARGET_STR)); } else { memcpy(&pAdapter->DbgID[2], VER_TARGET_STR, sizeof(pAdapter->DbgID)-3); pAdapter->DbgID[sizeof(pAdapter->DbgID)-1] = 0; } #endif /* // Initialize the member variables to their default settings. */ pAdapter->MiniportAdapterHandle = MiniportAdapterHandle; pAdapter->WrapperConfigurationContext = WrapperConfigurationContext; /* // Allocate spin locks to use for MUTEX queue protection. */ NdisAllocateSpinLock(&pAdapter->EventLock); NdisAllocateSpinLock(&pAdapter->TransmitLock); NdisAllocateSpinLock(&pAdapter->ReceiveLock); /* // Parse the registry parameters. */ Result = AdapterReadParameters(pAdapter); #if DBG // DbgInfo->DbgFlags = pAdapter->DbgFlags; #endif // DBG DBG_DISPLAY(("NOTICE: Adapter#%d=0x%X DbgFlags=0x%X\n", pAdapter->ObjectID, pAdapter, pAdapter->DbgFlags)); /* // If all goes well, we are ready to create the sub-components. */ if (Result == NDIS_STATUS_SUCCESS) { Result = AdapterCreateObjects(pAdapter); } if (Result == NDIS_STATUS_SUCCESS) { /* // All is well, so return the object pointer to the caller. */ *ppAdapter = pAdapter; } else { /* // Something went wrong, so let's make sure everything is // cleaned up. */ AdapterDestroy(pAdapter); } } DBG_RETURN(DbgInfo, Result); return (Result); } /* @doc INTERNAL Adapter Adapter_c AdapterDestroyObjects §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func calls the destroy routines for all the objects contained in . This should only be called by . : If you add any new objects to you will need to modify and so they will get created and destroyed properly. */ DBG_STATIC void AdapterDestroyObjects( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance return by // . ) { DBG_FUNC("AdapterDestroyObjects") UINT NumBChannels; // The number of BChannels supported by the NIC. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(DbgInfo); /* // Destroy the BChannel objects. */ NumBChannels = pAdapter->NumBChannels; while (NumBChannels--) { BChannelDestroy(pAdapter->pBChannelArray[NumBChannels]); } pAdapter->NumBChannels = 0; /* // Free space for the BChannels. */ if (pAdapter->pBChannelArray) { NumBChannels = CardNumChannels(pAdapter->pCard); FREE_MEMORY(pAdapter->pBChannelArray, sizeof(PVOID) * NumBChannels); } /* // Destroy the DChannel object. */ DChannelDestroy(pAdapter->pDChannel); /* // Destroy the Card object. */ CardDestroy(pAdapter->pCard); DBG_LEAVE(DbgInfo); } /* @doc INTERNAL Adapter Adapter_c AdapterDestroy §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func frees the memory for this . All memory allocated by will be released back to the OS. */ void AdapterDestroy( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance return by // . ) { DBG_FUNC("AdapterDestroy") DBG_ENTER(DbgInfo); if (pAdapter) { ASSERT(pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); /* // Release all objects allocated within this object. */ AdapterDestroyObjects(pAdapter); if (pAdapter->EventLock.SpinLock) { NdisFreeSpinLock(&pAdapter->EventLock); } if (pAdapter->TransmitLock.SpinLock) { NdisFreeSpinLock(&pAdapter->TransmitLock); } if (pAdapter->ReceiveLock.SpinLock) { NdisFreeSpinLock(&pAdapter->ReceiveLock); } /* // Make sure we fail the ASSERT if we see this object again. */ if (pAdapter->ObjectType <= MAX_ADAPTERS) { g_Adapters[pAdapter->ObjectType-1] = NULL; } pAdapter->ObjectType = 0; FREE_OBJECT(pAdapter); } DBG_LEAVE(DbgInfo); } /* @doc INTERNAL Adapter Adapter_c AdapterInitialize §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func prepares the and all its sub-components for use by the NDIS wrapper. Upon successful completion of this routine, the NIC will be ready to accept requests from the NDIS wrapper. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS AdapterInitialize( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance return by // . ) { DBG_FUNC("AdapterInitialize") NDIS_STATUS Result; // Holds the result code returned by this function. PBCHANNEL_OBJECT pBChannel; // A Pointer to one of our 's. ULONG Index; // Loop counter. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); /* // Initialize the WAN information structure to match the capabilities of // the adapter. */ pAdapter->WanInfo.MaxFrameSize = pAdapter->pCard->BufferSize - NDISWAN_EXTRA_SIZE; pAdapter->WanInfo.MaxSendWindow = pAdapter->pCard->TransmitBuffersPerLink; /* // We only support PPP, and multi-link PPP framing. */ pAdapter->WanInfo.FramingBits = PPP_FRAMING | PPP_MULTILINK_FRAMING; /* // This value is ignored by this driver, but its default behavior is such // that all these control bytes would appear to be handled transparently. */ pAdapter->WanInfo.DesiredACCM = 0; /* // Initialize the packet management queues to empty. */ InitializeListHead(&pAdapter->EventList); InitializeListHead(&pAdapter->TransmitPendingList); InitializeListHead(&pAdapter->TransmitCompleteList); InitializeListHead(&pAdapter->ReceiveCompleteList); /* // Setup the timer event handler. */ NdisMInitializeTimer(&pAdapter->EventTimer, pAdapter->MiniportAdapterHandle, MiniportTimer, pAdapter); /* // Initialize the DChannel object. */ DChannelInitialize(pAdapter->pDChannel); /* // Initialize all the BChannel objects. */ for (Index = 0; Index < pAdapter->NumBChannels; ++Index) { pBChannel = GET_BCHANNEL_FROM_INDEX(pAdapter, Index); BChannelInitialize(pBChannel); } /* // Now, we can initialize the Card object. */ Result = CardInitialize(pAdapter->pCard); DBG_RETURN(pAdapter, Result); return (Result); }