📄 apm.c
字号:
#include <u.h>#include <libc.h>#include </386/include/ureg.h>typedef struct Ureg Ureg;#include <auth.h>#include <fcall.h>#include <thread.h>#include <9p.h>enum { /* power mgmt event codes */ NotifyStandbyRequest = 0x0001, NotifySuspendRequest = 0x0002, NotifyNormalResume = 0x0003, NotifyCriticalResume = 0x0004, NotifyBatteryLow = 0x0005, NotifyPowerStatusChange = 0x0006, NotifyUpdateTime = 0x0007, NotifyCriticalSuspend = 0x0008, NotifyUserStandbyRequest = 0x0009, NotifyUserSuspendRequest = 0x000A, NotifyStandbyResume = 0x000B, NotifyCapabilitiesChange = 0x000C, /* power device ids: add device number or All */ DevBios = 0x0000, DevAll = 0x0001, DevDisplay = 0x0100, DevStorage = 0x0200, DevLpt = 0x0300, DevEia = 0x0400, DevNetwork = 0x0500, DevPCMCIA = 0x0600, DevBattery = 0x8000, All = 0x00FF, DevMask = 0xFF00, /* power states */ PowerEnabled = 0x0000, PowerStandby = 0x0001, PowerSuspend = 0x0002, PowerOff = 0x0003, /* apm commands */ CmdInstallationCheck = 0x5300, CmdRealModeConnect = 0x5301, CmdProtMode16Connect = 0x5302, CmdProtMode32Connect = 0x5303, CmdDisconnect = 0x5304, CmdCpuIdle = 0x5305, CmdCpuBusy = 0x5306, CmdSetPowerState = 0x5307, CmdSetPowerMgmt = 0x5308, DisablePowerMgmt = 0x0000, /* CX */ EnablePowerMgmt = 0x0001, CmdRestoreDefaults = 0x5309, CmdGetPowerStatus = 0x530A, CmdGetPMEvent = 0x530B, CmdGetPowerState = 0x530C, CmdGetPowerMgmt = 0x530D, CmdDriverVersion = 0x530E, /* like CmdDisconnect but doesn't lose the interface */ CmdGagePowerMgmt = 0x530F, DisengagePowerMgmt = 0x0000, /* CX */ EngagePowerManagemenet = 0x0001, CmdGetCapabilities = 0x5310, CapStandby = 0x0001, CapSuspend = 0x0002, CapTimerResumeStandby = 0x0004, CapTimerResumeSuspend = 0x0008, CapRingResumeStandby = 0x0010, CapRingResumeSuspend = 0x0020, CapPcmciaResumeStandby = 0x0040, CapPcmciaResumeSuspend = 0x0080, CapSlowCpu = 0x0100, CmdResumeTimer = 0x5311, DisableResumeTimer = 0x00, /* CL */ GetResumeTimer = 0x01, SetResumeTimer = 0x02, CmdResumeOnRing = 0x5312, DisableResumeOnRing = 0x0000, /* CX */ EnableResumeOnRing = 0x0001, GetResumeOnRing = 0x0002, CmdTimerRequests = 0x5313, DisableTimerRequests = 0x0000, /* CX */ EnableTimerRequests = 0x0001, GetTimerRequests = 0x0002,};static char* eventstr[] = {[NotifyStandbyRequest] "system standby request",[NotifySuspendRequest] "system suspend request",[NotifyNormalResume] "normal resume",[NotifyCriticalResume] "critical resume",[NotifyBatteryLow] "battery low",[NotifyPowerStatusChange] "power status change",[NotifyUpdateTime] "update time",[NotifyCriticalSuspend] "critical suspend",[NotifyUserStandbyRequest] "user standby request",[NotifyUserSuspendRequest] "user suspend request",[NotifyCapabilitiesChange] "capabilities change",};static char*apmevent(int e){ static char buf[32]; if(0 <= e && e < nelem(eventstr) && eventstr[e]) return eventstr[e]; sprint(buf, "event 0x%ux", (uint)e); return buf;}static char *error[256] = {[0x01] "power mgmt disabled",[0x02] "real mode connection already established",[0x03] "interface not connected",[0x05] "16-bit protected mode connection already established",[0x06] "16-bit protected mode interface not supported",[0x07] "32-bit protected mode interface already established",[0x08] "32-bit protected mode interface not supported",[0x09] "unrecognized device id",[0x0A] "parameter value out of range",[0x0B] "interface not engaged",[0x0C] "function not supported",[0x0D] "resume timer disabled",[0x60] "unable to enter requested state",[0x80] "no power mgmt events pending",[0x86] "apm not present",};static char*apmerror(int id){ char *e; static char buf[64]; if(e = error[id&0xFF]) return e; sprint(buf, "unknown error %x", id); return buf;}QLock apmlock;int apmdebug;static int_apmcall(int fd, Ureg *u){if(apmdebug) fprint(2, "call ax 0x%lux bx 0x%lux cx 0x%lux\n", u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF); seek(fd, 0, 0); if(write(fd, u, sizeof *u) != sizeof *u) return -1; seek(fd, 0, 0); if(read(fd, u, sizeof *u) != sizeof *u) return -1;if(apmdebug) fprint(2, "flags 0x%lux ax 0x%lux bx 0x%lux cx 0x%lux\n", u->flags&0xFFFF, u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF); if(u->flags & 1) { /* carry flag */ werrstr("%s", apmerror(u->ax>>8)); return -1; } return 0;}static intapmcall(int fd, Ureg *u){ int r; qlock(&apmlock); r = _apmcall(fd, u); qunlock(&apmlock); return r;}typedef struct Apm Apm;typedef struct Battery Battery;struct Battery { int status; int percent; int time;};enum { Mbattery = 4,};struct Apm { int fd; int verhi; int verlo; int acstatus; int nbattery; int capabilities; Battery battery[Mbattery];};enum { AcUnknown = 0, /* Apm.acstatus */ AcOffline, AcOnline, AcBackup, BatteryUnknown = 0, /* Battery.status */ BatteryHigh, BatteryLow, BatteryCritical, BatteryCharging,};static char*acstatusstr[] = {[AcUnknown] "unknown",[AcOffline] "offline",[AcOnline] "online",[AcBackup] "backup",};static char*batterystatusstr[] = {[BatteryUnknown] "unknown",[BatteryHigh] "high",[BatteryLow] "low",[BatteryCritical] "critical",[BatteryCharging] "charging",};static char*powerstatestr[] = {[PowerOff] "off",[PowerSuspend] "suspend",[PowerStandby] "standby",[PowerEnabled] "on",};static char*xstatus(char **str, int nstr, int x){ if(0 <= x && x < nstr && str[x]) return str[x]; return "unknown";}static char*batterystatus(int b){ return xstatus(batterystatusstr, nelem(batterystatusstr), b);}static char*powerstate(int s){ return xstatus(powerstatestr, nelem(powerstatestr), s);}static char*acstatus(int a){ return xstatus(acstatusstr, nelem(acstatusstr), a);} static intapmversion(Apm *apm){ Ureg u; u.ax = CmdDriverVersion; u.bx = 0x0000; u.cx = 0x0102; if(apmcall(apm->fd, &u) < 0) return -1; apm->verhi = u.cx>>8; apm->verlo = u.cx & 0xFF; return u.cx;}static intapmcpuidle(Apm *apm){ Ureg u; u.ax = CmdCpuIdle; return apmcall(apm->fd, &u);}static intapmcpubusy(Apm *apm){ Ureg u; u.ax = CmdCpuBusy; return apmcall(apm->fd, &u);}static intapmsetpowerstate(Apm *apm, int dev, int state){ Ureg u; u.ax = CmdSetPowerState; u.bx = dev; u.cx = state; return apmcall(apm->fd, &u);}static intapmsetpowermgmt(Apm *apm, int dev, int state){ Ureg u; u.ax = CmdSetPowerMgmt; u.bx = dev; u.cx = state; return apmcall(apm->fd, &u);}static intapmrestoredefaults(Apm *apm, int dev){ Ureg u; u.ax = CmdRestoreDefaults; u.bx = dev; return apmcall(apm->fd, &u);}static intapmgetpowerstatus(Apm *apm, int dev){ Battery *b; Ureg u; if(dev == DevAll) b = &apm->battery[0]; else if((dev & DevMask) == DevBattery) { if(dev - DevBattery < nelem(apm->battery)) b = &apm->battery[dev - DevBattery]; else b = nil; } else { werrstr("bad device number"); return -1; } u.ax = CmdGetPowerStatus; u.bx = dev; if(apmcall(apm->fd, &u) < 0) return -1; if((dev & DevMask) == DevBattery) apm->nbattery = u.si; switch(u.bx>>8) { case 0x00: apm->acstatus = AcOffline; break; case 0x01: apm->acstatus = AcOnline; break; case 0x02: apm->acstatus = AcBackup; break; default: apm->acstatus = AcUnknown; break; } if(b != nil) { switch(u.bx&0xFF) { case 0x00: b->status = BatteryHigh; break; case 0x01: b->status = BatteryLow; break; case 0x02: b->status = BatteryCritical; break; case 0x03: b->status = BatteryCharging; break; default: b->status = BatteryUnknown; break; } if((u.cx & 0xFF) == 0xFF) b->percent = -1; else b->percent = u.cx & 0xFF; if((u.dx&0xFFFF) == 0xFFFF) b->time = -1; else if(u.dx & 0x8000) b->time = 60*(u.dx & 0x7FFF); else b->time = u.dx & 0x7FFF; } return 0;}static intapmgetevent(Apm *apm){ Ureg u; u.ax = CmdGetPMEvent; u.bx = 0; u.cx = 0; //when u.bx == NotifyNormalResume or NotifyCriticalResume, //u.cx & 1 indicates PCMCIA socket was on while suspended, //u.cx & 1 == 0 indicates was off. if(apmcall(apm->fd, &u) < 0) return -1; return u.bx;}static intapmgetpowerstate(Apm *apm, int dev){ Ureg u; u.ax = CmdGetPowerState; u.bx = dev; u.cx = 0; if(apmcall(apm->fd, &u) < 0) return -1; return u.cx;}static intapmgetpowermgmt(Apm *apm, int dev){ Ureg u; u.ax = CmdGetPowerMgmt; u.bx = dev; if(apmcall(apm->fd, &u) < 0) return -1; return u.cx;}static intapmgetcapabilities(Apm *apm){ Ureg u; u.ax = CmdGetCapabilities; u.bx = DevBios; if(apmcall(apm->fd, &u) < 0) return -1; apm->nbattery = u.bx & 0xFF; apm->capabilities &= ~0xFFFF; apm->capabilities |= u.cx; return 0;}static intapminstallationcheck(Apm *apm){ Ureg u; u.ax = CmdInstallationCheck; u.bx = DevBios; if(apmcall(apm->fd, &u) < 0) return -1; if(u.cx & 0x0004) apm->capabilities |= CapSlowCpu; else apm->capabilities &= ~CapSlowCpu; return 0;}voidapmsetdisplaystate(Apm *apm, int s){ apmsetpowerstate(apm, DevDisplay, s);}voidapmblank(Apm *apm){ apmsetdisplaystate(apm, PowerStandby);}voidapmunblank(Apm *apm){ apmsetdisplaystate(apm, PowerEnabled);}voidapmsuspend(Apm *apm){ apmsetpowerstate(apm, DevAll, PowerSuspend);}Apm apm;voidpowerprint(void){ print("%s", ctime(time(0))); if(apmgetpowerstatus(&apm, DevAll) == 0) { print("%d batteries\n", apm.nbattery); print("battery 0: status %s percent %d time %d:%.2d\n", batterystatus(apm.battery[0].status), apm.battery[0].percent, apm.battery[0].time/60, apm.battery[0].time%60); }}void*erealloc(void *v, ulong n){ v = realloc(v, n); if(v == nil) sysfatal("out of memory reallocating %lud", n); setmalloctag(v, getcallerpc(&v)); return v;}void*emalloc(ulong n){ void *v; v = malloc(n); if(v == nil) sysfatal("out of memory allocating %lud", n); memset(v, 0, n); setmalloctag(v, getcallerpc(&n)); return v;}char*estrdup(char *s){ int l; char *t; if (s == nil) return nil; l = strlen(s)+1; t = emalloc(l); memcpy(t, s, l); setmalloctag(t, getcallerpc(&s)); return t;}char*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -