Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include </386/include/ureg.h>
4
typedef struct Ureg Ureg;
5
#include <auth.h>
6
#include <fcall.h>
7
#include <thread.h>
8
#include <9p.h>
9
 
10
enum {
11
	/* power mgmt event codes */
12
	NotifyStandbyRequest		= 0x0001,
13
	NotifySuspendRequest		= 0x0002,
14
	NotifyNormalResume 		= 0x0003,
15
	NotifyCriticalResume		= 0x0004,
16
	NotifyBatteryLow			= 0x0005,
17
	NotifyPowerStatusChange	= 0x0006,
18
	NotifyUpdateTime			= 0x0007,
19
	NotifyCriticalSuspend		= 0x0008,
20
	NotifyUserStandbyRequest	= 0x0009,
21
	NotifyUserSuspendRequest	= 0x000A,
22
	NotifyStandbyResume		= 0x000B,
23
	NotifyCapabilitiesChange		= 0x000C,
24
 
25
	/* power device ids: add device number or All */
26
	DevBios					= 0x0000,
27
	DevAll					= 0x0001,
28
	DevDisplay				= 0x0100,
29
	DevStorage				= 0x0200,
30
	DevLpt					= 0x0300,
31
	DevEia					= 0x0400,
32
	DevNetwork				= 0x0500,
33
	DevPCMCIA				= 0x0600,
34
	DevBattery				= 0x8000,
35
		All					= 0x00FF,
36
	DevMask					= 0xFF00,
37
 
38
	/* power states */
39
	PowerEnabled				= 0x0000,
40
	PowerStandby				= 0x0001,
41
	PowerSuspend				= 0x0002,
42
	PowerOff					= 0x0003,
43
 
44
	/* apm commands */
45
	CmdInstallationCheck		= 0x5300,
46
	CmdRealModeConnect		= 0x5301,
47
	CmdProtMode16Connect		= 0x5302,
48
	CmdProtMode32Connect		= 0x5303,
49
	CmdDisconnect			= 0x5304,
50
	CmdCpuIdle				= 0x5305,
51
	CmdCpuBusy				= 0x5306,
52
	CmdSetPowerState			= 0x5307,
53
	CmdSetPowerMgmt	= 0x5308,
54
	  DisablePowerMgmt	= 0x0000,		/* CX */
55
	  EnablePowerMgmt	= 0x0001,
56
	CmdRestoreDefaults			= 0x5309,
57
	CmdGetPowerStatus			= 0x530A,
58
	CmdGetPMEvent			= 0x530B,
59
	CmdGetPowerState			= 0x530C,
60
	CmdGetPowerMgmt			= 0x530D,
61
	CmdDriverVersion			= 0x530E,
62
 
63
	/* like CmdDisconnect but doesn't lose the interface */
64
	CmdGagePowerMgmt	= 0x530F,
65
	  DisengagePowerMgmt	= 0x0000,	/* CX */
66
	  EngagePowerManagemenet	= 0x0001,
67
 
68
	CmdGetCapabilities			= 0x5310,
69
	  CapStandby				= 0x0001,
70
	  CapSuspend				= 0x0002,
71
	  CapTimerResumeStandby	= 0x0004,
72
	  CapTimerResumeSuspend	= 0x0008,
73
	  CapRingResumeStandby		= 0x0010,
74
	  CapRingResumeSuspend	= 0x0020,
75
	  CapPcmciaResumeStandby	= 0x0040,
76
	  CapPcmciaResumeSuspend	= 0x0080,
77
	  CapSlowCpu				= 0x0100,
78
	CmdResumeTimer			= 0x5311,
79
	  DisableResumeTimer		= 0x00,		/* CL */
80
	  GetResumeTimer			= 0x01,
81
	  SetResumeTimer			= 0x02,
82
	CmdResumeOnRing			= 0x5312,
83
	  DisableResumeOnRing		= 0x0000,		/* CX */
84
	  EnableResumeOnRing		= 0x0001,
85
	  GetResumeOnRing			= 0x0002,
86
	CmdTimerRequests			= 0x5313,
87
	  DisableTimerRequests		= 0x0000,		/* CX */
88
	  EnableTimerRequests		= 0x0001,
89
	  GetTimerRequests			= 0x0002,
90
};
91
 
