Microsoft Windows CE 3.0 Technical Articles  

NDIS Implementation in Microsoft Windows CE Platform Builder 3.0

Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

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 DriverEntryfunction in its module definition (.def) file. DriverEntryinitializes 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 sampleon 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 sendhandler in the miniport driver.
    • The I/O port address that is returned from the NdisMRegisterIoPortRangefunction 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 NdisSendPacketsfunction 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 #ifdefand #endifstatements.

          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 DriverEntryfunction. 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 DriverEntryfunction requires the following syntax:

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

            The following parameters are passed into the DriverEntryfunction:

            • 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 DriverEntryfunction must call the NdisMInitializeWrapperfunction, and then the NdisMRegisterMiniportfunction. DriverEntryfirst calls NdisMRegisterMiniportwith the parameters that are passed to DriverEntry, which returns a wrapper handle. DriverEntrythen 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 MiniportXxxfunctions at its upper edge and ProtocolXxxfunctions 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_LOOPBACKpacket flag by calling the NdisSetPacketFlagsfunction.

              A layered miniport driver calls the NdisOpenAdapterfunction to open and establish a binding to an underlying adapter driver or intermediate NDIS driver that exports a set of MiniportXxxfunctions at its upper edge. A layered miniport driver exports the MiniportSetInformationand MiniportQueryInformationfunctions to process Setand Queryrequests from a higher-level driver, and to pass them on to a lower-level driver.

              NdisMXxxfunctions 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 NdisIMSwitchToMiniportfunction before you call any MiniportXxxfunctions. Use the NdisIMRevertBackfunction 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 MiniportHaltfunction of an NDIS intermediate driver to tear down the virtual network adapter of the driver.
              NdisIMGetDeviceContext Allows the MiniportInitializefunction of an NDIS intermediate driver to access the device context area that is allocated by its ProtocolBindAdapterfunction.
              NdisIMInitializeDeviceInstance Calls the MiniportInitializefunction 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 MiniportInitializefunction 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 MiniportXxxentry points and name with the NDIS library when the driver initializes.

              Any NDIS intermediate or layered miniport driver that exports both MiniportXxxand ProtocolXxxfunctions usually sets up a characteristics structure and calls the NdisIMRegisterLayeredMiniportfunction from its DriverEntryfunction after DriverEntrycalls the NdisMInitializeWrapperfunction. This structure is copied in the NdisIMRegisterLayeredMiniportrequest 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 NdisMRegisterMiniportfunction, instead of the NdisIMRegisterLayeredMiniportfunction, if it is prepared for an immediate call to the MiniportInitializefunction.

              NDIS Driver Upper-Edge Functions

              NDIS intermediate drivers and layered miniport drivers export a subset of MiniportXxxfunctions and a DriverEntryfunction 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 MiniportInitializefunction can call a MiniportReconfigurefunction 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 NdisMIndicateReceivePacketfunction.
              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 MiniportSendfunction.

              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 NdisCloseAdapterfunction returned NDIS_STATUS_PENDING.
              ProtocolOpenAdapterComplete Completes the processing of a binding operation for which the NdisOpenAdapterfunction 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 NdisTransferDatafunction 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 NdisMIndicateReceivePacketfunction 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 ProtocolReceivePacketfunction also can occur as a result of loop back.
              ProtocolRequestComplete Completes the processing of a protocol-initiated query or set for which the NdisRequestfunction returned NDIS_STATUS_PENDING.
              ProtocolResetComplete Completes the processing of a protocol-initiated reset operation for which the NdisResetfunction returned NDIS_STATUS_PENDING.
              ProtocolSendComplete Completes the processing of a protocol-initiated sendoperation that previously was passed to the NdisSendfunction, 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 NdisMIndicateStatusor the NdisMCoIndicateStatusfunction.
              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 NdisMIndicateReceivePacketfunction. The ProtocolTransferDataCompletefunction completes the processing of a protocol-initiated transfer-data request for which the NdisTransferDatafunction 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 MiniportXxxinterface functions within its DriverEntryfunction. A layered miniport driver must register its ProtocolXxxfunctions also. To register its MiniportXxxfunctions, 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 NdisMRegisterMiniportfunction, NDIS calls the MiniportInitializefunction 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 ProtocolXxxfunctions 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 MiniportXxxinterface 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 NdisSendfunction. Unlike Windows NT 4.0, Windows CE 3.0 does not support the NdisSendPacketsfunction, 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 NdisRequestfunction.

              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 Ordersubkey to a value that causes the protocol driver to load after NDIS. That is, the Ordervalue should be greater than that of the Ordervalue for NDIS.

              To register a protocol driver with NDIS, the driver should call the NdisRegisterProtocolfunction from within the MyDriverInitializefunction.

              To register a protocol driver as a stream interface driver, you must call the RegisterDevicefunction. 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 BindAdapterHandlerfunction, 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 ProtocolBindAdapterand ProtocolUnbindAdapterfunctions. NDIS calls the ProtocolBindAdapterfunction 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 NdisOpenAdapterfunction.

              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 NdisOpenAdapterfunction 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 BindAdapterHandlerfunction 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 BindAdapterHandlerfunction.

              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 BindAdapterHandlerfunction), 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\ProtocolsToBindToregistry entry of the adapter. This entry corresponds to a MULTI_SZvalue 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 NoIdleTimerResetsubkey has been entered in the registry and set to nonzero, the system will not call the SystemIdleTimerResetfunction. 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 NdisMRebindProtocolsToAdapterfunction, 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 DriverEntryfunction 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 BusNumberand BusTypekeys for network adapters. The BusNumberkey contains the socket and function pair for the adapter. The BusTypekey 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 Addressregistry key to store the network address.

                Miniport drivers for a network adapter typically implement an Install_Driverfunction 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_Driverentry point in the miniport driver. The Install_Driverfunction 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_RESOURCESmessage 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_RESOURCESmessage 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 NdisMTrIndicateReceivefunction. 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 NdisMTrIndicateReceiveCompletefunction to notify NDIS that the transfer operation has been completed, even if a particular packet is not accepted by any bound protocol. NdisMTrIndicateReceiveCompletenotifies 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 NdisMTrIndicateReceivefunction, 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 MaxTransmitvalue, and submits the MaxTransmitvalue to PPP as a response to an OID_WAN_GET_INFOrequest. The OID_WAN_GET_INFOstructure 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\Parmsregistry 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\Parmskey.

                        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 MaxRecvFrameSizeor MaxSendFrameSizewill override the value of MaxFrameSizefor 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 NdisMWanIndicateReceivefunction has returned), so that NDIS can notify the appropriate bound protocol driver(s).
                          NdisMWanSendComplete Returns the packet and final status of a completed sendrequest 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 VirtualAllocand VirtualCopyfunctions. 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 NdisMCompleteBufferPhysicalMappingto 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 NdisMInidcateReceivePacketfunction 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 NdisMStartBufferPhysicalMappingfunction, 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 NdisFlushBufferand NdisMUpdateSharedMemoryfunctions. 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 MiniportTimerfunction. After the network adapter has completed the transfer operation, the miniport driver calls the NdisMCompleteBufferPhysicalMappingfunction, usually from the MiniportHandleInterruptfunction.

                          On Windows CE, a miniport driver can use the LockPagesor UnlockPagesfunction, in place of the NdisMStartBufferPhysicalMappingand NdisMCompleteBufferPhysicalMappingNDIS functions, for mapping virtual addresses to physical address ranges.