o Enable standby mode in apm utility. You need a newer kernel for this

functionality to work (however, the kernel changes were committed
  to current at 1998/07/05 23:29:11 PDT).
o Enable setting of a timer for later wakeup.  Note, not all APM
  BIOSes support this for all modes (mine doesn't support waking up on
  a timer from standby mode).
o Print out the APM capabilities, as reported by the BIOS.
o Report wake on ring indication.  No way to enable/disable this, but
  it is reported.
o update man page with above
o The output of this command has changed, so if you have a script that
  parses its output, then you may need to rewrite it slightly.
o The code attempts to deal with older kernels than July 5, 1998, but
  that part of the code isn't well tested.
This commit is contained in:
Warner Losh 1998-09-04 16:08:54 +00:00
parent 253ab668e2
commit 94d1a20141
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=38809
2 changed files with 203 additions and 11 deletions

View File

@ -16,8 +16,9 @@
.Nd control the APM BIOS and display its information
.Sh SYNOPSIS
.Nm apm
.Op Fl ablstz
.Op Fl ablstzZ
.Op Fl d Ar 1|0
.Op Fl r Ar delta
.Pp
.Nm zzz
.Sh DESCRIPTION
@ -62,10 +63,17 @@ using the values
.Ar 1
or
.Ar 0
respectively.
respectively. This argument seems to not work on many different
laptops, including the Libretto 30CT and 50CT.
.It Fl l
Display the remaining battery percentage. If your laptop does not
support this function, 255 is displayed.
.It Fl r
Enable the resume wakeup timer, if the laptop supports it. This
doesn't actually suspend the laptop, but if the laptop is suspended,
and it supports resume from suspend, then it will be resume 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
@ -76,6 +84,11 @@ state respectively.
.It Fl t
Display the estimated remaining battery lifetime in seconds. If
it is unknown, -1 is displayed.
.It Fl Z
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 apm tells what your laptop claims to support.
.It Fl z
Suspend the system. It is equivalent to
.Nm zzz .

View File

@ -15,7 +15,7 @@
#ifndef lint
static const char rcsid[] =
"$Id: apm.c,v 1.12 1997/11/12 04:16:23 jdp Exp $";
"$Id: apm.c,v 1.13 1998/02/20 07:17:46 hosokawa Exp $";
#endif /* not lint */
#include <err.h>
@ -26,18 +26,57 @@ static const char rcsid[] =
#include <sys/ioctl.h>
#include <unistd.h>
#include <machine/apm_bios.h>
#include <time.h>
#define APMDEV "/dev/apm"
#define xh(a) (((a) & 0xff00) >> 8)
#define xl(a) ((a) & 0xff)
#define APMERR(a) xh(a)
int cmos_wall = 0; /* True when wall time is in cmos clock, else UTC */
void
usage()
{
fprintf(stderr, "%s\n%s\n",
"usage: apm [-ablstz] [-d 1|0]",
"usage: apm [-ablstzZ] [-d 1|0] [-r delta]",
" zzz");
exit(1);
}
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;
}
int
bcd2int(int bcd)
{
int retval = 0;
if (bcd > 0x9999)
return -1;
while (bcd) {
retval = retval * 10 + ((bcd & 0xf000) >> 12);
bcd = (bcd & 0xfff) << 4;
}
return retval;
}
void
apm_suspend(int fd)
{
@ -45,6 +84,13 @@ apm_suspend(int fd)
err(1, NULL);
}
void
apm_standby(int fd)
{
if (ioctl(fd, APMIO_STANDBY, NULL) == -1)
err(1, NULL);
}
void
apm_getinfo(int fd, apm_info_t aip)
{
@ -53,8 +99,11 @@ apm_getinfo(int fd, apm_info_t aip)
}
void
print_all_info(apm_info_t aip)
print_all_info(int fd, apm_info_t aip)
{
struct apm_bios_arg args;
int apmerr;
printf("APM version: %d.%d\n", aip->ai_major, aip->ai_minor);
printf("APM Managment: %s\n", (aip->ai_status ? "Enabled" : "Disabled"));
printf("AC Line status: ");
@ -100,8 +149,96 @@ print_all_info(apm_info_t aip)
printf("%2d:%02d:%02d", h, m, s);
}
printf("\n");
}
if (aip->ai_infoversion >= 1) {
printf("Number of batteries: ");
if (aip->ai_batteries == (u_int) -1)
printf("unknown\n");
else
printf("%d\n", aip->ai_batteries);
}
/*
* 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)) {
err(1,"Get resume timer");
} else {
apmerr = APMERR(args.eax);
if (apmerr == 0x0d || apmerr == 0x86)
printf("Resume timer: disabled\n");
else if (apmerr)
fprintf(stderr,
"Failed to get the resume timer: APM error0x%x\n",
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);
tm = *localtime(&t);
strftime(buf, sizeof(buf), "%c", &tm);
printf("Resume timer: %s\n", buf);
}
}
/*
* 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) {
printf("APM Capacities:\n", aip->ai_capabilities);
if (aip->ai_capabilities == 0xff00)
printf("\tunknown\n");
if (aip->ai_capabilities & 0x01)
printf("\tglobal standby state\n");
if (aip->ai_capabilities & 0x02)
printf("\tglobal suspend state\n");
if (aip->ai_capabilities & 0x04)
printf("\tresume timer from standby\n");
if (aip->ai_capabilities & 0x08)
printf("\tresume timer from suspend\n");
if (aip->ai_capabilities & 0x10)
printf("\tRI resume from standby\n");
if (aip->ai_capabilities & 0x20)
printf("\tRI resume from suspend\n");
if (aip->ai_capabilities & 0x40)
printf("\tPCMCIA RI resume from standby\n");
if (aip->ai_capabilities & 0x80)
printf("\tPCMCIA RI resume from suspend\n");
}
}
/*
* currently, it can turn off the display, but the display never comes
@ -115,13 +252,41 @@ apm_display(int fd, int newstate)
}
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 sleep = 0, all_info = 1, apm_status = 0, batt_status = 0;
int display = 0, batt_life = 0, ac_status = 0;
int batt_time = 0;
int display = 0, batt_life = 0, ac_status = 0, standby = 0;
int batt_time = 0, delta = 0;
char *cmdname;
@ -135,7 +300,7 @@ main(int argc, char *argv[])
all_info = 0;
goto finish_option;
}
while ((c = getopt(argc, argv, "ablstzd:")) != -1) {
while ((c = getopt(argc, argv, "ablRr:stzd:Z")) != -1) {
switch (c) {
case 'a':
ac_status = 1;
@ -158,6 +323,12 @@ main(int argc, char *argv[])
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;
@ -170,6 +341,10 @@ main(int argc, char *argv[])
sleep = 1;
all_info = 0;
break;
case 'Z':
standby = 1;
all_info = 0;
break;
case '?':
default:
usage();
@ -183,14 +358,18 @@ main(int argc, char *argv[])
warn("can't open %s", APMDEV);
return 1;
}
if (delta)
apm_set_timer(fd, delta);
if (sleep)
apm_suspend(fd);
else {
else if (standby)
apm_standby(fd);
else if (delta == 0) {
struct apm_info info;
apm_getinfo(fd, &info);
if (all_info)
print_all_info(&info);
print_all_info(fd, &info);
if (ac_status)
printf("%d\n", info.ai_acline);
if (batt_status)