|
@@ -1,1163 +0,0 @@
|
|
|
-/*
|
|
|
- * This file is part of the UCB release of Plan 9. It is subject to the license
|
|
|
- * terms in the LICENSE file found in the top-level directory of this
|
|
|
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
|
|
|
- * part of the UCB release of Plan 9, including this file, may be copied,
|
|
|
- * modified, propagated, or distributed except according to the terms contained
|
|
|
- * in the LICENSE file.
|
|
|
- */
|
|
|
-
|
|
|
-#include <u.h>
|
|
|
-#include <libc.h>
|
|
|
-#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%x", (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%lx bx 0x%lx cx 0x%lx\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%lx ax 0x%lx bx 0x%lx cx 0x%lx\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 int
|
|
|
-apmcall(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 int
|
|
|
-apmversion(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 int
|
|
|
-apmcpuidle(Apm *apm)
|
|
|
-{
|
|
|
- Ureg u;
|
|
|
-
|
|
|
- u.ax = CmdCpuIdle;
|
|
|
- return apmcall(apm->fd, &u);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-apmcpubusy(Apm *apm)
|
|
|
-{
|
|
|
- Ureg u;
|
|
|
-
|
|
|
- u.ax = CmdCpuBusy;
|
|
|
- return apmcall(apm->fd, &u);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-apmsetpowerstate(Apm *apm, int dev, int state)
|
|
|
-{
|
|
|
- Ureg u;
|
|
|
-
|
|
|
- u.ax = CmdSetPowerState;
|
|
|
- u.bx = dev;
|
|
|
- u.cx = state;
|
|
|
- return apmcall(apm->fd, &u);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-apmsetpowermgmt(Apm *apm, int dev, int state)
|
|
|
-{
|
|
|
- Ureg u;
|
|
|
-
|
|
|
- u.ax = CmdSetPowerMgmt;
|
|
|
- u.bx = dev;
|
|
|
- u.cx = state;
|
|
|
- return apmcall(apm->fd, &u);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-apmrestoredefaults(Apm *apm, int dev)
|
|
|
-{
|
|
|
- Ureg u;
|
|
|
-
|
|
|
- u.ax = CmdRestoreDefaults;
|
|
|
- u.bx = dev;
|
|
|
- return apmcall(apm->fd, &u);
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-apmgetpowerstatus(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 int
|
|
|
-apmgetevent(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 int
|
|
|
-apmgetpowerstate(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 int
|
|
|
-apmgetpowermgmt(Apm *apm, int dev)
|
|
|
-{
|
|
|
- Ureg u;
|
|
|
-
|
|
|
- u.ax = CmdGetPowerMgmt;
|
|
|
- u.bx = dev;
|
|
|
-
|
|
|
- if(apmcall(apm->fd, &u) < 0)
|
|
|
- return -1;
|
|
|
-
|
|
|
- return u.cx;
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-apmgetcapabilities(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 int
|
|
|
-apminstallationcheck(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;
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-apmsetdisplaystate(Apm *apm, int s)
|
|
|
-{
|
|
|
- apmsetpowerstate(apm, DevDisplay, s);
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-apmblank(Apm *apm)
|
|
|
-{
|
|
|
- apmsetdisplaystate(apm, PowerStandby);
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-apmunblank(Apm *apm)
|
|
|
-{
|
|
|
- apmsetdisplaystate(apm, PowerEnabled);
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-apmsuspend(Apm *apm)
|
|
|
-{
|
|
|
- apmsetpowerstate(apm, DevAll, PowerSuspend);
|
|
|
-}
|
|
|
-
|
|
|
-Apm apm;
|
|
|
-
|
|
|
-void
|
|
|
-powerprint(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, uint32_t n)
|
|
|
-{
|
|
|
- v = realloc(v, n);
|
|
|
- if(v == nil)
|
|
|
- sysfatal("out of memory reallocating %lu", n);
|
|
|
- setmalloctag(v, getcallerpc());
|
|
|
- return v;
|
|
|
-}
|
|
|
-
|
|
|
-void*
|
|
|
-emalloc(uint32_t n)
|
|
|
-{
|
|
|
- void *v;
|
|
|
-
|
|
|
- v = malloc(n);
|
|
|
- if(v == nil)
|
|
|
- sysfatal("out of memory allocating %lu", n);
|
|
|
- memset(v, 0, n);
|
|
|
- setmalloctag(v, getcallerpc());
|
|
|
- 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());
|
|
|
- return t;
|
|
|
-}
|
|
|
-
|
|
|
-char*
|
|
|
-estrdupn(char *s, int n)
|
|
|
-{
|
|
|
- int l;
|
|
|
- char *t;
|
|
|
-
|
|
|
- l = strlen(s);
|
|
|
- if(l > n)
|
|
|
- l = n;
|
|
|
- t = emalloc(l+1);
|
|
|
- memmove(t, s, l);
|
|
|
- t[l] = '\0';
|
|
|
- setmalloctag(t, getcallerpc());
|
|
|
- return t;
|
|
|
-}
|
|
|
-
|
|
|
-enum {
|
|
|
- Qroot = 0,
|
|
|
- Qevent,
|
|
|
- Qbattery,
|
|
|
- Qctl,
|
|
|
-};
|
|
|
-
|
|
|
-static void rootread(Req*);
|
|
|
-static void eventread(Req*);
|
|
|
-static void ctlread(Req*);
|
|
|
-static void ctlwrite(Req*);
|
|
|
-static void batteryread(Req*);
|
|
|
-
|
|
|
-typedef struct Dfile Dfile;
|
|
|
-struct Dfile {
|
|
|
- Qid qid;
|
|
|
- char *name;
|
|
|
- uint32_t mode;
|
|
|
- void (*read)(Req*);
|
|
|
- void (*write)(Req*);
|
|
|
-};
|
|
|
-
|
|
|
-Dfile dfile[] = {
|
|
|
- { {Qroot,0,QTDIR}, "/", DMDIR|0555, rootread, nil, },
|
|
|
- { {Qevent}, "event", 0444, eventread, nil, },
|
|
|
- { {Qbattery}, "battery", 0444, batteryread, nil, },
|
|
|
- { {Qctl}, "ctl", 0666, ctlread, ctlwrite, },
|
|
|
-};
|
|
|
-
|
|
|
-static int
|
|
|
-fillstat(uint64_t path, Dir *d, int doalloc)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- for(i=0; i<nelem(dfile); i++)
|
|
|
- if(path==dfile[i].qid.path)
|
|
|
- break;
|
|
|
- if(i==nelem(dfile))
|
|
|
- return -1;
|
|
|
-
|
|
|
- memset(d, 0, sizeof *d);
|
|
|
- d->uid = doalloc ? estrdup("apm") : "apm";
|
|
|
- d->gid = doalloc ? estrdup("apm") : "apm";
|
|
|
- d->length = 0;
|
|
|
- d->name = doalloc ? estrdup(dfile[i].name) : dfile[i].name;
|
|
|
- d->mode = dfile[i].mode;
|
|
|
- d->atime = d->mtime = time(0);
|
|
|
- d->qid = dfile[i].qid;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static char*
|
|
|
-fswalk1(Fid *fid, char *name, Qid *qid)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- if(strcmp(name, "..")==0){
|
|
|
- *qid = dfile[0].qid;
|
|
|
- fid->qid = *qid;
|
|
|
- return nil;
|
|
|
- }
|
|
|
-
|
|
|
- for(i=1; i<nelem(dfile); i++){ /* i=1: 0 is root dir */
|
|
|
- if(strcmp(dfile[i].name, name)==0){
|
|
|
- *qid = dfile[i].qid;
|
|
|
- fid->qid = *qid;
|
|
|
- return nil;
|
|
|
- }
|
|
|
- }
|
|
|
- return "file does not exist";
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-fsopen(Req *r)
|
|
|
-{
|
|
|
- switch((uint32_t)r->fid->qid.path){
|
|
|
- case Qroot:
|
|
|
- r->fid->aux = (void*)0;
|
|
|
- respond(r, nil);
|
|
|
- return;
|
|
|
-
|
|
|
- case Qevent:
|
|
|
- case Qbattery:
|
|
|
- if(r->ifcall.mode == OREAD){
|
|
|
- respond(r, nil);
|
|
|
- return;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case Qctl:
|
|
|
- if((r->ifcall.mode&~(OTRUNC|OREAD|OWRITE|ORDWR)) == 0){
|
|
|
- respond(r, nil);
|
|
|
- return;
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- respond(r, "permission denied");
|
|
|
- return;
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-fsstat(Req *r)
|
|
|
-{
|
|
|
- fillstat(r->fid->qid.path, &r->d, 1);
|
|
|
- respond(r, nil);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-fsread(Req *r)
|
|
|
-{
|
|
|
- dfile[r->fid->qid.path].read(r);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-fswrite(Req *r)
|
|
|
-{
|
|
|
- dfile[r->fid->qid.path].write(r);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-rootread(Req *r)
|
|
|
-{
|
|
|
- int n;
|
|
|
- uint64_t offset;
|
|
|
- char *p, *ep;
|
|
|
- Dir d;
|
|
|
-
|
|
|
- if(r->ifcall.offset == 0)
|
|
|
- offset = 0;
|
|
|
- else
|
|
|
- offset = (uint64_t)r->fid->aux;
|
|
|
-
|
|
|
- p = r->ofcall.data;
|
|
|
- ep = r->ofcall.data+r->ifcall.count;
|
|
|
-
|
|
|
- if(offset == 0) /* skip root */
|
|
|
- offset = 1;
|
|
|
- for(; p+2 < ep; p+=n){
|
|
|
- if(fillstat(offset, &d, 0) < 0)
|
|
|
- break;
|
|
|
- n = convD2M(&d, (uint8_t*)p, ep-p);
|
|
|
- if(n <= BIT16SZ)
|
|
|
- break;
|
|
|
- offset++;
|
|
|
- }
|
|
|
- r->fid->aux = (void*)offset;
|
|
|
- r->ofcall.count = p - r->ofcall.data;
|
|
|
- respond(r, nil);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-batteryread(Req *r)
|
|
|
-{
|
|
|
- char buf[Mbattery*80], *ep, *p;
|
|
|
- int i;
|
|
|
-
|
|
|
- apmgetpowerstatus(&apm, DevAll);
|
|
|
-
|
|
|
- p = buf;
|
|
|
- ep = buf+sizeof buf;
|
|
|
- *p = '\0'; /* could be no batteries */
|
|
|
- for(i=0; i<apm.nbattery && i<Mbattery; i++)
|
|
|
- p += snprint(p, ep-p, "%s %d %d\n",
|
|
|
- batterystatus(apm.battery[i].status),
|
|
|
- apm.battery[i].percent, apm.battery[i].time);
|
|
|
-
|
|
|
- readstr(r, buf);
|
|
|
- respond(r, nil);
|
|
|
-}
|
|
|
-
|
|
|
-int
|
|
|
-iscmd(char *p, char *cmd)
|
|
|
-{
|
|
|
- int l;
|
|
|
-
|
|
|
- l = strlen(cmd);
|
|
|
- return strncmp(p, cmd, l)==0 && p[l]=='\0' || p[l]==' ' || p[l]=='\t';
|
|
|
-}
|
|
|
-
|
|
|
-char*
|
|
|
-skip(char *p, char *cmd)
|
|
|
-{
|
|
|
- p += strlen(cmd);
|
|
|
- while(*p==' ' || *p=='\t')
|
|
|
- p++;
|
|
|
- return p;
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-respondx(Req *r, int c)
|
|
|
-{
|
|
|
- char err[ERRMAX];
|
|
|
-
|
|
|
- if(c == 0)
|
|
|
- respond(r, nil);
|
|
|
- else{
|
|
|
- rerrstr(err, sizeof err);
|
|
|
- respond(r, err);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * we don't do suspend because it messes up the
|
|
|
- * cycle counter as well as the pcmcia ethernet cards.
|
|
|
- */
|
|
|
-static void
|
|
|
-ctlwrite(Req *r)
|
|
|
-{
|
|
|
- char buf[80], *p, *q;
|
|
|
- int dev;
|
|
|
- int32_t count;
|
|
|
-
|
|
|
- count = r->ifcall.count;
|
|
|
- if(count > sizeof(buf)-1)
|
|
|
- count = sizeof(buf)-1;
|
|
|
- memmove(buf, r->ifcall.data, count);
|
|
|
- buf[count] = '\0';
|
|
|
-
|
|
|
- if(count && buf[count-1] == '\n'){
|
|
|
- --count;
|
|
|
- buf[count] = '\0';
|
|
|
- }
|
|
|
-
|
|
|
- q = buf;
|
|
|
- p = strchr(q, ' ');
|
|
|
- if(p==nil)
|
|
|
- p = q+strlen(q);
|
|
|
- else
|
|
|
- *p++ = '\0';
|
|
|
-
|
|
|
- if(strcmp(q, "")==0 || strcmp(q, "system")==0)
|
|
|
- dev = DevAll;
|
|
|
- else if(strcmp(q, "display")==0)
|
|
|
- dev = DevDisplay;
|
|
|
- else if(strcmp(q, "storage")==0)
|
|
|
- dev = DevStorage;
|
|
|
- else if(strcmp(q, "lpt")==0)
|
|
|
- dev = DevLpt;
|
|
|
- else if(strcmp(q, "eia")==0)
|
|
|
- dev = DevEia;
|
|
|
- else if(strcmp(q, "network")==0)
|
|
|
- dev = DevNetwork;
|
|
|
- else if(strcmp(q, "pcmcia")==0)
|
|
|
- dev = DevPCMCIA;
|
|
|
- else{
|
|
|
- respond(r, "unknown device");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if(strcmp(p, "enable")==0)
|
|
|
- respondx(r, apmsetpowermgmt(&apm, dev, EnablePowerMgmt));
|
|
|
- else if(strcmp(p, "disable")==0)
|
|
|
- respondx(r, apmsetpowermgmt(&apm, dev, DisablePowerMgmt));
|
|
|
- else if(strcmp(p, "standby")==0)
|
|
|
- respondx(r, apmsetpowerstate(&apm, dev, PowerStandby));
|
|
|
- else if(strcmp(p, "on")==0)
|
|
|
- respondx(r, apmsetpowerstate(&apm, dev, PowerEnabled));
|
|
|
-/*
|
|
|
- else if(strcmp(p, "off")==0)
|
|
|
- respondx(r, apmsetpowerstate(&apm, dev, PowerOff));
|
|
|
-*/
|
|
|
- else if(strcmp(p, "suspend")==0)
|
|
|
- respondx(r, apmsetpowerstate(&apm, dev, PowerSuspend));
|
|
|
- else
|
|
|
- respond(r, "unknown verb");
|
|
|
-}
|
|
|
-
|
|
|
-static int
|
|
|
-statusline(char *buf, int nbuf, char *name, int dev)
|
|
|
-{
|
|
|
- int s;
|
|
|
- char *state;
|
|
|
-
|
|
|
- state = "unknown";
|
|
|
- if((s = apmgetpowerstate(&apm, dev)) >= 0)
|
|
|
- state = powerstate(s);
|
|
|
- return snprint(buf, nbuf, "%s %s\n", name, state);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-ctlread(Req *r)
|
|
|
-{
|
|
|
- char buf[256+7*50], *ep, *p;
|
|
|
-
|
|
|
- p = buf;
|
|
|
- ep = buf+sizeof buf;
|
|
|
-
|
|
|
- p += snprint(p, ep-p, "ac %s\n", acstatus(apm.acstatus));
|
|
|
- p += snprint(p, ep-p, "capabilities");
|
|
|
- if(apm.capabilities & CapStandby)
|
|
|
- p += snprint(p, ep-p, " standby");
|
|
|
- if(apm.capabilities & CapSuspend)
|
|
|
- p += snprint(p, ep-p, " suspend");
|
|
|
- if(apm.capabilities & CapSlowCpu)
|
|
|
- p += snprint(p, ep-p, " slowcpu");
|
|
|
- p += snprint(p, ep-p, "\n");
|
|
|
-
|
|
|
- p += statusline(p, ep-p, "system", DevAll);
|
|
|
- p += statusline(p, ep-p, "display", DevDisplay);
|
|
|
- p += statusline(p, ep-p, "storage", DevStorage);
|
|
|
- p += statusline(p, ep-p, "lpt", DevLpt);
|
|
|
- p += statusline(p, ep-p, "eia", DevEia|All);
|
|
|
- p += statusline(p, ep-p, "network", DevNetwork|All);
|
|
|
- p += statusline(p, ep-p, "pcmcia", DevPCMCIA|All);
|
|
|
- USED(p);
|
|
|
-
|
|
|
- readstr(r, buf);
|
|
|
- respond(r, nil);
|
|
|
-}
|
|
|
-
|
|
|
-enum {
|
|
|
- STACK = 16384,
|
|
|
-};
|
|
|
-
|
|
|
-Channel *creq;
|
|
|
-Channel *cflush;
|
|
|
-Channel *cevent;
|
|
|
-Req *rlist, **tailp;
|
|
|
-int rp, wp;
|
|
|
-int nopoll;
|
|
|
-char eventq[32][80];
|
|
|
-
|
|
|
-static void
|
|
|
-flushthread(void *v)
|
|
|
-{
|
|
|
- Req *r, *or, **rq;
|
|
|
-
|
|
|
- threadsetname("flushthread");
|
|
|
- while(r = recvp(cflush)){
|
|
|
- or = r->oldreq;
|
|
|
- for(rq=&rlist; *rq; rq=&(*rq)->aux){
|
|
|
- if(*rq == or){
|
|
|
- *rq = or->aux;
|
|
|
- if(tailp==&or->aux)
|
|
|
- tailp = rq;
|
|
|
- respond(or, "interrupted");
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- respond(r, nil);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-answerany(void)
|
|
|
-{
|
|
|
- char *buf;
|
|
|
- int l, m;
|
|
|
- Req *r;
|
|
|
-
|
|
|
- if(rlist==nil || rp==wp)
|
|
|
- return;
|
|
|
-
|
|
|
- while(rlist && rp != wp){
|
|
|
- r = rlist;
|
|
|
- rlist = r->aux;
|
|
|
- if(rlist==nil)
|
|
|
- tailp = &rlist;
|
|
|
-
|
|
|
- l = 0;
|
|
|
- buf = r->ofcall.data;
|
|
|
- m = r->ifcall.count;
|
|
|
- while(rp != wp){
|
|
|
- if(l+strlen(eventq[rp]) <= m){
|
|
|
- strcpy(buf+l, eventq[rp]);
|
|
|
- l += strlen(buf+l);
|
|
|
- }else if(l==0){
|
|
|
- strncpy(buf, eventq[rp], m-1);
|
|
|
- buf[m-1] = '\0';
|
|
|
- l += m;
|
|
|
- }else
|
|
|
- break;
|
|
|
- rp++;
|
|
|
- if(rp == nelem(eventq))
|
|
|
- rp = 0;
|
|
|
- }
|
|
|
- r->ofcall.count = l;
|
|
|
- respond(r, nil);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-eventwatch(void *v)
|
|
|
-{
|
|
|
- int e, s;
|
|
|
-
|
|
|
- threadsetname("eventwatch");
|
|
|
- for(;;){
|
|
|
- s = 0;
|
|
|
- while((e = apmgetevent(&apm)) >= 0){
|
|
|
- sendul(cevent, e);
|
|
|
- s = 1;
|
|
|
- }
|
|
|
- if(s)
|
|
|
- sendul(cevent, -1);
|
|
|
- if (sleep(750) < 0)
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-eventthread(void *v)
|
|
|
-{
|
|
|
- int e;
|
|
|
-
|
|
|
- threadsetname("eventthread");
|
|
|
- for(;;){
|
|
|
- while((e = recvul(cevent)) >= 0){
|
|
|
- snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e));
|
|
|
- strcat(eventq[wp], "\n");
|
|
|
- wp++;
|
|
|
- if(wp==nelem(eventq))
|
|
|
- wp = 0;
|
|
|
- if(wp+1==rp || (wp+1==nelem(eventq) && rp==0))
|
|
|
- break;
|
|
|
- }
|
|
|
- answerany();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-eventproc(void *v)
|
|
|
-{
|
|
|
- Req *r;
|
|
|
-
|
|
|
- threadsetname("eventproc");
|
|
|
-
|
|
|
- creq = chancreate(sizeof(Req*), 0);
|
|
|
- cevent = chancreate(sizeof(uint32_t), 0);
|
|
|
- cflush = chancreate(sizeof(Req*), 0);
|
|
|
-
|
|
|
- tailp = &rlist;
|
|
|
- if(!nopoll)
|
|
|
- proccreate(eventwatch, nil, STACK);
|
|
|
- threadcreate(eventthread, nil, STACK);
|
|
|
- threadcreate(flushthread, nil, STACK);
|
|
|
-
|
|
|
- while(r = recvp(creq)){
|
|
|
- *tailp = r;
|
|
|
- r->aux = nil;
|
|
|
- tailp = &r->aux;
|
|
|
- answerany();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-fsflush(Req *r)
|
|
|
-{
|
|
|
- sendp(cflush, r);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-eventread(Req *r)
|
|
|
-{
|
|
|
- sendp(creq, r);
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-fsattach(Req *r)
|
|
|
-{
|
|
|
- char *spec;
|
|
|
- static int first = 1;
|
|
|
-
|
|
|
- spec = r->ifcall.aname;
|
|
|
-
|
|
|
- if(first){
|
|
|
- first = 0;
|
|
|
- proccreate(eventproc, nil, STACK);
|
|
|
- }
|
|
|
-
|
|
|
- if(spec && spec[0]){
|
|
|
- respond(r, "invalid attach specifier");
|
|
|
- return;
|
|
|
- }
|
|
|
- r->fid->qid = dfile[0].qid;
|
|
|
- r->ofcall.qid = dfile[0].qid;
|
|
|
- respond(r, nil);
|
|
|
-}
|
|
|
-
|
|
|
-Srv fs = {
|
|
|
-.attach= fsattach,
|
|
|
-.walk1= fswalk1,
|
|
|
-.open= fsopen,
|
|
|
-.read= fsread,
|
|
|
-.write= fswrite,
|
|
|
-.stat= fsstat,
|
|
|
-.flush= fsflush,
|
|
|
-};
|
|
|
-
|
|
|
-void
|
|
|
-usage(void)
|
|
|
-{
|
|
|
- fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n");
|
|
|
- exits("usage");
|
|
|
-}
|
|
|
-
|
|
|
-void
|
|
|
-threadmain(int argc, char **argv)
|
|
|
-{
|
|
|
- char *dev, *mtpt, *srv;
|
|
|
-
|
|
|
- dev = nil;
|
|
|
- mtpt = "/mnt/apm";
|
|
|
- srv = nil;
|
|
|
- ARGBEGIN{
|
|
|
- case 'A':
|
|
|
- apmdebug = 1;
|
|
|
- break;
|
|
|
- case 'D':
|
|
|
- chatty9p = 1;
|
|
|
- break;
|
|
|
- case 'P':
|
|
|
- nopoll = 1;
|
|
|
- break;
|
|
|
- case 'd':
|
|
|
- dev = EARGF(usage());
|
|
|
- break;
|
|
|
- case 'i':
|
|
|
- fs.nopipe++;
|
|
|
- fs.infd = 0;
|
|
|
- fs.outfd = 1;
|
|
|
- mtpt = nil;
|
|
|
- break;
|
|
|
- case 'm':
|
|
|
- mtpt = EARGF(usage());
|
|
|
- break;
|
|
|
- case 's':
|
|
|
- srv = EARGF(usage());
|
|
|
- break;
|
|
|
- }ARGEND
|
|
|
-
|
|
|
- if(dev == nil){
|
|
|
- if((apm.fd = open("/dev/apm", ORDWR)) < 0
|
|
|
- && (apm.fd = open("#P/apm", ORDWR)) < 0){
|
|
|
- fprint(2, "open %s: %r\n", dev);
|
|
|
- threadexitsall("open");
|
|
|
- }
|
|
|
- } else if((apm.fd = open(dev, ORDWR)) < 0){
|
|
|
- fprint(2, "open %s: %r\n", dev);
|
|
|
- threadexitsall("open");
|
|
|
- }
|
|
|
-
|
|
|
- if(apmversion(&apm) < 0){
|
|
|
- fprint(2, "cannot get apm version: %r\n");
|
|
|
- threadexitsall("apmversion");
|
|
|
- }
|
|
|
-
|
|
|
- if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){
|
|
|
- fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo);
|
|
|
- threadexitsall("apmversion");
|
|
|
- }
|
|
|
-
|
|
|
- if(apmgetcapabilities(&apm) < 0)
|
|
|
- fprint(2, "warning: cannot read apm capabilities: %r\n");
|
|
|
-
|
|
|
- apminstallationcheck(&apm);
|
|
|
- apmcpuidle(&apm);
|
|
|
-
|
|
|
- rfork(RFNOTEG);
|
|
|
- threadpostmountsrv(&fs, srv, mtpt, MREPL);
|
|
|
-}
|