Sync with trunk (48237)
[reactos.git] / drivers / network / ndis / ndis / miniport.c
index 5c72c10..bfe4123 100644 (file)
@@ -121,6 +121,55 @@ MiniDisplayPacket2(
 #endif /* DBG */
 }
 
+PNDIS_MINIPORT_WORK_ITEM
+MiniGetFirstWorkItem(
+    PLOGICAL_ADAPTER Adapter,
+    NDIS_WORK_ITEM_TYPE Type)
+{
+    PNDIS_MINIPORT_WORK_ITEM CurrentEntry = Adapter->WorkQueueHead;
+
+    while (CurrentEntry)
+    {
+      if (CurrentEntry->WorkItemType == Type)
+          return CurrentEntry;
+
+      CurrentEntry = (PNDIS_MINIPORT_WORK_ITEM)CurrentEntry->Link.Next;
+    }
+
+    return NULL;
+}
+
+BOOLEAN
+MiniIsBusy(
+    PLOGICAL_ADAPTER Adapter,
+    NDIS_WORK_ITEM_TYPE Type)
+{
+    BOOLEAN Busy = FALSE;
+    KIRQL OldIrql;
+
+    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+
+    if (Type == NdisWorkItemRequest &&
+        (Adapter->NdisMiniportBlock.PendingRequest || MiniGetFirstWorkItem(Adapter, NdisWorkItemRequest)))
+    {
+       Busy = TRUE;
+    }
+    else if (Type == NdisWorkItemSend &&
+             (Adapter->NdisMiniportBlock.FirstPendingPacket || MiniGetFirstWorkItem(Adapter, NdisWorkItemSend)))
+    {
+       Busy = TRUE;
+    }
+    else if (Type == NdisWorkItemResetRequested &&
+             (Adapter->NdisMiniportBlock.ResetStatus == NDIS_STATUS_PENDING || MiniGetFirstWorkItem(Adapter, NdisWorkItemResetRequested)))
+    {
+       Busy = TRUE;
+    }
+
+    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+
+    return Busy;
+}
+
 \f
 VOID
 MiniIndicateData(
@@ -267,7 +316,6 @@ MiniIndicateReceivePacket(
               if (!LookAheadBuffer)
               {
                   NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate lookahead buffer!\n"));
-                  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
                   return;
               }
 
@@ -309,8 +357,6 @@ MiniResetComplete(
     PADAPTER_BINDING AdapterBinding;
     KIRQL OldIrql;
 
-    MiniEndRequest(Adapter, NdisWorkItemResetRequested);
-
     if (AddressingReset)
         MiniDoAddressingReset(Adapter);
 
@@ -319,6 +365,17 @@ MiniResetComplete(
 
     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
 
+    if (Adapter->NdisMiniportBlock.ResetStatus != NDIS_STATUS_PENDING)
+    {
+        KeBugCheckEx(BUGCODE_ID_DRIVER,
+                     (ULONG_PTR)MiniportAdapterHandle,
+                     (ULONG_PTR)Status,
+                     (ULONG_PTR)AddressingReset,
+                     0);
+    }
+
+    Adapter->NdisMiniportBlock.ResetStatus = Status;
+
     CurrentEntry = Adapter->ProtocolListHead.Flink;
 
     while (CurrentEntry != &Adapter->ProtocolListHead)
@@ -347,11 +404,11 @@ MiniRequestComplete(
 
     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
-    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
-    Request = Adapter->NdisMiniportBlock.PendingRequest;
-    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
 
-    MiniEndRequest(Adapter, NdisWorkItemRequest);
+    KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+    Request = Adapter->NdisMiniportBlock.PendingRequest;
+    KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
 
     MacBlock = (PNDIS_REQUEST_MAC_BLOCK)Request->MacReserved;
 
@@ -361,22 +418,12 @@ MiniRequestComplete(
             Request,
             Status);
     }
-}
 
-VOID NTAPI
-MiniIndicateComplete(
-    IN  NDIS_HANDLE     MiniportAdapterHandle,
-    IN  PNDIS_PACKET    Packet,
-    IN  NDIS_STATUS     Status)
-{
-    PADAPTER_BINDING AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[1];
-
-    MiniEndRequest(MiniportAdapterHandle, NdisWorkItemSendLoopback);
+    KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+    Adapter->NdisMiniportBlock.PendingRequest = NULL;
+    KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
 
-    (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
-        AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-        Packet,
-        Status);
+    KeLowerIrql(OldIrql);
 }
 
 VOID NTAPI
@@ -402,6 +449,8 @@ MiniSendComplete(
 
     AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[1];
 
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
     if (Adapter->NdisMiniportBlock.ScatterGatherListSize != 0)
     {
         NDIS_DbgPrint(MAX_TRACE, ("Freeing Scatter/Gather list\n"));
@@ -409,51 +458,35 @@ MiniSendComplete(
         SGList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
                                                   ScatterGatherListPacketInfo);
 
-        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
-
         Adapter->NdisMiniportBlock.SystemAdapterObject->
             DmaOperations->PutScatterGatherList(
                            Adapter->NdisMiniportBlock.SystemAdapterObject,
                            SGList,
                            TRUE);
 
-        KeLowerIrql(OldIrql);
-
         NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
                                          ScatterGatherListPacketInfo) = NULL;
     }
 
-    MiniEndRequest(Adapter, NdisWorkItemSend);
-
     (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
         Packet,
         Status);
-}
-
-NDIS_STATUS
-SignalQueue(PLOGICAL_ADAPTER Adapter)
-{
-    PIO_WORKITEM WorkItem = IoAllocateWorkItem(Adapter->NdisMiniportBlock.DeviceObject);
-
-    ASSERT(WorkItem);
-    if (!WorkItem) return NDIS_STATUS_RESOURCES;
-
-    IoQueueWorkItem(WorkItem,
-                    MiniportWorker,
-                    DelayedWorkQueue,
-                    WorkItem);
 
-    return NDIS_STATUS_SUCCESS;
+    KeLowerIrql(OldIrql);
 }
 
+
 VOID NTAPI
 MiniSendResourcesAvailable(
     IN  NDIS_HANDLE MiniportAdapterHandle)
 {
-    SignalQueue(MiniportAdapterHandle);
+/*
+    UNIMPLEMENTED
+*/
 }
 
+
 VOID NTAPI
 MiniTransferDataComplete(
     IN  NDIS_HANDLE     MiniportAdapterHandle,
@@ -462,16 +495,19 @@ MiniTransferDataComplete(
     IN  UINT            BytesTransferred)
 {
     PADAPTER_BINDING AdapterBinding;
+    KIRQL OldIrql;
 
     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
     AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[1];
 
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
     (*AdapterBinding->ProtocolBinding->Chars.TransferDataCompleteHandler)(
         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
         Packet,
         Status,
         BytesTransferred);
+    KeLowerIrql(OldIrql);
 }
 
 \f
@@ -571,6 +607,12 @@ MiniLocateDevice(
 
   NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
+  if(IsListEmpty(&AdapterListHead))
+    {
+      NDIS_DbgPrint(MIN_TRACE, ("No registered miniports for protocol to bind to\n"));
+      return NULL;
+    }
+
   KeAcquireSpinLock(&AdapterListLock, &OldIrql);
     {
       CurrentEntry = AdapterListHead.Flink;
@@ -634,15 +676,9 @@ MiniSetInformation(
   NdisRequest->DATA.SET_INFORMATION.InformationBuffer = Buffer;
   NdisRequest->DATA.SET_INFORMATION.InformationBufferLength = Size;
 
-  NdisStatus = MiniBeginRequest(Adapter, NdisWorkItemRequest, NdisRequest);
-  if (!NT_SUCCESS(NdisStatus))
-      return NdisStatus;
-
   NdisStatus = MiniDoRequest(Adapter, NdisRequest);
 
   /* FIXME: Wait in pending case! */
-  if (NdisStatus != NDIS_STATUS_PENDING)
-      MiniEndRequest(Adapter, NdisWorkItemRequest);
 
   ASSERT(NdisStatus != NDIS_STATUS_PENDING);
 
@@ -690,15 +726,9 @@ MiniQueryInformation(
   NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer = Buffer;
   NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength = Size;
 
-  NdisStatus = MiniBeginRequest(Adapter, NdisWorkItemRequest, NdisRequest);
-  if (!NT_SUCCESS(NdisStatus))
-      return NdisStatus;
-
   NdisStatus = MiniDoRequest(Adapter, NdisRequest);
 
   /* FIXME: Wait in pending case! */
-  if (NdisStatus != NDIS_STATUS_PENDING)
-      MiniEndRequest(Adapter, NdisWorkItemRequest);
 
   ASSERT(NdisStatus != NDIS_STATUS_PENDING);
 
@@ -721,10 +751,13 @@ MiniCheckForHang( PLOGICAL_ADAPTER Adapter )
  */
 {
    BOOLEAN Ret = FALSE;
+   KIRQL OldIrql;
 
+   KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
    if (Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.CheckForHangHandler)
        Ret = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.CheckForHangHandler)(
          Adapter->NdisMiniportBlock.MiniportAdapterContext);
+   KeLowerIrql(OldIrql);
 
    return Ret;
 }
@@ -755,25 +788,32 @@ MiniReset(
  */
 {
    NDIS_STATUS Status;
+   KIRQL OldIrql;
    BOOLEAN AddressingReset = TRUE;
 
-   Status = MiniBeginRequest(Adapter, NdisWorkItemResetRequested, NULL);
-   if (!NT_SUCCESS(Status))
-       return Status;
+   if (MiniIsBusy(Adapter, NdisWorkItemResetRequested)) {
+       MiniQueueWorkItem(Adapter, NdisWorkItemResetRequested, NULL, FALSE);
+       return NDIS_STATUS_PENDING;
+   }
 
    NdisMIndicateStatus(Adapter, NDIS_STATUS_RESET_START, NULL, 0);
    NdisMIndicateStatusComplete(Adapter);
 
+   KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
    Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ResetHandler)(
             Adapter->NdisMiniportBlock.MiniportAdapterContext,
             &AddressingReset);
 
+   KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+   Adapter->NdisMiniportBlock.ResetStatus = Status;
+   KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+
+   KeLowerIrql(OldIrql);
+
    if (Status != NDIS_STATUS_PENDING) {
        if (AddressingReset)
            MiniDoAddressingReset(Adapter);
 
-       MiniEndRequest(Adapter, NdisWorkItemResetRequested);
-
        NdisMIndicateStatus(Adapter, NDIS_STATUS_RESET_END, NULL, 0);
        NdisMIndicateStatusComplete(Adapter);
    }
@@ -796,45 +836,78 @@ MiniportHangDpc(
   }
 }
 
-NDIS_STATUS
-MiniBeginRequest(
+\f
+VOID
+FASTCALL
+MiniQueueWorkItem(
     PLOGICAL_ADAPTER     Adapter,
     NDIS_WORK_ITEM_TYPE  WorkItemType,
-    PVOID                WorkItemContext)
+    PVOID                WorkItemContext,
+    BOOLEAN              Top)
+/*
+ * 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
+ * RETURNS:
+ *     Status of operation
+ */
 {
-    KIRQL OldIrql;
-    BOOLEAN QueueBusy;
     PNDIS_MINIPORT_WORK_ITEM MiniportWorkItem;
-    PSINGLE_LIST_ENTRY CurrentEntry;
+    PIO_WORKITEM IoWorkItem;
+    KIRQL OldIrql;
 
-    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    QueueBusy = (Adapter->NdisMiniportBlock.WorkQueue[WorkItemType].Next != NULL);
+    ASSERT(Adapter);
 
-    MiniportWorkItem = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
-    if (!MiniportWorkItem)
+    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+    if (Top)
     {
-        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
-        KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
-        return NDIS_STATUS_RESOURCES;
+        if (WorkItemType == NdisWorkItemSend)
+        {
+            NDIS_DbgPrint(MIN_TRACE, ("Requeuing failed packet (%x).\n", WorkItemContext));
+            Adapter->NdisMiniportBlock.FirstPendingPacket = WorkItemContext;
+        }
+        else
+        {
+            //This should never happen
+            ASSERT(FALSE);
+        }
     }
+    else
+    {
+        MiniportWorkItem = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
+        if (!MiniportWorkItem)
+        {
+            KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+            NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+            return;
+        }
 
-    MiniportWorkItem->WorkItemType    = WorkItemType;
-    MiniportWorkItem->WorkItemContext = WorkItemContext;
-    MiniportWorkItem->Link.Next = NULL;
+        MiniportWorkItem->WorkItemType    = WorkItemType;
+        MiniportWorkItem->WorkItemContext = WorkItemContext;
 
-    CurrentEntry = &Adapter->NdisMiniportBlock.WorkQueue[WorkItemType];
-    while (CurrentEntry->Next)
-       CurrentEntry = CurrentEntry->Next;
+        /* safe due to adapter lock held */
+        MiniportWorkItem->Link.Next = NULL;
+        if (!Adapter->WorkQueueHead)
+        {
+            Adapter->WorkQueueHead = MiniportWorkItem;
+            Adapter->WorkQueueTail = MiniportWorkItem;
+        }
+        else
+        {
+            Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)MiniportWorkItem;
+            Adapter->WorkQueueTail = MiniportWorkItem;
+        }
+    }
 
-    CurrentEntry->Next = (PSINGLE_LIST_ENTRY)MiniportWorkItem;
+    IoWorkItem = IoAllocateWorkItem(Adapter->NdisMiniportBlock.DeviceObject);
+    if (IoWorkItem)
+        IoQueueWorkItem(IoWorkItem, MiniportWorker, DelayedWorkQueue, IoWorkItem);
 
     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
-
-    if (QueueBusy)
-        NDIS_DbgPrint(MIN_TRACE, ("Queue %d busy!\n", WorkItemType));
-
-    return (QueueBusy ? NDIS_STATUS_PENDING : NDIS_STATUS_SUCCESS);
 }
 
 \f
@@ -842,7 +915,7 @@ NDIS_STATUS
 FASTCALL
 MiniDequeueWorkItem(
     PLOGICAL_ADAPTER    Adapter,
-    NDIS_WORK_ITEM_TYPE WorkItemType,
+    NDIS_WORK_ITEM_TYPE *WorkItemType,
     PVOID               *WorkItemContext)
 /*
  * FUNCTION: Dequeues a work item from the work queue of a logical adapter
@@ -858,49 +931,42 @@ MiniDequeueWorkItem(
  */
 {
     PNDIS_MINIPORT_WORK_ITEM MiniportWorkItem;
-    KIRQL OldIrql;
+    PNDIS_PACKET Packet;
 
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
-    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
-    MiniportWorkItem = (PNDIS_MINIPORT_WORK_ITEM)Adapter->NdisMiniportBlock.WorkQueue[WorkItemType].Next;
-    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+    MiniportWorkItem = Adapter->WorkQueueHead;
 
-    if (MiniportWorkItem)
+    if ((Packet = Adapter->NdisMiniportBlock.FirstPendingPacket))
     {
-        /* This is VERY IMPORTANT! We dequeue the work item AFTER completion */
+        Adapter->NdisMiniportBlock.FirstPendingPacket = NULL;
 
-        *WorkItemContext = MiniportWorkItem->WorkItemContext;
+        *WorkItemType = NdisWorkItemSend;
+        *WorkItemContext = Packet;
 
         return NDIS_STATUS_SUCCESS;
     }
-    else
+    else if (MiniportWorkItem)
     {
-        return NDIS_STATUS_FAILURE;
-    }
-}
+        /* safe due to adapter lock held */
+        Adapter->WorkQueueHead = (PNDIS_MINIPORT_WORK_ITEM)MiniportWorkItem->Link.Next;
 
-VOID
-MiniEndRequest(
-    PLOGICAL_ADAPTER     Adapter,
-    NDIS_WORK_ITEM_TYPE  WorkItemType)
-{
-    KIRQL OldIrql;
-    BOOLEAN QueueBusy;
-    PNDIS_MINIPORT_WORK_ITEM MiniportWorkItem;
+        if (MiniportWorkItem == Adapter->WorkQueueTail)
+            Adapter->WorkQueueTail = NULL;
 
-    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+        *WorkItemType    = MiniportWorkItem->WorkItemType;
+        *WorkItemContext = MiniportWorkItem->WorkItemContext;
 
-    MiniportWorkItem = (PNDIS_MINIPORT_WORK_ITEM)Adapter->NdisMiniportBlock.WorkQueue[WorkItemType].Next;
-    ASSERT(MiniportWorkItem);
-    Adapter->NdisMiniportBlock.WorkQueue[WorkItemType].Next = MiniportWorkItem->Link.Next;
-    ExFreePool(MiniportWorkItem);
+        ExFreePool(MiniportWorkItem);
 
-    QueueBusy = (Adapter->NdisMiniportBlock.WorkQueue[WorkItemType].Next != NULL);
-    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+        return NDIS_STATUS_SUCCESS;
+    }
+    else
+    {
+        NDIS_DbgPrint(MIN_TRACE, ("No work item to dequeue\n"));
 
-    if (QueueBusy)
-        SignalQueue(Adapter);
+        return NDIS_STATUS_FAILURE;
+    }
 }
 
 \f
@@ -919,12 +985,13 @@ MiniDoRequest(
 {
     NDIS_STATUS Status;
     KIRQL OldIrql;
-
     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
-    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+    KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
     Adapter->NdisMiniportBlock.PendingRequest = NdisRequest;
-    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+    KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
 
     if (!Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.CoRequestHandler)
     {
@@ -963,6 +1030,13 @@ MiniDoRequest(
             NdisRequest);
     }
 
+    if (Status != NDIS_STATUS_PENDING) {
+        KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+        Adapter->NdisMiniportBlock.PendingRequest = NULL;
+        KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+    }
+
+    KeLowerIrql(OldIrql);
     return Status;
 }
 
@@ -979,10 +1053,12 @@ NdisMSetInformationComplete(
 {
   PLOGICAL_ADAPTER Adapter =
        (PLOGICAL_ADAPTER)MiniportAdapterHandle;
-
-  (Adapter->NdisMiniportBlock.SetCompleteHandler)(MiniportAdapterHandle, Status);
-
-  MiniEndRequest(Adapter, NdisWorkItemRequest);
+  KIRQL OldIrql;
+  ASSERT(Adapter);
+  KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+  if (Adapter->NdisMiniportBlock.SetCompleteHandler)
+     (Adapter->NdisMiniportBlock.SetCompleteHandler)(MiniportAdapterHandle, Status);
+  KeLowerIrql(OldIrql);
 }
 
 \f
@@ -998,10 +1074,12 @@ NdisMQueryInformationComplete(
 {
     PLOGICAL_ADAPTER Adapter =
        (PLOGICAL_ADAPTER)MiniportAdapterHandle;
-
-    (Adapter->NdisMiniportBlock.QueryCompleteHandler)(MiniportAdapterHandle, Status);
-
-    MiniEndRequest(Adapter, NdisWorkItemRequest);
+    KIRQL OldIrql;
+    ASSERT(Adapter);
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+    if( Adapter->NdisMiniportBlock.QueryCompleteHandler )
+       (Adapter->NdisMiniportBlock.QueryCompleteHandler)(MiniportAdapterHandle, Status);
+    KeLowerIrql(OldIrql);
 }
 
 VOID
@@ -1009,20 +1087,25 @@ NTAPI
 MiniportWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
 {
   PLOGICAL_ADAPTER Adapter = DeviceObject->DeviceExtension;
-  KIRQL RaiseOldIrql;
+  KIRQL OldIrql, RaiseOldIrql;
   NDIS_STATUS NdisStatus;
   PVOID WorkItemContext;
   NDIS_WORK_ITEM_TYPE WorkItemType;
-  BOOLEAN AddressingReset, NextQueue;
+  BOOLEAN AddressingReset;
 
   IoFreeWorkItem((PIO_WORKITEM)Context);
 
-  for (WorkItemType = 0; WorkItemType < NUMBER_OF_WORK_ITEM_TYPES; WorkItemType++)
-  {
-     NextQueue = FALSE;
-     while (!NextQueue && MiniDequeueWorkItem(Adapter, WorkItemType, &WorkItemContext) == NDIS_STATUS_SUCCESS)
-     {
-        switch (WorkItemType)
+  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
+
+  NdisStatus =
+      MiniDequeueWorkItem
+      (Adapter, &WorkItemType, &WorkItemContext);
+
+  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+
+  if (NdisStatus == NDIS_STATUS_SUCCESS)
+    {
+      switch (WorkItemType)
         {
           case NdisWorkItemSend:
             /*
@@ -1051,7 +1134,7 @@ MiniportWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
 
                     NdisStatus = NDIS_GET_PACKET_STATUS((PNDIS_PACKET)WorkItemContext);
                     if( NdisStatus == NDIS_STATUS_RESOURCES ) {
-                        NextQueue = TRUE;
+                        MiniQueueWorkItem(Adapter, WorkItemType, WorkItemContext, TRUE);
                         break;
                     }
                 }
@@ -1077,7 +1160,7 @@ MiniportWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
                   NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
                   KeLowerIrql(RaiseOldIrql);
                   if( NdisStatus == NDIS_STATUS_RESOURCES ) {
-                      NextQueue = TRUE;
+                      MiniQueueWorkItem(Adapter, WorkItemType, WorkItemContext, TRUE);
                       break;
                   }
                 }
@@ -1097,17 +1180,27 @@ MiniportWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
             NdisStatus = ProIndicatePacket(Adapter, (PNDIS_PACKET)WorkItemContext);
 
             if( NdisStatus != NDIS_STATUS_PENDING )
-                MiniIndicateComplete((NDIS_HANDLE)Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus);
+                MiniSendComplete((NDIS_HANDLE)Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus);
             break;
 
           case NdisWorkItemReturnPackets:
             break;
 
           case NdisWorkItemResetRequested:
+            NdisMIndicateStatus(Adapter, NDIS_STATUS_RESET_START, NULL, 0);
+            NdisMIndicateStatusComplete(Adapter);
+
+            KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
             NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ResetHandler)(
                           Adapter->NdisMiniportBlock.MiniportAdapterContext,
                           &AddressingReset);
 
+            KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+            Adapter->NdisMiniportBlock.ResetStatus = NdisStatus;
+            KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
+
+            KeLowerIrql(OldIrql);
+
             if (NdisStatus != NDIS_STATUS_PENDING)
                MiniResetComplete(Adapter, NdisStatus, AddressingReset);
             break;
@@ -1136,18 +1229,15 @@ MiniportWorker(IN PDEVICE_OBJECT DeviceObject, IN PVOID Context)
 
                 default:
                   NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
-                  MiniEndRequest(Adapter, NdisWorkItemRequest);
                   break;
               }
             break;
 
           default:
-            MiniEndRequest(Adapter, WorkItemType);
             NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
             break;
         }
-     }
-  }
+    }
 }
 
 
@@ -1256,7 +1346,6 @@ NdisMCreateLog(
     if (Adapter->NdisMiniportBlock.Log)
     {
         *LogHandle = NULL;
-        KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
         return NDIS_STATUS_FAILURE;
     }
 
@@ -1264,7 +1353,6 @@ NdisMCreateLog(
     if (!Log)
     {
         *LogHandle = NULL;
-        KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
         return NDIS_STATUS_RESOURCES;
     }
 
@@ -1643,6 +1731,20 @@ NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
   return Status;
 }
 
+NTSTATUS
+NTAPI
+NdisICreateClose(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+  Irp->IoStatus.Status = STATUS_SUCCESS;
+  Irp->IoStatus.Information = 0;
+
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+  return STATUS_SUCCESS;
+}
+
 \f
 NTSTATUS
 NTAPI
@@ -1676,6 +1778,8 @@ NdisIPnPStartDevice(
   LARGE_INTEGER Timeout;
   UINT MaxMulticastAddresses;
   ULONG BytesWritten;
+  PLIST_ENTRY CurrentEntry;
+  PPROTOCOL_BINDING ProtocolBinding;
 
   /*
    * Prepare wrapper context used by HW and configuration routines.
@@ -1866,6 +1970,22 @@ NdisIPnPStartDevice(
     {
       NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
       ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
+      if (Adapter->NdisMiniportBlock.Interrupt)
+      {
+          KeBugCheckEx(BUGCODE_ID_DRIVER,
+                       (ULONG_PTR)Adapter,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.Interrupt,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.TimerQueue,
+                       1);
+      }
+      if (Adapter->NdisMiniportBlock.TimerQueue)
+      {
+          KeBugCheckEx(BUGCODE_ID_DRIVER,
+                       (ULONG_PTR)Adapter,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.Interrupt,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.TimerQueue,
+                       1);
+      }
       return NdisStatus;
     }
 
@@ -1938,6 +2058,17 @@ NdisIPnPStartDevice(
   /* Put adapter in adapter list for this miniport */
   ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
 
+  /* Refresh bindings for all protocols */
+  CurrentEntry = ProtocolListHead.Flink;
+  while (CurrentEntry != &ProtocolListHead)
+  {
+      ProtocolBinding = CONTAINING_RECORD(CurrentEntry, PROTOCOL_BINDING, ListEntry);
+
+      ndisBindMiniportsToProtocol(&NdisStatus, ProtocolBinding);
+
+      CurrentEntry = CurrentEntry->Flink;
+  }
+
   return STATUS_SUCCESS;
 }
 
@@ -2030,6 +2161,7 @@ NdisIDeviceIoControl(
   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
   NDIS_STATUS Status = STATUS_NOT_SUPPORTED;
+  ULONG Written;
 
   Irp->IoStatus.Information = 0;
 
@@ -2042,7 +2174,8 @@ NdisIDeviceIoControl(
                                     *(PNDIS_OID)Irp->AssociatedIrp.SystemBuffer,
                                     Stack->Parameters.DeviceIoControl.OutputBufferLength,
                                     MmGetSystemAddressForMdl(Irp->MdlAddress),
-                                    &Irp->IoStatus.Information);
+                                    &Written);
+      Irp->IoStatus.Information = Written;
       break;
 
     default:
@@ -2152,7 +2285,6 @@ NdisIAddDevice(
   PDEVICE_OBJECT DeviceObject;
   PLOGICAL_ADAPTER Adapter;
   NTSTATUS Status;
-  UINT i;
 
   /*
    * Gain the access to the miniport data structure first.
@@ -2276,9 +2408,6 @@ NdisIAddDevice(
   Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
   Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
 
-  for (i = 0; i < NUMBER_OF_WORK_ITEM_TYPES; i++)
-       Adapter->NdisMiniportBlock.WorkQueue[i].Next = NULL;
-
   KeInitializeTimer(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer);
   KeInitializeDpc(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Dpc, MiniportHangDpc, Adapter);
 
@@ -2422,6 +2551,8 @@ NdisMRegisterMiniport(
 
   *MiniportPtr = Miniport;
 
+  Miniport->DriverObject->MajorFunction[IRP_MJ_CREATE] = NdisICreateClose;
+  Miniport->DriverObject->MajorFunction[IRP_MJ_CLOSE] = NdisICreateClose;
   Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
   Miniport->DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = NdisIShutdown;
   Miniport->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisIDeviceIoControl;
@@ -2883,6 +3014,12 @@ NdisMRegisterDevice(
 
     DriverBlock->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
 
+    if (!DriverBlock->DriverObject->MajorFunction[IRP_MJ_CREATE])
+        DriverBlock->DriverObject->MajorFunction[IRP_MJ_CREATE] = NdisICreateClose;
+
+    if (!DriverBlock->DriverObject->MajorFunction[IRP_MJ_CLOSE])
+        DriverBlock->DriverObject->MajorFunction[IRP_MJ_CLOSE] = NdisICreateClose;
+
     DeviceBlock->DeviceObject = DeviceObject;
     DeviceBlock->SymbolicName = SymbolicName;