|
#include "ProtoTypes.h"
#pragma alloc_text(PAGE, InitPowerManagement)
#pragma alloc_text(PAGE, EvtDeviceD0Entry)
#pragma alloc_text(PAGE, EvtDeviceD0Exit)
#pragma alloc_text(PAGE, PowerName)
/*............................................................................*/
/* this function is called when the device is either started or woken up. */
/*............................................................................*/
NTSTATUS
EvtDeviceD0Entry(
IN WDFDEVICE Device,
IN WDF_POWER_DEVICE_STATE PreviousState
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_CONTEXT devCtx = NULL;
KdPrint((__DRIVER_NAME "Device D0 Entry. Coming from %s\n",
PowerName(PreviousState)));
devCtx = GetDeviceContext(Device);
status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(devCtx->UsbInterruptPipe));
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
"WdfIoTargetStart failed with status 0x%08x\n", status));
return status;
}
/*restore the state of the LED array if the device is waking up from a
D3 power state.*/
if(PreviousState == PowerDeviceD3)
{
status = llSetLightBar(devCtx, devCtx->WdfMemLEDArrayState);
}
return status;
}
/*............................................................................*/
/* this function is called when the device is powered down. */
/* the current IO is left pending, because otherwise the continuous interrupt */
/* read IO will also be cancelled, and it would have to be reconfigured. */
/*............................................................................*/
NTSTATUS
EvtDeviceD0Exit(
IN WDFDEVICE Device,
IN WDF_POWER_DEVICE_STATE TargetState
)
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_CONTEXT devCtx = NULL;
devCtx = GetDeviceContext(Device);
KdPrint((__DRIVER_NAME "Device D0 Exit. Going to %s\n",
PowerName(TargetState)));
/*save the state of the LED array if the device is waking up from a
D3 power state.*/
if(TargetState == PowerDeviceD3)
{
status = llGetLightBar(devCtx, devCtx->WdfMemLEDArrayState);
if(!NT_SUCCESS(status))
return status;
}
WdfIoTargetStop(WdfUsbTargetPipeGetIoTarget(devCtx->UsbInterruptPipe),
WdfIoTargetLeaveSentIoPending);
return status;
}
/*............................................................................*/
/* initialize the power management functionality of our USB device. */
/* we want it to support system wake-up with the on-board switch, and */
/* idle- time sleep that puts the device into a sleeping state if it is */
/* idle for a specified duration. */
/*............................................................................*/
NTSTATUS
InitPowerManagement(
IN WDFDEVICE Device,
IN PDEVICE_CONTEXT Context)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_USB_DEVICE_INFORMATION usbInfo;
KdPrint((__DRIVER_NAME "Device init power management\n"));
WDF_USB_DEVICE_INFORMATION_INIT(&usbInfo);
status = WdfUsbTargetDeviceRetrieveInformation(
Context->UsbDevice,
&usbInfo);
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
"WdfUsbTargetDeviceRetrieveInformation failed with status 0x%08x\n",
status));
return status;
}
KdPrint((__DRIVER_NAME "Device self powered: %d",
usbInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED ? 1 : 0));
KdPrint((__DRIVER_NAME "Device remote wake capable: %d",
usbInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE ? 1 : 0));
KdPrint((__DRIVER_NAME "Device high speed: %d",
usbInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED ? 1 : 0));
if(usbInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE)
{
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings;
WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings,
IdleUsbSelectiveSuspend);
idleSettings.IdleTimeout = 10000;
status = WdfDeviceAssignS0IdleSettings(Device, &idleSettings);
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
"WdfDeviceAssignS0IdleSettings failed with status 0x%08x\n",
status));
return status;
}
WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings);
wakeSettings.DxState = PowerDeviceD2;
status = WdfDeviceAssignSxWakeSettings(Device, &wakeSettings);
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
"WdfDeviceAssignSxWakeSettings failed with status 0x%08x\n",
status));
return status;
}
}
return status;
}
/*............................................................................*/
/* for debugging purposes it is nice to be able to print out power state */
/* names so that we can see where we are coming from, and where we are */
/* going to. */
/*............................................................................*/
LPCSTR PowerName(WDF_POWER_DEVICE_STATE PowerState)
{
char * name = "";
switch(PowerState)
{
case PowerDeviceUnspecified: name = "PowerDeviceUnspecified"; break;
case PowerDeviceD0: name = "PowerDeviceD0"; break;
case PowerDeviceD1: name = "PowerDeviceD1"; break;
case PowerDeviceD2: name = "PowerDeviceD2"; break;
case PowerDeviceD3: name = "PowerDeviceD3"; break;
case PowerDeviceMaximum: name = "PowerDeviceMaximum"; break;
default:
name = "PowerDeviceUnknown"; break;
}
return name;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I am a former professional software developer (now a system admin) with an interest in everything that is about making hardware work. In the course of my work, I have programmed device drivers and services on Windows and linux.
I have written firmware for embedded devices in C and assembly language, and have designed and implemented real-time applications for testing of satellite payload equipment.
Generally, finding out how to interface hardware with software is my hobby and job.