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.
1001 lines
25 KiB
1001 lines
25 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sSDevCtr.c
|
|
|
|
Abstract:
|
|
|
|
This file contains dispatch routines
|
|
for create and close. This file also
|
|
contains routines to selectively suspend
|
|
the device. The selective suspend feature
|
|
is usb specific and not hardware specific.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Notes:
|
|
|
|
Copyright (c) 2000 Microsoft Corporation.
|
|
All Rights Reserved.
|
|
|
|
--*/
|
|
|
|
#include "selSusp.h"
|
|
#include "sSPnP.h"
|
|
#include "sSPwr.h"
|
|
#include "sSDevCtr.h"
|
|
#include "sSUsr.h"
|
|
#include "sSWmi.h"
|
|
|
|
NTSTATUS
|
|
SS_DispatchCreate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch routine for create.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
Irp - I/O request packet.
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
PAGED_CODE();
|
|
|
|
SSDbgPrint(3, ("SS_DispatchCreate - begins\n"));
|
|
//
|
|
// initialize variables
|
|
//
|
|
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// set ntStatus to STATUS_SUCCESS
|
|
//
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
//
|
|
// increment OpenHandleCounts
|
|
//
|
|
InterlockedIncrement(&deviceExtension->OpenHandleCount);
|
|
|
|
Irp->IoStatus.Status = ntStatus;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
//
|
|
// the device is idle if it has no open handles or pending PnP Irps
|
|
// since this is create request, cancel idle req. if any
|
|
//
|
|
if(deviceExtension->SSEnable) {
|
|
|
|
CancelSelectSuspend(deviceExtension);
|
|
}
|
|
|
|
SSDbgPrint(3, ("SS_DispatchCreate - ends\n"));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
SS_DispatchClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch routine for close.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
Irp - I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
PAGED_CODE();
|
|
|
|
SSDbgPrint(3, ("SS_DispatchClose - begins\n"));
|
|
//
|
|
// initialize variables
|
|
//
|
|
deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// set ntStatus to STATUS_SUCCESS
|
|
//
|
|
ntStatus = STATUS_SUCCESS;
|
|
|
|
Irp->IoStatus.Status = ntStatus;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
InterlockedDecrement(&deviceExtension->OpenHandleCount);
|
|
|
|
SSDbgPrint(3, ("SS_DispatchClose - ends\n"));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
SS_DispatchDevCtrl(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch routine for IRP_MJ_DEVICE_CONTROL
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
Irp - I/O request packet
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
ULONG code;
|
|
PVOID ioBuffer;
|
|
ULONG inputBufferLength;
|
|
ULONG outputBufferLength;
|
|
ULONG info;
|
|
NTSTATUS ntStatus;
|
|
PDEVICE_EXTENSION deviceExtension;
|
|
PIO_STACK_LOCATION irpStack;
|
|
|
|
//
|
|
// initialize variables
|
|
//
|
|
|
|
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
|
|
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
code = irpStack->Parameters.DeviceIoControl.IoControlCode;
|
|
info = 0;
|
|
|
|
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
|
|
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
SSDbgPrint(3, ("SS_DispatchDevCtrl::"));
|
|
SSIoIncrement(deviceExtension);
|
|
|
|
switch(code) {
|
|
|
|
default :
|
|
|
|
ntStatus = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = ntStatus;
|
|
Irp->IoStatus.Information = info;
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
SSDbgPrint(3, ("SS_DispatchDevCtrl::"));
|
|
SSIoDecrement(deviceExtension);
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
NTSTATUS
|
|
SubmitIdleRequestIrp(
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine builds an idle request irp with an associated callback routine
|
|
and a completion routine in the driver and passes the irp down the stack.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - pointer to device extension
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
NTSTATUS ntStatus;
|
|
KIRQL oldIrql;
|
|
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
|
|
PIO_STACK_LOCATION nextStack;
|
|
|
|
//
|
|
// initialize variables
|
|
//
|
|
|
|
irp = NULL;
|
|
idleCallbackInfo = NULL;
|
|
|
|
SSDbgPrint(3, ("SubmitIdleRequestIrp - begins\n"));
|
|
|
|
//
|
|
// if the device is not in a D0 power state,
|
|
// budge out..
|
|
//
|
|
if(PowerDeviceD0 != DeviceExtension->DevPower) {
|
|
|
|
ntStatus = STATUS_POWER_STATE_INVALID;
|
|
|
|
goto SubmitIdleRequestIrp_Exit;
|
|
}
|
|
|
|
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
|
|
|
|
KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
|
|
|
|
if(InterlockedExchange(&DeviceExtension->IdleReqPend, 1)) {
|
|
|
|
SSDbgPrint(1, ("Idle request pending..\n"));
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
|
|
|
|
ntStatus = STATUS_DEVICE_BUSY;
|
|
|
|
goto SubmitIdleRequestIrp_Exit;
|
|
}
|
|
|
|
//
|
|
// clear the NoIdleReqPendEvent because we are about
|
|
// to submit an idle request. Since we are so early
|
|
// to clear this event, make sure that if we fail this
|
|
// request we set back the event.
|
|
//
|
|
KeClearEvent(&DeviceExtension->NoIdleReqPendEvent);
|
|
|
|
idleCallbackInfo = ExAllocatePool(NonPagedPool,
|
|
sizeof(struct _USB_IDLE_CALLBACK_INFO));
|
|
|
|
if(idleCallbackInfo) {
|
|
|
|
idleCallbackInfo->IdleCallback = IdleNotificationCallback;
|
|
|
|
idleCallbackInfo->IdleContext = (PVOID)DeviceExtension;
|
|
|
|
ASSERT(DeviceExtension->IdleCallbackInfo == NULL);
|
|
|
|
DeviceExtension->IdleCallbackInfo = idleCallbackInfo;
|
|
|
|
//
|
|
// we use IoAllocateIrp to create an irp to selectively suspend the
|
|
// device. This irp lies pending with the hub driver. When appropriate
|
|
// the hub driver will invoked callback, where we power down. The completion
|
|
// routine is invoked when we power back.
|
|
//
|
|
irp = IoAllocateIrp(DeviceExtension->TopOfStackDeviceObject->StackSize,
|
|
FALSE);
|
|
|
|
if(irp == NULL) {
|
|
|
|
SSDbgPrint(1, ("cannot build idle request irp\n"));
|
|
|
|
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
|
|
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
|
|
|
|
ExFreePool(idleCallbackInfo);
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
goto SubmitIdleRequestIrp_Exit;
|
|
}
|
|
|
|
nextStack = IoGetNextIrpStackLocation(irp);
|
|
|
|
nextStack->MajorFunction =
|
|
IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
|
|
nextStack->Parameters.DeviceIoControl.IoControlCode =
|
|
IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
|
|
|
|
nextStack->Parameters.DeviceIoControl.Type3InputBuffer =
|
|
idleCallbackInfo;
|
|
|
|
nextStack->Parameters.DeviceIoControl.InputBufferLength =
|
|
sizeof(struct _USB_IDLE_CALLBACK_INFO);
|
|
|
|
|
|
IoSetCompletionRoutine(irp,
|
|
IdleNotificationRequestComplete,
|
|
DeviceExtension,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE);
|
|
|
|
DeviceExtension->PendingIdleIrp = irp;
|
|
|
|
//
|
|
// we initialize the count to 2.
|
|
// The reason is, if the CancelSelectSuspend routine manages
|
|
// to grab the irp from the device extension, then the last of the
|
|
// CancelSelectSuspend routine/IdleNotificationRequestComplete routine
|
|
// to execute will free this irp. We need to have this schema so that
|
|
// 1. completion routine does not attempt to touch the irp freed by
|
|
// CancelSelectSuspend routine.
|
|
// 2. CancelSelectSuspend routine doesnt wait for ever for the completion
|
|
// routine to complete!
|
|
//
|
|
DeviceExtension->FreeIdleIrpCount = 2;
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
|
|
|
|
//
|
|
// check if the device is idle.
|
|
// A check here ensures that a race condition did not
|
|
// completely reverse the call sequence of SubmitIdleRequestIrp
|
|
// and CancelSelectiveSuspend
|
|
//
|
|
|
|
if(!CanDeviceSuspend(DeviceExtension) ||
|
|
PowerDeviceD0 != DeviceExtension->DevPower) {
|
|
|
|
//
|
|
// device cannot suspend - abort.
|
|
// also irps created using IoAllocateIrp
|
|
// needs to be deallocated.
|
|
//
|
|
|
|
SSDbgPrint(1, ("Device cannot selectively suspend - abort\n"));
|
|
|
|
KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
|
|
|
|
DeviceExtension->IdleCallbackInfo = NULL;
|
|
|
|
DeviceExtension->PendingIdleIrp = NULL;
|
|
|
|
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
|
|
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
|
|
|
|
if(idleCallbackInfo) {
|
|
|
|
ExFreePool(idleCallbackInfo);
|
|
}
|
|
|
|
//
|
|
// it is still safe to touch the local variable "irp" here.
|
|
// the irp has not been passed down the stack, the irp has
|
|
// no cancellation routine. The worse position is that the
|
|
// CancelSelectSuspend has run after we released the spin
|
|
// lock above. It is still essential to free the irp.
|
|
//
|
|
if(irp) {
|
|
|
|
IoFreeIrp(irp);
|
|
}
|
|
|
|
ntStatus = STATUS_UNSUCCESSFUL;
|
|
goto SubmitIdleRequestIrp_Exit;
|
|
}
|
|
|
|
SSDbgPrint(3, ("Cancelling the timer...\n"));
|
|
|
|
//
|
|
// Cancel the timer so that the DPCs are no longer fired.
|
|
// Thus, we are making judicious usage of our resources.
|
|
// we do not need DPCs because we already have an idle irp pending.
|
|
// The timers are re-initialized in the completion routine.
|
|
//
|
|
KeCancelTimer(&DeviceExtension->Timer);
|
|
|
|
SSDbgPrint(3, ("Submit an idle request at power state PowerDeviceD%X\n",
|
|
DeviceExtension->DevPower - 1))
|
|
|
|
ntStatus = IoCallDriver(DeviceExtension->TopOfStackDeviceObject, irp);
|
|
|
|
if(!NT_SUCCESS(ntStatus)) {
|
|
|
|
SSDbgPrint(1, ("IoCallDriver failed\n"));
|
|
|
|
goto SubmitIdleRequestIrp_Exit;
|
|
}
|
|
}
|
|
else {
|
|
|
|
SSDbgPrint(1, ("Memory allocation for idleCallbackInfo failed\n"));
|
|
|
|
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
|
|
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
SubmitIdleRequestIrp_Exit:
|
|
|
|
SSDbgPrint(3, ("SubmitIdleRequestIrp - ends\n"));
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
VOID
|
|
IdleNotificationCallback(
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
"A pointer to a callback function in your driver is passed down the stack with
|
|
this IOCTL, and it is this callback function that is called by USBHUB when it
|
|
safe for your device to power down."
|
|
|
|
"When the callback in your driver is called, all you really need to do is to
|
|
to first ensure that a WaitWake Irp has been submitted for your device, if
|
|
remote wake is possible for your device and then request a SetD2 (or DeviceWake)"
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - pointer to device extension
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
POWER_STATE powerState;
|
|
KEVENT irpCompletionEvent;
|
|
PIRP_COMPLETION_CONTEXT irpContext;
|
|
|
|
SSDbgPrint(3, ("IdleNotificationCallback - begins\n"));
|
|
|
|
//
|
|
// Dont idle, if the device was just disconnected or being stopped
|
|
// i.e. return for the following DeviceState(s)
|
|
// NotStarted, Stopped, PendingStop, PendingRemove, SurpriseRemoved, Removed
|
|
//
|
|
|
|
if(DeviceExtension->DeviceState != Working) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If there is not already a WW IRP pending, submit one now
|
|
//
|
|
if(DeviceExtension->WaitWakeEnable) {
|
|
|
|
IssueWaitWake(DeviceExtension);
|
|
}
|
|
|
|
|
|
//
|
|
// power down the device
|
|
//
|
|
|
|
irpContext = (PIRP_COMPLETION_CONTEXT)
|
|
ExAllocatePool(NonPagedPool,
|
|
sizeof(IRP_COMPLETION_CONTEXT));
|
|
|
|
if(!irpContext) {
|
|
|
|
SSDbgPrint(1, ("Failed to alloc memory for irpContext\n"));
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
else {
|
|
|
|
//
|
|
// increment the count. In the HoldIoRequestWorkerRoutine, the
|
|
// count is decremented twice (one for the system Irp and the
|
|
// other for the device Irp. An increment here compensates for
|
|
// the sytem irp..The decrement corresponding to this increment
|
|
// is in the completion function
|
|
//
|
|
|
|
SSDbgPrint(3, ("IdleNotificationCallback::"));
|
|
SSIoIncrement(DeviceExtension);
|
|
|
|
powerState.DeviceState = DeviceExtension->PowerDownLevel;
|
|
|
|
KeInitializeEvent(&irpCompletionEvent, NotificationEvent, FALSE);
|
|
|
|
irpContext->DeviceExtension = DeviceExtension;
|
|
irpContext->Event = &irpCompletionEvent;
|
|
|
|
ntStatus = PoRequestPowerIrp(
|
|
DeviceExtension->PhysicalDeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
(PREQUEST_POWER_COMPLETE) PoIrpCompletionFunc,
|
|
irpContext,
|
|
NULL);
|
|
|
|
//
|
|
// if PoRequestPowerIrp returns a failure, we will release memory below
|
|
//
|
|
|
|
if(STATUS_PENDING == ntStatus) {
|
|
|
|
SSDbgPrint(3, ("IdleNotificationCallback::"
|
|
"waiting for the power irp to complete\n"));
|
|
|
|
KeWaitForSingleObject(&irpCompletionEvent,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
if(!NT_SUCCESS(ntStatus)) {
|
|
|
|
if(irpContext) {
|
|
|
|
ExFreePool(irpContext);
|
|
}
|
|
}
|
|
|
|
SSDbgPrint(3, ("IdleNotificationCallback - ends\n"));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
IdleNotificationRequestComplete(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for idle notification irp
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
Irp - I/O request packet
|
|
DeviceExtension - pointer to device extension
|
|
|
|
Return Value:
|
|
|
|
NT status value
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS ntStatus;
|
|
POWER_STATE powerState;
|
|
KIRQL oldIrql;
|
|
PIRP idleIrp;
|
|
LARGE_INTEGER dueTime;
|
|
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
|
|
|
|
SSDbgPrint(3, ("IdleNotificationRequestCompete - begins\n"));
|
|
|
|
idleIrp = NULL;
|
|
|
|
//
|
|
// check the Irp status
|
|
//
|
|
ntStatus = Irp->IoStatus.Status;
|
|
|
|
if(!NT_SUCCESS(ntStatus) && ntStatus != STATUS_NOT_SUPPORTED) {
|
|
|
|
SSDbgPrint(1, ("Idle irp completes with error::"));
|
|
|
|
switch(ntStatus) {
|
|
|
|
case STATUS_INVALID_DEVICE_REQUEST:
|
|
|
|
SSDbgPrint(1, ("STATUS_INVALID_DEVICE_REQUEST\n"));
|
|
|
|
break;
|
|
|
|
case STATUS_CANCELLED:
|
|
|
|
SSDbgPrint(1, ("STATUS_CANCELLED\n"));
|
|
|
|
break;
|
|
|
|
case STATUS_POWER_STATE_INVALID:
|
|
|
|
SSDbgPrint(1, ("STATUS_POWER_STATE_INVALID\n"));
|
|
|
|
goto IdleNotificationRequestComplete_Exit;
|
|
|
|
case STATUS_DEVICE_BUSY:
|
|
|
|
SSDbgPrint(1, ("STATUS_DEVICE_BUSY\n"));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SSDbgPrint(1, ("default: %X\n", ntStatus));
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// if the irp completes in error, request for a SetD0 only if not in D0
|
|
//
|
|
|
|
if(PowerDeviceD0 != DeviceExtension->DevPower) {
|
|
SSDbgPrint(3, ("IdleNotificationRequestComplete::"));
|
|
SSIoIncrement(DeviceExtension);
|
|
|
|
powerState.DeviceState = PowerDeviceD0;
|
|
|
|
ntStatus = PoRequestPowerIrp(
|
|
DeviceExtension->PhysicalDeviceObject,
|
|
IRP_MN_SET_POWER,
|
|
powerState,
|
|
(PREQUEST_POWER_COMPLETE) PoIrpAsyncCompletionFunc,
|
|
DeviceExtension,
|
|
NULL);
|
|
|
|
if(!NT_SUCCESS(ntStatus)) {
|
|
|
|
SSDbgPrint(1, ("PoRequestPowerIrp failed\n"));
|
|
}
|
|
}
|
|
}
|
|
|
|
IdleNotificationRequestComplete_Exit:
|
|
|
|
KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
|
|
|
|
idleCallbackInfo = DeviceExtension->IdleCallbackInfo;
|
|
|
|
DeviceExtension->IdleCallbackInfo = NULL;
|
|
|
|
idleIrp = (PIRP) InterlockedExchangePointer(
|
|
&DeviceExtension->PendingIdleIrp,
|
|
NULL);
|
|
|
|
InterlockedExchange(&DeviceExtension->IdleReqPend, 0);
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
|
|
|
|
if(idleCallbackInfo) {
|
|
|
|
ExFreePool(idleCallbackInfo);
|
|
}
|
|
|
|
//
|
|
// since the irp was created using IoAllocateIrp,
|
|
// the Irp needs to be freed using IoFreeIrp.
|
|
// Also return STATUS_MORE_PROCESSING_REQUIRED so that
|
|
// the kernel does not reference this in the near future.
|
|
//
|
|
|
|
if(idleIrp) {
|
|
|
|
SSDbgPrint(3, ("the completion routine has a valid pointer to idleIrp - "
|
|
"free the irp\n"));
|
|
|
|
IoFreeIrp(Irp);
|
|
|
|
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
}
|
|
else {
|
|
|
|
//
|
|
// The CancelSelectiveSuspend routine has grabbed the Irp from the device
|
|
// extension. Now the last one to decrement the FreeIdleIrpCount should
|
|
// free the irp.
|
|
//
|
|
if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) {
|
|
|
|
SSDbgPrint(3, ("FreeIdleIrpCount is 0 - "
|
|
"free the irp\n"));
|
|
IoFreeIrp(Irp);
|
|
|
|
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
if(DeviceExtension->SSEnable) {
|
|
|
|
SSDbgPrint(3, ("Set the timer to fire DPCs\n"));
|
|
|
|
dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 5000 ms
|
|
|
|
SSDbgPrint(3, ("Setting the timer...\n"));
|
|
KeSetTimerEx(&DeviceExtension->Timer,
|
|
dueTime,
|
|
IDLE_INTERVAL, // 5000 ms
|
|
&DeviceExtension->DeferredProcCall);
|
|
|
|
SSDbgPrint(3, ("IdleNotificationRequestCompete - ends\n"));
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
VOID
|
|
CancelSelectSuspend(
|
|
IN PDEVICE_EXTENSION DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is invoked to cancel selective suspend request.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - pointer to device extension
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
KIRQL oldIrql;
|
|
|
|
irp = NULL;
|
|
|
|
SSDbgPrint(3, ("CancelSelectSuspend - begins\n"));
|
|
|
|
KeAcquireSpinLock(&DeviceExtension->IdleReqStateLock, &oldIrql);
|
|
|
|
if(!CanDeviceSuspend(DeviceExtension))
|
|
{
|
|
SSDbgPrint(3, ("Device is not idle\n"));
|
|
|
|
irp = (PIRP) InterlockedExchangePointer(
|
|
&DeviceExtension->PendingIdleIrp,
|
|
NULL);
|
|
}
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->IdleReqStateLock, oldIrql);
|
|
|
|
//
|
|
// since we have a valid Irp ptr,
|
|
// we can call IoCancelIrp on it,
|
|
// without the fear of the irp
|
|
// being freed underneath us.
|
|
//
|
|
|
|
if(irp) {
|
|
|
|
//
|
|
// This routine has the irp pointer.
|
|
// It is safe to call IoCancelIrp because we know that
|
|
// the compleiton routine will not free this irp unless...
|
|
//
|
|
//
|
|
if(IoCancelIrp(irp)) {
|
|
|
|
SSDbgPrint(3, ("IoCancelIrp returns TRUE\n"));
|
|
}
|
|
else {
|
|
SSDbgPrint(3, ("IoCancelIrp returns FALSE\n"));
|
|
}
|
|
|
|
//
|
|
// ....we decrement the FreeIdleIrpCount from 2 to 1.
|
|
// if completion routine runs ahead of us, then this routine
|
|
// decrements the FreeIdleIrpCount from 1 to 0 and hence shall
|
|
// free the irp.
|
|
//
|
|
if(0 == InterlockedDecrement(&DeviceExtension->FreeIdleIrpCount)) {
|
|
|
|
SSDbgPrint(3, ("FreeIdleIrpCount is 0 - "
|
|
"free the irp\n"));
|
|
IoFreeIrp(irp);
|
|
|
|
KeSetEvent(&DeviceExtension->NoIdleReqPendEvent,
|
|
IO_NO_INCREMENT,
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
SSDbgPrint(3, ("CancelSelectSuspend - ends\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
PoIrpCompletionFunc(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for power irp PoRequested in
|
|
IdleNotificationCallback.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
MinorFunciton - minor function for the irp.
|
|
PowerState - irp power state
|
|
Context - context passed to the completion function
|
|
IoStatus - status block.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PIRP_COMPLETION_CONTEXT irpContext;
|
|
|
|
//
|
|
// initialize variables
|
|
//
|
|
irpContext = NULL;
|
|
|
|
if(Context) {
|
|
|
|
irpContext = (PIRP_COMPLETION_CONTEXT) Context;
|
|
}
|
|
|
|
//
|
|
// all we do is set the event and decrement the count
|
|
//
|
|
|
|
if(irpContext) {
|
|
|
|
KeSetEvent(irpContext->Event, 0, FALSE);
|
|
|
|
SSDbgPrint(3, ("PoIrpCompletionFunc::"));
|
|
SSIoDecrement(irpContext->DeviceExtension);
|
|
|
|
ExFreePool(irpContext);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
PoIrpAsyncCompletionFunc(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for power irp PoRequested in IdleNotification
|
|
RequestComplete routine.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
MinorFunciton - minor function for the irp.
|
|
PowerState - irp power state
|
|
Context - context passed to the completion function
|
|
IoStatus - status block.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
//
|
|
// initialize variables
|
|
//
|
|
DeviceExtension = (PDEVICE_EXTENSION) Context;
|
|
|
|
//
|
|
// all we do is decrement the count
|
|
//
|
|
|
|
SSDbgPrint(3, ("PoIrpAsyncCompletionFunc::"));
|
|
SSIoDecrement(DeviceExtension);
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
WWIrpCompletionFunc(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN UCHAR MinorFunction,
|
|
IN POWER_STATE PowerState,
|
|
IN PVOID Context,
|
|
IN PIO_STATUS_BLOCK IoStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine for PoRequest wait wake irp
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - pointer to device object
|
|
MinorFunciton - minor function for the irp.
|
|
PowerState - irp power state
|
|
Context - context passed to the completion function
|
|
IoStatus - status block.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_EXTENSION DeviceExtension;
|
|
|
|
//
|
|
// initialize variables
|
|
//
|
|
DeviceExtension = (PDEVICE_EXTENSION) Context;
|
|
|
|
//
|
|
// all we do is decrement the count
|
|
//
|
|
|
|
SSDbgPrint(3, ("WWIrpCompletionFunc::"));
|
|
SSIoDecrement(DeviceExtension);
|
|
|
|
return;
|
|
}
|
|
|