📄 usblspwr.c
字号:
not in a compatible device power state. In this case, a pointer to
the IRP_MN_SET_POWER Irp is saved into the FDO device extension
(deviceExtension->PowerIrp), and then a call must be
made to PoRequestPowerIrp() to put the device into a proper power state,
and this routine is set as the completion routine.
We decrement our pending io count and pass the saved IRP_MN_SET_POWER Irp
on to the next driver
Arguments:
DeviceObject - Pointer to the device object for the class device.
Note that we must get our own device object from the Context
Context - Driver defined context, in this case our own functional device object ( FDO )
Return Value:
The function value is the final status from the operation.
--*/
{
PIRP irp;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = Context;
NTSTATUS ntStatus;
deviceExtension = deviceObject->DeviceExtension;
// Get the Irp we saved for later processing in USBLS120_ProcessPowerIrp()
// when we decided to request the Power Irp that this routine
// is the completion routine for.
irp = deviceExtension->PowerIrp;
// We will return the status set by the PDO for the power request we're completing
ntStatus = IoStatus->Status;
USBLS120_KdPrint( DBGLVL_HIGH,("Enter USBLS120_PoRequestCompletion()\n"));
// we should not be in the midst of handling a self-generated power irp
USBLS120_ASSERT( !deviceExtension->SelfPowerIrp );
// we must pass down to the next driver in the stack
IoCopyCurrentIrpStackLocationToNext(irp);
// Calling PoStartNextPowerIrp() indicates that the driver is finished
// with the previous power IRP, if any, and is ready to handle the next power IRP.
// It must be called for every power IRP.Although power IRPs are completed only once,
// typically by the lowest-level driver for a device, PoStartNextPowerIrp must be called
// for every stack location. Drivers must call PoStartNextPowerIrp while the current IRP
// stack location points to the current driver. Therefore, this routine must be called
// before IoCompleteRequest, IoSkipCurrentStackLocation, and PoCallDriver.
PoStartNextPowerIrp(irp);
// PoCallDriver is used to pass any power IRPs to the PDO instead of IoCallDriver.
// When passing a power IRP down to a lower-level driver, the caller should use
// IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to copy the IRP to
// the next stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext
// if processing the IRP requires setting a completion routine, or IoSkipCurrentStackLocation
// if no completion routine is needed.
PoCallDriver(
deviceExtension->TopOfStackDeviceObject,
irp
);
USBLS120_DecrementIoCount(deviceObject);
USBLS120_KdPrint( DBGLVL_MEDIUM,("USBLS120_PoRequestCompletion() Exit IRP_MN_SET_POWER\n"));
deviceExtension->PowerIrp = NULL;
return ntStatus;
}
NTSTATUS
USBLS120_PowerIrp_Complete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when An IRP_MN_SET_POWER of type 'DevicePowerState'
has been received by USBLS120_ProcessPowerIrp(), and that routine has determined
1) the request is for full powerup ( to PowerDeviceD0 ), and
2) We are not already in that state
A call is then made to PoRequestPowerIrp() with this routine set as the completion routine.
Arguments:
DeviceObject - Pointer to the device object for the class device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
USBLS120_KdPrint( DBGLVL_HIGH,("enter USBLS120_PowerIrp_Complete\n"));
deviceObject = (PDEVICE_OBJECT) Context;
deviceExtension = (PDEVICE_EXTENSION) deviceObject->DeviceExtension;
// If the lower driver returned PENDING, mark our stack location as pending also.
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
// We can assert that we're a device powerup-to D0 request,
// because that was the only type of request we set a completion routine
// for in the first place
USBLS120_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
USBLS120_ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
USBLS120_ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
USBLS120_ASSERT(irpStack->Parameters.Power.State.DeviceState==PowerDeviceD0);
// Now that we know we've let the lower drivers do what was needed to power up,
// we can set our device extension flags accordingly
deviceExtension->CurrentDevicePowerState = PowerDeviceD0;
Irp->IoStatus.Status = ntStatus;
USBLS120_DecrementIoCount(deviceObject);
USBLS120_KdPrint( DBGLVL_MEDIUM,("exit USBLS120_PowerIrp_Complete Exit IRP_MN_SET_POWER D0 complete\n"));
return ntStatus;
}
NTSTATUS
USBLS120_SelfSuspendOrActivate(
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN fSuspend
)
/*++
Routine Description:
Called on USBLS120_PnPAddDevice() to power down until needed (i.e., till a pipe is actually opened).
Called on USBLS120_Create() to power up device to D0 before opening 1st pipe.
Called on USBLS120_Close() to power down device if this is the last pipe.
Arguments:
DeviceObject - Pointer to the device object
fSuspend; TRUE to Suspend, FALSE to acivate.
Return Value:
If the operation is not attemtped, SUCCESS is returned.
If the operation is attemtped, the value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
POWER_STATE PowerState;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = DeviceObject->DeviceExtension;
USBLS120_KdPrint( DBGLVL_MAXIMUM,("Enter USBLS120_SelfSuspendOrActivate(),fSuspend = %d\n", fSuspend));
// Can't accept request if:
// 1) device is removed,
// 2) has never been started,
// 3) is stopped,
// 4) has a remove request pending,
// 5) has a stop device pending
if ( !USBLS120_CanAcceptIoRequests( DeviceObject ) ) {
ntStatus = STATUS_DELETE_PENDING;
USBLS120_KdPrint( DBGLVL_MEDIUM,("ABORTING USBLS120_SelfSuspendOrActivate()\n"));
return ntStatus;
}
// don't do anything if any System-generated Device Pnp irps are pending
if ( NULL != deviceExtension->PowerIrp ) {
USBLS120_KdPrint( DBGLVL_MAXIMUM,("Exit USBLS120_SelfSuspendOrActivate(),refusing on pending deviceExtension->PowerIrp 0x%x\n", deviceExtension->PowerIrp));
return ntStatus;
}
// don't do anything if any self-generated Device Pnp irps are pending
if ( deviceExtension->SelfPowerIrp ) {
USBLS120_KdPrint( DBGLVL_MAXIMUM,("Exit USBLS120_SelfSuspendOrActivate(),refusing on pending deviceExtension->SelfPowerIrp\n" ));
return ntStatus;
}
// don't auto-suspend if any pipes are open
if ( fSuspend && ( 0 != deviceExtension->OpenPipeCount ) ) {
USBLS120_KdPrint( DBGLVL_MAXIMUM,("Exit USBLS120_SelfSuspendOrActivate(),refusing to self-suspend on OpenPipeCount %d\n", deviceExtension->OpenPipeCount));
return ntStatus;
}
// don't auto-activate if no pipes are open
if ( !fSuspend && ( 0 == deviceExtension->OpenPipeCount ) ) {
USBLS120_KdPrint( DBGLVL_MAXIMUM,("Exit USBLS120_SelfSuspendOrActivate(),refusing to self-activate, no pipes open\n"));
return ntStatus;
}
// dont do anything if registry CurrentControlSet\Services\BulkUsb\Parameters\PowerDownLevel
// has been set to zero, PowerDeviceD0 ( 1 ), or a bogus high value
if ( ( deviceExtension->PowerDownLevel == PowerDeviceD0 ) ||
( deviceExtension->PowerDownLevel == PowerDeviceUnspecified) ||
( deviceExtension->PowerDownLevel >= PowerDeviceMaximum ) ) {
USBLS120_KdPrint( DBGLVL_MAXIMUM,("Exit USBLS120_SelfSuspendOrActivate(), refusing on deviceExtension->PowerDownLevel == %d\n", deviceExtension->PowerDownLevel));
return ntStatus;
}
if ( fSuspend )
PowerState.DeviceState = deviceExtension->PowerDownLevel;
else
PowerState.DeviceState = PowerDeviceD0; // power up all the way; we're probably just about to do some IO
ntStatus = USBLS120_SelfRequestPowerIrp( DeviceObject, PowerState );
USBLS120_KdPrint( DBGLVL_MAXIMUM,("USBLS120_SelfSuspendOrActivate() status 0x%x on setting dev state %s\n", ntStatus, USBLS120_StringForDevState(PowerState.DeviceState ) ));
return ntStatus;
}
NTSTATUS
USBLS120_SelfRequestPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN POWER_STATE PowerState
)
/*++
Routine Description:
This routine is called by USBLS120_SelfSuspendOrActivate() to
actually make the system request for a powerdown/up to PowerState.
It first checks to see if we are already in Powerstate and immediately
returns SUCCESS with no further processing if so
Arguments:
DeviceObject - Pointer to the device object
PowerState. power state requested, e.g PowerDeviceD0.
Return Value:
The function value is the final status from the operation.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PIRP pIrp = NULL;
deviceExtension = DeviceObject->DeviceExtension;
// This should have been reset in completion routine
USBLS120_ASSERT( !deviceExtension->SelfPowerIrp );
if ( deviceExtension->CurrentDevicePowerState == PowerState.DeviceState )
return STATUS_SUCCESS; // nothing to do
USBLS120_KdPrint( DBGLVL_HIGH,("Enter USBLS120_SelfRequestPowerIrp() will request power irp to state %s\n",
USBLS120_StringForDevState( PowerState.DeviceState )));
USBLS120_IncrementIoCount(DeviceObject);
// flag we're handling a self-generated power irp
deviceExtension->SelfPowerIrp = TRUE;
// actually request the Irp
ntStatus = PoRequestPowerIrp(
deviceExtension->PhysicalDeviceObject,
IRP_MN_SET_POWER,
PowerState,
USBLS120_PoSelfRequestCompletion,
DeviceObject,
NULL
);
if ( ntStatus == STATUS_PENDING ) {
// status pending is the return code we wanted
// We only need to wait for completion if we're powering up
if ( (ULONG) PowerState.DeviceState < deviceExtension->PowerDownLevel ) {
NTSTATUS waitStatus;
waitStatus = KeWaitForSingleObject(
&deviceExtension->SelfRequestedPowerIrpEvent,
Suspended,
KernelMode,
FALSE,
NULL
);
}
ntStatus = STATUS_SUCCESS;
deviceExtension->SelfPowerIrp = FALSE;
USBLS120_KdPrint( DBGLVL_HIGH, ("USBLS120_SelfRequestPowerIrp() SUCCESS\n IRP 0x%x to state %s\n",
pIrp, USBLS120_StringForDevState(PowerState.DeviceState) ));
}
else {
// The return status was not STATUS_PENDING; any other codes must be considered in error here;
// i.e., it is not possible to get a STATUS_SUCCESS or any other non-error return from this call;
USBLS120_KdPrint( DBGLVL_HIGH, ("USBLS120_SelfRequestPowerIrp() to state %s FAILED, status = 0x%x\n",
USBLS120_StringForDevState( PowerState.DeviceState ),ntStatus));
}
return ntStatus;
}
NTSTATUS
USBLS120_PoSelfRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
/*++
Routine Description:
This routine is called when the driver completes a self-originated power IRP
that was generated by a call to USBLS120_SelfSuspendOrActivate().
We power down whenever the last pipe is closed and power up when the first pipe is opened.
For power-up , we set an event in our FDO extension to signal this IRP done
so the power request can be treated as a synchronous call.
We need to know the device is powered up before opening the first pipe, for example.
For power-down, we do not set the event, as no caller waits for powerdown complete.
Arguments:
DeviceObject - Pointer to the device object for the class device. ( Physical Device Object )
Context - Driver defined context, in this case our FDO ( functional device object )
Return Value:
The function value is the final status from the operation.
--*/
{
PDEVICE_OBJECT deviceObject = Context;
PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension;
NTSTATUS ntStatus = IoStatus->Status;
// we should not be in the midst of handling a system-generated power irp
USBLS120_ASSERT( NULL == deviceExtension->PowerIrp );
// We only need to set the event if we're powering up;
// No caller waits on power down complete
if ( (ULONG) PowerState.DeviceState < deviceExtension->PowerDownLevel ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -