📄 usbfx2lk_selsusp.cpp
字号:
// This constitutes a new I/O on the device,
// so bump the oustanding I/O count
//
OsrIncrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
//
// And allocate an IRP of the appropriate size
//
idleCallbackIrp = IoAllocateIrp(DevExt->DeviceToSendIrpsTo->StackSize,
FALSE);
if (!idleCallbackIrp) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: IoAllocateIrp returned NULL. Exiting...\n"));
return;
}
//
// Get the next stack location for the IRP and
// set it up to be an idle notification request
//
nextStack = IoGetNextIrpStackLocation(idleCallbackIrp);
nextStack->MajorFunction =
IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
&DevExt->SSIdleCallbackInfo;
nextStack->Parameters.DeviceIoControl.InputBufferLength =
sizeof(USB_IDLE_CALLBACK_INFO);
//
// Setup our completion routine that will free the memory
// for this IRP
//
IoSetCompletionRoutine(idleCallbackIrp,
SSIdleNotificationCompletionRoutine,
DevExt,
TRUE,
TRUE,
TRUE);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Submitting idle IRP 0x%p.\n",
idleCallbackIrp));
//
// Set this IRP up in our device extension. We need to
// keep track of this IRP because it will pend
// forever if we are on a hub with a device that
// isn't suspending.
//
KeAcquireSpinLock(&DevExt->SSLock,&oldIrql);
//
// Shouldn't already have a request pending
//
ASSERT(DevExt->SSIdleIrp == NULL);
//
// There's another race condition that we have to contend
// with in this case. SSPowerDeviceIfSuspended may have
// already executed and looked to see if there is
// an Idle IRP pending. Because we haven't set the
// field yet, it will think that the device is just
// in the middle of powering up and will simply
// wait for the power up event. That means that we
// could sit here waiting for the idle notification
// callback to occur (which may not EVER happen) while
// the rest of our code is waiting for a device power
// up to happen, leading to a livelock in the driver.
//
// We'll cover this race condition by adding an extra
// check here to make sure that the device hasn't
// become busy while we were building the idle IRP.
// If it has, we'll just get out of here...
//
if (DevExt->SSDeviceCanNowSuspend == FALSE) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Device became busy while building "\
"IDLE IRP. Exiting.\n"));
//
// Free the IRP we built
//
IoFreeIrp(idleCallbackIrp);
KeReleaseSpinLock(&DevExt->SSLock,oldIrql);
//
// The I/O is finished.
//
OsrDecrementOutstandingIoCount(DevExt,__FILE__,__LINE__);
return;
}
//
// Setup a pointer to the idle IRP in the
// device extension
//
DevExt->SSIdleIrp = idleCallbackIrp;
KeReleaseSpinLock(&DevExt->SSLock,oldIrql);
//
// And submit the IRP down to the lower driver.
//
status = IoCallDriver(DevExt->DeviceToSendIrpsTo,
idleCallbackIrp);
if (NT_SUCCESS(status)) {
//
// If we got a successful status, wait for the
// idle callback to fire and the device to
// power down OR for the IRP's completion routine
// to be called because there was some sort of error
// that occurred before the device could idle
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Waiting for suspend idle callback "\
"or completion routine to fire...\n"));
waitObjects[0] = &DevExt->SSIdleCallbackCalled;
waitObjects[1] = &DevExt->SSIdleCompletionRoutineCalled;
//
// Wait on our above two events.
//
status = OsrWaitForMultipleObjects(2,
waitObjects,
WaitAny,
NULL);
if (status == STATUS_WAIT_0) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Idle callback fired!\n"));
} else if (status == STATUS_WAIT_1) {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Completion routine fired!\n"));
} else {
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: KeWaitForMultipleObjects "\
"returned unknown status 0x%x (%s).\n",
status,OsrNtStatusToString(status)));
}
} else {
//
// The IRP was failed before the idle callback was
// queued. Not much we can do, the completion routine
// will free the IRP
//
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Idle request failed, bus returned "\
"0x%x (%s). Exiting...\n",
status,OsrNtStatusToString(status)));
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSSuspendDeviceWithCallback: Exited\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// SSUsbIdleCallback
//
// This routine is the USB idle callback that does the actually
// suspending of the device when built for XP and later
//
// INPUTS:
//
// Context - One of our device extensions
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID SSUsbIdleCallback(PVOID Context)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)Context;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSUsbIdleCallback: Entered\n"));
//
// And now power the device down
//
SSSuspendDevice(devExt);
KeSetEvent(&devExt->SSIdleCallbackCalled,
EVENT_INCREMENT,
FALSE);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSUsbIdleCallback: Exited\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// SSIdleNotificationCompletionRoutine
//
// This routine is the completion routine for the IRP used to submit the
// USB idle callback
//
// INPUTS:
//
// DeviceObject - We allocated the IRP, so this is NULL
//
// Irp - The idle notification IRP
//
// Context - One of our device extensions
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// STATUS_MORE_PROCESSING_REQUIRED
//
// IRQL:
//
// IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS SSIdleNotificationCompletionRoutine(PDEVICE_OBJECT DeviceObject,
PIRP Irp, PVOID Context)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)Context;
KIRQL oldIrql;
PIRP idleIrp;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSIdleNotificationCompletionRoutine: Entered\n"));
KeAcquireSpinLock(&devExt->SSLock,&oldIrql);
//
// Let's see if someone else didn't get to this
// first
//
idleIrp = devExt->SSIdleIrp;
devExt->SSIdleIrp = NULL;
KeReleaseSpinLock(&devExt->SSLock,oldIrql);
if (idleIrp) {
//
// If we got the IRP, we free it. Otherwise let the
// person who cancelled the IRP free it.
//
IoFreeIrp(idleIrp);
}
KeSetEvent(&devExt->SSIdleCompletionRoutineCalled,
EVENT_INCREMENT,
FALSE);
//
// The I/O is finished.
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSIdleNotificationCompletionRoutine: Exited\n"));
return STATUS_MORE_PROCESSING_REQUIRED;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
// SSSynchronousPowerIrpCompletionFunc
//
// Generic SYNCHRONOUS selective suspend D-IRP power completion routine
//
// INPUTS:
//
// DeviceObject - Not used
//
// MinorFunction - Not used
//
// PowerState - Not used
//
// Context - An event to signal the completion of the D-IRP
//
// IoStatus - Not used
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID SSSynchronousPowerIrpCompletionFunc(PDEVICE_OBJECT DeviceObject,
UCHAR MinorFunction,
POWER_STATE PowerState,
PVOID Context,
PIO_STATUS_BLOCK IoStatus)
{
PKEVENT completeEvent = (PKEVENT)Context;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSSynchronousPowerIrpCompletionFunc: Entered\n"));
KeSetEvent(completeEvent, EVENT_INCREMENT, FALSE);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSSynchronousPowerIrpCompletionFunc: Exiting\n"));
}
///////////////////////////////////////////////////////////////////////////////
//
// SSAsynchronousPowerUpIrpCompletionFunc
//
// ASYNCHRONOUS selective suspend for power up D-IRP completion
// routine
//
// INPUTS:
//
// DeviceObject - Not used
//
// MinorFunction - Not used
//
// PowerState - Not used
//
// Context - One of our device extensions
//
// IoStatus - Not used
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL <= DISPATCH_LEVEL
//
// CONTEXT:
//
// Arbitrary
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID SSAsynchronousPowerUpIrpCompletionFunc(PDEVICE_OBJECT DeviceObject,
UCHAR MinorFunction,
POWER_STATE PowerState,
PVOID Context,
PIO_STATUS_BLOCK IoStatus)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)Context;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSAsynchronousPowerUpIrpCompletionFunc: Entered\n"));
//
// The I/O is finished.
//
OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__);
//
// A power up is complete, get the Selective Suspend
// state properly updated
//
SSPowerUpCompleteUpdateSSState(devExt);
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_SELECTIVE_SUSPEND,
("SSAsynchronousPowerUpIrpCompletionFunc: Exiting\n"));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -