apm(8): Remove support for APM BIOS

Drop support for queries and commands that are not supported by ACPI's
/dev/apm interface.  This includes dropping support for
enabling/disabling APM BIOS used by /etc/rc.d/apm.

Reviewed by:	ziaee, imp
Differential Revision:	https://reviews.freebsd.org/D59941
This commit is contained in:
John Baldwin committed 2026-09-30 12:21:45 -04:00
1 parent 8cf4fe39e8
commit 40ce54ccd9
7 files changed
+26 -394

No files matched your search

+3
View File
@@ -51,6 +51,9 @@
# xargs -n1 | sort | uniq -d;
# done
# 20260930: apm(8) only displays ACPI status
OLD_FILES+=etc/rc.d/apm
# 20260930: apm(4) not i386-specific
OLD_FILES+=usr/share/man/man4/i386/apm.4.gz
-6
View File
@@ -97,12 +97,6 @@ ACPIPACKAGE= acpi
ACPI= power_profile
.endif
.if ${MACHINE} == "i386"
CONFGROUPS.${MK_APM}+= APM
APMPACKAGE= apm
APM= apm
.endif
CONFGROUPS.${MK_AUDIT}+= AUDIT
AUDITPACKAGE= audit
AUDIT= auditd \
-50
View File
@@ -1,50 +0,0 @@
#!/bin/sh
#
#
# PROVIDE: apm
# REQUIRE: DAEMON
# BEFORE: LOGIN
# KEYWORD: nojail
. /etc/rc.subr
name="apm"
desc="Advanced power management"
rcvar="apm_enable"
start_precmd="apm_precmd"
command="/usr/sbin/${name}"
start_cmd="${command} -e enable"
stop_cmd="${command} -e disable"
status_cmd="apm_status"
apm_precmd()
{
case `${SYSCTL_N} hw.machine_arch` in
i386)
return 0
;;
esac
return 1
}
apm_status()
{
case `${command} -s` in
1)
echo "APM is enabled."
return 0
;;
0)
echo "APM is disabled"
;;
esac
return 1
}
load_rc_config $name
# doesn't make sense to run in a svcj: nojail keyword
apm_svcj="NO"
run_rc_command "$1"
-9
View File
@@ -293,14 +293,6 @@ A list of jail properties for the service.
See
.Sx SERVICE JAILS
for a list of valid properties.
.It Va apm_enable
.Pq Vt bool
If set to
.Dq Li YES ,
enable support for Automatic Power Management with
the
.Xr apm 8
command.
.It Va devd_enable
.Pq Vt bool
Run
@@ -5170,7 +5162,6 @@ to
.Xr security 7 ,
.Xr tuning 7 ,
.Xr accton 8 ,
.Xr apm 8 ,
.Xr bsdinstall 8 ,
.Xr bthidd 8 ,
.Xr chkprintcap 8 ,
+1 -3
View File
@@ -60,10 +60,8 @@ OLD_FILES+=etc/devd/power_profile.conf
.endif
.if ${MK_APM} == no
OLD_FILES+=etc/rc.d/apm
OLD_FILES+=usr/sbin/apm
.elif ${TARGET_ARCH} != "i386"
OLD_FILES+=etc/rc.d/apm
OLD_FILES+=usr/share/man/man8/apm.8.gz
.endif
.if ${MK_AT} == no
+12 -72
View File
@@ -9,25 +9,19 @@
.\" the author assume any responsibility for damages incurred with its
.\" use.
.\"
.Dd September 23, 2026
.Dd September 30, 2026
.Dt APM 8 i386
.Os
.Sh NAME
.Nm apm
.Nd control the APM BIOS and display its information
.Nd display power management status
.Sh SYNOPSIS
.Nm
.Op Fl ablstzZ
.Op Fl d Ar enable
.Op Fl e Ar enable
.Op Fl h Ar enable
.Op Fl r Ar delta
.Op Fl abltzZ
.Sh DESCRIPTION
The
.Nm
utility
controls the Intel / Microsoft APM (Advanced Power Management) BIOS and
displays the current status of APM on laptop PCs.
utility reports power management status.
.Pp
The options are as follows:
.Bl -tag -width indent
@@ -52,49 +46,10 @@ status,
status,
.Dq charging
status respectively.
.It Fl d Ar enable
Disable/enable suspending of the display separately from a normal suspend
using the boolean value for
.Ar enable .
This feature seems to not work on many different laptops,
including the Libretto 30CT and 50CT.
.It Fl e Ar enable
Enable or disable APM functions of the computer,
depending on the boolean
.Ar enable
argument.
.It Fl h Ar enable
Depending on the boolean value of
.Ar enable ,
enable or disable the HLT instruction in the kernel context switch routine.
These options are not necessary for almost all APM implementations,
but for some implementations whose
.Dq Pa Idle CPU
call executes both CPU clock slowdown and HLT instruction,
.Fl h Cm false
is necessary to prevent the system from reducing its peak performance.
See
.Xr apm 4
for details.
.It Fl l
Display the remaining battery percentage.
If your laptop does not
support this function, 255 is displayed.
.It Fl r Ar delta
Enable the resume wakeup timer, if the laptop supports it.
This
does not actually suspend the laptop, but if the laptop is suspended,
and it supports resume from suspend, then it will be resumed after
.Ar delta
seconds (from when you run this command, not from when you suspend).
.It Fl s
Display the status of the APM support as an integer value.
The values
0 and 1 correspond to the
.Dq disabled
state or
.Dq enabled
state respectively.
.It Fl t
Display the estimated remaining battery lifetime in seconds.
If
@@ -103,12 +58,6 @@ it is unknown, -1 is displayed.
Transition the system into standby mode.
This mode uses less power than
full power mode, but more than suspend mode.
Some laptops support
resuming from this state on timer or Ring Indicator events.
The
output of
.Nm
tells what your laptop claims to support.
.It Fl z
Suspend the system.
.El
@@ -119,24 +68,15 @@ displays information and current status of APM in verbose mode.
If multiple display options are given, the values are displayed one
per line in the order given here.
.Sh SEE ALSO
.Xr acpiconf 8 ,
.Xr acpi 4 ,
.Xr apm 4 ,
.Xr zzz 8
.Sh HISTORY
The
.Nm
utility originally controlled the Advanced Power Management (APM) BIOS
extension on i386,
now it interfaces with ACPI.
.Sh AUTHORS
.An Tatsumi Hosokawa Aq Mt [email protected]
.Sh BUGS
Some APM implementations do not support parameters needed by
.Nm .
On such systems,
.Nm
displays them as unknown.
.Pp
Some APM implementations cannot handle events such as pushing the
power button or closing the cover.
On such implementations, the system
.Ar must
be suspended
.Ar only
by using
.Nm
or
.Nm zzz .
+10 -254
View File
@@ -13,103 +13,29 @@
* Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD)
*/
#include <sys/cdefs.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <machine/apm_bios.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define APMDEV "/dev/apm"
#define APM_UNKNOWN 255
#define xh(a) (((a) & 0xff00) >> 8)
#define xl(a) ((a) & 0xff)
#define APMERR(a) xh(a)
static int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */
static void
usage(void)
{
fprintf(stderr,
"usage: apm [-ablstzZ] [-d enable ] [ -e enable ] "
"[ -h enable ] [-r delta]\n");
"usage: apm [-abltzZ]\n");
exit(1);
}
/*
* Return 1 for boolean true, and 0 for false, according to the
* interpretation of the string argument given.
*/
static int
is_true(const char *boolean)
{
char *endp;
long val;
val = strtoul(boolean, &endp, 0);
if (*endp == '\0')
return (val != 0 ? 1 : 0);
if (strcasecmp(boolean, "true") == 0 ||
strcasecmp(boolean, "yes") == 0 ||
strcasecmp(boolean, "enable") == 0)
return (1);
if (strcasecmp(boolean, "false") == 0 ||
strcasecmp(boolean, "no") == 0 ||
strcasecmp(boolean, "disable") == 0)
return (0);
/* Well, I have no idea what the user wants, so... */
warnx("invalid boolean argument \"%s\"", boolean);
usage();
/* NOTREACHED */
return (0);
}
static int
int2bcd(int i)
{
int retval = 0;
int base = 0;
if (i >= 10000)
return -1;
while (i) {
retval |= (i % 10) << base;
i /= 10;
base += 4;
}
return retval;
}
static int
bcd2int(int bcd)
{
int retval = 0;
int place = 1;
if (bcd > 0x9999)
return -1;
while (bcd) {
retval += (bcd & 0xf) * place;
bcd >>= 4;
place *= 10;
}
return retval;
}
static void
apm_suspend(int fd)
{
@@ -131,18 +57,6 @@ apm_getinfo(int fd, apm_info_t aip)
err(1, "ioctl(APMIO_GETINFO)");
}
static void
apm_enable(int fd, int enable)
{
if (enable) {
if (ioctl(fd, APMIO_ENABLE) == -1)
err(1, "ioctl(APMIO_ENABLE)");
} else {
if (ioctl(fd, APMIO_DISABLE) == -1)
err(1, "ioctl(APMIO_DISABLE)");
}
}
static void
print_batt_time(int batt_time)
{
@@ -188,10 +102,8 @@ print_batt_stat(u_int batt_stat)
}
static void
print_all_info(int fd, apm_info_t aip, int bioscall_available)
print_all_info(int fd, apm_info_t aip)
{
struct apm_bios_arg args;
int apmerr;
const char *line_msg[] = { "off-line", "on-line" , "backup power"};
printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor);
@@ -237,69 +149,6 @@ print_all_info(int fd, apm_info_t aip, int bioscall_available)
}
}
if (bioscall_available) {
/*
* try to get the suspend timer
*/
bzero(&args, sizeof(args));
args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
args.ebx = PMDV_APMBIOS;
args.ecx = 0x0001;
if (ioctl(fd, APMIO_BIOS, &args)) {
printf("Resume timer: unknown\n");
} else {
apmerr = APMERR(args.eax);
if (apmerr == 0x0d || apmerr == 0x86)
printf("Resume timer: disabled\n");
else if (apmerr)
warnx(
"failed to get the resume timer: APM error0x%x", apmerr);
else {
/*
* OK. We have the time (all bcd).
* CH - seconds
* DH - hours
* DL - minutes
* xh(SI) - month (1-12)
* xl(SI) - day of month (1-31)
* DI - year
*/
struct tm tm;
char buf[1024];
time_t t;
tm.tm_sec = bcd2int(xh(args.ecx));
tm.tm_min = bcd2int(xl(args.edx));
tm.tm_hour = bcd2int(xh(args.edx));
tm.tm_mday = bcd2int(xl(args.esi));
tm.tm_mon = bcd2int(xh(args.esi)) - 1;
tm.tm_year = bcd2int(args.edi) - 1900;
if (cmos_wall)
t = mktime(&tm);
else
t = timegm(&tm);
if (t != -1) {
tm = *localtime(&t);
strftime(buf, sizeof(buf), "%c", &tm);
printf("Resume timer: %s\n", buf);
} else
printf("Resume timer: unknown\n");
}
}
/*
* Get the ring indicator resume state
*/
bzero(&args, sizeof(args));
args.eax = (APM_BIOS) << 8 | APM_RESUMEONRING;
args.ebx = PMDV_APMBIOS;
args.ecx = 0x0002;
if (ioctl(fd, APMIO_BIOS, &args) == 0) {
printf("Resume on ring indicator: %sabled\n",
args.ecx ? "en" : "dis");
}
}
if (aip->ai_infoversion >= 1) {
if (aip->ai_capabilities == 0xff00)
return;
@@ -324,72 +173,15 @@ print_all_info(int fd, apm_info_t aip, int bioscall_available)
}
/*
* currently, it can turn off the display, but the display never comes
* back until the machine suspend/resumes :-).
*/
static void
apm_display(int fd, int newstate)
{
if (ioctl(fd, APMIO_DISPLAY, &newstate) == -1)
err(1, "ioctl(APMIO_DISPLAY)");
}
static void
apm_haltcpu(int fd, int enable)
{
if (enable) {
if (ioctl(fd, APMIO_HALTCPU, NULL) == -1)
err(1, "ioctl(APMIO_HALTCPU)");
} else {
if (ioctl(fd, APMIO_NOTHALTCPU, NULL) == -1)
err(1, "ioctl(APMIO_NOTHALTCPU)");
}
}
static void
apm_set_timer(int fd, int delta)
{
time_t tmr;
struct tm *tm;
struct apm_bios_arg args;
tmr = time(NULL) + delta;
if (cmos_wall)
tm = localtime(&tmr);
else
tm = gmtime(&tmr);
bzero(&args, sizeof(args));
args.eax = (APM_BIOS) << 8 | APM_RESUMETIMER;
args.ebx = PMDV_APMBIOS;
if (delta > 0) {
args.ecx = (int2bcd(tm->tm_sec) << 8) | 0x02;
args.edx = (int2bcd(tm->tm_hour) << 8) | int2bcd(tm->tm_min);
args.esi = (int2bcd(tm->tm_mon + 1) << 8) | int2bcd(tm->tm_mday);
args.edi = int2bcd(tm->tm_year + 1900);
} else {
args.ecx = 0x0000;
}
if (ioctl(fd, APMIO_BIOS, &args)) {
err(1,"set resume timer");
}
}
int
main(int argc, char *argv[])
{
int c, fd;
int dosleep = 0, all_info = 1, apm_status = 0, batt_status = 0;
int display = -1, batt_life = 0, ac_status = 0, standby = 0;
int batt_time = 0, delta = 0, enable = -1, haltcpu = -1;
int bioscall_available = 0;
size_t cmos_wall_len = sizeof(cmos_wall);
int dosleep = 0, all_info = 1, batt_status = 0;
int batt_life = 0, ac_status = 0, standby = 0;
int batt_time = 0;
if (sysctlbyname("machdep.wall_cmos_clock", &cmos_wall, &cmos_wall_len,
NULL, 0) == -1)
err(1, "sysctlbyname(machdep.wall_cmos_clock)");
while ((c = getopt(argc, argv, "abe:h:lRr:stzd:Z")) != -1) {
while ((c = getopt(argc, argv, "abltzZ")) != -1) {
switch (c) {
case 'a':
ac_status = 1;
@@ -399,32 +191,10 @@ main(int argc, char *argv[])
batt_status = 1;
all_info = 0;
break;
case 'd':
display = is_true(optarg);
all_info = 0;
break;
case 'l':
batt_life = 1;
all_info = 0;
break;
case 'R':
delta = -1;
break;
case 'r':
delta = atoi(optarg);
break;
case 's':
apm_status = 1;
all_info = 0;
break;
case 'e':
enable = is_true(optarg);
all_info = 0;
break;
case 'h':
haltcpu = is_true(optarg);
all_info = 0;
break;
case 't':
batt_time = 1;
all_info = 0;
@@ -444,44 +214,30 @@ main(int argc, char *argv[])
argc -= optind;
argv += optind;
}
if (haltcpu != -1 || enable != -1 || display != -1 || delta || dosleep
|| standby) {
if (dosleep || standby)
fd = open(APMDEV, O_RDWR);
bioscall_available = 1;
} else if ((fd = open(APMDEV, O_RDWR)) >= 0)
bioscall_available = 1;
else
fd = open(APMDEV, O_RDONLY);
if (fd == -1)
err(1, "can't open %s", APMDEV);
if (enable != -1)
apm_enable(fd, enable);
if (haltcpu != -1)
apm_haltcpu(fd, haltcpu);
if (delta)
apm_set_timer(fd, delta);
if (dosleep)
apm_suspend(fd);
else if (standby)
apm_standby(fd);
else if (delta == 0) {
else {
struct apm_info info;
apm_getinfo(fd, &info);
if (all_info)
print_all_info(fd, &info, bioscall_available);
print_all_info(fd, &info);
if (ac_status)
printf("%d\n", info.ai_acline);
if (batt_status)
printf("%d\n", info.ai_batt_stat);
if (batt_life)
printf("%d\n", info.ai_batt_life);
if (apm_status)
printf("%d\n", info.ai_status);
if (batt_time)
printf("%d\n", info.ai_batt_time);
if (display != -1)
apm_display(fd, display);
}
close(fd);
exit(0);