diff options
Diffstat (limited to 'appl/lib/usb')
| -rw-r--r-- | appl/lib/usb/mkfile | 16 | ||||
| -rw-r--r-- | appl/lib/usb/usb.b | 453 | ||||
| -rw-r--r-- | appl/lib/usb/usbmass.b | 465 | ||||
| -rw-r--r-- | appl/lib/usb/usbmct.b | 204 | ||||
| -rw-r--r-- | appl/lib/usb/usbmouse.b | 60 |
5 files changed, 1198 insertions, 0 deletions
diff --git a/appl/lib/usb/mkfile b/appl/lib/usb/mkfile new file mode 100644 index 00000000..3fe78cca --- /dev/null +++ b/appl/lib/usb/mkfile @@ -0,0 +1,16 @@ +<../../../mkconfig + +TARG=\ + usb.dis\ + usbmouse.dis\ + usbmct.dis\ + usbmass.dis + +MODULES= + +SYSMODULES= \ + usb.m\ + +DISBIN=$ROOT/dis/lib/usb + +<$ROOT/mkfiles/mkdis diff --git a/appl/lib/usb/usb.b b/appl/lib/usb/usb.b new file mode 100644 index 00000000..8c8fa139 --- /dev/null +++ b/appl/lib/usb/usb.b @@ -0,0 +1,453 @@ +# +# Copyright © 2002 Vita Nuova Holdings Limited +# +implement Usb; + +include "sys.m"; + sys: Sys; + +include "usb.m"; + +include "string.m"; + str: String; + +Proto: adt { + proto: int; + name: string; +}; + +SubClass: adt { + subclass: int; + name: string; + proto: array of Proto; +}; + +Class: adt { + class: int; + name: string; + subclass: array of SubClass; +}; + +classes := array [] of { + Class(Usb->CL_AUDIO, "audio", + array [] of { + SubClass(1, "control", nil), + SubClass(2, "stream", nil), + SubClass(3, "midi", nil), + } + ), + Class(Usb->CL_COMMS, "comms", + array [] of { + SubClass(1, "abstract", + array [] of { + Proto(1, "AT"), + } + ) + } + ), + Class(Usb->CL_HID, "hid", + array [] of { + SubClass(1, "boot", + array [] of { + Proto(1, "kbd"), + Proto(2, "mouse"), + } + ) + } + ), + Class(Usb->CL_PRINTER, "printer", + array [] of { + SubClass(1, "printer", + array [] of { + Proto(1, "uni"), + Proto(2, "bi"), + } + ) + } + ), + Class(Usb->CL_HUB, "hub", + array [] of { + SubClass(1, "hub", nil), + } + ), + Class(Usb->CL_DATA, "data", nil), + Class(Usb->CL_MASS, "mass", + array [] of { + SubClass(1, "rbc", + array [] of { + Proto(0, "cbi-cc"), + Proto(1, "cbi-nocc"), + Proto(16r50, "bulkonly"), + } + ), + SubClass(2, "sff-8020i/mmc-2", + array [] of { + Proto(0, "cbi-cc"), + Proto(1, "cbi-nocc"), + Proto(16r50, "bulkonly"), + } + ), + SubClass(3, "qic-157", + array [] of { + Proto(0, "cbi-cc"), + Proto(1, "cbi-nocc"), + Proto(16r50, "bulkonly"), + } + ), + SubClass(4, "ufi", + array [] of { + Proto(0, "cbi-cc"), + Proto(1, "cbi-nocc"), + Proto(16r50, "bulkonly"), + } + ), + SubClass(5, "sff-8070i", + array [] of { + Proto(0, "cbi-cc"), + Proto(1, "cbi-nocc"), + Proto(16r50, "bulkonly"), + } + ), + SubClass(6, "scsi", + array [] of { + Proto(0, "cbi-cc"), + Proto(1, "cbi-nocc"), + Proto(16r50, "bulkonly"), + } + ), + } + ), +}; + +get2(b: array of byte): int +{ + return int b[0] | (int b[1] << 8); +} + +put2(buf: array of byte, v: int) +{ + buf[0] = byte v; + buf[1] = byte (v >> 8); +} + +get4(b: array of byte): int +{ + return int b[0] | (int b[1] << 8) | (int b[2] << 16) | (int b[3] << 24); +} + +put4(buf: array of byte, v: int) +{ + buf[0] = byte v; + buf[1] = byte (v >> 8); + buf[2] = byte (v >> 16); + buf[3] = byte (v >> 24); +} + +bigget2(b: array of byte): int +{ + return int b[1] | (int b[0] << 8); +} + +bigput2(buf: array of byte, v: int) +{ + buf[1] = byte v; + buf[0] = byte (v >> 8); +} + +bigget4(b: array of byte): int +{ + return int b[3] | (int b[2] << 8) | (int b[1] << 16) | (int b[0] << 24); +} + +bigput4(buf: array of byte, v: int) +{ + buf[3] = byte v; + buf[2] = byte (v >> 8); + buf[1] = byte (v >> 16); + buf[0] = byte (v >> 24); +} + +strtol(s: string, base: int): (int, string) +{ + if (str == nil) + str = load String String->PATH; + if (base != 0) + return str->toint(s, base); + if (len s >= 2 && (s[0:2] == "0X" || s[0:2] == "0x")) + return str->toint(s[2:], 16); + if (len s > 0 && s[0:1] == "0") + return str->toint(s[1:], 8); + return str->toint(s, 10); +} + +memset(buf: array of byte, v: int) +{ + for (x := 0; x < len buf; x++) + buf[x] = byte v; +} + +setupreq(setupfd: ref Sys->FD, typ, req, value, index: int, outbuf: array of byte, count: int): int +{ + additional: int; + if (outbuf != nil) { + additional = len outbuf; + # if there is an outbuf, then the count sent must be length of the payload + # this assumes that RH2D is set + count = additional; + } + else + additional = 0; + buf := array[8 + additional] of byte; + buf[0] = byte typ; + buf[1] = byte req; + put2(buf[2:], value); + put2(buf[4:], index); + put2(buf[6:], count); + if (additional) + buf[8:] = outbuf; + rv := sys->write(setupfd, buf, len buf); + if (rv < 0) + return -1; + if (rv != len buf) + return -1; + return rv; +} + +setupreply(setupfd: ref Sys->FD, buf: array of byte): int +{ + nb := sys->read(setupfd, buf, len buf); + return nb; +} + +setup(setupfd: ref Sys->FD, typ, req, value, index: int, outbuf: array of byte, inbuf: array of byte): int +{ + count: int; + if (inbuf != nil) + count = len inbuf; + else + count = 0; + if (setupreq(setupfd, typ, req, value, index, outbuf, count) < 0) + return -1; + if (count == 0) + return 0; + return setupreply(setupfd, inbuf); +} + +get_descriptor(fd: ref Sys->FD, rtyp: int, dtyp: int, dindex: int, langid: int, buf: array of byte): int +{ + nr := -1; + if (setupreq(fd, RD2H | rtyp | Rdevice, GET_DESCRIPTOR, (dtyp << 8) | dindex, langid, nil, len buf) < 0 + || (nr = setupreply(fd, buf)) < 1) + return -1; + return nr; +} + +get_standard_descriptor(fd: ref Sys->FD, dtyp: int, index: int, buf: array of byte): int +{ + return get_descriptor(fd, Rstandard, dtyp, index, 0, buf); +} + +get_class_descriptor(fd: ref Sys->FD, dtyp: int, index: int, buf: array of byte): int +{ + return get_descriptor(fd, Rclass, dtyp, index, 0, buf); +} + +get_vendor_descriptor(fd: ref Sys->FD, dtyp: int, index: int, buf: array of byte): int +{ + return get_descriptor(fd, Rvendor, dtyp, index, 0, buf); +} + +get_status(fd: ref Sys->FD, port: int): int +{ + buf := array [4] of byte; + if (setupreq(fd, RD2H | Rclass | Rother, GET_STATUS, 0, port, nil, len buf) < 0 + || setupreply(fd, buf) < len buf) + return -1; + return get2(buf); +} + +set_address(fd: ref Sys->FD, address: int): int +{ + return setupreq(fd, RH2D | Rstandard | Rdevice, SET_ADDRESS, address, 0, nil, 0); +} + +set_configuration(fd: ref Sys->FD, n: int): int +{ + return setupreq(fd, RH2D | Rstandard | Rdevice, SET_CONFIGURATION, n, 0, nil, 0); +} + +setclear_feature(fd: ref Sys->FD, rtyp: int, value: int, index: int, on: int): int +{ + req: int; + if (on) + req = SET_FEATURE; + else + req = CLEAR_FEATURE; + return setupreq(fd, RH2D | rtyp, req, value, index, nil, 0); +} + +parse_conf(b: array of byte): ref Configuration +{ + if (len b < DCONFLEN) + return nil; + conf := ref Configuration; + conf.id = int b[5]; + conf.iface = array[int b[4]] of Interface; + conf.attr = int b[7]; + conf.powerma = int b[8] * 2; + return conf; +} + +parse_iface(conf: ref Configuration, b: array of byte): ref AltInterface +{ + if (len b < DINTERLEN || conf == nil) + return nil; + id := int b[2]; + if (id >= len conf.iface) + return nil; + ai := ref AltInterface; + ai.id = int b[3]; + if (int b[4] != 0) + ai.ep = array [int b[4]] of ref Endpt; + ai.class = int b[5]; + ai.subclass = int b[6]; + ai.proto = int b[7]; + conf.iface[id].altiface = ai :: conf.iface[id].altiface; + return ai; +} + +parse_endpt(conf: ref Configuration, ai: ref AltInterface, b: array of byte): ref Endpt +{ + if (len b < DENDPLEN || conf == nil || ai == nil || ai.ep == nil) + return nil; + for (i := 0; i < len ai.ep; i++) + if (ai.ep[i] == nil) + break; + if (i >= len ai.ep) + return nil; + ep := ref Endpt; + ai.ep[i] = ep; + ep.addr = int b[2]; + ep.attr = int b[3]; + ep.d2h = ep.addr & 16r80; + ep.etype = int b[3] & 3; + ep.isotype = (int b[3] >> 2) & 3; + ep.maxpkt = get2(b[4:]); + ep.interval = int b[6]; + return ep; +} + +get_parsed_configuration_descriptor(fd: ref Sys->FD, n: int): ref Configuration +{ + conf: ref Configuration; + altiface: ref AltInterface; + + b := array [256] of byte; + nr := get_standard_descriptor(fd, CONFIGURATION, n, b); + if (nr < 0) + return nil; + conf = nil; + altiface = nil; + for (i := 0; nr - i > 2 && b[i] > byte 0 && int b[i] <= nr - i; i += int b[i]) { + ni := i + int b[i]; + case int b[i + 1] { + Usb->CONFIGURATION => + conf = parse_conf(b[i: ni]); + if (conf == nil) + return nil; + Usb->INTERFACE => + altiface = parse_iface(conf, b[i: ni]); + if (altiface == nil) + return nil; + Usb->ENDPOINT => + if (parse_endpt(conf, altiface, b[i: ni]) == nil) + return nil; + } + } + if (i < nr) + sys->print("usb: residue at end of descriptors\n"); + return conf; +} + +get_parsed_device_descriptor(fd: ref Sys->FD): ref Device +{ + b := array [256] of byte; + nr := get_standard_descriptor(fd, DEVICE, 0, b); + if (nr < DDEVLEN) { + if (nr == 8 || nr == 16) { + memset(b[nr: DDEVLEN - 1], 0); + b[DDEVLEN - 1] = byte 1; + nr = DDEVLEN; + } + else + return nil; + } + dev := ref Device; + dev.usbmajor = int b[3]; + dev.usbminor = int b[2]; + dev.class = int b[4]; + dev.subclass = int b[5]; + dev.proto = int b[6]; + dev.maxpkt0 = int b[7]; + dev.vid = get2(b[8:]); + dev.did = get2(b[10:]); + dev.relmajor = int b[13]; + dev.relminor = int b[12]; + dev.nconf = int b[17]; + return dev; +} + +dump_configuration(fd: ref Sys->FD, conf: ref Configuration) +{ + sys->fprint(fd, "configuration %d attr 0x%.x powerma %d\n", conf.id, conf.attr, conf.powerma); + for (i := 0; i < len conf.iface; i++) { + sys->fprint(fd, "\tinterface %d\n", i); + ail := conf.iface[i].altiface; + while (ail != nil) { + ai := hd ail; + sys->fprint(fd, "\t\t%d class %d subclass %d proto %d [%s]\n", + ai.id, ai.class, ai.subclass, ai.proto, + sclass(ai.class, ai.subclass, ai.proto)); + for (e := 0; e < len ai.ep; e++) { + if (ai.ep[e] == nil) { + sys->fprint(fd, "\t\t\t missing descriptor\n"); + continue; + } + sys->fprint(fd, "\t\t\t0x%.2ux attr 0x%.x maxpkt %d interval %d\n", + ai.ep[e].addr, ai.ep[e].attr, ai.ep[e].maxpkt, ai.ep[e].interval); + } + ail = tl ail; + } + } +sys->fprint(fd, "done dumping\n"); +} + +sclass(class, subclass, proto: int): string +{ + for (c := 0; c < len classes; c++) + if (classes[c].class == class) + break; + if (c >= len classes) + return sys->sprint("%d.%d.%d", class, subclass, proto); + if (classes[c].subclass == nil) + return sys->sprint("%s.%d.%d", classes[c].name, subclass, proto); + for (sc := 0; sc < len classes[c].subclass; sc++) + if (classes[c].subclass[sc].subclass == subclass) + break; + if (sc >= len classes[c].subclass) + return sys->sprint("%s.%d.%d", classes[c].name, subclass, proto); + if (classes[c].subclass[sc].proto == nil) + return sys->sprint("%s.%s.%d", classes[c].name, classes[c].subclass[sc].name, proto); + for (p := 0; p < len classes[c].subclass[sc].proto; p++) + if (classes[c].subclass[sc].proto[p].proto == proto) + break; + if (p >= len classes[c].subclass[sc].proto) + return sys->sprint("%s.%s.%d", classes[c].name, classes[c].subclass[sc].name, proto); + return sys->sprint("%s.%s.%s", classes[c].name, classes[c].subclass[sc].name, + classes[c].subclass[sc].proto[p].name); +} + +init() +{ + sys = load Sys Sys->PATH; +} diff --git a/appl/lib/usb/usbmass.b b/appl/lib/usb/usbmass.b new file mode 100644 index 00000000..f5140cc3 --- /dev/null +++ b/appl/lib/usb/usbmass.b @@ -0,0 +1,465 @@ +# +# Copyright © 2001 Vita Nuova Holdings Limited. +# +implement UsbDriver; + +include "sys.m"; + sys: Sys; +include "usb.m"; + usb: Usb; + Endpt, RD2H, RH2D: import Usb; + +ENDPOINT_STALL: con 0; # TO DO: should be in usb.m + +readerpid: int; +setupfd, ctlfd: ref Sys->FD; +infd, outfd: ref Sys->FD; +inep, outep: ref Endpt; +cbwseq := 0; +capacity: big; +debug := 0; + +lun: int; +blocksize: int; + +kill(pid: int) +{ + fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE); + if (fd != nil) + sys->fprint(fd, "kill"); +} + +reader(pidc: chan of int, fileio: ref Sys->FileIO) +{ + pid := sys->pctl(0, nil); + pidc <-= pid; + for(;;) alt{ + (offset, count, nil, rc) := <-fileio.read => + if (rc != nil) { + if (offset%blocksize || count%blocksize) { + rc <- = (nil, "unaligned read"); + continue; + } + offset /= blocksize; + count /= blocksize; + buf := array [count * blocksize] of byte; + if (scsiread10(lun, offset, count, buf) < 0) { + scsirequestsense(lun); + rc <- = (nil, "read error"); + continue; + } + rc <- = (buf, nil); + } + (offset, data, nil, wc) := <-fileio.write => + if(wc != nil){ + count := len data; + if(offset%blocksize || count%blocksize){ + wc <-= (0, "unaligned write"); + continue; + } + offset /= blocksize; + count /= blocksize; + if(scsiwrite10(lun, offset, count, data) < 0){ + scsirequestsense(lun); + wc <-= (0, "write error"); + continue; + } + wc <-= (len data, nil); + } + } + readerpid = -1; +} + +massstoragereset(): int +{ + if (usb->setup(setupfd, Usb->RH2D | Usb->Rclass | Usb->Rinterface, 255, 0, 0, nil, nil) < 0) { + sys->print("usbmass: storagereset failed\n"); + return -1; + } + return 0; +} + +getmaxlun(): int +{ + buf := array[1] of byte; + if (usb->setup(setupfd, Usb->RD2H | Usb->Rclass | Usb->Rinterface, 254, 0, 0, nil, buf) < 0) { + sys->print("usbmass: getmaxlun failed\n"); + return -1; + } + return int buf[0]; +} + +# +# CBW: +# sig[4]="USBC" tag[4] datalen[4] flags[1] lun[1] len[1] cmd[len] +# +sendcbw(dtl: int, outdir: int, lun: int, cmd: array of byte): int +{ + cbw := array [31] of byte; + cbw[0] = byte 'U'; + cbw[1] = byte 'S'; + cbw[2] = byte 'B'; + cbw[3] = byte 'C'; + usb->put4(cbw[4:], ++cbwseq); + usb->put4(cbw[8:], dtl); + if (outdir) + cbw[12] = byte RH2D; + else + cbw[12] = byte RD2H; + cbw[13] = byte lun; + cbw[14] = byte len cmd; + cbw[15:] = cmd; + rv := sys->write(outfd, cbw, len cbw); + if (rv < 0) { + sys->print("sendcbw: failed: %r\n"); + return -1; + } + if (rv != len cbw) { + sys->print("sendcbw: truncated send\n"); + return -1; + } + return 0; +} + +# +# CSW: +# sig[4]="USBS" tag[4] residue[4] status[1] +# + +recvcsw(tag: int): (int, int) +{ + if(debug) + sys->print("recvcsw\n"); + buf := array [13] of byte; + if (sys->read(infd, buf, len buf) != len buf) { + sys->print("recvcsw: read failed: %r\n"); + return (-1, -1); + } + if (usb->get4(buf) != (('S'<<24)|('B'<<16)|('S'<<8)|'U')) { + sys->print("recvcsw: signature wrong\n"); + return (-1, -1); + } + recvtag := usb->get4(buf[4:]); + if (recvtag != tag) { + sys->print("recvcsw: tag does not match: sent %d recved %d\n", tag, recvtag); + return (-1, -1); + } + residue := usb->get4(buf[8:]); + status := int buf[12]; + if(debug) + sys->print("recvcsw: residue %d status %d\n", residue, status); + return (residue, status); +} + +unstall(ep: ref Endpt) +{ + if(debug) + sys->print("unstalling bulk %x\n", ep.addr); + x := ep.addr & 16rF; + sys->fprint(ctlfd, "unstall %d", x); + sys->fprint(ctlfd, "data %d 0", x); + if (usb->setclear_feature(setupfd, Usb->Rendpt, ENDPOINT_STALL, ep.addr, 0) < 0) { + sys->print("unstall: clear_feature() failed: %r\n"); + return; + } +} + +warnfprint(fd: ref Sys->FD, s: string) +{ + if (sys->fprint(fd, "%s", s) != len s) + sys->print("warning: writing %s failed: %r\n", s); +} + +bulkread(lun: int, cmd: array of byte, buf: array of byte, dump: int): int +{ + if (sendcbw(len buf, 0, lun, cmd) < 0) + return -1; + got := 0; + if (buf != nil) { + while (got < len buf) { + rv := sys->read(infd, buf[got:], len buf - got); + if (rv < 0) { + sys->print("bulkread: read failed: %r\n"); + break; + } + if(debug) + sys->print("read %d\n", rv); + got += rv; + break; + } + if (dump) { + for (i := 0; i < got; i++) + sys->print("%.2ux", int buf[i]); + sys->print("\n"); + } + if (got == 0) + unstall(inep); + } + (residue, status) := recvcsw(cbwseq); + if (residue < 0) { + unstall(inep); + (residue, status) = recvcsw(cbwseq); + if (residue < 0) + return -1; + } + if (status != 0) + return -1; + return got; +} + +bulkwrite(lun: int, cmd: array of byte, buf: array of byte): int +{ + if (sendcbw(len buf, 1, lun, cmd) < 0) + return -1; + got := 0; + if (buf != nil) { + while (got < len buf) { + rv := sys->write(outfd, buf[got:], len buf - got); + if (rv < 0) { + sys->print("bulkwrite: write failed: %r\n"); + break; + } + if(debug) + sys->print("write %d\n", rv); + got += rv; + break; + } + if (got == 0) + unstall(outep); + } + (residue, status) := recvcsw(cbwseq); + if (residue < 0) { + unstall(inep); + (residue, status) = recvcsw(cbwseq); + if (residue < 0) + return -1; + } + if (status != 0) + return -1; + return got; +} + +scsiinquiry(lun: int): int +{ + buf := array [36] of byte; # don't use 255, many devices can't cope + cmd := array [6] of byte; + cmd[0] = byte 16r12; + cmd[1] = byte (lun << 5); + cmd[2] = byte 0; + cmd[3] = byte 0; + cmd[4] = byte len buf; + cmd[5] = byte 0; + got := bulkread(lun, cmd, buf, 0); + if (got < 0) + return -1; + if (got < 36) { + sys->print("scsiinquiry: too little data\n"); + return -1; + } + t := int buf[0] & 16r1f; + if(debug) + sys->print("scsiinquiry: type %d/%s\n", t, string buf[8:35]); + if (t != 0) + return -1; + return 0; +} + +scsireadcapacity(lun: int): int +{ +# warnfprint(ctlfd, "debug 0 1"); +# warnfprint(ctlfd, "debug 1 1"); +# warnfprint(ctlfd, "debug 2 1"); + buf := array [8] of byte; + cmd := array [10] of byte; + cmd[0] = byte 16r25; + cmd[1] = byte (lun << 5); + cmd[2] = byte 0; + cmd[3] = byte 0; + cmd[4] = byte 0; + cmd[5] = byte 0; + cmd[6] = byte 0; + cmd[7] = byte 0; + cmd[8] = byte 0; + cmd[9] = byte 0; + got := bulkread(lun, cmd, buf, 0); + if (got < 0) + return -1; + if (got != len buf) { + sys->print("scsireadcapacity: returned data not right size\n"); + return -1; + } + blocksize = usb->bigget4(buf[4:]); + lba := big usb->bigget4(buf[0:]) & 16rFFFFFFFF; + capacity = big blocksize * (lba+big 1); + if(debug) + sys->print("block size %d lba %bd cap %bd\n", blocksize, lba, capacity); + return 0; +} + +scsirequestsense(lun: int): int +{ +# warnfprint(ctlfd, "debug 0 1"); +# warnfprint(ctlfd, "debug 1 1"); +# warnfprint(ctlfd, "debug 2 1"); + buf := array [18] of byte; + cmd := array [6] of byte; + cmd[0] = byte 16r03; + cmd[1] = byte (lun << 5); + cmd[2] = byte 0; + cmd[3] = byte 0; + cmd[4] = byte len buf; + cmd[5] = byte 0; + got := bulkread(lun, cmd, buf, 1); + if (got < 0) + return -1; + return 0; +} + +scsiread10(lun: int, offset, count: int, buf: array of byte): int +{ + cmd := array [10] of byte; + cmd[0] = byte 16r28; + cmd[1] = byte (lun << 5); + usb->bigput4(cmd[2:], offset); + cmd[6] = byte 0; + usb->bigput2(cmd[7:], count); + cmd[9] = byte 0; + got := bulkread(lun, cmd, buf, 0); + if (got < 0) + return -1; + return 0; +} + +scsiwrite10(lun: int, offset, count: int, buf: array of byte): int +{ + cmd := array [10] of byte; + cmd[0] = byte 16r2A; + cmd[1] = byte (lun << 5); + usb->bigput4(cmd[2:], offset); + cmd[6] = byte 0; + usb->bigput2(cmd[7:], count); + cmd[9] = byte 0; + got := bulkwrite(lun, cmd, buf); + if (got < 0) + return -1; + return 0; +} + +scsistartunit(lun: int, start: int): int +{ +# warnfprint(ctlfd, "debug 0 1"); +# warnfprint(ctlfd, "debug 1 1"); +# warnfprint(ctlfd, "debug 2 1"); + cmd := array [6] of byte; + cmd[0] = byte 16r1b; + cmd[1] = byte (lun << 5); + cmd[2] = byte 0; + cmd[3] = byte 0; + cmd[4] = byte (start & 1); + cmd[5] = byte 0; + got := bulkread(lun, cmd, nil, 0); + if (got < 0) + return -1; + return 0; +} + +init(usbmod: Usb, psetupfd, pctlfd: ref Sys->FD, + nil: ref Usb->Device, + conf: array of ref Usb->Configuration, path: string): int +{ + usb = usbmod; + setupfd = psetupfd; + ctlfd = pctlfd; + + sys = load Sys Sys->PATH; + rv := usb->set_configuration(setupfd, conf[0].id); + if (rv < 0) + return rv; + rv = massstoragereset(); + if (rv < 0) + return rv; + maxlun := getmaxlun(); + if (maxlun < 0) + return maxlun; + lun = 0; + if(debug) + sys->print("maxlun %d\n", maxlun); + inep = outep = nil; + epts := (hd conf[0].iface[0].altiface).ep; + for(i := 0; i < len epts; i++) + if(epts[i].etype == Usb->Ebulk){ + if(epts[i].d2h){ + if(inep == nil) + inep = epts[i]; + }else{ + if(outep == nil) + outep = epts[i]; + } + } + if(inep == nil || outep == nil){ + sys->print("can't find endpoints\n"); + return -1; + } + isrw := (inep.addr & 16rF) == (outep.addr & 16rF); + if(!isrw){ + infd = openep(path, inep, Sys->OREAD); + if(infd == nil) + return -1; + outfd = openep(path, outep, Sys->OWRITE); + if(outfd == nil) + return -1; + }else{ + infd = outfd = openep(path, inep, Sys->ORDWR); + if(infd == nil) + return -1; + } + if (scsiinquiry(0) < 0) + return -1; + scsistartunit(lun, 1); + if (scsireadcapacity(0) < 0) { + scsirequestsense(0); + if (scsireadcapacity(0) < 0) + return -1; + } + fileio := sys->file2chan("/chan", "usbdisk"); + if (fileio == nil) { + sys->print("file2chan failed: %r\n"); + return -1; + } + setlength("/chan/usbdisk", capacity); +# warnfprint(ctlfd, "debug 0 1"); +# warnfprint(ctlfd, "debug 1 1"); +# warnfprint(ctlfd, "debug 2 1"); + pidc := chan of int; + spawn reader(pidc, fileio); + readerpid = <- pidc; + return 0; +} + +shutdown() +{ + if (readerpid >= 0) + kill(readerpid); +} + +openep(path: string, ep: ref Endpt, mode: int): ref Sys->FD +{ + if(debug) + sys->print("ep %x maxpkt %d interval %d\n", ep.addr, ep.maxpkt, ep.interval); + ms: string; + case mode { + Sys->OREAD => ms = "r"; + Sys->OWRITE => ms = "w"; + * => ms = "rw"; + } + if(sys->fprint(ctlfd, "ep %d bulk %s %d 16", ep.addr&16rF, ms, ep.maxpkt) < 0) + return nil; + return sys->open(sys->sprint("%s/ep%ddata", path, ep.addr&16rF), mode); +} + +setlength(f: string, size: big) +{ + d := sys->nulldir; + d.length = size; + sys->wstat(f, d); # ignore errors since it fails on older kernels +} diff --git a/appl/lib/usb/usbmct.b b/appl/lib/usb/usbmct.b new file mode 100644 index 00000000..7384cb23 --- /dev/null +++ b/appl/lib/usb/usbmct.b @@ -0,0 +1,204 @@ +# +# Copyright © 2002 Vita Nuova Holdings Limited +# +implement UsbDriver; + +# MCT RS232 USB driver +# 'Documentation' mined from NetBSD + +include "sys.m"; + sys: Sys; +include "usb.m"; + usb: Usb; + +UMCT_SET_REQUEST: con 1640; + +REQ_SET_BAUD_RATE: con 5; +REQ_SET_LCR: con 7; + +LCR_SET_BREAK: con 16r40; +LCR_PARITY_EVEN: con 16r18; +LCR_PARITY_ODD: con 16r08; +LCR_PARITY_NONE: con 16r00; +LCR_DATA_BITS_5, LCR_DATA_BITS_6, LCR_DATA_BITS_7, LCR_DATA_BITS_8: con iota; +LCR_STOP_BITS_2: con 16r04; +LCR_STOP_BITS_1: con 16r00; + +setupfd: ref Sys->FD; +debug: con 1; + +ioreaderpid, statusreaderpid: int; + +kill(pid: int): int +{ + fd := sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE); + if (fd == nil) + return -1; + if (sys->write(fd, array of byte "kill", 4) != 4) + return -1; + return 0; +} + +ioreader(pidc: chan of int, fd: ref Sys->FD) +{ + pid := sys->pctl(0, nil); + pidc <-= pid; + buf := array [256] of byte; + while ((n := sys->read(fd, buf, len buf)) >= 0) + { + sys->print("[%d]\n", n); + sys->write(sys->fildes(1), buf, n); + } + ioreaderpid = -1; +} + +statusreader(pidc: chan of int, fd: ref Sys->FD) +{ + pid := sys->pctl(0, nil); + pidc <-= pid; + buf := array [2] of byte; + while ((n := sys->read(fd, buf, len buf)) >= 0) + { + sys->print("S(%d)%.2ux%.2ux\n", n, int buf[0], int buf[1]); + } + statusreaderpid = -1; +} + +set_baud_rate(baud: int) +{ + buf := array [1] of byte; + val := 12; + case baud { + 300 => val = 1; + 1200 => val = 3; + 2400 => val = 4; + 4800 => val = 6; + 9600 => val = 8; + 19200 => val = 9; + 38400 => val = 10; + 57600 => val = 11; + 115200 => val = 12; + } + buf[0] = byte val; + if (usb->setup(setupfd, UMCT_SET_REQUEST, REQ_SET_BAUD_RATE, 0, 0, buf, nil) < 0) { + if (debug) + sys->print("usbmct: set_baud_rate failed\n"); + } +} + +set_lcr(val: int) +{ + buf := array [1] of byte; + buf[0] = byte val; + if (usb->setup(setupfd, UMCT_SET_REQUEST, REQ_SET_LCR, 0, 0, buf, nil) < 0) { + if (debug) + sys->print("usbmct: set_lcr failed\n"); + } +} + +init(usbmod: Usb, psetupfd, pctlfd: ref Sys->FD, + dev: ref Usb->Device, + conf: array of ref Usb->Configuration, path: string): int +{ + statusep, inep, outep: ref Usb->Endpt; + usb = usbmod; + sys = load Sys Sys->PATH; + setupfd = psetupfd; + # check the device descriptor to see if it really is an MCT doofer + if (dev.vid != 16r0711 || dev.did != 16r0230) { + if (debug) + sys->print("usbmct: wrong device!\n"); + return -1; + } + usb->set_configuration(setupfd, conf[0].id); + ai := hd conf[0].iface[0].altiface; + statusep = nil; + inep = nil; + outep = nil; + for (e := 0; e < len ai.ep; e++) { + ep := ai.ep[e]; + if ((ep.addr & 16r80) != 0 && (ep.attr & 3) == 3 && ep.maxpkt == 2) + statusep = ep; + else if ((ep.addr & 16r80) != 0 && (ep.attr & 3) == 3) + inep = ep; + else if ((ep.addr & 16r80) == 0 && (ep.attr & 3) == 2) + outep = ep; + } + if (statusep == nil || outep == nil || inep == nil) { + if (debug) + sys->print("usbmct: can't find sensible endpoints\n"); + return -1; + } + if ((inep.addr & 15) != (outep.addr & 15)) { + if (debug) + sys->print("usbmct: in and out endpoints not same number\n"); + return -1; + } + ioid := inep.addr & 15; + statusid := statusep.addr & 15; + if (debug) + sys->print("ep %d %d r %d 32\n", ioid, inep.maxpkt, inep.interval); + if (sys->fprint(pctlfd, "ep %d %d r %d 32", ioid, inep.maxpkt, inep.interval) < 0) { + if (debug) + sys->print("usbmct: can't create i/o endpoint (i)\n"); + return -1; + } +# if (debug) +# sys->print("ep %d %d r bulk 32\n", ioid, inep.maxpkt); +# if (sys->fprint(pctlfd, "ep %d %d r bulk 32", ioid, inep.maxpkt) < 0) { +# if (debug) +# sys->print("usbmct: can't create i/o endpoint (i)\n"); +# return -1; +# } + if (debug) + sys->print("ep %d %d w bulk 8\n", ioid, outep.maxpkt); + if (sys->fprint(pctlfd, "ep %d %d w bulk 8", ioid, outep.maxpkt) < 0) { + if (debug) + sys->print("usbmct: can't create i/o endpoint (o)\n"); + return -1; + } + iofd := sys->open(path + "ep" + string ioid + "data", Sys->ORDWR); + if (iofd == nil) { + if (debug) + sys->print("usbmct: can't open i/o endpoint\n"); + return -1; + } + if (debug) + sys->print("ep %d %d r %d 8\n", statusid, statusep.maxpkt, statusep.interval); + if (sys->fprint(pctlfd, "ep %d %d r %d 8", statusid, statusep.maxpkt, statusep.interval) < 0) { + if (debug) + sys->print("usbmct: can't create status endpoint\n"); + return -1; + } + statusfd := sys->open(path + "ep" + string statusid + "data", Sys->ORDWR); + if (statusfd == nil) { + if (debug) + sys->print("usbmct: can't open status endpoint\n"); + return -1; + } +sys->print("setting baud rate\n"); + set_baud_rate(9600); +sys->print("setting lcr\n"); + set_lcr(LCR_PARITY_NONE | LCR_DATA_BITS_8 | LCR_STOP_BITS_1); +sys->print("launching reader\n"); + pidc := chan of int; + spawn ioreader(pidc, iofd); + ioreaderpid = <- pidc; + spawn statusreader(pidc, statusfd); + statusreaderpid = <- pidc; + buf := array[512] of byte; + for (x := 0; x < 512; x += 16) { + buf[x:] = array of byte sys->sprint("%.2ux", x / 16); + buf[x + 2:] = array of byte "-0123456789-\r\n"; + } + sys->write(iofd, buf, 512); + return 0; +} + +shutdown() +{ + if (ioreaderpid >= 0) + kill(ioreaderpid); + if (statusreaderpid >= 0) + kill(statusreaderpid); +} diff --git a/appl/lib/usb/usbmouse.b b/appl/lib/usb/usbmouse.b new file mode 100644 index 00000000..138f31c1 --- /dev/null +++ b/appl/lib/usb/usbmouse.b @@ -0,0 +1,60 @@ +# +# Copyright © 2002 Vita Nuova Holdings Limited. +# +implement UsbDriver; + +include "sys.m"; + sys: Sys; +include "usb.m"; + usb: Usb; + +readerpid: int; + +kill(pid: int): int +{ + fd := sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE); + if (fd == nil) + return -1; + if (sys->write(fd, array of byte "kill", 4) != 4) + return -1; + return 0; +} + +reader(pidc: chan of int, fd: ref Sys->FD) +{ + pid := sys->pctl(0, nil); + pidc <-= pid; + buf := array [4] of byte; + while ((n := sys->read(fd, buf, len buf)) >= 0) + sys->print("%d: %d\n", sys->millisec(), n); + readerpid = -1; +} + +init(usbmod: Usb, setupfd, ctlfd: ref Sys->FD, + nil: ref Usb->Device, + conf: array of ref Usb->Configuration, path: string): int +{ + usb = usbmod; + sys = load Sys Sys->PATH; + rv := usb->set_configuration(setupfd, conf[0].id); + if (rv < 0) + return rv; + ep := (hd conf[0].iface[0].altiface).ep[0]; + sys->print("maxpkt %d interval %d\n", ep.maxpkt, ep.interval); + rv = sys->fprint(ctlfd, "ep 1 %d r %d 32", ep.maxpkt, ep.interval); + if (rv < 0) + return rv; + datafd := sys->open(path + "ep1data", Sys->OREAD); + if (datafd == nil) + return -1; + pidc := chan of int; + spawn reader(pidc, datafd); + readerpid = <- pidc; + return 0; +} + +shutdown() +{ + if (readerpid >= 0) + kill(readerpid); +} |
