summaryrefslogtreecommitdiff
path: root/appl/lib/usb/usb.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/lib/usb/usb.b')
-rw-r--r--appl/lib/usb/usb.b453
1 files changed, 453 insertions, 0 deletions
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;
+}