You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1367 lines
58 KiB
1367 lines
58 KiB
/*
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
(C) Copyright 1998
|
|
All rights reserved.
|
|
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
Portions of this software are:
|
|
|
|
(C) Copyright 1995, 1999 TriplePoint, Inc. -- http://www.TriplePoint.com
|
|
License to use this software is granted under the terms outlined in
|
|
the TriplePoint Software Services Agreement.
|
|
|
|
(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.
|
|
|
|
@head3 Contents |
|
|
@index class,mfunc,func,msg,mdata,struct,enum | Miniport_c
|
|
|
|
@end
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
*/
|
|
|
|
/* @doc EXTERNAL INTERNAL
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
@topic 1.0 Miniport Overview |
|
|
|
|
The NDIS wrapper provides services to both the Transport drivers, and the
|
|
Miniport drivers. The NDIS wrapper provides an abstraction layer between
|
|
the two which allows them to interoperate with each other as long as they
|
|
both adhere to the NDIS interfaces defined for Transports and Miniports.
|
|
|
|
The NDIS wrapper also provides a set of services which isolate NDIS
|
|
drivers from the specifics of the Operating System (Win 3.11, Win95,
|
|
WinNT), as well as the platform specifics (Processor, Bus, Interrupts).
|
|
The advantage of using the NDIS wrapper is that the Miniport can be
|
|
easily ported to other Windows environments with little or no re-coding.
|
|
|
|
@iex
|
|
|
|
This diagram shows how the NDIS wrapper provides services
|
|
to both the Transport drivers, and the Miniport drivers.
|
|
|
|
| +--------+ +-----+ +---------------------------------+
|
|
| | | | |<-->| Windows Transport Drivers (TDI) |
|
|
| | | | | +---------------------------------+
|
|
| | | | | | Lower-Edge Functions ^
|
|
| | | | | | |
|
|
| | | | | v |
|
|
| | | | +--------------------------------------+
|
|
| | | | NDIS Interface Library (Wrapper) |
|
|
| | | | +--------------------------------------+
|
|
| |Windows | | | | ^
|
|
| | OS | | | | |
|
|
| |Services| | | v Upper-Edge Functions |
|
|
| | | | | +---------------------------------+
|
|
| | | | | | NDIS WAN/TAPI Driver (Miniport) |
|
|
| | | | | +---------------------------------+
|
|
| | | | | ^ Lower-Edge Functions
|
|
| | | | | |
|
|
| | | | | v
|
|
| | | | +--------------------------------------+
|
|
| | +---|<-->|------------+ |
|
|
| +----|---+ +--------------------------------------------+
|
|
| ^
|
|
| |
|
|
| v Hardware Bus
|
|
| +------------------------------+
|
|
| | Network Interface Card (NIC) |
|
|
| +------------------------------+
|
|
|
|
|
|
An NDISWAN Miniport consists of two, cooperating, drivers contained in
|
|
the same binary. The NDIS WAN portion of the driver handles packet
|
|
transmits and receives. While the WAN TAPI portion handles call setup
|
|
and tear down. Ultimately, it would be better if these two drivers
|
|
were separated, and there was an interface defined between them, but
|
|
history and expedience lead Microsoft to develop this interface model.
|
|
|
|
The NDIS WAN side of the Miniport is very similar to an NDIS LAN style
|
|
Miniport, except that some of the NDIS interfaces have been modified to
|
|
support the WAN media type. The primary difference from the Miniport's
|
|
point of view is the packet structure and different set of NDIS requests,
|
|
and more importantly the line can go up and down.
|
|
|
|
The WAN TAPI portion of the Miniport adds significant complexity to the
|
|
Miniport. The WAN Miniport must provide a pseudo Telephony Service
|
|
Provider Interface (TSPI) which lives under the WAN TSPI. The NDIS WAN
|
|
TSPI loads under TAPI as the 'real' service provider, and then routes all
|
|
RAS related TAPI events to the Miniport's TSPI.
|
|
|
|
The WAN TSPI can have multiple Miniport TSPI's living under its TSPI
|
|
interface. And since Remote Access Services (RAS) use the TAPI interface
|
|
to place and accept all calls, any Dial Up Networking (DUN) requests
|
|
associated with the Miniport, will end up at the Miniport's TSPI.
|
|
|
|
@topic 1.1 Call Control Interface |
|
|
|
|
FIXME_DESCRIPTION
|
|
|
|
@topic 1.2 Data Channel Interface |
|
|
|
|
FIXME_DESCRIPTION
|
|
|
|
Once a call is connected, the data channel associated with the call is
|
|
configured to transmit and receive raw HDLC packets. Then NDIS is
|
|
notified that the coresponding 'link' is up. The NDIS documentation
|
|
refers to a data pipe as a link, and the Miniport also uses this
|
|
nomenclature. In addition, NDIS/RAS wants to see each data channel as a
|
|
separate TAPI line device, so the Miniport also uses this link structure
|
|
to keep track of TAPI calls and lines since they are all mapped 1:1:1.
|
|
Keep this in mind as you read through the code and documentation, because
|
|
I often use line and link interchangeably.
|
|
|
|
@topic 1.3 Implementation Notes |
|
|
|
|
The Miniport is built as a Windows NT Portable Executable (PE) system
|
|
file (.SYS). The reason for this is that the NDIS WAN interfaces
|
|
routines are currently only defined in the Windows NT version of the NDIS
|
|
library. On Windows 95, the Miniport's binary image file is dynamically
|
|
loaded by the NDIS wrapper during initialization, and runs in Ring-0. A
|
|
Windows 95 version of the NDIS.VXD is available which supports the new
|
|
WAN interrfaces.
|
|
|
|
@end
|
|
*/
|
|
|
|
/* @doc EXTERNAL INTERNAL
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
@topic 2.0 Reference Documents |
|
|
|
|
The most reliable source of information is provided on the Microsoft
|
|
Developer Network CD. These documents will provide you with the complete
|
|
NDIS interface requirements and architectural overviews. In addition,
|
|
there are many addendums and developer notes in the Microsoft Knowledge
|
|
Base. The most important references are:
|
|
|
|
@iex
|
|
Product Documentation\DDKs\Windows 95 DDK\Network Drivers\
|
|
Windows 95 Network Drivers
|
|
NDIS 3.0 Netcard Driver
|
|
NDIS Netcard Driver Tester
|
|
Network Driver Installer
|
|
|
|
Product Documentation\DDKs\Windows NT DDK\Network Drivers\
|
|
Design Guide\PART2 NDIS 3.0 Driver Design
|
|
Chapters 1-7 discuss all the NDIS interface routines.
|
|
Chapters 8-11,17-18 provide details on WAN/TAPI extensions.
|
|
|
|
Product Documentation\SDKs\Win32 SDK\Win32 Telephony\
|
|
This section defines the Windows 95 TAPI implementation.
|
|
Note that this is slightly different than the Windows 3.1 TAPI
|
|
spec. Pay special attention to lineGetID and line device classes.
|
|
|
|
@topic 2.1 NDIS Background Information |
|
|
|
|
Microsoft is phasing out what they call the NDIS 3.0 Full MAC driver.
|
|
These drivers were written to the NDIS 3.0 specification using the older
|
|
interface routines which have now been augmented by the Miniport
|
|
routines. The Miniport extensions were added to the NDIS 3.0 interface
|
|
with the goal of making network drivers easier to write. By using the
|
|
Miniport routines rather than the original NDIS routines, the driver
|
|
writer can make many simplifying assumptions, because the NDIS Wrapper
|
|
will provide most of the queuing, scheduling, and sychronization code.
|
|
The Miniport only has to deal with moving packets on and off the wire.
|
|
|
|
The WAN and TAPI extensions were added into the NDIS 3.0 specification
|
|
shortly after the Miniport extensions. These new WAN interface routines
|
|
are very similar to the LAN interface routines. The only significant
|
|
difference is the packet format passed between the Miniport and the NDIS
|
|
Wrapper. The TAPI extensions have no counterpart in the LAN interface,
|
|
so these are all new. In fact, they turn out to be about half of the
|
|
implementation in a typical WAN/TAPI Miniport.
|
|
|
|
It would have been nice if Microsoft would have added these changes and
|
|
bumped the version numbers, but they didn't. So we are left with a real
|
|
problem trying to identifiy which NDIS 3.0 we are talking about. The
|
|
thing to remember is that you should avoid the Full MAC interface routines,
|
|
because Microsoft has said that these routines will not be supported in
|
|
future releases. This is largely due to the Plug-and-Play extensions
|
|
that were introduced in NDIS 3.1 for Windows 95.
|
|
|
|
In the near future Microsoft will be adding more features to NDIS 3.5 to
|
|
support advanced routing and some other enhancements. In addition,
|
|
NDIS 4.0 will be coming out with MANY new features to support ATM and
|
|
other virtual circuit type media. There are also more TAPI services
|
|
being defined for the NDIS interface. So don't expect this specification
|
|
to stand still long enough to read it all...
|
|
|
|
@topic 2.2 Differences between LAN and WAN miniports |
|
|
|
|
There are several differences in the way a WAN miniport interfaces
|
|
with NDIS as compared to a LAN miniport driver described in the
|
|
previous chapters. Such differences affect how a WAN driver is
|
|
implemented.
|
|
|
|
A WAN miniport must not register a MiniportTransferData handler with
|
|
NdisMRegisterMiniport. Instead, a WAN miniport always passes an entire
|
|
packet to the NdisMWanIndicateReceive function. When
|
|
NdisMWanIndicateReceive returns, the packet has been copied and the
|
|
WAN miniport can reuse the packet resources it allocated.
|
|
|
|
WAN miniports provide a MiniportWanSend function instead of a MiniportSend
|
|
function. The MiniportWanSend function accepts an additional parameter that
|
|
specifies a specific data channel on which a packet is to be sent.
|
|
|
|
WAN miniports never return NDIS_STATUS_RESOURCES as the status of
|
|
MiniportWanSend or any other MiniportXxx function and cannot call
|
|
NdisMSendResourcesAvailable.
|
|
|
|
WAN miniports support a set of WAN-specific OIDs to set and query
|
|
operating characteristics.
|
|
|
|
WAN miniports support a set of WAN-specific status indications
|
|
which are passed to NdisMIndicateStatus. These status indications
|
|
report changes in the status of a link.
|
|
|
|
WAN miniports call alternative WAN-specific NDIS functions to
|
|
complete the WAN-specific NDIS calls for send and receive. <nl>
|
|
The two completion calls are: <nl>
|
|
NdisMWanIndicateReceiveComplete <nl>
|
|
NdisMWanSendComplete <nl>
|
|
|
|
WAN miniport drivers use an NDIS_WAN_PACKET instead of an
|
|
NDIS_PACKET-type descriptor.
|
|
|
|
WAN miniport drivers keep a WAN-specific set of statistics.
|
|
|
|
WAN miniport drivers never do loopback; it is always
|
|
provided by NDIS.
|
|
|
|
WAN miniport drivers cannot be full-duplex miniports.
|
|
|
|
|
|
@end
|
|
*/
|
|
|
|
/* @doc EXTERNAL INTERNAL
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
@topic 3.0 NDISWAN Miniport Interface |
|
|
|
|
The Miniport provides the following functions to the NDIS wrapper.
|
|
The NDIS wrapper calls these functions on behalf of other layers of the
|
|
network software, such as a transport driver bound to a network interface
|
|
card. The Miniport uses <f NdisMRegisterMiniport> to give NDIS a list of
|
|
entry points for the supported routines, unused routines are set to NULL.
|
|
|
|
Some of the Miniport functions are synchronous, while others can
|
|
complete either synchronously or asynchronously. The Miniport must
|
|
indicate to the NDIS library when an asynchronous function has completed
|
|
by calling the appropriate NDIS library completion function. The NDIS
|
|
library can subsequently call completion functions in other layers of the
|
|
network software for postprocessing, if necessary.
|
|
|
|
<f DriverEntry> Called by the operating system to activate and
|
|
initialize the Miniport. (Synchronous)
|
|
|
|
<f MiniportCheckForHang> Checks the internal state of the network interface
|
|
card. (Synchronous)
|
|
|
|
<f MiniportHalt> Halts the network interface card so it is no longer
|
|
functioning. (Synchronous)
|
|
|
|
<f MiniportInitialize> Initializes the network interface card. (Synchronous)
|
|
|
|
<f MiniportQueryInformation> Queries the capabilities and current status of
|
|
the Miniport. NDISTAPI functions are also passed through this
|
|
interface. (Asynchronous)
|
|
|
|
<f MiniportReset> Issues a hardware reset to the network interface card.
|
|
(Asynchronous)
|
|
|
|
<f MiniportWanSend> Transmits a packet through the network interface card
|
|
onto the network. (Asynchronous)
|
|
|
|
<f MiniportSetInformation> Changes (sets) information about the Miniport
|
|
driver. NDISTAPI functions are also passed through this interface.
|
|
(Asynchronous)
|
|
|
|
@iex
|
|
|
|
The following routines are defined in the NDIS Miniport interface,
|
|
but they are not used by this implementation.
|
|
|
|
MiniportISR NOT USED by this Miniport.
|
|
|
|
Associated with each Miniport upper-edge driver function that may operate
|
|
asynchronously is a corresponding completion function in the NDIS library.
|
|
When the Miniport function returns a status of NDIS_STATUS_PENDING
|
|
indicating asynchronous operation, this is the completion function that
|
|
must be called when the Miniport has finally completed the request.
|
|
|
|
@iex
|
|
|
|
This table shows how each asynchronous Miniport routine maps to its
|
|
associated NDIS completion routine.
|
|
|
|
Miniport Function Asynchronous Completion Routine
|
|
----------------- -------------------------------
|
|
MiniportQueryInformation NdisMQueryInformationComplete
|
|
MiniportReset NdisMResetComplete
|
|
MiniportWanSend NdisMSendComplete
|
|
MiniportSetInformation NdisMSetInformationComplete
|
|
MiniportTransferData NdisMTransferDataComplete (NOT USED)
|
|
|
|
@end
|
|
*/
|
|
|
|
/* @doc EXTERNAL INTERNAL
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
@topic 3.1 Initialization and Setup |
|
|
|
|
The following diagram shows the typical call sequence used during system
|
|
initialization. Typically this occurs once when Windows loads. However,
|
|
NDIS does allow drivers to be unloaded, and then reloaded at any time, so
|
|
you must be prepared to handle this event.
|
|
|
|
@iex
|
|
|
|
| NDIS Wrapper | Miniport
|
|
| -----------------------------+------------------------------------
|
|
| Load NDIS Wrapper |
|
|
| >---------+---->+ DriverEntry
|
|
| | |
|
|
| NdisMInitializeWrapper <----+---->+
|
|
| | |
|
|
| NdisMRegisterMiniport <----+---->+
|
|
| | |
|
|
| <---------+----<+
|
|
| ~~~ TIME PASSES
|
|
| >---------+---->+ MiniportInitialize
|
|
| | |
|
|
| NdisOpenConfiguration <---+---->+
|
|
| | |
|
|
| NdisReadConfiguration... <---+---->+
|
|
| | |
|
|
| NdisCloseConfiguration <---+---->+
|
|
| | |
|
|
| NdisMSetAttributes <---+---->+
|
|
| | |
|
|
| <---------+----<+
|
|
| ~~~ TIME PASSES
|
|
| >---------+---->+ MiniportQueryInformation
|
|
| <---------+----<+ OID_WAN_CURRENT_ADDRESS
|
|
| ~~~ TIME PASSES
|
|
| >---------+---->+ MiniportQueryInformation
|
|
| <---------+----<+ OID_WAN_MEDIUM_SUBTYPE
|
|
| ~~~ TIME PASSES
|
|
| >---------+---->+ MiniportQueryInformation
|
|
| <---------+----<+ OID_WAN_GET_INFO
|
|
|
|
@end
|
|
*/
|
|
|
|
/* @doc EXTERNAL INTERNAL
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
@topic 3.6 Reset and Shutdown |
|
|
|
|
Aside from the initialization and run-time operations, the Miniport must
|
|
support being reset <f MiniportReset> and being shutdown <f MiniportHalt>.
|
|
|
|
The reset routine is only called when the NDIS wrapper detects an error
|
|
with the Miniport's operation. There are two ways in which the wrapper
|
|
determines an error condition. First, the NDIS wrapper calls
|
|
<f MiniportCheckForHang> once every couple seconds to ask the Miniport
|
|
if it thinks it needs to be reset. Second, the wrapper may detect a
|
|
timeout condition on an outstanding request to the Miniport. These are
|
|
both fail-safe conditions which should not happen under normal, run-time
|
|
conditions.
|
|
|
|
<f Note>: My feeling is that if you see a reset call, the Miniport is
|
|
broken, and you should find and fix the bug -- not the symptom.
|
|
|
|
The shutdown routine is normally only called when Windows is shutting
|
|
down. However, with the advent of plug and play devices, it is likely to
|
|
become more common to get a shutdown request followed by another load
|
|
request in the same Windows session. So it is very important to clean up
|
|
properly when <f MiniportHalt> is called. All memory and other resources
|
|
must be released, and all intefaces must be properly closed so they can
|
|
release their resources too.
|
|
|
|
NDIS will cleanup any outstanding requests, but the Miniport should
|
|
bring down all calls, and close all TAPI lines using synchronous
|
|
TAPI events. You can't depend on any NDIS WAN or TAPI events because
|
|
none will be passed through the wrapper as long as the reset is in
|
|
progress.
|
|
|
|
@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 95 wants this code locked down!
|
|
# pragma NDIS_LDATA
|
|
#endif
|
|
|
|
|
|
DBG_STATIC NDIS_HANDLE g_NdisWrapperHandle = NULL;
|
|
// Receives the context value representing the Miniport wrapper
|
|
// as returned from NdisMInitializeWrapper.
|
|
|
|
NDIS_PHYSICAL_ADDRESS g_HighestAcceptableAddress =
|
|
NDIS_PHYSICAL_ADDRESS_CONST(-1,-1);
|
|
// This constant is used for places where NdisAllocateMemory needs to be
|
|
// called and the g_HighestAcceptableAddress does not matter.
|
|
|
|
|
|
/* @doc 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.
|
|
|
|
<f DriverEntry> calls NdisMInitializeWrapper and then NdisMRegisterMiniport.
|
|
<f DriverEntry> passes both pointers it received to NdisMInitializeWrapper,
|
|
which returns a wrapper handle. <f 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).<nl>
|
|
|
|
NDIS miniports and intermediate drivers carry out two basic tasks in
|
|
their <f DriverEntry> functions:<nl>
|
|
|
|
1) Call NdisMInitializeWrapper to notify the NDIS library that the
|
|
driver is about to register itself as a miniport.
|
|
NDIS sets up the state it needs to track the driver and
|
|
returns an NdisWrapperHandle, which the driver saves for
|
|
subsequent calls to NdisXxx configuration and initialization
|
|
functions.<nl>
|
|
|
|
2) Fill in an NDISXX_MINIPORT_CHARCTERISTICS structure with the
|
|
appropriate version numbers and the entry points for
|
|
driver-supplied MiniportXxx functions and, then, call
|
|
NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport.
|
|
Usually, NIC drivers call NdisMRegisterMiniport, as do
|
|
intermediate drivers that export only a set of MiniportXxx
|
|
functions. Usually, NDIS intermediate drivers call
|
|
NdisIMRegisterLayeredMiniport, which effectively defers the
|
|
initialization of such a driver's virtual NIC until the driver
|
|
calls NdisIMInitializeDeviceInstance from its
|
|
ProtocolBindAdapter function.<nl>
|
|
|
|
<f DriverEntry> can allocate the NDISXX_MINIPORT_CHARACTERISTICS
|
|
structure on the stack since the NDIS library copies the relevant
|
|
information to its own storage. DriverEntry should clear the memory
|
|
for this structure with NdisZeroMemory before setting any driver-supplied
|
|
values in its members. The current MajorNdisVersion is 0x05, and the current
|
|
MinorNdisVersion is 0x00. In each XxxHandler member of the
|
|
characteristics structure, <f DriverEntry> must set the name of a
|
|
driver-supplied MiniportXxx function, or the member must be NULL.
|
|
|
|
Calling NdisMRegisterMiniport causes the driver's <f MiniportInitialize>
|
|
function to run in the context of NdisMRegisterMiniport. Calling
|
|
NdisIMRegisterLayeredMiniport defers the call to MiniportInitialize
|
|
until the driver calls NdisIMInitializeDeviceInstance.
|
|
|
|
Drivers that call NdisMRegisterMiniport must be prepared for an
|
|
immediate call to their <f MiniportInitialize> functions. Such a driver
|
|
must have sufficient installation and configuration information
|
|
stored in the registry or available from calls to an NdisXxx
|
|
bus-type-specific configuration function to set up any NIC-specific
|
|
resources the driver will need to carry out network I/O operations.
|
|
|
|
Drivers that call NdisIMRegisterLayeredMiniport defer the call to
|
|
their <f MiniportInitialize> functions to another driver-supplied
|
|
function that makes a call to NdisIMInitializeDeviceInstance.
|
|
NDIS intermediate drivers usually register a ProtocolBindAdapter
|
|
function and call NdisIMRegisterLayeredMiniport so that NDIS will
|
|
call the ProtocolBindAdapter function after all underlying NIC
|
|
drivers have initialized. This strategy gives such an NDIS
|
|
intermediate driver, which makes the call to
|
|
NdisIMInitializeDeviceInstance from ProtocolBindAdapter,
|
|
the advantage of having its <f MiniportInitialize> function configure
|
|
driver-allocated resources for the intermediate's virtual NIC to
|
|
the features of the underlying NIC driver to which the intermediate
|
|
has already bound itself.
|
|
|
|
If NdisMRegisterMiniport or NdisIMRegisterLayeredMiniport does
|
|
not return NDIS_STATUS_SUCCESS, <f DriverEntry> must release any
|
|
resources it allocated, such as memory to hold the NdisWrapperHandle,
|
|
and must call NdisTerminateWrapper before it returns control.
|
|
The driver will not be loaded if this occurs.
|
|
|
|
By default, <f DriverEntry> runs at IRQL PASSIVE_LEVEL in a
|
|
system-thread context.
|
|
|
|
@devnote
|
|
|
|
The parameters passed to <f 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.
|
|
|
|
@xref
|
|
|
|
<f MiniportInitialize>
|
|
|
|
*/
|
|
|
|
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_WAN_MINIPORT_CHARACTERISTICS WanCharacteristics;
|
|
// 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)&WanCharacteristics, sizeof(WanCharacteristics));
|
|
WanCharacteristics.MajorNdisVersion = NDIS_MAJOR_VERSION;
|
|
WanCharacteristics.MinorNdisVersion = NDIS_MINOR_VERSION;
|
|
WanCharacteristics.Reserved = NDIS_USE_WAN_WRAPPER;
|
|
|
|
WanCharacteristics.InitializeHandler = MiniportInitialize;
|
|
WanCharacteristics.WanSendHandler = MiniportWanSend;
|
|
WanCharacteristics.QueryInformationHandler = MiniportQueryInformation;
|
|
WanCharacteristics.SetInformationHandler = MiniportSetInformation;
|
|
WanCharacteristics.CheckForHangHandler = MiniportCheckForHang;
|
|
WanCharacteristics.ResetHandler = MiniportReset;
|
|
WanCharacteristics.HaltHandler = MiniportHalt;
|
|
|
|
/*
|
|
// 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)
|
|
WanCharacteristics.DisableInterruptHandler = MiniportDisableInterrupt;
|
|
WanCharacteristics.EnableInterruptHandler = MiniportEnableInterrupt;
|
|
#endif // CARD_REQUEST_ISR == FALSE
|
|
WanCharacteristics.HandleInterruptHandler = MiniportHandleInterrupt;
|
|
WanCharacteristics.ISRHandler = MiniportISR;
|
|
#endif // defined(CARD_REQUEST_ISR)
|
|
|
|
/*
|
|
// Register the driver with the Miniport wrapper.
|
|
*/
|
|
Status = NdisMRegisterMiniport(
|
|
g_NdisWrapperHandle,
|
|
(PNDIS_MINIPORT_CHARACTERISTICS) &WanCharacteristics,
|
|
sizeof(WanCharacteristics)
|
|
);
|
|
|
|
/*
|
|
// 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 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
|
|
|
|
NDIS submits no requests to a driver until its initialization
|
|
is completed.
|
|
|
|
In NIC and intermediate drivers that call NdisMRegisterMiniport
|
|
from their DriverEntry functions, NDIS calls MiniportInitialize
|
|
in the context of NdisMRegisterMiniport. The underlying device
|
|
driver must initialize before an intermediate driver that depends
|
|
on that device calls NdisMRegisterMiniport.
|
|
|
|
For NDIS intermediate drivers that export both ProtocolXxx and
|
|
MiniportXxx functions and that call NdisIMRegisterLayeredMiniport
|
|
from their DriverEntry functions, NDIS calls <f MiniportInitialize>
|
|
in the context of NdisIMInitializeDeviceInstance. Such a driver's
|
|
ProtocolBindAdapter function usually makes the call to
|
|
NdisIMInitializeDeviceInstance.
|
|
|
|
For NIC drivers, NDIS must find at least the NIC's I/O bus
|
|
interface type and, if it is not an ISA bus, the bus number
|
|
already installed in the registry by the driver's installation
|
|
script. For more information about installing Windows 2000 drivers,
|
|
see the Driver Writer's Guide.
|
|
|
|
The NIC driver obtains configuration information for its
|
|
NIC by calling NdisOpenConfiguration and NdisReadConfiguration.
|
|
The NIC driver obtains bus-specific information by calling the
|
|
appropriate bus-specific function:
|
|
|
|
Bus Function for Obtaining Bus-Specific Information:<nl>
|
|
|
|
EISA:<nl>
|
|
NdisReadEisaSlotInformation or NdisReadEisaSlotInformationEx
|
|
|
|
PCI:<nl>
|
|
NdisReadPciSlotInformation
|
|
|
|
PCMCIA:<nl>
|
|
NdisReadPcmciaAttributeMemory
|
|
|
|
The NIC driver for an EISA NIC obtains information on the
|
|
hardware resources for its NIC by calling
|
|
NdisReadEisaSlotInformation or NdisReadEisaSlotInformationEx.
|
|
NIC drivers for PCI NICs and PCMCIA NICs obtain such information
|
|
by calling NdisMQueryAdapterResources.
|
|
|
|
When it calls <f MiniportInitialize>, the NDIS library supplies an
|
|
array of supported media types, specified as system-defined
|
|
NdisMediumXxx values. <f MiniportInitialize> reads the array
|
|
elements and provides the index of the medium type that NDIS
|
|
should use with this driver for its NIC. If the miniport is
|
|
emulating a medium type, its emulation must be transparent to NDIS.
|
|
|
|
The <f MiniportInitialize> function of a NIC driver must call
|
|
NdisMSetAttributes or NdisMSetAttributesEx before it calls
|
|
any NdisXxx function, such as NdisRegisterIoPortRange or NdisMMapIoSpace,
|
|
that claims hardware resources in the registry for the NIC.
|
|
MiniportInitialize must call NdisMSetAttributes(Ex) before it
|
|
attempts to allocate resources for DMA operations as well. If
|
|
the NIC is a busmaster, <f MiniportInitialize> must call
|
|
NdisMAllocateMapRegisters following its call to
|
|
NdisMSetAttributes(Ex) and before it calls NdisMAllocateSharedMemory.
|
|
If the NIC is a slave, MiniportInitialize must call
|
|
NdisMSetAttributes(Ex) before it calls NdisMRegisterDmaChannel.
|
|
|
|
Intermediate driver <f MiniportInitialize> functions must call
|
|
NdisMSetAttributesEx with NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER
|
|
set in the AttributeFlags argument. Setting this flag causes
|
|
NDIS to treat every intermediate driver as a full-duplex miniport,
|
|
thereby preventing rare but intermittant deadlocks when concurrent
|
|
send and receive events occur. Consequently, every intermediate
|
|
driver must be written as a full-duplex driver capable of handling
|
|
concurrent sends and indications.
|
|
|
|
If the NDIS library's default four-second time-out interval on
|
|
outstanding sends and requests is too short for the driver's NIC,
|
|
<f MiniportInitialize> can call NdisMSetAttributesEx to extend the
|
|
interval. Every intermediate driver also should call
|
|
NdisMSetAttributesEx with NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT
|
|
and NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT set in the AttributeFlags
|
|
so that NDIS will not attempt to time out sends and requests that
|
|
NDIS holds queued to the intermediate driver.
|
|
|
|
The call to NdisMSetAttributes or NdisMSetAttributesEx includes a
|
|
MiniportAdapterContext handle to a driver-allocated context area,
|
|
in which the miniport maintains runtime state information. NDIS
|
|
subsequently passes the supplied <t MiniportAdapterContext> handle as
|
|
an input parameter to other MiniportXxx functions.
|
|
|
|
Consequently, the <f MiniportInitialize> function of an intermediate
|
|
driver must call NdisMSetAttributesEx to set up the <t MiniportAdapterContext>
|
|
handle for a driver-allocated per-virtual-NIC context area. Otherwise,
|
|
NDIS would pass a NULL <t MiniportAdapterContext> handle in its subsequent
|
|
calls to the intermediate driver's other MiniportXxx functions.
|
|
|
|
After a call to NdisMRegisterIoPortRange, a miniport must call
|
|
the NdisRawXxx functions with the PortOffset value returned by
|
|
NdisMRegisterIoPortRange to communicate with its NIC. The NIC
|
|
driver can no longer call the NdisImmediateRead/WritePortXxx
|
|
functions. Similarly, after a call to NdisMMapIoSpace, a NIC
|
|
driver can no longer call NdisImmediateRead/WriteSharedMemory.
|
|
|
|
After it has claimed any bus-relative hardware resources for its
|
|
NIC in the registry, a miniport should no longer call any
|
|
bus-type-specific NdisReadXxx function.
|
|
|
|
After <f MiniportInitialize> calls NdisMRegisterInterrupt, the driver's
|
|
<f MiniportISR> function is called if the driver's NIC generates an
|
|
interrupt or if any other device with which the NIC shares an IRQ
|
|
interrupts. NDIS does not call the <f MiniportDisableInterrupt> and
|
|
<f MiniportEnableInterrupt> functions, if the driver supplied them,
|
|
during initialization, so it is such a miniport's responsibility
|
|
to acknowledge and clear any interrupts its NIC generates. If the
|
|
NIC shares an IRQ, the driver must first determine whether its NIC
|
|
generated the interrupt; if not, the miniport must return FALSE as
|
|
soon as possible.
|
|
|
|
If the NIC does not generate interrupts, <f MiniportInitialize> should
|
|
call NdisMInitializeTimer with a driver-supplied polling
|
|
MiniportTimer function and a pointer to driver-allocated memory
|
|
for a timer object. Drivers of NICs that generate interrupts and
|
|
intermediate drivers also can set up one or more <f MiniportTimer>
|
|
functions, each with its own timer object. <f MiniportInitialize> usually
|
|
calls NdisMSetPeriodicTimer to enable a polling <f MiniportTimer> function;
|
|
a driver calls NdisMSetTimer subsequently when conditions occur such
|
|
that the driver's nonpolling <f MiniportTimer> function should be run.
|
|
|
|
If the driver subsequently indicates receives with
|
|
NdisMIndicateReceivePacket, the MiniportInitialize function
|
|
should call NdisAllocatePacketPool and NdisAllocateBufferPool
|
|
and save the handles returned by these NDIS functions. The packets
|
|
that the driver subsequently indicates with NdisMIndicateReceivePacket
|
|
must reference descriptors that were allocated with NdisAllocatePacket
|
|
and NdisAllocateBuffer.
|
|
|
|
If driver functions other than <f MiniportISR> or <f MiniportDisableInterrupt>
|
|
share resources, <f MiniportInitialize> should call NdisAllocateSpinLock
|
|
to set up any spin lock necessary to synchronize access to such a set
|
|
of shared resources, particularly in a full-duplex driver or in a
|
|
driver with a polling <f MiniportTimer> function rather than an ISR.
|
|
Resources shared by other driver functions with <f MiniportISR> or
|
|
<f MiniportDisableInterrupt>, such as NIC registers, are protected
|
|
by the interrupt object set up when <f MiniportInitialize> calls
|
|
NdisMRegisterInterrupt and accessed subsequently by calling
|
|
NdisMSynchronizeWithInterrupt.
|
|
|
|
Any NIC driver's <f MiniportInitialize> function should test the
|
|
NIC to be sure the hardware is configured correctly to carry
|
|
out subsequent network I/O operations. If it must wait for
|
|
state changes to occur in the hardware, <f MiniportInitialize>
|
|
either can call NdisWaitEvent with the pointer to a driver-initialized
|
|
event object, or it can call NdisMSleep.
|
|
|
|
Unless the <f MiniportInitialize> function of a NIC driver will
|
|
return an error status, it should call
|
|
NdisMRegisterAdapterShutdownHandler with a driver-supplied
|
|
MiniportShutdown function.
|
|
|
|
If <f MiniportInitialize> will fail the initialization, it must
|
|
release all resources it has already allocated before it
|
|
returns control.
|
|
|
|
If <f MiniportInitialize> returns NDIS_STATUS_OPEN_ERROR, NDIS can
|
|
examine the value returned at OpenErrorStatus to obtain more
|
|
information about the error.
|
|
|
|
When <f MiniportInitialize> returns NDIS_STATUS_SUCCESS, the NDIS
|
|
library calls the driver's <f MiniportQueryInformation> function next.
|
|
|
|
By default, <f MiniportInitialize> runs at IRQL PASSIVE_LEVEL and in
|
|
the context of a system thread.
|
|
|
|
|
|
|
|
|
|
@rdesc
|
|
|
|
<f MiniportInitialize> can return either of the following:
|
|
|
|
@flag NDIS_STATUS_SUCCESS |
|
|
<f MiniportInitialize> configured and set up the NIC, and it allocated
|
|
all the resources the driver needs to carry out network I/O operations.
|
|
@flag NDIS_STATUS_FAILURE |
|
|
<f MiniportInitialize> could not set up the NIC to an
|
|
operational state or could not allocate needed resources.
|
|
<f MiniportInitialize> called NdisWriteErrorLogEntry with parameters
|
|
specifying the configuration or resource allocation failure.<nl>
|
|
|
|
As alternatives to NDIS_STATUS_FAILURE, <f MiniportInitialize>
|
|
can return one of the following values, as appropriate,
|
|
when it fails an initialization:
|
|
|
|
@flag NDIS_STATUS_UNSUPPORTED_MEDIA |
|
|
The values at MediumArray did not include a medium
|
|
the driver (or its NIC) can support.
|
|
@flag NDIS_STATUS_ADAPTER_NOT_FOUND |
|
|
<f MiniportInitialize> did not recognize the NIC either
|
|
from its description in the registry, using
|
|
NdisOpenConfiguration and NdisReadConfiguration,
|
|
or by probing the NIC on a particular I/O bus, using
|
|
one of the NdisImmediateXxx or bus-type-specific
|
|
NdisXxx configuration functions. This return can be
|
|
propagated from the miniport's call to certain NdisXxx
|
|
functions, such as NdisOpenConfiguration.
|
|
@flag NDIS_STATUS_OPEN_ERROR |
|
|
<f MiniportInitialize> attempted to set up a NIC
|
|
but was unsuccessful.
|
|
@flag NDIS_STATUS_NOT_ACCEPTED |
|
|
<f MiniportInitialize> could not get its NIC to
|
|
accept the configuration parameters that it got from
|
|
the registry or from a bus-type-specific NdisXxx
|
|
configuration function.
|
|
@flag NDIS_STATUS_RESOURCES |
|
|
Either <f MiniportInitialize> could not allocate
|
|
sufficient resources to carry out network I/O
|
|
operations or an attempt to claim bus-relative
|
|
hardware resources in the registry for the NIC
|
|
failed. This return can be propagated from the
|
|
miniport's call to an NdisXxx function.
|
|
If another device has already claimed a
|
|
resource in the registry that its NIC needs,
|
|
<f MiniportInitialize> also should call
|
|
NdisWriteErrorLogEntry to record the
|
|
particular resource conflict (I/O port range,
|
|
interrupt vector, device memory range, as appropriate).
|
|
Supplying an error log record gives the user or system
|
|
administrator information that can be used to reconfigure
|
|
the machine to avoid such hardware resource conflicts.
|
|
|
|
|
|
@xref
|
|
|
|
<f DriverEntry>
|
|
<f MiniportDisableInterrupt>
|
|
<f MiniportEnableInterrupt>
|
|
<f MiniportEnableInterrupt>
|
|
<f MiniportISR>
|
|
<f MiniportQueryInformation>
|
|
<f MiniportShutdown>
|
|
<f MiniportTimer>
|
|
|
|
*/
|
|
|
|
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.
|
|
|
|
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 NdisMediumWan media type.
|
|
*/
|
|
for (Index = 0; Index < MediumArraySize; Index++)
|
|
{
|
|
if (MediumArray[Index] == NdisMediumWan)
|
|
{
|
|
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)
|
|
{
|
|
/*
|
|
// 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 NdisMediumWan 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 INTERNAL Miniport Miniport_c MiniportHalt
|
|
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
|
|
|
|
@func
|
|
|
|
<f MiniportHalt> request is used to halt the adapter such that it is
|
|
no longer functioning.
|
|
|
|
@comm
|
|
|
|
<f MiniportHalt> should stop the NIC, if it controls a physical
|
|
NIC, and must free all resources that the driver allocated for
|
|
it's NIC before <f MiniportHalt> returns control. In effect,
|
|
<f MiniportHalt> undoes everything that was done by <f MiniportInitialize>
|
|
for a particular NIC.
|
|
|
|
If the NIC driver allocated memory, claimed an I/O port range,
|
|
mapped on-board device memory to host memory, initialized timer(s)
|
|
and/or spin lock(s), allocated map registers or claimed a DMA channel,
|
|
and registered an interrupt, that driver must call the reciprocals of the
|
|
NdisXxx functions with which it originally allocated these resources.
|
|
|
|
As a general rule, a <f MiniportHalt> function should call reciprocal
|
|
NdisXxx functions in inverse order to the calls the driver made from
|
|
<f MiniportInitialize>. That is, if a NIC driver's <f MiniportInitialize>
|
|
function called NdisMRegisterAdapterShutdownHandler just before
|
|
it returned control, its <f MiniportHalt> function would call
|
|
NdisMDeregisterAdapterShutdownHandler first.
|
|
|
|
If its NIC generates interrupts or shares an IRQ, a NIC driver's
|
|
<f MiniportHalt> function can be pre-empted by its <f MiniportISR> or
|
|
<f MiniportDisableInterrupt> function until <f MiniportHalt> calls
|
|
NdisMDeregisterInterrupt. Such a driver's <f MiniportHalt>
|
|
function usually disables interrupts on the NIC, if
|
|
possible, and calls NdisMDeregisterInterrupt as soon
|
|
as it can.
|
|
|
|
If the driver has a <f MiniportTimer> function associated
|
|
with any timer object that might be in the system timer
|
|
queue, <f MiniportHalt> should call NdisMCancelTimer.
|
|
|
|
Otherwise, it is unnecessary for the miniport to complete
|
|
outstanding requests to its NIC before <f MiniportHalt> begins
|
|
releasing allocated resources. NDIS submits no further
|
|
requests to the miniport for the NIC designated by the
|
|
MiniportAdapterContext handle when NDIS has called <f MiniportHalt>.
|
|
On return from <f MiniportHalt>, NDIS cleans up any state it was
|
|
maintaining about this NIC and about its driver if this
|
|
miniport supports no other NICs in the current machine.
|
|
|
|
An NDIS intermediate driver's call to
|
|
NdisIMDeinitializeDeviceInstance causes a
|
|
call to it's <f MiniportHalt> function.
|
|
|
|
By default, <f MiniportHalt> runs at IRQL PASSIVE_LEVEL.
|
|
|
|
Interrupts are enabled during the call to this routine.
|
|
|
|
@xref
|
|
<f MiniportInitialize>
|
|
<f MiniportShutdown>
|
|
|
|
*/
|
|
|
|
VOID MiniportHalt(
|
|
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
|
|
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
|
|
)
|
|
{
|
|
DBG_FUNC("MiniportHalt")
|
|
|
|
NDIS_TAPI_PROVIDER_SHUTDOWN TapiShutDown;
|
|
// We use this message to make sure TAPI is cleaned up.
|
|
|
|
ULONG DummyLong;
|
|
// Don't care about the return value.
|
|
|
|
DBG_ENTER(DbgInfo);
|
|
|
|
/*
|
|
// Remove our shutdown handler from the system.
|
|
*/
|
|
NdisMDeregisterAdapterShutdownHandler(pAdapter->MiniportAdapterHandle);
|
|
|
|
/*
|
|
// Make sure all the lines are hungup and indicated.
|
|
// This should already be the case, but let's be sure.
|
|
*/
|
|
TapiShutDown.ulRequestID = OID_TAPI_PROVIDER_SHUTDOWN;
|
|
TspiProviderShutdown(pAdapter, &TapiShutDown, &DummyLong, &DummyLong);
|
|
|
|
/*
|
|
// Free adapter instance.
|
|
*/
|
|
AdapterDestroy(pAdapter);
|
|
|
|
DBG_LEAVE(DbgInfo);
|
|
}
|
|
|
|
|
|
/* @doc 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 <f 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 <f MiniportInitialize> function must call
|
|
NdisMRegisterAdapterShutdownHandler to set up a <f MiniportShutdown>
|
|
function. The driver's <f 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.
|
|
|
|
@xref
|
|
|
|
<f MiniportHalt>
|
|
<f MiniportInitialize>
|
|
|
|
*/
|
|
|
|
VOID MiniportShutdown(
|
|
IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm
|
|
// A pointer to the <t MINIPORT_ADAPTER_OBJECT> instance.
|
|
// This was supplied when the NIC driver's <f MiniportInitialize>
|
|
// function called NdisMRegisterAdapterShutdownHandler. Usually,
|
|
// this input parameter is the NIC-specific <t MINIPORT_ADAPTER_CONTEXT>
|
|
// pointer passed to other MiniportXxx functions
|
|
)
|
|
{
|
|
DBG_FUNC("MiniportShutdown")
|
|
|
|
DBG_ENTER(pAdapter);
|
|
|
|
/*
|
|
// Reset the hardware and bial out - don't release any resources!
|
|
*/
|
|
CardReset(pAdapter->pCard);
|
|
|
|
DBG_LEAVE(pAdapter);
|
|
}
|
|
|
|
|
|
/* @doc 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.
|
|
|
|
@comm
|
|
|
|
<f MiniportReset> can reset the parameters of its NIC. If a reset
|
|
causes a change in the NIC's station address, the miniport
|
|
automatically restores the station address following the reset
|
|
to its prior value. Any multicast or functional addressing masks
|
|
reset by the hardware do not have to be reset in this function.
|
|
|
|
If other information, such as multicast or functional addressing
|
|
information or the lookahead size, is changed by a reset,
|
|
<f MiniportReset> must set the variable at AddressingReset to TRUE
|
|
before it returns control. This causes NDIS to call the
|
|
<f MiniportSetInformation> function to restore the information.
|
|
|
|
As a general rule, the <f MiniportReset> function of an NDIS
|
|
intermediate driver should always set AddressingReset to TRUE.
|
|
Until the underlying NIC driver resets its NIC, such an intermediate
|
|
driver cannot determine whether it must restore addressing
|
|
information for its virtual NIC. Because an intermediate driver
|
|
disables the NDIS library's timing out of queued sends and requests
|
|
to itself with an initialization-time call to NdisMSetAttributesEx,
|
|
such a driver's <f MiniportReset> function is called only when a reset
|
|
request is directed to the underlying NIC driver.
|
|
|
|
Intermediate drivers that layer themselves above other types of
|
|
device drivers also must have a <f MiniportReset> function. Such a
|
|
<f MiniportReset> function must handle reset requests initiated by
|
|
protocol drivers' calls to NdisReset. If the intermediate driver
|
|
also has a <f MiniportCheckForHang> function, its <f MiniportReset> function
|
|
will be called whenever MiniportCheckForHang returns TRUE.
|
|
|
|
It is unnecessary for a driver to complete outstanding requests
|
|
before <f MiniportReset> begins resetting the NIC or updating its
|
|
software state. NDIS submits no further requests to the miniport
|
|
for the NIC designated by the <t MINIPORT_ADAPTER_CONTEXT> handle when
|
|
NDIS has called <f MiniportReset> until the reset operation is completed.
|
|
A miniport need not call NdisM(Co)IndicateStatus to signal the start
|
|
and finish of each reset operation because NDIS notifies bound
|
|
protocols when a reset begins and ends.
|
|
|
|
If <f MiniportReset> must wait for state changes in the NIC during
|
|
reset operations, it can call NdisStallExecution. However, a
|
|
MiniportReset function should never call NdisStallExecution
|
|
with an interval greater than 50 microseconds.
|
|
|
|
If <f MiniportReset> returns NDIS_STATUS_PENDING, the driver must
|
|
complete the original request subsequently with a call to
|
|
NdisMResetComplete.
|
|
|
|
<f MiniportReset> can be pre-empted by an interrupt.
|
|
|
|
If a NIC driver supplies a <f MiniportCheckForHang> function,
|
|
the NDIS library calls it periodically to determine whether
|
|
to call the driver's <f MiniportReset> function. Otherwise, the
|
|
NDIS library calls a NIC driver's <f MiniportReset> function whenever
|
|
requests NDIS submitted to the <f MiniportQueryInformation>,
|
|
<f MiniportSetInformation>, MiniportSendPackets, MiniportSend,
|
|
or <f MiniportWanSend> function seem to have timed out. (NDIS does
|
|
not call a deserialized NIC driver's <f MiniportReset> function if
|
|
the driver's MiniportSend or MiniportSendPackets function seems
|
|
to have timed out, nor does NDIS call a connection-oriented NIC
|
|
driver's <f MiniportReset> function if the driver's MiniportCoSendPackets
|
|
function seems to have timed out.) By default, the NDIS-determined
|
|
time-out interval for outstanding sends and requests is around
|
|
four seconds. If this default is too short, a NIC driver can make
|
|
an initialization-time call to NdisMSetAttributesEx, rather than
|
|
NdisMSetAttributes, to lengthen the time-out interval to suit its NIC.
|
|
|
|
Every NDIS intermediate driver should call NdisMSetAttributesEx
|
|
from <f MiniportInitialize> and disable NDIS's attempts to time out
|
|
requests and sends in the intermediate driver. NDIS runs an
|
|
intermediate driver's <f MiniportCheckForHang> function, if any,
|
|
approximately every two seconds.
|
|
|
|
NDIS cannot determine whether a NIC might be hung on receives,
|
|
so supplying a <f MiniportCheckForHang> function allows a driver to
|
|
monitor its NIC for this condition and to force a reset if it occurs.
|
|
|
|
By default, MiniportReset runs at IRQL DISPATCH_LEVEL.
|
|
|
|
@devnote
|
|
|
|
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> allways returns <f NDIS_STATUS_HARD_ERRORS>.
|
|
|
|
@xref
|
|
<f MiniportCheckForHang>
|
|
<f MiniportInitialize>
|
|
<f MiniportQueryInformation>
|
|
<f MiniportSetInformation>
|
|
<f MiniportWanSend>
|
|
|
|
*/
|
|
|
|
NDIS_STATUS MiniportReset(
|
|
OUT PBOOLEAN AddressingReset, // @parm
|
|
// The Miniport indicates if the wrapper needs to call
|
|
// <f MiniportSetInformation> 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);
|
|
}
|
|
|