NDIS Implementation in Microsoft Windows CE Platform Builder 3.0

Windows CE 3.0

Microsoft Corporation

July 2000

Summary: This white paper describes the implementation of the Network Driver Interface Specification (NDIS) in Microsoft Windows CE Platform Builder 3.0. (36 pages)

Contents

Introduction
Windows CE Implementation of NDIS
Differences Between Windows CE and Windows NT Implementations
What Is NDIS?
Windows CE Communications Architecture
Windows CE Miniport-Driver Architecture
Protocol Drivers
Installing Network Adapter Drivers
IrDA Support
NDIS Token Ring Support
NDISWAN Support
DMA

Introduction

This white paper describes the implementation of the Network Driver Interface Specification (NDIS) in Microsoft® Windows® CE Platform Builder 3.0. NDIS refers to the interface by which one or more local area network (LAN) and wide area network (WAN) adapter drivers communicate with one or more underlying network adapters, one or more overlying protocol drivers, one or more miniport drivers, and the operating system (OS). The Windows CE 3.0 communications architecture provides support for NDIS version 4.0. Windows CE 3.0 offers an array of new and improved NDIS features.

Windows CE 3.0 supports new features that include intermediate drivers that expose an NDIS protocol-driver interface, NDISWAN, Token Ring, a layered miniport-driver structure, and an improved structure for the binding of adapters. This white paper provides a brief outline of each one of these features. It also describes how the NDIS implementation in Microsoft Windows NT version 4.0 differs from the NDIS implementation in Windows CE 3.0, and it provides guidelines for programmers on how to handle these differences when they are writing NDIS drivers for Windows CE.

Windows CE Implementation of NDIS

Windows CE 3.0 supports NDIS 4.0, which also is implemented in Windows NT 4.0. The NDIS implementation in both Windows CE and Windows NT 4.0, with some minor exceptions, is source-code compatible. NDIS miniport drivers are fully portable, and you should be able to port an existing miniport driver from Windows NT to a Windows CE-based device. You also can create a customized miniport driver for a Windows CE-based device by following the steps that are provided in the Windows CE driver development kit (DDK) on how to write a miniport driver. Because Windows CE does not require backward compatibility with legacy drivers, it does not support full NIC (network interface card) drivers or monolithic network drivers.

Windows CE 3.0 features a built-in tool for testing NDIS miniport drivers. This testing tool, which is called NDISTest, allows you to perform functionality, stress, and performance tests on NDIS miniport drivers. NDISTest is implemented as a protocol driver and ships with a set of LAN test scripts. For more detailed information on NDISTest and how to use it, consult the Windows CE Device Driver Test Kit (DDTK).

The NDIS implementation in Windows CE 3.0 includes some new and improved features, such as support of Token Ring and NDISWAN, and full support of intermediate drivers. The new dynamic adapter-binding feature that is implemented in Windows CE 3.0 provides a more flexible system of managing the binding and unbinding of network adapters.

The following list shows the key features of NDIS support in Windows CE 3.0:

  • Portability of drivers between platforms that support NDIS.
  • Support for network adapter miniport drivers.
  • Support for intermediate (including layered) and upper-level drivers.
  • Support for Ethernet (802.3), Token Ring (802.5), and Infrared Data Association (IrDA) medium types.
  • Support for the WAN medium type.
  • Support for ISA, PCI, and PC Card devices.
  • Dynamic binding of adapters, and support for Plug and Play.
  • Support for multiple network adapters that are bound to the same protocol.

Differences Between Windows CE and Windows NT Implementations

Although the NDIS implementation in Windows CE and Windows NT is source-code compatible, and although each OS, with a few exceptions, supports identical APIs, there are some differences in the implementations of NDIS between Windows CE and Windows NT:

  • Windows NT and Windows CE share the same source code for miniport drivers, but each OS uses a different compilation method. In Windows NT, miniport drivers are compiled as system (.sys) files. Because Windows CE does not support system files, you must compile a miniport driver as a dynamic link library (DLL). To compile a miniport driver as a DLL, the driver must export the DriverEntry function in its module definition (.def) file. DriverEntry initializes the driver and calls other functions in the DLL to perform platform-specific initializations.
  • Windows CE does not support input (.inf) files for dynamic installation and configuration of NDIS miniport drivers.
  • Windows CE does not provide built-in support for Direct Memory Access (DMA) functionality. However, developers can implement DMA code in a miniport driver for a specific combination of a Windows CE-based platform and a network adapter. This white paper provides a code sample on how to implement DMA operations in a miniport driver for Windows CE.
  • Windows CE does not support contiguous physical memory allocations. This memory must be allocated in a platform-specific way.
  • The NDIS wrapper interface (Ndis.dll) that is supported in Windows CE does not make any calls to the multipacket send handler in the miniport driver.
  • The I/O port address that is returned from the NdisMRegisterIoPortRange function represents a 32-bit virtual address in Windows CE and should be treated as a 32-bit value. Because Windows CE does not use the lower 64 KB region of the I/O address space, you should not use 16-bit values for I/O port addresses. Many Windows CE devices emulate I/O ports on top of mapped memory.
  • The Windows CE implementation of NDIS does not provide access to the PCMCIA attribute memory. A driver instead must use the PC Card Services functions to read the card information.
  • In Windows CE, the IrDA protocol driver supports only a single statically bound adapter.
  • The NdisSendPackets function is not supported in Windows CE.

What Is NDIS?

NDIS describes the interface by which one or more network adapter drivers communicate with one or more underlying network adapters, with one or more overlying protocol drivers, with one or more miniport drivers, and with the OS. NDIS provides a fully abstracted interface for network adapter driver development.

NDIS provides a pair of abstraction layers that are used to connect network drivers to an overlying protocol stack, such as Transmission Control Protocol/Internet Protocol (TCP/IP) or IrDA, and an underlying network adapter. NDIS performs a set of external functions for network adapter drivers, such as registering and intercepting hardware interrupts and communicating with underlying network adapters.

The Windows library (Ndis.dll) provides a fully abstracted interface to which you can write a customized network adapter driver for Windows CE. This library exports all of the Windows CE kernel-mode functions that are required for driver development. The Ndis.dll file also maintains binding and state information about all of the underlying network adapter drivers. NDIS supports the following network components:

  • A network adapter driver that receives a network packet from an upper-layer driver for transmission on the network through an underlying network adapter.
  • A network adapter driver that accepts a network packet from an underlying network adapter and passes the packet up to an upper-layer driver.
  • An upper-layer driver that sets specific configuration parameters for a network adapter or a network adapter driver.
  • An upper-layer driver that queries a network adapter driver for specific configuration data from an underlying network adapter or from the network adapter driver.
  • A network adapter driver that informs an overlying driver asynchronously of changes in the status of the network or of the network adapter.

Figure 1 shows the general NDIS architecture that is implemented in Windows CE-based platforms.

Figure 1. General NDIS architecture in Windows CE-based platforms

The NDIS interface is located between an upper-level protocol driver (such as the TCP/IP protocol driver on the top of the communications architecture), the intermediate and miniport drivers in the middle of the communications architecture, and a network adapter at the bottom of the communications architecture. Because NDIS provides an interface to the upper and lower edges of a miniport driver, the NDIS interface often is referred to as the NDIS Wrapper. The NDIS Wrapper provides the operating environment for drivers that use NDIS; its components are located in the Ndis.dll file.

Windows CE Communications Architecture

