summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/ndis40/miniport.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/ndis40/miniport.c3180
1 files changed, 3180 insertions, 0 deletions
diff --git a/private/ntos/ndis/ndis40/miniport.c b/private/ntos/ndis/ndis40/miniport.c
new file mode 100644
index 000000000..859c55be1
--- /dev/null
+++ b/private/ntos/ndis/ndis40/miniport.c
@@ -0,0 +1,3180 @@
+/*++
+
+Copyright (c) 1990-1995 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ NDIS miniport wrapper functions
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 05-Oct-93
+ Jameel Hyder (JameelH) Re-organization 01-Jun-95
+
+Environment:
+
+ Kernel mode, FSD
+
+Revision History:
+
+--*/
+
+#include <precomp.h>
+#pragma hdrstop
+
+
+//
+// Define the module number for debug code.
+//
+#define MODULE_NUMBER MODULE_MINIPORT
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORK-ITEM CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+BOOLEAN
+NdisIMSwitchToMiniport(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ OUT PNDIS_HANDLE SwitchHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine will attempt to synchronously grab the miniport's (specified
+ by MiniportAdapterHandle) spin-lock and local lock. If it succeeds
+ it will return TRUE, otherwise it will return FALSE.
+
+Arguments:
+
+ MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
+ context we should nail down.
+ SwitchHandle - Pointer to storage for the current irql.
+ This is returned to the caller as a handle,
+ need-to-know basis baby.
+
+Return Value:
+
+ TRUE if we obtain both locks, FALSE otherwise.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ BOOLEAN LocalLock;
+ LONG Thread;
+
+ //
+ // Did we already acuqire the lock with this thread?
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
+ if (CURRENT_THREAD == Thread)
+ {
+ //
+ // We've already acquired the lock...
+ //
+ ASSERT(Miniport->LockAcquired);
+
+ *SwitchHandle = (NDIS_HANDLE)-1;
+
+ return(TRUE);
+ }
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, (PKIRQL)SwitchHandle);
+
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (!LocalLock)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)*SwitchHandle);
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+VOID
+NdisIMRevertBack(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE SwitchHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine will undo what NdisMLockMiniport did. It will release the
+ local lock and free the spin lock.
+
+Arguments:
+
+ MiniportAdapterHandle - Pointer to the NDIS_MINIPORT_BLOCK whose
+ context we are releasing.
+ SwitchHandle - This is the original irql from the NdisMLockMiniport
+ call.
+
+Return Value:
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ //
+ // Before we unlock the miniport's context we need to pick up any
+ // stray workitems for this miniport that may have been generated by
+ // the caller.
+ //
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ if ((NDIS_HANDLE)-1 == SwitchHandle)
+ {
+ return;
+ }
+
+ UNLOCK_MINIPORT(Miniport, TRUE);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, (KIRQL)SwitchHandle);
+}
+
+NDIS_STATUS
+NdisIMQueueMiniportCallback(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN W_MINIPORT_CALLBACK CallbackRoutine,
+ IN PVOID CallbackContext
+ )
+/*++
+
+Routine Description:
+
+ This routine will attempt to acquire the specified MiniportAdapterHandle's
+ miniport lock and local lock and call the callback routine with the context
+ information. If it cannot do so then it will queue a workitem to do it
+ later.
+
+Arguments:
+
+ MiniportAdapterHandle - PNDIS_MINIPORT_BLOCK of the miniport whose
+ context we are attempting to acquire.
+ CallbackRoutine - Pointer to the routine that we are to call.
+ CallbackContext - Context information for the callback routine.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS - If we were able to do this synchronously.
+ NDIS_STATUS_PENDING - If it will be called at a later time.
+ NDIS_STATUS_FAILURE - If the work item could not be queue'd.
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ BOOLEAN LocalLock;
+ KIRQL OldIrql;
+ LONG Thread;
+ BOOLEAN LockAcquired;
+
+ //
+ // Did we already acuqire the lock with this thread?
+ //
+ Thread = InterlockedExchangeAdd(&Miniport->MiniportThread, 0);
+ if (CURRENT_THREAD == Thread)
+ {
+ //
+ // We've already acquired the lock...
+ //
+ ASSERT(Miniport->LockAcquired);
+ LockAcquired = FALSE;
+ LocalLock = TRUE;
+ }
+ else
+ {
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+ LOCK_MINIPORT(Miniport, LocalLock);
+ LockAcquired = TRUE;
+ }
+
+ if (!LocalLock)
+ {
+ NDIS_STATUS Status;
+
+ //
+ // Queue the work item to do this later.
+ //
+ Status = NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ CallbackRoutine,
+ CallbackContext);
+
+ if (LockAcquired)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ return((NDIS_STATUS_SUCCESS == Status) ? NDIS_STATUS_PENDING : NDIS_STATUS_FAILURE);
+ }
+
+ //
+ // Call the callback routine.
+ //
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+#if _SEND_PRIORITY
+ //
+ // If we are not reseting and not halting then give priority to sends
+ // at this point.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_REQUESTED) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS) &&
+ !MINIPORT_TEST_FLAG(Miniport, fMINIPORT_HALTING))
+ {
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ ndisMProcessDeferredFullDuplexPrioritySends(Miniport);
+ }
+ else
+ {
+ ndisMProcessDeferredPrioritySends(Miniport);
+ }
+ }
+ else
+#endif
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ if (LockAcquired)
+ {
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ }
+
+ return(NDIS_STATUS_SUCCESS);
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORKITEM CODE FOR INTERMEDIATE MINIPORTS
+//
+/////////////////////////////////////////////////////////////////////
+
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ Queue's the specific workitem on the work queue.
+
+ NOTE!!!!!
+
+ This routine assumes that you have the correct lock acquire to
+ touch the SingleWorkItem that you requested to be queued.
+
+ NdisWorkItemSend - SendLock
+ NdisWorkItemResetRequested - Miniport lock
+ NdisWorkItemRequest - Miniport lock
+ NdisWorkItemDpc - Miniport lock
+ NdisWorkItemHalt - Miniport lock
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of work item to queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ //
+ // If the status is not accepted then it means that there is already
+ // a workitem of this type queued and there should be a timer fired
+ // to process it.
+ //
+ if (Status != NDIS_STATUS_NOT_ACCEPTED)
+ {
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+ }
+
+#endif
+ return(Status);
+}
+
+
+NDIS_STATUS
+FASTCALL
+ndisIMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ //
+ // Since we can have any number of these work items queued we
+ // need to be sure that they all get processed.
+ //
+ NDISM_DEFER_PROCESS_DEFERRED(Miniport);
+
+#endif
+ return(Status);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// WORKITEM CODE FOR HARDWARE MINIPORTS
+//
+/////////////////////////////////////////////////////////////////////
+
+
+VOID
+FASTCALL
+ndisMDeQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ OUT PVOID *WorkItemContext1,
+ OUT PVOID *WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will dequeue a workitem of the given type and return any context
+ information that is associated with it.
+
+ NOTE:
+
+ FOR FULL-DUPLEX USAGE THE WORK LOCK MUST BE ACQUIRED BEFORE THIS ROUTINE IS CALLED !!!!
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of workitem to dequeue.
+ WorkItemContext1 - Pointer to storage space for first piece of context information.
+ WorkItemContext2 - Pointer to storage space for second piece of context information.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+ //
+ // Grab the first workitem of the given type.
+ //
+ Link = PopEntryList(&Miniport->WorkQueue[WorkItemType]);
+ if (Link != NULL)
+ {
+ //
+ // Get a pointer to the context information.
+ //
+ WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
+
+ if (WorkItemContext1 != NULL)
+ {
+ *WorkItemContext1 = WorkItem->WorkItemContext1;
+ }
+
+ if (WorkItemContext2 != NULL)
+ {
+ *WorkItemContext2 = WorkItem->WorkItemContext2;
+ }
+
+ switch (WorkItemType)
+ {
+ case NdisWorkItemMiniportCallback:
+ case NdisWorkItemTimer:
+ case NdisWorkItemPendingOpen:
+
+ ASSERT(*WorkItemContext1 != NULL);
+ PushEntryList(&Miniport->WorkItemFreeQueue, Link);
+ break;
+
+ case NdisWorkItemResetInProgress:
+
+ PushEntryList(&Miniport->SingleWorkItems[NdisWorkItemResetRequested], Link);
+ break;
+
+ case NdisWorkItemResetRequested:
+
+ WorkItem->WorkItemType = NdisWorkItemResetInProgress;
+ PushEntryList(&Miniport->WorkQueue[NdisWorkItemResetInProgress], Link);
+ break;
+
+ default:
+ PushEntryList(&Miniport->SingleWorkItems[WorkItemType], Link);
+ break;
+ }
+ }
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ NDISM_QUEUE_WORK_ITEM_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ return(Status);
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ Queue's the specific workitem on the work queue.
+
+ NOTE!!!!!
+
+ This routine assumes that you have the correct lock acquire to
+ touch the SingleWorkItem that you requested to be queued.
+
+ NdisWorkItemSend - SendLock
+ NdisWorkItemResetRequested - Miniport lock
+ NdisWorkItemRequest - Miniport lock
+ NdisWorkItemDpc - Miniport lock
+ NdisWorkItemHalt - Miniport lock
+
+Arguments:
+
+ Miniport - Pointer to the miniport block.
+ WorkItemType - Type of work item to queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+#endif
+ return(Status);
+}
+
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItem(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+
+ NDISM_QUEUE_NEW_WORK_ITEM_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+ return(Status);
+}
+
+NDIS_STATUS
+FASTCALL
+ndisMQueueNewWorkItemFullDuplex(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_WORK_ITEM_TYPE WorkItemType,
+ IN PVOID WorkItemContext1,
+ IN PVOID WorkItemContext2
+ )
+/*++
+
+Routine Description:
+
+ This routine will queue a workitem in the work queue even if there
+ are already work items queue for it.
+
+ THE WORK QUEUE LOCK MUST BE HELD WHEN CALLING THIS ROUTINE!!!!
+
+Arguments:
+
+ Miniport - Miniport block to queue the workitem to.
+ WorkItem - Workitem to place on the queue.
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+
+ NDISM_QUEUE_NEW_WORK_ITEM_FULL_DUPLEX_MACRO(
+ Miniport,
+ WorkItemType,
+ WorkItemContext1,
+ WorkItemContext2,
+ &Status);
+
+#endif
+ return(Status);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// DEFERRED PROCESSING CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplexPrioritySends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef NDIS_NT
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredFullDuplexPrioritySends\n"));
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ BOOLEAN fMoreSends;
+
+ //
+ // Process the sends.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_START_SENDS(Miniport);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
+ {
+
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredFullDuplexPrioritySends\n"));
+#endif
+}
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferredFullDuplex(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+#ifdef NDIS_NT
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredFullDuplex\n"));
+
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
+ //
+ do
+ {
+ ProcessWorkItems = FALSE;
+
+ //
+ // Is there a reset currently in progress?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
+ {
+ //
+ // The only thing that can run during a reset in progress
+ // are the timers.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Grab the timer workitem.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ QUEUE_DPC(Dpc);
+ }
+ else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // We have requests to process that set up the packet
+ // filters.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ ndisMDoRequests(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ break;
+ }
+
+ //
+ // If the adapter is halting then get out of here.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Miniport is halting\n"));
+
+ break;
+ }
+
+ //
+ // If an intermediate miniport wants a call back do it now...
+ //
+ if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
+ {
+ W_MINIPORT_CALLBACK CallbackRoutine;
+ PVOID CallbackContext;
+
+ //
+ // Get the callback routine and the context information for it.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ (PVOID *)&CallbackRoutine,
+ &CallbackContext);
+
+ //
+ // Call the intermediate drivers callback routine.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Does a deferred dpc need to run?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing DPC\n"));
+
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Is there a timer to fire?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Finish any pending opens?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
+ {
+ //
+ // Grab the pending open block.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Finish the pending open.
+ //
+ Status = ndisMFinishPendingOpen(PendingOpen);
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Did it pend again?
+ //
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemPendingOpen,
+ PendingOpen,
+ NULL);
+ }
+
+
+ //
+ // Process more work items.
+ //
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Was there a reset requested?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset requested\n"));
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // We need to release the work item lock to
+ // indicate the status to the bindings
+ // and to call down to the miniport driver.
+ //
+ Status = ndisMProcessResetRequested(Miniport,
+ &AddressingReset);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset is pending\n"));
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Do we need to run a dpc?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+ }
+
+ //
+ // The reset is still in progress so we need to stop
+ // processing workitems and wait for the completion.
+ //
+ break;
+ }
+ else
+ {
+ //
+ // Do step1 of the reset complete.
+ //
+ ndisMResetCompleteCommonStep1(Miniport,
+ Status,
+ AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ continue;
+ }
+ }
+
+ //
+ // Process any requests?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // Process the requests.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ ndisMDoRequests(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
+ {
+ BOOLEAN fMoreLoopback;
+
+ //
+ // Process the loopback packets.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ fMoreLoopback = ndisMIndicateLoopback(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ if (!fMoreLoopback)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ BOOLEAN fMoreSends;
+
+ //
+ // Process the sends.
+ //
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ NDISM_START_SENDS(Miniport);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+ } while (ProcessWorkItems);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredFullDuplex\n"));
+#endif
+}
+
+#if _SEND_PRIORITY
+
+VOID
+FASTCALL
+ndisMProcessDeferredPrioritySends(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferredPrioritySends\n"));
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ //
+ // Process the sends.
+ //
+ NDISM_START_SENDS(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if ((Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL) ||
+ (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL))
+ {
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferredPrioritySends\n"));
+}
+
+#endif
+
+VOID
+FASTCALL
+ndisMProcessDeferred(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Processes all outstanding operations.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to send to.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ NDIS_STATUS Status;
+ BOOLEAN ProcessWorkItems;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_WORK_ITEM_TYPE WorkItemType;
+ BOOLEAN AddressingReset;
+ PKDPC Dpc;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PMINIPORT_PENDING_OPEN PendingOpen;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("==>ndisMProcessDeferred\n"));
+
+ //
+ // DO NOT CHANGE THE ORDER THAT THE WORKITEMS ARE PROCESSED!!!!!
+ //
+ do
+ {
+ ProcessWorkItems = FALSE;
+
+ //
+ // Is there a reset currently in progress?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetInProgress].Next != NULL)
+ {
+ //
+ // The only thing that can run during a reset in progress
+ // are the timers.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Grab the timer workitem.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ QUEUE_DPC(Dpc);
+ }
+ else if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // We have requests to process that set up the packet
+ // filters.
+ //
+ ndisMDoRequests(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+ break;
+ }
+
+ //
+ // If the adapter is halting then get out of here.
+ //
+ if (Miniport->WorkQueue[NdisWorkItemHalt].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Miniport is halting\n"));
+
+ break;
+ }
+
+ //
+ // If an intermediate miniport wants a call back do it now...
+ //
+ if (Miniport->WorkQueue[NdisWorkItemMiniportCallback].Next != NULL)
+ {
+ W_MINIPORT_CALLBACK CallbackRoutine;
+ PVOID CallbackContext;
+
+ //
+ // Get the callback routine and the context information for it.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(
+ Miniport,
+ NdisWorkItemMiniportCallback,
+ (PVOID *)&CallbackRoutine,
+ &CallbackContext);
+
+ //
+ // Call the intermediate drivers callback routine.
+ //
+ (*CallbackRoutine)(Miniport->MiniportAdapterContext, CallbackContext);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Does a deferred dpc need to run?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing DPC\n"));
+
+ //
+ // Queue the dpc to run.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Is there a timer to fire?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemTimer].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Queuing dpc timer\n"));
+
+ //
+ // Queue the timer's dpc to fire.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemTimer, &Dpc, NULL);
+ QUEUE_DPC(Dpc);
+
+ break;
+ }
+
+ //
+ // Finish any pending opens?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemPendingOpen].Next != NULL)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemPendingOpen, &PendingOpen, NULL);
+
+ //
+ // Finish the pending open.
+ //
+ Status = ndisMFinishPendingOpen(PendingOpen);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ NDISM_QUEUE_NEW_WORK_ITEM(
+ Miniport,
+ NdisWorkItemPendingOpen,
+ PendingOpen,
+ NULL);
+ }
+
+ //
+ // Process more work items.
+ //
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Was there a reset requested?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemResetRequested].Next != NULL)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset requested\n"));
+ //
+ // We need to release the work item lock to
+ // indicate the status to the bindings
+ // and to call down to the miniport driver.
+ //
+ Status = ndisMProcessResetRequested(Miniport,
+ &AddressingReset);
+ if (NDIS_STATUS_PENDING == Status)
+ {
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Reset is pending\n"));
+ //
+ // Do we need to run a dpc?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemDpc].Next != NULL)
+ {
+ //
+ // Dequeue the dpc.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemDpc, &Dpc, NULL);
+
+ //
+ // Queue the dpc to run.
+ //
+ QUEUE_DPC(Dpc);
+ }
+
+ //
+ // The reset is still in progress so we need to stop
+ // processing workitems and wait for the completion.
+ //
+ break;
+ }
+ else
+ {
+ //
+ // Do step1 of the reset complete.
+ //
+ ndisMResetCompleteCommonStep1(Miniport,
+ Status,
+ AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+ else
+ {
+ //
+ // We MUST complete the filter requests within
+ // the reset in progress workitem. Mainly because
+ // we don't want to do any sends at this time.
+ //
+ ProcessWorkItems = TRUE;
+
+ continue;
+ }
+ }
+ }
+
+ //
+ // Process any requests?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemRequest].Next != NULL)
+ {
+ //
+ // Process the requests.
+ //
+ ndisMDoRequests(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any loopback packets to indicate?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSendLoopback].Next != NULL)
+ {
+ BOOLEAN fMoreLoopback;
+
+ //
+ // Process the loopback packets.
+ //
+ fMoreLoopback = ndisMIndicateLoopback(Miniport);
+
+ if (!fMoreLoopback)
+ {
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSendLoopback, NULL, NULL);
+ }
+
+ ProcessWorkItems = TRUE;
+ }
+
+ //
+ // Are there any sends to process?
+ //
+ if (Miniport->WorkQueue[NdisWorkItemSend].Next != NULL)
+ {
+ //
+ // Process the sends.
+ //
+ NDISM_START_SENDS(Miniport);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ ProcessWorkItems = TRUE;
+ }
+ } while (ProcessWorkItems);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PROCESS_DEFERRED);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("<==ndisMProcessDeferred\n"));
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// INDICATE CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+VOID
+NdisMIndicateStatus(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates a new status of the media/mini-port.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ GeneralStatus - The status to indicate.
+
+ StatusBuffer - Additional information.
+
+ StatusBufferSize - Length of the buffer.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ if ((GeneralStatus == NDIS_STATUS_RING_STATUS) &&
+ (StatusBufferSize == sizeof(NDIS_STATUS)))
+ {
+
+ Status = *((PNDIS_STATUS)StatusBuffer);
+
+ if (Status & (NDIS_RING_LOBE_WIRE_FAULT |
+ NDIS_RING_HARD_ERROR |
+ NDIS_RING_SIGNAL_LOSS))
+ {
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+ }
+ }
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusHandler) (
+ Open->ProtocolBindingContext,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize
+ );
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+VOID
+NdisMIndicateStatusComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.StatusCompleteHandler) (
+ Open->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+VOID
+NdisMWanIndicateReceive(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext,
+ IN PUCHAR Packet,
+ IN ULONG PacketSize
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ *Status = ((WAN_RECEIVE_HANDLER)(Open->ProtocolHandle->ProtocolCharacteristics.ReceiveHandler)) (
+ NdisLinkContext,
+ Packet,
+ PacketSize);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+
+VOID
+NdisMWanIndicateReceiveComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE NdisLinkContext
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the status is complete.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ Open = Miniport->OpenQueue;
+
+ while (Open != NULL)
+ {
+ //
+ // Call Protocol to indicate status
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ReceiveCompleteHandler)(NdisLinkContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ Open = Open->MiniportNextOpen;
+ }
+}
+
+
+
+NDIS_STATUS
+NdisQueryReceiveInformation(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacContext,
+ OUT PLONGLONG TimeSent OPTIONAL,
+ OUT PLONGLONG TimeReceived OPTIONAL,
+ IN PUCHAR Buffer,
+ IN UINT BufferSize,
+ OUT PUINT SizeNeeded
+ )
+{
+ PNDIS_OPEN_BLOCK OpenBlock = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
+ PNDIS_M_OPEN_BLOCK MOpenBlock = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(MOpenBlock->MiniportHandle);
+ PNDIS_PACKET Packet = (PNDIS_PACKET)MacContext;
+ NDIS_STATUS Status = NDIS_STATUS_NOT_SUPPORTED;
+
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
+ ("NdisQueryReceiveInformation - Miniort %lx, Packet %lx\n",
+ Miniport, Packet));
+
+ //
+ // The following tests whether this is a mac or a miniport and also if we
+ // came here via a IndicatePacket or IndicateRecieve
+ //
+ if ((MOpenBlock->FakeOpen == OpenBlock) &&
+ (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID)))
+ {
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+ *SizeNeeded = pOob->SizeMediaSpecificInfo;
+ if (BufferSize < *SizeNeeded)
+ {
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ else
+ {
+ CopyMemory(Buffer, pOob->MediaSpecificInformation, *SizeNeeded);
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ if (ARGUMENT_PRESENT(TimeSent))
+ {
+ *TimeSent = pOob->TimeSent;
+ }
+ if (ARGUMENT_PRESENT(TimeReceived))
+ {
+ *TimeReceived = pOob->TimeReceived;
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+NdisReturnPackets(
+ IN PNDIS_PACKET *PacketsToReturn,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ Decrement the refcount for the packet and return back to the miniport if 0.
+ We take the Miniport lock here and hence are protected against other receives.
+
+Arguments:
+
+ NdisBindingHandle - Handle to the open binding
+ PacketsToReturn - Pointer to the set of packets to return to the miniport
+ NumberOfPackets - self descriptive
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UINT i;
+
+ for (i = 0; i < NumberOfPackets; i++)
+ {
+ KIRQL OldIrql;
+ PNDIS_MINIPORT_BLOCK Miniport;
+ W_RETURN_PACKET_HANDLER Handler;
+ PNDIS_PACKET Packet;
+ BOOLEAN QueueWorkItem = FALSE;
+
+ Packet = PacketsToReturn[i];
+ ASSERT (Packet != NULL);
+
+ Miniport = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport;
+ ASSERT (Miniport != NULL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount == 0)
+ {
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID))
+ {
+ Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
+ (*Handler)(Miniport->MiniportAdapterContext, Packet);
+ }
+ else
+ {
+ ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket =
+ Miniport->ReturnPacketsQueue;
+ Miniport->ReturnPacketsQueue = Packet;
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED))
+ {
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
+ QueueWorkItem = TRUE;
+ }
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ if (QueueWorkItem)
+ {
+ ndisReferenceMiniport(Miniport);
+ QUEUE_WORK_ITEM(&Miniport->WorkItem, HyperCriticalWorkQueue);
+ }
+ }
+}
+
+
+VOID
+ndisMLazyReturnPackets(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+{
+ KIRQL OldIrql;
+ PNDIS_PACKET Packet, NextPacket;
+ W_RETURN_PACKET_HANDLER Handler;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ ASSERT(MINIPORT_TEST_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED));
+
+ Packet = Miniport->ReturnPacketsQueue;
+ Miniport->ReturnPacketsQueue = NULL;
+
+ for (NOTHING;
+ Packet != NULL;
+ Packet = NextPacket)
+ {
+ NextPacket = PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->NextPacket;
+ Handler = Miniport->DriverHandle->MiniportCharacteristics.ReturnPacketHandler;
+ (*Handler)(Miniport->MiniportAdapterContext, Packet);
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RP_WORK_ITEM_QUEUED);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ ndisDereferenceMiniport(Miniport);
+}
+
+
+VOID
+ndisMIndicatePacket(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by the Miniport to indicate packets to
+ all bindings. This is the code path for ndis 4.0 miniport drivers.
+
+Arguments:
+
+ Miniport - The Miniport block.
+
+ PacketArray - An array of Packets indicated by the miniport. Each packet consists of a
+ single buffer.
+
+ NumberOfPackets - Self-explanatory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The private structure to indicate up with
+ //
+ PPNDIS_PACKET pPktArray = PacketArray;
+
+ //
+ // Pointer to the buffer in the ndispacket
+ //
+ PNDIS_BUFFER Buffer;
+
+ //
+ // Pointer to the 1st segment of the buffer, points to dest address
+ //
+ PUCHAR Address;
+
+ //
+ // Total packet length
+ //
+ UINT i, LASize,PacketSize, NumIndicates = 0;
+
+ //
+ // Decides whether we use the protocol's revpkt handler or fall
+ // back to old rcvindicate handler
+ //
+ BOOLEAN fFallBack, FixRef;
+
+ //
+ // The current open block
+ //
+ PNDIS_M_OPEN_BLOCK pOpenBlock, NextOpen;
+
+ NDIS_STATUS StatusOfReceive;
+
+ //
+ // Define a NULL Fiter structure so that the IndicateToProtocol macro can be used.
+ //
+ struct _NullFilter
+ {
+ PNDIS_SPIN_LOCK Lock;
+ } Filter;
+
+ Filter.Lock = &Miniport->Lock;
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+
+ // Walk all the packets
+ for (i = 0; i < NumberOfPackets; i++, pPktArray++)
+ {
+ PNDIS_PACKET Packet = *pPktArray;
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ ASSERT(Packet != NULL);
+ pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
+
+ NdisGetFirstBufferFromPacket(Packet,
+ &Buffer,
+ &Address,
+ &LASize,
+ &PacketSize);
+ ASSERT(Buffer != NULL);
+
+ //
+ // Set the status here that nobody is holding the packet. This will get
+ // overwritten by the real status from the protocol. Pay heed to what
+ // the miniport is saying.
+ //
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
+
+ if (pOob->Status != NDIS_STATUS_RESOURCES)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount --;
+ pOob->Status = NDIS_STATUS_SUCCESS;
+ fFallBack = FALSE;
+ FixRef = TRUE;
+ }
+ else
+ {
+ FixRef = FALSE;
+ fFallBack = TRUE;
+ }
+
+ //
+ // Ensure that we force re-calculation.
+ //
+ Packet->Private.ValidCounts = FALSE;
+
+ for (pOpenBlock = Miniport->OpenQueue;
+ pOpenBlock != NULL;
+ pOpenBlock = NextOpen)
+ {
+ //
+ // Get the next open to look at.
+ //
+ NextOpen = pOpenBlock->MiniportNextOpen;
+ pOpenBlock->ReceivedAPacket = TRUE;
+ pOpenBlock->References++;
+ NumIndicates ++;
+
+ IndicateToProtocol(Miniport,
+ &Filter,
+ pOpenBlock->FakeOpen,
+ Packet,
+ Address,
+ PacketSize,
+ pOob->HeaderSize,
+ &fFallBack,
+ FALSE,
+ NdisMediumMax); // A dummy medium since it is unknown
+
+ pOpenBlock->References--;
+ if (pOpenBlock->References == 0)
+ {
+ // Anything to do here ?
+ }
+ }
+
+ if (FixRef)
+ {
+ PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount++;
+ if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
+ {
+ NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
+ }
+ }
+ }
+
+ if (NumIndicates > 0)
+ {
+ for (pOpenBlock = Miniport->OpenQueue;
+ pOpenBlock != NULL;
+ pOpenBlock = NextOpen)
+ {
+ if (pOpenBlock->ReceiveCompleteHandler)
+ {
+ pOpenBlock->References++;
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (*pOpenBlock->ReceiveCompleteHandler)(pOpenBlock->ProtocolBindingContext);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ if ((--(pOpenBlock->References)) == 0)
+ {
+ // Anything to do here ?
+ }
+ }
+ }
+ }
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// TRANSFER DATA CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+VOID
+NdisMTransferDataComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a transfer data request.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Packet - The packet the data was copied into.
+
+ Status - Status of the operation.
+
+ BytesTransferred - Total number of bytes transferred.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET PrevPacket;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT(Miniport->FirstTDPacket != NULL);
+
+ //
+ // Find the packet
+ //
+
+ if (Packet == Miniport->FirstTDPacket)
+ {
+ Miniport->FirstTDPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+ }
+ else
+ {
+ PrevPacket = Miniport->FirstTDPacket;
+
+ while (PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next != Packet)
+ {
+ PrevPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next;
+
+ ASSERT(PrevPacket != NULL);
+ }
+
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevPacket)->Next =
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ if (Packet == Miniport->LastTDPacket)
+ {
+ Miniport->LastTDPacket = PrevPacket;
+ }
+ }
+
+ //
+ // Indicate to Protocol;
+ //
+
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.TransferDataCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ Status,
+ BytesTransferred);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+}
+
+NDIS_STATUS
+ndisMTransferDataSync(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_PACKET_OOB_DATA pOob;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+ ASSERT((Miniport->MacOptions & NDIS_MAC_OPTION_TRANSFERS_NOT_PEND) != 0);
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL)
+ {
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Call Miniport.
+ //
+
+ Status = (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer);
+ //
+ // This miniport better not pend this send.
+ //
+
+ ASSERT(Status != NDIS_STATUS_PENDING);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ if (*BytesTransferred == BytesToTransfer)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+
+NDIS_STATUS
+ndisMTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_PACKET_RESERVED Reserved = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet);
+ PNDIS_PACKET_OOB_DATA pOob;
+ PNDIS_PACKET PrevLast;
+ NDIS_STATUS Status;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Handle non-loopback as the default case.
+ //
+
+ if (Miniport->LoopbackPacket == NULL)
+ {
+ Reserved->Next = NULL;
+ Reserved->Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
+
+ //
+ // Put this guy on the transfer data queue.
+ //
+
+ PrevLast = Miniport->LastTDPacket;
+
+ if (Miniport->FirstTDPacket == NULL)
+ {
+ Miniport->FirstTDPacket = Packet;
+ }
+ else
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(Miniport->LastTDPacket)->Next = Packet;
+ }
+
+ Miniport->LastTDPacket = Packet;
+
+ //
+ // Call Miniport
+ //
+
+ Status = (Reserved->Open->TransferDataHandler)(
+ Packet,
+ BytesTransferred,
+ Reserved->Open->MiniportAdapterContext,
+ MacReceiveContext,
+ ByteOffset,
+ BytesToTransfer);
+
+ //
+ // If it didn't pend then we won't get a transfer data complte call
+ // so we need to remove this guy now.
+ //
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ //
+ // Remove from queue
+ //
+
+ if (Miniport->FirstTDPacket != Packet)
+ {
+ PNDIS_RESERVED_FROM_PNDIS_PACKET(PrevLast)->Next = NULL;
+ Miniport->LastTDPacket = PrevLast;
+ }
+ else
+ {
+ Miniport->FirstTDPacket = NULL;
+ Miniport->LastTDPacket = NULL;
+ }
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ return Status;
+ }
+
+ //
+ // This packet is a loopback packet!
+ //
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ Miniport->LoopbackPacket,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ if (*BytesTransferred == BytesToTransfer)
+ {
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ return NDIS_STATUS_FAILURE;
+}
+
+NDIS_STATUS
+ndisMDummyTransferData(
+ IN NDIS_HANDLE NdisBindingHandle,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer,
+ IN OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred
+ )
+{
+ PNDIS_PACKET_OOB_DATA pOob;
+
+ pOob = NDIS_OOB_DATA_FROM_PACKET((PNDIS_PACKET)MacReceiveContext);
+ NdisCopyFromPacketToPacket(Packet,
+ 0,
+ BytesToTransfer,
+ (PNDIS_PACKET)MacReceiveContext,
+ ByteOffset + pOob->HeaderSize,
+ BytesTransferred);
+
+ return ((*BytesTransferred == BytesToTransfer) ?
+ NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
+}
+
+
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// RESET CODE
+//
+/////////////////////////////////////////////////////////////////////
+
+VOID
+ndisMAbortPacketsAndRequests(
+ PNDIS_MINIPORT_BLOCK Miniport
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts all outstanding requests on a mini-port.
+
+ CALLED WITH THE LOCK HELD!!
+
+Arguments:
+
+ Miniport - Miniport to abort.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNDIS_PACKET Packet;
+ PNDIS_PACKET NextPacket;
+ PNDIS_REQUEST MiniportRequest;
+ PNDIS_REQUEST PendingRequest;
+ PNDIS_REQUEST NextRequest;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_PACKET ArcnetLimitPacket;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ BOOLEAN fRestoreDeferredState = FALSE;
+ PSINGLE_LIST_ENTRY Link;
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Enter abort packets and requests\n"));
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+
+ //
+ // Dequeue any send workitems and acquire the send spin lock
+ // if we are full duplex..
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Since we are full duplex we need to wrap the dequeue operation
+ // with spin lock acquire and release.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Acquire the spin lock.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // non-full duplex miniports can just dequeue any send work items
+ // that are queued
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemSend, NULL, NULL);
+ }
+
+ //
+ // Clear out the packet queues.
+ //
+ Packet = Miniport->FirstPacket;
+ ArcnetLimitPacket = Miniport->FirstPendingPacket;
+
+ Miniport->LastMiniportPacket = NULL;
+ Miniport->FirstPendingPacket = NULL;
+ Miniport->FirstPacket = NULL;
+ Miniport->LastPacket = NULL;
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'a');
+
+ //
+ // Go through the list of packets an return them to the
+ // bindings
+ //
+ while (Packet != NULL)
+ {
+ //
+ // Get a pointer to the next packet before we kill
+ // the current one.
+ //
+ NextPacket = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Next;
+
+ //
+ // Get the open that the packet came from.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_PACKET(Packet)->Open;
+
+ //
+ // Set flag that we've reached the packets that are
+ // not on the mini-port.
+ //
+
+ if (Packet == ArcnetLimitPacket)
+ {
+ ArcnetLimitPacket = NULL;
+ }
+
+ //
+ // Now free the arcnet header.
+ //
+
+ if (Miniport->MediaType == NdisMediumArcnet878_2 && ArcnetLimitPacket)
+ {
+ ndisMFreeArcnetHeader(Miniport, Packet);
+ }
+
+ NDISM_LOG_PACKET(Miniport, Packet, NULL, 'C');
+
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.SendCompleteHandler) (
+ Open->ProtocolBindingContext,
+ Packet,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Re-acquire the send lock if we are full duplex.
+ // Note that the wrapper does NOT keep track of open
+ // references with regard to sends for full duplex miniports.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+
+ //
+ // Get the next packet.
+ //
+ Packet = NextPacket;
+ }
+
+ NDISM_LOG_PACKET(Miniport, NULL, NULL, 'A');
+
+ Miniport->SendResourcesAvailable = 0x00ffffff;
+
+ //
+ // Dequeue any request workitems.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Release the send lock.
+ //
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Since we are full duplex we need to wrap the dequeue operation
+ // with spin lock acquire and release.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ }
+ else
+ {
+ //
+ // non-full duplex miniports can just dequeue any send work items
+ // that are queued
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemRequest, NULL, NULL);
+ }
+
+
+ //
+ // Clear the request timeout flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUEST_TIMEOUT);
+
+ //
+ // We need to clear out the pending request queue before the currently in
+ // progress one so that when we complete the in-progress request we
+ // won't think that we have to process more requests.
+ //
+ PendingRequest = Miniport->PendingRequest;
+ Miniport->PendingRequest = NULL;
+
+ MiniportRequest = Miniport->MiniportRequest;
+
+ //
+ // If there is one then abort it.
+ //
+ if (MiniportRequest != NULL)
+ {
+ //
+ // Get a pointer to the open that the request came from.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(MiniportRequest)->Open;
+
+ //
+ // Was this a statistics request?
+ //
+ if ((Open != NULL) &&
+ (MiniportRequest->RequestType == NdisRequestQueryStatistics))
+ {
+ ndisMAbortQueryStatisticsRequest(MiniportRequest,
+ NDIS_STATUS_REQUEST_ABORTED);
+
+ Miniport->MiniportRequest = NULL;
+ }
+ else
+ {
+ if (MiniportRequest->RequestType == NdisRequestSetInformation)
+ {
+ ndisMSyncSetInformationComplete((NDIS_HANDLE)Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ ndisMSyncQueryInformationComplete((NDIS_HANDLE)Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ }
+ }
+
+ //
+ // Go through the pending request queue and clear it out.
+ //
+ while (PendingRequest != NULL)
+ {
+ //
+ // Get a pointer to the next request before we kill the
+ // current one.
+ //
+ NextRequest = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Next;
+
+ //
+ // Get a pointer to the open that the request belongs to.
+ //
+ Open = PNDIS_RESERVED_FROM_PNDIS_REQUEST(PendingRequest)->Open;
+
+ if (PendingRequest->RequestType == NdisRequestQueryStatistics)
+ {
+ ndisMAbortQueryStatisticsRequest(
+ PendingRequest,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ //
+ // Make this request the request in progress.
+ //
+ Miniport->MiniportRequest = PendingRequest;
+
+ if (PendingRequest->RequestType == NdisRequestSetInformation)
+ {
+ ndisMSyncSetInformationComplete(Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ else
+ {
+ ndisMSyncQueryInformationComplete(Miniport,
+ NDIS_STATUS_REQUEST_ABORTED);
+ }
+ }
+
+ //
+ // Get the next request.
+ //
+ PendingRequest = NextRequest;
+ }
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Exit abort packets and requests\n"));
+}
+
+VOID
+ndisMResetCompleteCommonStep2(
+ IN PNDIS_MINIPORT_BLOCK Miniport
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PSINGLE_LIST_ENTRY Link;
+ PNDIS_M_OPEN_BLOCK Open;
+ PNDIS_M_OPEN_BLOCK tmpOpen;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+
+
+ //
+ // Dequeue the reset in progress work item.
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // Acquire the work lock and dequeue the reset in progress work item.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // Grab the send lock so that we can clear the reset in progress flag.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ for (tmpOpen = Miniport->OpenQueue;
+ tmpOpen != NULL;
+ tmpOpen = tmpOpen->MiniportNextOpen)
+ {
+ //
+ // Restore the send handler
+ //
+ tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
+
+ //
+ // Restore the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplex;
+ }
+ else
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsFullDuplexToSend;
+ }
+ }
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // For non full duplex miniports we don't need to acquire the work lock.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetInProgress, &Open, NULL);
+
+ //
+ // Clear the reset in progress flag.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ for (tmpOpen = Miniport->OpenQueue;
+ tmpOpen != NULL;
+ tmpOpen = tmpOpen->MiniportNextOpen)
+ {
+ //
+ // Restore the send handler
+ //
+ tmpOpen->FakeOpen->SendHandler = Miniport->FakeMac->MacCharacteristics.SendHandler;
+
+ //
+ // Restore the send packets handler.
+ //
+ if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPackets;
+ }
+ else
+ {
+ tmpOpen->FakeOpen->SendPacketsHandler = ndisMSendPacketsToSend;
+ }
+ }
+ }
+
+ ASSERT(Open != NULL);
+
+ //
+ // Indicate to Protocols the reset is complete
+ //
+ NdisMIndicateStatus(Miniport,
+ NDIS_STATUS_RESET_END,
+ &Miniport->ResetStatus,
+ sizeof(Miniport->ResetStatus));
+
+ NdisMIndicateStatusComplete(Miniport);
+
+ //
+ // If a protocol initiated the reset then notify it of the
+ // completion.
+ //
+ if (Open != (PNDIS_M_OPEN_BLOCK)Miniport)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ (Open->ProtocolHandle->ProtocolCharacteristics.ResetCompleteHandler)(
+ Open->ProtocolBindingContext,
+ Miniport->ResetStatus);
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("- Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ Open->References--;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("==0 Open 0x%x Reference 0x%x\n", Open, Open->References));
+
+ if (Open->References == 0)
+ {
+ ndisMFinishClose(Miniport,Open);
+ }
+ }
+}
+
+VOID
+ndisMResetCompleteCommonStep1(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ //
+ // Destroy all outstanding packets and requests.
+ //
+ ndisMAbortPacketsAndRequests(Miniport);
+
+ //
+ // Check if we are going to have to reset the
+ // adapter again. This happens when we are doing
+ // the reset because of a ring failure.
+ //
+ if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IGNORE_TOKEN_RING_ERRORS))
+ {
+ if (Miniport->TrResetRing == 1)
+ {
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Miniport->TrResetRing = 0;
+ }
+ else
+ {
+ Miniport->TrResetRing = NDIS_MINIPORT_TR_RESET_TIMEOUT;
+ }
+ }
+ }
+
+ //
+ // If we need to reset the miniports filter settings then
+ // queue the necessary requests & work items.
+ //
+ if (AddressingReset &&
+ (Status == NDIS_STATUS_SUCCESS) &&
+ ((Miniport->EthDB != NULL) || (Miniport->TrDB != NULL) ||
+ (Miniport->FddiDB != NULL) || (Miniport->ArcDB != NULL)))
+ {
+ ndisMRestoreFilterSettings(Miniport, NULL);
+ }
+
+ //
+ // Save the reset status as it is now.
+ //
+ Miniport->ResetStatus = Status;
+}
+
+
+NDIS_STATUS
+ndisMProcessResetRequested(
+ IN PNDIS_MINIPORT_BLOCK Miniport,
+ OUT PBOOLEAN pAddressingReset
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status;
+ PNDIS_M_OPEN_BLOCK Open;
+
+ //
+ //
+ if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
+ {
+ //
+ // We need to acquire the work lock to dequeue the reset requsted work item.
+ //
+ ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
+
+ RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
+
+ //
+ // We need to acquire the send lock to modify the reset requested and
+ // reset in progress flags.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Set the reset in progress bit so that the send path can see it.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ //
+ // Replace the send handler for the open's
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
+ }
+ else
+ {
+ Open->FakeOpen->SendHandler = ndisMResetSend;
+ }
+
+ Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
+ }
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+ }
+ else
+ {
+ //
+ // Dequeue the reset requested work item. this dequeuing will automatically
+ // queue the reset in progress work item.
+ //
+ NDISM_DEQUEUE_WORK_ITEM(Miniport, NdisWorkItemResetRequested, NULL, NULL);
+
+ //
+ // Set the reset in progress bit so that the send path can see it.
+ //
+ MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_IN_PROGRESS);
+
+ //
+ // Replace the send handler for the open's
+ //
+ for (Open = Miniport->OpenQueue;
+ Open != NULL;
+ Open = Open->MiniportNextOpen)
+ {
+ if (NdisMediumWan == Miniport->MediaType)
+ {
+ Open->FakeOpen->SendHandler = (PVOID)ndisMResetWanSend;
+ }
+ else
+ {
+ Open->FakeOpen->SendHandler = ndisMResetSend;
+ }
+
+ Open->FakeOpen->SendPacketsHandler = ndisMResetSendPackets;
+ }
+ }
+
+
+ //
+ // Indicate the reset status to the protocols.
+ //
+ NdisMIndicateStatus(Miniport, NDIS_STATUS_RESET_START, NULL, 0);
+ NdisMIndicateStatusComplete(Miniport);
+
+ DBGPRINT(DBG_COMP_WORK_ITEM, DBG_LEVEL_INFO,
+ ("Calling miniport reset\n"));
+ //
+ // Call the miniport's reset handler.
+ //
+ Status = (Miniport->DriverHandle->MiniportCharacteristics.ResetHandler)(
+ pAddressingReset,
+ Miniport->MiniportAdapterContext);
+
+ return(Status);
+}
+
+
+VOID
+ndisMResetCompleteFullDuplex(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+{
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Enter reset complete\n"));
+
+ //
+ // Code that is common for synchronous and async resets.
+ //
+ ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Exit reset complete\n"));
+#endif
+}
+
+VOID
+NdisMResetComplete(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_STATUS Status,
+ IN BOOLEAN AddressingReset
+ )
+/*++
+
+Routine Description:
+
+ This function indicates the completion of a reset.
+
+Arguments:
+
+ MiniportAdapterHandle - points to the adapter block.
+
+ Status - Status of the reset.
+
+ AddressingReset - Do we have to submit a request to reload the address
+ information. This includes packet filter, and multicast/functional addresses.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
+
+ ASSERT(MINIPORT_AT_DPC_LEVEL);
+ ASSERT(MINIPORT_LOCK_ACQUIRED(Miniport));
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Enter reset complete\n"));
+
+ //
+ // Code that is common for synchronous and async resets.
+ //
+ ndisMResetCompleteCommonStep1(Miniport, Status, AddressingReset);
+ if (!AddressingReset || (Status != NDIS_STATUS_SUCCESS))
+ {
+ //
+ // If there is no addressing reset to be done or
+ // the reset failed in some way then we tell the
+ // bindings now.
+ //
+ ndisMResetCompleteCommonStep2(Miniport);
+ }
+
+ DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
+ ("Exit reset complete\n"));
+}
+
+NDIS_STATUS
+ndisMResetFullDuplex(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+#ifdef NDIS_NT
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Is there already a reset in progress?
+ //
+ Status = NDISM_QUEUE_WORK_ITEM(Miniport,
+ NdisWorkItemResetRequested,
+ NdisBindingHandle,
+ NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Update the open's references.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle,
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // The reset requested flag is used by both the send path and the
+ // dpc path.
+ //
+ NDIS_ACQUIRE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+
+ NDIS_RELEASE_SEND_SPIN_LOCK_DPC(Miniport);
+
+ //
+ // Grab the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+#endif
+ return(NDIS_STATUS_PENDING);
+}
+
+NDIS_STATUS
+ndisMReset(
+ IN NDIS_HANDLE NdisBindingHandle
+ )
+{
+ PNDIS_MINIPORT_BLOCK Miniport = ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->MiniportHandle;
+ PNDIS_MINIPORT_WORK_ITEM WorkItem;
+ KIRQL OldIrql;
+ BOOLEAN LocalLock;
+ PSINGLE_LIST_ENTRY Link;
+ NDIS_STATUS Status;
+
+ NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
+
+ //
+ // Is there already a reset in progress?
+ //
+ Status = NDISM_QUEUE_WORK_ITEM(Miniport,
+ NdisWorkItemResetRequested,
+ NdisBindingHandle,
+ NULL);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+ return(NDIS_STATUS_RESET_IN_PROGRESS);
+ }
+
+ //
+ // Update the open's references.
+ //
+ ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References++;
+
+ DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
+ ("+ Open 0x%x Reference 0x%x\n", NdisBindingHandle, ((PNDIS_M_OPEN_BLOCK)NdisBindingHandle)->References));
+
+ //
+ // Set the reset requested flag.
+ //
+ MINIPORT_SET_FLAG(Miniport, fMINIPORT_RESET_REQUESTED);
+
+ //
+ // Grab the local lock.
+ //
+ LOCK_MINIPORT(Miniport, LocalLock);
+ if (LocalLock)
+ {
+ //
+ // If we did not lock down the mini-port, then some other routine will
+ // do this processing for us. Otherwise we need to do this processing.
+ //
+ NDISM_PROCESS_DEFERRED(Miniport);
+ }
+
+ UNLOCK_MINIPORT(Miniport, LocalLock);
+
+ NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
+
+ return(NDIS_STATUS_PENDING);
+}
+
+