Add output of per battery information to apm(1).

New ioctl APMIO_GETPWSTATUS is introduced.

Reviewed by:	-mobile and -current folks (no objection)
This commit is contained in:
Hajimu UMEMOTO 2000-08-13 17:05:27 +00:00
parent 5734912a24
commit 8ad6d022ca
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=64615
5 changed files with 171 additions and 34 deletions

View File

@ -60,6 +60,8 @@ Enable / Disable power management.
.It Sy APMIO_HALTCPU .It Sy APMIO_HALTCPU
.It Sy APMIO_NOTHALTCPU .It Sy APMIO_NOTHALTCPU
Control execution of HLT in the kernel context switch routine. Control execution of HLT in the kernel context switch routine.
.It Sy APMIO_GETPWSTATUS
Get per battery information.
.Pp .Pp
Some APM implementations execute the HLT Some APM implementations execute the HLT
.Pq Halt CPU until an interrupt occurs .Pq Halt CPU until an interrupt occurs

View File

@ -607,34 +607,60 @@ apm_resume(void)
} }
/* get power status per battery */
static int
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 = app->ap_device;
sc->bios.r.ecx = 0;
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 */ /* get APM information */
static int static int
apm_get_info(apm_info_t aip) apm_get_info(apm_info_t aip)
{ {
struct apm_softc *sc = &apm_softc; struct apm_softc *sc = &apm_softc;
struct apm_pwstatus aps;
sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPWSTATUS; bzero(&aps, sizeof(aps));
sc->bios.r.ebx = PMDV_ALLDEV; aps.ap_device = PMDV_ALLDEV;
sc->bios.r.ecx = 0; if (apm_get_pwstatus(&aps))
sc->bios.r.edx = 0xffff; /* default to unknown battery time */
if (apm_bioscall())
return 1; return 1;
aip->ai_infoversion = 1; aip->ai_infoversion = 1;
aip->ai_acline = (sc->bios.r.ebx >> 8) & 0xff; aip->ai_acline = aps.ap_acline;
aip->ai_batt_stat = sc->bios.r.ebx & 0xff; aip->ai_batt_stat = aps.ap_batt_stat;
aip->ai_batt_life = sc->bios.r.ecx & 0xff; 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_major = (u_int)sc->majorversion;
aip->ai_minor = (u_int)sc->minorversion; aip->ai_minor = (u_int)sc->minorversion;
aip->ai_status = (u_int)sc->active; 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.eax = (APM_BIOS << 8) | APM_GETCAPABILITIES;
sc->bios.r.ebx = 0; 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)) if (apm_get_info((apm_info_t)addr))
error = ENXIO; error = ENXIO;
break; break;
case APMIO_GETPWSTATUS:
if (apm_get_pwstatus((apm_pwstatus_t)addr))
error = ENXIO;
break;
case APMIO_ENABLE: case APMIO_ENABLE:
if (!(flag & FWRITE)) if (!(flag & FWRITE))
return (EPERM); return (EPERM);

View File

@ -607,34 +607,60 @@ apm_resume(void)
} }
/* get power status per battery */
static int
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 = app->ap_device;
sc->bios.r.ecx = 0;
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 */ /* get APM information */
static int static int
apm_get_info(apm_info_t aip) apm_get_info(apm_info_t aip)
{ {
struct apm_softc *sc = &apm_softc; struct apm_softc *sc = &apm_softc;
struct apm_pwstatus aps;
sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPWSTATUS; bzero(&aps, sizeof(aps));
sc->bios.r.ebx = PMDV_ALLDEV; aps.ap_device = PMDV_ALLDEV;
sc->bios.r.ecx = 0; if (apm_get_pwstatus(&aps))
sc->bios.r.edx = 0xffff; /* default to unknown battery time */
if (apm_bioscall())
return 1; return 1;
aip->ai_infoversion = 1; aip->ai_infoversion = 1;
aip->ai_acline = (sc->bios.r.ebx >> 8) & 0xff; aip->ai_acline = aps.ap_acline;
aip->ai_batt_stat = sc->bios.r.ebx & 0xff; aip->ai_batt_stat = aps.ap_batt_stat;
aip->ai_batt_life = sc->bios.r.ecx & 0xff; 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_major = (u_int)sc->majorversion;
aip->ai_minor = (u_int)sc->minorversion; aip->ai_minor = (u_int)sc->minorversion;
aip->ai_status = (u_int)sc->active; 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.eax = (APM_BIOS << 8) | APM_GETCAPABILITIES;
sc->bios.r.ebx = 0; 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)) if (apm_get_info((apm_info_t)addr))
error = ENXIO; error = ENXIO;
break; break;
case APMIO_GETPWSTATUS:
if (apm_get_pwstatus((apm_pwstatus_t)addr))
error = ENXIO;
break;
case APMIO_ENABLE: case APMIO_ENABLE:
if (!(flag & FWRITE)) if (!(flag & FWRITE))
return (EPERM); return (EPERM);

View File

@ -118,7 +118,12 @@
#define PMDV_PCMCIA1 0x0601 #define PMDV_PCMCIA1 0x0601
#define PMDV_PCMCIA2 0x0602 #define PMDV_PCMCIA2 0x0602
#define PMDV_PCMCIA3 0x0603 #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 */ /* 0xe000 - 0xefff OEM-defined power device IDs */
/* 0xf000 - 0xffff Reserved */ /* 0xf000 - 0xffff Reserved */
@ -220,6 +225,23 @@ typedef struct apm_info {
u_int ai_spare[6]; /* For future expansion */ u_int ai_spare[6]; /* For future expansion */
} *apm_info_t; } *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 { struct apm_bios_arg {
u_long eax; u_long eax;
u_long ebx; u_long ebx;
@ -245,6 +267,7 @@ struct apm_event_info {
#define APMIO_BIOS _IOWR('P', 10, struct apm_bios_arg) #define APMIO_BIOS _IOWR('P', 10, struct apm_bios_arg)
#define APMIO_GETINFO _IOR('P', 11, struct apm_info) #define APMIO_GETINFO _IOR('P', 11, struct apm_info)
#define APMIO_STANDBY _IO('P', 12) #define APMIO_STANDBY _IO('P', 12)
#define APMIO_GETPWSTATUS _IOWR('P', 13, struct apm_pwstatus)
/* for /dev/apmctl */ /* for /dev/apmctl */
#define APMIO_NEXTEVENT _IOR('A', 100, struct apm_event_info) #define APMIO_NEXTEVENT _IOR('A', 100, struct apm_event_info)
#define APMIO_REJECTLASTREQ _IO('P', 101) #define APMIO_REJECTLASTREQ _IO('P', 101)

View File

@ -198,8 +198,60 @@ print_all_info(int fd, apm_info_t aip, int bioscall_available)
printf("Number of batteries: "); printf("Number of batteries: ");
if (aip->ai_batteries == (u_int) -1) if (aip->ai_batteries == (u_int) -1)
printf("unknown\n"); printf("unknown\n");
else else {
int i;
struct apm_pwstatus aps;
printf("%d\n", aip->ai_batteries); 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) { if (bioscall_available) {