From d3b79934ef0de284945e094216799e7923171051 Mon Sep 17 00:00:00 2001 From: ume Date: Sun, 13 Aug 2000 17:05:27 +0000 Subject: Add output of per battery information to apm(1). New ioctl APMIO_GETPWSTATUS is introduced. Reviewed by: -mobile and -current folks (no objection) --- share/man/man4/man4.i386/apm.4 | 2 ++ sys/i386/apm/apm.c | 58 ++++++++++++++++++++++++++++++++---------- sys/i386/bios/apm.c | 58 ++++++++++++++++++++++++++++++++---------- sys/i386/include/apm_bios.h | 25 +++++++++++++++++- usr.sbin/apm/apm.c | 54 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 167 insertions(+), 30 deletions(-) diff --git a/share/man/man4/man4.i386/apm.4 b/share/man/man4/man4.i386/apm.4 index f9a3ebc..a6a5685 100644 --- a/share/man/man4/man4.i386/apm.4 +++ b/share/man/man4/man4.i386/apm.4 @@ -60,6 +60,8 @@ Enable / Disable power management. .It Sy APMIO_HALTCPU .It Sy APMIO_NOTHALTCPU Control execution of HLT in the kernel context switch routine. +.It Sy APMIO_GETPWSTATUS +Get per battery information. .Pp Some APM implementations execute the HLT .Pq Halt CPU until an interrupt occurs diff --git a/sys/i386/apm/apm.c b/sys/i386/apm/apm.c index d62b70b..b12c43f 100644 --- a/sys/i386/apm/apm.c +++ b/sys/i386/apm/apm.c @@ -607,34 +607,60 @@ apm_resume(void) } -/* get APM information */ +/* get power status per battery */ static int -apm_get_info(apm_info_t aip) +apm_get_pwstatus(apm_pwstatus_t app) { struct apm_softc *sc = &apm_softc; + if (app->ap_device != PMDV_ALLDEV && + (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) + return 1; + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPWSTATUS; - sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ebx = app->ap_device; sc->bios.r.ecx = 0; - sc->bios.r.edx = 0xffff; /* default to unknown battery time */ + sc->bios.r.edx = 0xffff; /* default to unknown battery time */ if (apm_bioscall()) return 1; + app->ap_acline = (sc->bios.r.ebx >> 8) & 0xff; + app->ap_batt_stat = sc->bios.r.ebx & 0xff; + app->ap_batt_flag = (sc->bios.r.ecx >> 8) & 0xff; + app->ap_batt_life = sc->bios.r.ecx & 0xff; + sc->bios.r.edx &= 0xffff; + if (sc->bios.r.edx == 0xffff) /* Time is unknown */ + app->ap_batt_time = -1; + else if (sc->bios.r.edx & 0x8000) /* Time is in minutes */ + app->ap_batt_time = (sc->bios.r.edx & 0x7fff) * 60; + else /* Time is in seconds */ + app->ap_batt_time = sc->bios.r.edx; + + return 0; +} + + +/* get APM information */ +static int +apm_get_info(apm_info_t aip) +{ + struct apm_softc *sc = &apm_softc; + struct apm_pwstatus aps; + + bzero(&aps, sizeof(aps)); + aps.ap_device = PMDV_ALLDEV; + if (apm_get_pwstatus(&aps)) + return 1; + aip->ai_infoversion = 1; - aip->ai_acline = (sc->bios.r.ebx >> 8) & 0xff; - aip->ai_batt_stat = sc->bios.r.ebx & 0xff; - aip->ai_batt_life = sc->bios.r.ecx & 0xff; + aip->ai_acline = aps.ap_acline; + aip->ai_batt_stat = aps.ap_batt_stat; + aip->ai_batt_life = aps.ap_batt_life; + aip->ai_batt_time = aps.ap_batt_time; aip->ai_major = (u_int)sc->majorversion; aip->ai_minor = (u_int)sc->minorversion; aip->ai_status = (u_int)sc->active; - sc->bios.r.edx &= 0xffff; - if (sc->bios.r.edx == 0xffff) /* Time is unknown */ - aip->ai_batt_time = -1; - else if (sc->bios.r.edx & 0x8000) /* Time is in minutes */ - aip->ai_batt_time = (sc->bios.r.edx & 0x7fff) * 60; - else /* Time is in seconds */ - aip->ai_batt_time = sc->bios.r.edx; sc->bios.r.eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; sc->bios.r.ebx = 0; @@ -1197,6 +1223,10 @@ apmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) if (apm_get_info((apm_info_t)addr)) error = ENXIO; break; + case APMIO_GETPWSTATUS: + if (apm_get_pwstatus((apm_pwstatus_t)addr)) + error = ENXIO; + break; case APMIO_ENABLE: if (!(flag & FWRITE)) return (EPERM); diff --git a/sys/i386/bios/apm.c b/sys/i386/bios/apm.c index d62b70b..b12c43f 100644 --- a/sys/i386/bios/apm.c +++ b/sys/i386/bios/apm.c @@ -607,34 +607,60 @@ apm_resume(void) } -/* get APM information */ +/* get power status per battery */ static int -apm_get_info(apm_info_t aip) +apm_get_pwstatus(apm_pwstatus_t app) { struct apm_softc *sc = &apm_softc; + if (app->ap_device != PMDV_ALLDEV && + (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) + return 1; + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPWSTATUS; - sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ebx = app->ap_device; sc->bios.r.ecx = 0; - sc->bios.r.edx = 0xffff; /* default to unknown battery time */ + sc->bios.r.edx = 0xffff; /* default to unknown battery time */ if (apm_bioscall()) return 1; + app->ap_acline = (sc->bios.r.ebx >> 8) & 0xff; + app->ap_batt_stat = sc->bios.r.ebx & 0xff; + app->ap_batt_flag = (sc->bios.r.ecx >> 8) & 0xff; + app->ap_batt_life = sc->bios.r.ecx & 0xff; + sc->bios.r.edx &= 0xffff; + if (sc->bios.r.edx == 0xffff) /* Time is unknown */ + app->ap_batt_time = -1; + else if (sc->bios.r.edx & 0x8000) /* Time is in minutes */ + app->ap_batt_time = (sc->bios.r.edx & 0x7fff) * 60; + else /* Time is in seconds */ + app->ap_batt_time = sc->bios.r.edx; + + return 0; +} + + +/* get APM information */ +static int +apm_get_info(apm_info_t aip) +{ + struct apm_softc *sc = &apm_softc; + struct apm_pwstatus aps; + + bzero(&aps, sizeof(aps)); + aps.ap_device = PMDV_ALLDEV; + if (apm_get_pwstatus(&aps)) + return 1; + aip->ai_infoversion = 1; - aip->ai_acline = (sc->bios.r.ebx >> 8) & 0xff; - aip->ai_batt_stat = sc->bios.r.ebx & 0xff; - aip->ai_batt_life = sc->bios.r.ecx & 0xff; + aip->ai_acline = aps.ap_acline; + aip->ai_batt_stat = aps.ap_batt_stat; + aip->ai_batt_life = aps.ap_batt_life; + aip->ai_batt_time = aps.ap_batt_time; aip->ai_major = (u_int)sc->majorversion; aip->ai_minor = (u_int)sc->minorversion; aip->ai_status = (u_int)sc->active; - sc->bios.r.edx &= 0xffff; - if (sc->bios.r.edx == 0xffff) /* Time is unknown */ - aip->ai_batt_time = -1; - else if (sc->bios.r.edx & 0x8000) /* Time is in minutes */ - aip->ai_batt_time = (sc->bios.r.edx & 0x7fff) * 60; - else /* Time is in seconds */ - aip->ai_batt_time = sc->bios.r.edx; sc->bios.r.eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; sc->bios.r.ebx = 0; @@ -1197,6 +1223,10 @@ apmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) if (apm_get_info((apm_info_t)addr)) error = ENXIO; break; + case APMIO_GETPWSTATUS: + if (apm_get_pwstatus((apm_pwstatus_t)addr)) + error = ENXIO; + break; case APMIO_ENABLE: if (!(flag & FWRITE)) return (EPERM); diff --git a/sys/i386/include/apm_bios.h b/sys/i386/include/apm_bios.h index 768d0d7..52212fe 100644 --- a/sys/i386/include/apm_bios.h +++ b/sys/i386/include/apm_bios.h @@ -118,7 +118,12 @@ #define PMDV_PCMCIA1 0x0601 #define PMDV_PCMCIA2 0x0602 #define PMDV_PCMCIA3 0x0603 -/* 0x0700 - 0xdfff Reserved */ +/* 0x0700 - 0x7fff Reserved */ +#define PMDV_BATT_BASE 0x8000 +#define PMDV_BATT0 0x8001 +#define PMDV_BATT1 0x8002 +#define PMDV_BATT_ALL 0x80ff +/* 0x8100 - 0xdfff Reserved */ /* 0xe000 - 0xefff OEM-defined power device IDs */ /* 0xf000 - 0xffff Reserved */ @@ -220,6 +225,23 @@ typedef struct apm_info { u_int ai_spare[6]; /* For future expansion */ } *apm_info_t; +/* Battery flag */ +#define APM_BATT_HIGH 0x01 +#define APM_BATT_LOW 0x02 +#define APM_BATT_CRITICAL 0x04 +#define APM_BATT_CHARGING 0x08 +#define APM_BATT_NOT_PRESENT 0x10 +#define APM_BATT_NO_SYSTEM 0x80 + +typedef struct apm_pwstatus { + u_int ap_device; /* Device code of battery */ + u_int ap_acline; /* AC line status (0) */ + u_int ap_batt_stat; /* Battery status (0) */ + u_int ap_batt_flag; /* Battery flag (0) */ + u_int ap_batt_life; /* Remaining battery life in percent (0) */ + int ap_batt_time; /* Remaining battery time in seconds (0) */ +} *apm_pwstatus_t; + struct apm_bios_arg { u_long eax; u_long ebx; @@ -245,6 +267,7 @@ struct apm_event_info { #define APMIO_BIOS _IOWR('P', 10, struct apm_bios_arg) #define APMIO_GETINFO _IOR('P', 11, struct apm_info) #define APMIO_STANDBY _IO('P', 12) +#define APMIO_GETPWSTATUS _IOWR('P', 13, struct apm_pwstatus) /* for /dev/apmctl */ #define APMIO_NEXTEVENT _IOR('A', 100, struct apm_event_info) #define APMIO_REJECTLASTREQ _IO('P', 101) diff --git a/usr.sbin/apm/apm.c b/usr.sbin/apm/apm.c index 6f8e09e..6cfd86f 100644 --- a/usr.sbin/apm/apm.c +++ b/usr.sbin/apm/apm.c @@ -198,8 +198,60 @@ print_all_info(int fd, apm_info_t aip, int bioscall_available) printf("Number of batteries: "); if (aip->ai_batteries == (u_int) -1) printf("unknown\n"); - else + else { + int i; + struct apm_pwstatus aps; + printf("%d\n", aip->ai_batteries); + for (i = 0; i < aip->ai_batteries; ++i) { + bzero(&aps, sizeof(aps)); + aps.ap_device = PMDV_BATT0 + i; + if (ioctl(fd, APMIO_GETPWSTATUS, &aps) == -1) + continue; + printf("Battery %d:\n", i); + printf("\tBattery status: "); + if (aps.ap_batt_flag != 255 && + (aps.ap_batt_flag & APM_BATT_NOT_PRESENT)) { + printf("not present\n"); + continue; + } + if (aps.ap_batt_stat == 255) + printf("unknown\n"); + else if (aps.ap_batt_stat > 3) + printf("invalid value (0x%x)\n", + aps.ap_batt_stat); + else { + char *messages[] = { "high", + "low", + "critical", + "charging" }; + printf("%s\n", + messages[aps.ap_batt_stat]); + } + printf("\tRemaining battery life: "); + if (aps.ap_batt_life == 255) + printf("unknown\n"); + else if (aps.ap_batt_life <= 100) + printf("%d%%\n", aps.ap_batt_life); + else + printf("invalid value (0x%x)\n", + aps.ap_batt_life); + printf("\tRemaining battery time: "); + if (aps.ap_batt_time == -1) + printf("unknown\n"); + else { + int t, h, m, s; + + t = aps.ap_batt_time; + s = t % 60; + t /= 60; + m = t % 60; + t /= 60; + h = t; + printf("%2d:%02d:%02d\n", h, m, s); + } + } + } } if (bioscall_available) { -- cgit v1.1