92
static char* eventstr[] = {
93
[NotifyStandbyRequest]	"system standby request",
94
[NotifySuspendRequest]	"system suspend request",
95
[NotifyNormalResume]	"normal resume",
96
[NotifyCriticalResume]	"critical resume",
97
[NotifyBatteryLow]		"battery low",
98
[NotifyPowerStatusChange]	"power status change",
99
[NotifyUpdateTime]		"update time",
100
[NotifyCriticalSuspend]	"critical suspend",
101
[NotifyUserStandbyRequest]	"user standby request",
102
[NotifyUserSuspendRequest]	"user suspend request",
103
[NotifyCapabilitiesChange]	"capabilities change",
104
};
105
 
106
static char*
107
apmevent(int e)
108
{
109
	static char buf[32];
110
 
111
	if(0 <= e && e < nelem(eventstr) && eventstr[e])
112
		return eventstr[e];
113
 
114
	sprint(buf, "event 0x%ux", (uint)e);
115
	return buf;
116
}
117
 
118
static char *error[256] = {
119
[0x01]	"power mgmt disabled",
120
[0x02]	"real mode connection already established",
121
[0x03]	"interface not connected",
122
[0x05]	"16-bit protected mode connection already established",
123
[0x06]	"16-bit protected mode interface not supported",
124
[0x07]	"32-bit protected mode interface already established",
125
[0x08]	"32-bit protected mode interface not supported",
126
[0x09]	"unrecognized device id",
127
[0x0A]	"parameter value out of range",
128
[0x0B]	"interface not engaged",
129
[0x0C]	"function not supported",
130
[0x0D]	"resume timer disabled",
131
[0x60]	"unable to enter requested state",
132
[0x80]	"no power mgmt events pending",
133
[0x86]	"apm not present",
134
};
135
 
136
static char*
137
apmerror(int id)
138
{
139
	char *e;
140
	static char buf[64];
141
 
142
	if(e = error[id&0xFF])
143
		return e;
144
 
145
	sprint(buf, "unknown error %x", id);
146
	return buf;
147
}
148
 
149
QLock apmlock;
150
int apmdebug;
151
 
152
static int
153
_apmcall(int fd, Ureg *u)
154
{
155
if(apmdebug) fprint(2, "call ax 0x%lux bx 0x%lux cx 0x%lux\n",
156
	u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF);
157
 
158
	seek(fd, 0, 0);
159
	if(write(fd, u, sizeof *u) != sizeof *u)
160
		return -1;
161
 
162
	seek(fd, 0, 0);
163
	if(read(fd, u, sizeof *u) != sizeof *u)
164
		return -1;
165
 
166
if(apmdebug) fprint(2, "flags 0x%lux ax 0x%lux bx 0x%lux cx 0x%lux\n",
167
	u->flags&0xFFFF, u->ax&0xFFFF, u->bx&0xFFFF, u->cx&0xFFFF);
168
 
169
	if(u->flags & 1) {	/* carry flag */
170
		werrstr("%s", apmerror(u->ax>>8));
171
		return -1;
172
	}
173
	return 0;
174
}
175
 
176
static int
177
apmcall(int fd, Ureg *u)
178
{
179
	int r;
180
 
181
	qlock(&apmlock);
182
	r = _apmcall(fd, u);
183
	qunlock(&apmlock);
184
	return r;
185
}
186
 
187
typedef struct Apm Apm;
188
typedef struct Battery Battery;
189
 
190
struct Battery {
191
	int status;
192
	int percent;
193
	int time;
194
};
195
 
196
enum {
197
	Mbattery = 4,
198
};
199
struct Apm {
200
	int fd;
201
 
202
	int verhi;
203
	int verlo;
204
 
205
	int acstatus;
206
	int nbattery;
207
 
208
	int capabilities;
209
 
210
	Battery battery[Mbattery];
211
};
212
enum {
213
	AcUnknown = 0,		/* Apm.acstatus */
214
	AcOffline,
215
	AcOnline,
216
	AcBackup,
217
 
218
	BatteryUnknown = 0,	/* Battery.status */
219
	BatteryHigh,
220
	BatteryLow,
221
	BatteryCritical,
222
	BatteryCharging,
223
};
224
 
225
static char*
226
acstatusstr[] = {
227
[AcUnknown]	"unknown",
228
[AcOffline]	"offline",
229
[AcOnline]	"online",
230
[AcBackup]	"backup",
231
};
232
 
233
static char*
234
batterystatusstr[] = {
235
[BatteryUnknown] "unknown",
236
[BatteryHigh]	"high",
237
[BatteryLow]	"low",
238
[BatteryCritical]	"critical",
239
[BatteryCharging]	"charging",
240
};
241
 
