Implement IRP_MN_QUERY_DEVICE_RELATIONS
[reactos.git] / reactos / drivers / net / ndis / ndis / miniport.c
index 3b1a69d..c8dd4c4 100644 (file)
@@ -4,20 +4,48 @@
  * FILE:        ndis/miniport.c
  * PURPOSE:     Routines used by NDIS miniport drivers
  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *              Vizzini (vizzini@plasmic.com)
  * REVISIONS:
  *   CSH 01/08-2000 Created
+ *   20 Aug 2003 vizzini - DMA support
+ *   3  Oct 2003 vizzini - SendPackets support
  */
-#include <miniport.h>
-#include <protocol.h>
+
+#include "ndissys.h"
+#include "efilter.h"
+
 #ifdef DBG
 #include <buffer.h>
 #endif /* DBG */
 
+#undef NdisMSendComplete
+VOID
+EXPORT
+NdisMSendComplete(
+    IN  NDIS_HANDLE     MiniportAdapterHandle,
+    IN  PNDIS_PACKET    Packet,
+    IN  NDIS_STATUS     Status);
+
+/* Root of the scm database */
+#define SERVICES_ROOT L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
+
+/*
+ * Define to 1 to get a debugger breakpoint at the end of NdisInitializeWrapper
+ * for each new miniport starting up
+ */
+#define BREAK_ON_MINIPORT_INIT 0
+
+/*
+ * This has to be big enough to hold the results of querying the Route value
+ * from the Linkage key.  Please re-code me to determine this dynamically.
+ */
+#define ROUTE_DATA_SIZE 256
 
 /* Number of media we know */
 #define MEDIA_ARRAY_SIZE    15
 
-static NDIS_MEDIUM MediaArray[MEDIA_ARRAY_SIZE] = {
+static NDIS_MEDIUM MediaArray[MEDIA_ARRAY_SIZE] =
+{
     NdisMedium802_3,
     NdisMedium802_5,
     NdisMediumFddi,
@@ -35,24 +63,24 @@ static NDIS_MEDIUM MediaArray[MEDIA_ARRAY_SIZE] = {
     NdisMediumMax
 };
 
-
+/* global list and lock of Miniports NDIS has registered */
 LIST_ENTRY MiniportListHead;
 KSPIN_LOCK MiniportListLock;
+
+/* global list and lock of adapters NDIS has registered */
 LIST_ENTRY AdapterListHead;
 KSPIN_LOCK AdapterListLock;
 
-
-#ifdef DBG
 VOID
 MiniDisplayPacket(
     PNDIS_PACKET Packet)
 {
+#ifdef DBG
     ULONG i, Length;
     UCHAR Buffer[64];
-#if 0
-    if ((DebugTraceLevel | DEBUG_PACKET) > 0) {
+    if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
         Length = CopyPacketToBuffer(
-            (PUCHAR)&Buffer,
+            Buffer,
             Packet,
             0,
             64);
@@ -67,11 +95,46 @@ MiniDisplayPacket(
 
         DbgPrint("*** PACKET STOP ***\n");
     }
-#endif
-}
 #endif /* DBG */
+}
+
+VOID
+MiniDisplayPacket2(
+    PVOID  HeaderBuffer,
+    UINT   HeaderBufferSize,
+    PVOID  LookaheadBuffer,
+    UINT   LookaheadBufferSize)
+{
+#ifdef DBG
+    if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
+        ULONG i, Length;
+        PUCHAR p;
+
+        DbgPrint("*** RECEIVE PACKET START ***\n");
+        DbgPrint("HEADER:");
+        p = HeaderBuffer;
+        for (i = 0; i < HeaderBufferSize; i++) {
+            if (i % 16 == 0)
+                DbgPrint("\n%04X ", i);
+            DbgPrint("%02X ", *p++);
+        }
+
+        DbgPrint("\nFRAME:");
+
+        p = LookaheadBuffer;
+        Length = (LookaheadBufferSize < 64)? LookaheadBufferSize : 64;
+        for (i = 0; i < Length; i++) {
+            if (i % 16 == 0)
+                DbgPrint("\n%04X ", i);
+            DbgPrint("%02X ", *p++);
+        }
 
+        DbgPrint("\n*** RECEIVE PACKET STOP ***\n");
+    }
+#endif /* DBG */
+}
 
+\f
 VOID
 MiniIndicateData(
     PLOGICAL_ADAPTER    Adapter,
@@ -93,144 +156,168 @@ MiniIndicateData(
  *     PacketSize          = Total size of received packet
  */
 {
-    KIRQL OldIrql;
-    PLIST_ENTRY CurrentEntry;
-    PADAPTER_BINDING AdapterBinding;
-
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called. Adapter (0x%X)  HeaderBuffer (0x%X)  "
-        "HeaderBufferSize (0x%X)  LookaheadBuffer (0x%X)  LookaheadBufferSize (0x%X).\n",
-        Adapter, HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize));
-
-#ifdef DBG
-#if 0
-    if ((DebugTraceLevel | DEBUG_PACKET) > 0) {
-        ULONG i, Length;
-        PUCHAR p;
-
-        DbgPrint("*** RECEIVE PACKET START ***\n");
-        DbgPrint("HEADER:");
-        p = HeaderBuffer;
-        for (i = 0; i < HeaderBufferSize; i++) {
-            if (i % 12 == 0)
-                DbgPrint("\n%04X ", i);
-            DbgPrint("%02X ", *p);
-            (ULONG_PTR)p += 1;
-        }
-
-        DbgPrint("\nFRAME:\n");
+  /* KIRQL OldIrql; */
+  PLIST_ENTRY CurrentEntry;
+  PADAPTER_BINDING AdapterBinding;
+
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called. Adapter (0x%X)  HeaderBuffer (0x%X)  "
+      "HeaderBufferSize (0x%X)  LookaheadBuffer (0x%X)  LookaheadBufferSize (0x%X).\n",
+      Adapter, HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize));
+
+  MiniDisplayPacket2(HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize);
+
+  /*
+   * XXX Think about this.  This is probably broken.  Spinlocks are
+   * taken out for now until i comprehend the Right Way to do this.
+   *
+   * This used to acquire the MiniportBlock spinlock and hold it until
+   * just before the call to ReceiveHandler.  It would then release and
+   * subsequently re-acquire the lock.
+   *
+   * I don't see how this does any good, as it would seem he's just
+   * trying to protect the packet list.  If somebody else dequeues
+   * a packet, we are in fact in bad shape, but we don't want to
+   * necessarily call the receive handler at elevated irql either.
+   *
+   * therefore: We *are* going to call the receive handler at high irql
+   * (due to holding the lock) for now, and eventually we have to
+   * figure out another way to protect this packet list.
+   *
+   * UPDATE: this is busted; this results in a recursive lock acquisition.
+   */
+  //NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
+  //KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+    {
+      CurrentEntry = Adapter->ProtocolListHead.Flink;
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("CurrentEntry = %x\n", CurrentEntry));
 
-        p = LookaheadBuffer;
-        Length = (LookaheadBufferSize < 64)? LookaheadBufferSize : 64;
-        for (i = 0; i < Length; i++) {
-            if (i % 12 == 0)
-                DbgPrint("\n%04X ", i);
-            DbgPrint("%02X ", *p);
-            (ULONG_PTR)p += 1;
+      if (CurrentEntry == &Adapter->ProtocolListHead)
+        {
+          NDIS_DbgPrint(DEBUG_MINIPORT, ("WARNING: No upper protocol layer.\n"));
         }
 
-        DbgPrint("\n*** RECEIVE PACKET STOP ***\n");
-    }
-#endif
-#endif /* DBG */
+      while (CurrentEntry != &Adapter->ProtocolListHead)
+        {
+          AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
+         NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterBinding = %x\n", AdapterBinding));
 
-    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
-    CurrentEntry = Adapter->ProtocolListHead.Flink;
-    while (CurrentEntry != &Adapter->ProtocolListHead) {
-           AdapterBinding = CONTAINING_RECORD(CurrentEntry,
-                                           ADAPTER_BINDING,
-                                           AdapterListEntry);
+          /* see above */
+          /* KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
 
-        KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+#ifdef DBG
+          if(!AdapterBinding)
+            {
+              NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding was null\n"));
+              break;
+            }
 
-        (*AdapterBinding->ProtocolBinding->Chars.u4.ReceiveHandler)(
-            AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-            MacReceiveContext,
-            HeaderBuffer,
-            HeaderBufferSize,
-            LookaheadBuffer,
-            LookaheadBufferSize,
-            PacketSize);
+          if(!AdapterBinding->ProtocolBinding)
+            {
+              NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding->ProtocolBinding was null\n"));
+              break;
+            }
 
-        KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+          if(!AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)
+            {
+              NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding->ProtocolBinding->Chars.ReceiveHandler was null\n"));
+              break;
+            }
+#endif
 
-        CurrentEntry = CurrentEntry->Flink;
+         NDIS_DbgPrint
+             (MID_TRACE,
+              ("XXX (%x) %x %x %x %x %x %x %x XXX\n",
+               *AdapterBinding->ProtocolBinding->Chars.ReceiveHandler,
+               AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
+               MacReceiveContext,
+               HeaderBuffer,
+               HeaderBufferSize,
+               LookaheadBuffer,
+               LookaheadBufferSize,
+               PacketSize));
+
+          /* call the receive handler */
+          (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
+              AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
+              MacReceiveContext,
+              HeaderBuffer,
+              HeaderBufferSize,
+              LookaheadBuffer,
+              LookaheadBufferSize,
+              PacketSize);
+
+          /* see above */
+          /* KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql); */
+
+          CurrentEntry = CurrentEntry->Flink;
+        }
     }
-    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
-}
+  //KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
 
+  NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
 
