This is actually cinap lenrek fixes along with more fixes. This patch deprecates cinap's patch to fix the ethernet. Reference: /n/sources/patch/applied/usb-ether-fixes Date: Fri Jul 24 12:01:55 CES 2009 Signed-off-by: nemo@lsub.org --- /sys/src/cmd/usb/ether/ether.c Fri Jul 24 12:01:37 2009 +++ /sys/src/cmd/usb/ether/ether.c Fri Jul 24 12:01:33 2009 @@ -130,7 +130,7 @@ { uvlong q; - q = (n&0xFFFFFF) << 8 | t&0xFF; + q = (n&0xFFFFFF) << 8 | t&0xFF; return q; } @@ -265,7 +265,7 @@ qlock(e); s = seprint(s, se, "ctlr id: %#x\n", e->cid); s = seprint(s, se, "phy: %#x\n", e->phy); - s = seprint(s, se, "exiting: %#x\n", e->exiting); + s = seprint(s, se, "exiting: %s\n", e->exiting ? "y" : "n"); s = seprint(s, se, "conns: %d\n", e->nconns); s = seprint(s, se, "allocated bufs: %d\n", e->nabufs); s = seprint(s, se, "used bufs: %d\n", e->nbufs); @@ -734,8 +734,12 @@ { deprint(2, "%s: etherbread\n", argv0); bp->rp = bp->data + Hdrsize; + bp->ndata = -1; bp->ndata = read(e->epin->dfd, bp->rp, sizeof(bp->data)-Hdrsize); - deprint(2, "%s: etherbread got %d bytes\n", argv0, bp->ndata); + if(bp->ndata < 0){ + deprint(2, "%s: etherbread: %r\n", argv0); + }else + deprint(2, "%s: etherbread: got %d bytes\n", argv0, bp->ndata); return bp->ndata; } @@ -746,12 +750,15 @@ deprint(2, "%s: etherbwrite %d bytes\n", argv0, bp->ndata); n = write(e->epout->dfd, bp->rp, bp->ndata); - deprint(2, "%s: etherbwrite wrote %ld bytes\n", argv0, n); + if(n < 0){ + deprint(2, "%s: etherbwrite: %r\n", argv0); + }else + deprint(2, "%s: etherbwrite wrote %ld bytes\n", argv0, n); if(n <= 0) return n; if((bp->ndata % e->epout->maxpkt) == 0){ deprint(2, "%s: short pkt write\n", argv0); - write(e->epout->dfd, "", 0); + write(e->epout->dfd, "", 1); } return n; } @@ -842,13 +849,17 @@ closedev(e->epout); return -1; } - dprint(2, "ether: ep in %s out %s\n", e->epin->dir, e->epout->dir); + dprint(2, "ether: ep in %s maxpkt %d; ep out %s maxpkt %d\n", + e->epin->dir, e->epin->maxpkt, e->epout->dir, e->epout->maxpkt); + + /* time outs are not activated for I/O endpoints */ if(usbdebug > 2 || etherdebug > 2){ devctl(e->epin, "debug 1"); devctl(e->epout, "debug 1"); devctl(e->dev, "debug 1"); } + return 0; } @@ -869,6 +880,16 @@ }; static void +shutdownchan(Channel *c) +{ + Buf *bp; + + while((bp=nbrecvp(c)) != nil) + free(bp); + chanfree(c); +} + +static void etherfree(Ether *e) { int i; @@ -878,7 +899,7 @@ e->free(e); closedev(e->epin); closedev(e->epout); - if(e->rc == nil){ + if(e->rc == nil){ /* not really started */ free(e); return; } @@ -889,16 +910,23 @@ chanfree(e->conns[i]->rc); free(e->conns[i]); } - while((bp = nbrecvp(e->bc)) != nil) - free(bp); - chanfree(e->bc); - chanfree(e->rc); - /* chanfree(e->wc); released by writeproc */ + shutdownchan(e->bc); + shutdownchan(e->rc); + shutdownchan(e->wc); e->epin = e->epout = nil; free(e); } +static void +etherdevfree(void *a) +{ + Ether *e = a; + + if(e != nil) + etherfree(e); +} + /* must return 1 if c wants bp; 0 if not */ static int cwantsbp(Conn *c, Buf *bp) @@ -923,15 +951,37 @@ e->nout++; if(e->bwrite(e, bp) < 0) e->noerrs++; - if(isloopback(e, bp)) + if(isloopback(e, bp) && e->exiting == 0) sendp(e->rc, bp); /* send to input queue */ else freebuf(e, bp); } - while((bp = nbrecvp(wc)) != nil) - free(bp); - chanfree(wc); deprint(2, "%s: writeproc exiting\n", argv0); + closedev(e->dev); +} + +static void +setbuftype(Buf *bp) +{ + uchar *p; + + bp->type = 0; + if(bp->ndata >= Ehdrsize){ + p = bp->rp + Eaddrlen*2; + bp->type = p[0]<<8 | p[1]; + } +} + +static void +etherexiting(Ether *e) +{ + devctl(e->dev, "detach"); + e->exiting = 1; + close(e->epin->dfd); + e->epin->dfd = -1; + close(e->epout->dfd); + e->epout->dfd = -1; + nbsend(e->wc, nil); } static void @@ -947,7 +997,7 @@ while(e->exiting == 0){ bp = nbrecvp(e->rc); if(bp == nil){ - bp = allocbuf(e); /* seems to leak bps kept at bc */ + bp = allocbuf(e); /* leak() may think we leak */ if(e->bread(e, bp) < 0){ freebuf(e, bp); break; @@ -957,7 +1007,8 @@ if(0)dprint(2, "%s: read: short\n", argv0); freebuf(e, bp); continue; - } + }else + setbuftype(bp); } e->nin++; nwants = 0; @@ -976,6 +1027,7 @@ dbp = allocbuf(e); memmove(dbp->rp, bp->rp, n); dbp->ndata = n; + dbp->type = bp->type; } if(nbsendp(e->conns[i]->rc, dbp) < 0){ e->nierrs++; @@ -984,46 +1036,15 @@ } freebuf(e, bp); } - while(e->exiting == 0) /* give them time... */ - yield(); - while((bp = nbrecvp(e->rc)) != nil) - free(bp); deprint(2, "%s: writeproc exiting\n", argv0); - etherfree(e); -} - -static void -etherdevfree(void *a) -{ - Ether *e = a; - - if(e == nil) - return; - if(e->free != nil) - e->free(e); - if(e->rc == nil){ - /* no readproc; free everything ourselves */ - etherfree(e); - return; - } - /* ether resources released by etherreadproc - * It will exit its main look for sure, because - * the endpoints must be detached by now. - */ - close(e->epin->dfd); - e->epin->dfd = -1; - close(e->epout->dfd); - e->epout->dfd = -1; - e->exiting = 1; + etherexiting(e); + closedev(e->dev); } static void setalt(Dev *d, int ifcid, int altid) { - int r; - - r = Rh2d|Rstd|Riface; - if(usbcmd(d, r, Rsetiface, altid, ifcid, nil, 0) < 0) + if(usbcmd(d, Rh2d|Rstd|Riface, Rsetiface, altid, ifcid, nil, 0) < 0) dprint(2, "%s: setalt ifc %d alt %d: %r\n", argv0, ifcid, altid); } @@ -1034,12 +1055,11 @@ Ep *ep; int epin; int epout; - int altid; if(ifc == nil) return -1; - altid = epin = epout = -1; + epin = epout = -1; for(i = 0; (epin < 0 || epout < 0) && i < nelem(ifc->ep); i++) if((ep = ifc->ep[i]) != nil && ep->type == Ebulk){ if(ep->dir == Eboth || ep->dir == Ein) @@ -1051,14 +1071,11 @@ } if(epin == -1 || epout == -1) return -1; + dprint(2, "ether: ep ids: in %d out %d\n", epin, epout); for(i = 0; i < nelem(ifc->altc); i++) - if(ifc->altc[i] != nil){ - altid = ifc->altc[i]->attrib; - break; - } - if(altid != -1) - setalt(e->dev, ifc->id, altid); + if(ifc->altc[i] != nil) + setalt(e->dev, ifc->id, i); *ei = epin; *eo = epout; @@ -1072,9 +1089,46 @@ Conf *c; int i; int j; + int ctlid; + int datid; + Iface *ctlif; + Iface *datif; + Desc *desc; *ei = *eo = -1; ud = e->dev->usb; + + /* look for union descriptor with ethernet ctrl interface */ + for(i = 0; i < nelem(ud->ddesc); i++){ + if((desc = ud->ddesc[i]) == nil) + continue; + if(desc->data.bLength < 5 || desc->data.bbytes[0] != Cdcunion) + continue; + + ctlid = desc->data.bbytes[1]; + datid = desc->data.bbytes[2]; + + if((c = desc->conf) == nil) + continue; + + ctlif = datif = nil; + for(j = 0; j < nelem(c->iface); j++){ + if(c->iface[j] == nil) + continue; + if(c->iface[j]->id == ctlid) + ctlif = c->iface[j]; + if(c->iface[j]->id == datid) + datif = c->iface[j]; + + if(datif != nil && ctlif != nil){ + if(Subclass(ctlif->csp) == Scether) + if(ifaceinit(e, datif, ei, eo) != -1) + return 0; + break; + } + } + } + /* try any other one that seems to be ok */ for(i = 0; i < nelem(ud->conf); i++) if((c = ud->conf[i]) != nil) for(j = 0; j < nelem(c->iface); j++) @@ -1131,7 +1185,9 @@ e->bc = chancreate(sizeof(Buf*), Nconns); e->rc = chancreate(sizeof(Buf*), Nconns/2); e->wc = chancreate(sizeof(Buf*), Nconns*2); + incref(e->dev); proccreate(etherwriteproc, e, 16*1024); + incref(e->dev); proccreate(etherreadproc, e, 16*1024); deprint(2, "%s: dev ref %ld\n", argv0, dev->ref); usbfsadd(&e->fs); --- /sys/src/cmd/usb/ether/ether.h Fri Jul 24 12:01:41 2009 +++ /sys/src/cmd/usb/ether/ether.h Fri Jul 24 12:01:38 2009 @@ -16,6 +16,8 @@ Eaddrlen = 6, Epktlen = 1514, + Ehdrsize = 2*Eaddrlen + 2, + Maxpkt = 2000, /* no jumbo packets here */ Nconns = 8, /* max number of connections */ Nbufs = 8, /* max number of buffers */ @@ -23,6 +25,8 @@ Fnheader = 0, /* Functions */ Fnunion = 6, Fnether = 15, + + Cdcunion = 6, /* CDC Union descriptor subtype */ }; struct Buf @@ -68,7 +72,8 @@ int cid; /* ctlr id */ int phy; /* phy id */ Ref prom; /* nb. of promiscuous conns */ - int exiting; /* shutting it down */ + int exiting; /* shutting down */ + int wrexited; /* write process died */ uchar addr[Eaddrlen]; /* mac */ int nconns; /* nb. of entries used in... */ Conn* conns[Nconns]; /* connections */