123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "../port/error.h"
- enum{
- Qdir,
- Qbacklight,
- Qbattery,
- Qbuttons,
- Qcruft,
- Qkbdin,
- Qled,
- Qversion,
- Qpower,
- /* command types */
- BLversion= 0,
- BLbuttons= 2, /* button events */
- BLtouch= 3, /* read touch screen events */
- BLled= 8, /* turn LED on/off */
- BLbattery= 9, /* read battery status */
- BLbacklight= 0xd, /* backlight control */
- SOF= 0x2, /* start of frame */
- };
- /* from /sys/include/keyboard.h */
- enum {
- KF= 0xF000, /* Rune: beginning of private Unicode space */
- /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */
- Khome= KF|0x0D,
- Kup= KF|0x0E,
- Kpgup= KF|0x0F,
- Kprint= KF|0x10,
- Kleft= KF|0x11,
- Kright= KF|0x12,
- Kdown= 0x80,
- Kview= 0x80,
- Kpgdown= KF|0x13,
- Kins= KF|0x14,
- Kend= '\r', /* [sic] */
- Kalt= KF|0x15,
- Kshift= KF|0x16,
- Kctl= KF|0x17,
- };
- Dirtab µcdir[]={
- ".", { Qdir, 0, QTDIR }, 0, DMDIR|0755,
- "backlight", { Qbacklight, 0 }, 0, 0664,
- "battery", { Qbattery, 0 }, 0, 0664,
- "buttons", { Qbuttons, 0 }, 0, 0664,
- "cruft", { Qcruft, 0 }, 0, 0664,
- "kbdin", { Qkbdin, 0 }, 0, 0664,
- "led", { Qled, 0 }, 0, 0664,
- "version", { Qversion, 0 }, 0, 0664,
- "power", { Qpower, 0 }, 0, 0600,
- };
- static struct µcontroller
- {
- /* message being rcvd */
- int state;
- uchar buf[16+4];
- uchar n;
- /* for messages that require acks */
- QLock;
- Rendez r;
- /* battery */
- uchar acstatus;
- uchar voltage;
- ushort batstatus;
- uchar batchem;
- /* version string */
- char version[16+2];
- } ctlr;
- /* button map */
- Rune bmap[2][4] =
- {
- {Kup, Kright, Kleft, Kdown}, /* portrait mode */
- {Kright, Kdown, Kup, Kleft}, /* landscape mode */
- };
- extern int landscape;
- int
- µcputc(Queue*, int ch)
- {
- int i, len, b, up;
- uchar cksum;
- uchar *p;
- static int samseq;
- static int touching; /* guard against something we call going spllo() */
- static int buttoning; /* guard against something we call going spllo() */
- if(ctlr.n > sizeof(ctlr.buf))
- panic("µcputc");
- ctlr.buf[ctlr.n++] = (uchar)ch;
- for(;;){
- /* message hasn't started yet? */
- if(ctlr.buf[0] != SOF){
- p = memchr(ctlr.buf, SOF, ctlr.n);
- if(p == nil){
- ctlr.n = 0;
- break;
- } else {
- ctlr.n -= p-ctlr.buf;
- memmove(ctlr.buf, p, ctlr.n);
- }
- }
-
- /* whole msg? */
- len = ctlr.buf[1] & 0xf;
- if(ctlr.n < 3 || ctlr.n < len+3)
- break;
-
- /* check the sum */
- ctlr.buf[0] = ~SOF; /* make sure we process this msg exactly once */
- cksum = 0;
- for(i = 1; i < len+2; i++)
- cksum += ctlr.buf[i];
- if(ctlr.buf[len+2] != cksum)
- continue;
-
- /* parse resulting message */
- p = ctlr.buf+2;
- switch(ctlr.buf[1] >> 4){
- case BLversion:
- strncpy(ctlr.version, (char*)p, len);
- ctlr.version[len] = '0';
- strcat(ctlr.version, "\n");
- wakeup(&ctlr.r);
- break;
- case BLbuttons:
- if(len < 1 || buttoning)
- break;
- buttoning = 1;
- b = p[0] & 0x7f;
- up = p[0] & 0x80;
- if(b > 5) {
- /* rocker panel acts like arrow keys */
- if(b < 10 && !up)
- kbdputc(kbdq, bmap[landscape][b-6]);
- } else {
- /* the rest like mouse buttons */
- if(--b == 0)
- b = 5;
- penbutton(up, 1<<b);
- }
- buttoning = 0;
- break;
- case BLtouch:
- if(touching)
- break;
- touching = 1;
- if(len == 4) {
- if (samseq++ > 10){
- if (landscape)
- pentrackxy((p[0]<<8)|p[1], (p[2]<<8)|p[3]);
- else
- pentrackxy((p[2]<<8)|p[3], (p[0]<<8)|p[1]);
- }
- } else {
- samseq = 0;
- pentrackxy(-1, -1);
- }
- touching = 0;
- break;
- case BLled:
- wakeup(&ctlr.r);
- break;
- case BLbattery:
- if(len >= 5){
- ctlr.acstatus = p[0];
- ctlr.voltage = (p[3]<<8)|p[2];
- ctlr.batstatus = p[4];
- ctlr.batchem = p[1];
- }
- wakeup(&ctlr.r);
- break;
- case BLbacklight:
- wakeup(&ctlr.r);
- break;
- default:
- print("unknown µc message: %ux", ctlr.buf[1] >> 4);
- for(i = 0; i < len; i++)
- print(" %ux", p[i]);
- print("\n");
- break;
- }
-
- /* remove the message */
- ctlr.n -= len+3;
- memmove(ctlr.buf, &ctlr.buf[len+3], ctlr.n);
- }
- return 0;
- }
- static void
- _sendmsg(uchar id, uchar *data, int len)
- {
- uchar buf[20];
- uchar cksum;
- uchar c;
- uchar *p = buf;
- int i;
- /* create the message */
- if(sizeof(buf) < len+4)
- return;
- cksum = (id<<4) | len;
- *p++ = SOF;
- *p++ = cksum;
- for(i = 0; i < len; i++){
- c = data[i];
- cksum += c;
- *p++ = c;
- }
- *p++ = cksum;
- /* send the message - there should be a more generic way to do this */
- serialµcputs(buf, p-buf);
- }
- /* the tsleep takes care of lost acks */
- static void
- sendmsgwithack(uchar id, uchar *data, int len)
- {
- if(waserror()){
- qunlock(&ctlr);
- nexterror();
- }
- qlock(&ctlr);
- _sendmsg(id, data, len);
- tsleep(&ctlr.r, return0, 0, 100);
- qunlock(&ctlr);
- poperror();
- }
- static void
- sendmsg(uchar id, uchar *data, int len)
- {
- if(waserror()){
- qunlock(&ctlr);
- nexterror();
- }
- qlock(&ctlr);
- _sendmsg(id, data, len);
- qunlock(&ctlr);
- poperror();
- }
- void
- µcinit(void)
- {
- }
- static Chan*
- µcattach(char* spec)
- {
- return devattach('r', spec);
- }
- static Walkqid*
- µcwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, µcdir, nelem(µcdir), devgen);
- }
- static int
- µcstat(Chan *c, uchar *dp, int n)
- {
- return devstat(c, dp, n, µcdir, nelem(µcdir), devgen);
- }
- static Chan*
- µcopen(Chan* c, int omode)
- {
- omode = openmode(omode);
- if(!iseve())
- error(Eperm);
- return devopen(c, omode, µcdir, nelem(µcdir), devgen);
- }
- static void
- µcclose(Chan*)
- {
- }
- char*
- acstatus(int x)
- {
- if(x)
- return "attached";
- else
- return "detached";
- }
- char*
- batstatus(int x)
- {
- switch(x){
- case 1: return "high";
- case 2: return "low";
- case 4: return "critical";
- case 8: return "charging";
- case 0x80: return "none";
- }
- return "ok";
- }
- static long
- µcread(Chan* c, void* a, long n, vlong off)
- {
- char buf[64];
- if(c->qid.path == Qdir)
- return devdirread(c, a, n, µcdir, nelem(µcdir), devgen);
- switch((ulong)c->qid.path){
- case Qbattery:
- sendmsgwithack(BLbattery, nil, 0); /* send a battery request */
- sprint(buf, "voltage: %d\nac: %s\nstatus: %s\n", ctlr.voltage,
- acstatus(ctlr.acstatus),
- batstatus(ctlr.batstatus));
- return readstr(off, a, n, buf);
- case Qversion:
- sendmsgwithack(BLversion, nil, 0); /* send a battery request */
- return readstr(off, a, n, ctlr.version);
- }
- error(Ebadarg);
- return 0;
- }
- #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
- static uchar lightdata[16];
- static long
- µcwrite(Chan* c, void* a, long n, vlong)
- {
- Cmdbuf *cmd;
- uchar data[16];
- char str[64];
- int i, j;
- ulong l;
- Rune r;
- extern ulong resumeaddr[];
- extern void power_resume(void);
- if(c->qid.path == Qkbdin){
- if(n >= sizeof(str))
- n = sizeof(str)-1;
- memmove(str, a, n);
- str[n] = 0;
- for(i = 0; i < n; i += j){
- j = chartorune(&r, &str[i]);
- kbdcr2nl(nil, r);
- }
- return n;
- }
- if(c->qid.path == Qpower){
- if(!iseve())
- error(Eperm);
- if(strncmp(a, "suspend", 7) == 0)
- *resumeaddr = (ulong)power_resume;
- else if(strncmp(a, "halt", 4) == 0)
- *resumeaddr = 0;
- else if(strncmp(a, "wakeup", 6) == 0){
- cmd = parsecmd(a, n);
- if (cmd->nf != 2)
- error(Ebadarg);
- l = strtoul(cmd->f[1], 0, 0);
- rtcalarm(l);
- return n;
- } else
- error(Ebadarg);
- deepsleep();
- return n;
- }
- cmd = parsecmd(a, n);
- if(cmd->nf > 15)
- error(Ebadarg);
- for(i = 0; i < cmd->nf; i++)
- data[i] = atoi(cmd->f[i]);
- switch((ulong)c->qid.path){
- case Qled:
- sendmsgwithack(BLled, data, cmd->nf);
- break;
- case Qbacklight:
- memmove(lightdata, data, 16);
- sendmsgwithack(BLbacklight, data, cmd->nf);
- break;
- case Qcruft:
- // lcdtweak(cmd);
- break;
- default:
- error(Ebadarg);
- }
- return n;
- }
- void
- µcpower(int on)
- {
- uchar data[16];
- if (on == 0)
- return;
- /* maybe dangerous, not holding the lock */
- if (lightdata[0] == 0){
- data[0]= 2;
- data[1]= 1;
- data[2]= 0;
- } else
- memmove(data, lightdata, 16);
- _sendmsg(0xd, data, 3);
- wakeup(&ctlr.r);
- }
- Dev µcdevtab = {
- 'r',
- "µc",
- devreset,
- µcinit,
- devshutdown,
- µcattach,
- µcwalk,
- µcstat,
- µcopen,
- devcreate,
- µcclose,
- µcread,
- devbread,
- µcwrite,
- devbwrite,
- devremove,
- devwstat,
- };
|