#include #include #include #include #include <9p.h> typedef struct Tablet Tablet; typedef struct Message Message; typedef struct QItem QItem; typedef struct Queue Queue; typedef struct Reader Reader; enum { MAX = 1000 }; struct Tablet { int ser; int xmax, ymax, pmax, version; int sx, sy; }; struct Message { Ref; int b, x, y, p; char *msg; }; Tablet* newtablet(char* dev) { int serctl; char* ctl; Tablet* t; ctl = smprint("%sctl", dev); t = calloc(sizeof(Tablet), 1); t->ser = open(dev, ORDWR); if(t->ser < 0) { free(t); return 0; } serctl = open(ctl, OWRITE); free(ctl); if(serctl < 0) { free(t); close(t->ser); return 0; } if(fprint(serctl, "b19200\n") < 0) { free(t); close(t->ser); close(serctl); return 0; } close(serctl); return t; } int query(Tablet* t) { uchar buf[11]; if(write(t->ser, "&0*", 3) < 3) return -1; do { if(read(t->ser, buf, 1) < 1) return -1; } while(buf[0] != 0xC0); if(readn(t->ser, buf+1, 10) < 10) return -1; t->xmax = (buf[1] << 9) | (buf[2] << 2) | ((buf[6] >> 5) & 3); t->ymax = (buf[3] << 9) | (buf[4] << 2) | ((buf[6] >> 3) & 3); t->pmax = buf[5] | (buf[6] & 7); t->version = (buf[9] << 7) | buf[10]; if(write(t->ser, "1", 1) < 1) return -1; return 0; } int screensize(Tablet* t) { int fd; char buf[189], buf2[12], *p; fd = open("/dev/draw/new", OREAD); if(fd < 0) return -1; read(fd, buf, 189); memcpy(buf2, buf + 72, 11); buf2[11] = 0; for(p = buf2; *p == ' '; p++); t->sx = atoi(p); memcpy(buf2, buf + 84, 11); for(p = buf2; *p == ' '; p++); t->sy = atoi(p); if(t->sx == 0 || t->sy == 0) { close(fd); werrstr("invalid resolution read from /dev/draw/new"); return -1; } close(fd); return 0; } int findheader(Tablet* t) { uchar c; do { if(read(t->ser, &c, 1) < 1) return -1; } while((c & 0x80) == 0); return c; } Message* readpacket(Tablet* t) { uchar buf[9]; int head; Message *m; head = findheader(t); if(head < 0) return 0; if(readn(t->ser, buf, 9) < 9) return 0; m = calloc(sizeof(Message), 1); incref(m); m->b = head & 7; m->x = (buf[0] << 9) | (buf[1] << 2) | ((buf[5] >> 5) & 3); m->y = (buf[2] << 9) | (buf[3] << 2) | ((buf[5] >> 3) & 3); m->p = ((buf[5] & 7) << 7) | buf[4]; m->p *= MAX; m->p /= t->pmax; m->x *= t->sx; m->x /= t->xmax; m->y *= t->sy; m->y /= t->ymax; m->msg = smprint("m %d %d %d %d\n", m->x, m->y, m->b, m->p); return m; } void msgdecref(Message *m) { if(decref(m) == 0) { free(m->msg); free(m); } } struct QItem { Message *m; QItem *next; }; struct Queue { Lock; QItem *first, *last; }; void qput(Queue* q, Message* m) { QItem *i; lock(q); i = malloc(sizeof(QItem)); i->m = m; i->next = 0; if(q->last == nil) { q->last = q->first = i; } else { q->last->next = i; q->last = i; } unlock(q); } Message* qget(Queue* q) { QItem *i; Message *m; if(q->first == nil) return nil; lock(q); i = q->first; if(q->first == q->last) { q->first = q->last = nil; } else { q->first = i->next; } m = i->m; free(i); unlock(q); return m; } void freequeue(Queue *q) { Message *m; while(m = qget(q)) msgdecref(m); free(q); } struct Reader { Queue *e; Reader *prev, *next; Req* req; }; Lock readers; Reader *rfirst, *rlast; void reply(Req *req, Message *m) { req->ofcall.count = strlen(m->msg); if(req->ofcall.count > req->ifcall.count) req->ofcall.count = req->ifcall.count; memmove(req->ofcall.data, m->msg, req->ofcall.count); respond(req, nil); } void sendout(Message *m) { Reader *r; lock(&readers); for(r = rfirst; r; r = r->next) { if(r->req) { reply(r->req, m); r->req = nil; } else { incref(m); qput(r->e, m); } } unlock(&readers); } void tabletopen(Req *req) { Reader *r; lock(&readers); r = calloc(sizeof(Reader), 1); r->e = calloc(sizeof(Queue), 1); if(rlast) rlast->next = r; r->prev = rlast; rlast = r; if(rfirst == nil) rfirst = r; unlock(&readers); req->fid->aux = r; respond(req, nil); } void tabletdestroyfid(Fid *fid) { Reader *r; r = fid->aux; if(r == nil) return; lock(&readers); if(r->prev) r->prev->next = r->next; if(r->next) r->next->prev = r->prev; if(r == rfirst) rfirst = r->next; if(r == rlast) rlast = r->prev; freequeue(r->e); free(r); unlock(&readers); } void tabletdestroyreq(Req *req) { Reader *r; if(req->fid == nil) return; r = req->fid->aux; if(r == nil) return; if(req == r->req) { r->req = nil; } } void tabletread(Req* req) { Reader *r; Message *m; r = req->fid->aux; if(m = qget(r->e)) { reply(req, m); msgdecref(m); } else { if(r->req) { respond(req, "no concurrent reads, please"); } else { r->req = req; } } } Srv tabletsrv = { .open = tabletopen, .read = tabletread, .destroyfid = tabletdestroyfid, .destroyreq = tabletdestroyreq, }; File *tfile; void main() { Tablet *t; Message *m; int fd[2]; pipe(fd); tabletsrv.infd = tabletsrv.outfd = fd[0]; tabletsrv.srvfd = fd[1]; tabletsrv.tree = alloctree(getuser(), getuser(), 0555, 0); tfile = createfile(tabletsrv.tree->root, "tablet", getuser(), 0400, 0); if(rfork(RFPROC | RFMEM | RFNOWAIT | RFNOTEG) > 0) exits(nil); if(rfork(RFPROC | RFMEM) == 0) { srv(&tabletsrv); exits(nil); } mount(fd[1], -1, "/dev", MAFTER, ""); t = newtablet("/dev/eia2"); if(!t) sysfatal("%r"); if(screensize(t) < 0) sysfatal("%r"); if(query(t) < 0) sysfatal("%r"); while(1) { m = readpacket(t); if(!m) sysfatal("%r"); sendout(m); msgdecref(m); } }