242
static char*
243
powerstatestr[] = {
244
[PowerOff]	"off",
245
[PowerSuspend]	"suspend",
246
[PowerStandby]	"standby",
247
[PowerEnabled]	"on",
248
};
249
 
250
static char*
251
xstatus(char **str, int nstr, int x)
252
{
253
	if(0 <= x && x < nstr && str[x])
254
		return str[x];
255
	return "unknown";
256
}
257
 
258
static char*
259
batterystatus(int b)
260
{
261
	return xstatus(batterystatusstr, nelem(batterystatusstr), b);
262
}
263
 
264
static char*
265
powerstate(int s)
266
{
267
	return xstatus(powerstatestr, nelem(powerstatestr), s);
268
}
269
 
270
static char*
271
acstatus(int a)
272
{
273
	return xstatus(acstatusstr, nelem(acstatusstr), a);
274
}
275
 
276
static int
277
apmversion(Apm *apm)
278
{
279
	Ureg u;
280
 
281
	u.ax = CmdDriverVersion;
282
	u.bx = 0x0000;
283
	u.cx = 0x0102;
284
	if(apmcall(apm->fd, &u) < 0)
285
		return -1;
286
 
287
	apm->verhi = u.cx>>8;
288
	apm->verlo = u.cx & 0xFF;
289
 
290
	return u.cx;
291
}
292
 
293
static int
294
apmcpuidle(Apm *apm)
295
{
296
	Ureg u;
297
 
298
	u.ax = CmdCpuIdle;
299
	return apmcall(apm->fd, &u);
300
}
301
 
302
static int
303
apmcpubusy(Apm *apm)
304
{
305
	Ureg u;
306
 
307
	u.ax = CmdCpuBusy;
308
	return apmcall(apm->fd, &u);
309
}
310
 
311
static int
312
apmsetpowerstate(Apm *apm, int dev, int state)
313
{
314
	Ureg u;
315
 
316
	u.ax = CmdSetPowerState;
317
	u.bx = dev;
318
	u.cx = state;
319
	return apmcall(apm->fd, &u);
320
}
321
 
322
static int
323
apmsetpowermgmt(Apm *apm, int dev, int state)
324
{
325
	Ureg u;
326
 
327
	u.ax = CmdSetPowerMgmt;
328
	u.bx = dev;
329
	u.cx = state;
330
	return apmcall(apm->fd, &u);
331
}
332
 
333
static int
334
apmrestoredefaults(Apm *apm, int dev)
335
{
336
	Ureg u;
337
 
338
	u.ax = CmdRestoreDefaults;
339
	u.bx = dev;
340
	return apmcall(apm->fd, &u);
341
}
342
 
343
static int
344
apmgetpowerstatus(Apm *apm, int dev)
345
{
346
	Battery *b;
347
	Ureg u;
348
 
349
	if(dev == DevAll)
350
		b = &apm->battery[0];
351
	else if((dev & DevMask) == DevBattery) {
352
		if(dev - DevBattery < nelem(apm->battery))
353
			b = &apm->battery[dev - DevBattery];
354
		else
355
			b = nil;
356
	} else {
357
		werrstr("bad device number");
358
		return -1;
359
	}
360
 
361
	u.ax = CmdGetPowerStatus;
362
	u.bx = dev;
363
 
364
	if(apmcall(apm->fd, &u) < 0)
365
		return -1;
366
 
367
	if((dev & DevMask) == DevBattery)
368
		apm->nbattery = u.si;
369
 
370
	switch(u.bx>>8) {
371
	case 0x00:
372
		apm->acstatus = AcOffline;
373
		break;
374
	case 0x01:
375
		apm->acstatus = AcOnline;
376
		break;
377
	case 0x02:
378
		apm->acstatus = AcBackup;
379
		break;
380
	default:
381
		apm->acstatus = AcUnknown;
382
		break;
383
	}
384
 
385
	if(b != nil) {
386
		switch(u.bx&0xFF) {
387
		case 0x00:
388
			b->status = BatteryHigh;
389
			break;
390
		case 0x01:
391
			b->status = BatteryLow;
392
			break;
393
		case 0x02:
394
			b->status = BatteryCritical;
395
			break;
396
		case 0x03:
397
			b->status = BatteryCharging;
398
			break;
399
		default:
400
			b->status = BatteryUnknown;
401
			break;
402
		}
403
 
404
		if((u.cx & 0xFF) == 0xFF)
405
			b->percent = -1;
406
		else
407
			b->percent = u.cx & 0xFF;
408
 
409
		if((u.dx&0xFFFF) == 0xFFFF)
410
			b->time = -1;
411
		else if(u.dx & 0x8000)
412
			b->time = 60*(u.dx & 0x7FFF);
413
		else
414
			b->time = u.dx & 0x7FFF;
415
	}
416
 
417
	return 0;
418
}
419
 
