Initializing a Miniport Driver
When a networking device becomes available, the system loads the NDIS miniport driver to manage the device (if the driver is not already loaded). Every miniport driver must provide a DriverEntry function. The system calls DriverEntry after it loads the driver. DriverEntry registers the miniport driver’s characteristics with NDIS (including the supported NDIS version and the driver entry points).
The system passes two arguments to DriverEntry:
A pointer to the driver object, which was created by the I/O system.
A pointer to the registry path, which specifies where driver-specific parameters are stored.
In DriverEntry, miniport drivers pass both of these pointers in a call to the NdisMRegisterMiniportDriver function. Miniport drivers export a set of standard MiniportXxx functions by storing their entry points in an NDIS_MINIPORT_DRIVER_CHARACTERISTICS structure and passing that structure to NdisMRegisterMiniportDriver.
DriverEntry for miniport drivers returns the value that is returned by the call to NdisMRegisterMiniportDriver.
A miniport driver also performs any other driver-specific initialization that it requires in DriverEntry. The driver performs adapter-specific initialization in the MiniportInitializeEx function. For more information about adapter initialization, see Initializing an Adapter.
DriverEntry can allocate the NDIS_MINIPORT_DRIVER_CHARACTERISTICS structure on the stack because 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 MajorNdisVersion and MinorNdisVersion members must contain the major and minor versions of NDIS that the driver supports. In each XxxHandler member of the characteristics structure, DriverEntry must set the entry point of a driver-supplied MiniportXxx function, or the member must be NULL.
To enable a miniport driver to configure optional services, NDIS calls the MiniportSetOptions function within the context of the miniport driver’s call to NdisMRegisterMiniportDriver. For more information about optional services, see Configuring Optional Miniport Driver Services.
Drivers that call NdisMRegisterMiniportDriver must be prepared for NDIS to call their MiniportInitializeEx functions any time after DriverEntry returns. 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.
The miniport driver must eventually call NdisMDeregisterMiniportDriver to release resources that it allocated by calling NdisMRegisterMiniportDriver. If the driver initialization fails after the call to NdisMRegisterMiniportDriver succeeded, the driver can call NdisMDeregisterMiniportDriver from within DriverEntry. Otherwise, the miniport driver must release the driver-specific resources that it allocates in its MiniportDriverUnload function. In other words, if NdisMRegisterMiniportDriver does not return NDIS_STATUS_SUCCESS, DriverEntry must release any resources that it allocated before it returns control. The driver will not be loaded if this occurs. For more information, see Unloading a Miniport Driver.
Miniport Driver Hardware Reset
MiniportResetEx can complete synchronously or asynchronously with a call to NdisMResetComplete(see the following figure).
Disable further interrupts.
Clear out the data that is associated with any sends in progress. For example, on a ring buffer for a bus-master direct memory access (DMA) device, the pointers to send buffers should be cleared. Deserialized and connection-oriented miniport drivers must return NDIS_STATUS_REQUEST_ABORTED for any queued send requests.
Restore the hardware state and the miniport driver’s internal state to the state that existed before the reset operation.
The miniport driver is responsible for restoring the hardware state of the device except for multicast addresses, packet filters, task offload settings, and wake up patterns. These setting are restored by either the miniport driver or NDIS. The miniport driver determines who is responsible for restoring these settings by returning a Boolean value in the AddressingReset parameter.
If the miniport driver returns FALSE in the AddressingReset parameter, the miniport driver restores its multicast addresses, packet filters, task offload settings, and wake up patterns to their initial state. If the miniport driver returns TRUE in AddressingReset, NDIS calls a connectionless miniport driver’s MiniportOidRequest function or a connection-oriented miniport driver’s MiniportCoOidRequest function to set the following configuration settings:
The network packet filter through a set request of OID_GEN_CURRENT_PACKET_FILTER.
The multicast address list through a set request of OID_802_3_MULTICAST_LIST.
Task offload encapsulation settings through a set request of OID_OFFLOAD_ENCAPSULATION.
Power management wake-up patterns through a set request of OID_PNP_ADD_WAKE_UP_PATTERN. NoteВ В Starting with NDIS 6.20, wake-up patterns set through OID_PM_ADD_WOL_PATTERN must be restored by the miniport driver.
Miniport drivers
An NDIS miniport driver has two basic functions:
Managing a network interface card (NIC), including sending and receiving data through the NIC.
Interfacing with higher-level drivers, such as filter drivers, intermediate drivers, and protocol drivers.
A miniport driver communicates with its NICs and with higher-level drivers through the NDIS library. The NDIS library exports a full set of functions (NdisMXxx and other NdisXxx functions) that encapsulate all of the operating system functions that a miniport driver must call. The miniport driver, in turn, must export a set of entry points (MiniportXxx functions) that NDIS calls for its own purposes, or on behalf of higher-level drivers, to access the miniport driver.
For more information about the NDIS driver stack and a diagram showing the relationship between all four NDIS driver types, see NDIS Driver Stack.
The following send and receive operations illustrate the interaction of miniport drivers with NDIS and with higher-level drivers:
When a transport driver has a packet to transmit, it calls an NdisXxx function exported by the NDIS library. NDIS then passes the packet to the miniport driver by calling the appropriate MiniportXxx function exported by the miniport driver. The miniport driver then forwards the packet to the NIC for transmission by calling the appropriate NdisXxx functions.
When a NIC receives a packet addressed to itself, it can post a hardware interrupt that is handled by NDIS or the NIC’s miniport driver. NDIS notifies the NIC’s miniport driver by calling the appropriate MiniportXxx function. The miniport driver sets up the transfer of data from the NIC and then indicates the presence of the received packet to bound higher-level drivers by calling the appropriate NdisXxx function.
Connectionless and Connection-Oriented Miniport Drivers
NDIS supports miniport drivers for both connectionless environments and connection-oriented environments.
Connectionless miniport drivers control NICs for connectionless network media, such as Ethernet. Connectionless miniport drivers are further divided into deserialized and serialized drivers:
NoteВ В All NDIS 6.0 and later drivers are deserialized.
Deserialized drivers serialize the operation of their own MiniportXxx functions and that internally queue all incoming send packets. This results in significantly better full-duplex performance, provided that the driver’s critical sections (code that only a single thread at a time can run) are kept small.
Serialized drivers rely on NDIS to serialize calls to their MiniportXxx functions and to manage their send queues.
Connection-oriented miniport drivers control NICs for connection-oriented network media, such as ISDN. Connection-oriented miniport drivers are always deserialized — they always serialize the operation of their own MiniportXxx functions and queue internally all incoming send packets.
An NDIS miniport driver can have a non-NDIS lower edge (see the following figure).
Through its non-NDIS lower edge, a miniport driver uses the class interface for a bus, such as the Universal Serial Bus (USB) to control a device on the bus. The miniport driver communicates with the device by sending I/O request packets (IRPs) either to the bus or directly to remote devices that are attached to the bus. At its upper edge, the miniport driver exposes a standard NDIS miniport driver interface, which enables the miniport driver to communicate with overlying NDIS drivers.
Deserialized NDIS Miniport Drivers
All NDIS 6.0 and later drivers are deserialized.
A deserialized NDIS miniport driver serializes the operation of its own MiniportXxx functions and queues internally all send requests rather than relying on NDIS to perform these functions. As a result, a deserialized miniport driver can achieve significantly better full-duplex performance than a serialized miniport driver.
The deserialized driver model is the default model for NDIS miniport drivers. Connection-oriented miniport drivers, as well as miniport drivers with a WDM lower edge, must be deserialized drivers. When writing a new NDIS miniport driver, you should write a deserialized driver. If possible, you should also port older drivers to NDIS 6.0 or later. For more information about porting drivers, see:
A deserialized miniport driver must meet the following requirements when it interfaces with NDIS:
A deserialized miniport driver must identify itself as such to NDIS during initialization.
A deserialized miniport driver must complete all send requests asynchronously. To complete a send request, connectionless NDIS 6.0 and later miniport drivers call the NdisMSendNetBufferListsComplete function. Connection-oriented NDIS 6.0 and later miniport drivers call the NdisMCoSendNetBufferListsComplete function.
A deserialized miniport driver that supports NDIS 6.0 or later sets the Status member of the NET_BUFFER_LIST structure that it will pass to NdisMSendNetBufferListsComplete.
If a deserialized miniport driver cannot immediately complete send requests, it cannot return the requests to NDIS for requeuing. Instead, the miniport driver must queue send requests internally until sufficient resources are available to transmit the data.
A deserialized miniport driver must not examine the structures that it passes to NDIS in receive indications until after NDIS returns them. NDIS returns NET_BUFFER_LIST structures to a miniport driver’s MiniportReturnNetBufferLists function.
A deserialized miniport driver must meet the following driver-internal requirements:
A deserialized miniport driver must protect its network buffer queues with spin locks. A deserialized miniport driver must also protect its shared state from simultaneous access by its own MiniportXxx functions.
A deserialized miniport driver’s MiniportXxx functions can run at IRQL —>
SCSI Miniport Drivers
This section contains the following information:
SCSI miniport drivers for NT-based operating systems are HBA-specific but operating system-independent. That is, each miniport driver links itself with the system-supplied SCSI port driver, which is a dynamic-link library (DLL), and calls only the port driver’s ScsiPortXxx routines to communicate with the system and its HBA. Such SCSI miniport drivers run on other Microsoft operating systems that support Microsoft Win32 applications and also export the ScsiPortXxx routines. For more information about the ScsiPortXxx routines, see SCSI Port Driver Support Routines.
Note that any SCSI miniport driver that calls routines other than the ScsiPortXxx cannot run in both Microsoft operating system environments. To remain portable across Microsoft Windows systems, including NT-based operating systems, SCSI miniport drivers must call only the system-supplied ScsiPortXxx.
A SCSI miniport driver can be a Plug and Play driver, or it can run as a legacy driver that does not participate in Plug and Play operations such as resource redistribution or power management. The primary differences between a Plug and Play and a legacy miniport driver are the order in which initialization routines are called and enforcement of certain restrictions that were applied to miniport drivers in Microsoft Windows NT 4.0, but not enforced.