/* §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ (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 Miniport Miniport_c @module Miniport.c | This module implements the routine, which is the first routine called when the driver is loaded into memory. The Miniport initialization and termination routines are also implemented here. @comm This module should not require any changes. @head3 Contents | @index class,mfunc,func,msg,mdata,struct,enum | Miniport_c @end §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ */ #define __FILEID__ MINIPORT_DRIVER_OBJECT_TYPE // Unique file ID for error logging #include "Miniport.h" // Defines all the miniport objects #include "TpiParam.h" #if defined(NDIS_LCODE) # pragma NDIS_LCODE // Windows 9x wants this code locked down! # pragma NDIS_LDATA #endif DBG_STATIC NDIS_HANDLE g_NdisWrapperHandle = NULL; // @globalv // Receives the context value representing the Miniport wrapper // as returned from NdisMInitializeWrapper. NDIS_PHYSICAL_ADDRESS g_HighestAcceptableAddress = // @globalv // This constant is used for places where NdisAllocateMemory needs to be // called and the g_HighestAcceptableAddress does not matter. NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); /* @doc EXTERNAL INTERNAL Miniport Miniport_c DriverEntry §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called by the operating system when a driver is loaded. This function creates an association between the miniport NIC driver and the NDIS library and registers the miniport's characteristics with NDIS. DriverEntry calls NdisMInitializeWrapper and then NdisMRegisterMiniport. DriverEntry passes both pointers it received to NdisMInitializeWrapper, which returns a wrapper handle. DriverEntry passes the wrapper handle to NdisMRegisterMiniport. The registry contains data that is persistent across system boots, as well as configuration information generated anew at each system boot. During driver installation, data describing the driver and the NIC is stored in the registry. The registry contains adapter characteristics that are read by the NIC driver to initialize itself and the NIC. See the Kernel-Mode Driver Design Guide for more about the registry and the Programmer's Guide for more information about the .inf files that install the driver and write to the registry. @comm Every miniport driver must provide a function called DriverEntry. By convention, DriverEntry is the entry point address for a driver. If a driver does not use the name DriverEntry, the driver developer must define the name of its entry function to the linker so that the entry point address can be known into the OS loader. It is interesting to note, that at the time DriverEntry is called, the OS doesn't know that the driver is an NDIS driver. The OS thinks it is just another driver being loaded. So it is possible to do anything any driver might do at this point. Since NDIS is the one who requested this driver to be loaded, it would be polite to register with the NDIS wrapper. But you can also hook into other OS functions to use and provide interfaces outside the NDIS wrapper. (Not recommended for the faint of heart). @comm The parameters passed to DriverEntry are OS specific! NT passes in valid values, but Windows 3.1 and Windows 95 just pass in zeros. We don't care, because we just pass them to the NDIS wrapper anyway. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, // @parm // A pointer to the driver object, which was created by the I/O system. IN PUNICODE_STRING RegistryPath // @parm // A pointer to the registry path, which specifies where driver-specific // parameters are stored. ) { DBG_FUNC("DriverEntry") NDIS_STATUS Status; // Status result returned from an NDIS function call. NTSTATUS Result; // Result code returned by this function. NDIS_MINIPORT_CHARACTERISTICS NdisCharacteristics; // Characteristics table passed to NdisMWanRegisterMiniport. /* // Setup default debug flags then breakpoint so we can tweak them // when this module is first loaded. It is also useful to see the // build date and time to be sure it's the one you think it is. */ #if DBG DbgInfo->DbgFlags = DBG_DEFAULTS; DbgInfo->DbgID[0] = '0'; DbgInfo->DbgID[1] = ':'; ASSERT (sizeof(VER_TARGET_STR) <= sizeof(DbgInfo->DbgID)-2); memcpy(&DbgInfo->DbgID[2], VER_TARGET_STR, sizeof(VER_TARGET_STR)); #endif // DBG DBG_PRINT((VER_TARGET_STR": Build Date:"__DATE__" Time:"__TIME__"\n")); DBG_PRINT((VER_TARGET_STR": DbgInfo=0x%X DbgFlags=0x%X\n", DbgInfo, DbgInfo->DbgFlags)); DBG_BREAK(DbgInfo); DBG_ENTER(DbgInfo); DBG_PARAMS(DbgInfo, ("\n" "\t|DriverObject=0x%X\n" "\t|RegistryPath=0x%X\n", DriverObject, RegistryPath )); /* // Initialize the Miniport wrapper - THIS MUST BE THE FIRST NDIS CALL. */ NdisMInitializeWrapper( &g_NdisWrapperHandle, DriverObject, RegistryPath, NULL ); ASSERT(g_NdisWrapperHandle); /* // Initialize the characteristics table, exporting the Miniport's entry // points to the Miniport wrapper. */ NdisZeroMemory((PVOID)&NdisCharacteristics, sizeof(NdisCharacteristics)); NdisCharacteristics.MajorNdisVersion = NDIS_MAJOR_VERSION; NdisCharacteristics.MinorNdisVersion = NDIS_MINOR_VERSION; NdisCharacteristics.Reserved = NDIS_USE_WAN_WRAPPER; NdisCharacteristics.InitializeHandler = MiniportInitialize; NdisCharacteristics.CheckForHangHandler = MiniportCheckForHang; NdisCharacteristics.HaltHandler = MiniportHalt; NdisCharacteristics.ResetHandler = MiniportReset; NdisCharacteristics.ReturnPacketHandler = MiniportReturnPacket; NdisCharacteristics.CoActivateVcHandler = MiniportCoActivateVc; NdisCharacteristics.CoDeactivateVcHandler = MiniportCoDeactivateVc; NdisCharacteristics.CoRequestHandler = MiniportCoRequest; NdisCharacteristics.CoSendPacketsHandler = MiniportCoSendPackets; // These two routines are not needed because we are an MCM. // NdisCharacteristics.CoCreateVcHandler = MiniportCoCreateVc; // NdisCharacteristics.CoDeleteVcHandler = MiniportCoDeleteVc; /* // If the adapter does not generate an interrupt, these entry points // are not required. Otherwise, you can use the have the ISR routine // called each time an interupt is generated, or you can use the // enable/disable routines. */ #if defined(CARD_REQUEST_ISR) # if (CARD_REQUEST_ISR == FALSE) NdisCharacteristics.DisableInterruptHandler = MiniportDisableInterrupt; NdisCharacteristics.EnableInterruptHandler = MiniportEnableInterrupt; # endif // CARD_REQUEST_ISR == FALSE NdisCharacteristics.HandleInterruptHandler = MiniportHandleInterrupt; NdisCharacteristics.ISRHandler = MiniportISR; #endif // defined(CARD_REQUEST_ISR) /* // Register the driver with the Miniport wrapper. */ Status = NdisMRegisterMiniport( g_NdisWrapperHandle, (PNDIS_MINIPORT_CHARACTERISTICS) &NdisCharacteristics, sizeof(NdisCharacteristics) ); /* // The driver will not load if this call fails. // The system will log the error for us. */ if (Status != NDIS_STATUS_SUCCESS) { DBG_ERROR(DbgInfo,("Status=0x%X\n",Status)); Result = STATUS_UNSUCCESSFUL; } else { DBG_NOTICE(DbgInfo,("Status=0x%X\n",Status)); Result = STATUS_SUCCESS; } DBG_RETURN(DbgInfo, Result); return (Result); } /* @doc EXTERNAL INTERNAL Miniport Miniport_c MiniportInitialize §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that sets up a NIC (or virtual NIC) for network I/O operations, claims all hardware resources necessary to the NIC in the registry, and allocates resources the driver needs to carry out network I/O operations. @comm No other outstanding requests to the miniport driver are possible when MiniportInitialize is called. No other request is submitted to the miniport driver until initialization is completed. The NDIS library supplies an array of supported media types. The miniport driver reads this array and provides the index of the media type that the NDIS library should use with this miniport driver. If the miniport driver is emulating a media type, its emulation must be transparent to the NDIS library. MiniportInitialize must call NdisMSetAttributes in order to return MiniportAdapterContext. If the miniport driver cannot find a common media type supported by both itself and the NDIS library, it should return NDIS_STATUS_UNSUPPORTED_MEDIA. If NDIS_STATUS_OPEN_ERROR is returned, the NDIS wrapper can examine the output parameter OpenErrorStatus to obtain more information about the error. MiniportInitialize is called with interrupts enabled. MiniportISR is called if the NIC generates any interrupts. The NDIS library will not call MiniportDisableInterrupt and MiniportEnableInterrupt during the MiniportInitialize function, so it is the responsibility of the miniport driver to acknowledge and clear any interrupts generated. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS MiniportInitialize( OUT PNDIS_STATUS OpenErrorStatus, // @parm // Points to a variable that MiniportInitialize sets to an // NDIS_STATUS_XXX code specifying additional information about the // error if MiniportInitialize will return NDIS_STATUS_OPEN_ERROR. OUT PUINT SelectedMediumIndex, // @parm // Points to a variable in which MiniportInitialize sets the index of // the MediumArray element that specifies the medium type the driver // or its NIC uses. IN PNDIS_MEDIUM MediumArray, // @parm // Specifies an array of NdisMediumXxx values from which // MiniportInitialize selects one that its NIC supports or that the // driver supports as an interface to higher-level drivers. IN UINT MediumArraySize, // @parm // Specifies the number of elements at MediumArray. 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("MiniportInitialize") NDIS_STATUS Status; // Status result returned from an NDIS function call. PMINIPORT_ADAPTER_OBJECT pAdapter; // Pointer to our newly allocated object. UINT Index; // Loop counter. NDIS_CALL_MANAGER_CHARACTERISTICS McmCharacteristics; // Characteristics table passed to NdisMCmRegisterAddressFamily. CO_ADDRESS_FAMILY McmAddressFamily; // Address family passed to NdisMCmRegisterAddressFamily. DBG_ENTER(DbgInfo); DBG_PARAMS(DbgInfo, ("\n" "\t|OpenErrorStatus=0x%X\n" "\t|SelectedMediumIndex=0x%X\n" "\t|MediumArray=0x%X\n" "\t|MediumArraySize=0x%X\n" "\t|MiniportAdapterHandle=0x%X\n" "\t|WrapperConfigurationContext=0x%X\n", OpenErrorStatus, SelectedMediumIndex, MediumArray, MediumArraySize, MiniportAdapterHandle, WrapperConfigurationContext )); /* // Search the MediumArray for the NdisMediumCoWan media type. */ for (Index = 0; Index < MediumArraySize; Index++) { if (MediumArray[Index] == NdisMediumCoWan) { break; } } /* // Make sure the protocol has requested the proper media type. */ if (Index < MediumArraySize) { /* // Allocate memory for the adapter information structure. */ Status = AdapterCreate( &pAdapter, MiniportAdapterHandle, WrapperConfigurationContext ); if (Status == NDIS_STATUS_SUCCESS) { /* // Now it's time to initialize the hardware resources. */ Status = AdapterInitialize(pAdapter); if (Status == NDIS_STATUS_SUCCESS) { /* // Initialize the address family so NDIS know's what we support. */ NdisZeroMemory(&McmAddressFamily, sizeof(McmAddressFamily)); McmAddressFamily.MajorVersion = NDIS_MAJOR_VERSION; McmAddressFamily.MinorVersion = NDIS_MINOR_VERSION; McmAddressFamily.AddressFamily = CO_ADDRESS_FAMILY_TAPI_PROXY; /* // Initialize the characteristics table, exporting the Miniport's entry // points to the Miniport wrapper. */ NdisZeroMemory((PVOID)&McmCharacteristics, sizeof(McmCharacteristics)); McmCharacteristics.MajorVersion = NDIS_MAJOR_VERSION; McmCharacteristics.MinorVersion = NDIS_MINOR_VERSION; McmCharacteristics.CmCreateVcHandler = ProtocolCoCreateVc; McmCharacteristics.CmDeleteVcHandler = ProtocolCoDeleteVc; McmCharacteristics.CmOpenAfHandler = ProtocolCmOpenAf; McmCharacteristics.CmCloseAfHandler = ProtocolCmCloseAf; McmCharacteristics.CmRegisterSapHandler = ProtocolCmRegisterSap; McmCharacteristics.CmDeregisterSapHandler = ProtocolCmDeregisterSap; McmCharacteristics.CmMakeCallHandler = ProtocolCmMakeCall; McmCharacteristics.CmCloseCallHandler = ProtocolCmCloseCall; McmCharacteristics.CmIncomingCallCompleteHandler = ProtocolCmIncomingCallComplete; McmCharacteristics.CmActivateVcCompleteHandler = ProtocolCmActivateVcComplete; McmCharacteristics.CmDeactivateVcCompleteHandler = ProtocolCmDeactivateVcComplete; McmCharacteristics.CmModifyCallQoSHandler = ProtocolCmModifyCallQoS; McmCharacteristics.CmRequestHandler = ProtocolCoRequest; McmCharacteristics.CmRequestCompleteHandler = ProtocolCoRequestComplete; DBG_NOTICE(pAdapter,("Calling NdisMCmRegisterAddressFamily\n")); Status = NdisMCmRegisterAddressFamily( MiniportAdapterHandle, &McmAddressFamily, &McmCharacteristics, sizeof(McmCharacteristics) ); if (Status != NDIS_STATUS_SUCCESS) { DBG_ERROR(DbgInfo,("NdisMCmRegisterAddressFamily Status=0x%X\n", Status)); /* // Log error message and return. */ NdisWriteErrorLogEntry( MiniportAdapterHandle, NDIS_ERROR_CODE_OUT_OF_RESOURCES, 3, Status, __FILEID__, __LINE__ ); } } if (Status == NDIS_STATUS_SUCCESS) { /* // Save the selected media type. */ *SelectedMediumIndex = Index; } else { /* // Something went wrong, so let's make sure everything is // cleaned up. */ MiniportHalt(pAdapter); } } } else { DBG_ERROR(DbgInfo,("No NdisMediumCoWan found (Array=0x%X, ArraySize=%d)\n", MediumArray, MediumArraySize)); /* // Log error message and return. */ NdisWriteErrorLogEntry( MiniportAdapterHandle, NDIS_ERROR_CODE_UNSUPPORTED_CONFIGURATION, 3, Index, __FILEID__, __LINE__ ); Status = NDIS_STATUS_UNSUPPORTED_MEDIA; } /* // If all goes well, register a shutdown handler for this adapter. */ if (Status == NDIS_STATUS_SUCCESS) { NdisMRegisterAdapterShutdownHandler(MiniportAdapterHandle, pAdapter, MiniportShutdown); } DBG_NOTICE(DbgInfo,("Status=0x%X\n",Status)); DBG_RETURN(DbgInfo, Status); return (Status); } /* @doc EXTERNAL INTERNAL Miniport Miniport_c MiniportHalt §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func request is used to halt the adapter such that it is no longer functioning. @comm The Miniport should stop the adapter and deregister all of its resources before returning from this routine. It is not necessary for the Miniport to complete all outstanding requests and no other requests will be submitted to the Miniport until the operation is completed. Interrupts are enabled during the call to this routine. */ VOID MiniportHalt( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance. ) { DBG_FUNC("MiniportHalt") DBG_ENTER(DbgInfo); /* // Remove our shutdown handler from the system. */ NdisMDeregisterAdapterShutdownHandler(pAdapter->MiniportAdapterHandle); /* // Free adapter instance. */ AdapterDestroy(pAdapter); DBG_LEAVE(DbgInfo); } /* @doc EXTERNAL INTERNAL Miniport Miniport_c MiniportShutdown §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is an optional function that restores a NIC to its initial state when the system is shut down, whether by the user or because an unrecoverable system error occurred. @comm Every NIC driver should have a function. does nothing more than restore the NIC to its initial state (before the miniport's DriverEntry function runs). However, this ensures that the NIC is in a known state and ready to be reinitialized when the machine is rebooted after a system shutdown occurs for any reason, including a crash dump. A NIC driver's MiniportInitialize function must call NdisMRegisterAdapterShutdownHandler to set up a function. The driver's MiniportHalt function must make a reciprocal call to NdisMDeregisterAdapterShutdownHandler. If is called due to a user-initiated system shutdown, it runs at IRQL PASSIVE_LEVEL in a system-thread context. If it is called due to an unrecoverable error, runs at an arbitrary IRQL and in the context of whatever component raised the error. For example, might be run at high DIRQL in the context of an ISR for a device essential to continued execution of the system. should call no NdisXxx functions. */ VOID MiniportShutdown( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance. ) { DBG_FUNC("MiniportShutdown") DBG_ENTER(pAdapter); /* // Reset the hardware and bial out - don't release any resources! */ CardReset(pAdapter->pCard); DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL Miniport Miniport_c MiniportReset §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func request instructs the Miniport to issue a hardware reset to the network adapter. The Miniport also resets its software state. The request may also reset the parameters of the adapter. If a hardware reset of the adapter resets the current station address to a value other than what it is currently configured to, the Miniport driver automatically restores the current station address following the reset. Any multicast or functional addressing masks reset by the hardware do not have to be reprogrammed by the Miniport. : This is change from the NDIS 3.0 driver specification. If the multicast or functional addressing information, the packet filter, the lookahead size, and so on, needs to be restored, the Miniport indicates this with setting the flag AddressingReset to TRUE. It is not necessary for the Miniport to complete all outstanding requests and no other requests will be submitted to the Miniport until the operation is completed. Also, the Miniport does not have to signal the beginning and ending of the reset with NdisMIndicateStatus. : These are different than the NDIS 3.0 driver specification. The Miniport must complete the original request, if the orginal call to return NDIS_STATUS_PENDING, by calling NdisMResetComplete. If the underlying hardware does not provide a reset function under software control, then this request completes abnormally with NDIS_STATUS_NOT_RESETTABLE. If the underlying hardware attempts a reset and finds recoverable errors, the request completes successfully with NDIS_STATUS_SOFT_ERRORS. If the underlying hardware resets and, in the process, finds nonrecoverable errors, the request completes successfully with the status NDIS_STATUS_HARD_ERRORS. If the underlying hardware reset is accomplished without any errors, the request completes successfully with the status NDIS_STATUS_SUCCESS. Interrupts are in any state during this call. @comm I have only seen MiniportReset called when the driver is not working properly. If this gets called, your code is probably broken, so fix it. Don't try to recover here unless there is some hardware/firmware problem you must work around. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS MiniportReset( OUT PBOOLEAN AddressingReset, // @parm // The Miniport indicates if the wrapper needs to call // to restore the addressing information // to the current values by setting this value to TRUE. IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance. ) { DBG_FUNC("MiniportReset") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Result code returned by this function. DBG_ENTER(pAdapter); DBG_ERROR(pAdapter,("##### !!! THIS SHOULD NEVER BE CALLED !!! #####\n")); /* // If anything goes wrong here, it's very likely an unrecoverable // hardware failure. So we'll just shut this thing down for good. */ Result = NDIS_STATUS_HARD_ERRORS; *AddressingReset = TRUE; return (Result); }