420
static int
421
apmgetevent(Apm *apm)
422
{
423
	Ureg u;
424
 
425
	u.ax = CmdGetPMEvent;
426
	u.bx = 0;
427
	u.cx = 0;
428
 
429
	//when u.bx == NotifyNormalResume or NotifyCriticalResume,
430
	//u.cx & 1 indicates PCMCIA socket was on while suspended,
431
	//u.cx & 1 == 0 indicates was off.
432
 
433
	if(apmcall(apm->fd, &u) < 0)
434
		return -1;
435
 
436
	return u.bx;
437
}
438
 
439
static int
440
apmgetpowerstate(Apm *apm, int dev)
441
{
442
	Ureg u;
443
 
444
	u.ax = CmdGetPowerState;
445
	u.bx = dev;
446
	u.cx = 0;
447
 
448
	if(apmcall(apm->fd, &u) < 0)
449
		return -1;
450
 
451
	return u.cx;
452
}
453
 
454
static int
455
apmgetpowermgmt(Apm *apm, int dev)
456
{
457
	Ureg u;
458
 
459
	u.ax = CmdGetPowerMgmt;
460
	u.bx = dev;
461
 
462
	if(apmcall(apm->fd, &u) < 0)
463
		return -1;
464
 
465
	return u.cx;
466
}
467
 
468
static int
469
apmgetcapabilities(Apm *apm)
470
{
471
	Ureg u;
472
 
473
	u.ax = CmdGetCapabilities;
474
	u.bx = DevBios;
475
 
476
	if(apmcall(apm->fd, &u) < 0)
477
		return -1;
478
 
479
	apm->nbattery = u.bx & 0xFF;
480
	apm->capabilities &= ~0xFFFF;
481
	apm->capabilities |= u.cx;
482
	return 0;
483
}
484
 
485
static int
486
apminstallationcheck(Apm *apm)
487
{
488
	Ureg u;
489
 
490
	u.ax = CmdInstallationCheck;
491
	u.bx = DevBios;
492
	if(apmcall(apm->fd, &u) < 0)
493
		return -1;
494
 
495
	if(u.cx & 0x0004)
496
		apm->capabilities |= CapSlowCpu;
497
	else
498
		apm->capabilities &= ~CapSlowCpu;
499
	return 0;
500
}
501
 
502
void
503
apmsetdisplaystate(Apm *apm, int s)
504
{
505
	apmsetpowerstate(apm, DevDisplay, s);
506
}
507
 
508
void
509
apmblank(Apm *apm)
510
{
511
	apmsetdisplaystate(apm, PowerStandby);
512
}
513
 
514
void
515
apmunblank(Apm *apm)
516
{
517
	apmsetdisplaystate(apm, PowerEnabled);
518
}
519
 
520
void
521
apmsuspend(Apm *apm)
522
{
523
	apmsetpowerstate(apm, DevAll, PowerSuspend);
524
}
525
 
526
Apm apm;
527
 
528
void
529
powerprint(void)
530
{
531
	print("%s", ctime(time(0)));
532
	if(apmgetpowerstatus(&apm, DevAll) == 0) {
533
		print("%d batteries\n", apm.nbattery);
534
		print("battery 0: status %s percent %d time %d:%.2d\n",
535
			batterystatus(apm.battery[0].status), apm.battery[0].percent,
536
			apm.battery[0].time/60, apm.battery[0].time%60);
537
	}
538
}
539
 
540
void*
541
erealloc(void *v, ulong n)
542
{
543
	v = realloc(v, n);
544
	if(v == nil)
545
		sysfatal("out of memory reallocating %lud", n);
546
	setmalloctag(v, getcallerpc(&v));
547
	return v;
548
}
549
 
550
void*
551
emalloc(ulong n)
552
{
553
	void *v;
554
 
555
	v = malloc(n);
556
	if(v == nil)
557
		sysfatal("out of memory allocating %lud", n);
558
	memset(v, 0, n);
559
	setmalloctag(v, getcallerpc(&n));
560
	return v;
561
}
562
 
563
char*
564
estrdup(char *s)
565
{
566
	int l;
567
	char *t;
568
 
569
	if (s == nil)
570
		return nil;
571
	l = strlen(s)+1;
572
	t = emalloc(l);
573
	memcpy(t, s, l);
574
	setmalloctag(t, getcallerpc(&s));
575
	return t;
576
}
577
 
