Advanced Configuration and Power Interface, or ACPI, is an open standard created to provide an easy and uniform way of configuration and power management.

Linux has a userspace daemon, acpid, that provides ACPI services to the operating system. This daemon works by hooking into the Linux kernel and reading events that come across as certain things happen, such as AC adapters being plugged in, laptop lids being closed, or power buttons being pressed.

A lot of us just rely on our distribution supporting some of these things by default, which isn’t always the case! However we can write our own ACPI handlers very easily, and get our laptop working the way we want!

Determining the ACPI event you want to hook

First, we have to know what we want to hook. Myself, I have a Lenovo W530 and a series 3 dock that I want to adjust a display for. When I dock my laptop, I want my operating system to fill all 3 of my monitors. When I pull the laptop off of the dock, I want the operating system to switch to only one monitor.

This is actually easier than it sounds. First, let’s investigate the acpi_listen command. acpi_listen will listen to the ACPI events that come across the kernel message interface, and print them on screen. Try it yourself! Run acpi_listen, and perform some action, like say, raising the volume on your laptop, or plug in your ac adapter. You should see something like this:

davidi@david-thinkpad:~$ acpi_listen
processor LNXCPU:00 00000080 00000005
processor LNXCPU:01 00000080 00000005
processor LNXCPU:02 00000080 00000005
processor LNXCPU:03 00000080 00000005
processor LNXCPU:04 00000080 00000005
processor LNXCPU:05 00000080 00000005
processor LNXCPU:06 00000080 00000005
processor LNXCPU:07 00000080 00000005
ac_adapter ACPI0003:00 00000080 00000000
ibm/hotkey LEN0068:00 00000080 00006030
thermal_zone LNXTHERM:00 00000081 00000000
battery PNP0C0A:00 00000080 00000001
battery PNP0C0A:00 00000080 00000001

Here, I plugged in my AC adapter, and got a ton of events! Looking closely, there is our ac_adapter event, and there’s a few other events, like one for the battery (probably a battery charging event).

If I place my laptop on the dock, I notice the following:

ibm/hotkey LEN0068:00 00000080 00004010

And when I remove my laptop from my dock, I see the following message pass through acpid:

ibm/hotkey LEN0068:00 00000080 00004011

This gives us enough information to hook into these events.

Creating a hook for your ACPI event

Now, we just need to tell acpid what to do when our event passes over the kernel acpi message interface. I will make a quick configuration file in /etc/acpi/events/lenovo-undock:

event=ibm/hotkey LEN0068:00 00000080 00004011
action=su davidi -c /etc/acpi/single_monitor.sh

I wrote a quick script called /etc/acpi/single_monitor.sh using the output of ARandR to disable my two other external monitors. Now, I’m going to handle lenovo-dock similarly:

event=ibm/hotkey LEN0068:00 00000080 00004010
action=su davidi -c /etc/acpi/triple_monitor.sh

ARandR is very easy to use. It has an X interface that you can drag windows around, and save their configuration as a series of xrandr commands. Note that I am the only user on this laptop, so I have no problems su’ing to my user. You may need to come up with something a little more complex for multi-user environments.

Now, when I take my laptop off of its dock and place it back on, my screens automatically reconfigure themselves correctly! This is just the tip of the iceberg when it comes to ACPI events. You can do things like scale the frequency of your CPU down or prevent intensive crons from running when you switch off AC power, or get those buttons working on your laptop that didn’t work before.

Scripting with ACPI