summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2000-08-13 17:05:27 +0000
committerume <ume@FreeBSD.org>2000-08-13 17:05:27 +0000
commitd3b79934ef0de284945e094216799e7923171051 (patch)
treeb0f8a89a2e666b7fe63e0dca9a265c5ebc8a89e8
parentb22fc876c04ad1d9386d870ad50e219c945ce392 (diff)
downloadFreeBSD-src-d3b79934ef0de284945e094216799e7923171051.zip
FreeBSD-src-d3b79934ef0de284945e094216799e7923171051.tar.gz
Add output of per battery information to apm(1).
New ioctl APMIO_GETPWSTATUS is introduced. Reviewed by: -mobile and -current folks (no objection)
-rw-r--r--share/man/man4/man4.i386/apm.42
-rw-r--r--sys/i386/apm/apm.c58
-rw-r--r--sys/i386/bios/apm.c58
-rw-r--r--sys/i386/include/apm_bios.h25
-rw-r--r--usr.sbin/apm/apm.c54
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) {
OpenPOWER on IntegriCloud