One of the key features of Windows CE-based devices is their ability to communicate with other devices. Windows CE supports two basic types of communication: serial communication and communication over a network. Most devices feature built-in communications hardware, such as a serial port or an IR transceiver. The NDIS implementation in Windows CE supports the following communications media: Ethernet (802.3), Token Ring (802.5), IrDA, and WAN.

Figure 2 outlines the communications architecture of the Windows CE OS.

Figure 2. Communications architecture of the Windows CE operating system

In the Windows CE communications architecture, the NDIS interface is located below the IrDA, TCP/IP, and Point-to-Point Protocol (PPP) protocol drivers. The NDIS Wrapper presents an interface to the upper and lower edges of a miniport driver. To an upper-level driver, such as the TCP/IP protocol driver, the NDIS interface looks like a miniport driver. To the miniport, the NDIS interface looks like an upper-level protocol driver. At the bottom of the communications architecture, the NDIS interface functions as a network adapter driver that interfaces directly with the network adapter at the lower edge. At the upper edge, the network adapter driver presents an interface to allow upper layers to send packets on the network, handle interrupts, reset or halt the network adapter, and query or set the operational characteristics of the driver.

Windows CE Miniport-Driver Architecture

Miniport drivers directly manage network adapters that are installed on a device. At the lower edge, miniport drivers use NDIS to "talk" to the adapter hardware. At the upper edge, miniport drivers present an interface to allow protocol drivers to configure the adapter, as well as to send and receive packets over the network.

Windows CE 3.0 supports WAN miniport drivers. A WAN miniport provides protocol drivers (for example, PPP) access to a WAN interface.

Windows CE currently supports miniport drivers for the following medium types:

  • Ethernet (802.3)
  • Token Ring (802.5)
  • IrDA
  • WAN

Writing a Miniport Driver

When you write an NDIS miniport driver, you should ensure that the driver is easily portable across all of the other platforms that support the NDIS 4.0 interface. Ideally, porting from one hardware platform to another will require only recompilation with a system-compatible compiler.

To guarantee cross-platform portability, you should avoid calling OS-specific functions and, instead, use the NDIS equivalents of such calls. NDIS exports a wide array of functions for writing drivers, so that it is not necessary to make calls to the OS directly.

You should write your miniport driver in the C language by using the ANSI C standard. Make sure not to include any calls to C run-time library functions in your driver code, instead of NDIS-provided functions. Kernel mode on Windows NT does not allow the use of floating-point operations; so, if you use floating-point calls in your driver, the driver might work only on Windows CE. If you must include platform-specific features in your driver, make sure to encapsulate the code between the #ifdef and #endif statements.

Windows CE 3.0 ships with several samples of driver code. Driver developers should consult this sample code to gain a better understanding of the concept of writing an NDIS miniport driver for Windows CE. The driver sample code that is shipped with Windows CE 3.0 includes the following:

  • NE2000 ISA, PCI, and PC Card drivers
  • Proxim Wireless Ethernet PC Card driver
  • FAST IR driver that uses the National Semiconductor chip set

For a set of detailed instructions on how to write a customized miniport driver for Windows CE, see the Windows CE DDK.

Driver Registration and NDIS Library Initialization

All NDIS miniport and intermediate drivers must provide a DriverEntry function. When a miniport driver is loaded, NDIS calls DriverEntry, which creates an association between the miniport driver and the NDIS library, and registers the miniport driver with NDIS.

The DriverEntry function requires the following syntax:

NTSTATUS DriverEntry(
IN PDRIVER_OBJECT pDriverObject_, 
IN PUNICODE_STRING pRegistryPath_);

The following parameters are passed into the DriverEntry function:

  • 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.

The DriverEntry function must call the NdisMInitializeWrapper function, and then the NdisMRegisterMiniport function. DriverEntry first calls NdisMRegisterMiniport with the parameters that are passed to DriverEntry, which returns a wrapper handle. DriverEntry then passes the handle to NdisMRegisterMiniport.

Windows CE does not support the common network .inf file format for dynamic installation and registry configuration of miniport drivers that are used in Windows NT. Instead, Windows CE uses the registry for dynamic installation and binding of device drivers. Therefore, your driver installation program must make sure to create the appropriate registry settings for your miniport driver in the Windows CE registry.

Figure 3 shows the process for registering a miniport driver and initializing the NDIS library.

Figure 3. Registering a miniport driver and initializing the NDIS library

Layered Miniport Drivers

The NDIS architecture that is implemented in Windows CE also features intermediate drivers. An NDIS intermediate driver does not use NDIS functions to control adapter hardware. Instead, it sits on top of another driver, such as the serial driver. The "layered" driver model represents a special kind of intermediate driver that sits on top of an NDIS miniport driver. Windows CE 3.0 now also supports a layered driver architecture. A layered miniport driver exposes a miniport-driver interface to the overlying protocol driver and a protocol-driver interface to the underlying miniport. In a layered miniport-driver structure, the protocol driver "talks" to a miniport driver that is at the bottom of the layered miniport driver. A layered miniport driver exports MiniportXxx functions at its upper edge and ProtocolXxx functions at its lower edge.

Layered miniport drivers are used to filter out certain packets or to perform other special functions, such as decryption and encryption of data. To prevent packets from looping back between the layered driver and the miniport driver, the layered driver should set the NDIS_FLAGS_DONT_LOOPBACK packet flag by calling the NdisSetPacketFlags function.

A layered miniport driver calls the NdisOpenAdapter function to open and establish a binding to an underlying adapter driver or intermediate NDIS driver that exports a set of MiniportXxx functions at its upper edge. A layered miniport driver exports the MiniportSetInformation and MiniportQueryInformation functions to process Set and Query requests from a higher-level driver, and to pass them on to a lower-level driver.

NdisMXxx functions may be called only when the driver is running in a miniport-driver context. If the function of a layered miniport driver is not in a miniport-driver context, make sure to use the NdisIMSwitchToMiniport function before you call any MiniportXxx functions. Use the NdisIMRevertBack function to leave the miniport-driver context. All of the miniport-driver handler functions that are registered with NDIS will be called by NDIS within a miniport-driver context.

Figure 4 shows the layered NDIS miniport-driver architecture that is supported in Windows CE 3.0.

Figure 4. Layered NDIS miniport-driver architecture supported in Windows CE 3.0

Table 1 lists a set of new NDIS library functions that are supported in Windows CE. These functions apply to intermediate drivers.

Table 1. New NDIS library functions that are supported in Windows CE

Function Description
NdisIMDeInitializeDeviceInstance Calls the MiniportHalt function of an NDIS intermediate driver to tear down the virtual network adapter of the driver.
NdisIMGetDeviceContext Allows the MiniportInitialize function of an NDIS intermediate driver to access the device context area that is allocated by its ProtocolBindAdapter function.
NdisIMInitializeDeviceInstance Calls the MiniportInitialize function of an NDIS intermediate driver to set up the virtual network adapter of the driver for I/O operations on an underlying network adapter driver to which the intermediate driver is bound.
NdisIMInitializeDeviceInstanceEx Calls the MiniportInitialize function of an NDIS intermediate driver to initialize the virtual network adapter of the driver and, optionally, to set up state information about the virtual network adapter of the driver for subsequently bound protocols.
NdisIMRegisterLayeredMiniport Registers an intermediate driver's MiniportXxx entry points and name with the NDIS library when the driver initializes.

