diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2023-01-05 06:34:12 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2023-01-05 06:34:12 +0000 |
commit | 556eea1f5a6cd0f1eeb74156ff3899803d107822 (patch) | |
tree | 721f62a0ccff10b16a734d63afdbc78763fea534 /sys/src/cmd/nusb | |
parent | 5bce05b759c695fdd5bc71fe04c00407406e644b (diff) |
nusb/usbd: add /dev/usbhubctl file to control port power and led indicators
Experimental feature:
echo portpower <hub> <port> on/off > /dev/usbhubctl
echo portindicator <hub> <port> on/off > /dev/usbhubctl
Where <hub> is the device number of the hub (as in /dev/usb/epX)
and <port> is the port index (1..n).
Hub and port numbers can be found by reading /dev/usb/ctl.
Diffstat (limited to 'sys/src/cmd/nusb')
-rw-r--r-- | sys/src/cmd/nusb/usbd/fns.h | 1 | ||||
-rw-r--r-- | sys/src/cmd/nusb/usbd/hub.c | 20 | ||||
-rw-r--r-- | sys/src/cmd/nusb/usbd/usbd.c | 99 |
3 files changed, 103 insertions, 17 deletions
diff --git a/sys/src/cmd/nusb/usbd/fns.h b/sys/src/cmd/nusb/usbd/fns.h index 4bd584188..52eb8d7f6 100644 --- a/sys/src/cmd/nusb/usbd/fns.h +++ b/sys/src/cmd/nusb/usbd/fns.h @@ -4,3 +4,4 @@ void work(void); Hub* newhub(char *, Dev*); int hname(char *); void checkidle(void); +int portfeature(Hub*, int, int, int); diff --git a/sys/src/cmd/nusb/usbd/hub.c b/sys/src/cmd/nusb/usbd/hub.c index 8bc175207..8a9a6c115 100644 --- a/sys/src/cmd/nusb/usbd/hub.c +++ b/sys/src/cmd/nusb/usbd/hub.c @@ -13,8 +13,8 @@ static int pollms = Pollms; static char *dsname[] = { "disabled", "attached", "configed" }; -static int -hubfeature(Hub *h, int port, int f, int on) +int +portfeature(Hub *h, int port, int f, int on) { int cmd; @@ -202,12 +202,12 @@ newhub(char *fn, Dev *d) devctl(h->dev, "info hub csp %#08ulx ports %d vid %#.4ux did %#.4ux %q %q", ud->csp, h->nport, ud->vid, ud->did, ud->vendor, ud->product); for(i = 1; i <= h->nport; i++) - if(hubfeature(h, i, Fportpower, 1) < 0) + if(portfeature(h, i, Fportpower, 1) < 0) fprint(2, "%s: %s: power: %r\n", argv0, fn); sleep(h->pwrms); for(i = 1; i <= h->nport; i++) if(h->leds != 0) - hubfeature(h, i, Fportindicator, 1); + portfeature(h, i, Fportindicator, 1); } h->next = hubs; hubs = h; @@ -374,7 +374,7 @@ portattach(Hub *h, int p, u32int sts) sp = "super"; } else { sleep(Enabledelay); - if(hubfeature(h, p, Fportreset, 1) < 0){ + if(portfeature(h, p, Fportreset, 1) < 0){ dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p); goto Fail; } @@ -384,7 +384,7 @@ portattach(Hub *h, int p, u32int sts) goto Fail; if((sts & PSenable) == 0){ dprint(2, "%s: %s: port %d: not enabled?\n", argv0, d->dir, p); - hubfeature(h, p, Fportenable, 1); + portfeature(h, p, Fportenable, 1); sts = portstatus(h, p); if((sts & PSenable) == 0) goto Fail; @@ -468,7 +468,7 @@ Fail: if(pp->hub != nil) pp->hub = nil; /* hub closed by enumhub */ if(!h->dev->isusb3) - hubfeature(h, p, Fportenable, 0); + portfeature(h, p, Fportenable, 0); if(nd != nil) devctl(nd, "detach"); closedev(nd); @@ -549,7 +549,7 @@ portreset(Hub *h, int p) d = h->dev; pp = &h->port[p]; dprint(2, "%s: %s: port %d: resetting\n", argv0, d->dir, p); - if(hubfeature(h, p, Fportreset, 1) < 0){ + if(portfeature(h, p, Fportreset, 1) < 0){ dprint(2, "%s: %s: port %d: reset: %r\n", argv0, d->dir, p); goto Fail; } @@ -587,7 +587,7 @@ Fail: pp->sts = 0; portdetach(h, p); if(!d->isusb3) - hubfeature(h, p, Fportenable, 0); + portfeature(h, p, Fportenable, 0); } static int @@ -627,7 +627,7 @@ enumhub(Hub *h, int p) onhubs = nhubs; if(!h->dev->isusb3){ if((sts & PSsuspend) != 0){ - if(hubfeature(h, p, Fportsuspend, 0) < 0) + if(portfeature(h, p, Fportsuspend, 0) < 0) dprint(2, "%s: %s: port %d: unsuspend: %r\n", argv0, d->dir, p); sleep(Enabledelay); sts = portstatus(h, p); diff --git a/sys/src/cmd/nusb/usbd/usbd.c b/sys/src/cmd/nusb/usbd/usbd.c index cb195ff1f..101fc9338 100644 --- a/sys/src/cmd/nusb/usbd/usbd.c +++ b/sys/src/cmd/nusb/usbd/usbd.c @@ -10,15 +10,18 @@ enum { Qroot, Qusbevent, + Qusbhubctl, Qmax }; char *names[] = { "", "usbevent", + "usbhubctl", }; static char Enonexist[] = "does not exist"; +static char Eperm[] = "permission denied"; typedef struct Event Event; @@ -146,12 +149,19 @@ dirgen(int n, Dir *d, void *) return -1; d->qid.path = n + 1; d->qid.vers = 0; - if(n >= 0){ - d->qid.type = 0; - d->mode = 0444; - }else{ + switch((ulong)d->qid.path){ + case Qroot: d->qid.type = QTDIR; d->mode = 0555 | DMDIR; + break; + case Qusbevent: + d->qid.type = 0; + d->mode = 0444; + break; + case Qusbhubctl: + d->qid.type = 0; + d->mode = 0222; + break; } d->uid = estrdup9p(getuser()); d->gid = estrdup9p(d->uid); @@ -211,6 +221,69 @@ usbdread(Req *req) } static void +usbdwrite(Req *req) +{ + extern QLock hublock; + extern Hub *hubs; + Hub *hub; + Cmdbuf *cb; + int hubid, port, feature, on; + + if((long)req->fid->qid.path != Qusbhubctl){ + respond(req, Enonexist); + return; + } + cb = parsecmd(req->ifcall.data, req->ifcall.count); + if(cb->nf < 4){ + respond(req, "not enougth arguments"); + goto out; + } + if(strcmp(cb->f[0], "portpower") == 0) + feature = Fportpower; + else if(strcmp(cb->f[0], "portindicator") == 0) + feature = Fportindicator; + else { + respond(req, "unnown feature"); + goto out; + } + hubid = atoi(cb->f[1]); + port = atoi(cb->f[2]); + if(strcmp(cb->f[3], "on") == 0) + on = 1; + else if(strcmp(cb->f[3], "off") == 0) + on = 0; + else + on = atoi(cb->f[3]) != 0; + + qlock(&hublock); + for(hub = hubs; hub != nil; hub = hub->next) + if(hub->dev->id == hubid) + break; + if(hub == nil){ + qunlock(&hublock); + respond(req, "unknown hub"); + goto out; + } + if(port < 1 || port > hub->nport){ + qunlock(&hublock); + respond(req, "unknown port"); + goto out; + } + if(feature == Fportpower && hub->pwrmode != 1 + || feature == Fportindicator && !hub->leds){ + qunlock(&hublock); + respond(req, "not supported"); + goto out; + } + portfeature(hub, port, feature, on); + qunlock(&hublock); + req->ofcall.count = req->ifcall.count; + respond(req, nil); +out: + free(cb); +} + +static void usbdstat(Req *req) { if(dirgen(req->fid->qid.path - 1, &req->d, nil) < 0) @@ -265,10 +338,14 @@ static void usbdopen(Req *req) { extern QLock hublock; + Event *e; - if(req->fid->qid.path == Qusbevent){ - Event *e; - + switch((ulong)req->fid->qid.path){ + case Qusbevent: + if(req->ifcall.mode != OREAD){ + respond(req, Eperm); + return; + } qlock(&hublock); qlock(&evlock); @@ -279,6 +356,13 @@ usbdopen(Req *req) qunlock(&evlock); qunlock(&hublock); + break; + case Qusbhubctl: + if((req->ifcall.mode&~OTRUNC) != OWRITE){ + respond(req, Eperm); + return; + } + break; } respond(req, nil); } @@ -350,6 +434,7 @@ Srv usbdsrv = { .attach = usbdattach, .walk1 = usbdwalk, .read = usbdread, + .write = usbdwrite, .stat = usbdstat, .open = usbdopen, .flush = usbdflush, |