ulong frno; /* next frame number avail for I/O */
ulong left; /* remainder after rounding Hz to samples/ms */
int nerrs; /* consecutive errors on iso I/O */
+ int delay; /* maximum number of frames to buffer */
};
/*
iso->navail > iso->nframes / 2;
}
+static int
+isodelay(void *a)
+{
+ Isoio *iso;
+
+ iso = a;
+ if(iso->state == Qclose || iso->err != nil || iso->delay == 0)
+ return 1;
+ return (iso->nframes - iso->navail) <= iso->delay;
+}
+
/*
* Service a completed/failed Td from the done queue.
* It may be of any transfer type.
switch(err){
case Tddataovr: /* Overrun is not an error */
case Tdok:
- /* can't make this assertion in virtualbox */
-// if(td->cbp != 0)
-// panic("ohci: full packet but cbp != 0");
- break;
+ /* virtualbox doesn't always report underflow on short packets */
+ if(td->cbp == 0)
+ break;
+ /* fall through */
case Tddataund:
/* short input packets are ok */
if(mode == OREAD){
Td *td, *dtd;
Block *bp;
- if(ep->maxpkt > 0x2000)
- panic("ohci: max packet > two pages");
- if(ep->maxpkt < count)
- error("maxpkt too short");
- bp = allocb(ep->maxpkt); /* panics if no mem */
- assert(bp != nil);
+ if(count <= BY2PG)
+ bp = allocb(count);
+ else{
+ if(count > 2*BY2PG)
+ panic("ohci: transfer > two pages");
+ /* maximum of one physical page crossing allowed */
+ bp = allocb(count+BY2PG);
+ bp->rp = (uchar*)PGROUND((uintptr)bp->rp);
+ bp->wp = bp->rp;
+ }
dtd = *dtdp;
td = dtd;
td->bp = bp;
print("\t%s\n", buf);
}
if(mustlock){
- qlock(io);
+ eqlock(io);
if(waserror()){
qunlock(io);
nexterror();
ltd = td0 = ed->tds;
load = tot = 0;
do{
- n = ep->maxpkt;
+ n = 2*BY2PG;
if(count-tot < n)
n = count-tot;
if(c != nil && io->tok != Tdtokin)
switch(ep->ttype){
case Tctl:
cio = ep->aux;
- qlock(cio);
+ eqlock(cio);
if(waserror()){
qunlock(cio);
nexterror();
cio, ep->dev->nb, ep->nb, count);
if(count < Rsetuplen)
error("short usb command");
- qlock(cio);
+ eqlock(cio);
free(cio->data);
cio->data = nil;
cio->ndata = 0;
ctlr = ep->hp->aux;
iso = ep->aux;
+ iso->delay = (ep->sampledelay*ep->samplesz + ep->maxpkt-1) / ep->maxpkt;
iso->debug = ep->debug;
- qlock(iso);
+ eqlock(iso);
if(waserror()){
qunlock(iso);
nexterror();
nw = putsamples(ctlr, ep, iso, b+tot, count-tot);
ilock(ctlr);
}
+ while(isodelay(iso) == 0){
+ iunlock(ctlr);
+ sleep(iso, isodelay, iso);
+ ilock(ctlr);
+ }
if(iso->state != Qclose)
iso->state = Qdone;
iunlock(ctlr);
return 0;
ctlr = hp->aux;
- qlock(&ctlr->resetl);
+ eqlock(&ctlr->resetl);
if(waserror()){
qunlock(&ctlr->resetl);
nexterror();
ctlr = hp->aux;
dprint("ohci: %#p port %d enable=%d\n", ctlr->ohci, port, on);
- qlock(&ctlr->resetl);
+ eqlock(&ctlr->resetl);
if(waserror()){
qunlock(&ctlr->resetl);
nexterror();