xref: /plan9/sys/src/cmd/aux/apm.c (revision 5e91980f0bca263e952809e3dc0cfc5dde74b999)
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*
apmevent(int e)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*
apmerror(int id)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
_apmcall(int fd,Ureg * u)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
apmcall(int fd,Ureg * u)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*
xstatus(char ** str,int nstr,int x)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*
batterystatus(int b)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*
powerstate(int s)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*
acstatus(int a)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
apmversion(Apm * apm)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
apmcpuidle(Apm * apm)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
apmcpubusy(Apm * apm)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
apmsetpowerstate(Apm * apm,int dev,int state)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
apmsetpowermgmt(Apm * apm,int dev,int state)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
apmrestoredefaults(Apm * apm,int dev)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
apmgetpowerstatus(Apm * apm,int dev)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
apmgetevent(Apm * apm)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
apmgetpowerstate(Apm * apm,int dev)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
apmgetpowermgmt(Apm * apm,int dev)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
apmgetcapabilities(Apm * apm)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
apminstallationcheck(Apm * apm)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
apmsetdisplaystate(Apm * apm,int s)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
apmblank(Apm * apm)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
apmunblank(Apm * apm)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
apmsuspend(Apm * apm)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
powerprint(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*
erealloc(void * v,ulong n)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*
emalloc(ulong n)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*
estrdup(char * s)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*
estrdupn(char * s,int n)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
fillstat(uvlong path,Dir * d,int doalloc)624*5e91980fSDavid du Colombier fillstat(uvlong 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*
fswalk1(Fid * fid,char * name,Qid * qid)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
fsopen(Req * r)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
fsstat(Req * r)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
fsread(Req * r)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
fswrite(Req * r)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
rootread(Req * r)7149a747e4fSDavid du Colombier rootread(Req *r)
71580ee5cbfSDavid du Colombier {
716*5e91980fSDavid du Colombier 	int n;
717*5e91980fSDavid du Colombier 	uvlong offset;
7189a747e4fSDavid du Colombier 	char *p, *ep;
71980ee5cbfSDavid du Colombier 	Dir d;
72080ee5cbfSDavid du Colombier 
7219a747e4fSDavid du Colombier 	if(r->ifcall.offset == 0)
7229a747e4fSDavid du Colombier 		offset = 0;
7239a747e4fSDavid du Colombier 	else
724*5e91980fSDavid du Colombier 		offset = (uvlong)r->fid->aux;
7259a747e4fSDavid du Colombier 
7269a747e4fSDavid du Colombier 	p = r->ofcall.data;
7279a747e4fSDavid du Colombier 	ep = r->ofcall.data+r->ifcall.count;
7289a747e4fSDavid du Colombier 
7299a747e4fSDavid du Colombier 	if(offset == 0)		/* skip root */
7309a747e4fSDavid du Colombier 		offset = 1;
7319a747e4fSDavid du Colombier 	for(; p+2 < ep; p+=n){
7329a747e4fSDavid du Colombier 		if(fillstat(offset, &d, 0) < 0)
73380ee5cbfSDavid du Colombier 			break;
7349a747e4fSDavid du Colombier 		n = convD2M(&d, (uchar*)p, ep-p);
7359a747e4fSDavid du Colombier 		if(n <= BIT16SZ)
7369a747e4fSDavid du Colombier 			break;
7379a747e4fSDavid du Colombier 		offset++;
73880ee5cbfSDavid du Colombier 	}
7399a747e4fSDavid du Colombier 	r->fid->aux = (void*)offset;
7409a747e4fSDavid du Colombier 	r->ofcall.count = p - r->ofcall.data;
74180ee5cbfSDavid du Colombier 	respond(r, nil);
74280ee5cbfSDavid du Colombier }
74380ee5cbfSDavid du Colombier 
74480ee5cbfSDavid du Colombier static void
batteryread(Req * r)7459a747e4fSDavid du Colombier batteryread(Req *r)
74680ee5cbfSDavid du Colombier {
74780ee5cbfSDavid du Colombier 	char buf[Mbattery*80], *ep, *p;
74880ee5cbfSDavid du Colombier 	int i;
74980ee5cbfSDavid du Colombier 
75080ee5cbfSDavid du Colombier 	apmgetpowerstatus(&apm, DevAll);
75180ee5cbfSDavid du Colombier 
75280ee5cbfSDavid du Colombier 	p = buf;
75380ee5cbfSDavid du Colombier 	ep = buf+sizeof buf;
7549a747e4fSDavid du Colombier 	*p = '\0';	/* could be no batteries */
75580ee5cbfSDavid du Colombier 	for(i=0; i<apm.nbattery && i<Mbattery; i++)
75680ee5cbfSDavid du Colombier 		p += snprint(p, ep-p, "%s %d %d\n",
75780ee5cbfSDavid du Colombier 			batterystatus(apm.battery[i].status),
75880ee5cbfSDavid du Colombier 			apm.battery[i].percent, apm.battery[i].time);
75980ee5cbfSDavid du Colombier 
7609a747e4fSDavid du Colombier 	readstr(r, buf);
76180ee5cbfSDavid du Colombier 	respond(r, nil);
76280ee5cbfSDavid du Colombier }
76380ee5cbfSDavid du Colombier 
76480ee5cbfSDavid du Colombier int
iscmd(char * p,char * cmd)76580ee5cbfSDavid du Colombier iscmd(char *p, char *cmd)
76680ee5cbfSDavid du Colombier {
76780ee5cbfSDavid du Colombier 	int l;
76880ee5cbfSDavid du Colombier 
76980ee5cbfSDavid du Colombier 	l = strlen(cmd);
77080ee5cbfSDavid du Colombier 	return strncmp(p, cmd, l)==0 && p[l]=='\0' || p[l]==' ' || p[l]=='\t';
77180ee5cbfSDavid du Colombier }
77280ee5cbfSDavid du Colombier 
77380ee5cbfSDavid du Colombier char*
skip(char * p,char * cmd)77480ee5cbfSDavid du Colombier skip(char *p, char *cmd)
77580ee5cbfSDavid du Colombier {
77680ee5cbfSDavid du Colombier 	p += strlen(cmd);
77780ee5cbfSDavid du Colombier 	while(*p==' ' || *p=='\t')
77880ee5cbfSDavid du Colombier 		p++;
77980ee5cbfSDavid du Colombier 	return p;
78080ee5cbfSDavid du Colombier }
78180ee5cbfSDavid du Colombier 
78280ee5cbfSDavid du Colombier static void
respondx(Req * r,int c)78380ee5cbfSDavid du Colombier respondx(Req *r, int c)
78480ee5cbfSDavid du Colombier {
7859a747e4fSDavid du Colombier 	char err[ERRMAX];
78680ee5cbfSDavid du Colombier 
78780ee5cbfSDavid du Colombier 	if(c == 0)
78880ee5cbfSDavid du Colombier 		respond(r, nil);
78980ee5cbfSDavid du Colombier 	else{
7909a747e4fSDavid du Colombier 		rerrstr(err, sizeof err);
79180ee5cbfSDavid du Colombier 		respond(r, err);
79280ee5cbfSDavid du Colombier 	}
79380ee5cbfSDavid du Colombier }
79480ee5cbfSDavid du Colombier 
79580ee5cbfSDavid du Colombier /*
79680ee5cbfSDavid du Colombier  * we don't do suspend because it messes up the
79780ee5cbfSDavid du Colombier  * cycle counter as well as the pcmcia ethernet cards.
79880ee5cbfSDavid du Colombier  */
79980ee5cbfSDavid du Colombier static void
ctlwrite(Req * r)8009a747e4fSDavid du Colombier ctlwrite(Req *r)
80180ee5cbfSDavid du Colombier {
80280ee5cbfSDavid du Colombier 	char buf[80], *p, *q;
80380ee5cbfSDavid du Colombier 	int dev;
8049a747e4fSDavid du Colombier 	long count;
80580ee5cbfSDavid du Colombier 
8069a747e4fSDavid du Colombier 	count = r->ifcall.count;
8079a747e4fSDavid du Colombier 	if(count > sizeof(buf)-1)
8089a747e4fSDavid du Colombier 		count = sizeof(buf)-1;
8099a747e4fSDavid du Colombier 	memmove(buf, r->ifcall.data, count);
8109a747e4fSDavid du Colombier 	buf[count] = '\0';
81180ee5cbfSDavid du Colombier 
8129a747e4fSDavid du Colombier 	if(count && buf[count-1] == '\n'){
8139a747e4fSDavid du Colombier 		--count;
8149a747e4fSDavid du Colombier 		buf[count] = '\0';
8159a747e4fSDavid du Colombier 	}
81680ee5cbfSDavid du Colombier 
81780ee5cbfSDavid du Colombier 	q = buf;
81880ee5cbfSDavid du Colombier 	p = strchr(q, ' ');
81980ee5cbfSDavid du Colombier 	if(p==nil)
82080ee5cbfSDavid du Colombier 		p = q+strlen(q);
82180ee5cbfSDavid du Colombier 	else
82280ee5cbfSDavid du Colombier 		*p++ = '\0';
82380ee5cbfSDavid du Colombier 
82480ee5cbfSDavid du Colombier 	if(strcmp(q, "")==0 || strcmp(q, "system")==0)
82580ee5cbfSDavid du Colombier 		dev = DevAll;
82680ee5cbfSDavid du Colombier 	else if(strcmp(q, "display")==0)
82780ee5cbfSDavid du Colombier 		dev = DevDisplay;
82880ee5cbfSDavid du Colombier 	else if(strcmp(q, "storage")==0)
82980ee5cbfSDavid du Colombier 		dev = DevStorage;
83080ee5cbfSDavid du Colombier 	else if(strcmp(q, "lpt")==0)
83180ee5cbfSDavid du Colombier 		dev = DevLpt;
83280ee5cbfSDavid du Colombier 	else if(strcmp(q, "eia")==0)
83380ee5cbfSDavid du Colombier 		dev = DevEia;
83480ee5cbfSDavid du Colombier 	else if(strcmp(q, "network")==0)
83580ee5cbfSDavid du Colombier 		dev = DevNetwork;
83680ee5cbfSDavid du Colombier 	else if(strcmp(q, "pcmcia")==0)
83780ee5cbfSDavid du Colombier 		dev = DevPCMCIA;
83880ee5cbfSDavid du Colombier 	else{
83980ee5cbfSDavid du Colombier 		respond(r, "unknown device");
84080ee5cbfSDavid du Colombier 		return;
84180ee5cbfSDavid du Colombier 	}
84280ee5cbfSDavid du Colombier 
84380ee5cbfSDavid du Colombier 	if(strcmp(p, "enable")==0)
84480ee5cbfSDavid du Colombier 		respondx(r, apmsetpowermgmt(&apm, dev, EnablePowerMgmt));
84580ee5cbfSDavid du Colombier 	else if(strcmp(p, "disable")==0)
84680ee5cbfSDavid du Colombier 		respondx(r, apmsetpowermgmt(&apm, dev, DisablePowerMgmt));
84780ee5cbfSDavid du Colombier 	else if(strcmp(p, "standby")==0)
84880ee5cbfSDavid du Colombier 		respondx(r, apmsetpowerstate(&apm, dev, PowerStandby));
84980ee5cbfSDavid du Colombier 	else if(strcmp(p, "on")==0)
85080ee5cbfSDavid du Colombier 		respondx(r, apmsetpowerstate(&apm, dev, PowerEnabled));
85180ee5cbfSDavid du Colombier /*
85280ee5cbfSDavid du Colombier 	else if(strcmp(p, "off")==0)
85380ee5cbfSDavid du Colombier 		respondx(r, apmsetpowerstate(&apm, dev, PowerOff));
8549a747e4fSDavid du Colombier */
85580ee5cbfSDavid du Colombier 	else if(strcmp(p, "suspend")==0)
85680ee5cbfSDavid du Colombier 		respondx(r, apmsetpowerstate(&apm, dev, PowerSuspend));
85780ee5cbfSDavid du Colombier 	else
85880ee5cbfSDavid du Colombier 		respond(r, "unknown verb");
85980ee5cbfSDavid du Colombier }
86080ee5cbfSDavid du Colombier 
86180ee5cbfSDavid du Colombier static int
statusline(char * buf,int nbuf,char * name,int dev)86280ee5cbfSDavid du Colombier statusline(char *buf, int nbuf, char *name, int dev)
86380ee5cbfSDavid du Colombier {
86480ee5cbfSDavid du Colombier 	int s;
86580ee5cbfSDavid du Colombier 	char *state;
86680ee5cbfSDavid du Colombier 
86780ee5cbfSDavid du Colombier 	state = "unknown";
86880ee5cbfSDavid du Colombier 	if((s = apmgetpowerstate(&apm, dev)) >= 0)
86980ee5cbfSDavid du Colombier 		state = powerstate(s);
87080ee5cbfSDavid du Colombier 	return snprint(buf, nbuf, "%s %s\n", name, state);
87180ee5cbfSDavid du Colombier }
87280ee5cbfSDavid du Colombier 
87380ee5cbfSDavid du Colombier static void
ctlread(Req * r)8749a747e4fSDavid du Colombier ctlread(Req *r)
87580ee5cbfSDavid du Colombier {
87680ee5cbfSDavid du Colombier 	char buf[256+7*50], *ep, *p;
87780ee5cbfSDavid du Colombier 
87880ee5cbfSDavid du Colombier 	p = buf;
87980ee5cbfSDavid du Colombier 	ep = buf+sizeof buf;
88080ee5cbfSDavid du Colombier 
88180ee5cbfSDavid du Colombier 	p += snprint(p, ep-p, "ac %s\n", acstatus(apm.acstatus));
88280ee5cbfSDavid du Colombier 	p += snprint(p, ep-p, "capabilities");
88380ee5cbfSDavid du Colombier 	if(apm.capabilities & CapStandby)
88480ee5cbfSDavid du Colombier 		p += snprint(p, ep-p, " standby");
88580ee5cbfSDavid du Colombier 	if(apm.capabilities & CapSuspend)
88680ee5cbfSDavid du Colombier 		p += snprint(p, ep-p, " suspend");
88780ee5cbfSDavid du Colombier 	if(apm.capabilities & CapSlowCpu)
88880ee5cbfSDavid du Colombier 		p += snprint(p, ep-p, " slowcpu");
88980ee5cbfSDavid du Colombier 	p += snprint(p, ep-p, "\n");
89080ee5cbfSDavid du Colombier 
89180ee5cbfSDavid du Colombier 	p += statusline(p, ep-p, "system", DevAll);
89280ee5cbfSDavid du Colombier 	p += statusline(p, ep-p, "display", DevDisplay);
89380ee5cbfSDavid du Colombier 	p += statusline(p, ep-p, "storage", DevStorage);
89480ee5cbfSDavid du Colombier 	p += statusline(p, ep-p, "lpt", DevLpt);
89580ee5cbfSDavid du Colombier 	p += statusline(p, ep-p, "eia", DevEia|All);
89680ee5cbfSDavid du Colombier 	p += statusline(p, ep-p, "network", DevNetwork|All);
89780ee5cbfSDavid du Colombier 	p += statusline(p, ep-p, "pcmcia", DevPCMCIA|All);
89880ee5cbfSDavid du Colombier 	USED(p);
89980ee5cbfSDavid du Colombier 
9009a747e4fSDavid du Colombier 	readstr(r, buf);
90180ee5cbfSDavid du Colombier 	respond(r, nil);
90280ee5cbfSDavid du Colombier }
90380ee5cbfSDavid du Colombier 
90480ee5cbfSDavid du Colombier enum {
90580ee5cbfSDavid du Colombier 	STACK = 16384,
90680ee5cbfSDavid du Colombier };
90780ee5cbfSDavid du Colombier 
90880ee5cbfSDavid du Colombier Channel *creq;
90980ee5cbfSDavid du Colombier Channel *cflush;
91080ee5cbfSDavid du Colombier Channel *cevent;
91180ee5cbfSDavid du Colombier Req *rlist, **tailp;
91280ee5cbfSDavid du Colombier int rp, wp;
91380ee5cbfSDavid du Colombier int nopoll;
91480ee5cbfSDavid du Colombier char eventq[32][80];
91580ee5cbfSDavid du Colombier 
91680ee5cbfSDavid du Colombier static void
flushthread(void *)91780ee5cbfSDavid du Colombier flushthread(void*)
91880ee5cbfSDavid du Colombier {
91980ee5cbfSDavid du Colombier 	Req *r, *or, **rq;
92080ee5cbfSDavid du Colombier 
92180ee5cbfSDavid du Colombier 	threadsetname("flushthread");
92280ee5cbfSDavid du Colombier 	while(r = recvp(cflush)){
92380ee5cbfSDavid du Colombier 		or = r->oldreq;
92480ee5cbfSDavid du Colombier 		for(rq=&rlist; *rq; rq=&(*rq)->aux){
92580ee5cbfSDavid du Colombier 			if(*rq == or){
92680ee5cbfSDavid du Colombier 				*rq = or->aux;
92780ee5cbfSDavid du Colombier 				if(tailp==&or->aux)
92880ee5cbfSDavid du Colombier 					tailp = rq;
929d3c05884SDavid du Colombier 				respond(or, "interrupted");
93080ee5cbfSDavid du Colombier 				break;
93180ee5cbfSDavid du Colombier 			}
93280ee5cbfSDavid du Colombier 		}
93380ee5cbfSDavid du Colombier 		respond(r, nil);
93480ee5cbfSDavid du Colombier 	}
93580ee5cbfSDavid du Colombier }
93680ee5cbfSDavid du Colombier 
93780ee5cbfSDavid du Colombier static void
answerany(void)93880ee5cbfSDavid du Colombier answerany(void)
93980ee5cbfSDavid du Colombier {
94080ee5cbfSDavid du Colombier 	char *buf;
94180ee5cbfSDavid du Colombier 	int l, m;
94280ee5cbfSDavid du Colombier 	Req *r;
94380ee5cbfSDavid du Colombier 
94480ee5cbfSDavid du Colombier 	if(rlist==nil || rp==wp)
94580ee5cbfSDavid du Colombier 		return;
94680ee5cbfSDavid du Colombier 
94780ee5cbfSDavid du Colombier 	while(rlist && rp != wp){
94880ee5cbfSDavid du Colombier 		r = rlist;
94980ee5cbfSDavid du Colombier 		rlist = r->aux;
95080ee5cbfSDavid du Colombier 		if(rlist==nil)
95180ee5cbfSDavid du Colombier 			tailp = &rlist;
95280ee5cbfSDavid du Colombier 
95380ee5cbfSDavid du Colombier 		l = 0;
95480ee5cbfSDavid du Colombier 		buf = r->ofcall.data;
955da51d93aSDavid du Colombier 		m = r->ifcall.count;
95680ee5cbfSDavid du Colombier 		while(rp != wp){
95780ee5cbfSDavid du Colombier 			if(l+strlen(eventq[rp]) <= m){
95880ee5cbfSDavid du Colombier 				strcpy(buf+l, eventq[rp]);
95980ee5cbfSDavid du Colombier 				l += strlen(buf+l);
96080ee5cbfSDavid du Colombier 			}else if(l==0){
96180ee5cbfSDavid du Colombier 				strncpy(buf, eventq[rp], m-1);
96280ee5cbfSDavid du Colombier 				buf[m-1] = '\0';
96380ee5cbfSDavid du Colombier 				l += m;
96480ee5cbfSDavid du Colombier 			}else
96580ee5cbfSDavid du Colombier 				break;
96680ee5cbfSDavid du Colombier 			rp++;
96780ee5cbfSDavid du Colombier 			if(rp == nelem(eventq))
96880ee5cbfSDavid du Colombier 				rp = 0;
96980ee5cbfSDavid du Colombier 		}
97080ee5cbfSDavid du Colombier 		r->ofcall.count = l;
97180ee5cbfSDavid du Colombier 		respond(r, nil);
97280ee5cbfSDavid du Colombier 	}
97380ee5cbfSDavid du Colombier }
97480ee5cbfSDavid du Colombier 
97580ee5cbfSDavid du Colombier static void
eventwatch(void *)97680ee5cbfSDavid du Colombier eventwatch(void*)
97780ee5cbfSDavid du Colombier {
97880ee5cbfSDavid du Colombier 	int e, s;
97980ee5cbfSDavid du Colombier 
98080ee5cbfSDavid du Colombier 	threadsetname("eventwatch");
98180ee5cbfSDavid du Colombier 	for(;;){
98280ee5cbfSDavid du Colombier 		s = 0;
98380ee5cbfSDavid du Colombier 		while((e = apmgetevent(&apm)) >= 0){
98480ee5cbfSDavid du Colombier 			sendul(cevent, e);
98580ee5cbfSDavid du Colombier 			s = 1;
98680ee5cbfSDavid du Colombier 		}
98780ee5cbfSDavid du Colombier 		if(s)
98880ee5cbfSDavid du Colombier 			sendul(cevent, -1);
98980ee5cbfSDavid du Colombier 		if(sleep(750) < 0)
99080ee5cbfSDavid du Colombier 			break;
99180ee5cbfSDavid du Colombier 	}
99280ee5cbfSDavid du Colombier }
99380ee5cbfSDavid du Colombier 
99480ee5cbfSDavid du Colombier static void
eventthread(void *)99580ee5cbfSDavid du Colombier eventthread(void*)
99680ee5cbfSDavid du Colombier {
99780ee5cbfSDavid du Colombier 	int e;
99880ee5cbfSDavid du Colombier 
99980ee5cbfSDavid du Colombier 	threadsetname("eventthread");
100080ee5cbfSDavid du Colombier 	for(;;){
100180ee5cbfSDavid du Colombier 		while((e = recvul(cevent)) >= 0){
100280ee5cbfSDavid du Colombier 			snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e));
100380ee5cbfSDavid du Colombier 			strcat(eventq[wp], "\n");
100480ee5cbfSDavid du Colombier 			wp++;
100580ee5cbfSDavid du Colombier 			if(wp==nelem(eventq))
100680ee5cbfSDavid du Colombier 				wp = 0;
100780ee5cbfSDavid du Colombier 			if(wp+1==rp || (wp+1==nelem(eventq) && rp==0))
100880ee5cbfSDavid du Colombier 				break;
100980ee5cbfSDavid du Colombier 		}
101080ee5cbfSDavid du Colombier 		answerany();
101180ee5cbfSDavid du Colombier 	}
101280ee5cbfSDavid du Colombier }
101380ee5cbfSDavid du Colombier 
101480ee5cbfSDavid du Colombier static void
eventproc(void *)101580ee5cbfSDavid du Colombier eventproc(void*)
101680ee5cbfSDavid du Colombier {
101780ee5cbfSDavid du Colombier 	Req *r;
101880ee5cbfSDavid du Colombier 
101980ee5cbfSDavid du Colombier 	threadsetname("eventproc");
102080ee5cbfSDavid du Colombier 
102180ee5cbfSDavid du Colombier 	creq = chancreate(sizeof(Req*), 0);
102280ee5cbfSDavid du Colombier 	cevent = chancreate(sizeof(ulong), 0);
102380ee5cbfSDavid du Colombier 	cflush = chancreate(sizeof(Req*), 0);
102480ee5cbfSDavid du Colombier 
102580ee5cbfSDavid du Colombier 	tailp = &rlist;
102680ee5cbfSDavid du Colombier 	if(!nopoll)
102780ee5cbfSDavid du Colombier 		proccreate(eventwatch, nil, STACK);
102880ee5cbfSDavid du Colombier 	threadcreate(eventthread, nil, STACK);
102980ee5cbfSDavid du Colombier 	threadcreate(flushthread, nil, STACK);
103080ee5cbfSDavid du Colombier 
103180ee5cbfSDavid du Colombier 	while(r = recvp(creq)){
103280ee5cbfSDavid du Colombier 		*tailp = r;
103380ee5cbfSDavid du Colombier 		r->aux = nil;
103480ee5cbfSDavid du Colombier 		tailp = &r->aux;
103580ee5cbfSDavid du Colombier 		answerany();
103680ee5cbfSDavid du Colombier 	}
103780ee5cbfSDavid du Colombier }
103880ee5cbfSDavid du Colombier 
103980ee5cbfSDavid du Colombier static void
fsflush(Req * r)10409a747e4fSDavid du Colombier fsflush(Req *r)
104180ee5cbfSDavid du Colombier {
104280ee5cbfSDavid du Colombier 	sendp(cflush, r);
104380ee5cbfSDavid du Colombier }
104480ee5cbfSDavid du Colombier 
104580ee5cbfSDavid du Colombier static void
eventread(Req * r)10469a747e4fSDavid du Colombier eventread(Req *r)
104780ee5cbfSDavid du Colombier {
104880ee5cbfSDavid du Colombier 	sendp(creq, r);
104980ee5cbfSDavid du Colombier }
105080ee5cbfSDavid du Colombier 
105180ee5cbfSDavid du Colombier static void
fsattach(Req * r)10529a747e4fSDavid du Colombier fsattach(Req *r)
105380ee5cbfSDavid du Colombier {
10549a747e4fSDavid du Colombier 	char *spec;
105580ee5cbfSDavid du Colombier 	static int first = 1;
105680ee5cbfSDavid du Colombier 
10579a747e4fSDavid du Colombier 	spec = r->ifcall.aname;
10589a747e4fSDavid du Colombier 
105980ee5cbfSDavid du Colombier 	if(first){
106080ee5cbfSDavid du Colombier 		first = 0;
106180ee5cbfSDavid du Colombier 		proccreate(eventproc, nil, STACK);
106280ee5cbfSDavid du Colombier 	}
106380ee5cbfSDavid du Colombier 
106480ee5cbfSDavid du Colombier 	if(spec && spec[0]){
106580ee5cbfSDavid du Colombier 		respond(r, "invalid attach specifier");
106680ee5cbfSDavid du Colombier 		return;
106780ee5cbfSDavid du Colombier 	}
10689a747e4fSDavid du Colombier 	r->fid->qid = dfile[0].qid;
10699a747e4fSDavid du Colombier 	r->ofcall.qid = dfile[0].qid;
107080ee5cbfSDavid du Colombier 	respond(r, nil);
107180ee5cbfSDavid du Colombier }
107280ee5cbfSDavid du Colombier 
10739a747e4fSDavid du Colombier Srv fs = {
107480ee5cbfSDavid du Colombier .attach=	fsattach,
10759a747e4fSDavid du Colombier .walk1=	fswalk1,
107680ee5cbfSDavid du Colombier .open=	fsopen,
107780ee5cbfSDavid du Colombier .read=	fsread,
107880ee5cbfSDavid du Colombier .write=	fswrite,
107980ee5cbfSDavid du Colombier .stat=	fsstat,
108080ee5cbfSDavid du Colombier .flush=	fsflush,
108180ee5cbfSDavid du Colombier };
108280ee5cbfSDavid du Colombier 
108380ee5cbfSDavid du Colombier void
usage(void)10849a747e4fSDavid du Colombier usage(void)
10859a747e4fSDavid du Colombier {
10869a747e4fSDavid du Colombier 	fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n");
10879a747e4fSDavid du Colombier 	exits("usage");
10889a747e4fSDavid du Colombier }
10899a747e4fSDavid du Colombier 
10909a747e4fSDavid du Colombier void
threadmain(int argc,char ** argv)109180ee5cbfSDavid du Colombier threadmain(int argc, char **argv)
109280ee5cbfSDavid du Colombier {
109380ee5cbfSDavid du Colombier 	char *dev, *mtpt, *srv;
109480ee5cbfSDavid du Colombier 
10959a747e4fSDavid du Colombier 	dev = nil;
109680ee5cbfSDavid du Colombier 	mtpt = "/mnt/apm";
109780ee5cbfSDavid du Colombier 	srv = nil;
109880ee5cbfSDavid du Colombier 	ARGBEGIN{
109980ee5cbfSDavid du Colombier 	case 'A':
110080ee5cbfSDavid du Colombier 		apmdebug = 1;
110180ee5cbfSDavid du Colombier 		break;
110280ee5cbfSDavid du Colombier 	case 'D':
11039a747e4fSDavid du Colombier 		chatty9p = 1;
110480ee5cbfSDavid du Colombier 		break;
110580ee5cbfSDavid du Colombier 	case 'P':
110680ee5cbfSDavid du Colombier 		nopoll = 1;
110780ee5cbfSDavid du Colombier 		break;
110880ee5cbfSDavid du Colombier 	case 'd':
110980ee5cbfSDavid du Colombier 		dev = EARGF(usage());
111080ee5cbfSDavid du Colombier 		break;
11119a747e4fSDavid du Colombier 	case 'i':
11129a747e4fSDavid du Colombier 		fs.nopipe++;
11139a747e4fSDavid du Colombier 		fs.infd = 0;
11149a747e4fSDavid du Colombier 		fs.outfd = 1;
11159a747e4fSDavid du Colombier 		mtpt = nil;
11169a747e4fSDavid du Colombier 		break;
111780ee5cbfSDavid du Colombier 	case 'm':
111880ee5cbfSDavid du Colombier 		mtpt = EARGF(usage());
111980ee5cbfSDavid du Colombier 		break;
112080ee5cbfSDavid du Colombier 	case 's':
112180ee5cbfSDavid du Colombier 		srv = EARGF(usage());
112280ee5cbfSDavid du Colombier 		break;
112380ee5cbfSDavid du Colombier 	}ARGEND
112480ee5cbfSDavid du Colombier 
11259a747e4fSDavid du Colombier 	if(dev == nil){
11269a747e4fSDavid du Colombier 		if((apm.fd = open("/dev/apm", ORDWR)) < 0
11279a747e4fSDavid du Colombier 		&& (apm.fd = open("#P/apm", ORDWR)) < 0){
11289a747e4fSDavid du Colombier 			fprint(2, "open %s: %r\n", dev);
11299a747e4fSDavid du Colombier 			threadexitsall("open");
11309a747e4fSDavid du Colombier 		}
11319a747e4fSDavid du Colombier 	} else if((apm.fd = open(dev, ORDWR)) < 0){
11329a747e4fSDavid du Colombier 		fprint(2, "open %s: %r\n", dev);
113380ee5cbfSDavid du Colombier 		threadexitsall("open");
113480ee5cbfSDavid du Colombier 	}
113580ee5cbfSDavid du Colombier 
113680ee5cbfSDavid du Colombier 	if(apmversion(&apm) < 0){
11379a747e4fSDavid du Colombier 		fprint(2, "cannot get apm version: %r\n");
113880ee5cbfSDavid du Colombier 		threadexitsall("apmversion");
113980ee5cbfSDavid du Colombier 	}
114080ee5cbfSDavid du Colombier 
114180ee5cbfSDavid du Colombier 	if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){
11429a747e4fSDavid du Colombier 		fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo);
114380ee5cbfSDavid du Colombier 		threadexitsall("apmversion");
114480ee5cbfSDavid du Colombier 	}
114580ee5cbfSDavid du Colombier 
114680ee5cbfSDavid du Colombier 	if(apmgetcapabilities(&apm) < 0)
11479a747e4fSDavid du Colombier 		fprint(2, "warning: cannot read apm capabilities: %r\n");
114880ee5cbfSDavid du Colombier 
114980ee5cbfSDavid du Colombier 	apminstallationcheck(&apm);
115080ee5cbfSDavid du Colombier 	apmcpuidle(&apm);
115180ee5cbfSDavid du Colombier 
11529a747e4fSDavid du Colombier 	rfork(RFNOTEG);
11539a747e4fSDavid du Colombier 	threadpostmountsrv(&fs, srv, mtpt, MREPL);
115480ee5cbfSDavid du Colombier }
1155