578
char*
579
estrdupn(char *s, int n)
580
{
581
	int l;
582
	char *t;
583
 
584
	l = strlen(s);
585
	if(l > n)
586
		l = n;
587
	t = emalloc(l+1);
588
	memmove(t, s, l);
589
	t[l] = '\0';
590
	setmalloctag(t, getcallerpc(&s));
591
	return t;
592
}
593
 
594
enum {
595
	Qroot = 0,
596
	Qevent,
597
	Qbattery,
598
	Qctl,
599
};
600
 
601
static void rootread(Req*);
602
static void eventread(Req*);
603
static void ctlread(Req*);
604
static void ctlwrite(Req*);
605
static void batteryread(Req*);
606
 
607
typedef struct Dfile Dfile;
608
struct Dfile {
609
	Qid qid;
610
	char *name;
611
	ulong mode;
612
	void (*read)(Req*);
613
	void (*write)(Req*);
614
};
615
 
616
Dfile dfile[] = {
617
	{ {Qroot,0,QTDIR},		"/",		DMDIR|0555,	rootread,		nil, },
618
	{ {Qevent},		"event",	0444,		eventread,	nil, },
619
	{ {Qbattery},	"battery",	0444,		batteryread,	nil, },
620
	{ {Qctl},		"ctl",		0666,		ctlread,		ctlwrite, },
621
};
622
 
623
static int
624
fillstat(uvlong path, Dir *d, int doalloc)
625
{
626
	int i;
627
 
628
	for(i=0; i<nelem(dfile); i++)
629
		if(path==dfile[i].qid.path)
630
			break;
631
	if(i==nelem(dfile))
632
		return -1;
633
 
634
	memset(d, 0, sizeof *d);
635
	d->uid = doalloc ? estrdup("apm") : "apm";
636
	d->gid = doalloc ? estrdup("apm") : "apm";
637
	d->length = 0;
638
	d->name = doalloc ? estrdup(dfile[i].name) : dfile[i].name;
639
	d->mode = dfile[i].mode;
640
	d->atime = d->mtime = time(0);
641
	d->qid = dfile[i].qid;
642
	return 0;
643
}
644
 
645
static char*
646
fswalk1(Fid *fid, char *name, Qid *qid)
647
{
648
	int i;
649
 
650
	if(strcmp(name, "..")==0){
651
		*qid = dfile[0].qid;
652
		fid->qid = *qid;
653
		return nil;
654
	}
655
 
656
	for(i=1; i<nelem(dfile); i++){	/* i=1: 0 is root dir */
657
		if(strcmp(dfile[i].name, name)==0){
658
			*qid = dfile[i].qid;
659
			fid->qid = *qid;
660
			return nil;
661
		}
662
	}
663
	return "file does not exist";
664
}
665
 
666
static void
667
fsopen(Req *r)
668
{
669
	switch((ulong)r->fid->qid.path){
670
	case Qroot:
671
		r->fid->aux = (void*)0;
672
		respond(r, nil);
673
		return;
674
 
675
	case Qevent:
676
	case Qbattery:
677
		if(r->ifcall.mode == OREAD){
678
			respond(r, nil);
679
			return;
680
		}
681
		break;
682
 
683
	case Qctl:
684
		if((r->ifcall.mode&~(OTRUNC|OREAD|OWRITE|ORDWR)) == 0){
685
			respond(r, nil);
686
			return;
687
		}
688
		break;
689
	}
690
	respond(r, "permission denied");
691
	return;
692
}
693
 
694
static void
695
fsstat(Req *r)
696
{
697
	fillstat(r->fid->qid.path, &r->d, 1);
698
	respond(r, nil);
699
}
700
 
701
static void
702
fsread(Req *r)
703
{
704
	dfile[r->fid->qid.path].read(r);
705
}
706
 
707
static void
708
fswrite(Req *r)
709
{
710
	dfile[r->fid->qid.path].write(r);
711
}
712
 
713
static void
714
rootread(Req *r)
715
{
716
	int n;
717
	uvlong offset;
718
	char *p, *ep;
719
	Dir d;
720
 
721
	if(r->ifcall.offset == 0)
722
		offset = 0;
723
	else
724
		offset = (uvlong)r->fid->aux;
725
 
726
	p = r->ofcall.data;
727
	ep = r->ofcall.data+r->ifcall.count;
728
 
729
	if(offset == 0)		/* skip root */
730
		offset = 1;
731
	for(; p+2 < ep; p+=n){
732
		if(fillstat(offset, &d, 0) < 0)
733
			break;
734
		n = convD2M(&d, (uchar*)p, ep-p);
735
		if(n <= BIT16SZ)
736
			break;
737
		offset++;
738
	}
739
	r->fid->aux = (void*)offset;
740
	r->ofcall.count = p - r->ofcall.data;
741
	respond(r, nil);
742
}
743
 
