|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
adapter.c
Author:
ervinp
Environment:
Kernel mode
Revision History:
--*/
#include <WDM.H>
#include <usbdi.h>
#include <usbdlib.h>
#include <usbioctl.h>
#include "usb8023.h"
#include "debug.h"
LIST_ENTRY allAdaptersList;
KSPIN_LOCK globalSpinLock;
#ifdef RAW_TEST
BOOLEAN rawTest = TRUE; #endif
ADAPTEREXT *NewAdapter(PDEVICE_OBJECT pdo) { ADAPTEREXT *adapter;
adapter = AllocPool(sizeof(ADAPTEREXT)); if (adapter){
adapter->sig = DRIVER_SIG;
adapter->nextDevObj = pdo; adapter->physDevObj = pdo;
InitializeListHead(&adapter->adaptersListEntry); KeInitializeSpinLock(&adapter->adapterSpinLock);
InitializeListHead(&adapter->usbFreePacketPool); InitializeListHead(&adapter->usbPendingReadPackets); InitializeListHead(&adapter->usbPendingWritePackets); InitializeListHead(&adapter->usbCompletedReadPackets);
adapter->initialized = FALSE; adapter->halting = FALSE; adapter->gotPacketFilterIndication = FALSE; adapter->readReentrancyCount = 0;
#ifdef RAW_TEST
adapter->rawTest = rawTest; #endif
/*
* Do all internal allocations. * If any of them fail, FreeAdapter will free the others. */ adapter->deviceDesc = AllocPool(sizeof(USB_DEVICE_DESCRIPTOR));
#if SPECIAL_WIN98SE_BUILD
adapter->ioWorkItem = MyIoAllocateWorkItem(adapter->physDevObj); #else
adapter->ioWorkItem = IoAllocateWorkItem(adapter->physDevObj); #endif
if (adapter->deviceDesc && adapter->ioWorkItem){ } else { FreeAdapter(adapter); adapter = NULL; } }
return adapter; }
VOID FreeAdapter(ADAPTEREXT *adapter) { USBPACKET *packet;
ASSERT(adapter->sig == DRIVER_SIG); adapter->sig = 0xDEADDEAD; /*
* All the read and write packets should have been returned to the free list. */ ASSERT(IsListEmpty(&adapter->usbPendingReadPackets)); ASSERT(IsListEmpty(&adapter->usbPendingWritePackets)); ASSERT(IsListEmpty(&adapter->usbCompletedReadPackets));
/*
* Free all the packets in the free list. */ while (packet = DequeueFreePacket(adapter)){ FreePacket(packet); }
/*
* FreeAdapter can be called after a failed start, * so check that each pointer was actually allocated before freeing it. */ if (adapter->deviceDesc) FreePool(adapter->deviceDesc); if (adapter->configDesc) FreePool(adapter->configDesc); if (adapter->notifyBuffer) FreePool(adapter->notifyBuffer); if (adapter->notifyIrpPtr) IoFreeIrp(adapter->notifyIrpPtr); if (adapter->notifyUrbPtr) FreePool(adapter->notifyUrbPtr); if (adapter->interfaceInfo) FreePool(adapter->interfaceInfo); if (adapter->interfaceInfoMaster) FreePool(adapter->interfaceInfoMaster);
if (adapter->ioWorkItem){ #if SPECIAL_WIN98SE_BUILD
MyIoFreeWorkItem(adapter->ioWorkItem); #else
IoFreeWorkItem(adapter->ioWorkItem); #endif
}
FreePool(adapter); }
VOID EnqueueAdapter(ADAPTEREXT *adapter) { KIRQL oldIrql;
ASSERT(adapter->sig == DRIVER_SIG);
KeAcquireSpinLock(&globalSpinLock, &oldIrql); InsertTailList(&allAdaptersList, &adapter->adaptersListEntry); KeReleaseSpinLock(&globalSpinLock, oldIrql); }
VOID DequeueAdapter(ADAPTEREXT *adapter) { KIRQL oldIrql;
ASSERT(adapter->sig == DRIVER_SIG);
KeAcquireSpinLock(&globalSpinLock, &oldIrql); ASSERT(!IsListEmpty(&allAdaptersList)); RemoveEntryList(&adapter->adaptersListEntry); InitializeListHead(&adapter->adaptersListEntry); KeReleaseSpinLock(&globalSpinLock, oldIrql); }
VOID HaltAdapter(ADAPTEREXT *adapter) { ASSERT(!adapter->halting);
adapter->halting = TRUE;
ASSERT(IsListEmpty(&adapter->usbCompletedReadPackets));
CancelAllPendingPackets(adapter);
adapter->initialized = FALSE; }
VOID QueueAdapterWorkItem(ADAPTEREXT *adapter) { BOOLEAN queueNow; KIRQL oldIrql; BOOLEAN useTimer;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql); if (adapter->workItemOrTimerPending || adapter->halting || adapter->resetting){ queueNow = FALSE; } else { adapter->workItemOrTimerPending = queueNow = TRUE; useTimer = (adapter->numConsecutiveReadFailures >= 8); } KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
if (queueNow){
KeInitializeEvent(&adapter->workItemOrTimerEvent, NotificationEvent, FALSE);
if (useTimer){ /*
* If we're experiencing a large number of read failures, * then possibly the hardware needs more time to recover * than allowed by the workItem delay. * This happens specifically on a surprise remove: the reads * start failing, and the flurry of workItems hold off the * actual remove forever. * So in this case, we use a long timer instead of a workItem * in order to allow a large gap before the next attempted read. */ LARGE_INTEGER timerPeriod; const ULONG numSeconds = 10;
DBGWARN(("Large number of READ FAILURES (%d), scheduling %d-second backoff timer ...", adapter->numConsecutiveReadFailures, numSeconds));
/*
* Set the timer for 10 seconds (in negative 100 nsec units). */ timerPeriod.HighPart = -1; timerPeriod.LowPart = numSeconds * -10000000; KeInitializeTimer(&adapter->backoffTimer); KeInitializeDpc(&adapter->backoffTimerDPC, BackoffTimerDpc, adapter); KeSetTimer(&adapter->backoffTimer, timerPeriod, &adapter->backoffTimerDPC); } else {
#if SPECIAL_WIN98SE_BUILD
MyIoQueueWorkItem( adapter->ioWorkItem, AdapterWorkItemCallback, DelayedWorkQueue, adapter); #else
IoQueueWorkItem( adapter->ioWorkItem, AdapterWorkItemCallback, DelayedWorkQueue, adapter); #endif
} } }
VOID AdapterWorkItemCallback(IN PDEVICE_OBJECT devObj, IN PVOID context) { ADAPTEREXT *adapter = (ADAPTEREXT *)context; ASSERT(adapter->sig == DRIVER_SIG); ASSERT(adapter->physDevObj == devObj);
ProcessWorkItemOrTimerCallback(adapter); }
VOID BackoffTimerDpc( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ) { ADAPTEREXT *adapter = (ADAPTEREXT *)DeferredContext; ASSERT(adapter->sig == DRIVER_SIG);
DBGWARN((" ... Backoff timer CALLBACK: (halting=%d, readDeficit=%d)", adapter->halting, adapter->readDeficit)); ProcessWorkItemOrTimerCallback(adapter); }
VOID ProcessWorkItemOrTimerCallback(ADAPTEREXT *adapter) { BOOLEAN stillHaveReadDeficit; KIRQL oldIrql; if (adapter->initialized && !adapter->halting){ /*
* Attempt to service any read deficit. * If read packets are still not available, then this * will NOT queue another workItem in TryReadUSB * because adapter->workItemOrTimerPending is STILL SET. */ ServiceReadDeficit(adapter);
#if DO_FULL_RESET
if (adapter->needFullReset){ /*
* We can only do a full reset if we are not at DPC level, * so skip it if we are called from the timer DPC. */ if (KeGetCurrentIrql() <= APC_LEVEL){ AdapterFullResetAndRestore(adapter); } } #endif
}
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql); ASSERT(adapter->workItemOrTimerPending); adapter->workItemOrTimerPending = FALSE; KeSetEvent(&adapter->workItemOrTimerEvent, 0, FALSE); stillHaveReadDeficit = (adapter->readDeficit > 0); KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
/*
* If we were not able to service the entire read deficit, * (e.g. because no free packets have become available) * then schedule another workItem so that we try again later. */ if (stillHaveReadDeficit && !adapter->halting){ QueueAdapterWorkItem(adapter); }
}
|