diff options
author | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2022-10-08 01:20:32 +0000 |
---|---|---|
committer | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2022-10-08 01:20:32 +0000 |
commit | 4f6e074f979e185f093f44b20a1021714c479b3b (patch) | |
tree | 8b39a290f7ee39f8cf3ca6f251727455e44b9ad2 | |
parent | 9d20339e479551841d6d917669bf67b83893b126 (diff) |
reform/pm: provide /dev/kbdoled to display a 126x32x1 bitmap on the keyboard OLED
-rw-r--r-- | sys/man/1/reform | 4 | ||||
-rw-r--r-- | sys/src/cmd/reform/pm.c | 87 |
2 files changed, 74 insertions, 17 deletions
diff --git a/sys/man/1/reform b/sys/man/1/reform index 93fad367f..c2bc1fa0c 100644 --- a/sys/man/1/reform +++ b/sys/man/1/reform @@ -109,6 +109,10 @@ Returns attached battery array statistics in the same manner as .B cputemp Exposes the current temperature reading of the CPU. .TP +.B kbdoled +An image can be displayed on the keyboard OLED by writing a 126x32x1 +uncompressed Plan 9 image (with or without a header). +.TP .B light Provides a way to control the backlight of the built-in LCD by writing \fIlcd [-+]N\fR or \fIkbd [-+]N\fR, diff --git a/sys/src/cmd/reform/pm.c b/sys/src/cmd/reform/pm.c index 0561d0f0e..1c15daaf6 100644 --- a/sys/src/cmd/reform/pm.c +++ b/sys/src/cmd/reform/pm.c @@ -3,6 +3,8 @@ #include <fcall.h> #include <thread.h> #include <9p.h> +#include <draw.h> +#include <memdraw.h> enum { @@ -23,8 +25,12 @@ enum Light = 1, Temp, Battery, + Kbdoled, Pmctl, + KbdoledW = 126, + KbdoledH = 32, + Lcd = 0, Kbd, @@ -72,11 +78,13 @@ enum STAT_RR = 1<<3, }; +static char *uid = "pm"; static Reqqueue *lpcreq; static u32int *pwm2, *tmu, *spi2; static int kbdlight = 0; static int kbdhidfd = -1; -static char *uid = "pm"; +static Memimage *kbdoled; +static u8int kbdoledraw[4+KbdoledW*KbdoledH/8] = {'W', 'B', 'I', 'T', 0}; static void wr(u32int *base, int reg, u32int v) @@ -125,23 +133,54 @@ openkbdhid(void) char path[32], *s, *k, *e; int f; - if(kbdhidfd >= 0) - return kbdhidfd; - - if((f = open("/dev/usb/ctl", OREAD)) >= 0){ + if(kbdhidfd < 0 && (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); + if((kbdhidfd = open(path, OWRITE)) >= 0 && write(kbdhidfd, "rawon", 5) != 5){ + close(kbdhidfd); + kbdhidfd = -1; + } } free(s); close(f); } - return kbdhidfd; + return kbdhidfd < 0; +} + +static int +loadkbdoled(void *data, int size) +{ + int x, y, i, k, v, bpl; + u8int *p, q; + + bpl = bytesperline(kbdoled->r, kbdoled->depth); + if(size == 60+bpl*KbdoledH){ + data = (u8int*)data + 60; + size -= 60; + }else if(size != bpl*KbdoledH){ + werrstr("invalid image: expected %dx%d GREY1 (%d bytes)", KbdoledW, KbdoledH, bpl*KbdoledH); + return -1; + } + + k = loadmemimage(kbdoled, kbdoled->r, data, size); + if(k < 0 || openkbdhid() != 0) + return -1; + for(y = 0, i = 4; y < KbdoledH; y += 8){ + for(x = v = 0; x < KbdoledW; x++, v = (v+1)&7){ + SET(p); + if(v == 0) + p = byteaddr(kbdoled, Pt(x,y)); + for(k = q = 0; k < 8; k++) + q |= ((p[bpl*k] >> (7-v)) & 1) << k; + kbdoledraw[i++] = q; + } + } + + return write(kbdhidfd, kbdoledraw, sizeof(kbdoledraw)); } static int @@ -158,7 +197,7 @@ setlight(int k, int p) v = Pwmsrcclk / rd(pwm2, PWMSAR); wr(pwm2, PWMPR, (Pwmsrcclk/(v*p/100))-2); return 0; - }else if(k == Kbd && (kbdhidfd = openkbdhid()) >= 0){ + }else if(k == Kbd && openkbdhid() == 0){ v = Kbdlightmax*p/100; if(fprint(kbdhidfd, "LITE%c", '0'+v) > 0){ kbdlight = v; @@ -420,10 +459,21 @@ fswrite(Req *r) int nf, v, p, k; void *aux; - 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*)Kbdoled){ + if(loadkbdoled(r->ifcall.data, r->ifcall.count) < 0){ +Err: + responderror(r); + return; + } + r->ofcall.count = r->ifcall.count; + respond(r, nil); + return; + } + + snprint(msg, sizeof(msg), "%.*s", utfnlen(r->ifcall.data, r->ifcall.count), r->ifcall.data); + nf = tokenize(msg, f, nelem(f)); if(aux == (void*)Light){ if(nf < 2){ Bad: @@ -439,10 +489,8 @@ Bad: v = atoi(f[1]); if(*f[1] == '+' || *f[1] == '-') v += getlight(k); - if(setlight(k, v) != 0){ - responderror(r); - return; - } + if(setlight(k, v) != 0) + goto Err; }else if(aux == (void*)Pmctl){ p = -1; if(nf >= 2 && strcmp(f[0], "power") == 0){ @@ -451,7 +499,7 @@ Bad: * LPC firmware might not be up to date so try * shutting down through the keyboard first */ - if((kbdhidfd = openkbdhid()) >= 0){ + if(openkbdhid() == 0){ write(kbdhidfd, "PWR0", 4); sleep(2000); /* give it a chance */ } @@ -520,11 +568,16 @@ threadmain(int argc, char **argv) if((spi2 = segattach(0, "ecspi2", 0, 0x20)) == (void*)-1) sysfatal("no spi2"); tmuinit(); + if(memimageinit() != 0) + sysfatal("%r"); + if((kbdoled = allocmemimage(Rect(0, 0, KbdoledW, KbdoledH), GREY1)) == nil) + sysfatal("%r"); lpcreq = reqqueuecreate(); 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, "kbdoled", uid, 0222, (void*)Kbdoled); createfile(fs.tree->root, "pmctl", uid, 0666, (void*)Pmctl); threadpostmountsrv(&fs, srv, mtpt, MAFTER); |