From 099f92f50dfc6d5ada42f8465e4d198514a13c0f Mon Sep 17 00:00:00 2001 From: imp Date: Fri, 4 Sep 1998 16:08:54 +0000 Subject: 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. --- usr.sbin/apm/apm.8 | 17 ++++- usr.sbin/apm/apm.c | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 203 insertions(+), 11 deletions(-) diff --git a/usr.sbin/apm/apm.8 b/usr.sbin/apm/apm.8 index 240671f..81b9234 100644 --- a/usr.sbin/apm/apm.8 +++ b/usr.sbin/apm/apm.8 @@ -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 . diff --git a/usr.sbin/apm/apm.c b/usr.sbin/apm/apm.c index 3229a2a..bf6184f 100644 --- a/usr.sbin/apm/apm.c +++ b/usr.sbin/apm/apm.c @@ -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 @@ -26,18 +26,57 @@ static const char rcsid[] = #include #include #include +#include #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) { @@ -46,6 +85,13 @@ apm_suspend(int fd) } void +apm_standby(int fd) +{ + if (ioctl(fd, APMIO_STANDBY, NULL) == -1) + err(1, NULL); +} + +void apm_getinfo(int fd, apm_info_t aip) { if (ioctl(fd, APMIO_GETINFO, aip) == -1) @@ -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 @@ finish_option: 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) -- cgit v1.1