Any NDIS intermediate or layered miniport driver that exports both MiniportXxx and ProtocolXxx functions usually sets up a characteristics structure and calls the NdisIMRegisterLayeredMiniport function from its DriverEntry function after DriverEntry calls the NdisMInitializeWrapper function. This structure is copied in the NdisIMRegisterLayeredMiniport request to the internal storage of the NDIS library. Thus, once it has registered, such a driver cannot change its handler functions. An intermediate driver can call the NdisMRegisterMiniport function, instead of the NdisIMRegisterLayeredMiniport function, if it is prepared for an immediate call to the MiniportInitialize function.

NDIS Driver Upper-Edge Functions

NDIS intermediate drivers and layered miniport drivers export a subset of MiniportXxx functions and a DriverEntry function that fulfills the initialization-time requirements of the NDIS library. NDIS miniport drivers, as well as NDIS intermediate drivers, export NDIS upper-edge functions.

The following table lists the NDIS driver upper-edge functions that are supported in Windows CE.

Table 2. NDIS driver upper-edge functions supported in Windows CE 3.0

Function Description
DriverEntry Is called by the OS to activate and initialize the network adapter driver.
MiniportCheckForHang Checks the internal state of the network adapter.
MiniportDisableInterrupt Disables the network adapter from generating interrupts.
MiniportEnableInterrupt Enables the network adapter to generate interrupts.
MiniportHalt De-allocates and de-registers resources that are used for the network adapter, and halts the network adapter.
MiniportHandleInterrupt Is called to complete interrupt-driven I/O processing; this is a deferred processing function.
MiniportInitialize Initializes the network adapter.
MiniportISR Runs at a high priority as the interrupt service function for the network adapter.
MiniportQueryInformation Queries the capabilities and current status of the miniport driver.
MiniportReconfigure Currently, the NDIS library never calls this function; but a MiniportInitialize function can call a MiniportReconfigure function as an internal driver function.
MiniportReset Issues a hardware reset to the network adapter.
MiniportReturnPacket Receives a packet from an upper layer that previously was passed up by a call to the NdisMIndicateReceivePacket function.
MiniportSend Transmits a packet though the network adapter onto the network.
MiniportSetInformation Changes (sets) information about the miniport driver or its network adapter.
MiniportTransferData Copies the contents of a packet that is received by the network adapter into a given packet buffer.
MiniportWanSend Transmits a packet though the network adapter onto the network. WAN miniport drivers use this function instead of the MiniportSend function.

Windows CE does not support Windows NT NDIS IRQ lines.

NDIS Protocol Driver Lower-Edge Functions

NDIS protocol drivers and layered miniport drivers also export a set of lower-edge functions that share "Protocol" as a common prefix. All of the NDIS driver functions that have this prefix have been given metanames that describe their respective basic functionalities in the references that follow.

NDIS-defined driver functions can have any name that the driver writer chooses. For easy debugging, most system-supplied protocols substitute a driver-specific prefix for the "Protocol" prefix that is used in this documentation.

The following table lists the NDIS driver lower-edge functions that are supported in Windows CE.

Table 3. NDIS driver lower-edge functions supported in Windows CE 3.0

Function Description
ProtocolBindAdapter Is a required driver function to support Plug and Play.
ProtocolCloseAdapterComplete Completes the processing for an unbinding operation for which the NdisCloseAdapter function returned NDIS_STATUS_PENDING.
ProtocolOpenAdapterComplete Completes the processing of a binding operation for which the NdisOpenAdapter function returned NDIS_STATUS_PENDING.
ProtocolReceive Is a required driver function in NDIS protocols that bind themselves to connectionless network adapter drivers; this function determines whether a received network packet is of interest to the protocol's client(s) and, if so, copies the indicated data and, possibly, calls the NdisTransferData function to retrieve the rest of the indicated network packet.
ProtocolReceiveComplete Completes post-processing of one or more of the preceding receive indications from a network adapter driver.
ProtocolReceivePacket Processes receive indications that are made by underlying connectionless network adapter driver(s) that call the NdisMIndicateReceivePacket function either with packet arrays, because the underlying driver supports multipacket receive indications, or with individual packets that have out-of-band information associated with them. A call to the ProtocolReceivePacket function also can occur as a result of loop back.
ProtocolRequestComplete Completes the processing of a protocol-initiated query or set for which the NdisRequest function returned NDIS_STATUS_PENDING.
ProtocolResetComplete Completes the processing of a protocol-initiated reset operation for which the NdisReset function returned NDIS_STATUS_PENDING.
ProtocolSendComplete Completes the processing of a protocol-initiated send operation that previously was passed to the NdisSend function, which returned NDIS_STATUS_PENDING.
ProtocolStatus Handles status-change notifications that are raised by an underlying connectionless network adapter driver or by NDIS.
ProtocolStatusComplete Completes a status-change operation that was initiated when the underlying driver called the NdisMIndicateStatus or the NdisMCoIndicateStatus function.
ProtocolTransferDataComplete Is a required driver function if the protocol might bind itself to an underlying connectionless network adapter driver that does not indicate full-packet receives by using the NdisMIndicateReceivePacket function. The ProtocolTransferDataComplete function completes the processing of a protocol-initiated transfer-data request for which the NdisTransferData function returned NDIS_STATUS_PENDING.
ProtocolUnbindAdapter Is a required driver function to support Plug and Play.

Miniport-Driver Registration

An NDIS miniport driver must register its MiniportXxx interface functions within its DriverEntry function. A layered miniport driver must register its ProtocolXxx functions also. To register its MiniportXxx functions, the driver must make one of two possible NDIS registration calls: either NdisMRegisterMiniport (for non-layered miniport drivers) or NdisIMRegisterLayeredMiniport (for layered miniport drivers). Both of these calls export the MiniportXxx functions of the driver. The function that is called determines whether the intermediate driver or the NDIS controls when the intermediate driver initializes as a miniport driver and, as a result, when the intermediate driver's virtual network adapter(s) is (are) made available for requests from higher-level drivers.

After the driver calls the NdisMRegisterMiniport function, NDIS calls the MiniportInitialize function of the driver to request initialization of its virtual network adapter(s).

Protocol Drivers

Windows CE 3.0 provides protocol drivers for TCP/IP, PPP, and IrDA. A protocol driver exports a set of ProtocolXxx functions at its lower edge, then communicates with NDIS to send and receive network packets, and to bind to an underlying miniport network-adapter driver or intermediate NDIS driver that exports a MiniportXxx interface at its upper edge.

Protocol drivers that communicate with underlying NDIS drivers call NDIS library functions to send and receive packets. To send a packet to an underlying NDIS driver, a protocol driver must call the NdisSend function. Unlike Windows NT 4.0, Windows CE 3.0 does not support the NdisSendPackets function, which allows for multiple packets to be sent to underlying drivers. To forward a request to the underlying driver that it query the capabilities or status of its network adapter, or that it set the state of its network adapter, a protocol driver must call the NdisRequest function.

Windows CE NDIS protocol drivers are exposed to applications through the Windows Sockets (Winsock) API. The interface between a protocol driver and Winsock is private. Figure 5 shows the NDIS protocol-driver architecture that is supported in Windows CE.

Figure 5. NDIS protocol-driver architecture supported in Windows CE

In the Windows CE protocol-driver architecture, a protocol driver communicates with the overlying Winsock APIs through a private interface. The NDIS protocol driver uses the NDIS interface to communicate with the underlying miniport driver and bind to the network adapter.

Protocol-Driver Initialization

