📄 usb.c
字号:
); // returns TRUE for D0
IoCopyCurrentIrpStackLocationToNext(Irp);
if (fGoingToD0) {
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPowerIrp() Set PowerIrp Completion Routine, fGoingToD0 =%d\n", fGoingToD0));
IoSetCompletionRoutine(Irp,
USB_PowerIrp_Complete,
// Always pass FDO to completion routine as its Context;
// This is because the DriverObject passed by the system to the routine
// is the Physical Device Object ( PDO ) not the Functional Device Object ( FDO )
DeviceObject,
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
}
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
if ( !fGoingToD0 ) // completion routine will decrement
USB_DecrementIoCount(DeviceObject);
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPowerIrp() Exit IRP_MN_SET_POWER\n"));
break;
} /* case irpStack->Parameters.Power.Type */
}
break; /* IRP_MN_SET_POWER */
case IRP_MN_QUERY_POWER:
//
// A power policy manager sends this IRP to determine whether it can change
// the system or device power state, typically to go to sleep.
//
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPowerIrp() IRP_MN_QUERY_POWER\n"));
// We do nothing special here, just let the PDO handle it
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);
USB_DecrementIoCount(DeviceObject);
break; /* IRP_MN_QUERY_POWER */
default:
USB_KdPrint( DBGLVL_MEDIUM,("USB_ProcessPowerIrp() UNKNOWN POWER MESSAGE (%x)\n", irpStack->MinorFunction));
//
// All unhandled power messages are passed on to the PDO
//
IoCopyCurrentIrpStackLocationToNext(Irp);
PoStartNextPowerIrp(Irp);
ntStatus = PoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
USB_DecrementIoCount(DeviceObject);
} /* irpStack->MinorFunction */
USB_KdPrint( DBGLVL_MEDIUM, ( "Exit USB_ProcessPowerIrp() ntStatus = 0x%x\n", ntStatus ) );
return ntStatus;
}
NTSTATUS
USB_PoRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP irp;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_OBJECT deviceObject = Context;
NTSTATUS ntStatus;
deviceExtension = deviceObject->DeviceExtension;
// Get the Irp we saved for later processing in USB_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;
USB_KdPrint( DBGLVL_HIGH,("Enter USB_PoRequestCompletion()\n"));
// we should not be in the midst of handling a self-generated power irp
USB_ASSERT( !deviceExtension->SelfPowerIrp );
// we must pass down to the next driver in the stack
IoCopyCurrentIrpStackLocationToNext(irp);
PoStartNextPowerIrp(irp);
PoCallDriver(deviceExtension->TopOfStackDeviceObject,
irp);
USB_DecrementIoCount(deviceObject);
USB_KdPrint( DBGLVL_MEDIUM,("USB_PoRequestCompletion() Exit IRP_MN_SET_POWER\n"));
deviceExtension->PowerIrp = NULL;
return ntStatus;
}
NTSTATUS
USB_PowerIrp_Complete(
IN PDEVICE_OBJECT NullDeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject;
PIO_STACK_LOCATION irpStack;
PDEVICE_EXTENSION deviceExtension;
USB_KdPrint( DBGLVL_HIGH,("enter USB_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
USB_ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
USB_ASSERT(irpStack->MinorFunction == IRP_MN_SET_POWER);
USB_ASSERT(irpStack->Parameters.Power.Type==DevicePowerState);
USB_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;
USB_DecrementIoCount(deviceObject);
USB_KdPrint( DBGLVL_MEDIUM,("exit USB_PowerIrp_Complete Exit IRP_MN_SET_POWER D0 complete\n"));
return ntStatus;
}
NTSTATUS
USB_SelfSuspendOrActivate(
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN fSuspend
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
POWER_STATE PowerState;
PDEVICE_EXTENSION deviceExtension;
deviceExtension = DeviceObject->DeviceExtension;
USB_KdPrint( DBGLVL_MAXIMUM,("Enter USB_SelfSuspendOrActivate(),fSuspend = %d\n", fSuspend));
return STATUS_SUCCESS;
if ( !USB_CanAcceptIoRequests( DeviceObject ) ) {
ntStatus = STATUS_DELETE_PENDING;
USB_KdPrint( DBGLVL_MEDIUM,("ABORTING USB_SelfSuspendOrActivate()\n"));
return ntStatus;
}
// don't do anything if any System-generated Device Pnp irps are pending
if ( NULL != deviceExtension->PowerIrp ) {
USB_KdPrint( DBGLVL_MAXIMUM,("Exit USB_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 ) {
USB_KdPrint( DBGLVL_MAXIMUM,("Exit USB_SelfSuspendOrActivate(),refusing on pending deviceExtension->SelfPowerIrp\n" ));
return ntStatus;
}
// don't auto-suspend if any pipes are open
if ( fSuspend && ( 0 != deviceExtension->OpenPipeCount ) ) {
USB_KdPrint( DBGLVL_MAXIMUM,("Exit USB_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 ) ) {
USB_KdPrint( DBGLVL_MAXIMUM,("Exit USB_SelfSuspendOrActivate(),refusing to self-activate, no pipes open\n"));
return ntStatus;
}
// dont do anything if registry CurrentControlSet\Services\USB\Parameters\PowerDownLevel
// has been set to zero, PowerDeviceD0 ( 1 ), or a bogus high value
if ( ( deviceExtension->PowerDownLevel == PowerDeviceD0 ) ||
( deviceExtension->PowerDownLevel == PowerDeviceUnspecified) ||
( deviceExtension->PowerDownLevel >= PowerDeviceMaximum ) ) {
USB_KdPrint( DBGLVL_MAXIMUM,("Exit USB_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 = USB_SelfRequestPowerIrp( DeviceObject, PowerState );
USB_KdPrint( DBGLVL_MAXIMUM,("USB_SelfSuspendOrActivate() status 0x%x on setting dev state %s\n", ntStatus, USB_StringForDevState(PowerState.DeviceState ) ));
return ntStatus;
}
NTSTATUS
USB_SelfRequestPowerIrp(
IN PDEVICE_OBJECT DeviceObject,
IN POWER_STATE PowerState
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
PIRP pIrp = NULL;
deviceExtension = DeviceObject->DeviceExtension;
// This should have been reset in completion routine
USB_ASSERT( !deviceExtension->SelfPowerIrp );
if ( deviceExtension->CurrentDevicePowerState == PowerState.DeviceState )
return STATUS_SUCCESS; // nothing to do
USB_KdPrint( DBGLVL_HIGH,("Enter USB_SelfRequestPowerIrp() will request power irp to state %s\n",
USB_StringForDevState( PowerState.DeviceState )));
USB_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,
USB_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;
USB_KdPrint( DBGLVL_HIGH, ("USB_SelfRequestPowerIrp() SUCCESS\n IRP 0x%x to state %s\n",
pIrp, USB_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;
USB_KdPrint( DBGLVL_HIGH, ("USB_SelfRequestPowerIrp() to state %s FAILED, status = 0x%x\n",
USB_StringForDevState( PowerState.DeviceState ),ntStatus));
}
return ntStatus;
}
NTSTATUS
USB_PoSelfRequestCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus
)
{
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
USB_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 ) {
// Trigger Self-requested power irp completed event;
// The caller is waiting for completion
KeSetEvent(&deviceExtension->SelfRequestedPowerIrpEvent, 1, FALSE);
}
USB_DecrementIoCount(deviceObject);
USB_KdPrintCond( DBGLVL_HIGH, !NT_SUCCESS(ntStatus),("Exit USB_PoSelfRequestCompletion() FAILED, ntStatus = 0x%x\n", ntStatus ));
return ntStatus;
}
BOOLEAN
USB_SetDevicePowerState(
IN PDEVICE_OBJECT DeviceObject,
IN DEVICE_POWER_STATE DeviceState
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION deviceExtension;
BOOLEAN fRes = FALSE;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
switch (DeviceState) {
case PowerDeviceD3:
//
// Device will be going OFF,
// TODO: add any needed device-dependent code to save state here.
// ( We have nothing to do in this sample )
//
USB_KdPrint( DBGLVL_MEDIUM,("USB_SetDevicePowerState() PowerDeviceD3 (OFF)\n"));
deviceExtension->CurrentDevicePowerState = DeviceState;
break;
case PowerDeviceD1:
case PowerDeviceD2:
//
// power states D1,D2 translate to USB suspend
USB_KdPrint( DBGLVL_MEDIUM,("USB_SetDevicePowerState() %s\n",
USB_StringForDevState(DeviceState) ));
deviceExtension->CurrentDevicePowerState =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -