180ee5cbfSDavid du Colombier #include <u.h> 280ee5cbfSDavid du Colombier #include <libc.h> 380ee5cbfSDavid du Colombier #include </386/include/ureg.h> 480ee5cbfSDavid du Colombier typedef struct Ureg Ureg; 580ee5cbfSDavid du Colombier #include <auth.h> 680ee5cbfSDavid du Colombier #include <fcall.h> 780ee5cbfSDavid du Colombier #include <thread.h> 880ee5cbfSDavid du Colombier #include <9p.h> 980ee5cbfSDavid du Colombier 1080ee5cbfSDavid du Colombier enum { 1180ee5cbfSDavid du Colombier /* power mgmt event codes */ 1280ee5cbfSDavid du Colombier NotifyStandbyRequest = 0x0001, 1380ee5cbfSDavid du Colombier NotifySuspendRequest = 0x0002, 1480ee5cbfSDavid du Colombier NotifyNormalResume = 0x0003, 1580ee5cbfSDavid du Colombier NotifyCriticalResume = 0x0004, 1680ee5cbfSDavid du Colombier NotifyBatteryLow = 0x0005, 1780ee5cbfSDavid du Colombier NotifyPowerStatusChange = 0x0006, 1880ee5cbfSDavid du Colombier NotifyUpdateTime = 0x0007, 1980ee5cbfSDavid du Colombier NotifyCriticalSuspend = 0x0008, 2080ee5cbfSDavid du Colombier NotifyUserStandbyRequest = 0x0009, 2180ee5cbfSDavid du Colombier NotifyUserSuspendRequest = 0x000A, 2280ee5cbfSDavid du Colombier NotifyStandbyResume = 0x000B, 2380ee5cbfSDavid du Colombier NotifyCapabilitiesChange = 0x000C, 2480ee5cbfSDavid du Colombier 2580ee5cbfSDavid du Colombier /* power device ids: add device number or All */ 2680ee5cbfSDavid du Colombier DevBios = 0x0000, 2780ee5cbfSDavid du Colombier DevAll = 0x0001, 2880ee5cbfSDavid du Colombier DevDisplay = 0x0100, 2980ee5cbfSDavid du Colombier DevStorage = 0x0200, 3080ee5cbfSDavid du Colombier DevLpt = 0x0300, 3180ee5cbfSDavid du Colombier DevEia = 0x0400, 3280ee5cbfSDavid du Colombier DevNetwork = 0x0500, 3380ee5cbfSDavid du Colombier DevPCMCIA = 0x0600, 3480ee5cbfSDavid du Colombier DevBattery = 0x8000, 3580ee5cbfSDavid du Colombier All = 0x00FF, 3680ee5cbfSDavid du Colombier DevMask = 0xFF00, 3780ee5cbfSDavid du Colombier 3880ee5cbfSDavid du Colombier /* power states */ 3980ee5cbfSDavid du Colombier PowerEnabled = 0x0000, 4080ee5cbfSDavid du Colombier PowerStandby = 0x0001, 4180ee5cbfSDavid du Colombier PowerSuspend = 0x0002, 4280ee5cbfSDavid du Colombier PowerOff = 0x0003, 4380ee5cbfSDavid du Colombier 4480ee5cbfSDavid du Colombier /* apm commands */ 4580ee5cbfSDavid du Colombier CmdInstallationCheck = 0x5300, 4680ee5cbfSDavid du Colombier CmdRealModeConnect = 0x5301, 4780ee5cbfSDavid du Colombier CmdProtMode16Connect = 0x5302, 4880ee5cbfSDavid du Colombier CmdProtMode32Connect = 0x5303, 4980ee5cbfSDavid du Colombier CmdDisconnect = 0x5304, 5080ee5cbfSDavid du Colombier CmdCpuIdle = 0x5305, 5180ee5cbfSDavid du Colombier CmdCpuBusy = 0x5306, 5280ee5cbfSDavid du Colombier CmdSetPowerState = 0x5307, 5380ee5cbfSDavid du Colombier CmdSetPowerMgmt = 0x5308, 5480ee5cbfSDavid du Colombier DisablePowerMgmt = 0x0000, /* CX */ 5580ee5cbfSDavid du Colombier EnablePowerMgmt = 0x0001, 5680ee5cbfSDavid du Colombier CmdRestoreDefaults = 0x5309, 5780ee5cbfSDavid du Colombier CmdGetPowerStatus = 0x530A, 5880ee5cbfSDavid du Colombier CmdGetPMEvent = 0x530B, 5980ee5cbfSDavid du Colombier CmdGetPowerState = 0x530C, 6080ee5cbfSDavid du Colombier CmdGetPowerMgmt = 0x530D, 6180ee5cbfSDavid du Colombier CmdDriverVersion = 0x530E, 6280ee5cbfSDavid du Colombier 6380ee5cbfSDavid du Colombier /* like CmdDisconnect but doesn't lose the interface */ 6480ee5cbfSDavid du Colombier CmdGagePowerMgmt = 0x530F, 6580ee5cbfSDavid du Colombier DisengagePowerMgmt = 0x0000, /* CX */ 6680ee5cbfSDavid du Colombier EngagePowerManagemenet = 0x0001, 6780ee5cbfSDavid du Colombier 6880ee5cbfSDavid du Colombier CmdGetCapabilities = 0x5310, 6980ee5cbfSDavid du Colombier CapStandby = 0x0001, 7080ee5cbfSDavid du Colombier CapSuspend = 0x0002, 7180ee5cbfSDavid du Colombier CapTimerResumeStandby = 0x0004, 7280ee5cbfSDavid du Colombier CapTimerResumeSuspend = 0x0008, 7380ee5cbfSDavid du Colombier CapRingResumeStandby = 0x0010, 7480ee5cbfSDavid du Colombier CapRingResumeSuspend = 0x0020, 7580ee5cbfSDavid du Colombier CapPcmciaResumeStandby = 0x0040, 7680ee5cbfSDavid du Colombier CapPcmciaResumeSuspend = 0x0080, 7780ee5cbfSDavid du Colombier CapSlowCpu = 0x0100, 7880ee5cbfSDavid du Colombier CmdResumeTimer = 0x5311, 7980ee5cbfSDavid du Colombier DisableResumeTimer = 0x00, /* CL */ 8080ee5cbfSDavid du Colombier GetResumeTimer = 0x01, 8180ee5cbfSDavid du Colombier SetResumeTimer = 0x02, 8280ee5cbfSDavid du Colombier CmdResumeOnRing = 0x5312, 8380ee5cbfSDavid du Colombier DisableResumeOnRing = 0x0000, /* CX */ 8480ee5cbfSDavid du Colombier EnableResumeOnRing = 0x0001, 8580ee5cbfSDavid du Colombier GetResumeOnRing = 0x0002, 8680ee5cbfSDavid du Colombier CmdTimerRequests = 0x5313, 8780ee5cbfSDavid du Colombier DisableTimerRequests = 0x0000, /* CX */ 8880ee5cbfSDavid du Colombier EnableTimerRequests = 0x0001, 8980ee5cbfSDavid du Colombier GetTimerRequests = 0x0002, 9080ee5cbfSDavid du Colombier }; 9180ee5cbfSDavid du Colombier 9280ee5cbfSDavid du Colombier static char* eventstr[] = { 9380ee5cbfSDavid du Colombier [NotifyStandbyRequest] "system standby request", 9480ee5cbfSDavid du Colombier [NotifySuspendRequest] "system suspend request", 9580ee5cbfSDavid du Colombier [NotifyNormalResume] "normal resume", 9680ee5cbfSDavid du Colombier [NotifyCriticalResume] "critical resume", 9780ee5cbfSDavid du Colombier [NotifyBatteryLow] "battery low", 9880ee5cbfSDavid du Colombier [NotifyPowerStatusChange] "power status change", 9980ee5cbfSDavid du Colombier [NotifyUpdateTime] "update time", 10080ee5cbfSDavid du Colombier [NotifyCriticalSuspend] "critical suspend", 10180ee5cbfSDavid du Colombier [NotifyUserStandbyRequest] "user standby request", 10280ee5cbfSDavid du Colombier [NotifyUserSuspendRequest] "user suspend request", 10380ee5cbfSDavid du Colombier [NotifyCapabilitiesChange] "capabilities change", 10480ee5cbfSDavid du Colombier }; 10580ee5cbfSDavid du Colombier 10680ee5cbfSDavid du Colombier static char* 10780ee5cbfSDavid du Colombier apmevent(int e) 10880ee5cbfSDavid du Colombier { 10980ee5cbfSDavid du Colombier static char buf[32]; 11080ee5cbfSDavid du Colombier 11180ee5cbfSDavid du Colombier if(0 <= e && e < nelem(eventstr) && eventstr[e]) 11280ee5cbfSDavid du Colombier return eventstr[e]; 11380ee5cbfSDavid du Colombier 11480ee5cbfSDavid du Colombier sprint(buf, "event 0x%ux", (uint)e); 11580ee5cbfSDavid du Colombier return buf; 11680ee5cbfSDavid du Colombier } 11780ee5cbfSDavid du Colombier 11880ee5cbfSDavid du Colombier static char *error[256] = { 11980ee5cbfSDavid du Colombier [0x01] "power mgmt disabled", 12080ee5cbfSDavid du Colombier [0x02] "real mode connection already established", 12180ee5cbfSDavid du Colombier [0x03] "interface not connected", 12280ee5cbfSDavid du Colombier [0x05] "16-bit protected mode connection already established", 12380ee5cbfSDavid du Colombier [0x06] "16-bit protected mode interface not supported", 12480ee5cbfSDavid du Colombier [0x07] "32-bit protected mode interface already established", 12580ee5cbfSDavid du Colombier [0x08] "32-bit protected mode interface not supported", 12680ee5cbfSDavid du Colombier [0x09] "unrecognized device id", 12780ee5cbfSDavid du Colombier [0x0A] "parameter value out of range", 12880ee5cbfSDavid du Colombier [0x0B] "interface not engaged", 12980ee5cbfSDavid du Colombier [0x0C] "function not supported", 13080ee5cbfSDavid du Colombier [0x0D] "resume timer disabled", 131d3c05884SDavid du Colombier [0x60] "unable to enter requested state", 13280ee5cbfSDavid du Colombier [0x80] "no power mgmt events pending", 13380ee5cbfSDavid du Colombier [0x86] "apm not present", 13480ee5cbfSDavid du Colombier }; 13580ee5cbfSDavid du Colombier 13680ee5cbfSDavid du Colombier static char* 13780ee5cbfSDavid du Colombier apmerror(int id) 13880ee5cbfSDavid du Colombier { 13980ee5cbfSDavid du Colombier char *e; 14080ee5cbfSDavid du Colombier static char buf[64]; 14180ee5cbfSDavid du Colombier 14280ee5cbfSDavid du Colombier if(e = error[id&0xFF]) 14380ee5cbfSDavid du Colombier return e; 14480ee5cbfSDavid du Colombier 14580ee5cbfSDavid du Colombier sprint(buf, "unknown error %x", id); 14680ee5cbfSDavid du Colombier return buf; 14780ee5cbfSDavid du Colombier } 14880ee5cbfSDavid du Colombier 14980ee5cbfSDavid du Colombier QLock apmlock; 15080ee5cbfSDavid du Colombier int apmdebug; 15180ee5cbfSDavid du Colombier 15280ee5cbfSDavid du Colombier static int 15380ee5cbfSDavid du Colombier _apmcall(int fd, Ureg *u) 15480ee5cbfSDavid du Colombier { 1559a747e4fSDavid du Colombier if(apmdebug) fprint(2, "call ax 0x%lux bx 0x%lux cx 0x%lux\n", 15680ee5cbfSDavid du Colombier u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF); 15780ee5cbfSDavid du Colombier 15880ee5cbfSDavid du Colombier seek(fd, 0, 0); 15980ee5cbfSDavid du Colombier if(write(fd, u, sizeof *u) != sizeof *u) 16080ee5cbfSDavid du Colombier return -1; 16180ee5cbfSDavid du Colombier 16280ee5cbfSDavid du Colombier seek(fd, 0, 0); 16380ee5cbfSDavid du Colombier if(read(fd, u, sizeof *u) != sizeof *u) 16480ee5cbfSDavid du Colombier return -1; 16580ee5cbfSDavid du Colombier 1669a747e4fSDavid du Colombier if(apmdebug) fprint(2, "flags 0x%lux ax 0x%lux bx 0x%lux cx 0x%lux\n", 16780ee5cbfSDavid du Colombier u->flags&0xFFFF, u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF); 16880ee5cbfSDavid du Colombier 16980ee5cbfSDavid du Colombier if(u->flags & 1) { /* carry flag */ 17080ee5cbfSDavid du Colombier werrstr("%s", apmerror(u->ax>>8)); 17180ee5cbfSDavid du Colombier return -1; 17280ee5cbfSDavid du Colombier } 17380ee5cbfSDavid du Colombier return 0; 17480ee5cbfSDavid du Colombier } 17580ee5cbfSDavid du Colombier 17680ee5cbfSDavid du Colombier static int 17780ee5cbfSDavid du Colombier apmcall(int fd, Ureg *u) 17880ee5cbfSDavid du Colombier { 17980ee5cbfSDavid du Colombier int r; 18080ee5cbfSDavid du Colombier 18180ee5cbfSDavid du Colombier qlock(&apmlock); 18280ee5cbfSDavid du Colombier r = _apmcall(fd, u); 18380ee5cbfSDavid du Colombier qunlock(&apmlock); 18480ee5cbfSDavid du Colombier return r; 18580ee5cbfSDavid du Colombier } 18680ee5cbfSDavid du Colombier 18780ee5cbfSDavid du Colombier typedef struct Apm Apm; 18880ee5cbfSDavid du Colombier typedef struct Battery Battery; 18980ee5cbfSDavid du Colombier 19080ee5cbfSDavid du Colombier struct Battery { 19180ee5cbfSDavid du Colombier int status; 19280ee5cbfSDavid du Colombier int percent; 19380ee5cbfSDavid du Colombier int time; 19480ee5cbfSDavid du Colombier }; 19580ee5cbfSDavid du Colombier 19680ee5cbfSDavid du Colombier enum { 19780ee5cbfSDavid du Colombier Mbattery = 4, 19880ee5cbfSDavid du Colombier }; 19980ee5cbfSDavid du Colombier struct Apm { 20080ee5cbfSDavid du Colombier int fd; 20180ee5cbfSDavid du Colombier 20280ee5cbfSDavid du Colombier int verhi; 20380ee5cbfSDavid du Colombier int verlo; 20480ee5cbfSDavid du Colombier 20580ee5cbfSDavid du Colombier int acstatus; 20680ee5cbfSDavid du Colombier int nbattery; 20780ee5cbfSDavid du Colombier 20880ee5cbfSDavid du Colombier int capabilities; 20980ee5cbfSDavid du Colombier 21080ee5cbfSDavid du Colombier Battery battery[Mbattery]; 21180ee5cbfSDavid du Colombier }; 21280ee5cbfSDavid du Colombier enum { 21380ee5cbfSDavid du Colombier AcUnknown = 0, /* Apm.acstatus */ 21480ee5cbfSDavid du Colombier AcOffline, 21580ee5cbfSDavid du Colombier AcOnline, 21680ee5cbfSDavid du Colombier AcBackup, 21780ee5cbfSDavid du Colombier 21880ee5cbfSDavid du Colombier BatteryUnknown = 0, /* Battery.status */ 21980ee5cbfSDavid du Colombier BatteryHigh, 22080ee5cbfSDavid du Colombier BatteryLow, 22180ee5cbfSDavid du Colombier BatteryCritical, 22280ee5cbfSDavid du Colombier BatteryCharging, 22380ee5cbfSDavid du Colombier }; 22480ee5cbfSDavid du Colombier 22580ee5cbfSDavid du Colombier static char* 22680ee5cbfSDavid du Colombier acstatusstr[] = { 22780ee5cbfSDavid du Colombier [AcUnknown] "unknown", 22880ee5cbfSDavid du Colombier [AcOffline] "offline", 22980ee5cbfSDavid du Colombier [AcOnline] "online", 23080ee5cbfSDavid du Colombier [AcBackup] "backup", 23180ee5cbfSDavid du Colombier }; 23280ee5cbfSDavid du Colombier 23380ee5cbfSDavid du Colombier static char* 23480ee5cbfSDavid du Colombier batterystatusstr[] = { 23580ee5cbfSDavid du Colombier [BatteryUnknown] "unknown", 23680ee5cbfSDavid du Colombier [BatteryHigh] "high", 23780ee5cbfSDavid du Colombier [BatteryLow] "low", 23880ee5cbfSDavid du Colombier [BatteryCritical] "critical", 23980ee5cbfSDavid du Colombier [BatteryCharging] "charging", 24080ee5cbfSDavid du Colombier }; 24180ee5cbfSDavid du Colombier 24280ee5cbfSDavid du Colombier static char* 24380ee5cbfSDavid du Colombier powerstatestr[] = { 24480ee5cbfSDavid du Colombier [PowerOff] "off", 24580ee5cbfSDavid du Colombier [PowerSuspend] "suspend", 24680ee5cbfSDavid du Colombier [PowerStandby] "standby", 24780ee5cbfSDavid du Colombier [PowerEnabled] "on", 24880ee5cbfSDavid du Colombier }; 24980ee5cbfSDavid du Colombier 25080ee5cbfSDavid du Colombier static char* 25180ee5cbfSDavid du Colombier xstatus(char **str, int nstr, int x) 25280ee5cbfSDavid du Colombier { 25380ee5cbfSDavid du Colombier if(0 <= x && x < nstr && str[x]) 25480ee5cbfSDavid du Colombier return str[x]; 25580ee5cbfSDavid du Colombier return "unknown"; 25680ee5cbfSDavid du Colombier } 25780ee5cbfSDavid du Colombier 25880ee5cbfSDavid du Colombier static char* 25980ee5cbfSDavid du Colombier batterystatus(int b) 26080ee5cbfSDavid du Colombier { 26180ee5cbfSDavid du Colombier return xstatus(batterystatusstr, nelem(batterystatusstr), b); 26280ee5cbfSDavid du Colombier } 26380ee5cbfSDavid du Colombier 26480ee5cbfSDavid du Colombier static char* 26580ee5cbfSDavid du Colombier powerstate(int s) 26680ee5cbfSDavid du Colombier { 26780ee5cbfSDavid du Colombier return xstatus(powerstatestr, nelem(powerstatestr), s); 26880ee5cbfSDavid du Colombier } 26980ee5cbfSDavid du Colombier 27080ee5cbfSDavid du Colombier static char* 27180ee5cbfSDavid du Colombier acstatus(int a) 27280ee5cbfSDavid du Colombier { 27380ee5cbfSDavid du Colombier return xstatus(acstatusstr, nelem(acstatusstr), a); 27480ee5cbfSDavid du Colombier } 27580ee5cbfSDavid du Colombier 27680ee5cbfSDavid du Colombier static int 27780ee5cbfSDavid du Colombier apmversion(Apm *apm) 27880ee5cbfSDavid du Colombier { 27980ee5cbfSDavid du Colombier Ureg u; 28080ee5cbfSDavid du Colombier 28180ee5cbfSDavid du Colombier u.ax = CmdDriverVersion; 28280ee5cbfSDavid du Colombier u.bx = 0x0000; 28380ee5cbfSDavid du Colombier u.cx = 0x0102; 28480ee5cbfSDavid du Colombier if(apmcall(apm->fd, &u) < 0) 28580ee5cbfSDavid du Colombier return -1; 28680ee5cbfSDavid du Colombier 28780ee5cbfSDavid du Colombier apm->verhi = u.cx>>8; 28880ee5cbfSDavid du Colombier apm->verlo = u.cx & 0xFF; 28980ee5cbfSDavid du Colombier 29080ee5cbfSDavid du Colombier return u.cx; 29180ee5cbfSDavid du Colombier } 29280ee5cbfSDavid du Colombier 29380ee5cbfSDavid du Colombier static int 29480ee5cbfSDavid du Colombier apmcpuidle(Apm *apm) 29580ee5cbfSDavid du Colombier { 29680ee5cbfSDavid du Colombier Ureg u; 29780ee5cbfSDavid du Colombier 29880ee5cbfSDavid du Colombier u.ax = CmdCpuIdle; 29980ee5cbfSDavid du Colombier return apmcall(apm->fd, &u); 30080ee5cbfSDavid du Colombier } 30180ee5cbfSDavid du Colombier 30280ee5cbfSDavid du Colombier static int 30380ee5cbfSDavid du Colombier apmcpubusy(Apm *apm) 30480ee5cbfSDavid du Colombier { 30580ee5cbfSDavid du Colombier Ureg u; 30680ee5cbfSDavid du Colombier 30780ee5cbfSDavid du Colombier u.ax = CmdCpuBusy; 30880ee5cbfSDavid du Colombier return apmcall(apm->fd, &u); 30980ee5cbfSDavid du Colombier } 31080ee5cbfSDavid du Colombier 31180ee5cbfSDavid du Colombier static int 31280ee5cbfSDavid du Colombier apmsetpowerstate(Apm *apm, int dev, int state) 31380ee5cbfSDavid du Colombier { 31480ee5cbfSDavid du Colombier Ureg u; 31580ee5cbfSDavid du Colombier 31680ee5cbfSDavid du Colombier u.ax = CmdSetPowerState; 31780ee5cbfSDavid du Colombier u.bx = dev; 31880ee5cbfSDavid du Colombier u.cx = state; 31980ee5cbfSDavid du Colombier return apmcall(apm->fd, &u); 32080ee5cbfSDavid du Colombier } 32180ee5cbfSDavid du Colombier 32280ee5cbfSDavid du Colombier static int 32380ee5cbfSDavid du Colombier apmsetpowermgmt(Apm *apm, int dev, int state) 32480ee5cbfSDavid du Colombier { 32580ee5cbfSDavid du Colombier Ureg u; 32680ee5cbfSDavid du Colombier 32780ee5cbfSDavid du Colombier u.ax = CmdSetPowerMgmt; 32880ee5cbfSDavid du Colombier u.bx = dev; 32980ee5cbfSDavid du Colombier u.cx = state; 33080ee5cbfSDavid du Colombier return apmcall(apm->fd, &u); 33180ee5cbfSDavid du Colombier } 33280ee5cbfSDavid du Colombier 33380ee5cbfSDavid du Colombier static int 33480ee5cbfSDavid du Colombier apmrestoredefaults(Apm *apm, int dev) 33580ee5cbfSDavid du Colombier { 33680ee5cbfSDavid du Colombier Ureg u; 33780ee5cbfSDavid du Colombier 33880ee5cbfSDavid du Colombier u.ax = CmdRestoreDefaults; 33980ee5cbfSDavid du Colombier u.bx = dev; 34080ee5cbfSDavid du Colombier return apmcall(apm->fd, &u); 34180ee5cbfSDavid du Colombier } 34280ee5cbfSDavid du Colombier 34380ee5cbfSDavid du Colombier static int 34480ee5cbfSDavid du Colombier apmgetpowerstatus(Apm *apm, int dev) 34580ee5cbfSDavid du Colombier { 34680ee5cbfSDavid du Colombier Battery *b; 34780ee5cbfSDavid du Colombier Ureg u; 34880ee5cbfSDavid du Colombier 34980ee5cbfSDavid du Colombier if(dev == DevAll) 35080ee5cbfSDavid du Colombier b = &apm->battery[0]; 35180ee5cbfSDavid du Colombier else if((dev & DevMask) == DevBattery) { 35280ee5cbfSDavid du Colombier if(dev - DevBattery < nelem(apm->battery)) 35380ee5cbfSDavid du Colombier b = &apm->battery[dev - DevBattery]; 35480ee5cbfSDavid du Colombier else 35580ee5cbfSDavid du Colombier b = nil; 35680ee5cbfSDavid du Colombier } else { 35780ee5cbfSDavid du Colombier werrstr("bad device number"); 35880ee5cbfSDavid du Colombier return -1; 35980ee5cbfSDavid du Colombier } 36080ee5cbfSDavid du Colombier 36180ee5cbfSDavid du Colombier u.ax = CmdGetPowerStatus; 36280ee5cbfSDavid du Colombier u.bx = dev; 36380ee5cbfSDavid du Colombier 36480ee5cbfSDavid du Colombier if(apmcall(apm->fd, &u) < 0) 36580ee5cbfSDavid du Colombier return -1; 36680ee5cbfSDavid du Colombier 36780ee5cbfSDavid du Colombier if((dev & DevMask) == DevBattery) 36880ee5cbfSDavid du Colombier apm->nbattery = u.si; 36980ee5cbfSDavid du Colombier 37080ee5cbfSDavid du Colombier switch(u.bx>>8) { 37180ee5cbfSDavid du Colombier case 0x00: 37280ee5cbfSDavid du Colombier apm->acstatus = AcOffline; 37380ee5cbfSDavid du Colombier break; 37480ee5cbfSDavid du Colombier case 0x01: 37580ee5cbfSDavid du Colombier apm->acstatus = AcOnline; 37680ee5cbfSDavid du Colombier break; 37780ee5cbfSDavid du Colombier case 0x02: 37880ee5cbfSDavid du Colombier apm->acstatus = AcBackup; 37980ee5cbfSDavid du Colombier break; 38080ee5cbfSDavid du Colombier default: 38180ee5cbfSDavid du Colombier apm->acstatus = AcUnknown; 38280ee5cbfSDavid du Colombier break; 38380ee5cbfSDavid du Colombier } 38480ee5cbfSDavid du Colombier 38580ee5cbfSDavid du Colombier if(b != nil) { 38680ee5cbfSDavid du Colombier switch(u.bx&0xFF) { 38780ee5cbfSDavid du Colombier case 0x00: 38880ee5cbfSDavid du Colombier b->status = BatteryHigh; 38980ee5cbfSDavid du Colombier break; 39080ee5cbfSDavid du Colombier case 0x01: 39180ee5cbfSDavid du Colombier b->status = BatteryLow; 39280ee5cbfSDavid du Colombier break; 39380ee5cbfSDavid du Colombier case 0x02: 39480ee5cbfSDavid du Colombier b->status = BatteryCritical; 39580ee5cbfSDavid du Colombier break; 39680ee5cbfSDavid du Colombier case 0x03: 39780ee5cbfSDavid du Colombier b->status = BatteryCharging; 39880ee5cbfSDavid du Colombier break; 39980ee5cbfSDavid du Colombier default: 40080ee5cbfSDavid du Colombier b->status = BatteryUnknown; 40180ee5cbfSDavid du Colombier break; 40280ee5cbfSDavid du Colombier } 40380ee5cbfSDavid du Colombier 40480ee5cbfSDavid du Colombier if((u.cx & 0xFF) == 0xFF) 40580ee5cbfSDavid du Colombier b->percent = -1; 40680ee5cbfSDavid du Colombier else 40780ee5cbfSDavid du Colombier b->percent = u.cx & 0xFF; 40880ee5cbfSDavid du Colombier 40980ee5cbfSDavid du Colombier if((u.dx&0xFFFF) == 0xFFFF) 41080ee5cbfSDavid du Colombier b->time = -1; 41180ee5cbfSDavid du Colombier else if(u.dx & 0x8000) 41280ee5cbfSDavid du Colombier b->time = 60*(u.dx & 0x7FFF); 41380ee5cbfSDavid du Colombier else 41480ee5cbfSDavid du Colombier b->time = u.dx & 0x7FFF; 41580ee5cbfSDavid du Colombier } 41680ee5cbfSDavid du Colombier 41780ee5cbfSDavid du Colombier return 0; 41880ee5cbfSDavid du Colombier } 41980ee5cbfSDavid du Colombier 42080ee5cbfSDavid du Colombier static int 42180ee5cbfSDavid du Colombier apmgetevent(Apm *apm) 42280ee5cbfSDavid du Colombier { 42380ee5cbfSDavid du Colombier Ureg u; 42480ee5cbfSDavid du Colombier 42580ee5cbfSDavid du Colombier u.ax = CmdGetPMEvent; 42680ee5cbfSDavid du Colombier u.bx = 0; 42780ee5cbfSDavid du Colombier u.cx = 0; 42880ee5cbfSDavid du Colombier 42980ee5cbfSDavid du Colombier //when u.bx == NotifyNormalResume or NotifyCriticalResume, 43080ee5cbfSDavid du Colombier //u.cx & 1 indicates PCMCIA socket was on while suspended, 43180ee5cbfSDavid du Colombier //u.cx & 1 == 0 indicates was off. 43280ee5cbfSDavid du Colombier 43380ee5cbfSDavid du Colombier if(apmcall(apm->fd, &u) < 0) 43480ee5cbfSDavid du Colombier return -1; 43580ee5cbfSDavid du Colombier 43680ee5cbfSDavid du Colombier return u.bx; 43780ee5cbfSDavid du Colombier } 43880ee5cbfSDavid du Colombier 43980ee5cbfSDavid du Colombier static int 44080ee5cbfSDavid du Colombier apmgetpowerstate(Apm *apm, int dev) 44180ee5cbfSDavid du Colombier { 44280ee5cbfSDavid du Colombier Ureg u; 44380ee5cbfSDavid du Colombier 44480ee5cbfSDavid du Colombier u.ax = CmdGetPowerState; 44580ee5cbfSDavid du Colombier u.bx = dev; 44680ee5cbfSDavid du Colombier u.cx = 0; 44780ee5cbfSDavid du Colombier 44880ee5cbfSDavid du Colombier if(apmcall(apm->fd, &u) < 0) 44980ee5cbfSDavid du Colombier return -1; 45080ee5cbfSDavid du Colombier 45180ee5cbfSDavid du Colombier return u.cx; 45280ee5cbfSDavid du Colombier } 45380ee5cbfSDavid du Colombier 45480ee5cbfSDavid du Colombier static int 45580ee5cbfSDavid du Colombier apmgetpowermgmt(Apm *apm, int dev) 45680ee5cbfSDavid du Colombier { 45780ee5cbfSDavid du Colombier Ureg u; 45880ee5cbfSDavid du Colombier 45980ee5cbfSDavid du Colombier u.ax = CmdGetPowerMgmt; 46080ee5cbfSDavid du Colombier u.bx = dev; 46180ee5cbfSDavid du Colombier 46280ee5cbfSDavid du Colombier if(apmcall(apm->fd, &u) < 0) 46380ee5cbfSDavid du Colombier return -1; 46480ee5cbfSDavid du Colombier 46580ee5cbfSDavid du Colombier return u.cx; 46680ee5cbfSDavid du Colombier } 46780ee5cbfSDavid du Colombier 46880ee5cbfSDavid du Colombier static int 46980ee5cbfSDavid du Colombier apmgetcapabilities(Apm *apm) 47080ee5cbfSDavid du Colombier { 47180ee5cbfSDavid du Colombier Ureg u; 47280ee5cbfSDavid du Colombier 47380ee5cbfSDavid du Colombier u.ax = CmdGetCapabilities; 47480ee5cbfSDavid du Colombier u.bx = DevBios; 47580ee5cbfSDavid du Colombier 47680ee5cbfSDavid du Colombier if(apmcall(apm->fd, &u) < 0) 47780ee5cbfSDavid du Colombier return -1; 47880ee5cbfSDavid du Colombier 47980ee5cbfSDavid du Colombier apm->nbattery = u.bx & 0xFF; 48080ee5cbfSDavid du Colombier apm->capabilities &= ~0xFFFF; 48180ee5cbfSDavid du Colombier apm->capabilities |= u.cx; 48280ee5cbfSDavid du Colombier return 0; 48380ee5cbfSDavid du Colombier } 48480ee5cbfSDavid du Colombier 48580ee5cbfSDavid du Colombier static int 48680ee5cbfSDavid du Colombier apminstallationcheck(Apm *apm) 48780ee5cbfSDavid du Colombier { 48880ee5cbfSDavid du Colombier Ureg u; 48980ee5cbfSDavid du Colombier 49080ee5cbfSDavid du Colombier u.ax = CmdInstallationCheck; 49180ee5cbfSDavid du Colombier u.bx = DevBios; 49280ee5cbfSDavid du Colombier if(apmcall(apm->fd, &u) < 0) 49380ee5cbfSDavid du Colombier return -1; 49480ee5cbfSDavid du Colombier 49580ee5cbfSDavid du Colombier if(u.cx & 0x0004) 49680ee5cbfSDavid du Colombier apm->capabilities |= CapSlowCpu; 49780ee5cbfSDavid du Colombier else 49880ee5cbfSDavid du Colombier apm->capabilities &= ~CapSlowCpu; 49980ee5cbfSDavid du Colombier return 0; 50080ee5cbfSDavid du Colombier } 50180ee5cbfSDavid du Colombier 50280ee5cbfSDavid du Colombier void 50380ee5cbfSDavid du Colombier apmsetdisplaystate(Apm *apm, int s) 50480ee5cbfSDavid du Colombier { 50580ee5cbfSDavid du Colombier apmsetpowerstate(apm, DevDisplay, s); 50680ee5cbfSDavid du Colombier } 50780ee5cbfSDavid du Colombier 50880ee5cbfSDavid du Colombier void 50980ee5cbfSDavid du Colombier apmblank(Apm *apm) 51080ee5cbfSDavid du Colombier { 51180ee5cbfSDavid du Colombier apmsetdisplaystate(apm, PowerStandby); 51280ee5cbfSDavid du Colombier } 51380ee5cbfSDavid du Colombier 51480ee5cbfSDavid du Colombier void 51580ee5cbfSDavid du Colombier apmunblank(Apm *apm) 51680ee5cbfSDavid du Colombier { 51780ee5cbfSDavid du Colombier apmsetdisplaystate(apm, PowerEnabled); 51880ee5cbfSDavid du Colombier } 51980ee5cbfSDavid du Colombier 52080ee5cbfSDavid du Colombier void 52180ee5cbfSDavid du Colombier apmsuspend(Apm *apm) 52280ee5cbfSDavid du Colombier { 52380ee5cbfSDavid du Colombier apmsetpowerstate(apm, DevAll, PowerSuspend); 52480ee5cbfSDavid du Colombier } 52580ee5cbfSDavid du Colombier 52680ee5cbfSDavid du Colombier Apm apm; 52780ee5cbfSDavid du Colombier 52880ee5cbfSDavid du Colombier void 52980ee5cbfSDavid du Colombier powerprint(void) 53080ee5cbfSDavid du Colombier { 53180ee5cbfSDavid du Colombier print("%s", ctime(time(0))); 53280ee5cbfSDavid du Colombier if(apmgetpowerstatus(&apm, DevAll) == 0) { 53380ee5cbfSDavid du Colombier print("%d batteries\n", apm.nbattery); 53480ee5cbfSDavid du Colombier print("battery 0: status %s percent %d time %d:%.2d\n", 53580ee5cbfSDavid du Colombier batterystatus(apm.battery[0].status), apm.battery[0].percent, 53680ee5cbfSDavid du Colombier apm.battery[0].time/60, apm.battery[0].time%60); 53780ee5cbfSDavid du Colombier } 53880ee5cbfSDavid du Colombier } 53980ee5cbfSDavid du Colombier 54080ee5cbfSDavid du Colombier void* 54180ee5cbfSDavid du Colombier erealloc(void *v, ulong n) 54280ee5cbfSDavid du Colombier { 54380ee5cbfSDavid du Colombier v = realloc(v, n); 54480ee5cbfSDavid du Colombier if(v == nil) 54580ee5cbfSDavid du Colombier sysfatal("out of memory reallocating %lud", n); 54680ee5cbfSDavid du Colombier setmalloctag(v, getcallerpc(&v)); 54780ee5cbfSDavid du Colombier return v; 54880ee5cbfSDavid du Colombier } 54980ee5cbfSDavid du Colombier 55080ee5cbfSDavid du Colombier void* 55180ee5cbfSDavid du Colombier emalloc(ulong n) 55280ee5cbfSDavid du Colombier { 55380ee5cbfSDavid du Colombier void *v; 55480ee5cbfSDavid du Colombier 55580ee5cbfSDavid du Colombier v = malloc(n); 55680ee5cbfSDavid du Colombier if(v == nil) 55780ee5cbfSDavid du Colombier sysfatal("out of memory allocating %lud", n); 55880ee5cbfSDavid du Colombier memset(v, 0, n); 55980ee5cbfSDavid du Colombier setmalloctag(v, getcallerpc(&n)); 56080ee5cbfSDavid du Colombier return v; 56180ee5cbfSDavid du Colombier } 56280ee5cbfSDavid du Colombier 56380ee5cbfSDavid du Colombier char* 56480ee5cbfSDavid du Colombier estrdup(char *s) 56580ee5cbfSDavid du Colombier { 56680ee5cbfSDavid du Colombier int l; 56780ee5cbfSDavid du Colombier char *t; 56880ee5cbfSDavid du Colombier 56980ee5cbfSDavid du Colombier if (s == nil) 57080ee5cbfSDavid du Colombier return nil; 57180ee5cbfSDavid du Colombier l = strlen(s)+1; 57280ee5cbfSDavid du Colombier t = emalloc(l); 57380ee5cbfSDavid du Colombier memcpy(t, s, l); 57480ee5cbfSDavid du Colombier setmalloctag(t, getcallerpc(&s)); 57580ee5cbfSDavid du Colombier return t; 57680ee5cbfSDavid du Colombier } 57780ee5cbfSDavid du Colombier 57880ee5cbfSDavid du Colombier char* 57980ee5cbfSDavid du Colombier estrdupn(char *s, int n) 58080ee5cbfSDavid du Colombier { 58180ee5cbfSDavid du Colombier int l; 58280ee5cbfSDavid du Colombier char *t; 58380ee5cbfSDavid du Colombier 58480ee5cbfSDavid du Colombier l = strlen(s); 58580ee5cbfSDavid du Colombier if(l > n) 58680ee5cbfSDavid du Colombier l = n; 58780ee5cbfSDavid du Colombier t = emalloc(l+1); 58880ee5cbfSDavid du Colombier memmove(t, s, l); 58980ee5cbfSDavid du Colombier t[l] = '\0'; 59080ee5cbfSDavid du Colombier setmalloctag(t, getcallerpc(&s)); 59180ee5cbfSDavid du Colombier return t; 59280ee5cbfSDavid du Colombier } 59380ee5cbfSDavid du Colombier 59480ee5cbfSDavid du Colombier enum { 5959a747e4fSDavid du Colombier Qroot = 0, 5969a747e4fSDavid du Colombier Qevent, 59780ee5cbfSDavid du Colombier Qbattery, 59880ee5cbfSDavid du Colombier Qctl, 59980ee5cbfSDavid du Colombier }; 60080ee5cbfSDavid du Colombier 6019a747e4fSDavid du Colombier static void rootread(Req*); 6029a747e4fSDavid du Colombier static void eventread(Req*); 6039a747e4fSDavid du Colombier static void ctlread(Req*); 6049a747e4fSDavid du Colombier static void ctlwrite(Req*); 6059a747e4fSDavid du Colombier static void batteryread(Req*); 60680ee5cbfSDavid du Colombier 60780ee5cbfSDavid du Colombier typedef struct Dfile Dfile; 60880ee5cbfSDavid du Colombier struct Dfile { 6099a747e4fSDavid du Colombier Qid qid; 61080ee5cbfSDavid du Colombier char *name; 61180ee5cbfSDavid du Colombier ulong mode; 6129a747e4fSDavid du Colombier void (*read)(Req*); 6139a747e4fSDavid du Colombier void (*write)(Req*); 61480ee5cbfSDavid du Colombier }; 61580ee5cbfSDavid du Colombier 61680ee5cbfSDavid du Colombier Dfile dfile[] = { 6179a747e4fSDavid du Colombier { {Qroot,0,QTDIR}, "/", DMDIR|0555, rootread, nil, }, 6189a747e4fSDavid du Colombier { {Qevent}, "event", 0444, eventread, nil, }, 6199a747e4fSDavid du Colombier { {Qbattery}, "battery", 0444, batteryread, nil, }, 6209a747e4fSDavid du Colombier { {Qctl}, "ctl", 0666, ctlread, ctlwrite, }, 62180ee5cbfSDavid du Colombier }; 62280ee5cbfSDavid du Colombier 62380ee5cbfSDavid du Colombier static int 6249a747e4fSDavid du Colombier fillstat(ulong path, Dir *d, int doalloc) 62580ee5cbfSDavid du Colombier { 62680ee5cbfSDavid du Colombier int i; 62780ee5cbfSDavid du Colombier 62880ee5cbfSDavid du Colombier for(i=0; i<nelem(dfile); i++) 6299a747e4fSDavid du Colombier if(path==dfile[i].qid.path) 63080ee5cbfSDavid du Colombier break; 63180ee5cbfSDavid du Colombier if(i==nelem(dfile)) 63280ee5cbfSDavid du Colombier return -1; 63380ee5cbfSDavid du Colombier 63480ee5cbfSDavid du Colombier memset(d, 0, sizeof *d); 6359a747e4fSDavid du Colombier d->uid = doalloc ? estrdup("apm") : "apm"; 6369a747e4fSDavid du Colombier d->gid = doalloc ? estrdup("apm") : "apm"; 63780ee5cbfSDavid du Colombier d->length = 0; 6389a747e4fSDavid du Colombier d->name = doalloc ? estrdup(dfile[i].name) : dfile[i].name; 63980ee5cbfSDavid du Colombier d->mode = dfile[i].mode; 64080ee5cbfSDavid du Colombier d->atime = d->mtime = time(0); 6419a747e4fSDavid du Colombier d->qid = dfile[i].qid; 64280ee5cbfSDavid du Colombier return 0; 64380ee5cbfSDavid du Colombier } 64480ee5cbfSDavid du Colombier 6459a747e4fSDavid du Colombier static char* 6469a747e4fSDavid du Colombier fswalk1(Fid *fid, char *name, Qid *qid) 64780ee5cbfSDavid du Colombier { 64880ee5cbfSDavid du Colombier int i; 64980ee5cbfSDavid du Colombier 65080ee5cbfSDavid du Colombier if(strcmp(name, "..")==0){ 6519a747e4fSDavid du Colombier *qid = dfile[0].qid; 6529a747e4fSDavid du Colombier fid->qid = *qid; 6539a747e4fSDavid du Colombier return nil; 65480ee5cbfSDavid du Colombier } 65580ee5cbfSDavid du Colombier 65680ee5cbfSDavid du Colombier for(i=1; i<nelem(dfile); i++){ /* i=1: 0 is root dir */ 65780ee5cbfSDavid du Colombier if(strcmp(dfile[i].name, name)==0){ 6589a747e4fSDavid du Colombier *qid = dfile[i].qid; 6599a747e4fSDavid du Colombier fid->qid = *qid; 6609a747e4fSDavid du Colombier return nil; 66180ee5cbfSDavid du Colombier } 66280ee5cbfSDavid du Colombier } 6639a747e4fSDavid du Colombier return "file does not exist"; 66480ee5cbfSDavid du Colombier } 66580ee5cbfSDavid du Colombier 66680ee5cbfSDavid du Colombier static void 6679a747e4fSDavid du Colombier fsopen(Req *r) 66880ee5cbfSDavid du Colombier { 6699a747e4fSDavid du Colombier switch((ulong)r->fid->qid.path){ 67080ee5cbfSDavid du Colombier case Qroot: 6719a747e4fSDavid du Colombier r->fid->aux = (void*)0; 6729a747e4fSDavid du Colombier respond(r, nil); 6739a747e4fSDavid du Colombier return; 6749a747e4fSDavid du Colombier 67580ee5cbfSDavid du Colombier case Qevent: 67680ee5cbfSDavid du Colombier case Qbattery: 6779a747e4fSDavid du Colombier if(r->ifcall.mode == OREAD){ 67880ee5cbfSDavid du Colombier respond(r, nil); 67980ee5cbfSDavid du Colombier return; 68080ee5cbfSDavid du Colombier } 68180ee5cbfSDavid du Colombier break; 68280ee5cbfSDavid du Colombier 68380ee5cbfSDavid du Colombier case Qctl: 6849a747e4fSDavid du Colombier if((r->ifcall.mode&~(OTRUNC|OREAD|OWRITE|ORDWR)) == 0){ 68580ee5cbfSDavid du Colombier respond(r, nil); 68680ee5cbfSDavid du Colombier return; 68780ee5cbfSDavid du Colombier } 68880ee5cbfSDavid du Colombier break; 68980ee5cbfSDavid du Colombier } 69080ee5cbfSDavid du Colombier respond(r, "permission denied"); 69180ee5cbfSDavid du Colombier return; 69280ee5cbfSDavid du Colombier } 69380ee5cbfSDavid du Colombier 69480ee5cbfSDavid du Colombier static void 6959a747e4fSDavid du Colombier fsstat(Req *r) 69680ee5cbfSDavid du Colombier { 6979a747e4fSDavid du Colombier fillstat(r->fid->qid.path, &r->d, 1); 69880ee5cbfSDavid du Colombier respond(r, nil); 69980ee5cbfSDavid du Colombier } 70080ee5cbfSDavid du Colombier 70180ee5cbfSDavid du Colombier static void 7029a747e4fSDavid du Colombier fsread(Req *r) 70380ee5cbfSDavid du Colombier { 7049a747e4fSDavid du Colombier dfile[r->fid->qid.path].read(r); 70580ee5cbfSDavid du Colombier } 70680ee5cbfSDavid du Colombier 70780ee5cbfSDavid du Colombier static void 7089a747e4fSDavid du Colombier fswrite(Req *r) 70980ee5cbfSDavid du Colombier { 7109a747e4fSDavid du Colombier dfile[r->fid->qid.path].write(r); 71180ee5cbfSDavid du Colombier } 71280ee5cbfSDavid du Colombier 71380ee5cbfSDavid du Colombier static void 7149a747e4fSDavid du Colombier rootread(Req *r) 71580ee5cbfSDavid du Colombier { 7169a747e4fSDavid du Colombier int n, offset; 7179a747e4fSDavid du Colombier char *p, *ep; 71880ee5cbfSDavid du Colombier Dir d; 71980ee5cbfSDavid du Colombier 7209a747e4fSDavid du Colombier if(r->ifcall.offset == 0) 7219a747e4fSDavid du Colombier offset = 0; 7229a747e4fSDavid du Colombier else 7239a747e4fSDavid du Colombier offset = (int)r->fid->aux; 7249a747e4fSDavid du Colombier 7259a747e4fSDavid du Colombier p = r->ofcall.data; 7269a747e4fSDavid du Colombier ep = r->ofcall.data+r->ifcall.count; 7279a747e4fSDavid du Colombier 7289a747e4fSDavid du Colombier if(offset == 0) /* skip root */ 7299a747e4fSDavid du Colombier offset = 1; 7309a747e4fSDavid du Colombier for(; p+2 < ep; p+=n){ 7319a747e4fSDavid du Colombier if(fillstat(offset, &d, 0) < 0) 73280ee5cbfSDavid du Colombier break; 7339a747e4fSDavid du Colombier n = convD2M(&d, (uchar*)p, ep-p); 7349a747e4fSDavid du Colombier if(n <= BIT16SZ) 7359a747e4fSDavid du Colombier break; 7369a747e4fSDavid du Colombier offset++; 73780ee5cbfSDavid du Colombier } 7389a747e4fSDavid du Colombier r->fid->aux = (void*)offset; 7399a747e4fSDavid du Colombier r->ofcall.count = p - r->ofcall.data; 74080ee5cbfSDavid du Colombier respond(r, nil); 74180ee5cbfSDavid du Colombier } 74280ee5cbfSDavid du Colombier 74380ee5cbfSDavid du Colombier static void 7449a747e4fSDavid du Colombier batteryread(Req *r) 74580ee5cbfSDavid du Colombier { 74680ee5cbfSDavid du Colombier char buf[Mbattery*80], *ep, *p; 74780ee5cbfSDavid du Colombier int i; 74880ee5cbfSDavid du Colombier 74980ee5cbfSDavid du Colombier apmgetpowerstatus(&apm, DevAll); 75080ee5cbfSDavid du Colombier 75180ee5cbfSDavid du Colombier p = buf; 75280ee5cbfSDavid du Colombier ep = buf+sizeof buf; 7539a747e4fSDavid du Colombier *p = '\0'; /* could be no batteries */ 75480ee5cbfSDavid du Colombier for(i=0; i<apm.nbattery && i<Mbattery; i++) 75580ee5cbfSDavid du Colombier p += snprint(p, ep-p, "%s %d %d\n", 75680ee5cbfSDavid du Colombier batterystatus(apm.battery[i].status), 75780ee5cbfSDavid du Colombier apm.battery[i].percent, apm.battery[i].time); 75880ee5cbfSDavid du Colombier 7599a747e4fSDavid du Colombier readstr(r, buf); 76080ee5cbfSDavid du Colombier respond(r, nil); 76180ee5cbfSDavid du Colombier } 76280ee5cbfSDavid du Colombier 76380ee5cbfSDavid du Colombier int 76480ee5cbfSDavid du Colombier iscmd(char *p, char *cmd) 76580ee5cbfSDavid du Colombier { 76680ee5cbfSDavid du Colombier int l; 76780ee5cbfSDavid du Colombier 76880ee5cbfSDavid du Colombier l = strlen(cmd); 76980ee5cbfSDavid du Colombier return strncmp(p, cmd, l)==0 && p[l]=='\0' || p[l]==' ' || p[l]=='\t'; 77080ee5cbfSDavid du Colombier } 77180ee5cbfSDavid du Colombier 77280ee5cbfSDavid du Colombier char* 77380ee5cbfSDavid du Colombier skip(char *p, char *cmd) 77480ee5cbfSDavid du Colombier { 77580ee5cbfSDavid du Colombier p += strlen(cmd); 77680ee5cbfSDavid du Colombier while(*p==' ' || *p=='\t') 77780ee5cbfSDavid du Colombier p++; 77880ee5cbfSDavid du Colombier return p; 77980ee5cbfSDavid du Colombier } 78080ee5cbfSDavid du Colombier 78180ee5cbfSDavid du Colombier static void 78280ee5cbfSDavid du Colombier respondx(Req *r, int c) 78380ee5cbfSDavid du Colombier { 7849a747e4fSDavid du Colombier char err[ERRMAX]; 78580ee5cbfSDavid du Colombier 78680ee5cbfSDavid du Colombier if(c == 0) 78780ee5cbfSDavid du Colombier respond(r, nil); 78880ee5cbfSDavid du Colombier else{ 7899a747e4fSDavid du Colombier rerrstr(err, sizeof err); 79080ee5cbfSDavid du Colombier respond(r, err); 79180ee5cbfSDavid du Colombier } 79280ee5cbfSDavid du Colombier } 79380ee5cbfSDavid du Colombier 79480ee5cbfSDavid du Colombier /* 79580ee5cbfSDavid du Colombier * we don't do suspend because it messes up the 79680ee5cbfSDavid du Colombier * cycle counter as well as the pcmcia ethernet cards. 79780ee5cbfSDavid du Colombier */ 79880ee5cbfSDavid du Colombier static void 7999a747e4fSDavid du Colombier ctlwrite(Req *r) 80080ee5cbfSDavid du Colombier { 80180ee5cbfSDavid du Colombier char buf[80], *p, *q; 80280ee5cbfSDavid du Colombier int dev; 8039a747e4fSDavid du Colombier long count; 80480ee5cbfSDavid du Colombier 8059a747e4fSDavid du Colombier count = r->ifcall.count; 8069a747e4fSDavid du Colombier if(count > sizeof(buf)-1) 8079a747e4fSDavid du Colombier count = sizeof(buf)-1; 8089a747e4fSDavid du Colombier memmove(buf, r->ifcall.data, count); 8099a747e4fSDavid du Colombier buf[count] = '\0'; 81080ee5cbfSDavid du Colombier 8119a747e4fSDavid du Colombier if(count && buf[count-1] == '\n'){ 8129a747e4fSDavid du Colombier --count; 8139a747e4fSDavid du Colombier buf[count] = '\0'; 8149a747e4fSDavid du Colombier } 81580ee5cbfSDavid du Colombier 81680ee5cbfSDavid du Colombier q = buf; 81780ee5cbfSDavid du Colombier p = strchr(q, ' '); 81880ee5cbfSDavid du Colombier if(p==nil) 81980ee5cbfSDavid du Colombier p = q+strlen(q); 82080ee5cbfSDavid du Colombier else 82180ee5cbfSDavid du Colombier *p++ = '\0'; 82280ee5cbfSDavid du Colombier 82380ee5cbfSDavid du Colombier if(strcmp(q, "")==0 || strcmp(q, "system")==0) 82480ee5cbfSDavid du Colombier dev = DevAll; 82580ee5cbfSDavid du Colombier else if(strcmp(q, "display")==0) 82680ee5cbfSDavid du Colombier dev = DevDisplay; 82780ee5cbfSDavid du Colombier else if(strcmp(q, "storage")==0) 82880ee5cbfSDavid du Colombier dev = DevStorage; 82980ee5cbfSDavid du Colombier else if(strcmp(q, "lpt")==0) 83080ee5cbfSDavid du Colombier dev = DevLpt; 83180ee5cbfSDavid du Colombier else if(strcmp(q, "eia")==0) 83280ee5cbfSDavid du Colombier dev = DevEia; 83380ee5cbfSDavid du Colombier else if(strcmp(q, "network")==0) 83480ee5cbfSDavid du Colombier dev = DevNetwork; 83580ee5cbfSDavid du Colombier else if(strcmp(q, "pcmcia")==0) 83680ee5cbfSDavid du Colombier dev = DevPCMCIA; 83780ee5cbfSDavid du Colombier else{ 83880ee5cbfSDavid du Colombier respond(r, "unknown device"); 83980ee5cbfSDavid du Colombier return; 84080ee5cbfSDavid du Colombier } 84180ee5cbfSDavid du Colombier 84280ee5cbfSDavid du Colombier if(strcmp(p, "enable")==0) 84380ee5cbfSDavid du Colombier respondx(r, apmsetpowermgmt(&apm, dev, EnablePowerMgmt)); 84480ee5cbfSDavid du Colombier else if(strcmp(p, "disable")==0) 84580ee5cbfSDavid du Colombier respondx(r, apmsetpowermgmt(&apm, dev, DisablePowerMgmt)); 84680ee5cbfSDavid du Colombier else if(strcmp(p, "standby")==0) 84780ee5cbfSDavid du Colombier respondx(r, apmsetpowerstate(&apm, dev, PowerStandby)); 84880ee5cbfSDavid du Colombier else if(strcmp(p, "on")==0) 84980ee5cbfSDavid du Colombier respondx(r, apmsetpowerstate(&apm, dev, PowerEnabled)); 85080ee5cbfSDavid du Colombier /* 85180ee5cbfSDavid du Colombier else if(strcmp(p, "off")==0) 85280ee5cbfSDavid du Colombier respondx(r, apmsetpowerstate(&apm, dev, PowerOff)); 8539a747e4fSDavid du Colombier */ 85480ee5cbfSDavid du Colombier else if(strcmp(p, "suspend")==0) 85580ee5cbfSDavid du Colombier respondx(r, apmsetpowerstate(&apm, dev, PowerSuspend)); 85680ee5cbfSDavid du Colombier else 85780ee5cbfSDavid du Colombier respond(r, "unknown verb"); 85880ee5cbfSDavid du Colombier } 85980ee5cbfSDavid du Colombier 86080ee5cbfSDavid du Colombier static int 86180ee5cbfSDavid du Colombier statusline(char *buf, int nbuf, char *name, int dev) 86280ee5cbfSDavid du Colombier { 86380ee5cbfSDavid du Colombier int s; 86480ee5cbfSDavid du Colombier char *state; 86580ee5cbfSDavid du Colombier 86680ee5cbfSDavid du Colombier state = "unknown"; 86780ee5cbfSDavid du Colombier if((s = apmgetpowerstate(&apm, dev)) >= 0) 86880ee5cbfSDavid du Colombier state = powerstate(s); 86980ee5cbfSDavid du Colombier return snprint(buf, nbuf, "%s %s\n", name, state); 87080ee5cbfSDavid du Colombier } 87180ee5cbfSDavid du Colombier 87280ee5cbfSDavid du Colombier static void 8739a747e4fSDavid du Colombier ctlread(Req *r) 87480ee5cbfSDavid du Colombier { 87580ee5cbfSDavid du Colombier char buf[256+7*50], *ep, *p; 87680ee5cbfSDavid du Colombier 87780ee5cbfSDavid du Colombier p = buf; 87880ee5cbfSDavid du Colombier ep = buf+sizeof buf; 87980ee5cbfSDavid du Colombier 88080ee5cbfSDavid du Colombier p += snprint(p, ep-p, "ac %s\n", acstatus(apm.acstatus)); 88180ee5cbfSDavid du Colombier p += snprint(p, ep-p, "capabilities"); 88280ee5cbfSDavid du Colombier if(apm.capabilities & CapStandby) 88380ee5cbfSDavid du Colombier p += snprint(p, ep-p, " standby"); 88480ee5cbfSDavid du Colombier if(apm.capabilities & CapSuspend) 88580ee5cbfSDavid du Colombier p += snprint(p, ep-p, " suspend"); 88680ee5cbfSDavid du Colombier if(apm.capabilities & CapSlowCpu) 88780ee5cbfSDavid du Colombier p += snprint(p, ep-p, " slowcpu"); 88880ee5cbfSDavid du Colombier p += snprint(p, ep-p, "\n"); 88980ee5cbfSDavid du Colombier 89080ee5cbfSDavid du Colombier p += statusline(p, ep-p, "system", DevAll); 89180ee5cbfSDavid du Colombier p += statusline(p, ep-p, "display", DevDisplay); 89280ee5cbfSDavid du Colombier p += statusline(p, ep-p, "storage", DevStorage); 89380ee5cbfSDavid du Colombier p += statusline(p, ep-p, "lpt", DevLpt); 89480ee5cbfSDavid du Colombier p += statusline(p, ep-p, "eia", DevEia|All); 89580ee5cbfSDavid du Colombier p += statusline(p, ep-p, "network", DevNetwork|All); 89680ee5cbfSDavid du Colombier p += statusline(p, ep-p, "pcmcia", DevPCMCIA|All); 89780ee5cbfSDavid du Colombier USED(p); 89880ee5cbfSDavid du Colombier 8999a747e4fSDavid du Colombier readstr(r, buf); 90080ee5cbfSDavid du Colombier respond(r, nil); 90180ee5cbfSDavid du Colombier } 90280ee5cbfSDavid du Colombier 90380ee5cbfSDavid du Colombier enum { 90480ee5cbfSDavid du Colombier STACK = 16384, 90580ee5cbfSDavid du Colombier }; 90680ee5cbfSDavid du Colombier 90780ee5cbfSDavid du Colombier Channel *creq; 90880ee5cbfSDavid du Colombier Channel *cflush; 90980ee5cbfSDavid du Colombier Channel *cevent; 91080ee5cbfSDavid du Colombier Req *rlist, **tailp; 91180ee5cbfSDavid du Colombier int rp, wp; 91280ee5cbfSDavid du Colombier int nopoll; 91380ee5cbfSDavid du Colombier char eventq[32][80]; 91480ee5cbfSDavid du Colombier 91580ee5cbfSDavid du Colombier static void 91680ee5cbfSDavid du Colombier flushthread(void*) 91780ee5cbfSDavid du Colombier { 91880ee5cbfSDavid du Colombier Req *r, *or, **rq; 91980ee5cbfSDavid du Colombier 92080ee5cbfSDavid du Colombier threadsetname("flushthread"); 92180ee5cbfSDavid du Colombier while(r = recvp(cflush)){ 92280ee5cbfSDavid du Colombier or = r->oldreq; 92380ee5cbfSDavid du Colombier for(rq=&rlist; *rq; rq=&(*rq)->aux){ 92480ee5cbfSDavid du Colombier if(*rq == or){ 92580ee5cbfSDavid du Colombier *rq = or->aux; 92680ee5cbfSDavid du Colombier if(tailp==&or->aux) 92780ee5cbfSDavid du Colombier tailp = rq; 928d3c05884SDavid du Colombier respond(or, "interrupted"); 92980ee5cbfSDavid du Colombier break; 93080ee5cbfSDavid du Colombier } 93180ee5cbfSDavid du Colombier } 93280ee5cbfSDavid du Colombier respond(r, nil); 93380ee5cbfSDavid du Colombier } 93480ee5cbfSDavid du Colombier } 93580ee5cbfSDavid du Colombier 93680ee5cbfSDavid du Colombier static void 93780ee5cbfSDavid du Colombier answerany(void) 93880ee5cbfSDavid du Colombier { 93980ee5cbfSDavid du Colombier char *buf; 94080ee5cbfSDavid du Colombier int l, m; 94180ee5cbfSDavid du Colombier Req *r; 94280ee5cbfSDavid du Colombier 94380ee5cbfSDavid du Colombier if(rlist==nil || rp==wp) 94480ee5cbfSDavid du Colombier return; 94580ee5cbfSDavid du Colombier 94680ee5cbfSDavid du Colombier while(rlist && rp != wp){ 94780ee5cbfSDavid du Colombier r = rlist; 94880ee5cbfSDavid du Colombier rlist = r->aux; 94980ee5cbfSDavid du Colombier if(rlist==nil) 95080ee5cbfSDavid du Colombier tailp = &rlist; 95180ee5cbfSDavid du Colombier 95280ee5cbfSDavid du Colombier l = 0; 95380ee5cbfSDavid du Colombier buf = r->ofcall.data; 954*da51d93aSDavid du Colombier m = r->ifcall.count; 95580ee5cbfSDavid du Colombier while(rp != wp){ 95680ee5cbfSDavid du Colombier if(l+strlen(eventq[rp]) <= m){ 95780ee5cbfSDavid du Colombier strcpy(buf+l, eventq[rp]); 95880ee5cbfSDavid du Colombier l += strlen(buf+l); 95980ee5cbfSDavid du Colombier }else if(l==0){ 96080ee5cbfSDavid du Colombier strncpy(buf, eventq[rp], m-1); 96180ee5cbfSDavid du Colombier buf[m-1] = '\0'; 96280ee5cbfSDavid du Colombier l += m; 96380ee5cbfSDavid du Colombier }else 96480ee5cbfSDavid du Colombier break; 96580ee5cbfSDavid du Colombier rp++; 96680ee5cbfSDavid du Colombier if(rp == nelem(eventq)) 96780ee5cbfSDavid du Colombier rp = 0; 96880ee5cbfSDavid du Colombier } 96980ee5cbfSDavid du Colombier r->ofcall.count = l; 97080ee5cbfSDavid du Colombier respond(r, nil); 97180ee5cbfSDavid du Colombier } 97280ee5cbfSDavid du Colombier } 97380ee5cbfSDavid du Colombier 97480ee5cbfSDavid du Colombier static void 97580ee5cbfSDavid du Colombier eventwatch(void*) 97680ee5cbfSDavid du Colombier { 97780ee5cbfSDavid du Colombier int e, s; 97880ee5cbfSDavid du Colombier 97980ee5cbfSDavid du Colombier threadsetname("eventwatch"); 98080ee5cbfSDavid du Colombier for(;;){ 98180ee5cbfSDavid du Colombier s = 0; 98280ee5cbfSDavid du Colombier while((e = apmgetevent(&apm)) >= 0){ 98380ee5cbfSDavid du Colombier sendul(cevent, e); 98480ee5cbfSDavid du Colombier s = 1; 98580ee5cbfSDavid du Colombier } 98680ee5cbfSDavid du Colombier if(s) 98780ee5cbfSDavid du Colombier sendul(cevent, -1); 98880ee5cbfSDavid du Colombier if(sleep(750) < 0) 98980ee5cbfSDavid du Colombier break; 99080ee5cbfSDavid du Colombier } 99180ee5cbfSDavid du Colombier } 99280ee5cbfSDavid du Colombier 99380ee5cbfSDavid du Colombier static void 99480ee5cbfSDavid du Colombier eventthread(void*) 99580ee5cbfSDavid du Colombier { 99680ee5cbfSDavid du Colombier int e; 99780ee5cbfSDavid du Colombier 99880ee5cbfSDavid du Colombier threadsetname("eventthread"); 99980ee5cbfSDavid du Colombier for(;;){ 100080ee5cbfSDavid du Colombier while((e = recvul(cevent)) >= 0){ 100180ee5cbfSDavid du Colombier snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e)); 100280ee5cbfSDavid du Colombier strcat(eventq[wp], "\n"); 100380ee5cbfSDavid du Colombier wp++; 100480ee5cbfSDavid du Colombier if(wp==nelem(eventq)) 100580ee5cbfSDavid du Colombier wp = 0; 100680ee5cbfSDavid du Colombier if(wp+1==rp || (wp+1==nelem(eventq) && rp==0)) 100780ee5cbfSDavid du Colombier break; 100880ee5cbfSDavid du Colombier } 100980ee5cbfSDavid du Colombier answerany(); 101080ee5cbfSDavid du Colombier } 101180ee5cbfSDavid du Colombier } 101280ee5cbfSDavid du Colombier 101380ee5cbfSDavid du Colombier static void 101480ee5cbfSDavid du Colombier eventproc(void*) 101580ee5cbfSDavid du Colombier { 101680ee5cbfSDavid du Colombier Req *r; 101780ee5cbfSDavid du Colombier 101880ee5cbfSDavid du Colombier threadsetname("eventproc"); 101980ee5cbfSDavid du Colombier 102080ee5cbfSDavid du Colombier creq = chancreate(sizeof(Req*), 0); 102180ee5cbfSDavid du Colombier cevent = chancreate(sizeof(ulong), 0); 102280ee5cbfSDavid du Colombier cflush = chancreate(sizeof(Req*), 0); 102380ee5cbfSDavid du Colombier 102480ee5cbfSDavid du Colombier tailp = &rlist; 102580ee5cbfSDavid du Colombier if(!nopoll) 102680ee5cbfSDavid du Colombier proccreate(eventwatch, nil, STACK); 102780ee5cbfSDavid du Colombier threadcreate(eventthread, nil, STACK); 102880ee5cbfSDavid du Colombier threadcreate(flushthread, nil, STACK); 102980ee5cbfSDavid du Colombier 103080ee5cbfSDavid du Colombier while(r = recvp(creq)){ 103180ee5cbfSDavid du Colombier *tailp = r; 103280ee5cbfSDavid du Colombier r->aux = nil; 103380ee5cbfSDavid du Colombier tailp = &r->aux; 103480ee5cbfSDavid du Colombier answerany(); 103580ee5cbfSDavid du Colombier } 103680ee5cbfSDavid du Colombier } 103780ee5cbfSDavid du Colombier 103880ee5cbfSDavid du Colombier static void 10399a747e4fSDavid du Colombier fsflush(Req *r) 104080ee5cbfSDavid du Colombier { 104180ee5cbfSDavid du Colombier sendp(cflush, r); 104280ee5cbfSDavid du Colombier } 104380ee5cbfSDavid du Colombier 104480ee5cbfSDavid du Colombier static void 10459a747e4fSDavid du Colombier eventread(Req *r) 104680ee5cbfSDavid du Colombier { 104780ee5cbfSDavid du Colombier sendp(creq, r); 104880ee5cbfSDavid du Colombier } 104980ee5cbfSDavid du Colombier 105080ee5cbfSDavid du Colombier static void 10519a747e4fSDavid du Colombier fsattach(Req *r) 105280ee5cbfSDavid du Colombier { 10539a747e4fSDavid du Colombier char *spec; 105480ee5cbfSDavid du Colombier static int first = 1; 105580ee5cbfSDavid du Colombier 10569a747e4fSDavid du Colombier spec = r->ifcall.aname; 10579a747e4fSDavid du Colombier 105880ee5cbfSDavid du Colombier if(first){ 105980ee5cbfSDavid du Colombier first = 0; 106080ee5cbfSDavid du Colombier proccreate(eventproc, nil, STACK); 106180ee5cbfSDavid du Colombier } 106280ee5cbfSDavid du Colombier 106380ee5cbfSDavid du Colombier if(spec && spec[0]){ 106480ee5cbfSDavid du Colombier respond(r, "invalid attach specifier"); 106580ee5cbfSDavid du Colombier return; 106680ee5cbfSDavid du Colombier } 10679a747e4fSDavid du Colombier r->fid->qid = dfile[0].qid; 10689a747e4fSDavid du Colombier r->ofcall.qid = dfile[0].qid; 106980ee5cbfSDavid du Colombier respond(r, nil); 107080ee5cbfSDavid du Colombier } 107180ee5cbfSDavid du Colombier 10729a747e4fSDavid du Colombier Srv fs = { 107380ee5cbfSDavid du Colombier .attach= fsattach, 10749a747e4fSDavid du Colombier .walk1= fswalk1, 107580ee5cbfSDavid du Colombier .open= fsopen, 107680ee5cbfSDavid du Colombier .read= fsread, 107780ee5cbfSDavid du Colombier .write= fswrite, 107880ee5cbfSDavid du Colombier .stat= fsstat, 107980ee5cbfSDavid du Colombier .flush= fsflush, 108080ee5cbfSDavid du Colombier }; 108180ee5cbfSDavid du Colombier 108280ee5cbfSDavid du Colombier void 10839a747e4fSDavid du Colombier usage(void) 10849a747e4fSDavid du Colombier { 10859a747e4fSDavid du Colombier fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n"); 10869a747e4fSDavid du Colombier exits("usage"); 10879a747e4fSDavid du Colombier } 10889a747e4fSDavid du Colombier 10899a747e4fSDavid du Colombier void 109080ee5cbfSDavid du Colombier threadmain(int argc, char **argv) 109180ee5cbfSDavid du Colombier { 109280ee5cbfSDavid du Colombier char *dev, *mtpt, *srv; 109380ee5cbfSDavid du Colombier 10949a747e4fSDavid du Colombier dev = nil; 109580ee5cbfSDavid du Colombier mtpt = "/mnt/apm"; 109680ee5cbfSDavid du Colombier srv = nil; 109780ee5cbfSDavid du Colombier ARGBEGIN{ 109880ee5cbfSDavid du Colombier case 'A': 109980ee5cbfSDavid du Colombier apmdebug = 1; 110080ee5cbfSDavid du Colombier break; 110180ee5cbfSDavid du Colombier case 'D': 11029a747e4fSDavid du Colombier chatty9p = 1; 110380ee5cbfSDavid du Colombier break; 110480ee5cbfSDavid du Colombier case 'P': 110580ee5cbfSDavid du Colombier nopoll = 1; 110680ee5cbfSDavid du Colombier break; 110780ee5cbfSDavid du Colombier case 'd': 110880ee5cbfSDavid du Colombier dev = EARGF(usage()); 110980ee5cbfSDavid du Colombier break; 11109a747e4fSDavid du Colombier case 'i': 11119a747e4fSDavid du Colombier fs.nopipe++; 11129a747e4fSDavid du Colombier fs.infd = 0; 11139a747e4fSDavid du Colombier fs.outfd = 1; 11149a747e4fSDavid du Colombier mtpt = nil; 11159a747e4fSDavid du Colombier break; 111680ee5cbfSDavid du Colombier case 'm': 111780ee5cbfSDavid du Colombier mtpt = EARGF(usage()); 111880ee5cbfSDavid du Colombier break; 111980ee5cbfSDavid du Colombier case 's': 112080ee5cbfSDavid du Colombier srv = EARGF(usage()); 112180ee5cbfSDavid du Colombier break; 112280ee5cbfSDavid du Colombier }ARGEND 112380ee5cbfSDavid du Colombier 11249a747e4fSDavid du Colombier if(dev == nil){ 11259a747e4fSDavid du Colombier if((apm.fd = open("/dev/apm", ORDWR)) < 0 11269a747e4fSDavid du Colombier && (apm.fd = open("#P/apm", ORDWR)) < 0){ 11279a747e4fSDavid du Colombier fprint(2, "open %s: %r\n", dev); 11289a747e4fSDavid du Colombier threadexitsall("open"); 11299a747e4fSDavid du Colombier } 11309a747e4fSDavid du Colombier } else if((apm.fd = open(dev, ORDWR)) < 0){ 11319a747e4fSDavid du Colombier fprint(2, "open %s: %r\n", dev); 113280ee5cbfSDavid du Colombier threadexitsall("open"); 113380ee5cbfSDavid du Colombier } 113480ee5cbfSDavid du Colombier 113580ee5cbfSDavid du Colombier if(apmversion(&apm) < 0){ 11369a747e4fSDavid du Colombier fprint(2, "cannot get apm version: %r\n"); 113780ee5cbfSDavid du Colombier threadexitsall("apmversion"); 113880ee5cbfSDavid du Colombier } 113980ee5cbfSDavid du Colombier 114080ee5cbfSDavid du Colombier if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){ 11419a747e4fSDavid du Colombier fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo); 114280ee5cbfSDavid du Colombier threadexitsall("apmversion"); 114380ee5cbfSDavid du Colombier } 114480ee5cbfSDavid du Colombier 114580ee5cbfSDavid du Colombier if(apmgetcapabilities(&apm) < 0) 11469a747e4fSDavid du Colombier fprint(2, "warning: cannot read apm capabilities: %r\n"); 114780ee5cbfSDavid du Colombier 114880ee5cbfSDavid du Colombier apminstallationcheck(&apm); 114980ee5cbfSDavid du Colombier apmcpuidle(&apm); 115080ee5cbfSDavid du Colombier 11519a747e4fSDavid du Colombier rfork(RFNOTEG); 11529a747e4fSDavid du Colombier threadpostmountsrv(&fs, srv, mtpt, MREPL); 115380ee5cbfSDavid du Colombier } 1154