NDIS protocol drivers are loaded through the registry. You must set the registry values for the following registry key: HKEY_LOCAL_MACHINE\Drivers\BuiltIn\MyDriver. This key commonly is named after the customized driver, and contains the subkeys that appear in Table 4.

Table 4. Registry subkeys for NDIS protocol-driver initialization

Subkey Contents
DLL "Mydriver.dll"
Order dword:3
Keep dword:1
Entry MyDriverInitialize
Note   Make sure to set the Order subkey to a value that causes the protocol driver to load after NDIS. That is, the Order value should be greater than that of the Order value for NDIS.

To register a protocol driver with NDIS, the driver should call the NdisRegisterProtocol function from within the MyDriverInitialize function.

To register a protocol driver as a stream interface driver, you must call the RegisterDevice function. For a list of the required entry points for stream interface driver DLLs, see the Windows CE DDK.

Dynamic Adapter Binding

Windows CE 3.0 features an inherent dynamic-adapter-handling system that provides Plug and Play compatibility for built-in—and removable—network adapters. Windows CE 3.0 supports a set of new functions that allow protocol drivers greater control over the creation of adapter instances and over adapter binding and unbinding.

When a protocol driver registers with NDIS, the currently registered adapters are offered to the protocol via the BindAdapterHandler function, just as if the adapters were newly inserted PC Cards. Protocol drivers no longer require registry keys that specify the built-in adapter instances to which they must bind. A Plug and Play-ready protocol driver can support dynamic binding to underlying network adapters by providing the ProtocolBindAdapter and ProtocolUnbindAdapter functions. NDIS calls the ProtocolBindAdapter function of a protocol driver to notify it that an adapter is available. The protocol can choose to ignore this notification, or it can try to bind to the adapter by calling the NdisOpenAdapter function.

Previously, the built-in and removable network adapters featured different binding mechanisms. For built-in adapters, the protocol was responsible for binding to a network adapter by calling the NdisOpenAdapter function according to registry settings. TCP/IP and IrDA each had its own set of registry settings that defined the names of the adapters to which it was to bind during initialization. Driver developers could modify the binding process by manipulating the registry settings for protocol drivers.

In Windows CE version 2.10 or earlier, NDIS informed the protocol driver of the presence of a new network adapter by calling the BindAdapterHandler function only if the network adapter was a removable PC Card. With Windows CE 3.0, this binding mechanism applies to built-in, as well as removable, adapters. That is, when a protocol driver registers with NDIS, it is informed about all current adapters via its BindAdapterHandler function.

Although driver developers no longer can control the binding mechanism by manipulating the protocol registry settings (except for IrDA, which statically binds to a single adapter and, thus, does not use the BindAdapterHandler function), Windows CE 3.0 features an alternate mechanism that enables driver developers to specify which adapters get bound to which protocols. You can define the protocols that an adapter is to bind to by specifying the required protocol in the HKLM\Comm\<adapter Name>\Parms\ProtocolsToBindTo registry entry of the adapter. This entry corresponds to a MULTI_SZ value that lists the names of all of the protocols that should be informed about the presence of the adapter. If the first entry is "NOT," the remaining entries will list the protocols that should not be informed about the adapter. If this registry entry is not set for an adapter, all of the protocol drivers will be informed about the adapter instance, and might attempt to bind to it.

If a Windows CE-based device has a PC Card inserted into its PCMCIA slot, the system will not suspend automatically on idle activity. To allow a Windows CE-based device to suspend on no user activity, you must make the following registry entry under HKEY_LOCAL_MACHINE:

HKEY_LOCAL_MACHINE\Comm\Cxport\NoIdleTimerReset

The TCP/IP protocol stack checks for this registry setting during initialization. If the NoIdleTimerReset subkey has been entered in the registry and set to nonzero, the system will not call the SystemIdleTimerReset function. Note that when the system goes into suspend, you will have to reinitialize all of your networking activity; for example, you will have to obtain a new IP address. Also, because TCP/IP checks for the registry setting during initialization time, you must restart the device if you want to change from one registry setting to another. Failure to set the above registry key will result in the system not suspending.

NDIS Adapter-Binding Management

Windows CE 3.0 supports the NdisMRebindProtocolsToAdapter function, which allows a network adapter to request that it be unbound from all of the protocol drivers to which it currently is bound, and then re-bound to protocols, as if it were newly registered with NDIS. For example, a wireless adapter that switches to a base station on a subnet that is different from its current IP address can invoke this function to cause the TCP/IP protocol stack to rerun DHCP to obtain a new IP address for the device. This functionality eliminates the need for the user to "pop out" a network adapter and reinsert it in order to obtain a new address.

Plug and Play

The dynamic adapter-binding feature that is supported in Windows CE 3.0 complies with the requirements for Plug and Play compatibility. Plug and Play enables a computer system to recognize hardware configuration changes automatically, and configure attached devices with little or no user intervention. Plug and Play allows the user to attach a new network adapter and start working without having to configure the device manually. With Windows CE 3.0, you can unbind an adapter from a protocol driver and subsequently rebind it without having to remove the adapter.

Windows CE support for Plug and Play differs from the Windows 2000 support for Plug and Play.

Windows CE support for Plug and Play has the following capabilities and features:

  • Automatic and dynamic recognition of installed hardware, which includes initial system installation, in addition to response to run-time hardware events, such as insertion or removal of cards.
  • Streamlined hardware configuration in response to automatic and dynamic recognition of hardware, which includes dynamic hardware activation, resource arbitration, device-driver loading, drive mounting, and so forth.
  • Support for particular buses and other hardware standards that facilitate automatic and dynamic recognition of hardware and streamlined hardware configuration, which includes Plug and Play PCMCIA, PC Card/CardBus, USB, and 1394. Support also includes promulgation of standards, and advice on how hardware should behave.
  • An orderly Plug and Play framework in which driver writers can operate, which includes infrastructure such as APIs, kernel-mode notifications, executive interfaces, and so forth.

Note that Plug and Play operation does not require Plug and Play hardware. To the degree that it is possible, the first two items that are listed above apply to legacy hardware, as well as to Plug and Play hardware. In some cases, orderly enumeration of legacy devices is not possible, because the detection methods are destructive or inordinately time-consuming.

The primary impact that Plug and Play support has on protocol stacks is that network interfaces can connect and disconnect at any time. The Windows CE TCP/IP stack and related components have been adapted to support Plug and Play.

Windows CE Plug and Play is transparent to the miniport drivers. When the user attaches a network adapter, a miniport driver is automatically installed, loaded, and bound. When the network adapter is removed, the miniport driver is unbound, shut down, and unloaded. To implement Plug and Play on a Windows CE-based system, you must set the DriverEntry function to "init." All of the other miniport-driver initialization code should be set to "page," as it might be used after system initialization. The Windows NT DDK provides the standard registry keywords that can be used for Plug and Play.

Miniport drivers for network adapters require a HKEY_LOCAL_MACHINE\Drivers\PCMCIA\Plug and Play ID\ registry key. This key typically is named after the Plug and Play ID of the network adapter, but setting this key is not a requirement. Table 5 shows the subkeys that are contained in the key:

Table 5. Subkeys contained in network adapter registry key

Subkey Contents
DLL The literal value Ndis.dll.
Prefix The literal value NDS.
Miniport The name of the miniport driver for the network adapter, which corresponds with the name of the registry key that is within HKEY_LOCAL_MACHINE\Comm\ for the miniport driver.

For example, a network adapter can have the following additional keys:

[HKEY_LOCAL_MACHINE\Drivers\PCMCIA\Plug and Play ID]

DLL="NDIS.dll"

Prefix= "NDS"

Miniport="NE2000"

The NDIS interface sets the values for the BusNumber and BusType keys for network adapters. The BusNumber key contains the socket and function pair for the adapter. The BusType key contains the value for the network adapter bus. If the information structure of the network adapter contains a network address value, Ndis.dll will create a \HKEY_LOCAL_MACHINE\Comm\<miniport Name>\<miniport Instance>\Network Address registry key to store the network address.

Miniport drivers for a network adapter typically implement an Install_Driver function for installing the appropriate registry settings that will allow dynamic recognition of the network adapter. For example, when a network adapter is inserted into a Windows CE system, it tries to recognize the appropriate driver for the adapter by matching its Plug and Play ID with an appropriate key in the registry. If the system fails to find a Plug and Play match, it will prompt the user to enter a driver name. If this user-supplied driver DLL exports Install_Driver, the system calls this function. The primary purpose of this function is to populate the Windows CE registry with appropriate entries for this miniport driver, as described above, so that future insertions of the network adapter will lead to dynamic loading of the correct NDIS miniport driver.

Installing Network Adapter Drivers

The installation procedures for network adapter drivers depend on whether you want to install an adapter driver for a removable network adapter, such as a PC Card, or for a built-in network adapter.

To install a removable network adapter driver, you must complete the following steps:

  1. Connect to a Windows CE platform, or detect that a connection already exists.
  2. Copy the installable device driver DLL to the Windows directory.
  3. PC Card Services will call the Install_Driver entry point in the miniport driver. The Install_Driver function will create the appropriate registry keys and values for each driver.

To install a built-in network adapter driver, Setup must complete the following steps:

  1. Connect to a Windows CE platform, or detect that a connection already exists.
  2. Copy the installable device driver DLL to the Windows directory.
  3. Wait for the Setup program to create the required registry keys and values for the driver.
  4. Restart the device.

IrDA Support

The NDIS implementation in Windows CE 3.0 features IrDA support. Unlike in Windows NT, which supports binding to multiple adapter instances, the Windows CE IrDA protocol driver can bind only to a single miniport driver at a time. In the Windows communications architecture, infrared sockets are exposed through extensions to the Winsock interface.

Windows CE features the following two Windows CE-specific object identifiers that provide for the sharing of hardware resources:

  • OID_IRDA_REACQUIRE_HW_RESOURCES
  • OID_IRDA_RELEASE_HW_RESOURCES

When an infrared socket has been opened and no others are currently open, the set information handler of the miniport driver is passed a request with the OID_IRDA_REACQUIRE_HW_RESOURCES message to the miniport driver. This message tells the miniport driver to take ownership of any resources that are needed for IR communication (for example, IrSIR opens a COM port). After all of the open infrared sockets have been closed, the miniport driver receives the OID_IRDA_RELEASE_HW_RESOURCES message through its query information handler. After it receives this message, the miniport driver releases all of the previously acquired hardware resources.

NDIS Token Ring Support

The Windows CE implementation of NDIS now supports network adapters that are of a Token Ring medium type (802.5). The Token Ring support in Windows CE is a subset of the NDIS Token Ring implementation in Windows NT.

When a network adapter of Token Ring medium type receives a data packet over the network, its miniport driver indicates the packet by calling the NdisMTrIndicateReceive function. This function notifies NDIS that a particular link has received a packet, and that the packet is ready to be forwarded to the appropriate bound protocol driver.

After the complete packet has been transferred, the miniport driver must call the NdisMTrIndicateReceiveComplete function to notify NDIS that the transfer operation has been completed, even if a particular packet is not accepted by any bound protocol. NdisMTrIndicateReceiveComplete notifies any bound protocol that already has consumed the initial indication that it can begin post-processing the received data.

Table 6 shows a list of supported APIs that apply directly to the Token Ring medium type.

Table 6. Supported APIs that apply directly to the Token Ring medium type

Function Description
NdisMTrIndicateReceive Notifies NDIS that a Token Ring packet (or some initial look-ahead portion of the packet) has arrived, so that NDIS can forward the packet to bound protocols.
NdisMTrIndicateReceiveComplete Notifies NDIS that a Token Ring receive packet, which was identified in a preceding call to the NdisMTrIndicateReceive function, has been transferred fully by the NIC, so that NDIS can notify the appropriate bound protocol drivers.

Token Ring Object Identifiers

Table 7 summarizes the object identifiers that are used to get or set Token Ring operational characteristics for NDIS drivers and network adapters. All Token Ring object identifiers start with OID_802_5Xxx, which is the universal identifier for Token Ring networks.

Table 7. Object identifiers

Length Q S Name
6 M   OID_802_5_PERMANENT_ADDRESS
Permanent station address
6 M   OID_802_5_CURRENT_ADDRESS
Current station address
4 M M OID_802_5_CURRENT_FUNCTIONAL
Current functional address
4 M M OID_802_5_CURRENT_GROUP
Current group address
4 M   OID_802_5_LAST_OPEN_STATUS
Last open status
4 M   OID_802_5_CURRENT_RING_STATUS
Current ring status
4 M   OID_802_5_CURRENT_RING_STATE
Current ring state

NDISWAN Support

Windows CE 3.0 now also supports NDISWAN. The NDISWAN implementation in Windows CE 3.0 features the AsyncMAC miniport driver. The AsyncMAC miniport driver is responsible for sending and receiving packets, performing asynchronous framing, and managing Telephony API (TAPI) devices. NDISWAN for Windows CE 3.0 also features a PPP layer, which is implemented as an NDIS protocol driver. Driver writers also can develop their own customized NDISWAN miniport driver.

The NDISWAN architecture that is implemented in Windows CE differs from the NDISWAN architecture that is implemented in Windows NT. Windows NT uses an intermediate NDIS driver, NDISWAN, which manages WAN miniport drivers and maps WAN packets into Ethernet packets, as it binds to the TCP/IP protocol stack as an 802.3 adapter. In Windows CE, the PPP protocol driver does not bind to TCP/IP as an 802.3 miniport driver. Instead, it interfaces directly to IP. While asynchronous framing occurs in the AsyncMAC miniport driver in Windows CE, Windows NT uses the NDISWAN intermediate driver to perform asynchronous framing. Unlike Windows NT, Windows CE 3.0 does not support multi-link PPP.

Figure 6, below, shows the NDISWAN architecture that is implemented in Windows CE.

Figure 6: NDISWAN architecture in Windows CE.

In the NDISWAN architecture in Windows CE, PPP is implemented as an NDIS protocol driver. PPP communicates with the underlying AsyncMAC miniport driver through the NDIS layer, which exposes an NDIS protocol interface on the upper edge and an NDIS miniport-driver interface on the lower edge. When PPP receives a packet from TCP/IP, it does PPP framing, compression, and encryption, and then passes the packet on to the AsyncMAC miniport driver. After having received a packet from PPP, the AsyncMAC miniport driver performs the asynchronous framing, and then forwards the packet to the TAPI device by calling Win32 serial APIs. When receiving a packet through the network, the AsyncMAC miniport driver strips the flags off the packet, performs the Cyclic Redundancy Check (CRC), and passes the packet up to PPP through the NDIS layer. Before the WAN miniport driver can send or receive packets on the network, an application must set up a connection that originates on the sending node, or accept a connection that originates on a remote node, by making or accepting a call. Requests from TAPI and status indications to TAPI all go through the WAN miniport driver.

