shithub: riscv

Download patch

ref: 26e00d014cebde8bc07725700b5ac9c0cade8171
parent: e01577f8f61023ab90d8022e75cb00027399428c
author: ftrvxmtrx <ftrvxmtrx@gmail.com>
date: Tue Oct 18 19:05:09 EDT 2016

aux/acpi: batteries and CPU temp reading so far

--- /dev/null
+++ b/sys/src/cmd/aux/acpi.c
@@ -1,0 +1,594 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include <aml.h>
+
+typedef struct Batstat Batstat;
+typedef struct Battery Battery;
+typedef struct Dfile Dfile;
+typedef struct Tbl Tbl;
+typedef struct Thermal Thermal;
+
+struct Batstat {
+	int rate;
+	int capacity;
+	int state;
+	int voltage;
+};
+
+struct Battery {
+	char *unit;
+	void *bst;
+	int id;
+	int fullcharge;
+	int capacity;
+	int capacitywarn;
+	int capacitylow;
+	int voltage;
+};
+
+struct Dfile {
+	Qid qid;
+	char *name;
+	ulong mode;
+	void (*read)(Req*);
+	void (*write)(Req*);
+};
+
+struct Tbl {
+	uchar sig[4];
+	uchar len[4];
+	uchar rev;
+	uchar csum;
+	uchar oemid[6];
+	uchar oemtid[8];
+	uchar oemrev[4];
+	uchar cid[4];
+	uchar crev[4];
+	uchar data[];
+};
+
+struct Thermal {
+	uint cpus;
+	void *tmp;
+};
+
+enum {
+	Stacksz = 16384,
+	Tblsz = 4+4+1+1+6+8+4+4+4,
+
+	Qroot = 0,
+	Qbattery,
+	Qcputemp,
+	Qctl,
+};
+
+static void rootread(Req*);
+static void ctlread(Req*);
+static void ctlwrite(Req*);
+static void batteryread(Req*);
+static void tmpread(Req*);
+
+int ec, mem, iofd[5], nbats, ntherms, rp, wp;
+char *units[] = {"mW", "mA"};
+Battery bats[4];
+Thermal therms[4];
+Channel *creq, *cevent;
+Req *rlist, **tailp;
+
+Dfile dfile[] = {
+	{{Qroot,0,QTDIR},	"/",		DMDIR|0555,	rootread,		nil},
+	{{Qbattery},		"battery",	0444,		batteryread,	nil},
+	{{Qcputemp},		"cputemp",	0444,		tmpread,		nil},
+	{{Qctl},			"ctl",		0666,		ctlread,		ctlwrite},
+};
+
+static int
+enumbat(void *dot, void *)
+{
+	void *p, *r, **rr;
+	Battery *b;
+	int n;
+
+	if(nbats >= nelem(bats))
+		return 1;
+
+	if((p = amlwalk(dot, "^_STA")) == nil)
+		return 1;
+	if(amleval(p, "", &r) < 0 || (amlint(r)&3) != 3)
+		return 1;
+	if(amleval(dot, "", &r) < 0) /* _BIF */
+		return 1;
+	if(r == nil || amltag(r) != 'p' || amllen(r) < 7)
+		return 1;
+
+	rr = amlval(r);
+	b = &bats[nbats];
+	if((n = amlint(rr[0])) >= nelem(units) || n < 0)
+		b->unit = "??";
+	else
+		b->unit = units[n];
+	b->capacity = amlint(rr[1]);
+	if((int)b->capacity < 0) /* even though _STA tells it's there */
+		return 1;
+	b->fullcharge = amlint(rr[2]);
+	b->voltage = amlint(rr[4]);
+	b->capacitywarn = amlint(rr[5]);
+	b->capacitylow = amlint(rr[6]);
+	b->id = amlint(amlwalk(dot, "^_UID"));
+	b->bst = amlwalk(dot, "^_BST");
+	if(b->bst != nil){
+		amltake(b->bst);
+		nbats++;
+	}
+
+	return 1;
+}
+
+static int
+enumtmp(void *dot, void *)
+{
+	void *r, **rr;
+	char s[64];
+	int i, n;
+	uint cpus;
+
+	cpus = 0;
+	if(ntherms < nelem(therms) && amleval(dot, "", &r) >= 0 && amllen(r) > 0 && (rr = amlval(r)) != nil){
+		for(i = 0; i < amllen(r); i++){
+			snprint(s, sizeof(s), "%N", amlval(rr[i]));
+			if((n = strlen(s)) > 0){
+				for(n--; n > 3; n--){
+					if(s[n-2] == 'C' && s[n-1] == 'P' && s[n] == 'U' && s[n+1] >= '0' && s[n+1] <= '9'){
+						cpus |= 1<<atoi(&s[n+1]);
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	if(cpus != 0 && (dot = amlwalk(dot, "^_TMP")) != nil){
+		therms[ntherms].cpus = cpus;
+		therms[ntherms].tmp = dot;
+		ntherms++;
+	}
+
+	return 1;
+}
+
+static int
+batstat(Battery *b, Batstat *s)
+{
+	void *r, **rr;
+
+	if(amleval(b->bst, "", &r) < 0)
+		return -1;
+	if(r == nil || amltag(r) != 'p' || amllen(r) < 4)
+		return -1;
+	rr = amlval(r);
+	s->state = amlint(rr[0]);
+	s->rate = amlint(rr[1]);
+	s->capacity = amlint(rr[2]);
+	s->voltage = amlint(rr[3]);
+	return 0;
+}
+
+static void
+batteryread(Req *r)
+{
+	char buf[nelem(bats)*120], *ep, *p, *state;
+	Battery *b;
+	Batstat st;
+	int n, x, h, m, s;
+
+	p = buf;
+	*p = 0;
+	ep = buf + sizeof(buf);
+	for(n = 0; n < nbats; n++){
+		b = &bats[n];
+
+		st.rate = -1;
+		st.capacity = -1;
+		st.state = 0;
+		st.voltage = -1;
+		batstat(b, &st);
+
+		h = m = s = 0;
+		if(st.state & 4)
+			state = "critical";
+		else if(st.state & 1)
+			state = "discharging";
+		else if(st.state & 2)
+			state = "charging";
+		else
+			state = "unknown";
+		if(st.rate > 0){
+			s = ((st.state & 2) ? bats[n].fullcharge - st.capacity : st.capacity) * 3600 / st.rate;
+			h = s/3600;
+			s -= 3600*(s/3600);
+			m = s/60;
+			s -= 60*(s/60);
+		}
+		x = bats[n].fullcharge > 0 ? st.capacity * 100 / bats[n].fullcharge : -1;
+		p += snprint(p, ep-p, "%d %d %s %d %d %d %d %d %s %d %d %02d:%02d:%02d %s\n",
+			n, x,
+			bats[n].unit, st.capacity, b->fullcharge, b->capacity, b->capacitywarn, b->capacitylow,
+			"mV", st.voltage, b->voltage,
+			h, m, s,
+			state
+		);
+	}
+	
+	readstr(r, buf);
+	respond(r, nil);
+}
+
+static void
+tmpread(Req *r)
+{
+	char buf[32], *ep, *p;
+	void *er;
+	int n, t, cpu;
+
+	p = buf;
+	ep = buf + sizeof(buf);
+
+	for(n = 0; n < ntherms; n++){
+		t = 0;
+		if(amleval(therms[n].tmp, "", &er) >= 0)
+			t = amlint(er);
+		for(cpu = 0; cpu < 32; cpu++){
+			if(therms[n].cpus & (1<<cpu))
+				p += snprint(p, ep-p, "%d %d\n", cpu, (t - 2732)/10);
+		}
+	}
+
+	readstr(r, buf);
+	respond(r, nil);
+}
+
+static void
+ctlread(Req *r)
+{
+	respond(r, "no.");
+}
+
+static void
+ctlwrite(Req *r)
+{
+	respond(r, "no.");
+}
+
+void*
+emalloc(ulong n)
+{
+	void *v;
+
+	v = malloc(n);
+	if(v == nil)
+		sysfatal("out of memory allocating %lud", n);
+	memset(v, 0, n);
+	setmalloctag(v, getcallerpc(&n));
+	return v;
+}
+
+char*
+estrdup(char *s)
+{
+	int l;
+	char *t;
+
+	if (s == nil)
+		return nil;
+	l = strlen(s)+1;
+	t = emalloc(l);
+	memcpy(t, s, l);
+	setmalloctag(t, getcallerpc(&s));
+	return t;
+}
+
+static int
+fillstat(uvlong 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("acpi") : "acpi";
+	d->gid = doalloc ? estrdup("acpi") : "acpi";
+	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((ulong)r->fid->qid.path){
+	case Qroot:
+		r->fid->aux = (void*)0;
+		respond(r, nil);
+		return;
+
+	case Qbattery:
+	case Qcputemp:
+		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;
+	uvlong offset;
+	char *p, *ep;
+	Dir d;
+
+	offset = r->ifcall.offset == 0 ? 0 : (uvlong)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, (uchar*)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
+fsattach(Req *r)
+{
+	if(r->ifcall.aname && r->ifcall.aname[0]){
+		respond(r, "invalid attach specifier");
+		return;
+	}
+	r->fid->qid = dfile[0].qid;
+	r->ofcall.qid = dfile[0].qid;
+	respond(r, nil);
+}
+
+static void
+usage(void)
+{
+	fprint(2, "usage: aux/acpi [-Di] [-d /dev] [-m /mnt/acpi] [-s service]\n");
+	exits("usage");
+}
+
+static ulong
+get32(uchar *p){
+	return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
+}
+
+Srv fs = {
+	.attach = fsattach,
+	.walk1 = fswalk1,
+	.open = fsopen,
+	.read = fsread,
+	.write = fswrite,
+	.stat = fsstat,
+};
+
+void
+threadmain(int argc, char **argv)
+{
+	char *mtpt, *srv;
+	Tbl *t;
+	int fd, n, l;
+
+	mtpt = "/mnt/acpi";
+	srv = nil;
+	ARGBEGIN{
+	case 'D':
+		chatty9p = 1;
+		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((ec = open("/dev/ec", ORDWR)) < 0)
+		if((ec = open("#P/ec", ORDWR)) < 0)
+			goto fail;
+	if((mem = open("/dev/acpimem", ORDWR)) < 0)
+		mem = open("#P/acpimem", ORDWR);
+	if((iofd[1] = open("/dev/iob", ORDWR)) < 0)
+		if((iofd[1] = open("#P/iob", ORDWR)) < 0)
+			goto fail;
+	if((iofd[2] = open("/dev/iow", ORDWR)) < 0)
+		if((iofd[2] = open("#P/iow", ORDWR)) < 0)
+			goto fail;
+	if((iofd[4] = open("/dev/iol", ORDWR)) < 0)
+		if((iofd[4] = open("#P/iol", ORDWR)) < 0)
+			goto fail;
+	if((fd = open("/dev/acpitbls", OREAD)) < 0)
+		if((fd = open("#P/acpitbls", OREAD)) < 0)
+			goto fail;
+
+	amlinit();
+	for(;;){
+		t = malloc(sizeof(*t));
+		if((n = readn(fd, t, Tblsz)) <= 0)
+			break;
+		if(n != Tblsz)
+			goto fail;
+		l = get32(t->len);
+		if(l < Tblsz)
+			goto fail;
+		l -= Tblsz;
+		t = realloc(t, sizeof(*t) + l);
+		if(readn(fd, t->data, l) != l)
+			goto fail;
+		if(memcmp("DSDT", t->sig, 4) == 0){
+			amlintmask = (~0ULL) >> (t->rev <= 1)*32;
+			amlload(t->data, l);
+		}else if(memcmp("SSDT", t->sig, 4) == 0)
+			amlload(t->data, l);
+	}
+	close(fd);
+
+	amlenum(amlroot, "_BIF", enumbat, nil);
+	amlenum(amlroot, "_PSL", enumtmp, nil);
+
+	rfork(RFNOTEG);
+	threadpostmountsrv(&fs, srv, mtpt, MREPL);
+	return;
+
+fail:
+	fprint(2, "%r\n");
+	amlexit();
+	threadexitsall("acpi");
+}
+
+static int
+readec(Amlio *, void *data, int len, int off)
+{
+	return pread(ec, data, len, off);
+}
+
+static int
+writeec(Amlio *, void *data, int len, int off)
+{
+	return pwrite(ec, data, len, off);
+}
+
+static int
+readio(Amlio *io, void *data, int len, int port)
+{
+	assert(len == 1 || len == 2 || len == 4);
+	return pread(iofd[len], data, len, io->off+port);
+}
+
+static int
+writeio(Amlio *io, void *data, int len, int port)
+{
+	assert(len == 1 || len == 2 || len == 4);
+	return pwrite(iofd[len], data, len, io->off+port);
+}
+
+static int
+memread(Amlio *io, void *data, int len, int addr)
+{
+	return pread(mem, data, len, io->off+addr);
+}
+
+static int
+memwrite(Amlio *io, void *data, int len, int addr)
+{
+	return pwrite(mem, data, len, io->off+addr);
+}
+
+static int
+dummy(Amlio *, void *, int len, int)
+{
+	return len;
+}
+
+int
+amlmapio(Amlio *io)
+{
+	switch(io->space){
+	case EbctlSpace:
+		io->read = readec;
+		io->write = writeec;
+		break;
+	case IoSpace:
+		io->read = readio;
+		io->write = writeio;
+		break;
+	case MemSpace:
+		io->read = mem >= 0 ? memread : dummy;
+		io->write = mem >= 0 ? memwrite : dummy;
+		break;
+	default:
+		io->read = dummy;
+		io->write = dummy;
+		break;
+	}
+	return 0;
+}
+
+void
+amlunmapio(Amlio *)
+{
+}
--- a/sys/src/cmd/aux/mkfile
+++ b/sys/src/cmd/aux/mkfile
@@ -5,6 +5,7 @@
 	9pcon\
 	accupoint\
 	acidleak\
+	acpi\
 	apm\
 	astarld\
 	bflz\