windows-nt/Source/XPSP1/NT/net/ndis/samples/coisdn/miniport.c
2020-09-26 16:20:57 +08:00

682 lines
25 KiB
C

/*
§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§
(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 <f DriverEntry> 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
<f DriverEntry> 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
<f DriverEntry> returns zero if it is successful.<nl>
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] = ':';
if (sizeof(VER_TARGET_STR) < sizeof(DbgInfo->DbgID)-3)
{
memcpy(&DbgInfo->DbgID[2], VER_TARGET_STR, sizeof(VER_TARGET_STR));
}
else
{
memcpy(&DbgInfo->DbgID[2], VER_TARGET_STR, sizeof(DbgInfo->DbgID)-3);
DbgInfo->DbgID[sizeof(DbgInfo->DbgID)-1] = 0;
}
#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
<f MiniportInitialize> 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
<f MiniportInitialize> returns zero if it is successful.<nl>
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
<f MiniportHalt> 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 <t MINIPORT_ADAPTER_OBJECT> 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
<f MiniportShutdown> 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 <f MiniportShutdown> function.
<f MiniportShutdown> 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 <f MiniportShutdown>
function. The driver's MiniportHalt function must make a reciprocal call
to NdisMDeregisterAdapterShutdownHandler.
If <f MiniportShutdown> 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, <f MiniportShutdown> runs at an arbitrary
IRQL and in the context of whatever component raised the error. For
example, <f MiniportShutdown> might be run at high DIRQL in the context of
an ISR for a device essential to continued execution of the system.
<f MiniportShutdown> should call no NdisXxx functions.
*/
VOID MiniportShutdown(
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> 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
<f MiniportReset> request instructs the Miniport to issue a hardware
reset to the network adapter. The Miniport also resets its software
state.
The <F MiniportReset> 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.
<f Note>: 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.
<f Note>: These are different than the NDIS 3.0 driver specification.
The Miniport must complete the original request, if the orginal
call to <F MiniportReset> 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
<f MiniportReset> returns zero if it is successful.<nl>
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
// <f MiniportCoRequest> 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 <t MINIPORT_ADAPTER_OBJECT> 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);
}