wakeup_clock: tool to set the wakeup time on ATX mainboards

Most current PCs offer the possibility of automatic wakeup. A certain wakeup time, typically within one month in the future, can be set up from within the BIOS. At this time the PC will restart automatically, as long as it has been shut down by the APM poweroff function (and the power has not been turned off). Usually, only the day of month and the HH:MM:SS time of day can be set for a future wakeup.

wakeup_clock is a tool to set up this date and time from the running system, such that a specific downtime can be scheduled without having to turn the system back on manually. During the downtime, only the standby power of the ATX power supply is consumed.

Unfortunately, there is absolutely no standard which CMOS registers need to be set up to achieve automatic wakeup, each mainboard vendor has implemented this differently.

Note: Just turning the PC off manually will normally not work, it has to be shut down by the APM or (preferably, and on some boards necessarily) the ACPI poweroff function.

Supported boards and systems

Currently (Dec 31st 2006) wakeup_clock attempts to support only the following mainboards: (product names are properties of their respective owners and are acknowledged) Hopefully this list will grow further; see below for what information is required to add support for other boards.

I'm compiling and running wakeup_clock on ix86-Linux only, however apart from the cmos_..() routines (which use outb()) and the reading of the /dev/mem special file to identify the board, there is nothing that would prevent a port to other systems. Patches are always welcome.

Please note that wakeup_clock always must be run as root. On some boards, it is required to run with ACPI enabled (e.g. I had to boot with acpi=force for the MSI K8T Neo-V). In some particular cases, after running wakeup_clock it is unfortunately necessary to complete a reboot cycle before the changed wakeup time actually takes effect.

Usage

Usage  : wakeup_clock [date_string]
  note : date_string interpreted in local time
Example: wakeup_clock "4/5 14:15"

wakeup_clock takes a single argument, a date string. This string must be in a format understood by the date program, and usually needs to be quoted to prevent the shell from creating multiple arguments. In the example above, the wakeup time would be April 5th at 2:15 pm.

Using the date program has the advantage of extensive parsing capabilities, and that the time can be specified in the local time zone. wakeup_clock automatically detects (via the third line of the /etc/adjtime file) whether the BIOS clock is set to UTC (like it should be!) and computes the proper BIOS time which is eventually written to the board-specific CMOS registers.

Note that wakeup_clock currently does not activate the "automatic wakeup" feature (you have to do that yourself in the BIOS once), it only sets the date and time at which an automatic wakeup will occur if enabled. There are also no sanity checks whether the specified time is actually in the future, and less than a month in the future; the month is simply not used.

How to add support for a new board

It is relatively easy to add support for a new mainboard. Simply turn on the automatic wakeup feature in the board's BIOS, and set up an easily recognizable wakeup time, e.g. day=10 and time=11:12:13. Then run
wakeup_clock -d >d10
to capture the CMOS state in the file d10. Reboot, and change the wakeup time from the BIOS to another time, e.g. day=11, time=12:13:14. Then run
wakeup_clock -d >d11
once more. Now
diff d1 d2
should show exactly which registers hold the date and time information. Often there is also a checksum register that is changed as well--in the example above the checksum would increase by 4 (modulo 256).

Be careful when experimenting with the CMOS registers. Setting the wrong registers randomly might cause instability and necessitate a clearing of the CMOS in hardware!

Finally, a string in the BIOS needs to be found (e.g. from the boot screen) that uniquely identifies the mainboard. This string can then be looked for in the output of

dd if=/dev/mem bs=1 skip=983040 count=256000
(hint: 983040 is 0xF0000) e.g. with a hex editor, in order to compute the exact offset for struct board_entry.

Please send information and patches to the address below. Thanks.

Source code for wakeup_clock

Currently there is only a single source file, wakeup_clock.c, which needs to be compiled like
gcc -O wakeup_clock.c -o wakeup_clock
You need the C library's development headers, including < asm/...> installed. For your convenience, a binary for glibc-2.2.4 or later is available here.

License

wakeup_clock is distributed under the GNU General Public License. In particular, it is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Wolfram Gloger