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:
parent
5734912a24
commit
8ad6d022ca
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=64615
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user