/*++ Copyright (c) 1997 Microsoft Corporation Module Name: power.c Abstract: Author: Environment: kernel mode only Notes: Revision History: --*/ #include #include "stddef.h" #include "wdm.h" #include "usbscan.h" #include "usbd_api.h" #include "private.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, USPower) #endif NTSTATUS USPower( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Process the Power IRPs sent to the PDO for this device. Arguments: pDeviceObject - pointer to the functional device object (FDO) for this device. pIrp - pointer to an I/O Request Packet Return Value: NT status code --*/ { NTSTATUS Status; PUSBSCAN_DEVICE_EXTENSION pde; PIO_STACK_LOCATION pIrpStack; BOOLEAN hookIt = FALSE; POWER_STATE powerState; PAGED_CODE(); DebugTrace(TRACE_PROC_ENTER,("USPower: Enter... \n")); // // Check arguments. // if( (NULL == pDeviceObject) || (NULL == pDeviceObject->DeviceExtension) || (NULL == pIrp) ) { DebugTrace(TRACE_ERROR,("USPower: ERROR!! Invalid parameter passed.\n")); Status = STATUS_INVALID_PARAMETER; DebugTrace(TRACE_PROC_LEAVE,("USPower: Leaving.. Status = %x.\n", Status)); return Status; } USIncrementIoCount(pDeviceObject); pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension; pIrpStack = IoGetCurrentIrpStackLocation( pIrp ); Status = STATUS_SUCCESS; switch (pIrpStack -> MinorFunction) { case IRP_MN_SET_POWER: DebugTrace(TRACE_STATUS,("USPower: IRP_MN_SET_POWER\n")); switch (pIrpStack -> Parameters.Power.Type) { case SystemPowerState: DebugTrace(TRACE_STATUS,("USPower: SystemPowerState\n")); // // find the device power state equivalent to the given system state // DebugTrace(TRACE_STATUS,("USPower: Set Power, SystemPowerState (%d)\n", pIrpStack -> Parameters.Power.State.SystemState)); if (pIrpStack -> Parameters.Power.State.SystemState == PowerSystemWorking) { powerState.DeviceState = PowerDeviceD0; } else if (/* pde ->EnabledForWakeup */ FALSE) { DebugTrace(TRACE_STATUS,("USPower: USBSCAN always enabled for wakeup\n")); powerState.DeviceState = pde -> DeviceCapabilities.DeviceState[pIrpStack->Parameters.Power.State.SystemState]; } else { // // wakeup not enabled, just go in to the 'OFF' state. // powerState.DeviceState = PowerDeviceD3; } //irpStack->Parameters.Power.State.SystemState // // are we already in this state? // if (powerState.DeviceState != pde -> CurrentDevicePowerState) { // // No, request that we be put into this state // DebugTrace(TRACE_STATUS,("USPower: Requesting powerstate %d\n", powerState.DeviceState)); IoMarkIrpPending(pIrp); pde -> pPowerIrp = pIrp; Status = PoRequestPowerIrp(pde -> pPhysicalDeviceObject, IRP_MN_SET_POWER, powerState, USPoRequestCompletion, pDeviceObject, NULL); if (!NT_SUCCESS(Status)) { // // Allocation failed, we must complete the IRP // ourselves. // PoStartNextPowerIrp(pIrp); IoCompleteRequest(pIrp, IO_NO_INCREMENT); USDecrementIoCount(pDeviceObject); } // // We marked the IRP pending, so we must return // STATUS_PENDING (our caller will examine // Irp->IoStatus.Status) // Status = STATUS_PENDING; } else { // // Yes, just pass it on // IoCopyCurrentIrpStackLocationToNext(pIrp); PoStartNextPowerIrp(pIrp); Status = PoCallDriver(pde -> pStackDeviceObject, pIrp); USDecrementIoCount(pDeviceObject); } break; case DevicePowerState: DebugTrace(TRACE_STATUS,("USPower: DevicePowerState\n")); Status = USSetDevicePowerState(pDeviceObject, pIrpStack -> Parameters.Power.State.DeviceState, &hookIt); IoCopyCurrentIrpStackLocationToNext(pIrp); if (hookIt) { DebugTrace(TRACE_STATUS,("USPower: Set PowerIrp Completion Routine\n")); IoSetCompletionRoutine(pIrp, USPowerIrpComplete, // always pass FDO to completion routine pDeviceObject, hookIt, hookIt, hookIt); } PoStartNextPowerIrp(pIrp); Status = PoCallDriver(pde ->pStackDeviceObject, pIrp); if (!hookIt) { USDecrementIoCount(pDeviceObject); } break; } /* case irpStack->Parameters.Power.Type */ break; /* IRP_MN_SET_POWER */ case IRP_MN_QUERY_POWER: DebugTrace(TRACE_STATUS,("USPower: IRP_MN_QUERY_POWER\n")); IoCopyCurrentIrpStackLocationToNext(pIrp); PoStartNextPowerIrp(pIrp); Status = PoCallDriver(pde -> pStackDeviceObject, pIrp); USDecrementIoCount(pDeviceObject); break; /* IRP_MN_QUERY_POWER */ default: DebugTrace(TRACE_STATUS,("USPower: Unknown power message (%x)\n",pIrpStack->MinorFunction)); IoCopyCurrentIrpStackLocationToNext(pIrp); PoStartNextPowerIrp(pIrp); Status = PoCallDriver(pde -> pStackDeviceObject, pIrp); USDecrementIoCount(pDeviceObject); } /* pIrpStack -> MinorFunction */ DebugTrace(TRACE_PROC_LEAVE,("USPower: Leaving... Status = 0x%x\n", Status)); return Status; } NTSTATUS USPoRequestCompletion( IN PDEVICE_OBJECT pPdo, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PDEVICE_OBJECT pDeviceObject, IN PIO_STATUS_BLOCK pIoStatus ) /*++ Routine Description: This routine is called when the port driver completes an IRP. Arguments: Return Value: The function value is the final status from the operation. --*/ { NTSTATUS Status; PUSBSCAN_DEVICE_EXTENSION pde; PIRP pIrp; DebugTrace(TRACE_PROC_ENTER,("USPoRequestCompletion: Enter...\n")); pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension; pIrp = pde -> pPowerIrp; Status = pIoStatus -> Status; IoCopyCurrentIrpStackLocationToNext(pIrp); PoStartNextPowerIrp(pIrp); PoCallDriver(pde -> pStackDeviceObject, pIrp); USDecrementIoCount(pDeviceObject); DebugTrace(TRACE_PROC_LEAVE,("USPoRequestCompletion: Leaving... Status = 0x%x\n", Status)); return Status; } USPowerIrpComplete( IN PDEVICE_OBJECT pPdo, IN PIRP pIrp, IN PDEVICE_OBJECT pDeviceObject ) /*++ Routine Description: This routine is called when the port driver completes an IRP. Arguments: Return Value: The function value is the final status from the operation. --*/ { NTSTATUS Status; PUSBSCAN_DEVICE_EXTENSION pde; PIO_STACK_LOCATION pIrpStack; DebugTrace(TRACE_PROC_ENTER,("USPowerIrpComplete: Enter...\n")); pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension; Status = STATUS_SUCCESS; if (pIrp -> PendingReturned) { IoMarkIrpPending(pIrp); } pIrpStack = IoGetCurrentIrpStackLocation (pIrp); ASSERT(pIrpStack -> MajorFunction == IRP_MJ_POWER); ASSERT(pIrpStack -> MinorFunction == IRP_MN_SET_POWER); ASSERT(pIrpStack -> Parameters.Power.Type == DevicePowerState); ASSERT(pIrpStack -> Parameters.Power.State.DeviceState == PowerDeviceD0); pde -> AcceptingRequests = TRUE; pde -> CurrentDevicePowerState = PowerDeviceD0; pIrp -> IoStatus.Status = Status; USDecrementIoCount(pDeviceObject); DebugTrace(TRACE_PROC_LEAVE,("USPowerIrpComplete: Leaving... Status = 0x%x\n", Status)); return Status; } NTSTATUS USSetDevicePowerState( IN PDEVICE_OBJECT pDeviceObject, IN DEVICE_POWER_STATE DeviceState, IN PBOOLEAN pHookIt ) /*++ Routine Description: Arguments: pDeviceObject - Pointer to the device object for the class device. DeviceState - Device specific power state to set the device in to. Return Value: --*/ { NTSTATUS Status; PUSBSCAN_DEVICE_EXTENSION pde; DebugTrace(TRACE_PROC_ENTER,("USSetDevicePowerState: Enter...\n")); pde = (PUSBSCAN_DEVICE_EXTENSION)pDeviceObject -> DeviceExtension; Status = STATUS_SUCCESS; switch (DeviceState) { case PowerDeviceD3: // ASSERT(pde -> AcceptingRequests); // pde -> AcceptingRequests = FALSE; // USCancelPipe(pDeviceObject, ALL_PIPE, TRUE); // pde -> CurrentDevicePowerState = DeviceState; // break; case PowerDeviceD1: case PowerDeviceD2: #if DBG if (DeviceState) { DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD3 (OFF)\n")); } else { DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD1/D2 (SUSPEND)\n")); } #endif USCancelPipe(pDeviceObject, NULL, ALL_PIPE, TRUE); // // power states D1,D2 translate to USB suspend // D3 transltes to OFF pde -> CurrentDevicePowerState = DeviceState; break; case PowerDeviceD0: DebugTrace(TRACE_STATUS,("USSetDevicePowerState: PowerDeviceD0 (ON)\n")); // // finish the rest in the completion routine // *pHookIt = TRUE; // pass on to PDO break; default: DebugTrace(TRACE_WARNING,("USSetDevicePowerState: Bogus DeviceState = %x\n", DeviceState)); } DebugTrace(TRACE_PROC_LEAVE,("USSetDevicePowerState: Leaving... Status = 0x%x\n", Status)); return Status; }