-VOID
-MiniEthReceiveComplete(
-    IN  PETH_FILTER Filter)
+\f
+VOID NTAPI
+MiniIndicateReceivePacket(
+    IN  NDIS_HANDLE    Miniport,
+    IN  PPNDIS_PACKET  PacketArray,
+    IN  UINT           NumberOfPackets)
 /*
- * FUNCTION: Receive indication complete function for Ethernet devices
+ * FUNCTION: receives miniport packet array indications
  * ARGUMENTS:
- *     Filter = Pointer to Ethernet filter
+ *     Miniport: Miniport handle for the adapter
+ *     PacketArray: pointer to a list of packet pointers to indicate
+ *     NumberOfPackets: number of packets to indicate
+ * NOTES:
+ *     - This currently is a big temporary hack.  In the future this should
+ *       call ProtocolReceivePacket() on each bound protocol if it exists.
+ *       For now it just mimics NdisMEthIndicateReceive.
  */
 {
-    KIRQL OldIrql;
-    PLIST_ENTRY CurrentEntry;
-    PLOGICAL_ADAPTER Adapter;
-    PADAPTER_BINDING AdapterBinding;
+  UINT i;
 
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+  for(i = 0; i < NumberOfPackets; i++)
+    {
+      PCHAR PacketBuffer = 0;
+      UINT PacketLength = 0;
+      PNDIS_BUFFER NdisBuffer = 0;
 
-    Adapter = (PLOGICAL_ADAPTER)Filter->Miniport;
+#define PACKET_TAG (('k' << 24) + ('P' << 16) + ('D' << 8) + 'N')
 
-    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
-    CurrentEntry = Adapter->ProtocolListHead.Flink;
-    while (CurrentEntry != &Adapter->ProtocolListHead) {
-           AdapterBinding = CONTAINING_RECORD(CurrentEntry,
-                                           ADAPTER_BINDING,
-                                           AdapterListEntry);
+      NdisAllocateMemoryWithTag((PVOID)&PacketBuffer, 1518, PACKET_TAG);
+      if(!PacketBuffer)
+        {
+          NDIS_DbgPrint(MIN_TRACE, ("insufficient resources\n"));
+          return;
+        }
 
-        KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+      NdisQueryPacket(PacketArray[i], NULL, NULL, &NdisBuffer, NULL);
 
-        (*AdapterBinding->ProtocolBinding->Chars.ReceiveCompleteHandler)(
-            AdapterBinding->NdisOpenBlock.ProtocolBindingContext);
+      while(NdisBuffer)
+        {
+          PNDIS_BUFFER CurrentBuffer;
+          PVOID BufferVa;
+          UINT BufferLen;
 
-        KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+          NdisQueryBuffer(NdisBuffer, &BufferVa, &BufferLen);
+          memcpy(PacketBuffer + PacketLength, BufferVa, BufferLen);
+          PacketLength += BufferLen;
 
-        CurrentEntry = CurrentEntry->Flink;
-    }
-    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
-}
+          CurrentBuffer = NdisBuffer;
+          NdisGetNextBuffer(CurrentBuffer, &NdisBuffer);
+        }
 
+      NDIS_DbgPrint(MID_TRACE, ("indicating a %d-byte packet\n", PacketLength));
 
-VOID
-MiniEthReceiveIndication(
-    IN  PETH_FILTER Filter,
-    IN  NDIS_HANDLE MacReceiveContext,
-    IN  PCHAR       Address,
-    IN  PVOID       HeaderBuffer,
-    IN  UINT        HeaderBufferSize,
-    IN  PVOID       LookaheadBuffer,
-    IN  UINT        LookaheadBufferSize,
-    IN  UINT        PacketSize)
-/*
- * FUNCTION: Receive indication function for Ethernet devices
- * ARGUMENTS:
- *     Filter              = Pointer to Ethernet filter
- *     MacReceiveContext   = MAC receive context handle
- *     Address             = Pointer to destination Ethernet address
- *     HeaderBuffer        = Pointer to Ethernet header buffer
- *     HeaderBufferSize    = Size of Ethernet header buffer
- *     LookaheadBuffer     = Pointer to lookahead buffer
- *     LookaheadBufferSize = Size of lookahead buffer
- *     PacketSize          = Total size of received packet
- */
-{
-    MiniIndicateData((PLOGICAL_ADAPTER)Filter->Miniport,
-                     MacReceiveContext,
-                     HeaderBuffer,
-                     HeaderBufferSize,
-                     LookaheadBuffer,
-                     LookaheadBufferSize,
-                     PacketSize);
-}
+      MiniIndicateData(Miniport, NULL, PacketBuffer, 14, PacketBuffer+14, PacketLength-14, PacketLength-14);
 
+      NdisFreeMemory(PacketBuffer, 0, 0);
+    }
+}
 
-VOID
+\f
+VOID NTAPI
 MiniResetComplete(
     IN  NDIS_HANDLE MiniportAdapterHandle,
     IN  NDIS_STATUS Status,
@@ -240,7 +327,26 @@ MiniResetComplete(
 }
 
 
-VOID
+\f
+VOID NTAPI
+MiniRequestComplete(
+    IN PNDIS_MINIPORT_BLOCK Adapter,
+    IN PNDIS_REQUEST Request,
+    IN NDIS_STATUS Status)
+{
+    PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)Request->MacReserved;
+
+    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+
+    if( MacBlock->Binding->RequestCompleteHandler ) {
+        (*MacBlock->Binding->RequestCompleteHandler)(
+            MacBlock->Binding->ProtocolBindingContext,
+            Request,
+            Status);
+    }
+}
+
+VOID NTAPI
 MiniSendComplete(
     IN  NDIS_HANDLE     MiniportAdapterHandle,
     IN  PNDIS_PACKET    Packet,
@@ -260,14 +366,14 @@ MiniSendComplete(
 
     AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
 
-    (*AdapterBinding->ProtocolBinding->Chars.u2.SendCompleteHandler)(
+    (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
         Packet,
         Status);
 }
 
 
-VOID
+VOID NTAPI
 MiniSendResourcesAvailable(
     IN  NDIS_HANDLE MiniportAdapterHandle)
 {
@@ -275,32 +381,32 @@ MiniSendResourcesAvailable(
 }
 
 
-VOID
+VOID NTAPI
 MiniTransferDataComplete(
     IN  NDIS_HANDLE     MiniportAdapterHandle,
     IN  PNDIS_PACKET    Packet,
     IN  NDIS_STATUS     Status,
     IN  UINT            BytesTransferred)
 {
-    PLOGICAL_ADAPTER Adapter        = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
-    PADAPTER_BINDING AdapterBinding = Adapter->MiniportAdapterBinding;
+    PADAPTER_BINDING AdapterBinding;
 
     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
-    (*AdapterBinding->ProtocolBinding->Chars.u3.TransferDataCompleteHandler)(
+    AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
+
+    (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
         Packet,
-        Status,
-        BytesTransferred);
+        Status);
 }
 
-
+\f
 BOOLEAN
 MiniAdapterHasAddress(
     PLOGICAL_ADAPTER Adapter,
     PNDIS_PACKET Packet)
 /*
- * FUNCTION: Determines wether a packet has the same destination address as an adapter
+ * FUNCTION: Determines whether a packet has the same destination address as an adapter
  * ARGUMENTS:
  *     Adapter = Pointer to logical adapter object
  *     Packet  = Pointer to NDIS packet
@@ -308,49 +414,73 @@ MiniAdapterHasAddress(
  *     TRUE if the destination address is that of the adapter, FALSE if not
  */
 {
-    UINT Length;
-    PUCHAR Start1;
-    PUCHAR Start2;
-    PNDIS_BUFFER NdisBuffer;
-    UINT BufferLength;
-
-    Start1 = (PUCHAR)&Adapter->Address;
-    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
-    if (!NdisBuffer) {
-        NDIS_DbgPrint(MID_TRACE, ("Packet contains no buffers.\n"));
-        return FALSE;
+  UINT Length;
+  PUCHAR Start1;
+  PUCHAR Start2;
+  PNDIS_BUFFER NdisBuffer;
+  UINT BufferLength;
+
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+
+#ifdef DBG
+  if(!Adapter)
+    {
+      NDIS_DbgPrint(MID_TRACE, ("Adapter object was null\n"));
+      return FALSE;
+    }
+
+  if(!Packet)
+    {
+      NDIS_DbgPrint(MID_TRACE, ("Packet was null\n"));
+      return FALSE;
+    }
+#endif
+
+  NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
+
+  if (!NdisBuffer)
+    {
+      NDIS_DbgPrint(MID_TRACE, ("Packet contains no buffers.\n"));
+      return FALSE;
     }
 
-    NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
+  NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
 
-    /* FIXME: Should handle fragmented packets */
+  /* FIXME: Should handle fragmented packets */
 
-    switch (Adapter->NdisMiniportBlock.MediaType) {
-    case NdisMedium802_3:
+  switch (Adapter->NdisMiniportBlock.MediaType)
+    {
+      case NdisMedium802_3:
         Length = ETH_LENGTH_OF_ADDRESS;
         /* Destination address is the first field */
         break;
 
-    default:
-        NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n",
-            Adapter->NdisMiniportBlock.MediaType));
+      default:
+        NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n", Adapter->NdisMiniportBlock.MediaType));
         return FALSE;
     }
 
-    if (BufferLength < Length) {
+  if (BufferLength < Length)
+    {
         NDIS_DbgPrint(MID_TRACE, ("Buffer is too small.\n"));
         return FALSE;
     }
 
-    return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
-}
+  Start1 = (PUCHAR)&Adapter->Address;
+  NDIS_DbgPrint(MAX_TRACE, ("packet address: %x:%x:%x:%x:%x:%x adapter address: %x:%x:%x:%x:%x:%x\n",
+      *((char *)Start1), *(((char *)Start1)+1), *(((char *)Start1)+2), *(((char *)Start1)+3), *(((char *)Start1)+4), *(((char *)Start1)+5),
+      *((char *)Start2), *(((char *)Start2)+1), *(((char *)Start2)+2), *(((char *)Start2)+3), *(((char *)Start2)+4), *(((char *)Start2)+5))
+  );
 
+  return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
+}
 
+\f
 PLOGICAL_ADAPTER
 MiniLocateDevice(
     PNDIS_STRING AdapterName)
 /*
- * FUNCTION: Returns the logical adapter object for a specific adapter
+ * FUNCTION: Finds an adapter object by name
  * ARGUMENTS:
  *     AdapterName = Pointer to name of adapter
  * RETURNS:
@@ -359,124 +489,123 @@ MiniLocateDevice(
  *     is responsible for dereferencing after use
  */
 {
-    KIRQL OldIrql;
-    PLIST_ENTRY CurrentEntry;
-    PLOGICAL_ADAPTER Adapter;
+  KIRQL OldIrql;
+  PLIST_ENTRY CurrentEntry;
+  PLOGICAL_ADAPTER Adapter = 0;
 
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+  ASSERT(AdapterName);
 
-    KeAcquireSpinLock(&AdapterListLock, &OldIrql);
-    CurrentEntry = AdapterListHead.Flink;
-    while (CurrentEntry != &AdapterListHead) {
-           Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
-        if (RtlCompareUnicodeString(AdapterName, &Adapter->DeviceName, TRUE) == 0) {
-            ReferenceObject(Adapter);
-            KeReleaseSpinLock(&AdapterListLock, OldIrql);
+  if(IsListEmpty(&AdapterListHead))
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("No registered miniports for protocol to bind to\n"));
+      return NULL;
+    }
 
-            NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at (0x%X).\n", Adapter));
+  KeAcquireSpinLock(&AdapterListLock, &OldIrql);
+    {
+      do
+        {
+          CurrentEntry = AdapterListHead.Flink;
 
-            return Adapter;
-        }
+          while (CurrentEntry != &AdapterListHead)
+            {
+              Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
 
-        CurrentEntry = CurrentEntry->Flink;
+              ASSERT(Adapter);
+
+              NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterName = %wZ\n", AdapterName));
+              NDIS_DbgPrint(DEBUG_MINIPORT, ("DeviceName = %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
+
+              if (RtlCompareUnicodeString(AdapterName, &Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
+                {
+                  break;
+                }
+
+              Adapter = NULL;
+              CurrentEntry = CurrentEntry->Flink;
+            }
+        } while (0);
     }
-    KeReleaseSpinLock(&AdapterListLock, OldIrql);
+  KeReleaseSpinLock(&AdapterListLock, OldIrql);
 
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving (adapter not found).\n"));
+  if(Adapter)
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at 0x%x\n", Adapter));
+    }
+  else
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving (adapter not found).\n"));
+    }
 
-    return NULL;
+  return Adapter;
 }
 
-
+\f
 NDIS_STATUS
 MiniQueryInformation(
     PLOGICAL_ADAPTER    Adapter,
     NDIS_OID            Oid,
     ULONG               Size,
+    PVOID               Buffer,
     PULONG              BytesWritten)
 /*
  * FUNCTION: Queries a logical adapter for properties
  * ARGUMENTS:
  *     Adapter      = Pointer to the logical adapter object to query
  *     Oid          = Specifies the Object ID to query for
- *     Size         = If non-zero overrides the length in the adapter object
+ *     Size         = Size of the passed buffer
+ *     Buffer       = Buffer for the output
  *     BytesWritten = Address of buffer to place number of bytes written
  * NOTES:
  *     If the specified buffer is too small, a new buffer is allocated,
  *     and the query is attempted again
  * RETURNS:
  *     Status of operation
+ * TODO:
+ *     Is there any way to use the buffer provided by the protocol?
  */
 {
-    NDIS_STATUS NdisStatus;
-    ULONG BytesNeeded;
-
-    if (Adapter->QueryBufferLength == 0) {
-        Adapter->QueryBuffer = ExAllocatePool(NonPagedPool, (Size == 0)? 32 : Size);
-
-        if (!Adapter->QueryBuffer) {
-            NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-            return NDIS_STATUS_RESOURCES;
-        }
+  NDIS_STATUS NdisStatus;
+  ULONG BytesNeeded;
 
-        Adapter->QueryBufferLength = (Size == 0)? 32 : Size;
-    }
-
-    BytesNeeded = (Size == 0)? Adapter->QueryBufferLength : Size;
-
-    NdisStatus = (*Adapter->Miniport->Chars.QueryInformationHandler)(
-        Adapter->NdisMiniportBlock.MiniportAdapterContext,
-        Oid,
-        Adapter->QueryBuffer,
-        BytesNeeded,
-        BytesWritten,
-        &BytesNeeded);
-
-    if ((NT_SUCCESS(NdisStatus)) || (NdisStatus == NDIS_STATUS_PENDING)) {
-        NDIS_DbgPrint(DEBUG_MINIPORT, ("Miniport returned status (0x%X).\n", NdisStatus));
-        return NdisStatus;
-    }
-
-    if (NdisStatus == NDIS_STATUS_INVALID_LENGTH) {
-        ExFreePool(Adapter->QueryBuffer);
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
-        Adapter->QueryBufferLength += BytesNeeded;
-        Adapter->QueryBuffer = ExAllocatePool(NonPagedPool,
-                                              Adapter->QueryBufferLength);
+  /* call the miniport's queryinfo handler */
+  NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+      Adapter->NdisMiniportBlock.MiniportAdapterContext,
+      Oid,
+      Buffer,
+      Size,
+      BytesWritten,
+      &BytesNeeded);
 
-        if (!Adapter->QueryBuffer) {
-            NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-            return NDIS_STATUS_RESOURCES;
-        }
+  /* FIXME: Wait in pending case! */
 
-        NdisStatus = (*Adapter->Miniport->Chars.QueryInformationHandler)(
-            Adapter->NdisMiniportBlock.MiniportAdapterContext,
-            Oid,
-            Adapter->QueryBuffer,
-            Size,
-            BytesWritten,
-            &BytesNeeded);
+  /* XXX is status_pending part of success macro? */
+  if ((NT_SUCCESS(NdisStatus)) || (NdisStatus == NDIS_STATUS_PENDING))
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Miniport returned status (0x%X).\n", NdisStatus));
+      return NdisStatus;
     }
 
-    return NdisStatus;
+  return NdisStatus;
 }
 
-
+\f
 NDIS_STATUS
 FASTCALL
 MiniQueueWorkItem(
-    PLOGICAL_ADAPTER    Adapter,
-    NDIS_WORK_ITEM_TYPE WorkItemType,
-    PVOID               WorkItemContext,
-    NDIS_HANDLE         Initiator)
+    PLOGICAL_ADAPTER     Adapter,
+    NDIS_WORK_ITEM_TYPE  WorkItemType,
+    PVOID                WorkItemContext)
 /*
  * FUNCTION: Queues a work item for execution at a later time
  * ARGUMENTS:
  *     Adapter         = Pointer to the logical adapter object to queue work item on
  *     WorkItemType    = Type of work item to queue
  *     WorkItemContext = Pointer to context information for work item
- *     Initiator       = Pointer to ADAPTER_BINDING structure of initiating protocol
  * NOTES:
  *     Adapter lock must be held when called
  * RETURNS:
@@ -486,53 +615,52 @@ MiniQueueWorkItem(
     PNDIS_MINIPORT_WORK_ITEM Item;
 
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
-
-    if (Adapter->WorkQueueLevel < NDIS_MINIPORT_WORK_QUEUE_SIZE - 1) {
-        Item = &Adapter->WorkQueue[Adapter->WorkQueueLevel];
-        Adapter->WorkQueueLevel++;
-    } else {
-        Item = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
-        if (Item) {
-            /* Set flag so we know that the buffer should be freed
-               when work item is dequeued */
-            Item->Allocated = TRUE;
-        } else {
-            NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-            return NDIS_STATUS_RESOURCES;
-        }
+    
+    ASSERT(Adapter);
+    ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+    
+    Item = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
+    if (Item == NULL)
+    {
+        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NDIS_STATUS_RESOURCES;
     }
-
+    
     Item->WorkItemType    = WorkItemType;
     Item->WorkItemContext = WorkItemContext;
-    Item->Initiator       = Initiator;
-
+    
+    /* safe due to adapter lock held */
     Item->Link.Next = NULL;
-    if (!Adapter->WorkQueueHead) {
+    if (!Adapter->WorkQueueHead)
+    {
         Adapter->WorkQueueHead = Item;
-    } else {
+        Adapter->WorkQueueTail = Item;
+    }
+    else
+    {
         Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)Item;
+        Adapter->WorkQueueTail = Item;
     }
-
-    KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
-
+    
+    KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
+    
     return NDIS_STATUS_SUCCESS;
 }
 
