How are power buttons reported in Windows?

There are a few different possible types of power related buttons on a PC. There is the
button on the case itself. If you have a laptop, there is a lid switch to detect
state change in the lid. There are also power keys on a keyboard. All of these buttons
have different underylying physical connections to the PC, but each reports the
button press in the same way.

The definitions for all of the constants mentioned in this post can be found in
poclass.h in the DDK. There are 2 IOCTLs that the power manager uses for detecting power buttons
and knowing when they are pressed.

IOCTL_GET_SYS_BUTTON_CAPS

This is used to find out
what buttons are present. The buffer is a ULONG and is treated as a bitfield. You can
report the following flags: SYS_BUTTON_POWER, SYS_BUTTON_SLEEP,
SYS_BUTTON_WAKE (which is 0x0, so really it is a nop), and SYS_BUTTON_LID.
If you are responding to this IOCTL, you should only set the flags for the buttons
that are present, otherwise the UI will present the user with an option to map a button to a
power action, but that button will not exist! This IOCTL is completed immediately. If completed
with an error NTSTATUS, the power manager will close your device and not send the
second IOCTL.

IOCTL_GET_SYS_BUTTON_EVENT

This is used to report the actual button press. It's buffer is also a ULONG and is also
treated as a bit field. It uses the same flag values as the first IOCTL. This
PIRP is pended until the actual power button has been pressed. When completing
this PIRP, you set the appropriate flag in the buffer indicating which button was pressed.
The power manager will then process the power button event and do the right thing according to the system
and the user's policy.

If you report SYS_BUTTON_LID, then there are additional flags that you can specify in the ULONG:
SYS_BUTTON_LID_OPEN, SYS_BUTTON_LID_CLOSED, SYS_BUTTON_LID_INITIAL, SYS_BUTTON_LID_CHANGED.
The open and closed flags are obvious in how they are used. You set SYS_BUTTON_LID_INITIAL
when first reporting the lid state or coming out of low power so that the OS can
know what the initial lid state is. For instance, this allows you to report the lid as closed
and still boot up without immediately shutting down again. SYS_BUTTON_LID_CHANGED is
used to report a change in the previous lid state.

Opening a power button source

So now we know how the buttons are reported, but how does the power manager
even know to ask your driver if it has power buttons? Well, it registers for
notification arrival for two different device interface GUIDs and when either
appears, it opens up the interface and sends the IOCTLs. The first device interface
the power manager listens for, GUID_DEVICE_SYS_BUTTON, is dedicated to reporting
power butttons. The second interface GUID is GUID_CLASS_INPUT, the HID interface.
This means that every HID device, whether or not it has power buttons on it, will be
opened and queried by the power manager! If you want to expose power buttons,
I would suggest registering the GUID_DEVICE_SYS_BUTTON interface GUID and keep things simple.

My next entry will explain how the two different types of keyboards (PS2 and HID)
detect and report power buttons.