744
static void
745
batteryread(Req *r)
746
{
747
	char buf[Mbattery*80], *ep, *p;
748
	int i;
749
 
750
	apmgetpowerstatus(&apm, DevAll);
751
 
752
	p = buf;
753
	ep = buf+sizeof buf;
754
	*p = '\0';	/* could be no batteries */
755
	for(i=0; i<apm.nbattery && i<Mbattery; i++)
756
		p += snprint(p, ep-p, "%s %d %d\n",
757
			batterystatus(apm.battery[i].status),
758
			apm.battery[i].percent, apm.battery[i].time);
759
 
760
	readstr(r, buf);
761
	respond(r, nil);
762
}
763
 
764
int
765
iscmd(char *p, char *cmd)
766
{
767
	int l;
768
 
769
	l = strlen(cmd);
770
	return strncmp(p, cmd, l)==0 && p[l]=='\0' || p[l]==' ' || p[l]=='\t';
771
}
772
 
773
char*
774
skip(char *p, char *cmd)
775
{
776
	p += strlen(cmd);
777
	while(*p==' ' || *p=='\t')
778
		p++;
779
	return p;
780
}
781
 
782
static void
783
respondx(Req *r, int c)
784
{
785
	char err[ERRMAX];
786
 
787
	if(c == 0)
788
		respond(r, nil);
789
	else{
790
		rerrstr(err, sizeof err);
791
		respond(r, err);
792
	}
793
}
794
 
795
/*
796
 * we don't do suspend because it messes up the
797
 * cycle counter as well as the pcmcia ethernet cards.
798
 */
799
static void
800
ctlwrite(Req *r)
801
{
802
	char buf[80], *p, *q;
803
	int dev;
804
	long count;
805
 
806
	count = r->ifcall.count;
807
	if(count > sizeof(buf)-1)
808
		count = sizeof(buf)-1;
809
	memmove(buf, r->ifcall.data, count);
810
	buf[count] = '\0';
811
 
812
	if(count && buf[count-1] == '\n'){
813
		--count;
814
		buf[count] = '\0';
815
	}
816
 
817
	q = buf;
818
	p = strchr(q, ' ');
819
	if(p==nil)
820
		p = q+strlen(q);
821
	else
822
		*p++ = '\0';
823
 
824
	if(strcmp(q, "")==0 || strcmp(q, "system")==0)
825
		dev = DevAll;
826
	else if(strcmp(q, "display")==0)
827
		dev = DevDisplay;
828
	else if(strcmp(q, "storage")==0)
829
		dev = DevStorage;
830
	else if(strcmp(q, "lpt")==0)
831
		dev = DevLpt;
832
	else if(strcmp(q, "eia")==0)
833
		dev = DevEia;
834
	else if(strcmp(q, "network")==0)
835
		dev = DevNetwork;
836
	else if(strcmp(q, "pcmcia")==0)
837
		dev = DevPCMCIA;
838
	else{
839
		respond(r, "unknown device");
840
		return;
841
	}
842
 
843
	if(strcmp(p, "enable")==0)
844
		respondx(r, apmsetpowermgmt(&apm, dev, EnablePowerMgmt));
845
	else if(strcmp(p, "disable")==0)
846
		respondx(r, apmsetpowermgmt(&apm, dev, DisablePowerMgmt));
847
	else if(strcmp(p, "standby")==0)
848
		respondx(r, apmsetpowerstate(&apm, dev, PowerStandby));
849
	else if(strcmp(p, "on")==0)
850
		respondx(r, apmsetpowerstate(&apm, dev, PowerEnabled));
851
/*
852
	else if(strcmp(p, "off")==0)
853
		respondx(r, apmsetpowerstate(&apm, dev, PowerOff));
854
*/
855
	else if(strcmp(p, "suspend")==0)
856
		respondx(r, apmsetpowerstate(&apm, dev, PowerSuspend));
857
	else
858
		respond(r, "unknown verb");
859
}
860
 
861
static int
862
statusline(char *buf, int nbuf, char *name, int dev)
863
{
864
	int s;
865
	char *state;
866
 
867
	state = "unknown";
868
	if((s = apmgetpowerstate(&apm, dev)) >= 0)
869
		state = powerstate(s);
870
	return snprint(buf, nbuf, "%s %s\n", name, state);
871
}
872
 
873
static void
874
ctlread(Req *r)
875
{
876
	char buf[256+7*50], *ep, *p;
877
 
878
	p = buf;
879
	ep = buf+sizeof buf;
880
 
881
	p += snprint(p, ep-p, "ac %s\n", acstatus(apm.acstatus));
882
	p += snprint(p, ep-p, "capabilities");
883
	if(apm.capabilities & CapStandby) 
884
		p += snprint(p, ep-p, " standby");
885
	if(apm.capabilities & CapSuspend) 
886
		p += snprint(p, ep-p, " suspend");
887
	if(apm.capabilities & CapSlowCpu)
888
		p += snprint(p, ep-p, " slowcpu");
889
	p += snprint(p, ep-p, "\n");
890
 
891
	p += statusline(p, ep-p, "system", DevAll);
892
	p += statusline(p, ep-p, "display", DevDisplay);
893
	p += statusline(p, ep-p, "storage", DevStorage);
894
	p += statusline(p, ep-p, "lpt", DevLpt);
895
	p += statusline(p, ep-p, "eia", DevEia|All);
896
	p += statusline(p, ep-p, "network", DevNetwork|All);
897
	p += statusline(p, ep-p, "pcmcia", DevPCMCIA|All);
898
	USED(p);
899
 
900
	readstr(r, buf);
901
	respond(r, nil);
902
}
903
 
904
enum {
905
	STACK = 16384,
906
};
907
 
908
Channel *creq;
909
Channel *cflush;
910
Channel *cevent;
911
Req *rlist, **tailp;
912
int rp, wp;
913
int nopoll;
914
char eventq[32][80];
915
 
916
static void
917
flushthread(void*)
918
{
919
	Req *r, *or, **rq;
920
 
921
	threadsetname("flushthread");
922
	while(r = recvp(cflush)){
923
		or = r->oldreq;
924
		for(rq=&rlist; *rq; rq=&(*rq)->aux){
925
			if(*rq == or){
926
				*rq = or->aux;
927
				if(tailp==&or->aux)
928
					tailp = rq;
929
				respond(or, "interrupted");
930
				break;
931
			}
932
		}
933
		respond(r, nil);
934
	}
935
}
936
 
937
static void
938
answerany(void)
939
{
940
	char *buf;
941
	int l, m;
942
	Req *r;
943
 
944
	if(rlist==nil || rp==wp)
945
		return;
946
 
947
	while(rlist && rp != wp){
948
		r = rlist;
949
		rlist = r->aux;
950
		if(rlist==nil)
951
			tailp = &rlist;
952
 
953
		l = 0;
954
		buf = r->ofcall.data;
955
		m = r->ifcall.count;
956
		while(rp != wp){
957
			if(l+strlen(eventq[rp]) <= m){
958
				strcpy(buf+l, eventq[rp]);
959
				l += strlen(buf+l);
960
			}else if(l==0){
961
				strncpy(buf, eventq[rp], m-1);
962
				buf[m-1] = '\0';
963
				l += m;
964
			}else
965
				break;
966
			rp++;
967
			if(rp == nelem(eventq))
968
				rp = 0;
969
		}
970
		r->ofcall.count = l;
971
		respond(r, nil);
972
	}
973
}
974
 
975
static void
976
eventwatch(void*)
977
{
978
	int e, s;
979
 
980
	threadsetname("eventwatch");
981
	for(;;){
982
		s = 0;
983
		while((e = apmgetevent(&apm)) >= 0){
984
			sendul(cevent, e);
985
			s = 1;
986
		}
987
		if(s)
988
			sendul(cevent, -1);
989
		if(sleep(750) < 0)
990
			break;
991
	}
992
}
993
 
994
static void
995
eventthread(void*)
996
{
997
	int e;
998
 
999
	threadsetname("eventthread");
1000
	for(;;){
1001
		while((e = recvul(cevent)) >= 0){
1002
			snprint(eventq[wp], sizeof(eventq[wp])-1, "%s", apmevent(e));
1003
			strcat(eventq[wp], "\n");
1004
			wp++;
1005
			if(wp==nelem(eventq))
1006
				wp = 0;
1007
			if(wp+1==rp || (wp+1==nelem(eventq) && rp==0))
1008
				break;
1009
		}
1010
		answerany();
1011
	}
1012
}
1013
 
1014
static void
1015
eventproc(void*)
1016
{
1017
	Req *r;
1018
 
1019
	threadsetname("eventproc");
1020
 
1021
	creq = chancreate(sizeof(Req*), 0);
1022
	cevent = chancreate(sizeof(ulong), 0);
1023
	cflush = chancreate(sizeof(Req*), 0);
1024
 
1025
	tailp = &rlist;
1026
	if(!nopoll)
1027
		proccreate(eventwatch, nil, STACK);
1028
	threadcreate(eventthread, nil, STACK);
1029
	threadcreate(flushthread, nil, STACK);
1030
 
1031
	while(r = recvp(creq)){
1032
		*tailp = r;
1033
		r->aux = nil;
1034
		tailp = &r->aux;
1035
		answerany();
1036
	}
1037
}
1038
 
1039
static void
1040
fsflush(Req *r)
1041
{
1042
	sendp(cflush, r);
1043
}
1044
 
1045
static void
1046
eventread(Req *r)
1047
{
1048
	sendp(creq, r);
1049
}
1050
 
1051
static void
1052
fsattach(Req *r)
1053
{
1054
	char *spec;
1055
	static int first = 1;
1056
 
1057
	spec = r->ifcall.aname;
1058
 
1059
	if(first){
1060
		first = 0;
1061
		proccreate(eventproc, nil, STACK);
1062
	}
1063
 
1064
	if(spec && spec[0]){
1065
		respond(r, "invalid attach specifier");
1066
		return;
1067
	}
1068
	r->fid->qid = dfile[0].qid;
1069
	r->ofcall.qid = dfile[0].qid;
1070
	respond(r, nil);
1071
}
1072
 
1073
Srv fs = {
1074
.attach=	fsattach,
1075
.walk1=	fswalk1,
1076
.open=	fsopen,
1077
.read=	fsread,
1078
.write=	fswrite,
1079
.stat=	fsstat,
1080
.flush=	fsflush,
1081
};
1082
 
1083
void
1084
usage(void)
1085
{
1086
	fprint(2, "usage: aux/apm [-ADPi] [-d /dev/apm] [-m /mnt/apm] [-s service]\n");
1087
	exits("usage");
1088
}
1089
 
1090
void
1091
threadmain(int argc, char **argv)
1092
{
1093
	char *dev, *mtpt, *srv;
1094
 
1095
	dev = nil;
1096
	mtpt = "/mnt/apm";
1097
	srv = nil;
1098
	ARGBEGIN{
1099
	case 'A':
1100
		apmdebug = 1;
1101
		break;
1102
	case 'D':
1103
		chatty9p = 1;
1104
		break;
1105
	case 'P':
1106
		nopoll = 1;
1107
		break;
1108
	case 'd':
1109
		dev = EARGF(usage());
1110
		break;
1111
	case 'i':
1112
		fs.nopipe++;
1113
		fs.infd = 0;
1114
		fs.outfd = 1;
1115
		mtpt = nil;
1116
		break;
1117
	case 'm':
1118
		mtpt = EARGF(usage());
1119
		break;
1120
	case 's':
1121
		srv = EARGF(usage());
1122
		break;
1123
	}ARGEND
1124
 
1125
	if(dev == nil){
1126
		if((apm.fd = open("/dev/apm", ORDWR)) < 0
1127
		&& (apm.fd = open("#P/apm", ORDWR)) < 0){
1128
			fprint(2, "open %s: %r\n", dev);
1129
			threadexitsall("open");
1130
		}
1131
	} else if((apm.fd = open(dev, ORDWR)) < 0){
1132
		fprint(2, "open %s: %r\n", dev);
1133
		threadexitsall("open");
1134
	}
1135
 
1136
	if(apmversion(&apm) < 0){
1137
		fprint(2, "cannot get apm version: %r\n");
1138
		threadexitsall("apmversion");
1139
	}
1140
 
1141
	if(apm.verhi < 1 || (apm.verhi==1 && apm.verlo < 2)){
1142
		fprint(2, "apm version %d.%d not supported\n", apm.verhi, apm.verlo);
1143
		threadexitsall("apmversion");
1144
	}
1145
 
1146
	if(apmgetcapabilities(&apm) < 0)
1147
		fprint(2, "warning: cannot read apm capabilities: %r\n");
1148
 
1149
	apminstallationcheck(&apm);
1150
	apmcpuidle(&apm);
1151
 
1152
	rfork(RFNOTEG);
1153
	threadpostmountsrv(&fs, srv, mtpt, MREPL);
1154
}