-
+\f
 NDIS_STATUS
 FASTCALL
 MiniDequeueWorkItem(
     PLOGICAL_ADAPTER    Adapter,
     NDIS_WORK_ITEM_TYPE *WorkItemType,
-    PVOID               *WorkItemContext,
-    NDIS_HANDLE         *Initiator)
+    PVOID               *WorkItemContext)
 /*
  * FUNCTION: Dequeues a work item from the work queue of a logical adapter
  * ARGUMENTS:
  *     Adapter         = Pointer to the logical adapter object to dequeue work item from
+ *     AdapterBinding  = Address of buffer for adapter binding for this request
  *     WorkItemType    = Address of buffer for work item type
  *     WorkItemContext = Address of buffer for pointer to context information
- *     Initiator       = Address of buffer for initiator of the work (ADAPTER_BINDING)
  * NOTES:
  *     Adapter lock must be held when called
  * RETURNS:
@@ -540,80 +668,95 @@ MiniDequeueWorkItem(
  */
 {
     PNDIS_MINIPORT_WORK_ITEM Item;
-
+    
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
-
+    
     Item = Adapter->WorkQueueHead;
-    if (Item) {
+    
+    if (Item)
+    {
+        /* safe due to adapter lock held */
         Adapter->WorkQueueHead = (PNDIS_MINIPORT_WORK_ITEM)Item->Link.Next;
+        
         if (Item == Adapter->WorkQueueTail)
             Adapter->WorkQueueTail = NULL;
-
+        
         *WorkItemType    = Item->WorkItemType;
         *WorkItemContext = Item->WorkItemContext;
-        *Initiator       = Item->Initiator;
-
-        if (Item->Allocated) {
-            ExFreePool(Item);
-        } else {
-            Adapter->WorkQueueLevel--;
-#ifdef DBG
-            if (Adapter->WorkQueueLevel < 0) {
-                NDIS_DbgPrint(MIN_TRACE, ("Adapter->WorkQueueLevel is < 0 (should be >= 0).\n"));
-            }
-#endif
-        }
-
+        
+        ExFreePool(Item);
+        
         return NDIS_STATUS_SUCCESS;
     }
-
+    
     return NDIS_STATUS_FAILURE;
 }
 
-
+\f
 NDIS_STATUS
 MiniDoRequest(
-    PLOGICAL_ADAPTER Adapter,
+    PNDIS_MINIPORT_BLOCK Adapter,
     PNDIS_REQUEST NdisRequest)
 /*
  * FUNCTION: Sends a request to a miniport
  * ARGUMENTS:
- *     Adapter     = Pointer to logical adapter object
- *     NdisRequest = Pointer to NDIS request structure describing request
+ *     AdapterBinding = Pointer to binding used in the request
+ *     NdisRequest    = Pointer to NDIS request structure describing request
  * RETURNS:
  *     Status of operation
  */
 {
-    Adapter->NdisMiniportBlock.MediaRequest = NdisRequest;
-
-    switch (NdisRequest->RequestType) {
+    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+    
+    Adapter->MediaRequest = NdisRequest;
+    
+    switch (NdisRequest->RequestType)
+    {
     case NdisRequestQueryInformation:
-        return (*Adapter->Miniport->Chars.QueryInformationHandler)(
-            Adapter->NdisMiniportBlock.MiniportAdapterContext,
+        return (*Adapter->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
+            Adapter->MiniportAdapterContext,
             NdisRequest->DATA.QUERY_INFORMATION.Oid,
             NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
             NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
             (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
             (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded);
         break;
-
+        
     case NdisRequestSetInformation:
-        return (*Adapter->Miniport->Chars.SetInformationHandler)(
-            Adapter->NdisMiniportBlock.MiniportAdapterContext,
+        return (*Adapter->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
+            Adapter->MiniportAdapterContext,
             NdisRequest->DATA.SET_INFORMATION.Oid,
             NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
             NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
             (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesRead,
             (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesNeeded);
         break;
-
+        
     default:
         return NDIS_STATUS_FAILURE;
     }
 }
 
+\f
+/*
+ * @implemented
+ */
+#undef NdisMQueryInformationComplete
+VOID
+EXPORT
+NdisMQueryInformationComplete(
+    IN  NDIS_HANDLE MiniportAdapterHandle,
+    IN  NDIS_STATUS Status)
+{
+    PNDIS_MINIPORT_BLOCK MiniportBlock =
+       (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+    ASSERT(MiniportBlock);
+    if( MiniportBlock->QueryCompleteHandler )
+       (MiniportBlock->QueryCompleteHandler)(MiniportAdapterHandle, Status);
+}
 
-VOID STDCALL MiniportDpc(
+\f
+VOID NTAPI MiniportDpc(
     IN PKDPC Dpc,
     IN PVOID DeferredContext,
     IN PVOID SystemArgument1,
@@ -627,88 +770,115 @@ VOID STDCALL MiniportDpc(
  *     SystemArgument2 = Unused
  */
 {
-    NDIS_STATUS NdisStatus;
-    PVOID WorkItemContext;
-    NDIS_WORK_ITEM_TYPE WorkItemType;
-    PADAPTER_BINDING AdapterBinding;
-    PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
+  NDIS_STATUS NdisStatus;
+  PVOID WorkItemContext;
+  NDIS_WORK_ITEM_TYPE WorkItemType;
+  PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
 
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
-    NdisStatus = MiniDequeueWorkItem(Adapter,
-                                     &WorkItemType,
-                                     &WorkItemContext,
-                                     (PNDIS_HANDLE)&AdapterBinding);
-    if (NdisStatus == NDIS_STATUS_SUCCESS) {
-        Adapter->MiniportAdapterBinding = AdapterBinding;
-        switch (WorkItemType) {
-        case NdisWorkItemSend:
+  NdisStatus = 
+      MiniDequeueWorkItem
+      (Adapter, &WorkItemType, &WorkItemContext);
+
+  if (NdisStatus == NDIS_STATUS_SUCCESS)
+    {
+      switch (WorkItemType)
+        {
+          case NdisWorkItemSend:
+            /*
+             * called by ProSend when protocols want to send packets to the miniport
+             */
 #ifdef DBG
             MiniDisplayPacket((PNDIS_PACKET)WorkItemContext);
 #endif
-            NdisStatus = (*Adapter->Miniport->Chars.u1.SendHandler)(
-                Adapter->NdisMiniportBlock.MiniportAdapterContext,
-                (PNDIS_PACKET)WorkItemContext,
-                0);
-            if (NdisStatus != NDIS_STATUS_PENDING) {
-                MiniSendComplete((NDIS_HANDLE)Adapter,
-                                 (PNDIS_PACKET)WorkItemContext,
-                                 NdisStatus);
-            }
-            break;
-
-        case NdisWorkItemSendLoopback:
-            NdisStatus = ProIndicatePacket(Adapter,
-                                           (PNDIS_PACKET)WorkItemContext);
-            MiniSendComplete((NDIS_HANDLE)Adapter,
-                             (PNDIS_PACKET)WorkItemContext,
-                             NdisStatus);
+            if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
+              {
+                NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
+
+                /*
+                 * XXX assumes single-packet - prolly OK since we'll call something
+                 * different on multi-packet sends
+                 */
+                (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
+                    Adapter->NdisMiniportBlock.MiniportAdapterContext, (PPNDIS_PACKET)&WorkItemContext, 1);
+               NdisStatus =
+                   NDIS_GET_PACKET_STATUS((PNDIS_PACKET)WorkItemContext);
+
+                NDIS_DbgPrint(MAX_TRACE, ("back from miniport's SendPackets handler\n"));
+              }
+            else
+              {
+                NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
+
+                NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
+                    Adapter->NdisMiniportBlock.MiniportAdapterContext, (PNDIS_PACKET)WorkItemContext, 0);
+
+                NDIS_DbgPrint(MAX_TRACE, ("back from miniport's Send handler\n"));
+              }
+           if( NdisStatus != NDIS_STATUS_PENDING ) {
+               NdisMSendComplete
+                   ( Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus );
+               Adapter->MiniportBusy = FALSE;
+           }
             break;
 
-        case NdisWorkItemReturnPackets:
+          case NdisWorkItemSendLoopback:
+            /*
+             * called by ProSend when protocols want to send loopback packets
+             */
+            /* XXX atm ProIndicatePacket sends a packet up via the loopback adapter only */
+            NdisStatus = ProIndicatePacket(Adapter, (PNDIS_PACKET)WorkItemContext);
+            MiniSendComplete((NDIS_HANDLE)Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus);
             break;
 
-        case NdisWorkItemResetRequested:
+          case NdisWorkItemReturnPackets:
             break;
 
-        case NdisWorkItemResetInProgress:
+          case NdisWorkItemResetRequested:
             break;
 
-        case NdisWorkItemHalt:
+          case NdisWorkItemResetInProgress:
             break;
 
-        case NdisWorkItemMiniportCallback:
+          case NdisWorkItemMiniportCallback:
             break;
 
-        case NdisWorkItemRequest:
-            NdisStatus = MiniDoRequest(Adapter, (PNDIS_REQUEST)WorkItemContext);
+          case NdisWorkItemRequest:
+            NdisStatus = MiniDoRequest(&Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext);
 
             if (NdisStatus == NDIS_STATUS_PENDING)
-                break;
-
-            switch (((PNDIS_REQUEST)WorkItemContext)->RequestType) {
-            case NdisRequestQueryInformation:
-                NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
-                break;
-
-            case NdisRequestSetInformation:
-                NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
-                break;
-
-            default:
-                NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
-                break;
-            }
+              break;
+
+            switch (((PNDIS_REQUEST)WorkItemContext)->RequestType)
+              {
+                case NdisRequestQueryInformation:
+                 NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
+                  MiniRequestComplete( &Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
+                  break;
+
+                case NdisRequestSetInformation:
+                  NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
+                  MiniRequestComplete( &Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
+                  break;
+
+                default:
+                  NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
+                  break;
+              }
             break;
 
-        default:
+          default:
             NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
             break;
         }
     }
 }
 
-
+\f
+/*
+ * @unimplemented
+ */
 VOID
 EXPORT
 NdisMCloseLog(
@@ -717,7 +887,10 @@ NdisMCloseLog(
     UNIMPLEMENTED
 }
 
-
+\f
+/*
+ * @unimplemented
+ */
 NDIS_STATUS
 EXPORT
 NdisMCreateLog(
@@ -727,19 +900,34 @@ NdisMCreateLog(
 {
     UNIMPLEMENTED
 
-       return NDIS_STATUS_FAILURE;
+  return NDIS_STATUS_FAILURE;
 }
 
-
+\f
+/*
+ * @implemented
+ */
 VOID
 EXPORT
 NdisMDeregisterAdapterShutdownHandler(
     IN  NDIS_HANDLE MiniportHandle)
+/*
+ * FUNCTION: de-registers a shutdown handler
+ * ARGUMENTS:  MiniportHandle:  Handle passed into MiniportInitialize
+ */
 {
-    UNIMPLEMENTED
-}
+  PLOGICAL_ADAPTER  Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
 
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
+  if(Adapter->BugcheckContext->ShutdownHandler)
+    KeDeregisterBugCheckCallback(Adapter->BugcheckContext->CallbackRecord);
+}
+
+\f
+/*
+ * @unimplemented
+ */
 VOID
 EXPORT
 NdisMFlushLog(
@@ -748,7 +936,10 @@ NdisMFlushLog(
     UNIMPLEMENTED
 }
 
-
+/*
+ * @unimplemented
+ */
+#undef NdisMIndicateStatus
 VOID
 EXPORT
 NdisMIndicateStatus(
@@ -760,7 +951,10 @@ NdisMIndicateStatus(
     UNIMPLEMENTED
 }
 
-
+/*
+ * @unimplemented
+ */
+#undef NdisMIndicateStatusComplete
 VOID
 EXPORT
 NdisMIndicateStatusComplete(
@@ -769,7 +963,10 @@ NdisMIndicateStatusComplete(
     UNIMPLEMENTED
 }
 
-
+\f
+/*
+ * @implemented
+ */
 VOID
 EXPORT
 NdisInitializeWrapper(
@@ -784,67 +981,137 @@ NdisInitializeWrapper(
  *     SystemSpecific1   = Pointer to the driver's driver object
  *     SystemSpecific2   = Pointer to the driver's registry path
  *     SystemSpecific3   = Always NULL
+ * NOTES:
+ *     - SystemSpecific2 goes invalid so we copy it
  */
 {
-    PMINIPORT_DRIVER Miniport;
+  PNDIS_M_DRIVER_BLOCK Miniport;
+  PUNICODE_STRING RegistryPath;
+  WCHAR *RegistryBuffer;
 
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+  NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    Miniport = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_DRIVER));
-    if (!Miniport) {
-        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-        *NdisWrapperHandle = NULL;
-        return;
-    }
+  ASSERT(NdisWrapperHandle);
 
-    RtlZeroMemory(Miniport, sizeof(MINIPORT_DRIVER));
+  *NdisWrapperHandle = NULL;
 
-    KeInitializeSpinLock(&Miniport->Lock);
+#if BREAK_ON_MINIPORT_INIT
+  __asm__ ("int $3\n");
+#endif
 
-    Miniport->RefCount = 1;
+  Miniport = ExAllocatePool(NonPagedPool, sizeof(NDIS_M_DRIVER_BLOCK));
 
-    Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
+  if (!Miniport)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+      return;
+    }
 
-    InitializeListHead(&Miniport->AdapterListHead);
+  RtlZeroMemory(Miniport, sizeof(NDIS_M_DRIVER_BLOCK));
 
-    /* Put miniport in global miniport list */
-    ExInterlockedInsertTailList(&MiniportListHead,
-                                &Miniport->ListEntry,
-                                &MiniportListLock);
+  KeInitializeSpinLock(&Miniport->Lock);
 
-    *NdisWrapperHandle = Miniport;
-}
+  Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
 
+  /* set the miniport's driver registry path */
+  RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));
+  if(!RegistryPath)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+      return;
+    }
 
-VOID
-EXPORT
-NdisMQueryInformationComplete(
-    IN  NDIS_HANDLE MiniportAdapterHandle,
-    IN  NDIS_STATUS Status)
-{
-    PLOGICAL_ADAPTER Adapter        = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
-    PADAPTER_BINDING AdapterBinding = (PADAPTER_BINDING)Adapter->MiniportAdapterBinding;
+  RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
+  RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR);  /* room for 0-term */
 
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+  RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
+  if(!RegistryBuffer)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+      return;
+    }
 
-    (*AdapterBinding->ProtocolBinding->Chars.RequestCompleteHandler)(
-        AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-        Adapter->NdisMiniportBlock.MediaRequest,
-        Status);
+  RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);
+  RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;
+
+  RegistryPath->Buffer = RegistryBuffer;
+  Miniport->RegistryPath = RegistryPath;
+
+  InitializeListHead(&Miniport->DeviceList);
+
+  /* Put miniport in global miniport list */
+  ExInterlockedInsertTailList(&MiniportListHead, &Miniport->ListEntry, &MiniportListLock);
+
+  *NdisWrapperHandle = Miniport;
 }
 
+\f
+VOID NTAPI NdisIBugcheckCallback(
+    IN PVOID   Buffer,
+    IN ULONG   Length)
+/*
+ * FUNCTION:  Internal callback for handling bugchecks - calls adapter's shutdown handler
+ * ARGUMENTS:
+ *     Buffer:  Pointer to a bugcheck callback context
+ *     Length:  Unused
+ */
+{
+  PMINIPORT_BUGCHECK_CONTEXT Context = (PMINIPORT_BUGCHECK_CONTEXT)Buffer;
+  ADAPTER_SHUTDOWN_HANDLER sh = (ADAPTER_SHUTDOWN_HANDLER)Context->ShutdownHandler;
+
+   NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
+  if(sh)
+    sh(Context->DriverContext);
+}
+
+\f
+/*
+ * @implemented
+ */
 VOID
 EXPORT
 NdisMRegisterAdapterShutdownHandler(
     IN  NDIS_HANDLE                 MiniportHandle,
     IN  PVOID                       ShutdownContext,
     IN  ADAPTER_SHUTDOWN_HANDLER    ShutdownHandler)
+/*
+ * FUNCTION:  Register a shutdown handler for an adapter
+ * ARGUMENTS:
+ *     MiniportHandle:  Handle originally passed into MiniportInitialize
+ *     ShutdownContext:  Pre-initialized bugcheck context
+ *     ShutdownHandler:  Function to call to handle the bugcheck
+ * NOTES:
+ *     - I'm not sure about ShutdownContext
+ *     - FIXME - memory leak below
+ */
 {
-    UNIMPLEMENTED
-}
+  PLOGICAL_ADAPTER            Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
+  PMINIPORT_BUGCHECK_CONTEXT  BugcheckContext = Adapter->BugcheckContext;
+
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+
+  if(BugcheckContext)
+    return;
+
+  BugcheckContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_BUGCHECK_CONTEXT));
+  if(!BugcheckContext)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+      return;
+    }
 
+  BugcheckContext->ShutdownHandler = ShutdownHandler;
+  BugcheckContext->DriverContext = ShutdownContext;
 
+  /* not sure if this needs to be initialized or not... oh well, it's a leak. */
+  BugcheckContext->CallbackRecord = ExAllocatePool(NonPagedPool, sizeof(KBUGCHECK_CALLBACK_RECORD));
+
+  KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback,
+      BugcheckContext, sizeof(BugcheckContext), (PUCHAR)"Ndis Miniport");
+}
+
+\f
 NDIS_STATUS
 DoQueries(
     PLOGICAL_ADAPTER Adapter,
@@ -858,289 +1125,692 @@ DoQueries(
  *     Status of operation
  */
 {
-    ULONG BytesWritten;
-    NDIS_STATUS NdisStatus;
+  ULONG BytesWritten;
+  NDIS_STATUS NdisStatus;
 
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+  NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+  /* Get MAC options for adapter */
+  NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAC_OPTIONS, sizeof(UINT), 
+                                    &Adapter->NdisMiniportBlock.MacOptions,
+                                    &BytesWritten);
 
-    /* Get MAC options for adapter */
-    NdisStatus = MiniQueryInformation(Adapter,
-                                      OID_GEN_MAC_OPTIONS,
-                                      0,
-                                      &BytesWritten);
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
-        return NdisStatus;
+  if (NdisStatus != NDIS_STATUS_SUCCESS)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
+      return NdisStatus;
     }
 
-    RtlCopyMemory(&Adapter->NdisMiniportBlock.MacOptions, Adapter->QueryBuffer, sizeof(UINT));
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
 
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
+  /* Get current hardware address of adapter */
+  NdisStatus = MiniQueryInformation(Adapter, AddressOID, Adapter->AddressLength,
+                                    &Adapter->Address, &BytesWritten);
 
-    /* Get current hardware address of adapter */
-    NdisStatus = MiniQueryInformation(Adapter,
-                                      AddressOID,
-                                      0,
-                                      &BytesWritten);
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n",
-            AddressOID, NdisStatus));
-        return NdisStatus;
+  if (NdisStatus != NDIS_STATUS_SUCCESS)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n", AddressOID, NdisStatus));
+      return NdisStatus;
     }
 
-    RtlCopyMemory(&Adapter->Address, Adapter->QueryBuffer, Adapter->AddressLength);
 #ifdef DBG
     {
-        /* 802.3 only */
+      /* 802.3 only */
 
-        PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
+      PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
 
-        NDIS_DbgPrint(MAX_TRACE, ("Adapter address is (%02X %02X %02X %02X %02X %02X).\n",
-            A[0], A[1], A[2], A[3], A[4], A[5]));
+      NDIS_DbgPrint(MAX_TRACE, ("Adapter address is (%02X %02X %02X %02X %02X %02X).\n", A[0], A[1], A[2], A[3], A[4], A[5]));
     }
 #endif /* DBG */
 
-    /* Get maximum lookahead buffer size of adapter */
-    NdisStatus = MiniQueryInformation(Adapter,
-                                      OID_GEN_MAXIMUM_LOOKAHEAD,
-                                      0,
-                                      &BytesWritten);
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
-        return NdisStatus;
+  /* Get maximum lookahead buffer size of adapter */
+  NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_LOOKAHEAD, sizeof(ULONG),
+                                    &Adapter->NdisMiniportBlock.MaximumLookahead, &BytesWritten);
+
+  if (NdisStatus != NDIS_STATUS_SUCCESS)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
+      return NdisStatus;
     }
 
-    Adapter->MaxLookaheadLength = *((PULONG)Adapter->QueryBuffer);
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.MaximumLookahead));
 
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->MaxLookaheadLength));
+  /* Get current lookahead buffer size of adapter */
+  NdisStatus = MiniQueryInformation(Adapter, OID_GEN_CURRENT_LOOKAHEAD, sizeof(ULONG),
+                                    &Adapter->NdisMiniportBlock.CurrentLookahead, &BytesWritten);
 
-    /* Get current lookahead buffer size of adapter */
-    NdisStatus = MiniQueryInformation(Adapter,
-                                      OID_GEN_CURRENT_LOOKAHEAD,
-                                      0,
-                                      &BytesWritten);
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {
-        NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
-        return NdisStatus;
+  if (NdisStatus != NDIS_STATUS_SUCCESS)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
+      return NdisStatus;
     }
 
-    Adapter->CurLookaheadLength = *((PULONG)Adapter->QueryBuffer);
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.CurrentLookahead));
 
-    NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->CurLookaheadLength));
+  if (Adapter->NdisMiniportBlock.MaximumLookahead != 0)
+    {
+      Adapter->LookaheadLength = Adapter->NdisMiniportBlock.MaximumLookahead + Adapter->MediumHeaderSize;
+      Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool, Adapter->LookaheadLength);
 
-    if (Adapter->MaxLookaheadLength != 0) {
-        Adapter->LookaheadLength = Adapter->MaxLookaheadLength +
-                                   Adapter->MediumHeaderSize;
-        Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool,
-                                                  Adapter->LookaheadLength);
-        if (!Adapter->LookaheadBuffer)
-            return NDIS_STATUS_RESOURCES;
+      if (!Adapter->LookaheadBuffer)
+        return NDIS_STATUS_RESOURCES;
     }
 
-    return STATUS_SUCCESS;
+  return STATUS_SUCCESS;
 }
 