After a connection with a remote node has been established, packets can be exchanged over the network. The WAN miniport driver specifies the default number of outstanding packets that it can have for every data channel in the MaxTransmit value, and submits the MaxTransmit value to PPP as a response to an OID_WAN_GET_INFO request. The OID_WAN_GET_INFO structure contains the following information:

  • The type of framing that is required for a packet.
  • The amount of padding that must be placed at the head and tail of a frame.
  • The maximum size frame that the network adapter driver can send and receive.
  • The maximum number of frames that can be queued for transmission.
  • The number of links that are supported by the network adapter.

The WAN miniport driver might have to modify or add to the header, as well as to the end of a packet. The NDISWAN implementation in Windows CE 3.0 provides appropriate padding at the beginning and end of each packet. The WAN miniport driver can alter the data in the packet in any way that is appropriate, in order to send it on the WAN medium.

AsyncMAC Registry Settings

The NDISWAN implementation in Windows CE 3.0 includes a HKEY_LOCAL_MACHINE\Comm\AsyncMac1\Parms registry key. This key contains a set of subkeys that allow you to configure values that are specific to the WAN miniport driver, such as the maximum packet size that a miniport driver will receive from a link.

The following table describes the registry settings for the HKEY_LOCAL_MACHINE\Comm\AsyncMac1\Parms key.

Table 8. Registry settings

Registry key Type Default Description
MaxFrameSize DWORD 1500 Specifies the maximum frame size (in bytes) that the driver can send and receive, not including MAC layer framing.
MaxRecvFrameSize DWORD 1500 Specifies the largest packet that the driver will accept from the network, not including MAC layer framing.
MaxSendFrameSize DWORD 1500 Specifies the largest packet size that the driver will send, not including MAC layer framing.
ReceiveBufferSize DWORD 2000 Specifies the total size, in bytes, of the receive buffer for a driver that supports internal buffering.
Note   Setting MaxRecvFrameSize or MaxSendFrameSize will override the value of MaxFrameSize for that direction.

NDIS Library Functions Used by WAN Miniport Drivers

NDIS miniport drivers for WAN adapters call most of the functions that are called by other miniport drivers. However, WAN miniport drivers cannot call the following functions:

  • NDISMIndicateReceive
  • NDISMIndicateReceiveComplete
  • NDISMSendComplete

NDIS miniport drivers for WAN adapters must instead call the functions shown in Table 9.

Table 9. Functions called for NDIS miniport drivers for WAN adapters

Function Description
NdisMWanIndicateReceive Notifies NDIS that a particular link has received a packet, and that the packet has been identified by the given link-context handle, and on a particular network adapter, by the adapter handle. Also, notifies NDIS that the full packet is available to be forwarded to the appropriate bound protocol driver(s).
NdisMWanIndicateReceiveComplete Notifies NDIS that one or more receives on a particular link, identified by the given link-context handle, and on a particular network adapter, identified by the adapter handle, are complete (that is, the preceding call to the NdisMWanIndicateReceive function has returned), so that NDIS can notify the appropriate bound protocol driver(s).
NdisMWanSendComplete Returns the packet and final status of a completed send request for which the driver previously returned NDIS_STATUS_PENDING, so that NDIS can return the completed packet to the appropriate bound protocol driver.

NDISWAN Object Identifiers

Table 10 summarizes the object identifiers that are used to get or set operational characteristics for NDIS drivers and WAN adapters.

Table 10. Object identifiers

Length Q S Name
6 M   OID_WAN_PERMANENT_ADDRESS
Permanent station address
6 M   OID_WAN_CURRENT_ADDRESS
Current station
1 or 6   M OID_WAN_PROTOCOL_TYPE
Protocol type
4 M   OID_WAN_MEDIUM_SUBTYPE
Medium subtype
4   M OID_WAN_HEADER_FORMAT
Format the packet header
4 M   OID_WAN_GET_INFO
Get information
4 M   OID_WAN_GET_LINK_INFO
Get link information
4   M OID_WAN_SET_LINK_INFO
Set link information
4 M   OID_WAN_LINE_COUNT
Line count
50 0   OID_WAN_GET_COMP_INFO
Get compression information
50   O OID_WAN_SET_COMP_INFO
Set compression information
60 O   OID_WAN_GET_STATS_INFO
Get statistics information
      OID_TAPI_TRANSLATE_ADDRESS
Translate the name or number entered by the user into the final format required by the miniport driver to make the connection

DMA

Unlike the Windows NT implementation, the Windows CE implementation of NDIS does not support Direct Memory Access (DMA) operations inherently. Some platforms might provide DMA libraries for use by driver developers, or the miniport driver might need to implement DMA entirely on its own. In Windows NT, there are two methods to implement DMA, depending on whether the LAN is a subordinate DMA network adapter or a busmaster DMA network adapter.

Non-Busmaster DMA Network Adapters

For subordinate DMA transfers, a Windows NT miniport driver calls a set of functions that consist of NdisMRegisterDmaChannel, NdisMDeregisterDmaChannel, NdisMSetupDmaTransfer, NdisMCompleteDmaTransfer, and NdisMReadDmaCounter. The Windows CE implementation of NDIS does not support these functions. Instead, the required functionality can be implemented directly in the miniport-driver code.

To implement DMA transfers in a miniport driver, you must reserve a physical memory block from the memory map of a Windows CE-based device. Then, you must map the memory block of the device to virtual address pointers by using the VirtualAlloc and VirtualCopy functions. Mapping the memory block of the device to virtual address pointers provides the miniport driver with a shared memory block to send and receive packet buffers.

To see an example of how to implement DMA operations in a miniport driver for Windows CE, consult the sample code for the National Semiconductor Fast IR Miniport Driver that is shipped with Windows CE 3.0.

The following code samples show how to implement DMA functionality in a miniport driver in Windows CE:

/********************************/

Copyright (c) 2000 Microsoft Corporation
Module Name:    
  Ndisdma.h

Abstract:       
  This will implement the NDIS-required DMA
  functions that differ from the Windows CE
  and Windows NT implementations.

**********************************/

#ifndef _NDISDMA_H_
#define _NDISDMA_H_

#ifdef UNDER_CE

typedef struct _NDIS_DMA_DESCRIPTION 
{
  BOOLEAN DemandMode;
  BOOLEAN AutoInitialize;
  BOOLEAN DmaChannelSpecified;
  DMA_WIDTH DmaWidth;
  DMA_SPEED DmaSpeed;
  ULONG DmaPort;
  ULONG DmaChannel;
} NDIS_DMA_DESCRIPTION, *PNDIS_DMA_DESCRIPTION;

// DMA Operations.  
NDIS_STATUS NdisMRegisterDmaChannel (
   OUT PNDIS_HANDLE            MiniportDmaHandle,
   IN  NDIS_HANDLE             MiniportAdapterHandle,
   IN  UINT                    DmaChannel,
   IN  BOOLEAN                 Dma32BitAddresses,
   IN  PNDIS_DMA_DESCRIPTION   DmaDescription,
   IN  ULONG                   MaximumLength);

VOID NdisMDeregisterDmaChannel
(IN NDIS_HANDLE MiniportDmaHandle);
VOID NdisMSetupDmaTransfer (
   OUT PNDIS_STATUS            Status,
   IN  PNDIS_HANDLE            MiniportDmaHandle,
   IN  PNDIS_BUFFER            Buffer,
   IN  ULONG                   Offset,
   IN  ULONG                   Length,
   IN  BOOLEAN                 WriteToDevice);

