implement Usbd; include "sys.m"; sys: Sys;include "draw.m";include "string.m"; str: String;include "lock.m"; lock: Lock; Semaphore: import lock;include "arg.m"; arg: Arg; include "usb.m"; usb: Usb; Device, Configuration, Endpt: import Usb;include "bufio.m"; bufio: Bufio; Iobuf: import bufio; Detached, Attached, Enabled, Assigned, Configured: con (iota); Usbd: module{ init: fn(nil: ref Draw->Context, args: list of string);}; Hub: adt { nport, pwrmode, compound, pwrms, maxcurrent, removable, pwrctl: int; ports: cyclic ref DDevice;}; DDevice: adt { port: int; pids: list of int; parent: cyclic ref DDevice; next: cyclic ref DDevice; cfd, setupfd, rawfd: ref Sys->FD; id: int; ls: int; state: int; ep: array of ref Endpt; config: array of ref Usb->Configuration; hub: Hub; mod: UsbDriver; d: ref Device;}; Line: adt { level: int; command: string; value: int; svalue: string;}; ENUMERATE_POLL_INTERVAL: con 1000;FAILED_ENUMERATE_RETRY_INTERVAL: con 10000; verbose: int;debug: int;stderr: ref Sys->FD; usbportfd: ref Sys->FD;usbctlfd: ref Sys->FD;usbctl0: ref Sys->FD;usbsetup0: ref Sys->FD; usbbase: string; configsema, setupsema, treesema: ref Semaphore; # UHCI style status which is returned by the driver.UHCIstatus_Suspend: con 1 << 12;UHCIstatus_PortReset: con 1 << 9;UHCIstatus_SlowDevice: con 1 << 8;UHCIstatus_ResumeDetect: con 1 << 6;UHCIstatus_PortEnableChange: con 1 << 3; UHCIstatus_PortEnable: con 1 << 2;UHCIstatus_ConnectStatusChange: con 1 << 1; UHCIstatus_DevicePresent: con 1 << 0; obt(){# sys->fprint(stderr, "%d waiting\n", sys->pctl(0, nil)); setupsema.obtain();# sys->fprint(stderr, "%d got\n", sys->pctl(0, nil));} rel(){# sys->fprint(stderr, "%d releasing\n", sys->pctl(0, nil)); setupsema.release();} hubid(hub: ref DDevice): int{ if (hub == nil) return 0; return hub.id;} hubfeature(d: ref DDevice, p: int, feature: int, on: int): int{ rtyp: int; if (p == 0) rtyp = Usb->Rclass; else rtyp = Usb->Rclass | Usb->Rother; obt(); rv := usb->setclear_feature(d.setupfd, rtyp, feature, p, on); rel(); return rv;} portpower(hub: ref DDevice, port: int, on: int){ if (verbose) sys->fprint(stderr, "portpower %d/%d %d\n", hubid(hub), port, on); if (hub == nil) return; if (port) hubfeature(hub, port, Usb->PORT_POWER, on);} countrootports(): int{ sys->seek(usbportfd, big 0, Sys->SEEKSTART); buf := array [256] of byte; n := sys->read(usbportfd, buf, len buf); if (n <= 0) { sys->fprint(stderr, "usbd: countrootports: error reading root port status\n"); exit; } (nv, nil) := sys->tokenize(string buf[0: n], "\n"); if (nv < 1) { sys->fprint(stderr, "usbd: countrootports: strange root port status\n"); exit; } return nv;} portstatus(hub: ref DDevice, port: int): int{ rv: int;# setupsema.obtain(); obt(); if (hub == nil) { sys->seek(usbportfd, big 0, Sys->SEEKSTART); buf := array [256] of byte; n := sys->read(usbportfd, buf, len buf); if (n < 1) { sys->fprint(stderr, "usbd: portstatus: read error\n"); rel(); return 0; } (nil, l) := sys->tokenize(string buf[0: n], "\n"); for(; l != nil; l = tl l){ (nv, f) := sys->tokenize(hd l, " "); if(nv < 2){ sys->fprint(stderr, "usbd: portstatus: odd status line\n"); rel(); return 0; } if(int hd f == port){ (rv, nil) = usb->strtol(hd tl f, 16); # the status change bits are not used so mask them off rv &= 16rffff; break; } } if (l == nil) { sys->fprint(stderr, "usbd: portstatus: no status for port %d\n", port); rel(); return 0; } } else rv = usb->get_status(hub.setupfd, port);# setupsema.release(); rel(); if (rv < 0) return 0; return rv;} portenable(hub: ref DDevice, port: int, enable: int){ if (verbose) sys->fprint(stderr, "portenable %d/%d %d\n", hubid(hub), port, enable); if (hub == nil) { if (enable) sys->fprint(usbctlfd, "enable %d", port); else sys->fprint(usbctlfd, "disable %d", port); return; } if (port) hubfeature(hub, port, Usb->PORT_ENABLE, enable);} portreset(hub: ref DDevice, port: int){ if (verbose) sys->fprint(stderr, "portreset %d/%d\n", hubid(hub), port); if (hub == nil) { if(0)sys->fprint(usbctlfd, "reset %d", port); for (i := 0; i < 4; ++i) { sys->sleep(20); # min 10 milli second reset recovery. s := portstatus(hub, port); if ((s & UHCIstatus_PortReset) == 0) # only leave when reset is finished. break; } return; } if (port) hubfeature(hub, port, Usb->PORT_RESET, 1); return;} devspeed(d: ref DDevice){ sys->fprint(d.cfd, "speed %d", !d.ls); if (debug) { s: string; if (d.ls) s = "low"; else s = "high"; sys->fprint(stderr, "%d: set speed %s\n", d.id, s); }} devmaxpkt0(d: ref DDevice, size: int){ sys->fprint(d.cfd, "maxpkt 0 %d", size); if (debug) sys->fprint(stderr, "%d: set maxpkt0 %d\n", d.id, size);} closedev(d: ref DDevice){ d.cfd = usbctl0; d.rawfd = nil; d.setupfd = usbsetup0;} openusb(f: string, mode: int): ref Sys->FD{ fd := sys->open(usbbase + f, mode); if (fd == nil) { sys->fprint(stderr, "usbd: can't open %s: %r\n", usbbase + f); raise "fail:open"; } return fd;} opendevf(id: int, f: string, mode: int): ref Sys->FD{ fd := sys->open(usbbase + string id + "/" + f, mode); if (fd == nil) { sys->fprint(stderr, "usbd: can't open %s: %r\n", usbbase + string id + "/" + f); exit; } return fd;} kill(pid: int): int{ if (debug) sys->print("killing %d\n", pid); fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE); if (fd == nil) { sys->print("kill: open failed\n"); return -1; } if (sys->write(fd, array of byte "kill", 4) != 4) { sys->print("kill: write failed\n"); return -1; } return 0;} rdetach(d: ref DDevice){ if (d.mod != nil) { d.mod->shutdown(); d.mod = nil; } while (d.pids != nil) { if (verbose) sys->fprint(stderr, "kill %d\n", hd d.pids); kill(hd d.pids); d.pids = tl d.pids; } if (d.parent != nil) { last, hp: ref DDevice; last = nil; hp = d.parent.hub.ports; while (hp != nil && hp != d) hp = hp.next; if (last != nil) last.next = d.next; else d.parent.hub.ports = d.next; } if (d.hub.ports != nil) { for (c := d.hub.ports; c != nil; c = c.next) { c.parent = nil; rdetach(c); } } d.state = Detached; if (sys->fprint(d.cfd, "detach") < 0) sys->fprint(stderr, "detach failed\n"); d.cfd = nil; d.rawfd = nil; d.setupfd = nil;} detach(d: ref DDevice){ configsema.obtain(); treesema.obtain(); obt();# setupsema.obtain(); if (verbose) sys->fprint(stderr, "detach %d\n", d.id); rdetach(d); if (verbose) sys->fprint(stderr, "detach %d done\n", d.id);# setupsema.release(); rel(); treesema.release(); configsema.release();} readnum(fd: ref Sys->FD): int{ buf := array [16] of byte; n := sys->read(fd, buf, len buf); if (n <= 0) return -1; (rv , nil) := usb->strtol(string buf[0: n], 0); return rv;} setaddress(d: ref DDevice): int{ if (d.state == Assigned) return d.id; closedev(d); d.id = 0; d.cfd = openusb("new", Sys->ORDWR); id := readnum(d.cfd); if (id <= 0) { if (debug) sys->fprint(stderr, "usbd: usb/new ID: %r\n"); d.cfd = nil; return -1; }# setupsema.obtain(); obt(); if (usb->set_address(d.setupfd, id) < 0) {# setupsema.release(); rel(); return -1; }# setupsema.release(); rel(); d.id = id; d.state = Assigned; return id;} #optstring(d: ref DDevice, langids: list of int, desc: string, index: int)#{# if (index) {# buf := array [256] of byte;# while (langids != nil) {# nr := usb->get_descriptor(d.setupfd, Usb->Rstandard, Usb->STRING, index, hd langids, buf);# if (nr > 2) {# sys->fprint(stderr, "%s: ", desc);# usbdump->desc(d, -1, buf[0: nr]);# }# langids = tl langids;# }# }#} langid(d: ref DDevice): (list of int){ l: list of int; buf := array [256] of byte; nr := usb->get_standard_descriptor(d.setupfd, Usb->STRING, 0, buf); if (nr < 4) return nil; if (nr & 1) nr--; l = nil; for (i := nr - 2; i >= 2; i -= 2) l = usb->get2(buf[i:]) :: l; return l;} describedevice(d: ref DDevice): int{ obt(); devmaxpkt0(d, 64); # guess 64 byte max packet to avoid overrun on read for (x := 0; x < 3; x++) { # retry 3 times d.d = usb->get_parsed_device_descriptor(d.setupfd); if (d.d != nil) break; sys->sleep(200); # tolerate out of spec. devices } if (d.d == nil) { rel(); return -1; } if (d.d.maxpkt0 != 64) { devmaxpkt0(d, d.d.maxpkt0); d.d = usb->get_parsed_device_descriptor(d.setupfd); if (d.d == nil) { rel(); return -1; } } rel(); if (verbose) { sys->fprint(stderr, "usb %x.%x", d.d.usbmajor, d.d.usbminor); sys->fprint(stderr, " class %d subclass %d proto %d [%s] max0 %d", d.d.class, d.d.subclass, d.d.proto, usb->sclass(d.d.class, d.d.subclass, d.d.proto), d.d.maxpkt0); sys->fprint(stderr, " vendor 0x%.4x product 0x%.4x rel %x.%x", d.d.vid, d.d.did, d.d.relmajor, d.d.relminor); sys->fprint(stderr, " nconf %d", d.d.nconf); sys->fprint(stderr, "\n"); obt(); l := langid(d); if (l != nil) { l2 := l; sys->fprint(stderr, "langids ["); while (l2 != nil) { sys->fprint(stderr, " %d", hd l2); l2 = tl l2; } sys->fprint(stderr, "]\n"); }# optstring(d, l, "manufacturer", int buf[14]);# optstring(d, l, "product", int buf[15]);# optstring(d, l, "serial number", int buf[16]); rel(); } return 0;} describehub(d: ref DDevice): int{ b := array [256] of byte;# setupsema.obtain(); obt(); nr := usb->get_class_descriptor(d.setupfd, 0, 0, b); if (nr < Usb->DHUBLEN) {# setupsema.release(); rel(); sys->fprint(stderr, "usbd: error reading hub descriptor: got %d of %d\n", nr, Usb->DHUBLEN); return -1; }# setupsema.release(); rel(); if (verbose) sys->fprint(stderr, "nport %d charac 0x%.4ux pwr %dms current %dmA remov 0x%.2ux pwrctl 0x%.2ux", int b[2], usb->get2(b[3:]), int b[5] * 2, int b[6] * 2, int b[7], int b[8]); d.hub.nport = int b[2]; d.hub.pwrms = int b[5] * 2; d.hub.maxcurrent = int b[6] * 2; char := usb->get2(b[3:]); d.hub.pwrmode = char & 3; d.hub.compound = (char & 4) != 0; d.hub.removable = int b[7]; d.hub.pwrctl = int b[8]; return 0;} loadconfig(d: ref DDevice, n: int): int{ obt(); d.config[n] = usb->get_parsed_configuration_descriptor(d.setupfd, n); if (d.config[n] == nil) { rel(); sys->fprint(stderr, "usbd: error reading configuration descriptor\n"); return -1; } rel(); if (verbose)Lines 1–500 of 835. Load more
implement Usbd; include "sys.m"; sys: Sys; include "draw.m"; include "string.m"; str: String; include "lock.m"; lock: Lock; Semaphore: import lock; include "arg.m"; arg: Arg; include "usb.m"; usb: Usb; Device, Configuration, Endpt: import Usb; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; Detached, Attached, Enabled, Assigned, Configured: con (iota); Usbd: module { init: fn(nil: ref Draw->Context, args: list of string); }; Hub: adt { nport, pwrmode, compound, pwrms, maxcurrent, removable, pwrctl: int; ports: cyclic ref DDevice; }; DDevice: adt { port: int; pids: list of int; parent: cyclic ref DDevice; next: cyclic ref DDevice; cfd, setupfd, rawfd: ref Sys->FD; id: int; ls: int; state: int; ep: array of ref Endpt; config: array of ref Usb->Configuration; hub: Hub; mod: UsbDriver; d: ref Device; }; Line: adt { level: int; command: string; value: int; svalue: string; }; ENUMERATE_POLL_INTERVAL: con 1000; FAILED_ENUMERATE_RETRY_INTERVAL: con 10000; verbose: int; debug: int; stderr: ref Sys->FD; usbportfd: ref Sys->FD; usbctlfd: ref Sys->FD; usbctl0: ref Sys->FD; usbsetup0: ref Sys->FD; usbbase: string; configsema, setupsema, treesema: ref Semaphore; # UHCI style status which is returned by the driver. UHCIstatus_Suspend: con 1 << 12; UHCIstatus_PortReset: con 1 << 9; UHCIstatus_SlowDevice: con 1 << 8; UHCIstatus_ResumeDetect: con 1 << 6; UHCIstatus_PortEnableChange: con 1 << 3; UHCIstatus_PortEnable: con 1 << 2; UHCIstatus_ConnectStatusChange: con 1 << 1; UHCIstatus_DevicePresent: con 1 << 0; obt() { # sys->fprint(stderr, "%d waiting\n", sys->pctl(0, nil)); setupsema.obtain(); # sys->fprint(stderr, "%d got\n", sys->pctl(0, nil)); } rel() { # sys->fprint(stderr, "%d releasing\n", sys->pctl(0, nil)); setupsema.release(); } hubid(hub: ref DDevice): int { if (hub == nil) return 0; return hub.id; } hubfeature(d: ref DDevice, p: int, feature: int, on: int): int { rtyp: int; if (p == 0) rtyp = Usb->Rclass; else rtyp = Usb->Rclass | Usb->Rother; obt(); rv := usb->setclear_feature(d.setupfd, rtyp, feature, p, on); rel(); return rv; } portpower(hub: ref DDevice, port: int, on: int) { if (verbose) sys->fprint(stderr, "portpower %d/%d %d\n", hubid(hub), port, on); if (hub == nil) return; if (port) hubfeature(hub, port, Usb->PORT_POWER, on); } countrootports(): int { sys->seek(usbportfd, big 0, Sys->SEEKSTART); buf := array [256] of byte; n := sys->read(usbportfd, buf, len buf); if (n <= 0) { sys->fprint(stderr, "usbd: countrootports: error reading root port status\n"); exit; } (nv, nil) := sys->tokenize(string buf[0: n], "\n"); if (nv < 1) { sys->fprint(stderr, "usbd: countrootports: strange root port status\n"); exit; } return nv; } portstatus(hub: ref DDevice, port: int): int { rv: int; # setupsema.obtain(); obt(); if (hub == nil) { sys->seek(usbportfd, big 0, Sys->SEEKSTART); buf := array [256] of byte; n := sys->read(usbportfd, buf, len buf); if (n < 1) { sys->fprint(stderr, "usbd: portstatus: read error\n"); rel(); return 0; } (nil, l) := sys->tokenize(string buf[0: n], "\n"); for(; l != nil; l = tl l){ (nv, f) := sys->tokenize(hd l, " "); if(nv < 2){ sys->fprint(stderr, "usbd: portstatus: odd status line\n"); rel(); return 0; } if(int hd f == port){ (rv, nil) = usb->strtol(hd tl f, 16); # the status change bits are not used so mask them off rv &= 16rffff; break; } } if (l == nil) { sys->fprint(stderr, "usbd: portstatus: no status for port %d\n", port); rel(); return 0; } } else rv = usb->get_status(hub.setupfd, port); # setupsema.release(); rel(); if (rv < 0) return 0; return rv; } portenable(hub: ref DDevice, port: int, enable: int) { if (verbose) sys->fprint(stderr, "portenable %d/%d %d\n", hubid(hub), port, enable); if (hub == nil) { if (enable) sys->fprint(usbctlfd, "enable %d", port); else sys->fprint(usbctlfd, "disable %d", port); return; } if (port) hubfeature(hub, port, Usb->PORT_ENABLE, enable); } portreset(hub: ref DDevice, port: int) { if (verbose) sys->fprint(stderr, "portreset %d/%d\n", hubid(hub), port); if (hub == nil) { if(0)sys->fprint(usbctlfd, "reset %d", port); for (i := 0; i < 4; ++i) { sys->sleep(20); # min 10 milli second reset recovery. s := portstatus(hub, port); if ((s & UHCIstatus_PortReset) == 0) # only leave when reset is finished. break; } return; } if (port) hubfeature(hub, port, Usb->PORT_RESET, 1); return; } devspeed(d: ref DDevice) { sys->fprint(d.cfd, "speed %d", !d.ls); if (debug) { s: string; if (d.ls) s = "low"; else s = "high"; sys->fprint(stderr, "%d: set speed %s\n", d.id, s); } } devmaxpkt0(d: ref DDevice, size: int) { sys->fprint(d.cfd, "maxpkt 0 %d", size); if (debug) sys->fprint(stderr, "%d: set maxpkt0 %d\n", d.id, size); } closedev(d: ref DDevice) { d.cfd = usbctl0; d.rawfd = nil; d.setupfd = usbsetup0; } openusb(f: string, mode: int): ref Sys->FD { fd := sys->open(usbbase + f, mode); if (fd == nil) { sys->fprint(stderr, "usbd: can't open %s: %r\n", usbbase + f); raise "fail:open"; } return fd; } opendevf(id: int, f: string, mode: int): ref Sys->FD { fd := sys->open(usbbase + string id + "/" + f, mode); if (fd == nil) { sys->fprint(stderr, "usbd: can't open %s: %r\n", usbbase + string id + "/" + f); exit; } return fd; } kill(pid: int): int { if (debug) sys->print("killing %d\n", pid); fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE); if (fd == nil) { sys->print("kill: open failed\n"); return -1; } if (sys->write(fd, array of byte "kill", 4) != 4) { sys->print("kill: write failed\n"); return -1; } return 0; } rdetach(d: ref DDevice) { if (d.mod != nil) { d.mod->shutdown(); d.mod = nil; } while (d.pids != nil) { if (verbose) sys->fprint(stderr, "kill %d\n", hd d.pids); kill(hd d.pids); d.pids = tl d.pids; } if (d.parent != nil) { last, hp: ref DDevice; last = nil; hp = d.parent.hub.ports; while (hp != nil && hp != d) hp = hp.next; if (last != nil) last.next = d.next; else d.parent.hub.ports = d.next; } if (d.hub.ports != nil) { for (c := d.hub.ports; c != nil; c = c.next) { c.parent = nil; rdetach(c); } } d.state = Detached; if (sys->fprint(d.cfd, "detach") < 0) sys->fprint(stderr, "detach failed\n"); d.cfd = nil; d.rawfd = nil; d.setupfd = nil; } detach(d: ref DDevice) { configsema.obtain(); treesema.obtain(); obt(); # setupsema.obtain(); if (verbose) sys->fprint(stderr, "detach %d\n", d.id); rdetach(d); if (verbose) sys->fprint(stderr, "detach %d done\n", d.id); # setupsema.release(); rel(); treesema.release(); configsema.release(); } readnum(fd: ref Sys->FD): int { buf := array [16] of byte; n := sys->read(fd, buf, len buf); if (n <= 0) return -1; (rv , nil) := usb->strtol(string buf[0: n], 0); return rv; } setaddress(d: ref DDevice): int { if (d.state == Assigned) return d.id; closedev(d); d.id = 0; d.cfd = openusb("new", Sys->ORDWR); id := readnum(d.cfd); if (id <= 0) { if (debug) sys->fprint(stderr, "usbd: usb/new ID: %r\n"); d.cfd = nil; return -1; } # setupsema.obtain(); obt(); if (usb->set_address(d.setupfd, id) < 0) { # setupsema.release(); rel(); return -1; } # setupsema.release(); rel(); d.id = id; d.state = Assigned; return id; } #optstring(d: ref DDevice, langids: list of int, desc: string, index: int) #{ # if (index) { # buf := array [256] of byte; # while (langids != nil) { # nr := usb->get_descriptor(d.setupfd, Usb->Rstandard, Usb->STRING, index, hd langids, buf); # if (nr > 2) { # sys->fprint(stderr, "%s: ", desc); # usbdump->desc(d, -1, buf[0: nr]); # } # langids = tl langids; # } # } #} langid(d: ref DDevice): (list of int) { l: list of int; buf := array [256] of byte; nr := usb->get_standard_descriptor(d.setupfd, Usb->STRING, 0, buf); if (nr < 4) return nil; if (nr & 1) nr--; l = nil; for (i := nr - 2; i >= 2; i -= 2) l = usb->get2(buf[i:]) :: l; return l; } describedevice(d: ref DDevice): int { obt(); devmaxpkt0(d, 64); # guess 64 byte max packet to avoid overrun on read for (x := 0; x < 3; x++) { # retry 3 times d.d = usb->get_parsed_device_descriptor(d.setupfd); if (d.d != nil) break; sys->sleep(200); # tolerate out of spec. devices } if (d.d == nil) { rel(); return -1; } if (d.d.maxpkt0 != 64) { devmaxpkt0(d, d.d.maxpkt0); d.d = usb->get_parsed_device_descriptor(d.setupfd); if (d.d == nil) { rel(); return -1; } } rel(); if (verbose) { sys->fprint(stderr, "usb %x.%x", d.d.usbmajor, d.d.usbminor); sys->fprint(stderr, " class %d subclass %d proto %d [%s] max0 %d", d.d.class, d.d.subclass, d.d.proto, usb->sclass(d.d.class, d.d.subclass, d.d.proto), d.d.maxpkt0); sys->fprint(stderr, " vendor 0x%.4x product 0x%.4x rel %x.%x", d.d.vid, d.d.did, d.d.relmajor, d.d.relminor); sys->fprint(stderr, " nconf %d", d.d.nconf); sys->fprint(stderr, "\n"); obt(); l := langid(d); if (l != nil) { l2 := l; sys->fprint(stderr, "langids ["); while (l2 != nil) { sys->fprint(stderr, " %d", hd l2); l2 = tl l2; } sys->fprint(stderr, "]\n"); } # optstring(d, l, "manufacturer", int buf[14]); # optstring(d, l, "product", int buf[15]); # optstring(d, l, "serial number", int buf[16]); rel(); } return 0; } describehub(d: ref DDevice): int { b := array [256] of byte; # setupsema.obtain(); obt(); nr := usb->get_class_descriptor(d.setupfd, 0, 0, b); if (nr < Usb->DHUBLEN) { # setupsema.release(); rel(); sys->fprint(stderr, "usbd: error reading hub descriptor: got %d of %d\n", nr, Usb->DHUBLEN); return -1; } # setupsema.release(); rel(); if (verbose) sys->fprint(stderr, "nport %d charac 0x%.4ux pwr %dms current %dmA remov 0x%.2ux pwrctl 0x%.2ux", int b[2], usb->get2(b[3:]), int b[5] * 2, int b[6] * 2, int b[7], int b[8]); d.hub.nport = int b[2]; d.hub.pwrms = int b[5] * 2; d.hub.maxcurrent = int b[6] * 2; char := usb->get2(b[3:]); d.hub.pwrmode = char & 3; d.hub.compound = (char & 4) != 0; d.hub.removable = int b[7]; d.hub.pwrctl = int b[8]; return 0; } loadconfig(d: ref DDevice, n: int): int { obt(); d.config[n] = usb->get_parsed_configuration_descriptor(d.setupfd, n); if (d.config[n] == nil) { rel(); sys->fprint(stderr, "usbd: error reading configuration descriptor\n"); return -1; } rel(); if (verbose)