code: plan9front

Download patch

ref: 79293e820d4bf25efd685fb43be78d52b7a093b1
parent: ff1f02c31615450c31163df752fcab74567ad322
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Sep 7 15:45:20 EDT 2022

reform: add pmctl to read more info and to turn power rails off; manpages

--- a/sys/man/1/reform
+++ b/sys/man/1/reform
@@ -102,6 +102,13 @@
 .I pm
 presents a file system consisting of the following files:
 .TP
+.B battery
+Returns attached battery array statistics in the same manner as
+\fIacpi\fR(8).
+.TP
+.B cputemp
+Exposes the current temperature reading of the CPU.
+.TP
 .B light
 Provides a way to control the backlight of the built-in LCD by
 writing \fIlcd [-+]N\fR,
@@ -113,11 +120,22 @@
 .B light
 returns the current brightness.
 .TP
-.B cputemp
-Exposes the current temperature reading of the CPU.
+.B pmctl
+Reading
+.B pmctl
+gives the System Controller firmware version string, voltage (mV) of
+each cell and current(mA) of the battery array.
+.IP
+Writing
+.I power off
+to
+.B pmctl
+will turn off all power rails, which is what \fIfshalt\fR(8) does
+after halting the file systems.
 .SS Shortcuts
 .I shortcuts
-enables LCD brightness and audio volume adjustment via keyboard shortcuts.
+enables LCD brightness and audio volume adjustment via keyboard
+shortcuts.
 .PP
 The program uses Rio's
 .I kbdtap
--- a/sys/src/cmd/reform/pm.c
+++ b/sys/src/cmd/reform/pm.c
@@ -17,9 +17,12 @@
 	Sfullycharged,
 	Spowersave,
 
+	Psomoff = 1,
+
 	Light = 1,
 	Temp,
 	Battery,
+	Pmctl,
 
 	PWMSAR = 0x0c/4,
 	PWMPR = 0x10/4,
@@ -65,14 +68,11 @@
 		CONFIG_SS_CTL_NCSS = 1<<8,
 		CONFIG_SCLK_POL_HIGH = 0<<4,
 		CONFIG_SCLK_PHA_1 = 1<<0,
-	SPIx_INTREG = 0x10/4,
 	SPIx_STATREG = 0x18/4,
-		STAT_TC = 1<<7,
 		STAT_RR = 1<<3,
-		STAT_TE = 1<<0,
-	SPIx_PERIODREG = 0x1c/4,
 };
 
+static char lpcfw[9*3+1];
 static u32int *pwm2, *tmu, *spi2;
 static char *uid = "pm";
 
@@ -115,7 +115,7 @@
 }
 
 static int
-getcputemp(int c[3])
+gettemp(int c[3])
 {
 	int i, r[] = {TMUTRITSR0, TMUTRITSR1, TMUTRITSR2};
 	u32int s;
@@ -240,12 +240,24 @@
 	wr(spi2, SPIx_CONREG, con & ~CON_EN);
 }
 
-static int
-readbattery(char *buf, int sz)
+static void
+lpcinit(void)
 {
+	char s[3][8];
+
+	lpccall(0, 0, s[0]); /* a dummy one to make sure there is no garbage */
+	lpccall('f', 0, s[0]);
+	lpccall('f', 1, s[1]);
+	lpccall('f', 2, s[2]);
+	snprint(lpcfw, sizeof(lpcfw), "%.*s %.*s %.*s", 8, s[0], 8, s[1], 8, s[2]);
+}
+
+static char *
+readbattery(char *s, char *e)
+{
 	u8int st[8], ch[8];
-	char *state;
 	s16int current;
+	char *state;
 
 	lpccall('c', 0, ch);
 	lpccall('q', 0, st);
@@ -261,7 +273,7 @@
 		switch(st[5]){
 		case Sfullycharged: state = "full"; break;
 		case Smissing: state = "missing"; break;
-		case Sovervolted: state = "overvolted"; break;
+		case Sovervolted: state = "balancing"; break;
 		case Scooldown: state = "cooldown"; break;
 		case Spowersave: state = "powersave"; break;
 		}
@@ -268,38 +280,72 @@
 	}
 
 	if(st[5] != Smissing){
-		snprint(buf, sz, "%d mA %d %d %d ? %d mV %d ? ??:??:?? %s\n",
+		return seprint(s, e, "%d mA %d %d %d ? %d mV %d ? ??:??:?? %s\n",
 			st[4],
 			ch[0]|ch[1]<<8, ch[4]|ch[5]<<8, ch[4]|ch[5]<<8, ch[2]|ch[3]<<8,
 			st[0]|st[1]<<8,
 			state
 		);
-		return 0;
 	}
 
-	return -1;
+	werrstr("battery is missing");
+	return nil;
 }
 
+static char *
+readcells(char *s, char *e)
+{
+	u8int v[16];
+	int i;
+
+	lpccall('v', 0, v+0);
+	lpccall('v', 1, v+8);
+	s = seprint(s, e, "cells(mV)");
+	for(i = 0; i < 16; i += 2)
+		s = seprint(s, e, " %d", v[i] | v[i+1]<<8);
+	return seprint(s, e, "\n");
+}
+
+static char *
+readcurrent(char *s, char *e)
+{
+	u8int q[8];
+
+	lpccall('q', 0, q);
+	return seprint(s, e, "current(mA) %d\n", (s16int)(q[2] | q[3]<<8));
+}
+
 static void
 fsread(Req *r)
 {
-	char msg[256];
+	char msg[256], *s, *e;
+	void *aux;
 	int c[3];
 
 	msg[0] = 0;
 	if(r->ifcall.offset == 0){
-		if(r->fid->file->aux == (void*)Light)
+		aux = r->fid->file->aux;
+		s = msg;
+		e = s+sizeof(msg);
+		if(aux == (void*)Light){
 			snprint(msg, sizeof(msg), "lcd %d\n", getlight());
-		else if(r->fid->file->aux == (void*)Temp){
-			if(getcputemp(c) == 0)
-				snprint(msg, sizeof(msg), "%d.0\n", c[0]);
-			else
-				snprint(msg, sizeof(msg), "%r\n");
-		}else if(r->fid->file->aux == (void*)Battery){
-			if(readbattery(msg, sizeof(msg)) != 0){
-				respond(r, "missing");
+		}else if(aux == (void*)Temp){
+			if(gettemp(c) != 0){
+				responderror(r);
 				return;
 			}
+			/* only the first one is CPU temperature */
+			snprint(msg, sizeof(msg), "%d.0\n", c[0]);
+		}else if(aux == (void*)Battery){
+			if(readbattery(s, e) == nil){
+				responderror(r);
+				return;
+			}
+		}else if(aux == (void*)Pmctl){
+			s = seprint(s, e, "version %s\n", lpcfw);
+			s = readcells(s, e);
+			s = readcurrent(s, e);
+			USED(s);
 		}
 	}
 
@@ -311,13 +357,16 @@
 fswrite(Req *r)
 {
 	char msg[256], *f[4];
-	int nf, v;
+	int nf, v, p;
+	void *aux;
 
-	if(r->fid->file->aux == (void*)Light){
-		snprint(msg, sizeof(msg), "%.*s",
-			utfnlen((char*)r->ifcall.data, r->ifcall.count), (char*)r->ifcall.data);
-		nf = tokenize(msg, f, nelem(f));
+	snprint(msg, sizeof(msg), "%.*s",
+		utfnlen((char*)r->ifcall.data, r->ifcall.count), (char*)r->ifcall.data);
+	nf = tokenize(msg, f, nelem(f));
+	aux = r->fid->file->aux;
+	if(aux == (void*)Light){
 		if(nf < 2){
+Bad:
 			respond(r, "invalid ctl message");
 			return;
 		}
@@ -327,6 +376,13 @@
 				v += getlight();
 			setlight(v);
 		}
+	}else if(aux == (void*)Pmctl){
+		p = -1;
+		if(nf == 2 && strcmp(f[0], "power") == 0 && strcmp(f[1], "off") == 0)
+			p = Psomoff;
+		if(p < 0)
+			goto Bad;
+		lpccall('p', p, msg);
 	}
 
 	r->ofcall.count = r->ifcall.count;
@@ -341,7 +397,7 @@
 static void
 usage(void)
 {
-	fprint(2, "usage: %s [-D] [-m /dev] [-s service]\n", argv0);
+	fprint(2, "usage: %s [-D] [-m mountpoint] [-s service]\n", argv0);
 	exits("usage");
 }
 
@@ -373,10 +429,12 @@
 	if((spi2 = segattach(0, "ecspi2", 0, 0x20)) == (void*)-1)
 		sysfatal("no spi2");
 	tmuinit();
+	lpcinit();
 	fs.tree = alloctree(uid, uid, DMDIR|0555, nil);
 	createfile(fs.tree->root, "battery", uid, 0444,(void*)Battery);
 	createfile(fs.tree->root, "cputemp", uid, 0444, (void*)Temp);
 	createfile(fs.tree->root, "light", uid, 0666, (void*)Light);
+	createfile(fs.tree->root, "pmctl", uid, 0666, (void*)Pmctl);
 	postmountsrv(&fs, srv, mtpt, MAFTER);
 
 	exits(nil);