VOID NdisMCompleteDmaTransfer (
   OUT PNDIS_STATUS            Status,
   IN  PNDIS_HANDLE            MiniportDmaHandle,
   IN  PNDIS_BUFFER            Buffer,
   IN  ULONG                   Offset,
   IN  ULONG                   Length,
   IN  BOOLEAN                 WriteToDevice);

ULONG NdisMReadDmaCounter
(IN NDIS_HANDLE MiniportDmaHandle);

#endif // UNDER_CE

#endif // _NDISDMA_H_
/**********************************/

THIS CODE AND INFORMATION IS PROVIDED "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
FITNESS FOR A PARTICULAR PURPOSE.
Copyright (c) 2000  Microsoft Corporation

**********************************/

#include <windows.h>
#include <ndis.h>
#include "Nsc.h"
#include "Ndisdma.h"

#define FIR_BUFFER_BASE_PA
0x00001000
#define MINIPORT_DMA_HANDLE
(NDIS_HANDLE) 0x45454545

// We will map our virtual address to
// our DMA physical buffer.
// This is used with any buffer that
// was mapped into our physical
// buffer.
PVOID VirtualToPhysAddress
(PVOID pvVirtual)
{
  // Make sure that the given virtual address is
  // within the range of our buffer.
  ASSERT (((PUCHAR)pvVirtual
>= (PUCHAR)g_pvDmaVirtualBase) && 
         ((PUCHAR)pvVirtual
<((puchar)g_pvdmavirtualbase
         + NSCIRDA_DMA_BUFFER_LEN)));
   // Physical address is the base physical address
   // plus the offset in the virtual address space.
   return (PVOID) ((DWORD)NSCIRDA_DMA_BUFFER_BASE_PA +
   (DWORD)pvVirtual (DWORD)g_pvDmaVirtualBase); }
   const int DmaAddrReg[4]="{" 0x00, 0x02, 0x04, 0x06};
   const int DmaCountReg[4]="{" 0x01, 0x03, 0x05, 0x07};
   const int DmaPageReg[4]="{" 0x87, 0x83, 0x81, 0x82};
   // Define the DMA-mode register structure.
   typedef struct _DMA_MODE { UCHAR Channel : 2;
   UCHAR TransferType : 2; UCHAR AutoInitialize : 1;
   UCHAR AddressDecrement : 1; UCHAR RequestMode : 2;
   }DMA_MODE, *PDMA_MODE;
   // Define TransferType values.
   #define VERIFY_TRANSFER 0x00
   #define READ_TRANSFER 0x01
   // Read from the device. #define WRITE_TRANSFER 0x02
   // Write to the device.
   // Define RequestMode values.
   #define DEMAND_REQUEST_MODE 0x00
   #define SINGLE_REQUEST_MODE 0x01
   #define BLOCK_REQUEST_MODE 0x02
   #define CASCADE_REQUEST_MODE 0x03
   #define DMA_SETMASK 4
   #define DMA_CLEARMASK 0
   #define DMA_READ 4 #define DMA_WRITE 8
   #define DMA_SINGLE_TRANSFER 0x40
   #define DMA_AUTO_INIT 0x10
   // Auto initialization mode
   // Define DMA 1 address and
   // count structure
   // (for 8237 compatibility)
   typedef struct _DMA1_ADDRESS_COUNT {
   UCHAR DmaBaseAddress; UCHAR DmaBaseCount; }
   DMA1_ADDRESS_COUNT, *PDMA1_ADDRESS_COUNT;
   // Define DMA 1 control register structure
   // (for 8237 compatibility)
   typedef struct _DMA1_CONTROL {
   DMA1_ADDRESS_COUNT DmaAddressCount[4];
   UCHAR DmaStatus; UCHAR DmaRequest;
   UCHAR SingleMask; UCHAR Mode;
   UCHAR ClearBytePointer; UCHAR MasterClear;
   UCHAR ClearMask; UCHAR AllMask; }
   DMA1_CONTROL, *PDMA1_CONTROL;
   NDIS_DMA_DESCRIPTION g_DMA_Description;
   BOOL g_fRegistered; UINT g_nDmaChannel;
   /**********************************/
   NDIS_STATUS NdisMRegisterDmaChannel (
   PNDIS_HANDLE phMiniportDmaHandle,
   NDIS_HANDLE hMiniportAdapterHandle,
   UINT nDmaChannel, BOOLEAN fDma32BitAddresses,
   PNDIS_DMA_DESCRIPTION pDmaDescription,
   ULONG ulMaximumLength) {
   NDIS_STATUS Status="NDIS_STATUS_SUCCESS;"
   DEBUGMSG (ZONE_INIT | ZONE_DMA,
   (TEXT(“+NdisMRegisterDmaChannel
   (%#x, %#x, %d, %d, %#x, %d\r\n”),
   phMiniportDmaHandle, hMiniportAdapterHandle,
   nDmaChannel, fDma32BitAddresses, pDmaDescription,
ulMaximumLength));
// Check to ensure that we are not registered already.
Allow only // one at a time.
if (g_fRegistered) {
Status="NDIS_STATUS_RESOURCE_CONFLICT;" goto done; }
// One DMA Channel per driver. Return Constant.
*phMiniportDmaHandle="MINIPORT_DMA_HANDLE;"
// Store the description for later use.
memcpy (&g_DMA_Description, pDmaDescription,
sizeof (NDIS_DMA_DESCRIPTION));
g_nDmaChannel="nDmaChannel;"
if (g_nDmaChannel> 3)

  {
    DBGERR ((TEXT("The channel is > 3.
    Not available in this sample driver!")));
    Status = NDIS_STATUS_RESOURCES;
    goto done;
  }

  // Indicate that we are registered.
  g_fRegistered = TRUE;

done:
  DEBUGMSG (ZONE_INIT | ZONE_DMA,
    (TEXT("-NdisMRegisterDmaChannel
    [%s, hDma = %#x]\r\n"), 
    DBG_NDIS_RESULT_STR (Status),
    *phMiniportDmaHandle));

  return (Status);
}

/**********************************/
VOID NdisMDeregisterDmaChannel
(PNDIS_HANDLE phMiniportDmaHandle)
{
  DEBUGMSG (ZONE_INIT | ZONE_DMA,
  (TEXT("+NdisMDeregisterDmaChannel
  (%#x)\r\n"), phMiniportDmaHandle));

  if (*phMiniportDmaHandle ==
  MINIPORT_DMA_HANDLE)
    g_fRegistered = FALSE;

  DEBUGMSG (ZONE_INIT | ZONE_DMA, 
  (TEXT("-NdisMDeregisterDmaChannel\r\n")));
}

/**********************************/
VOID NdisMSetupDmaTransfer (
        PNDIS_STATUS  pStatus,
        PNDIS_HANDLE  phMiniportDmaHandle,
        PNDIS_BUFFER  pBuffer,
        ULONG         Offset,
        ULONG         Length,
        BOOLEAN       WriteToDevice)
{
  int    DMAAddr, DMACount, DMAPage, Offset2, Page;
  int    DMAChanOffset;
  UCHAR  bReadWrite;
  UCHAR  bMode;
  PDMA1_CONTROL dmaControl = 0;
  DMA_MODE dmaMode;
  DWORD  dwPhysAddress;

  DBGDMA((TEXT("+NdisMSetupDmaTransfer %s:
  buf = 0x%x, offset = %d, len = %d"),
    (WriteToDevice == TRUE) ? TEXT("TX")
    : TEXT(“RX”),
    pBuffer, Offset, Length));

  *pStatus = NDIS_STATUS_SUCCESS;

  if (phMiniportDmaHandle != MINIPORT_DMA_HANDLE)
  {
    *pStatus = NDIS_STATUS_RESOURCES;
    goto done;
  }

  DMAAddr  = DmaAddrReg[g_nDmaChannel];
  DMACount = DmaCountReg[g_nDmaChannel];
  DMAPage  = DmaPageReg[g_nDmaChannel];

  // We";re making the assumption of 8-bit.
  DMAChanOffset = g_nDmaChannel;

  if (Offset + Length >
  pBuffer->BufferLength)
  {
    DBGERR ((TEXT(";The offset + length
    is greater than the buffer length!")));
    *pStatus = NDIS_STATUS_RESOURCES;
    goto done;
  }
    
  // Get the physical address from the virtual address. 
  dwPhysAddress = 
    (DWORD)VirtualToPhysAddress
    (pBuffer->VirtualAddress) + Offset;

  DBGDMA((TEXT("Address = 0x%X";), 
    (PBYTE)pBuffer->VirtualAddress + Offset));
  DBGDMA((TEXT("Length  = 0x%X"),
  pBuffer->BufferLength));
  DBGDMA((TEXT("Channel = 0x%X"),
  g_nDmaChannel));
  DBGDMA((TEXT("DMA Buffer 0x%x,
  len %d"), 
    dwPhysAddress + Offset, Length));

  // PROGRAM THE DMA chip
  Page    = (int) ((dwPhysAddress >> 16)
  & 0xFF);
  Offset2 = (int) (dwPhysAddress & 0xFFFF);

  // Disable DMA while programming.
  WRITE_PORT_UCHAR ((PUCHAR) 0x0A,
  (UCHAR) (DMAChanOffset | 4));

  // Clear byte pointer.
  WRITE_PORT_UCHAR ((PUCHAR) 0x0C, (UCHAR) 0);

  dmaMode.Channel = g_nDmaChannel;
  dmaMode.TransferType = 
    (WriteToDevice ? 
    WRITE_TRANSFER : READ_TRANSFER);
  dmaMode.RequestMode = DEMAND_REQUEST_MODE;
  dmaMode.AutoInitialize = FALSE;
  dmaMode.AddressDecrement = FALSE;

  // 8-bit demand mode non-autoinit
  bReadWrite = (WriteToDevice ? 0x8 : 0x4);
  bMode = bReadWrite | g_nDmaChannel;
  WRITE_PORT_UCHAR ((PUCHAR) 0x0B, bMode);

  // LO byte address of buffer.
  WRITE_PORT_UCHAR
  ((PUCHAR)DMAAddr, (UCHAR) (Offset2 & 0xFF));
  // HI byte address of buffer.
  WRITE_PORT_UCHAR
  ((PUCHAR)DMAAddr, (UCHAR) (Offset2 >> 8));
  // Physical page number.
  WRITE_PORT_UCHAR
  ((PUCHAR)DMAPage, (UCHAR) Page);
  // LO byte of count.
  WRITE_PORT_UCHAR
  ((PUCHAR)DMACount, (UCHAR) ((Length - 1) & 0xFF));
  // HI byte of count.
  WRITE_PORT_UCHAR
  ((PUCHAR)DMACount, (UCHAR) ((Length - 1) >> 8));

  DBGDMA((TEXT("ReadCount
  (before) = %d"), 
    NdisMReadDmaCounter (phMiniportDmaHandle)));

  // Done programming the DMA, enable it.
  WRITE_PORT_UCHAR ((PUCHAR) 0x0A,
  (UCHAR) DMAChanOffset);

done:
  DBGDMA((TEXT("-NdisMSetupDmaTransfer [%s]"), 
    DBG_NDIS_RESULT_STR (*pStatus)));
  return;
}

/**********************************/
VOID NdisMCompleteDmaTransfer (
        PNDIS_STATUS Status,
        PNDIS_HANDLE MiniportDmaHandle,
        PNDIS_BUFFER Buffer,
        ULONG Offset,
        ULONG Length,
        BOOLEAN WriteToDevice)
{
  DBGDMA((TEXT("+NdisMCompleteDmaTransfer %s:
  buf = 0x%x, offset = %d, len = %d"),
   (WriteToDevice == TRUE) ? TEXT("TX")
   : TEXT("RX"),
    Buffer, Offset, Length));

  // Disable the DMA.
  WRITE_PORT_UCHAR ((PUCHAR) 0x0A,
  (UCHAR) (g_nDmaChannel | 4));

  DBGDMA((TEXT("-NdisMCompleteDmaTransfer
  [NDIS_STATUS_SUCCESS]")));
    *Status = NDIS_STATUS_SUCCESS;
}

/********************************/
ULONG NdisMReadDmaCounter
(NDIS_HANDLE MiniportDmaHandle)
{
  UCHAR bLo, bHi;

  bLo = READ_PORT_UCHAR
  ((PUCHAR) DmaCountReg[g_nDmaChannel]);
  bHi = READ_PORT_UCHAR
  ((PUCHAR) DmaCountReg[g_nDmaChannel]);

  DBGDMA((TEXT("NdisMReadDmaCounter
  [StatusReg = 0x%x, Count = %d]"), 
    READ_PORT_UCHAR ((PUCHAR) 0x08), 
    bHi << 8 | bLo)); return (bHi << 8 | bLo); }

Busmaster-DMA Network Adapter

For busmaster-DMA network adapters, a Windows NT miniport driver calls a set of functions that consist of NdisQueryMapRegisters, NdisMAllocateMapRegisters, NdisMAllocateSharedMemory, NdisMFreeSharedMemory, NdisMStartBufferPhysicalMapping, and NdisMCompleteBufferPhysicalMapping to facilitate the DMA transfer. The Windows CE implementation of NDIS does not support these functions. However, driver developers can implement a functionality that supports DMA transfers directly in the miniport driver.

In Windows NT, a miniport driver generally transfers data that is received by a busmaster-DMA network adapter into device-accessible buffers that are within a shared memory block allocated by the miniport driver. The miniport driver calls the NdisMInidcateReceivePacket function to indicate the packet to the protocol. The miniport driver can reserve a shared memory block, too, as described in the preceding section, Non-Busmaster DMA Network Adapters.

To transfer packet data for a send request, a Windows NT miniport driver first maps the virtual range that contains the data to the NdisMStartBufferPhysicalMapping function, in order to obtain the mapped range of device-accessible addresses for use by its network adapter. Then, the miniport driver downloads the returned physical addresses to the network adapter. If the driver allocated cached memory, the miniport driver calls the NdisFlushBuffer and NdisMUpdateSharedMemory functions. After it has downloaded the physical addresses to the network adapter, the miniport driver programs the network adapter for the transfer operation.

The network adapter indicates that the transfer operation is complete, either by transmitting an interrupt, or by a change of state that is discovered when the network adapter driver polls the MiniportTimer function. After the network adapter has completed the transfer operation, the miniport driver calls the NdisMCompleteBufferPhysicalMapping function, usually from the MiniportHandleInterrupt function.

On Windows CE, a miniport driver can use the LockPages or UnlockPages function, in place of the NdisMStartBufferPhysicalMapping and NdisMCompleteBufferPhysicalMapping NDIS functions, for mapping virtual addresses to physical address ranges.

Show: