ref: e1949eedf6893c76472360189b6539bc0d573378
parent: a945c6f5b1f69b9bf7a6a3a5404b14b9fe6c5e5c
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Thu Oct 6 19:21:16 EDT 2022
reform/pm: add keyboard light level controlling to /dev/light
--- a/sys/man/1/reform
+++ b/sys/man/1/reform
@@ -111,7 +111,7 @@
.TP
.B light
Provides a way to control the backlight of the built-in LCD by
-writing \fIlcd [-+]N\fR,
+writing \fIlcd [-+]N\fR or \fIkbd [-+]N\fR,
where
.I N
is expressed in percentage, either as an absolute value (0-100) or
@@ -174,8 +174,9 @@
.B Light
was chosen as a shorter alternative to
.BR brightness .
-In the future it might support controlling keyboard and trackball
-light levels.
+.PP
+Current keyboard light level reading is only an indication, there is
+no way to get the actual value from the keyboard.
.PP
Values displayed in the
.B battery
--- a/sys/src/cmd/reform/pm.c
+++ b/sys/src/cmd/reform/pm.c
@@ -8,6 +8,7 @@
{
Mhz = 1000*1000,
Pwmsrcclk = 25*Mhz,
+ Kbdlightmax = 8,
Scharge = 0,
Sovervolted,
@@ -24,6 +25,9 @@
Battery,
Pmctl,
+ Lcd = 0,
+ Kbd,
+
PWMSAR = 0x0c/4,
PWMPR = 0x10/4,
@@ -70,6 +74,8 @@
static Reqqueue *lpcreq;
static u32int *pwm2, *tmu, *spi2;
+static int kbdlight = 0;
+static int kbdhidfd = -1;
static char *uid = "pm";
static void
@@ -86,9 +92,61 @@
return base != nil ? base[reg] : -1;
}
-static void
-setlight(int p)
+static char *
+readall(int f)
{
+ int bufsz, sz, n;
+ char *s;
+
+ bufsz = 2047;
+ s = nil;
+ for(sz = 0;; sz += n){
+ if(bufsz-sz < 2048){
+ bufsz *= 2;
+ s = realloc(s, bufsz);
+ }
+ if((n = readn(f, s+sz, bufsz-sz-1)) < 1)
+ break;
+ }
+ if(n < 0 || sz < 1){
+ if(n == 0)
+ werrstr("empty");
+ free(s);
+ return nil;
+ }
+ s[sz] = 0;
+
+ return s;
+}
+
+static int
+openkbdhid(void)
+{
+ char path[32], *s, *k, *e;
+ int f;
+
+ if(kbdhidfd >= 0)
+ return kbdhidfd;
+
+ if((f = open("/dev/usb/ctl", OREAD)) >= 0){
+ if((s = readall(f)) != nil &&
+ (k = strstr(s, "MNT 'Reform Keyboard'")) != nil &&
+ (e = strchr(k+22, ' ')) != nil){
+ *e = 0;
+ snprint(path, sizeof(path), "/dev/hidU%sctl", k+22);
+ if((kbdhidfd = open(path, OWRITE)) >= 0)
+ write(kbdhidfd, "rawon", 5);
+ }
+ free(s);
+ close(f);
+ }
+
+ return kbdhidfd;
+}
+
+static int
+setlight(int k, int p)
+{
u32int v;
if(p < 0)
@@ -96,17 +154,37 @@
if(p > 100)
p = 100;
- v = Pwmsrcclk / rd(pwm2, PWMSAR);
- wr(pwm2, PWMPR, (Pwmsrcclk/(v*p/100))-2);
+ if(k == Lcd){
+ v = Pwmsrcclk / rd(pwm2, PWMSAR);
+ wr(pwm2, PWMPR, (Pwmsrcclk/(v*p/100))-2);
+ return 0;
+ }else if(k == Kbd && (kbdhidfd = openkbdhid()) >= 0){
+ v = Kbdlightmax*p/100;
+ if(fprint(kbdhidfd, "LITE%c", '0'+v) > 0){
+ kbdlight = v;
+ return 0;
+ }
+ close(kbdhidfd);
+ kbdhidfd = -1;
+ kbdlight = 0;
+ }
+
+ return -1;
}
static int
-getlight(void)
+getlight(int k)
{
u32int m, v;
- m = Pwmsrcclk / rd(pwm2, PWMSAR);
- v = Pwmsrcclk / (rd(pwm2, PWMPR)+2);
+ SET(m, v);
+ if(k == Lcd){
+ m = Pwmsrcclk / rd(pwm2, PWMSAR);
+ v = Pwmsrcclk / (rd(pwm2, PWMPR)+2);
+ }else if(k == Kbd){
+ m = Kbdlightmax;
+ v = kbdlight;
+ }
return v*100/m;
}
@@ -194,17 +272,17 @@
wr(spi2, SPIx_TXDATA, cmd);
wr(spi2, SPIx_TXDATA, arg);
wr(spi2, SPIx_CONREG, con | CON_XCH);
- sleep(60);
- /* LPC buffers 3 bytes without responding, ignore (including garbage) */
+ /*
+ * LPC buffers 3 bytes without responding, but spends some time
+ * to prepare the response. 50ms should be safe, add a bit more
+ * to be sure LPC is blocked waiting for the chip select to go
+ * active again.
+ */
+ sleep(60);
while(rd(spi2, SPIx_STATREG) & STAT_RR)
rd(spi2, SPIx_RXDATA);
- /*
- * at this point LPC hopefully is blocked waiting for
- * chip select to go active
- */
-
/* expecting 8 bytes, start the exchange */
for(i = 0; i < 8; i++)
wr(spi2, SPIx_TXDATA, 0);
@@ -315,7 +393,7 @@
if(r->ifcall.offset == 0){
aux = r->fid->file->aux;
if(aux == (void*)Light){
- snprint(msg, sizeof(msg), "lcd %d\n", getlight());
+ snprint(msg, sizeof(msg), "lcd %d\nkbd %d\n", getlight(Lcd), getlight(Kbd));
}else if(aux == (void*)Temp){
if((c = getcputemp()) < 0){
responderror(r);
@@ -339,7 +417,7 @@
fswrite(Req *r)
{
char msg[256], *f[4];
- int nf, v, p;
+ int nf, v, p, k;
void *aux;
snprint(msg, sizeof(msg), "%.*s",
@@ -352,16 +430,25 @@
respond(r, "invalid ctl message");
return;
}
- if(strcmp(f[0], "lcd") == 0){
- v = atoi(f[1]);
- if(*f[1] == '+' || *f[1] == '-')
- v += getlight();
- setlight(v);
+ if(strcmp(f[0], "lcd") == 0)
+ k = Lcd;
+ else if(strcmp(f[0], "kbd") == 0)
+ k = Kbd;
+ else
+ goto Bad;
+ v = atoi(f[1]);
+ if(*f[1] == '+' || *f[1] == '-')
+ v += getlight(k);
+ if(setlight(k, v) != 0){
+ responderror(r);
+ return;
}
}else if(aux == (void*)Pmctl){
p = -1;
- if(nf == 2 && strcmp(f[0], "power") == 0 && strcmp(f[1], "off") == 0)
- p = Psomoff;
+ if(nf >= 2 && strcmp(f[0], "power") == 0){
+ if(nf == 2 && strcmp(f[1], "off") == 0)
+ p = Psomoff;
+ }
if(p < 0)
goto Bad;
lpccall('p', p, msg);
@@ -427,7 +514,7 @@
tmuinit();
lpcreq = reqqueuecreate();
fs.tree = alloctree(uid, uid, DMDIR|0555, nil);
- createfile(fs.tree->root, "battery", uid, 0444,(void*)Battery);
+ 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);