summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/wacom.c
diff options
context:
space:
mode:
authoraiju <aiju@phicode.de>2011-05-09 08:59:11 +0000
committeraiju <aiju@phicode.de>2011-05-09 08:59:11 +0000
commit908a525ef5ed769f0621df6df4184b1349920d94 (patch)
treec817f51b4cecf6133835641674ea3f9615b1e2cf /sys/src/cmd/aux/wacom.c
parented3a999828fa841c803993ed4ad8ab545b876aeb (diff)
added aux/wacom and aux/tablet
Diffstat (limited to 'sys/src/cmd/aux/wacom.c')
-rw-r--r--sys/src/cmd/aux/wacom.c352
1 files changed, 352 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/wacom.c b/sys/src/cmd/aux/wacom.c
new file mode 100644
index 000000000..5b076873c
--- /dev/null
+++ b/sys/src/cmd/aux/wacom.c
@@ -0,0 +1,352 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#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);
+ }
+} \ No newline at end of file