Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

338 lines
8.5 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
int.c
Abstract:
code to handle adapter interrupts
Environment:
kernel mode only
Notes:
Revision History:
6-20-99 : created
--*/
#include "common.h"
// paged functions
#ifdef ALLOC_PRAGMA
#endif
// non paged functions
// USBPORT_InterruptService
// USBPORT_IsrDpc
// USBPORT_DisableInterrupts
// USBPORT_IsrDpcWorker
BOOLEAN
USBPORT_InterruptService(
PKINTERRUPT Interrupt,
PVOID Context
)
/*++
Routine Description:
This is the interrupt service routine for the PORT driver.
Arguments:
Interrupt - A pointer to the interrupt object for this interrupt.
Context - A pointer to the device object.
Return Value:
Returns TRUE if the interrupt was expected (and therefore processed);
otherwise, FALSE is returned.
--*/
{
PDEVICE_OBJECT fdoDeviceObject = Context;
PDEVICE_EXTENSION devExt;
BOOLEAN usbInt = FALSE;
GET_DEVICE_EXT(devExt, fdoDeviceObject);
ASSERT_FDOEXT(devExt);
// by definition, if we are in any other power state than D0 then
// the interrupt could not be from the controller. To handle this
// case we use our internal flag that indicates interrupts are
// disabled
if (!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_EN)) {
return FALSE;
}
// if the controller is gone then the interrupt cannot
// be from USB
if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_CONTROLLER_GONE)) {
return FALSE;
}
// check flag and calldown to miniport
if (devExt->Fdo.MpStateFlags & MP_STATE_STARTED) {
MP_InterruptService(devExt, usbInt);
}
//#if DBG
// else {
// // interrupt before we have started,
// // it had better not be ours
// DEBUG_BREAK();
// }
//#endif
if (usbInt) {
devExt->Fdo.StatPciInterruptCount++;
KeInsertQueueDpc(&devExt->Fdo.IsrDpc,
NULL,
NULL);
}
return usbInt;
}
VOID
USBPORT_IsrDpcWorker(
PDEVICE_OBJECT FdoDeviceObject,
BOOLEAN HcInterrupt
)
/*++
Routine Description:
This routine runs at DISPATCH_LEVEL IRQL.
This routine dous our 'ISR Work' it can be called as a result
of an interrupt or from the Deadman DPC timer.
This function is not reentrant
This function does not directly signal the worker thread
instead we leave this to invalidate endpoint.
Arguments:
Return Value:
None.
--*/
{
PDEVICE_EXTENSION devExt;
KIRQL irql;
PLIST_ENTRY listEntry;
LONG busy;
GET_DEVICE_EXT(devExt, FdoDeviceObject);
ASSERT_FDOEXT(devExt);
busy = InterlockedIncrement(&devExt->Fdo.WorkerDpc);
if (busy) {
InterlockedDecrement(&devExt->Fdo.WorkerDpc);
return;
}
// noisy becuse it is called via timer
#if DBG
{
ULONG cf;
MP_Get32BitFrameNumber(devExt, cf);
if (HcInterrupt) {
LOGENTRY(NULL,
FdoDeviceObject, LOG_NOISY, 'iDW+', FdoDeviceObject, cf, HcInterrupt);
} else {
LOGENTRY(NULL,
FdoDeviceObject, LOG_NOISY, 'idw+', FdoDeviceObject, cf, HcInterrupt);
}
}
#endif
// check the state list for any endpoints
// that have changed state
//
// We add elements to the tail so the ones at
// the head should be the oldest and ready
// for processing.
// if we hit one that is not ready then we know
// the others are not ready either so we bail.
listEntry =
ExInterlockedRemoveHeadList(&devExt->Fdo.EpStateChangeList,
&devExt->Fdo.EpStateChangeListSpin.sl);
while (listEntry != NULL) {
PHCD_ENDPOINT endpoint;
ULONG frameNumber;
endpoint = (PHCD_ENDPOINT) CONTAINING_RECORD(
listEntry,
struct _HCD_ENDPOINT,
StateLink);
ASSERT_ENDPOINT(endpoint);
// lock the endpoint before changing its state
ACQUIRE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'LeG0');
// see if it is time
MP_Get32BitFrameNumber(devExt, frameNumber);
LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'chgS', endpoint, frameNumber,
endpoint->StateChangeFrame);
if (frameNumber <= endpoint->StateChangeFrame &&
!TEST_FLAG(endpoint->Flags, EPFLAG_NUKED)) {
// not time yet, put it back (on the head) and bail
RELEASE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'UeG1');
ExInterlockedInsertHeadList(&devExt->Fdo.EpStateChangeList,
&endpoint->StateLink,
&devExt->Fdo.EpStateChangeListSpin.sl);
// request an SOF just in case
MP_InterruptNextSOF(devExt);
break;
}
// this endpoint is ripe, change its state
//
// note: we should never move into the unknown state
//
// IT IS CRITICAL that this is the only place an endpoint state
// may be changed.
// there is one exception and that is cahnging the state to
// CLOSED
RELEASE_ENDPOINT_LOCK(endpoint, FdoDeviceObject, 'UeG0');
ACQUIRE_STATECHG_LOCK(FdoDeviceObject, endpoint);
USBPORT_ASSERT(endpoint->NewState != ENDPOINT_TRANSITION);
endpoint->CurrentState = endpoint->NewState;
RELEASE_STATECHG_LOCK(FdoDeviceObject, endpoint);
// endpoint needs to be checked,
// since we are in DPC context we will be processing
// all endpoints
USBPORT_InvalidateEndpoint(FdoDeviceObject,
endpoint,
0);
listEntry =
ExInterlockedRemoveHeadList(&devExt->Fdo.EpStateChangeList,
&devExt->Fdo.EpStateChangeListSpin.sl);
}
//#ifdef USBPERF
// // always run the DPC worker from the timer to compensate for
// // reduced thread activity
// USBPORT_DpcWorker(FdoDeviceObject);
//#else
if (HcInterrupt) {
USBPORT_DpcWorker(FdoDeviceObject);
}
//#endif
#if DBG
if (HcInterrupt) {
LOGENTRY(NULL, FdoDeviceObject, LOG_NOISY, 'iDW-', 0,
0, 0);
} else {
LOGENTRY(NULL, FdoDeviceObject, LOG_NOISY, 'idw-', 0,
0, 0);
}
#endif
InterlockedDecrement(&devExt->Fdo.WorkerDpc);
}
VOID
USBPORT_IsrDpc(
PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2
)
/*++
Routine Description:
This routine runs at DISPATCH_LEVEL IRQL.
If the controller was the source of the interrupt this
routine will be called.
Arguments:
Dpc - Pointer to the DPC object.
DeferredContext - supplies the DeviceObject.
SystemArgument1 - not used.
SystemArgument2 - not used.
Return Value:
None.
--*/
{
PDEVICE_EXTENSION devExt;
PDEVICE_OBJECT fdoDeviceObject;
BOOLEAN enableIrq;
fdoDeviceObject = (PDEVICE_OBJECT) DeferredContext;
GET_DEVICE_EXT(devExt, fdoDeviceObject);
ASSERT_FDOEXT(devExt);
LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'iDP+', fdoDeviceObject, 0, 0);
KeAcquireSpinLockAtDpcLevel(&devExt->Fdo.IsrDpcSpin.sl);
LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'DPlk', fdoDeviceObject, 0, 0);
if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_EN)) {
enableIrq = TRUE;
} else {
enableIrq = FALSE;
}
MP_InterruptDpc(devExt, enableIrq);
KeReleaseSpinLockFromDpcLevel(&devExt->Fdo.IsrDpcSpin.sl);
LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'DPuk', fdoDeviceObject, 0, 0);
if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_SUSPENDED)) {
// if we take an interrupt while 'suspended' we treat
// this as a wakeup event.
USBPORT_KdPrint((1, " HC Wake Event\n"));
USBPORT_CompletePdoWaitWake(fdoDeviceObject);
} else {
USBPORT_IsrDpcWorker(fdoDeviceObject, TRUE);
}
LOGENTRY(NULL, fdoDeviceObject, LOG_MISC, 'iDP-', 0,
0, 0);
}