+\f
+NTSTATUS
+NTAPI
+NdisIForwardIrpAndWaitCompletionRoutine(
+    PDEVICE_OBJECT Fdo,
+    PIRP Irp,
+    PVOID Context)
+{
+  PKEVENT Event = Context;
 
-NDIS_STATUS
-EXPORT
-NdisMRegisterMiniport(
-    IN  NDIS_HANDLE                     NdisWrapperHandle,
-    IN  PNDIS_MINIPORT_CHARACTERISTICS  MiniportCharacteristics,
-    IN  UINT                            CharacteristicsLength)
+  if (Irp->PendingReturned)
+    KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+
+  return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+\f
+NTSTATUS
+NTAPI
+NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
+{
+  KEVENT Event;
+  NTSTATUS Status;
+
+  KeInitializeEvent(&Event, NotificationEvent, FALSE);
+  IoCopyCurrentIrpStackLocationToNext(Irp);
+  IoSetCompletionRoutine(Irp, NdisIForwardIrpAndWaitCompletionRoutine, &Event,
+                         TRUE, TRUE, TRUE);
+  Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
+  if (Status == STATUS_PENDING)
+    {
+      KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+      Status = Irp->IoStatus.Status;
+    }
+  return Status;
+}
+
+\f
+NTSTATUS
+NTAPI
+NdisIPnPStartDevice(
+    IN PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
 /*
- * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
+ * FUNCTION: Handle the PnP start device event
  * ARGUMENTS:
- *     NdisWrapperHandle       = Pointer to handle returned by NdisMInitializeWrapper
- *     MiniportCharacteristics = Pointer to a buffer with miniport characteristics
- *     CharacteristicsLength   = Number of bytes in characteristics buffer
+ *     DeviceObejct = Functional Device Object
+ *     Irp          = IRP_MN_START_DEVICE I/O request packet
  * RETURNS:
  *     Status of operation
  */
 {
-    UINT MinSize;
-    KIRQL OldIrql;
-    NTSTATUS Status;
-    NDIS_STATUS NdisStatus;
-    NDIS_STATUS OpenErrorStatus;
-    UINT SelectedMediumIndex;
-    PLOGICAL_ADAPTER Adapter;
-    NDIS_OID AddressOID;
-    BOOLEAN MemError          = FALSE;
-    PMINIPORT_DRIVER Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
+  PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
+  PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
+  NDIS_WRAPPER_CONTEXT WrapperContext;
+  NDIS_STATUS NdisStatus;
+  NDIS_STATUS OpenErrorStatus;
+  NTSTATUS Status;
+  UINT SelectedMediumIndex = 0;
+  NDIS_OID AddressOID;
+  BOOLEAN Success = FALSE;
+  ULONG ResourceCount;
+  ULONG ResourceListSize;
+  UNICODE_STRING ParamName;
+  PNDIS_CONFIGURATION_PARAMETER ConfigParam;
+  NDIS_HANDLE ConfigHandle;
+  ULONG Size;
+/* FIXME - KIRQL OldIrql; */
+
+  /*
+   * Prepare wrapper context used by HW and configuration routines.
+   */
+
+  Status = IoOpenDeviceRegistryKey(
+    Adapter->NdisMiniportBlock.PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER,
+    KEY_ALL_ACCESS, &WrapperContext.RegistryHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key\n"));
+      return Status;
+    }
 
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+  NDIS_DbgPrint(MAX_TRACE, ("opened device reg key\n"));
 
-    switch (MiniportCharacteristics->MajorNdisVersion) {
-    case 0x03:
-        MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS_S);
+  WrapperContext.DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
+
+  /*
+   * Store the adapter resources used by HW routines such as
+   * NdisMQueryAdapterResources.
+   */
+
+  if (Stack->Parameters.StartDevice.AllocatedResources != NULL &&
+      Stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)
+    {
+      ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
+                      PartialResourceList.Count;
+      ResourceListSize =
+        FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
+                     PartialDescriptors[ResourceCount]);
+
+      Adapter->NdisMiniportBlock.AllocatedResources =
+        ExAllocatePool(PagedPool, ResourceListSize);
+      if (Adapter->NdisMiniportBlock.AllocatedResources == NULL)
+        {
+          return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+      Adapter->NdisMiniportBlock.AllocatedResourcesTranslated =
+        ExAllocatePool(PagedPool, ResourceListSize);
+      if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated == NULL)
+        {
+          ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
+          Adapter->NdisMiniportBlock.AllocatedResources = NULL;
+          return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+      RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResources,
+                    Stack->Parameters.StartDevice.AllocatedResources,
+                    ResourceListSize);
+
+      RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated,
+                    Stack->Parameters.StartDevice.AllocatedResourcesTranslated,
+                    ResourceListSize);
+    }
+
+  /*
+   * Store the Bus Type, Bus Number and Slot information. It's used by
+   * the hardware routines then.
+   */
+
+  NdisOpenConfiguration(&NdisStatus, &ConfigHandle, (NDIS_HANDLE)&WrapperContext);
+
+  Size = sizeof(ULONG);
+  Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
+                               DevicePropertyLegacyBusType, Size,
+                               &Adapter->NdisMiniportBlock.BusType, &Size);
+  if (!NT_SUCCESS(Status) || (INTERFACE_TYPE)Adapter->NdisMiniportBlock.BusType == InterfaceTypeUndefined)
+    {
+      NdisInitUnicodeString(&ParamName, L"BusType");
+      NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
+                            &ParamName, NdisParameterInteger);
+      if (NdisStatus == NDIS_STATUS_SUCCESS)
+        Adapter->NdisMiniportBlock.BusType = ConfigParam->ParameterData.IntegerData;
+      else
+        Adapter->NdisMiniportBlock.BusType = Isa;
+    }
+
+  Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
+                               DevicePropertyBusNumber, Size,
+                               &Adapter->NdisMiniportBlock.BusNumber, &Size);
+  if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.BusNumber == 0xFFFFFFF0)
+    {
+      NdisInitUnicodeString(&ParamName, L"BusNumber");
+      NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
+                            &ParamName, NdisParameterInteger);
+      if (NdisStatus == NDIS_STATUS_SUCCESS)
+        Adapter->NdisMiniportBlock.BusNumber = ConfigParam->ParameterData.IntegerData;
+      else
+        Adapter->NdisMiniportBlock.BusNumber = 0;
+    }
+  WrapperContext.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
+
+  Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
+                               DevicePropertyAddress, Size,
+                               &Adapter->NdisMiniportBlock.SlotNumber, &Size);
+  if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.SlotNumber == (NDIS_INTERFACE_TYPE)-1)
+    {
+      NdisInitUnicodeString(&ParamName, L"SlotNumber");
+      NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
+                            &ParamName, NdisParameterInteger);
+      if (NdisStatus == NDIS_STATUS_SUCCESS)
+        Adapter->NdisMiniportBlock.SlotNumber = ConfigParam->ParameterData.IntegerData;
+      else
+        Adapter->NdisMiniportBlock.SlotNumber = 0;
+    }
+
+  NdisCloseConfiguration(ConfigHandle);
+
+  /*
+   * Call MiniportInitialize.
+   */
+
+  NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
+  NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.InitializeHandler)(
+    &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
+    MEDIA_ARRAY_SIZE, Adapter, (NDIS_HANDLE)&WrapperContext);
+
+  ZwClose(WrapperContext.RegistryHandle);
+
+  if (NdisStatus != NDIS_STATUS_SUCCESS ||
+      SelectedMediumIndex >= MEDIA_ARRAY_SIZE)
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
+      return (NTSTATUS)NdisStatus;
+    }
+
+  /* Set handlers (some NDIS macros require these) */
+
+  Adapter->NdisMiniportBlock.EthRxCompleteHandler = EthFilterDprIndicateReceiveComplete;
+  Adapter->NdisMiniportBlock.EthRxIndicateHandler = EthFilterDprIndicateReceive;
+  Adapter->NdisMiniportBlock.SendCompleteHandler  = MiniSendComplete;
+  Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
+  Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
+  Adapter->NdisMiniportBlock.TDCompleteHandler    = MiniTransferDataComplete;
+  Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
+
+  Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
+
+  switch (Adapter->NdisMiniportBlock.MediaType)
+    {
+      case NdisMedium802_3:
+        Adapter->MediumHeaderSize = 14;       /* XXX figure out what to do about LLC */
+        AddressOID = OID_802_3_CURRENT_ADDRESS;
+        Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
+        NdisStatus = DoQueries(Adapter, AddressOID);
+        if (NdisStatus == NDIS_STATUS_SUCCESS)
+          {
+            Success = EthCreateFilter(32, /* FIXME: Query this from miniport. */
+                                      Adapter->Address.Type.Medium802_3,
+                                      &Adapter->NdisMiniportBlock.EthDB);
+            if (Success)
+              ((PETHI_FILTER)Adapter->NdisMiniportBlock.EthDB)->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
+            else
+              NdisStatus = NDIS_STATUS_RESOURCES;
+          }
         break;
 
-    case 0x04:
-        MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS_S);
+      default:
+        /* FIXME: Support other types of media */
+        NDIS_DbgPrint(MIN_TRACE, ("error: unsupported media\n"));
+        ASSERT(FALSE);
+/* FIXME - KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
+        return STATUS_UNSUCCESSFUL;
+    }
+
+  if (!Success || NdisStatus != NDIS_STATUS_SUCCESS)
+    {
+      NDIS_DbgPrint(MAX_TRACE, ("couldn't create filter (%x)\n", NdisStatus));
+      if (Adapter->LookaheadBuffer)
+        {
+          ExFreePool(Adapter->LookaheadBuffer);
+          Adapter->LookaheadBuffer = NULL;
+        }
+      return (NTSTATUS)NdisStatus;
+    }
+
+  Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
+  Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStarted;
+
+  /* Put adapter in adapter list for this miniport */
+  ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
+
+  /* Put adapter in global adapter list */
+  ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
+
+  return STATUS_SUCCESS;
+}
+
+\f
+NTSTATUS
+NTAPI
+NdisIPnPStopDevice(
+    IN PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+/*
+ * FUNCTION: Handle the PnP stop device event
+ * ARGUMENTS:
+ *     DeviceObejct = Functional Device Object
+ *     Irp          = IRP_MN_STOP_DEVICE I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+  PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
+  KIRQL OldIrql;
+
+  /* Remove adapter from adapter list for this miniport */
+  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, &OldIrql);
+  RemoveEntryList(&Adapter->MiniportListEntry);
+  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, OldIrql);
+
+  /* Remove adapter from global adapter list */
+  KeAcquireSpinLock(&AdapterListLock, &OldIrql);
+  RemoveEntryList(&Adapter->ListEntry);
+  KeReleaseSpinLock(&AdapterListLock, OldIrql);
+
+  (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HaltHandler)(Adapter);
+
+  if (Adapter->LookaheadBuffer)
+    {
+      ExFreePool(Adapter->LookaheadBuffer);
+      Adapter->LookaheadBuffer = NULL;
+    }
+  if (Adapter->NdisMiniportBlock.AllocatedResources)
+    {
+      ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
+      Adapter->NdisMiniportBlock.AllocatedResources = NULL;
+    }
+  if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated)
+    {
+      ExFreePool(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated);
+      Adapter->NdisMiniportBlock.AllocatedResourcesTranslated = NULL;
+    }
+
+  Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
+  Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStopped;
+
+  return STATUS_SUCCESS;
+}
+
+\f
+NTSTATUS
+NTAPI
+NdisIDispatchPnp(
+    IN PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+  PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
+  PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
+  NTSTATUS Status;
+
+  switch (Stack->MinorFunction)
+    {
+      case IRP_MN_START_DEVICE:
+        Status = NdisIForwardIrpAndWait(Adapter, Irp);
+        if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+          {
+             Status = NdisIPnPStartDevice(DeviceObject, Irp);
+          }
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
         break;
 
-    case 0x05:
-        MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS_S);
+      case IRP_MN_STOP_DEVICE:
+        Status = NdisIForwardIrpAndWait(Adapter, Irp);
+        if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+          {
+            Status = NdisIPnPStopDevice(DeviceObject, Irp);
+          }
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
         break;
 
-    default:
-        NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
-        return NDIS_STATUS_BAD_VERSION;
+      case IRP_MN_QUERY_DEVICE_RELATIONS:
+        Status = STATUS_NOT_SUPPORTED;
+        Irp->IoStatus.Status = Status;
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        break;
+
+      default:
+        IoSkipCurrentIrpStackLocation(Irp);
+        Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
+        break;
     }
 
-    if (CharacteristicsLength < MinSize) {
-        NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
-        return NDIS_STATUS_BAD_CHARACTERISTICS;
+  return Status;
+}
+
+\f
+NTSTATUS
+NTAPI
+NdisIAddDevice(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PDEVICE_OBJECT PhysicalDeviceObject)
+/*
+ * FUNCTION: Create a device for an adapter found using PnP
+ * ARGUMENTS:
+ *     DriverObject         = Pointer to the miniport driver object
+ *     PhysicalDeviceObject = Pointer to the PDO for our adapter
+ */
+{
+  static const WCHAR ClassKeyName[] = {'C','l','a','s','s','\\'};
+  static const WCHAR LinkageKeyName[] = {'\\','L','i','n','k','a','g','e',0};
+  PNDIS_M_DRIVER_BLOCK Miniport;
+  PNDIS_M_DRIVER_BLOCK *MiniportPtr;
+  WCHAR *LinkageKeyBuffer;
+  ULONG DriverKeyLength;
+  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+  UNICODE_STRING ExportName;
+  PDEVICE_OBJECT DeviceObject;
+  PLOGICAL_ADAPTER Adapter;
+  NTSTATUS Status;
+
+  /*
+   * Gain the access to the miniport data structure first.
+   */
+
+  MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));
+  if (MiniportPtr == NULL)
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension.\n"));
+      return STATUS_UNSUCCESSFUL;
+    }
+  Miniport = *MiniportPtr;
+
+  /*
+   * Get name of the Linkage registry key for our adapter. It's located under
+   * the driver key for our driver and so we have basicly two ways to do it.
+   * Either we can use IoOpenDriverRegistryKey or compose it using information
+   * gathered by IoGetDeviceProperty. I choosed the second because
+   * IoOpenDriverRegistryKey wasn't implemented at the time of writing.
+   */
+
+  Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
+                               0, NULL, &DriverKeyLength);
+  if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length.\n"));
+      return Status;
     }
 
-    /* Check if mandatory MiniportXxx functions are specified */
-    if ((!MiniportCharacteristics->HaltHandler) ||
-        (!MiniportCharacteristics->InitializeHandler)||
-        (!MiniportCharacteristics->QueryInformationHandler) ||
-        (!MiniportCharacteristics->ResetHandler) ||
-        (!MiniportCharacteristics->SetInformationHandler)) {
-        NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
-        return NDIS_STATUS_BAD_CHARACTERISTICS;
+  LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +
+                                    sizeof(ClassKeyName) + sizeof(LinkageKeyName));
+  if (LinkageKeyBuffer == NULL)
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name.\n"));
+      return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-    if (MiniportCharacteristics->MajorNdisVersion == 0x03) {
-        if (!MiniportCharacteristics->u1.SendHandler) {
-            NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
-            return NDIS_STATUS_BAD_CHARACTERISTICS;
-        }
-    } else if (MiniportCharacteristics->MajorNdisVersion >= 0x04) {
-        /* NDIS 4.0+ */
-        if ((!MiniportCharacteristics->u1.SendHandler) &&
-            (!MiniportCharacteristics->SendPacketsHandler)) {
-            NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
-            return NDIS_STATUS_BAD_CHARACTERISTICS;
-        }
+  Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
+                               DriverKeyLength, LinkageKeyBuffer +
+                               (sizeof(ClassKeyName) / sizeof(WCHAR)),
+                               &DriverKeyLength);
+  if (!NT_SUCCESS(Status))
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key.\n"));
+      ExFreePool(LinkageKeyBuffer);
+      return Status;
     }
 
-    RtlCopyMemory(&Miniport->Chars, MiniportCharacteristics, MinSize);
+  /* Compose the linkage key name. */
+  RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));
+  RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /
+                sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));
 
-    Adapter = ExAllocatePool(NonPagedPool, sizeof(LOGICAL_ADAPTER));
-    if (!Adapter) {
-        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-        return NDIS_STATUS_RESOURCES;
+  NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S.\n", LinkageKeyBuffer));
+
+  /*
+   * Now open the linkage key and read the "Export" and "RootDevice" values
+   * which contains device name and root service respectively.
+   */
+
+  RtlZeroMemory(QueryTable, sizeof(QueryTable));
+  RtlInitUnicodeString(&ExportName, NULL);
+  QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
+  QueryTable[0].Name = L"Export";
+  QueryTable[0].EntryContext = &ExportName;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,
+                                  QueryTable, NULL, NULL);
+  ExFreePool(LinkageKeyBuffer);
+  if (!NT_SUCCESS(Status))
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)\n", Status));
+      return Status;
     }
 
-    /* This is very important */
-    RtlZeroMemory(Adapter, sizeof(LOGICAL_ADAPTER));
-
-    /* Create the device object for this adapter */
-    /* FIXME: Use GUIDs */
-    RtlInitUnicodeStringFromLiteral(&Adapter->DeviceName, L"\\Device\\ne2000");
-    Status = IoCreateDevice(Miniport->DriverObject,
-                            0,
-                            &Adapter->DeviceName,
-                            FILE_DEVICE_PHYSICAL_NETCARD,
-                            0,
-                            FALSE,
-                            &Adapter->NdisMiniportBlock.DeviceObject);
-    if (!NT_SUCCESS(Status)) {
-        NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
-        ExFreePool(Adapter);
-        return NDIS_STATUS_FAILURE;
+  /*
+   * Create the device object.
+   */
+
+  NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ\n", &ExportName));
+
+  Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),
+    &ExportName, FILE_DEVICE_PHYSICAL_NETCARD,
+    0, FALSE, &DeviceObject);
+  if (!NT_SUCCESS(Status))
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
+      RtlFreeUnicodeString(&ExportName);
+      return Status;
     }
 
-    /* Initialize adapter object */
+  /*
+   * Initialize the adapter structure.
+   */
 
-    KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
+  Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
+  KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
+  InitializeListHead(&Adapter->ProtocolListHead);
+  Adapter->NdisMiniportBlock.DriverHandle = Miniport;
 
-    InitializeListHead(&Adapter->ProtocolListHead);
+  Adapter->NdisMiniportBlock.MiniportName = ExportName;
 
-    Adapter->RefCount = 1;
+  Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;
+  Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;
+  Adapter->NdisMiniportBlock.NextDeviceObject =
+    IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,
+                                PhysicalDeviceObject);
 
-    Adapter->Miniport = Miniport;
+  Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
+  Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
 
-    /* Set handlers (some NDIS macros require these) */
+  KeInitializeDpc(&Adapter->NdisMiniportBlock.DeferredDpc, MiniportDpc, (PVOID)Adapter);
 
-    Adapter->NdisMiniportBlock.EthRxCompleteHandler = MiniEthReceiveComplete;
-    Adapter->NdisMiniportBlock.EthRxIndicateHandler = MiniEthReceiveIndication;
+  DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
 
-    Adapter->NdisMiniportBlock.SendCompleteHandler  = MiniSendComplete;
-    Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
-    Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
-    Adapter->NdisMiniportBlock.TDCompleteHandler    = MiniTransferDataComplete;
+  return STATUS_SUCCESS;
+}
 
+\f
+/*
+ * @implemented
+ */
+NDIS_STATUS
+EXPORT
+NdisMRegisterMiniport(
+    IN  NDIS_HANDLE                     NdisWrapperHandle,
+    IN  PNDIS_MINIPORT_CHARACTERISTICS  MiniportCharacteristics,
+    IN  UINT                            CharacteristicsLength)
+/*
+ * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
+ * ARGUMENTS:
+ *     NdisWrapperHandle       = Pointer to handle returned by NdisMInitializeWrapper
+ *     MiniportCharacteristics = Pointer to a buffer with miniport characteristics
+ *     CharacteristicsLength   = Number of bytes in characteristics buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+  UINT MinSize;
+  PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
+  PNDIS_M_DRIVER_BLOCK *MiniportPtr;
+  NTSTATUS Status;
 
-    KeInitializeDpc(&Adapter->MiniportDpc, MiniportDpc, (PVOID)Adapter);
+  NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    /* Put adapter in adapter list for this miniport */
-    ExInterlockedInsertTailList(&Miniport->AdapterListHead,
-                                &Adapter->MiniportListEntry,
-                                &Miniport->Lock);
+  switch (MiniportCharacteristics->MajorNdisVersion)
+    {
+      case 0x03:
+        MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
+        break;
 
-    /* Put adapter in global adapter list */
-    ExInterlockedInsertTailList(&AdapterListHead,
-                                &Adapter->ListEntry,
-                                &AdapterListLock);
+      case 0x04:
+        MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
+        break;
 
-    /* Call MiniportInitialize */
-    NdisStatus = (*Miniport->Chars.InitializeHandler)(
-        &OpenErrorStatus,
-        &SelectedMediumIndex,
-        &MediaArray[0],
-        MEDIA_ARRAY_SIZE,
-        Adapter,
-        NULL /* FIXME: WrapperConfigurationContext */);
+      case 0x05:
+        MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
+        break;
 
-    if ((NdisStatus == NDIS_STATUS_SUCCESS) &&
-        (SelectedMediumIndex < MEDIA_ARRAY_SIZE)) {
-        
-        Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
-
-        switch (Adapter->NdisMiniportBlock.MediaType) {
-        case NdisMedium802_3:
-            Adapter->MediumHeaderSize = 14;
-            AddressOID = OID_802_3_CURRENT_ADDRESS;
-            Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
-
-            Adapter->NdisMiniportBlock.FilterDbs.u.EthDB = ExAllocatePool(NonPagedPool,
-                                                        sizeof(ETH_FILTER));
-            if (Adapter->NdisMiniportBlock.FilterDbs.u.EthDB) {
-                RtlZeroMemory(Adapter->NdisMiniportBlock.FilterDbs.u.EthDB, sizeof(ETH_FILTER));
-                Adapter->NdisMiniportBlock.FilterDbs.u.EthDB->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
-            } else
-                MemError = TRUE;
-            break;
+      default:
+        NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
+        return NDIS_STATUS_BAD_VERSION;
+    }
 
-        default:
-            /* FIXME: Support other types of medias */
-            ASSERT(FALSE);
-            return NDIS_STATUS_FAILURE;
-        }
+  if (CharacteristicsLength < MinSize)
+    {
+        NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
+        return NDIS_STATUS_BAD_CHARACTERISTICS;
+    }
 
-        NdisStatus = DoQueries(Adapter, AddressOID);
+  /* Check if mandatory MiniportXxx functions are specified */
+  if ((!MiniportCharacteristics->HaltHandler) ||
+      (!MiniportCharacteristics->InitializeHandler)||
+      (!MiniportCharacteristics->QueryInformationHandler) ||
+      (!MiniportCharacteristics->ResetHandler) ||
+      (!MiniportCharacteristics->SetInformationHandler))
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
+      return NDIS_STATUS_BAD_CHARACTERISTICS;
     }
 
-    if ((MemError) ||
-        (NdisStatus != NDIS_STATUS_SUCCESS) ||
-        (SelectedMediumIndex >= MEDIA_ARRAY_SIZE)) {
+  if (MiniportCharacteristics->MajorNdisVersion == 0x03)
+    {
+      if (!MiniportCharacteristics->SendHandler)
+        {
+          NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
+          return NDIS_STATUS_BAD_CHARACTERISTICS;
+        }
+    }
+  else if (MiniportCharacteristics->MajorNdisVersion >= 0x04)
+    {
+      /* NDIS 4.0+ */
+      if ((!MiniportCharacteristics->SendHandler) &&
+          (!MiniportCharacteristics->SendPacketsHandler))
+        {
+          NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
+          return NDIS_STATUS_BAD_CHARACTERISTICS;
+        }
+    }
 
-        /* Remove adapter from adapter list for this miniport */
-        KeAcquireSpinLock(&Miniport->Lock, &OldIrql);
-        RemoveEntryList(&Adapter->MiniportListEntry);
-        KeReleaseSpinLock(&Miniport->Lock, OldIrql);
+  /* TODO: verify NDIS5 and NDIS5.1 */
 
-        /* Remove adapter from global adapter list */
-        KeAcquireSpinLock(&AdapterListLock, &OldIrql);
-        RemoveEntryList(&Adapter->ListEntry);
-        KeReleaseSpinLock(&AdapterListLock, OldIrql);
+  RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);
 
-        if (Adapter->LookaheadBuffer)
-            ExFreePool(Adapter->LookaheadBuffer);
+  /*
+   * NOTE: This is VERY unoptimal! Should we store the NDIS_M_DRIVER_BLOCK
+   * structure in the driver extension or what?
+   */
 
-        IoDeleteDevice(Adapter->NdisMiniportBlock.DeviceObject);
-        ExFreePool(Adapter);
-        return NDIS_STATUS_FAILURE;
+  Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),
+                                           sizeof(PNDIS_M_DRIVER_BLOCK), (PVOID*)&MiniportPtr);
+  if (!NT_SUCCESS(Status))
+    {
+      NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension.\n"));
+      return NDIS_STATUS_RESOURCES;
     }
 
-    return NDIS_STATUS_SUCCESS;
-}
+  *MiniportPtr = Miniport;
 
+  Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
+  Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;
 
+  return NDIS_STATUS_SUCCESS;
+}
+
+\f
+/*
+ * @implemented
+ */
+#undef NdisMResetComplete
 VOID
 EXPORT
 NdisMResetComplete(
@@ -1148,12 +1818,14 @@ NdisMResetComplete(
     IN NDIS_STATUS Status,
     IN BOOLEAN     AddressingReset)
 {
-    MiniResetComplete(MiniportAdapterHandle,
-                      Status,
-                      AddressingReset);
+  MiniResetComplete(MiniportAdapterHandle, Status, AddressingReset);
 }
 
-
+\f
+/*
+ * @implemented
+ */
+#undef NdisMSendComplete
 VOID
 EXPORT
 NdisMSendComplete(
@@ -1169,21 +1841,27 @@ NdisMSendComplete(
  *     Status            = Status of send operation
  */
 {
-    MiniSendComplete(MiniportAdapterHandle,
-                     Packet,
-                     Status);
+  MiniSendComplete(MiniportAdapterHandle, Packet, Status);
 }
 
-
+\f
+/*
+ * @implemented
+ */
+#undef NdisMSendResourcesAvailable
 VOID
 EXPORT
 NdisMSendResourcesAvailable(
     IN  NDIS_HANDLE MiniportAdapterHandle)
 {
-    MiniSendResourcesAvailable(MiniportAdapterHandle);
+  MiniSendResourcesAvailable(MiniportAdapterHandle);
 }
 
-
+\f
+/*
+ * @implemented
+ */
+#undef NdisMTransferDataComplete
 VOID
 EXPORT
 NdisMTransferDataComplete(
@@ -1192,31 +1870,28 @@ NdisMTransferDataComplete(
     IN  NDIS_STATUS     Status,
     IN  UINT            BytesTransferred)
 {
-    MiniTransferDataComplete(MiniportAdapterHandle,
-                             Packet,
-                             Status,
-                             BytesTransferred);
+  MiniTransferDataComplete(MiniportAdapterHandle, Packet, Status, BytesTransferred);
 }
 
-
+\f
+/*
+ * @implemented
+ */
+#undef NdisMSetInformationComplete
 VOID
 EXPORT
 NdisMSetInformationComplete(
     IN  NDIS_HANDLE MiniportAdapterHandle,
     IN  NDIS_STATUS Status)
 {
-    PLOGICAL_ADAPTER Adapter        = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
-    PADAPTER_BINDING AdapterBinding = (PADAPTER_BINDING)Adapter->MiniportAdapterBinding;
-
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
-
-    (*AdapterBinding->ProtocolBinding->Chars.RequestCompleteHandler)(
-        AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-        Adapter->NdisMiniportBlock.MediaRequest,
-        Status);
+  (*((PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle))->SetCompleteHandler)(MiniportAdapterHandle, Status);
 }
 
-
+\f
+/*
+ * @implemented
+ */
+#undef NdisMSetAttributes
 VOID
 EXPORT
 NdisMSetAttributes(
@@ -1233,17 +1908,16 @@ NdisMSetAttributes(
  *     AdapterType            = Specifies the I/O bus interface of the caller's NIC
  */
 {
-    PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
-
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
-
-    Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
-    Adapter->Attributes    = BusMaster? NDIS_ATTRIBUTE_BUS_MASTER : 0;
-    Adapter->NdisMiniportBlock.AdapterType   = AdapterType;
-    Adapter->AttributesSet = TRUE;
+  NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+  NdisMSetAttributesEx(MiniportAdapterHandle, MiniportAdapterContext, 0,
+                       BusMaster ? NDIS_ATTRIBUTE_BUS_MASTER : 0,
+                       AdapterType);
 }
 
-
+\f
+/*
+ * @implemented
+ */
 VOID
 EXPORT
 NdisMSetAttributesEx(
@@ -1263,19 +1937,51 @@ NdisMSetAttributesEx(
  *     AdapterType               = Specifies the I/O bus interface of the caller's NIC
  */
 {
-    UNIMPLEMENTED
-}
+  /* TODO: Take CheckForHandTimeInSeconds into account! */
 
+  PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
 
+  NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+  Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
+  Adapter->NdisMiniportBlock.Flags = AttributeFlags;
+  Adapter->NdisMiniportBlock.AdapterType = AdapterType;
+  if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
+    NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
+}
+
+\f
+/*
+ * @implemented
+ */
 VOID
 EXPORT
 NdisMSleep(
     IN  ULONG   MicrosecondsToSleep)
+/*
+ * FUNCTION: delay the thread's execution for MicrosecondsToSleep
+ * ARGUMENTS:
+ *     MicrosecondsToSleep: duh...
+ * NOTES:
+ *     - Because this is a blocking call, current IRQL must be < DISPATCH_LEVEL
+ */
 {
-    UNIMPLEMENTED
-}
+  KTIMER Timer;
+  LARGE_INTEGER DueTime;
+
+  PAGED_CODE();
 
+  DueTime.QuadPart = (-1) * 10 * MicrosecondsToSleep;
+
+  KeInitializeTimer(&Timer);
+  KeSetTimer(&Timer, DueTime, 0);
+  KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
+}
 
+\f
+/*
+ * @implemented
+ */
 BOOLEAN
 EXPORT
 NdisMSynchronizeWithInterrupt(
@@ -1283,12 +1989,15 @@ NdisMSynchronizeWithInterrupt(
     IN  PVOID                       SynchronizeFunction,
     IN  PVOID                       SynchronizeContext)
 {
-    UNIMPLEMENTED
-
-    return FALSE;
+  return(KeSynchronizeExecution(Interrupt->InterruptObject,
+                               (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
+                               SynchronizeContext));
 }
 
-
+\f
+/*
+ * @unimplemented
+ */
 NDIS_STATUS
 EXPORT
 NdisMWriteLogData(
@@ -1298,10 +2007,13 @@ NdisMWriteLogData(
 {
     UNIMPLEMENTED
 
-       return NDIS_STATUS_FAILURE;
+  return NDIS_STATUS_FAILURE;
 }
 
-
+\f
+/*
+ * @implemented
+ */
 VOID
 EXPORT
 NdisTerminateWrapper(
@@ -1310,15 +2022,18 @@ NdisTerminateWrapper(
 /*
  * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
  * ARGUMENTS:
- *     NdisWrapperHandle = Handle returned by NdisInitializeWrapper (MINIPORT_DRIVER)
+ *     NdisWrapperHandle = Handle returned by NdisInitializeWrapper (NDIS_M_DRIVER_BLOCK)
  *     SystemSpecific    = Always NULL
  */
 {
-    PMINIPORT_DRIVER Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
+  PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
 
-    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+  NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    ExFreePool(Miniport);
+  ExFreePool(Miniport->RegistryPath->Buffer);
+  ExFreePool(Miniport->RegistryPath);
+  ExFreePool(Miniport);
 }
 
 /* EOF */
+