Previous Next

PoCallDriver

The PoCallDriver routine passes a power IRP to the next-lower driver in the device stack.

NTSTATUS
  PoCallDriver(
    IN PDEVICE_OBJECT  DeviceObject,
    IN OUT PIRP  Irp
    );

Parameters

DeviceObject
Pointer to the driver-created DEVICE_OBJECT to which the IRP is to be routed.
Irp
Pointer to an IRP.

Return Value

PoCallDriver returns STATUS_SUCCESS to indicate success. It returns STATUS_PENDING if it has queued the IRP.

Headers

Declared in wdm.h and ntddk.h. Include wdm.h or ntddk.h.

Comments

Drivers call PoCallDriver — not IoCallDriver — to pass a power IRP to the next-lower driver. Drivers must call PoStartNextPowerIrp before calling PoCallDriver.

A driver that requires a new IRP should call PoRequestPowerIrp. A driver must not allocate its own power IRP.

When passing a power IRP down to the next-lower driver, the caller should use IoSkipCurrentIrpStackLocation or IoCopyCurrentIrpStackLocationToNext to set the IRP stack location, then call PoCallDriver. Use IoCopyCurrentIrpStackLocationToNext if processing the IRP requires setting an IoCompletion routine, or IoSkipCurrentStackLocation if no IoCompletion routine is required.

When a device is powering up, its drivers must set IoCompletion routines to perform start-up tasks (initializing the device, restoring context, and so on) after the bus driver has set the device in the working state. Set IoCompletion routines before calling PoCallDriver.

When a device is powering down, its drivers must perform necessary power-down tasks before passing the IRP to the next lower driver. After the IRP has reached the bus driver, the device will be powered off and its drivers will no longer have access to it. An IoCompletion routine associated with a power-down IRP should simply call PoStartNextPowerIrp.

Only one inrush IRP can be active in the system at a time. When passing a power-up IRP for a device that requires inrush current (in other words, the DO_POWER_INRUSH flag is set in the device object), PoCallDriver checks whether another inrush IRP is already active. If so, PoCallDriver queues the current IRP for handling after the previous IRP completes, and then returns STATUS_PENDING. For more information on inrush IRPs, see Setting Device Object Flags for Power Management.

If an IRP_MN_SET_POWER or IRP_MN_QUERY_POWER request is already active for DeviceObject, PoCallDriver queues this IRP and returns STATUS_PENDING.

On Windows® 2000 and later systems, pagable drivers (the DO_POWER_PAGABLE flag is set in the device object) must call PoCallDriver at IRQL = PASSIVE_LEVEL. Drivers that can not be paged (DO_POWER_PABABLE is not set in the device object) or that require inrush current (DO_POWER_INRUSH is set in the device object) can call PoCallDriver at IRQL = PASSIVE_LEVEL or DISPATCH_LEVEL.

On Windows 98/Me, all drivers call PoCallDriver at IRQL = PASSIVE_LEVEL.

See Also

IoCallDriver, IoCompletion, IoCopyCurrentIrpStackLocationToNext, IoSkipCurrentIrpStackLocation, IRP, IRP_MN_QUERY_POWER, IRP_MN_SET_POWER, PoRequestPowerIrp, PoStartNextPowerIrp