|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
packet.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"
ULONG uniquePacketId = 0;
USBPACKET *NewPacket(ADAPTEREXT *adapter) { USBPACKET *packet = AllocPool(sizeof(USBPACKET)); if (packet){ BOOLEAN allAllocsOk;
packet->sig = DRIVER_SIG; packet->adapter = adapter; packet->cancelled = FALSE;
InitializeListHead(&packet->listEntry);
packet->irpPtr = IoAllocateIrp(adapter->nextDevObj->StackSize, FALSE); packet->urbPtr = AllocPool(sizeof(URB));
packet->dataBuffer = AllocPool(PACKET_BUFFER_SIZE); packet->dataBufferMaxLength = PACKET_BUFFER_SIZE; if (packet->dataBuffer){ packet->dataBufferMdl = IoAllocateMdl(packet->dataBuffer, PACKET_BUFFER_SIZE, FALSE, FALSE, NULL); }
packet->dataBufferCurrentLength = 0;
allAllocsOk = (packet->irpPtr && packet->urbPtr && packet->dataBuffer && packet->dataBufferMdl);
if (allAllocsOk){ packet->packetId = ++uniquePacketId; } else {
if (packet->irpPtr) IoFreeIrp(packet->irpPtr); if (packet->urbPtr) FreePool(packet->urbPtr); if (packet->dataBuffer) FreePool(packet->dataBuffer); if (packet->dataBufferMdl) IoFreeMdl(packet->dataBufferMdl);
FreePool(packet); packet = NULL; } }
return packet; }
VOID FreePacket(USBPACKET *packet) { PIRP irp = packet->irpPtr;
ASSERT(packet->sig == DRIVER_SIG); packet->sig = 0xDEADDEAD;
ASSERT(!irp->CancelRoutine); IoFreeIrp(irp);
FreePool(packet->urbPtr);
ASSERT(packet->dataBufferMdl); IoFreeMdl(packet->dataBufferMdl);
ASSERT(packet->dataBuffer); FreePool(packet->dataBuffer);
FreePool(packet); }
VOID EnqueueFreePacket(USBPACKET *packet) { ADAPTEREXT *adapter = packet->adapter; KIRQL oldIrql;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
ASSERT(IsListEmpty(&packet->listEntry)); InsertTailList(&adapter->usbFreePacketPool, &packet->listEntry);
adapter->numFreePackets++; ASSERT(adapter->numFreePackets <= USB_PACKET_POOL_SIZE);
#if DBG
packet->timeStamp = DbgGetSystemTime_msec();
if (adapter->dbgInLowPacketStress){ if (adapter->numFreePackets > USB_PACKET_POOL_SIZE/2){ adapter->dbgInLowPacketStress = FALSE; DBGWARN(("recovered from low-packet stress")); } } #endif
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); }
USBPACKET *DequeueFreePacket(ADAPTEREXT *adapter) { USBPACKET *packet; KIRQL oldIrql;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
if (IsListEmpty(&adapter->usbFreePacketPool)){ packet = NULL; } else { PLIST_ENTRY listEntry = RemoveHeadList(&adapter->usbFreePacketPool); packet = CONTAINING_RECORD(listEntry, USBPACKET, listEntry); ASSERT(packet->sig == DRIVER_SIG); InitializeListHead(&packet->listEntry);
ASSERT(adapter->numFreePackets > 0); adapter->numFreePackets--; }
#if DBG
if (adapter->numFreePackets < USB_PACKET_POOL_SIZE/8){ if (!adapter->dbgInLowPacketStress){ /*
* We are entering low-packet stress. * Repeated debug spew can slow the system and actually * keep the system from recovering the packets. * So only spew a warning once. */ DBGWARN(("low on free packets (%d free, %d reads, %d writes, %d indicated)", adapter->numFreePackets, adapter->numActiveReadPackets, adapter->numActiveWritePackets, adapter->numIndicatedReadPackets)); adapter->dbgInLowPacketStress = TRUE; } } #endif
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
return packet; }
VOID EnqueuePendingReadPacket(USBPACKET *packet) { ADAPTEREXT *adapter = packet->adapter; KIRQL oldIrql;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
ASSERT(IsListEmpty(&packet->listEntry)); InsertTailList(&adapter->usbPendingReadPackets, &packet->listEntry);
#if DBG
packet->timeStamp = DbgGetSystemTime_msec(); #endif
adapter->numActiveReadPackets++;
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); }
/*
* DequeuePendingReadPacket * */ VOID DequeuePendingReadPacket(USBPACKET *packet) { ADAPTEREXT *adapter = packet->adapter; KIRQL oldIrql;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
ASSERT(!IsListEmpty(&adapter->usbPendingReadPackets)); ASSERT(!IsListEmpty(&packet->listEntry));
RemoveEntryList(&packet->listEntry); ASSERT(packet->sig == DRIVER_SIG); InitializeListHead(&packet->listEntry);
ASSERT(adapter->numActiveReadPackets > 0); adapter->numActiveReadPackets--;
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); }
VOID EnqueuePendingWritePacket(USBPACKET *packet) { ADAPTEREXT *adapter = packet->adapter; KIRQL oldIrql;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
ASSERT(IsListEmpty(&packet->listEntry)); InsertTailList(&adapter->usbPendingWritePackets, &packet->listEntry);
adapter->numActiveWritePackets++; ASSERT(adapter->numActiveWritePackets <= USB_PACKET_POOL_SIZE);
#if DBG
packet->timeStamp = DbgGetSystemTime_msec(); #endif
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); }
/*
* DequeuePendingWritePacket * * Return either the indicated packet or the first packet in the pending queue. */ VOID DequeuePendingWritePacket(USBPACKET *packet) { ADAPTEREXT *adapter = packet->adapter; KIRQL oldIrql;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
ASSERT(!IsListEmpty(&adapter->usbPendingWritePackets)); ASSERT(!IsListEmpty(&packet->listEntry));
RemoveEntryList(&packet->listEntry);
ASSERT(adapter->numActiveWritePackets > 0); adapter->numActiveWritePackets--;
ASSERT(packet->sig == DRIVER_SIG); InitializeListHead(&packet->listEntry);
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); }
VOID EnqueueCompletedReadPacket(USBPACKET *packet) { ADAPTEREXT *adapter = packet->adapter; KIRQL oldIrql;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
ASSERT(IsListEmpty(&packet->listEntry)); InsertTailList(&adapter->usbCompletedReadPackets, &packet->listEntry);
#if DBG
packet->timeStamp = DbgGetSystemTime_msec(); #endif
adapter->numIndicatedReadPackets++;
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); }
VOID DequeueCompletedReadPacket(USBPACKET *packet) { ADAPTEREXT *adapter = packet->adapter; KIRQL oldIrql; PLIST_ENTRY listEntry;
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
ASSERT(!IsListEmpty(&adapter->usbCompletedReadPackets)); ASSERT(!IsListEmpty(&packet->listEntry));
RemoveEntryList(&packet->listEntry); InitializeListHead(&packet->listEntry);
ASSERT(adapter->numIndicatedReadPackets > 0); adapter->numIndicatedReadPackets--;
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); }
VOID CancelAllPendingPackets(ADAPTEREXT *adapter) { PLIST_ENTRY listEntry; USBPACKET *packet; PIRP irp; KIRQL oldIrql;
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
/*
* Cancel all pending READs. */ while (!IsListEmpty(&adapter->usbPendingReadPackets)){
listEntry = RemoveHeadList(&adapter->usbPendingReadPackets); packet = CONTAINING_RECORD(listEntry, USBPACKET, listEntry); irp = packet->irpPtr;
ASSERT(packet->sig == DRIVER_SIG);
/*
* Leave the IRP in the list when we cancel it so that completion routine * can move it to the free list. */ InsertTailList(&adapter->usbPendingReadPackets, &packet->listEntry);
KeInitializeEvent(&packet->cancelEvent, NotificationEvent, FALSE);
ASSERT(!packet->cancelled); packet->cancelled = TRUE;
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
DBGVERBOSE((" - cancelling pending read packet #%xh @ %ph, irp=%ph ...", packet->packetId, packet, irp)); IoCancelIrp(irp);
/*
* Wait for the completion routine to run and set the cancelEvent. * By the time we get done waiting, the packet should be back in the free list. */ KeWaitForSingleObject(&packet->cancelEvent, Executive, KernelMode, FALSE, NULL);
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql); }
ASSERT(IsListEmpty(&adapter->usbPendingReadPackets));
/*
* Cancel all pending WRITEs. */ while (!IsListEmpty(&adapter->usbPendingWritePackets)){
listEntry = RemoveHeadList(&adapter->usbPendingWritePackets); packet = CONTAINING_RECORD(listEntry, USBPACKET, listEntry); irp = packet->irpPtr;
ASSERT(packet->sig == DRIVER_SIG);
/*
* Leave the IRP in the list when we cancel it so that completion routine * can move it to the free list. */ InsertTailList(&adapter->usbPendingWritePackets, &packet->listEntry);
KeInitializeEvent(&packet->cancelEvent, NotificationEvent, FALSE);
ASSERT(!packet->cancelled); packet->cancelled = TRUE;
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
DBGVERBOSE((" - cancelling pending write packet #%xh @ %ph, irp=%ph ...", packet->packetId, packet, irp)); IoCancelIrp(irp);
/*
* Wait for the completion routine to run and set the cancelEvent. * By the time we get done waiting, the packet should be back in the free list. */ KeWaitForSingleObject(&packet->cancelEvent, Executive, KernelMode, FALSE, NULL);
KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql); }
ASSERT(IsListEmpty(&adapter->usbPendingWritePackets));
/*
* Cancel the read on the NOTIFY pipe. */ if (adapter->notifyPipeHandle){
/*
* Make sure we've actually sent the notify irp before trying * to cancel it; otherwise, we hang forever waiting for it to complete. */ if (adapter->initialized){ if (adapter->notifyStopped){ /*
* The notify irp has already stopped looping because it returned with error * in NotificationCompletion. Don't cancel it because we'll hang forever * waiting for it to complete. */ DBGVERBOSE(("CancelAllPendingPackets: notify irp already stopped, no need to cancel")); } else { KeInitializeEvent(&adapter->notifyCancelEvent, NotificationEvent, FALSE); adapter->cancellingNotify = TRUE;
KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql); DBGVERBOSE((" - cancelling notify irp = %ph ...", adapter->notifyIrpPtr)); IoCancelIrp(adapter->notifyIrpPtr); KeWaitForSingleObject(&adapter->notifyCancelEvent, Executive, KernelMode, FALSE, NULL); KeAcquireSpinLock(&adapter->adapterSpinLock, &oldIrql);
adapter->cancellingNotify = FALSE; } } }
adapter->readDeficit = 0; KeReleaseSpinLock(&adapter->adapterSpinLock, oldIrql);
}
|