#include "dat.h"
#include "fns.h"
#include "io.h"
+#include "../port/pci.h"
#include "../port/error.h"
#include "../port/usb.h"
{
Resetdelay = 100, /* delay after a controller reset (ms) */
Enabledelay = 100, /* waiting for a port to enable */
- Abortdelay = 5, /* delay after cancelling Tds (ms) */
+ Abortdelay = 10, /* delay after cancelling Tds (ms) */
Incr = 64, /* for Td and Qh pools */
Tdatomic = 8, /* max nb. of Tds per bulk I/O op. */
Qh* next; /* in active or free list */
Td* tds; /* Td list in this Qh (initially, elink) */
char* tag; /* debug and align, mostly */
- ulong align;
};
/*
{
int i;
Td *td;
- Td *pool;
+ uchar *pool;
lock(&tdpool);
if(tdpool.free == nil){
ddprint("uhci: tdalloc %d Tds\n", Incr);
- pool = xspanalloc(Incr*sizeof(Td), Align, 0);
+ pool = xspanalloc(Incr*ROUND(sizeof(Td), Align), Align, 0);
if(pool == nil)
panic("tdalloc");
for(i=Incr; --i>=0;){
- pool[i].next = tdpool.free;
- tdpool.free = &pool[i];
+ td = (Td*)(pool + i*ROUND(sizeof(Td), Align));
+ td->next = tdpool.free;
+ tdpool.free = td;
}
tdpool.nalloc += Incr;
tdpool.nfree += Incr;
memset(td, 0, sizeof(Td));
td->link = Tdterm;
- assert(((ulong)td & 0xF) == 0);
+ assert(((uintptr)td & 0xF) == 0);
return td;
}
{
int i;
Qh *qh;
- Qh *pool;
+ uchar *pool;
lock(&qhpool);
if(qhpool.free == nil){
ddprint("uhci: qhalloc %d Qhs\n", Incr);
- pool = xspanalloc(Incr*sizeof(Qh), Align, 0);
+ pool = xspanalloc(Incr*ROUND(sizeof(Qh), Align), Align, 0);
if(pool == nil)
panic("qhalloc");
for(i=Incr; --i>=0;){
- pool[i].next = qhpool.free;
- qhpool.free = &pool[i];
+ qh = (Qh*)(pool + i*ROUND(sizeof(Qh), Align));
+ qh->next = qhpool.free;
+ qhpool.free = qh;
}
qhpool.nalloc += Incr;
qhpool.nfree += Incr;
iunlock(ctlr);
}
- assert(((ulong)qh & 0xF) == 0);
+ assert(((uintptr)qh & 0xF) == 0);
return qh;
}
qhfree(Ctlr *ctlr, Qh *qh)
{
Td *td;
- Td *ltd;
Qh *q;
- if(qh == nil)
- return;
-
ilock(ctlr);
for(q = ctlr->qhs; q != nil; q = q->next)
if(q->next == qh)
panic("qhfree: nil q");
q->next = qh->next;
q->link = qh->link;
+ qh->state = Qfree; /* paranoia */
iunlock(ctlr);
- for(td = qh->tds; td != nil; td = ltd){
- ltd = td->next;
+ while((td = qh->tds) != nil){
+ qh->tds = td->next;
tdfree(td);
}
+
lock(&qhpool);
- qh->state = Qfree; /* paranoia */
qh->next = qhpool.free;
qh->tag = nil;
qh->io = nil;
}
OUTS(Status, sts & Sall);
cmd = INS(Cmd);
- if(cmd & Crun == 0){
- print("uhci %#ux: not running: uhci bug?\n", ctlr->port);
- /* BUG: should abort everything in this case */
- }
if(debug > 1){
frptr = INL(Flbaseadd);
frno = INL(Frnum);
frno = TRUNC(frno, Nframes);
- print("cmd %#ux sts %#ux frptr %#ux frno %d\n",
+ iprint("cmd %#ux sts %#ux frptr %#ux frno %d\n",
cmd, sts, frptr, frno);
}
ctlr->ntdintr++;
* it is activated and tdu advanced.
*/
static long
-putsamples(Isoio *iso, uchar *b, long count)
+putsamples(Ctlr *ctlr, Isoio *iso, uchar *b, long count)
{
- long tot;
- long n;
+ long n, tot, left;
+ Td *tdu;
for(tot = 0; isocanwrite(iso) && tot < count; tot += n){
n = count-tot;
- if(n > maxtdlen(iso->tdu) - iso->nleft)
- n = maxtdlen(iso->tdu) - iso->nleft;
- memmove(iso->tdu->data+iso->nleft, b+tot, n);
+ tdu = iso->tdu;
+ left = iso->nleft;
+ if(n > maxtdlen(tdu) - left)
+ n = maxtdlen(tdu) - left;
+ iunlock(ctlr); /* can pagefault here */
+ memmove(tdu->data+left, b+tot, n);
+ ilock(ctlr);
+ if(tdu != iso->tdu)
+ continue;
iso->nleft += n;
- if(iso->nleft == maxtdlen(iso->tdu)){
- tdisoinit(iso, iso->tdu, iso->nleft);
+ if(iso->nleft == maxtdlen(tdu)){
+ tdisoinit(iso, tdu, iso->nleft);
+ iso->tdu = tdu->next;
iso->nleft = 0;
- iso->tdu = iso->tdu->next;
}
}
return tot;
diprint("uhci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb);
ctlr = ep->hp->aux;
- qlock(iso);
+ eqlock(iso);
if(waserror()){
qunlock(iso);
nexterror();
}
if(iso->state != Qrun)
panic("episowrite: iso not running");
- iunlock(ctlr); /* We could page fault here */
- nw = putsamples(iso, b+tot, count-tot);
- ilock(ctlr);
+ nw = putsamples(ctlr, iso, b+tot, count-tot);
}
while(isodelay(iso) == 0){
iunlock(ctlr);
b = a;
ctlr = ep->hp->aux;
- qlock(iso);
+ eqlock(iso);
if(waserror()){
qunlock(iso);
nexterror();
iunlock(ctlr); /* We could page fault here */
memmove(b+tot, tdu->data, nr);
ilock(ctlr);
+ if(iso->tdu != tdu)
+ continue;
if(nr < tdu->ndata)
memmove(tdu->data, tdu->data+nr, tdu->ndata - nr);
tdu->ndata -= nr;
{
Td *td;
- qh->state = Qdone;
qh->elink = QHterm;
+ coherence();
for(td = qh->tds; td != nil; td = td->next){
- if(td->csw & Tdactive)
+ if(td->csw & Tdactive){
td->ndata = 0;
- td->csw &= ~(Tdactive|Tdioc);
+ td->csw &= ~(Tdactive|Tdioc);
+ coherence();
+ }
}
}
else if(qh->state != Qdone && qh->state != Qclose)
panic("epio: queue not done and not closed");
if(timedout){
- aborttds(io->qh);
- io->err = "request timed out";
+ aborttds(qh);
+ qh->state = Qdone;
+ if(io->err == nil)
+ io->err = "request timed out";
iunlock(ctlr);
- if(!waserror()){
- tsleep(&up->sleep, return0, 0, Abortdelay);
- poperror();
- }
+ while(waserror())
+ ;
+ tsleep(&up->sleep, return0, 0, Abortdelay);
+ poperror();
ilock(ctlr);
}
if(qh->state != Qclose)
ulong load;
char *err;
- qh = io->qh;
ctlr = ep->hp->aux;
io->debug = ep->debug;
tmout = ep->tmout;
print("uchi epio: user data: %s\n", buf);
}
if(mustlock){
- qlock(io);
+ eqlock(io);
if(waserror()){
qunlock(io);
nexterror();
}
io->err = nil;
ilock(ctlr);
- if(qh->state == Qclose){ /* Tds released by cancelio */
+ qh = io->qh;
+ if(qh == nil || qh->state == Qclose){ /* Tds released by cancelio */
iunlock(ctlr);
error(io->err ? io->err : Eio);
}
if(debug > 1 || ep->debug > 1)
dumptd(td0, "epio: got tds: ");
+ err = io->err;
+
tot = 0;
c = a;
saved = 0;
if(saved++ == 0)
io->toggle = td->token & Tddata1;
}else{
- tot += td->ndata;
- if(c != nil && tdtok(td) == Tdtokin && td->ndata > 0){
- memmove(c, td->data, td->ndata);
- c += td->ndata;
+ n = td->ndata;
+ if(err == nil && n < 0)
+ err = Eio;
+ if(err == nil && n > 0 && tot < count){
+ if((tot + n) > count)
+ n = count - tot;
+ if(c != nil && tdtok(td) == Tdtokin){
+ memmove(c, td->data, n);
+ c += n;
+ }
+ tot += n;
}
}
ntd = td->next;
tdfree(td);
}
- err = io->err;
if(mustlock){
qunlock(io);
poperror();
io, ntds, tot, err);
if(err != nil)
error(err);
- if(tot < 0)
- error(Eio);
return tot;
}
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 comand");
- qlock(cio);
+ eqlock(cio);
free(cio->data);
cio->data = nil;
cio->ndata = 0;
case Tintr:
io = ep->aux = smalloc(sizeof(Qio)*2);
io[OREAD].debug = io[OWRITE].debug = ep->debug;
- usbid = ((ep->nb&Epmax)<<7)|(ep->dev->nb &Devmax);
+ usbid = ((ep->nb&Epmax)<<7)|(ep->dev->nb&Devmax);
if(ep->mode != OREAD){
if(ep->toggle[OWRITE] != 0)
io[OWRITE].toggle = Tddata1;
ilock(ctlr);
qh = io->qh;
- if(io == nil || io->qh == nil || io->qh->state == Qclose){
+ if(qh == nil || qh->state == Qclose){
iunlock(ctlr);
return;
}
aborttds(qh);
qh->state = Qclose;
iunlock(ctlr);
- if(!waserror()){
- tsleep(&up->sleep, return0, 0, Abortdelay);
- poperror();
- }
+
+ while(waserror())
+ ;
+ tsleep(&up->sleep, return0, 0, Abortdelay);
+ poperror();
wakeup(io);
qlock(io);
/* wait for epio if running */
+ if(io->qh == qh)
+ io->qh = nil;
qunlock(io);
qhfree(ctlr, qh);
- io->qh = nil;
}
static void
ctlr = hp->aux;
dprint("uhci: %#x port %d enable=%d\n", ctlr->port, port, on);
ioport = PORT(port-1);
- qlock(&ctlr->portlck);
+ eqlock(&ctlr->portlck);
if(waserror()){
qunlock(&ctlr->portlck);
nexterror();
ctlr = hp->aux;
ioport = PORT(port-1);
- qlock(&ctlr->portlck);
+ eqlock(&ctlr->portlck);
if(waserror()){
iunlock(ctlr);
qunlock(&ctlr->portlck);
continue;
switch(p->ccrp){
case 0:
- io = p->mem[4].bar & ~0x0F;
+ if((p->mem[4].bar & 1) == 0)
+ continue;
+ io = p->mem[4].bar & ~3;
break;
default:
continue;
print("usbuhci: port %#ux in use\n", io);
continue;
}
- if(p->intl == 0xFF || p->intl == 0){
- print("usbuhci: no irq assigned for port %#ux\n", io);
- continue;
- }
- dprint("uhci: %#x %#x: port %#ux size %#x irq %d\n",
+ print("uhci: %#x %#x: port %#ux size %#x irq %d\n",
p->vid, p->did, io, p->mem[4].size, p->intl);
- ctlr = smalloc(sizeof(Ctlr));
+ ctlr = malloc(sizeof(Ctlr));
+ if(ctlr == nil){
+ iofree(io);
+ print("usbuhci: no memory\n");
+ continue;
+ }
ctlr->pcidev = p;
ctlr->port = io;
for(i = 0; i < Nhcis; i++)
break;
}
if(i == Nhcis)
- print("uhci: bug: no more controllers\n");
+ print("usbuhci: bug: no more controllers\n");
}
}
return -1;
p = ctlr->pcidev;
+ pcienable(p);
+
hp->aux = ctlr;
hp->port = ctlr->port;
hp->irq = p->intl;
uhcireset(ctlr);
uhcimeminit(ctlr);
+ pcisetbme(p);
+
/*
* Linkage to the generic HCI driver.
*/
hp->shutdown = shutdown;
hp->debug = setdebug;
hp->type = "uhci";
+ intrenable(hp->irq, hp->interrupt, hp, hp->tbdf, hp->type);
+
return 0;
}