From 26a8accad26267678c240e48a8544a208d9ba571 Mon Sep 17 00:00:00 2001 From: aiju Date: Sun, 9 Mar 2014 18:03:07 +0100 Subject: nusb: added joy --- sys/src/cmd/nusb/joy/hid.h | 77 ++++++++ sys/src/cmd/nusb/joy/joy.c | 436 ++++++++++++++++++++++++++++++++++++++++++++ sys/src/cmd/nusb/joy/mkfile | 20 ++ sys/src/cmd/nusb/mkfile | 1 + 4 files changed, 534 insertions(+) create mode 100644 sys/src/cmd/nusb/joy/hid.h create mode 100644 sys/src/cmd/nusb/joy/joy.c create mode 100644 sys/src/cmd/nusb/joy/mkfile diff --git a/sys/src/cmd/nusb/joy/hid.h b/sys/src/cmd/nusb/joy/hid.h new file mode 100644 index 000000000..7f849ad9d --- /dev/null +++ b/sys/src/cmd/nusb/joy/hid.h @@ -0,0 +1,77 @@ +/* + * USB joystick constants + */ +enum { + + Stack = 32 * 1024, + + /* HID class subclass protocol ids */ + JoyCSP = 0x000003, + + Maxaxes = 3, + + /* Requests */ + Getreport = 0x01, + Setreport = 0x09, + Getproto = 0x03, + Setproto = 0x0b, + + /* protocols for SET_PROTO request */ + Bootproto = 0, + Reportproto = 1, + + /* protocols for SET_REPORT request */ + Reportout = 0x0200, +}; + +/* + * USB HID report descriptor item tags + */ +enum { + /* main items */ + Input = 8, + Output, + Collection, + Feature, + + CollectionEnd, + + /* global items */ + UsagPg = 0, + LogiMin, + LogiMax, + PhysMin, + PhysMax, + UnitExp, + UnitTyp, + RepSize, + RepId, + RepCnt, + + Push, + Pop, + + /* local items */ + Usage = 0, + UsagMin, + UsagMax, + DesgIdx, + DesgMin, + DesgMax, + StrgIdx, + StrgMin, + StrgMax, + + Delim, +}; + +/* main item flags */ +enum { + Fdata = 0<<0, Fconst = 1<<0, + Farray = 0<<1, Fvar = 1<<1, + Fabs = 0<<2, Frel = 1<<2, + Fnowrap = 0<<3, Fwrap = 1<<3, + Flinear = 0<<4, Fnonlin = 1<<4, + Fpref = 0<<5, Fnopref = 1<<5, + Fnonull = 0<<6, Fnullst = 1<<6, +}; diff --git a/sys/src/cmd/nusb/joy/joy.c b/sys/src/cmd/nusb/joy/joy.c new file mode 100644 index 000000000..d63199b62 --- /dev/null +++ b/sys/src/cmd/nusb/joy/joy.c @@ -0,0 +1,436 @@ +/* + * USB Human Interaction Device: keyboard and mouse. + * + * If there's no usb keyboard, it tries to setup the mouse, if any. + * It should be started at boot time. + * + * Mouse events are converted to the format of mouse(3) + * on mousein file. + * Keyboard keycodes are translated to scan codes and sent to kbdfs(8) + * on kbin file.bv + * + */ + +#include +#include +#include +#include "usb.h" +#include "hid.h" + +typedef struct KDev KDev; +struct KDev +{ + Dev* dev; /* usb device*/ + Dev* ep; /* endpoint to get events */ + + /* report descriptor */ + int nrep; + uchar rep[512]; +}; + +static void +kbfree(KDev *kd) +{ + if(kd->ep != nil) + closedev(kd->ep); + if(kd->dev != nil) + closedev(kd->dev); + free(kd); +} + +static void +kbfatal(KDev *kd, char *sts) +{ + if(sts != nil) + fprint(2, "%s: fatal: %s\n", argv0, sts); + else + fprint(2, "%s: exiting\n", argv0); + kbfree(kd); + threadexits(sts); +} + +static int debug, kbd; + +static int +signext(int v, int bits) +{ + int s; + + s = sizeof(v)*8 - bits; + v <<= s; + v >>= s; + return v; +} + +static int +getbits(uchar *p, uchar *e, int bits, int off) +{ + int v, m; + + p += off/8; + off %= 8; + v = 0; + m = 1; + if(p < e){ + while(bits--){ + if(*p & (1<= e) + break; + off = 0; + } + m <<= 1; + } + } + return v; +} + +enum { + Ng = RepCnt+1, + UsgCnt = Delim+1, /* fake */ + Nl = UsgCnt+1, + Nu = 256, +}; + +static uchar* +repparse1(uchar *d, uchar *e, int g[], int l[], int c, + void (*f)(int t, int v, int g[], int l[], int c, void *a), void *a) +{ + int z, k, t, v, i; + + while(d < e){ + v = 0; + t = *d++; + z = t & 3, t >>= 2; + k = t & 3, t >>= 2; + switch(z){ + case 3: + d += 4; + if(d > e) continue; + v = d[-4] | d[-3]<<8 | d[-2]<<16 | d[-1]<<24; + break; + case 2: + d += 2; + if(d > e) continue; + v = d[-2] | d[-1]<<8; + break; + case 1: + d++; + if(d > e) continue; + v = d[-1]; + break; + } + switch(k){ + case 0: /* main item*/ + switch(t){ + case Collection: + memset(l, 0, Nl*sizeof(l[0])); + d = repparse1(d, e, g, l, v, f, a); + continue; + case CollectionEnd: + return d; + case Input: + case Output: + case Feature: + if(l[UsgCnt] == 0 && l[UsagMin] != 0 && l[UsagMin] < l[UsagMax]) + for(i=l[UsagMin]; i<=l[UsagMax] && l[UsgCnt] < Nu; i++) + l[Nl + l[UsgCnt]++] = i; + for(i=0; idev->usb->ep[eid]->iface->id; + f->nrep = usbcmd(f->dev, Rd2h|Rstd|Riface, Rgetdesc, Dreport<<8, id, + f->rep, sizeof(f->rep)); + if(f->nrep > 0){ + if(debug){ + int i; + + fprint(2, "report descriptor:"); + for(i = 0; i < f->nrep; i++){ + if(i%8 == 0) + fprint(2, "\n\t"); + fprint(2, "%#2.2ux ", f->rep[i]); + } + fprint(2, "\n"); + } + proto = Reportproto; + }else + kbfatal(f, "no report"); + return usbcmd(f->dev, Rh2d|Rclass|Riface, Setproto, proto, id, nil, 0); +} + +static void +kbprocname(KDev *kd, char *name) +{ + char buf[128]; + snprint(buf, sizeof(buf), "%s %s", name, kd->ep->dir); + threadsetname(buf); +} + +static void +sethipri(void) +{ + char fn[64]; + int fd; + + snprint(fn, sizeof(fn), "/proc/%d/ctl", getpid()); + fd = open(fn, OWRITE); + if(fd < 0) + return; + fprint(fd, "pri 13"); + close(fd); +} + +typedef struct Joy Joy; +struct Joy +{ + int axes[Maxaxes]; + int oldaxes[Maxaxes]; + u64int btns; + + int o; + uchar *e; + uchar p[128]; +}; + +static void +joyparse(int t, int f, int g[], int l[], int, void *a) +{ + int v, i; + Joy *p = a; + u64int m; + + if(t != Input) + return; + if(g[RepId] != 0){ + if(p->p[0] != g[RepId]){ + p->o = 0; + return; + } + if(p->o < 8) + p->o = 8; /* skip report id byte */ + } + v = getbits(p->p, p->e, g[RepSize], p->o); + if(g[LogiMin] < 0) + v = signext(v, g[RepSize]); + if((f & (Fvar|Farray)) == Fvar && v >= g[LogiMin] && v <= g[LogiMax]){ + switch(l[Usage]){ + case 0x010030: + case 0x010031: + case 0x010032: + i = l[Usage] - 0x010030; + if((f & (Fabs|Frel)) == Fabs) + p->axes[i] = v; + else + p->axes[i] += v; + break; + } + if((l[Usage] >> 16) == 0x09){ + m = 1ULL << (l[Usage] & 0xff); + p->btns &= ~m; + if(v != 0) + p->btns |= m; + } + } + p->o += g[RepSize]; +} + +static int +kbdbusy(uchar* buf, int n) +{ + int i; + + for(i = 1; i < n; i++) + if(buf[i] == 0 || buf[i] != buf[0]) + return 0; + return 1; +} + +static void +joywork(void *a) +{ + char err[ERRMAX]; + int i, c, nerrs; + KDev* f = a; + Joy p; + u64int lastb; + + kbprocname(f, "joy"); + sethipri(); + + memset(&p, 0, sizeof(p)); + lastb = 0; + + nerrs = 0; + for(;;){ + if(f->ep == nil) + kbfatal(f, nil); + if(f->ep->maxpkt < 1 || f->ep->maxpkt > sizeof(p.p)) + kbfatal(f, "joy: weird mouse maxpkt"); + + memset(p.p, 0, sizeof(p.p)); + c = read(f->ep->dfd, p.p, f->ep->maxpkt); + if(c <= 0){ + if(c < 0) + rerrstr(err, sizeof(err)); + else + strcpy(err, "zero read"); + if(++nerrs < 3){ + fprint(2, "%s: joy: %s: read: %s\n", argv0, f->ep->dir, err); + continue; + } + kbfatal(f, err); + } + nerrs = 0; + + p.o = 0; + p.e = p.p + c; + repparse(f->rep, f->rep+f->nrep, joyparse, &p); + for(i = 0; i < Maxaxes; i++){ + if(p.axes[i] != p.oldaxes[i]) + print("axis %d %d\n", i, p.axes[i]); + p.oldaxes[i] = p.axes[i]; + } + for(i = 0; i < 64; i++) + if(((lastb ^ p.btns) & (1ULL<dev = d; + if(setproto(kd, ep->id) < 0){ + fprint(2, "%s: %s: setproto: %r\n", argv0, d->dir); + goto Err; + } + kd->ep = openep(kd->dev, ep->id); + if(kd->ep == nil){ + fprint(2, "%s: %s: openep %d: %r\n", argv0, d->dir, ep->id); + goto Err; + } + if(opendevdata(kd->ep, OREAD) < 0){ + fprint(2, "%s: %s: opendevdata: %r\n", argv0, kd->ep->dir); + goto Err; + } + f(kd); + return; +Err: + kbfree(kd); +} + +static void +usage(void) +{ + fprint(2, "usage: %s [-d] devid\n", argv0); + threadexits("usage"); +} + +void +threadmain(int argc, char* argv[]) +{ + int i; + Dev *d; + Ep *ep; + Usbdev *ud; + + ARGBEGIN{ + case 'd': + debug++; + break; + default: + usage(); + }ARGEND; + if(argc != 1) + usage(); + d = getdev(atoi(*argv)); + if(d == nil) + sysfatal("getdev: %r"); + ud = d->usb; + ep = nil; + for(i = 0; i < nelem(ud->ep); i++){ + if((ep = ud->ep[i]) == nil) + continue; + if(ep->type == Eintr && ep->dir == Ein && ep->iface->csp == JoyCSP) + break; + } + if(ep == nil) + sysfatal("no suitable endpoint found"); + kbstart(d, ep, joywork); + threadexits(nil); +} diff --git a/sys/src/cmd/nusb/joy/mkfile b/sys/src/cmd/nusb/joy/mkfile new file mode 100644 index 000000000..63af40506 --- /dev/null +++ b/sys/src/cmd/nusb/joy/mkfile @@ -0,0 +1,20 @@ +