1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "io.h" 7 #include "../port/error.h" 8 9 #include "usb.h" 10 11 #define XPRINT if(debug)print 12 #define XXPRINT if(0)print 13 14 static int Chatty = 0; 15 static int debug = 0; 16 17 static char Estalled[] = "usb endpoint stalled"; 18 19 /* 20 * UHCI interface registers and bits 21 */ 22 enum 23 { 24 /* i/o space */ 25 Cmd = 0, 26 Status = 2, 27 Usbintr = 4, 28 Frnum = 6, 29 Flbaseadd = 8, 30 SOFMod = 0xC, 31 Portsc0 = 0x10, 32 Portsc1 = 0x12, 33 34 /* port status */ 35 Suspend = 1<<12, 36 PortReset = 1<<9, 37 SlowDevice = 1<<8, 38 ResumeDetect = 1<<6, 39 PortChange = 1<<3, /* write 1 to clear */ 40 PortEnable = 1<<2, 41 StatusChange = 1<<1, /* write 1 to clear */ 42 DevicePresent = 1<<0, 43 44 NFRAME = 1024, 45 FRAMESIZE= NFRAME*sizeof(ulong), /* fixed by hardware; aligned to same */ 46 47 Vf = 1<<2, /* TD only */ 48 IsQH = 1<<1, 49 Terminate = 1<<0, 50 51 /* TD.status */ 52 SPD = 1<<29, 53 ErrLimit0 = 0<<27, 54 ErrLimit1 = 1<<27, 55 ErrLimit2 = 2<<27, 56 ErrLimit3 = 3<<27, 57 LowSpeed = 1<<26, 58 IsoSelect = 1<<25, 59 IOC = 1<<24, 60 Active = 1<<23, 61 Stalled = 1<<22, 62 DataBufferErr = 1<<21, 63 Babbling = 1<<20, 64 NAKed = 1<<19, 65 CRCorTimeout = 1<<18, 66 BitstuffErr = 1<<17, 67 AnyError = (Stalled | DataBufferErr | Babbling | NAKed | CRCorTimeout | BitstuffErr), 68 69 /* TD.dev */ 70 IsDATA1 = 1<<19, 71 72 /* TD.flags (software) */ 73 CancelTD= 1<<0, 74 IsoClean= 1<<2, 75 }; 76 77 static struct 78 { 79 int bit; 80 char *name; 81 } 82 portstatus[] = 83 { 84 { Suspend, "suspend", }, 85 { PortReset, "reset", }, 86 { SlowDevice, "lowspeed", }, 87 { ResumeDetect, "resume", }, 88 { PortChange, "portchange", }, 89 { PortEnable, "enable", }, 90 { StatusChange, "statuschange", }, 91 { DevicePresent, "present", }, 92 }; 93 94 typedef struct Ctlr Ctlr; 95 typedef struct Endptx Endptx; 96 typedef struct QH QH; 97 typedef struct TD TD; 98 99 /* 100 * software structures 101 */ 102 struct Ctlr 103 { 104 Lock; /* protects state shared with interrupt (eg, free list) */ 105 Ctlr* next; 106 Pcidev* pcidev; 107 int active; 108 109 int io; 110 ulong* frames; /* frame list */ 111 ulong* frameld; /* real time load on each of the frame list entries */ 112 QLock resetl; /* lock controller during USB reset */ 113 114 TD* tdpool; 115 TD* freetd; 116 QH* qhpool; 117 QH* freeqh; 118 119 QH* ctlq; /* queue for control i/o */ 120 QH* bwsop; /* empty bandwidth sop (to PIIX4 errata specifications) */ 121 QH* bulkq; /* queue for bulk i/o (points back to bandwidth sop) */ 122 QH* recvq; /* receive queues for bulk i/o */ 123 124 Udev* ports[2]; 125 126 struct { 127 Lock; 128 Endpt* f; 129 } activends; 130 131 long usbints; /* debugging */ 132 long framenumber; 133 long frameptr; 134 long usbbogus; 135 }; 136 137 #define IN(x) ins(ctlr->io+(x)) 138 #define OUT(x, v) outs(ctlr->io+(x), (v)) 139 140 static Ctlr* ctlrhead; 141 static Ctlr* ctlrtail; 142 143 struct Endptx 144 { 145 QH* epq; /* queue of TDs for this endpoint */ 146 147 /* ISO related: */ 148 void* tdalloc; 149 void* bpalloc; 150 uchar* bp0; /* first block in array */ 151 TD* td0; /* first td in array */ 152 TD* etd; /* pointer into circular list of TDs for isochronous ept */ 153 TD* xtd; /* next td to be cleaned */ 154 }; 155 156 /* 157 * UHCI hardware structures, aligned on 16-byte boundary 158 */ 159 struct TD 160 { 161 ulong link; 162 ulong status; /* controller r/w */ 163 ulong dev; 164 ulong buffer; 165 166 /* software */ 167 ulong flags; 168 union{ 169 Block* bp; /* non-iso */ 170 ulong offset; /* iso */ 171 }; 172 Endpt* ep; 173 TD* next; 174 }; 175 #define TFOL(p) ((TD*)KADDR((ulong)(p) & ~(0xF|PCIWINDOW))) 176 177 struct QH 178 { 179 ulong head; 180 ulong entries; /* address of next TD or QH to process (updated by controller) */ 181 182 /* software */ 183 QH* hlink; 184 TD* first; 185 QH* next; /* free list */ 186 TD* last; 187 ulong _d1; /* fillers */ 188 ulong _d2; 189 }; 190 #define QFOL(p) ((QH*)KADDR((ulong)(p) & ~(0xF|PCIWINDOW))) 191 192 static TD * 193 alloctd(Ctlr *ctlr) 194 { 195 TD *t; 196 197 ilock(ctlr); 198 t = ctlr->freetd; 199 if(t == nil) 200 panic("alloctd"); /* TO DO */ 201 ctlr->freetd = t->next; 202 t->next = nil; 203 iunlock(ctlr); 204 t->ep = nil; 205 t->bp = nil; 206 t->status = 0; 207 t->link = Terminate; 208 t->buffer = 0; 209 t->flags = 0; 210 return t; 211 } 212 213 static void 214 freetd(Ctlr *ctlr, TD *t) 215 { 216 t->ep = nil; 217 if(t->bp) 218 freeb(t->bp); 219 t->bp = nil; 220 ilock(ctlr); 221 t->buffer = 0xdeadbeef; 222 t->next = ctlr->freetd; 223 ctlr->freetd = t; 224 iunlock(ctlr); 225 } 226 227 static void 228 dumpdata(Block *b, int n) 229 { 230 int i; 231 232 XPRINT("\tb %8.8lux[%d]: ", (ulong)b->rp, n); 233 if(n > 16) 234 n = 16; 235 for(i=0; i<n; i++) 236 XPRINT(" %2.2ux", b->rp[i]); 237 XPRINT("\n"); 238 } 239 240 static void 241 dumptd(TD *t, int follow) 242 { 243 int i, n; 244 char buf[20], *s; 245 TD *t0; 246 247 t0 = t; 248 while(t){ 249 i = t->dev & 0xFF; 250 if(i == TokOUT || i == TokSETUP) 251 n = ((t->dev>>21) + 1) & 0x7FF; 252 else if((t->status & Active) == 0) 253 n = (t->status + 1) & 0x7FF; 254 else 255 n = 0; 256 s = buf; 257 if(t->status & Active) 258 *s++ = 'A'; 259 if(t->status & Stalled) 260 *s++ = 'S'; 261 if(t->status & DataBufferErr) 262 *s++ = 'D'; 263 if(t->status & Babbling) 264 *s++ = 'B'; 265 if(t->status & NAKed) 266 *s++ = 'N'; 267 if(t->status & CRCorTimeout) 268 *s++ = 'T'; 269 if(t->status & BitstuffErr) 270 *s++ = 'b'; 271 if(t->status & LowSpeed) 272 *s++ = 'L'; 273 *s = 0; 274 XPRINT("td %8.8lux: ", t); 275 XPRINT("l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n", 276 t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags); 277 XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", 278 buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1); 279 if(debug && t->bp && (t->flags & CancelTD) == 0) 280 dumpdata(t->bp, n); 281 if(!follow || t->link & Terminate || t->link & IsQH) 282 break; 283 t = TFOL(t->link); 284 if(t == t0) 285 break; /* looped */ 286 } 287 } 288 289 static TD * 290 alloctde(Ctlr *ctlr, Endpt *e, int pid, int n) 291 { 292 TD *t; 293 int tog, id; 294 295 t = alloctd(ctlr); 296 id = (e->x<<7)|(e->dev->x&0x7F); 297 tog = 0; 298 if((pid == TokOUT && e->wdata01) || (pid == TokIN && e->rdata01)) 299 tog = IsDATA1; 300 t->ep = e; 301 t->status = ErrLimit3 | Active | IOC; /* or put IOC only on last? */ 302 if(e->dev->ls) 303 t->status |= LowSpeed; 304 t->dev = ((n-1)<<21) | ((id&0x7FF)<<8) | pid | tog; 305 return t; 306 } 307 308 static QH * 309 allocqh(Ctlr *ctlr) 310 { 311 QH *qh; 312 313 ilock(ctlr); 314 qh = ctlr->freeqh; 315 if(qh == nil) 316 panic("allocqh"); /* TO DO */ 317 ctlr->freeqh = qh->next; 318 qh->next = nil; 319 iunlock(ctlr); 320 qh->head = Terminate; 321 qh->entries = Terminate; 322 qh->hlink = nil; 323 qh->first = nil; 324 qh->last = nil; 325 return qh; 326 } 327 328 static void 329 freeqh(Ctlr *ctlr, QH *qh) 330 { 331 ilock(ctlr); 332 qh->next = ctlr->freeqh; 333 ctlr->freeqh = qh; 334 iunlock(ctlr); 335 } 336 337 static void 338 dumpqh(QH *q) 339 { 340 int i; 341 QH *q0; 342 343 q0 = q; 344 for(i = 0; q != nil && i < 10; i++){ 345 XPRINT("qh %8.8lux: %8.8lux %8.8lux\n", q, q->head, q->entries); 346 if((q->entries & (IsQH|Terminate)) == 0) 347 dumptd(TFOL(q->entries), 1); 348 if(q->head & Terminate) 349 break; 350 if((q->head & IsQH) == 0){ 351 XPRINT("head:"); 352 dumptd(TFOL(q->head), 1); 353 break; 354 } 355 q = QFOL(q->head); 356 if(q == q0) 357 break; /* looped */ 358 } 359 } 360 361 static void 362 queuetd(Ctlr *ctlr, QH *q, TD *t, int vf, char *why) 363 { 364 TD *lt; 365 366 for(lt = t; lt->next != nil; lt = lt->next) 367 lt->link = PCIWADDR(lt->next) | vf; 368 lt->link = Terminate; 369 ilock(ctlr); 370 XPRINT("queuetd %s: t=%p lt=%p q=%p first=%p last=%p entries=%.8lux\n", 371 why, t, lt, q, q->first, q->last, q->entries); 372 if(q->first != nil){ 373 q->last->link = PCIWADDR(t) | vf; 374 q->last->next = t; 375 }else{ 376 q->first = t; 377 q->entries = PCIWADDR(t); 378 } 379 q->last = lt; 380 XPRINT(" t=%p q=%p first=%p last=%p entries=%.8lux\n", 381 t, q, q->first, q->last, q->entries); 382 dumpqh(q); 383 iunlock(ctlr); 384 } 385 386 static void 387 cleantd(Ctlr *ctlr, TD *t, int discard) 388 { 389 Block *b; 390 int n, err; 391 392 XPRINT("cleanTD: %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); 393 if(t->ep != nil && t->ep->debug) 394 dumptd(t, 0); 395 if(t->status & Active) 396 panic("cleantd Active"); 397 err = t->status & (AnyError&~NAKed); 398 /* TO DO: on t->status&AnyError, q->entries will not have advanced */ 399 if (err) { 400 XPRINT("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); 401 // print("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer); 402 } 403 switch(t->dev&0xFF){ 404 case TokIN: 405 if(discard || (t->flags & CancelTD) || t->ep == nil || t->ep->x!=0&&err){ 406 if(t->ep != nil){ 407 if(err != 0) 408 t->ep->err = err==Stalled? Estalled: Eio; 409 wakeup(&t->ep->rr); /* in case anyone cares */ 410 } 411 break; 412 } 413 b = t->bp; 414 n = (t->status + 1) & 0x7FF; 415 if(n > b->lim - b->wp) 416 n = 0; 417 b->wp += n; 418 if(Chatty) 419 dumpdata(b, n); 420 t->bp = nil; 421 t->ep->nbytes += n; 422 t->ep->nblocks++; 423 qpass(t->ep->rq, b); /* TO DO: flow control */ 424 wakeup(&t->ep->rr); /* TO DO */ 425 break; 426 case TokSETUP: 427 XPRINT("cleanTD: TokSETUP %lux\n", &t->ep); 428 /* don't really need to wakeup: subsequent IN or OUT gives status */ 429 if(t->ep != nil) { 430 wakeup(&t->ep->wr); /* TO DO */ 431 XPRINT("cleanTD: wakeup %lux\n", &t->ep->wr); 432 } 433 break; 434 case TokOUT: 435 /* TO DO: mark it done somewhere */ 436 XPRINT("cleanTD: TokOut %lux\n", &t->ep); 437 if(t->ep != nil){ 438 if(t->bp){ 439 n = BLEN(t->bp); 440 t->ep->nbytes += n; 441 t->ep->nblocks++; 442 } 443 if(t->ep->x!=0 && err != 0) 444 t->ep->err = err==Stalled? Estalled: Eio; 445 if(--t->ep->ntd < 0) 446 panic("cleantd ntd"); 447 wakeup(&t->ep->wr); /* TO DO */ 448 XPRINT("cleanTD: wakeup %lux\n", &t->ep->wr); 449 } 450 break; 451 } 452 freetd(ctlr, t); 453 } 454 455 static void 456 cleanq(Ctlr *ctlr, QH *q, int discard, int vf) 457 { 458 TD *t, *tp; 459 460 ilock(ctlr); 461 tp = nil; 462 for(t = q->first; t != nil;){ 463 XPRINT("cleanq: %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer, t->flags, t->next); 464 if(t->status & Active){ 465 if(t->status & NAKed){ 466 t->status = (t->status & ~NAKed) | IOC; /* ensure interrupt next frame */ 467 tp = t; 468 t = t->next; 469 continue; 470 } 471 if(t->flags & CancelTD){ 472 XPRINT("cancelTD: %8.8lux\n", (ulong)t); 473 t->status = (t->status & ~Active) | IOC; /* ensure interrupt next frame */ 474 tp = t; 475 t = t->next; 476 continue; 477 } 478 tp = t; 479 t = t->next; 480 continue; 481 } 482 t->status &= ~IOC; 483 if (tp == nil) { 484 q->first = t->next; 485 if(q->first != nil) 486 q->entries = PCIWADDR(q->first); 487 else 488 q->entries = Terminate; 489 } else { 490 tp->next = t->next; 491 if (t->next != nil) 492 tp->link = PCIWADDR(t->next) | vf; 493 else 494 tp->link = Terminate; 495 } 496 if (q->last == t) 497 q->last = tp; 498 iunlock(ctlr); 499 cleantd(ctlr, t, discard); 500 ilock(ctlr); 501 if (tp) 502 t = tp->next; 503 else 504 t = q->first; 505 XPRINT("t = %8.8lux\n", t); 506 dumpqh(q); 507 } 508 if(q->first && q->entries != PCIWADDR(q->first)){ 509 ctlr->usbbogus++; 510 q->entries = PCIWADDR(q->first); 511 } 512 iunlock(ctlr); 513 } 514 515 static void 516 canceltds(Ctlr *ctlr, QH *q, Endpt *e) 517 { 518 TD *t; 519 520 if(q != nil){ 521 ilock(ctlr); 522 for(t = q->first; t != nil; t = t->next) 523 if(t->ep == e) 524 t->flags |= CancelTD; 525 iunlock(ctlr); 526 XPRINT("cancel:\n"); 527 dumpqh(q); 528 } 529 } 530 531 static void 532 eptcancel(Ctlr *ctlr, Endpt *e) 533 { 534 Endptx *x; 535 536 if(e == nil) 537 return; 538 x = e->private; 539 canceltds(ctlr, x->epq, e); 540 canceltds(ctlr, ctlr->ctlq, e); 541 canceltds(ctlr, ctlr->bulkq, e); 542 } 543 544 static void 545 eptactivate(Ctlr *ctlr, Endpt *e) 546 { 547 ilock(&ctlr->activends); 548 if(e->active == 0){ 549 XPRINT("activate 0x%p\n", e); 550 e->active = 1; 551 e->activef = ctlr->activends.f; 552 ctlr->activends.f = e; 553 } 554 iunlock(&ctlr->activends); 555 } 556 557 static void 558 eptdeactivate(Ctlr *ctlr, Endpt *e) 559 { 560 Endpt **l; 561 562 /* could be O(1) but not worth it yet */ 563 ilock(&ctlr->activends); 564 if(e->active){ 565 e->active = 0; 566 XPRINT("deactivate 0x%p\n", e); 567 for(l = &ctlr->activends.f; *l != e; l = &(*l)->activef) 568 if(*l == nil){ 569 iunlock(&ctlr->activends); 570 panic("usb eptdeactivate"); 571 } 572 *l = e->activef; 573 } 574 iunlock(&ctlr->activends); 575 } 576 577 static void 578 queueqh(Ctlr *ctlr, QH *qh) 579 { 580 QH *q; 581 582 // See if it's already queued 583 for (q = ctlr->recvq->next; q; q = q->hlink) 584 if (q == qh) 585 return; 586 if ((qh->hlink = ctlr->recvq->next) == nil) 587 qh->head = Terminate; 588 else 589 qh->head = PCIWADDR(ctlr->recvq->next) | IsQH; 590 ctlr->recvq->next = qh; 591 ctlr->recvq->entries = PCIWADDR(qh) | IsQH; 592 } 593 594 static QH* 595 qxmit(Ctlr *ctlr, Endpt *e, Block *b, int pid) 596 { 597 TD *t; 598 int n, vf; 599 QH *qh; 600 Endptx *x; 601 602 x = e->private; 603 if(b != nil){ 604 n = BLEN(b); 605 t = alloctde(ctlr, e, pid, n); 606 t->bp = b; 607 t->buffer = PCIWADDR(b->rp); 608 }else 609 t = alloctde(ctlr, e, pid, 0); 610 ilock(ctlr); 611 e->ntd++; 612 iunlock(ctlr); 613 if(e->debug) pprint("QTD: %8.8lux n=%ld\n", t, b?BLEN(b): 0); 614 vf = 0; 615 if(e->x == 0){ 616 qh = ctlr->ctlq; 617 vf = 0; 618 }else if((qh = x->epq) == nil || e->mode != OWRITE){ 619 qh = ctlr->bulkq; 620 vf = Vf; 621 } 622 queuetd(ctlr, qh, t, vf, "qxmit"); 623 return qh; 624 } 625 626 static QH* 627 qrcv(Ctlr *ctlr, Endpt *e) 628 { 629 TD *t; 630 Block *b; 631 QH *qh; 632 int vf; 633 Endptx *x; 634 635 x = e->private; 636 t = alloctde(ctlr, e, TokIN, e->maxpkt); 637 b = allocb(e->maxpkt); 638 t->bp = b; 639 t->buffer = PCIWADDR(b->wp); 640 vf = 0; 641 if(e->x == 0){ 642 qh = ctlr->ctlq; 643 }else if((qh = x->epq) == nil || e->mode != OREAD){ 644 qh = ctlr->bulkq; 645 vf = Vf; 646 } 647 queuetd(ctlr, qh, t, vf, "qrcv"); 648 return qh; 649 } 650 651 static int 652 usbsched(Ctlr *ctlr, int pollms, ulong load) 653 { 654 int i, d, q; 655 ulong best, worst; 656 657 best = 1000000; 658 q = -1; 659 for (d = 0; d < pollms; d++){ 660 worst = 0; 661 for (i = d; i < NFRAME; i++){ 662 if (ctlr->frameld[i] + load > worst) 663 worst = ctlr->frameld[i] + load; 664 } 665 if (worst < best){ 666 best = worst; 667 q = d; 668 } 669 } 670 return q; 671 } 672 673 static int 674 schedendpt(Ctlr *ctlr, Endpt *e) 675 { 676 TD *td; 677 Endptx *x; 678 uchar *bp; 679 int i, id, ix, size, frnum; 680 681 if(!e->iso || e->sched >= 0) 682 return 0; 683 684 if (e->active){ 685 return -1; 686 } 687 e->off = 0; 688 e->sched = usbsched(ctlr, e->pollms, e->maxpkt); 689 if(e->sched < 0) 690 return -1; 691 692 x = e->private; 693 if (x->tdalloc || x->bpalloc) 694 panic("usb: tdalloc/bpalloc"); 695 x->tdalloc = mallocz(0x10 + NFRAME*sizeof(TD), 1); 696 x->bpalloc = mallocz(0x10 + e->maxpkt*NFRAME/e->pollms, 1); 697 x->td0 = (TD*)(((ulong)x->tdalloc + 0xf) & ~0xf); 698 x->bp0 = (uchar *)(((ulong)x->bpalloc + 0xf) & ~0xf); 699 frnum = (IN(Frnum) + 1) & 0x3ff; 700 frnum = (frnum & ~(e->pollms - 1)) + e->sched; 701 x->xtd = &x->td0[(frnum+8)&0x3ff]; /* Next td to finish */ 702 x->etd = nil; 703 e->remain = 0; 704 e->nbytes = 0; 705 td = x->td0; 706 for(i = e->sched; i < NFRAME; i += e->pollms){ 707 bp = x->bp0 + e->maxpkt*i/e->pollms; 708 td->buffer = PCIWADDR(bp); 709 td->ep = e; 710 td->next = &td[1]; 711 ctlr->frameld[i] += e->maxpkt; 712 td++; 713 } 714 td[-1].next = x->td0; 715 for(i = e->sched; i < NFRAME; i += e->pollms){ 716 ix = (frnum+i) & 0x3ff; 717 td = &x->td0[ix]; 718 719 id = (e->x<<7)|(e->dev->x&0x7F); 720 if (e->mode == OREAD) 721 /* enable receive on this entry */ 722 td->dev = ((e->maxpkt-1)<<21) | ((id&0x7FF)<<8) | TokIN; 723 else{ 724 size = (e->hz + e->remain)*e->pollms/1000; 725 e->remain = (e->hz + e->remain)*e->pollms%1000; 726 size *= e->samplesz; 727 td->dev = ((size-1)<<21) | ((id&0x7FF)<<8) | TokOUT; 728 } 729 td->status = ErrLimit1 | Active | IsoSelect | IOC; 730 td->link = ctlr->frames[ix]; 731 td->flags |= IsoClean; 732 ctlr->frames[ix] = PCIWADDR(td); 733 } 734 return 0; 735 } 736 737 static void 738 unschedendpt(Ctlr *ctlr, Endpt *e) 739 { 740 int q; 741 TD *td; 742 Endptx *x; 743 ulong *addr; 744 745 if(!e->iso || e->sched < 0) 746 return; 747 748 x = e->private; 749 if (x->tdalloc == nil) 750 panic("tdalloc"); 751 for (q = e->sched; q < NFRAME; q += e->pollms){ 752 td = x->td0++; 753 addr = &ctlr->frames[q]; 754 while(*addr != PADDR(td)) { 755 if(*addr & IsQH) 756 panic("usb: TD expected"); 757 addr = &TFOL(*addr)->link; 758 } 759 *addr = td->link; 760 ctlr->frameld[q] -= e->maxpkt; 761 } 762 free(x->tdalloc); 763 free(x->bpalloc); 764 x->tdalloc = nil; 765 x->bpalloc = nil; 766 x->etd = nil; 767 x->td0 = nil; 768 e->sched = -1; 769 } 770 771 static void 772 epalloc(Usbhost *uh, Endpt *e) 773 { 774 Endptx *x; 775 776 x = malloc(sizeof(Endptx)); 777 e->private = x; 778 x->epq = allocqh(uh->ctlr); 779 if(x->epq == nil) 780 panic("devendptx"); 781 } 782 783 static void 784 epfree(Usbhost *uh, Endpt *e) 785 { 786 Ctlr *ctlr; 787 Endptx *x; 788 789 ctlr = uh->ctlr; 790 x = e->private; 791 if(x->epq != nil) 792 freeqh(ctlr, x->epq); 793 } 794 795 static void 796 epopen(Usbhost *uh, Endpt *e) 797 { 798 Ctlr *ctlr; 799 800 ctlr = uh->ctlr; 801 if(e->iso && e->active) 802 error("already open"); 803 if(schedendpt(ctlr, e) < 0){ 804 if(e->active) 805 error("cannot schedule USB endpoint, active"); 806 else 807 error("cannot schedule USB endpoint"); 808 } 809 eptactivate(ctlr, e); 810 } 811 812 static void 813 epclose(Usbhost *uh, Endpt *e) 814 { 815 Ctlr *ctlr; 816 817 ctlr = uh->ctlr; 818 eptdeactivate(ctlr, e); 819 unschedendpt(ctlr, e); 820 } 821 822 static void 823 epmode(Usbhost *uh, Endpt *e) 824 { 825 Ctlr *ctlr; 826 Endptx *x; 827 828 ctlr = uh->ctlr; 829 x = e->private; 830 if(e->iso) { 831 if(x->epq != nil) { 832 freeqh(ctlr, x->epq); 833 x->epq = nil; 834 } 835 } 836 else { 837 /* Each bulk device gets a queue head hanging off the 838 * bulk queue head 839 */ 840 if(x->epq == nil) { 841 x->epq = allocqh(ctlr); 842 if(x->epq == nil) 843 panic("epbulk: allocqh"); 844 } 845 queueqh(ctlr, x->epq); 846 } 847 } 848 849 static int ioport[] = {-1, Portsc0, Portsc1}; 850 851 static void 852 portreset(Usbhost *uh, int port) 853 { 854 int i, p; 855 Ctlr *ctlr; 856 857 ctlr = uh->ctlr; 858 if(port != 1 && port != 2) 859 error(Ebadarg); 860 861 /* should check that device not being configured on other port? */ 862 p = ioport[port]; 863 qlock(&ctlr->resetl); 864 if(waserror()){ 865 qunlock(&ctlr->resetl); 866 nexterror(); 867 } 868 XPRINT("r: %x\n", IN(p)); 869 ilock(ctlr); 870 OUT(p, PortReset); 871 delay(12); /* BUG */ 872 XPRINT("r2: %x\n", IN(p)); 873 OUT(p, IN(p) & ~PortReset); 874 XPRINT("r3: %x\n", IN(p)); 875 OUT(p, IN(p) | PortEnable); 876 microdelay(64); 877 for(i=0; i<1000 && (IN(p) & PortEnable) == 0; i++) 878 ; 879 XPRINT("r': %x %d\n", IN(p), i); 880 OUT(p, (IN(p) & ~PortReset)|PortEnable); 881 iunlock(ctlr); 882 poperror(); 883 qunlock(&ctlr->resetl); 884 } 885 886 static void 887 portenable(Usbhost *uh, int port, int on) 888 { 889 int w, p; 890 Ctlr *ctlr; 891 892 ctlr = uh->ctlr; 893 if(port != 1 && port != 2) 894 error(Ebadarg); 895 896 /* should check that device not being configured on other port? */ 897 p = ioport[port]; 898 qlock(&ctlr->resetl); 899 if(waserror()){ 900 qunlock(&ctlr->resetl); 901 nexterror(); 902 } 903 ilock(ctlr); 904 w = IN(p); 905 if(on) 906 w |= PortEnable; 907 else 908 w &= ~PortEnable; 909 OUT(p, w); 910 microdelay(64); 911 iunlock(ctlr); 912 XPRINT("e: %x\n", IN(p)); 913 poperror(); 914 qunlock(&ctlr->resetl); 915 } 916 917 static void 918 portinfo(Usbhost *uh, char *s, char *se) 919 { 920 int x, i, j; 921 Ctlr *ctlr; 922 923 ctlr = uh->ctlr; 924 for(i = 1; i <= 2; i++) { 925 ilock(ctlr); 926 x = IN(ioport[i]); 927 if((x & (PortChange|StatusChange)) != 0) 928 OUT(ioport[i], x); 929 iunlock(ctlr); 930 s = seprint(s, se, "%d %ux", i, x); 931 for(j = 0; j < nelem(portstatus); j++) { 932 if((x & portstatus[j].bit) != 0) 933 s = seprint(s, se, " %s", portstatus[j].name); 934 } 935 s = seprint(s, se, "\n"); 936 } 937 } 938 939 static void 940 cleaniso(Endpt *e, int frnum) 941 { 942 TD *td; 943 int id, n, i; 944 Endptx *x; 945 uchar *bp; 946 947 x = e->private; 948 td = x->xtd; 949 if (td->status & Active) 950 return; 951 id = (e->x<<7)|(e->dev->x&0x7F); 952 do { 953 if (td->status & AnyError) 954 XPRINT("usbisoerror 0x%lux\n", td->status); 955 n = (td->status + 1) & 0x3ff; 956 e->nbytes += n; 957 if ((td->flags & IsoClean) == 0) 958 e->nblocks++; 959 if (e->mode == OREAD){ 960 e->buffered += n; 961 e->poffset += (td->status + 1) & 0x3ff; 962 td->offset = e->poffset; 963 td->dev = ((e->maxpkt -1)<<21) | ((id&0x7FF)<<8) | TokIN; 964 e->toffset = td->offset; 965 }else{ 966 if ((td->flags & IsoClean) == 0){ 967 e->buffered -= n; 968 if (e->buffered < 0){ 969 // print("e->buffered %d?\n", e->buffered); 970 e->buffered = 0; 971 } 972 } 973 e->toffset = td->offset; 974 n = (e->hz + e->remain)*e->pollms/1000; 975 e->remain = (e->hz + e->remain)*e->pollms%1000; 976 n *= e->samplesz; 977 td->dev = ((n -1)<<21) | ((id&0x7FF)<<8) | TokOUT; 978 td->offset = e->poffset; 979 e->poffset += n; 980 } 981 td = td->next; 982 if (x->xtd == td){ 983 XPRINT("@"); 984 break; 985 } 986 } while ((td->status & Active) == 0); 987 e->time = todget(nil); 988 x->xtd = td; 989 for (n = 2; n < 4; n++){ 990 i = ((frnum + n)&0x3ff); 991 td = x->td0 + i; 992 bp = x->bp0 + e->maxpkt*i/e->pollms; 993 if (td->status & Active) 994 continue; 995 996 if (e->mode == OWRITE){ 997 if (td == x->etd) { 998 XPRINT("*"); 999 memset(bp+e->off, 0, e->maxpkt-e->off); 1000 if (e->off == 0) 1001 td->flags |= IsoClean; 1002 else 1003 e->buffered += (((td->dev>>21) +1) & 0x3ff) - e->off; 1004 x->etd = nil; 1005 }else if ((td->flags & IsoClean) == 0){ 1006 XPRINT("-"); 1007 memset(bp, 0, e->maxpkt); 1008 td->flags |= IsoClean; 1009 } 1010 } else { 1011 /* Unread bytes are now lost */ 1012 e->buffered -= (td->status + 1) & 0x3ff; 1013 } 1014 td->status = ErrLimit1 | Active | IsoSelect | IOC; 1015 } 1016 wakeup(&e->wr); 1017 } 1018 1019 static void 1020 interrupt(Ureg*, void *a) 1021 { 1022 QH *q; 1023 Ctlr *ctlr; 1024 Endpt *e; 1025 Endptx *x; 1026 int s, frnum; 1027 Usbhost *uh; 1028 1029 uh = a; 1030 ctlr = uh->ctlr; 1031 s = IN(Status); 1032 ctlr->frameptr = inl(ctlr->io+Flbaseadd); 1033 ctlr->framenumber = IN(Frnum) & 0x3ff; 1034 OUT(Status, s); 1035 if ((s & 0x1f) == 0) 1036 return; 1037 ctlr->usbints++; 1038 frnum = IN(Frnum) & 0x3ff; 1039 if (s & 0x1a) { 1040 XPRINT("cmd #%x sofmod #%x\n", IN(Cmd), inb(ctlr->io+SOFMod)); 1041 XPRINT("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1)); 1042 } 1043 1044 ilock(&ctlr->activends); 1045 for(e = ctlr->activends.f; e != nil; e = e->activef) { 1046 x = e->private; 1047 if(!e->iso && x->epq != nil) { 1048 XXPRINT("cleanq(ctlr, x->epq, 0, 0)\n"); 1049 cleanq(ctlr, x->epq, 0, 0); 1050 } 1051 if(e->iso) { 1052 XXPRINT("cleaniso(e)\n"); 1053 cleaniso(e, frnum); 1054 } 1055 } 1056 iunlock(&ctlr->activends); 1057 XXPRINT("cleanq(ctlr, ctlr->ctlq, 0, 0)\n"); 1058 cleanq(ctlr, ctlr->ctlq, 0, 0); 1059 XXPRINT("cleanq(ctlr, ctlr->bulkq, 0, Vf)\n"); 1060 cleanq(ctlr, ctlr->bulkq, 0, Vf); 1061 XXPRINT("clean recvq\n"); 1062 for (q = ctlr->recvq->next; q; q = q->hlink) { 1063 XXPRINT("cleanq(ctlr, q, 0, Vf)\n"); 1064 cleanq(ctlr, q, 0, Vf); 1065 } 1066 } 1067 1068 static int 1069 eptinput(void *arg) 1070 { 1071 Endpt *e; 1072 1073 e = arg; 1074 return e->eof || e->err || qcanread(e->rq); 1075 } 1076 1077 static int 1078 isoready(void *a) 1079 { 1080 Endptx *x; 1081 TD *etd; 1082 1083 x = a; 1084 return (etd = x->etd) == nil || (etd != x->xtd && (etd->status & Active) == 0); 1085 } 1086 1087 static long 1088 isoio(Ctlr *ctlr, Endpt *e, void *a, long n, ulong offset, int w) 1089 { 1090 TD *td; 1091 Endptx *x; 1092 int i, frnum; 1093 uchar *p, *q, *bp; 1094 volatile int isolock; 1095 1096 x = e->private; 1097 qlock(&e->rlock); 1098 isolock = 0; 1099 if(waserror()){ 1100 if (isolock){ 1101 isolock = 0; 1102 iunlock(&ctlr->activends); 1103 } 1104 qunlock(&e->rlock); 1105 eptcancel(ctlr, e); 1106 nexterror(); 1107 } 1108 p = a; 1109 if (offset != 0 && offset != e->foffset){ 1110 iprint("offset %lud, foffset %lud\n", offset, e->foffset); 1111 /* Seek to a specific position */ 1112 frnum = (IN(Frnum) + 8) & 0x3ff; 1113 td = x->td0 +frnum; 1114 if (offset < td->offset) 1115 error("ancient history"); 1116 while (offset > e->toffset){ 1117 tsleep(&e->wr, return0, 0, 500); 1118 } 1119 while (offset >= td->offset + ((w?(td->dev >> 21):td->status) + 1) & 0x7ff){ 1120 td = td->next; 1121 if (td == x->xtd) 1122 iprint("trouble\n"); 1123 } 1124 ilock(&ctlr->activends); 1125 isolock = 1; 1126 e->off = td->offset - offset; 1127 if (e->off >= e->maxpkt){ 1128 iprint("I can't program: %d\n", e->off); 1129 e->off = 0; 1130 } 1131 x->etd = td; 1132 e->foffset = offset; 1133 } 1134 do { 1135 if (isolock == 0){ 1136 ilock(&ctlr->activends); 1137 isolock = 1; 1138 } 1139 td = x->etd; 1140 if (td == nil || e->off == 0){ 1141 if (td == nil){ 1142 XPRINT("0"); 1143 if (w){ 1144 frnum = (IN(Frnum) + 1) & 0x3ff; 1145 td = x->td0 + frnum; 1146 while(td->status & Active) 1147 td = td->next; 1148 }else{ 1149 frnum = (IN(Frnum) - 4) & 0x3ff; 1150 td = x->td0 + frnum; 1151 while(td->next != x->xtd) 1152 td = td->next; 1153 } 1154 x->etd = td; 1155 e->off = 0; 1156 }else{ 1157 /* New td, make sure it's ready */ 1158 while (isoready(x) == 0){ 1159 isolock = 0; 1160 iunlock(&ctlr->activends); 1161 sleep(&e->wr, isoready, x); 1162 ilock(&ctlr->activends); 1163 isolock = 1; 1164 } 1165 if (x->etd == nil){ 1166 XPRINT("!"); 1167 continue; 1168 } 1169 } 1170 if (w) 1171 e->psize = ((td->dev >> 21) + 1) & 0x7ff; 1172 else 1173 e->psize = (x->etd->status + 1) & 0x7ff; 1174 if(e->psize > e->maxpkt) 1175 panic("packet size > maximum"); 1176 } 1177 if((i = n) >= e->psize) 1178 i = e->psize; 1179 if (w) 1180 e->buffered += i; 1181 else{ 1182 e->buffered -= i; 1183 if (e->buffered < 0) 1184 e->buffered = 0; 1185 } 1186 isolock = 0; 1187 iunlock(&ctlr->activends); 1188 td->flags &= ~IsoClean; 1189 bp = x->bp0 + (td - x->td0) * e->maxpkt / e->pollms; 1190 q = bp + e->off; 1191 if (w){ 1192 memmove(q, p, i); 1193 }else{ 1194 memmove(p, q, i); 1195 } 1196 p += i; 1197 n -= i; 1198 e->off += i; 1199 e->psize -= i; 1200 if (e->psize){ 1201 if (n != 0) 1202 panic("usb iso: can't happen"); 1203 break; 1204 } 1205 if(w) 1206 td->offset = offset + (p-(uchar*)a) - (((td->dev >> 21) + 1) & 0x7ff); 1207 td->status = ErrLimit3 | Active | IsoSelect | IOC; 1208 x->etd = td->next; 1209 e->off = 0; 1210 } while(n > 0); 1211 n = p-(uchar*)a; 1212 e->foffset += n; 1213 poperror(); 1214 if (isolock) 1215 iunlock(&ctlr->activends); 1216 qunlock(&e->rlock); 1217 return n; 1218 } 1219 1220 static long 1221 read(Usbhost *uh, Endpt *e, void *a, long n, vlong offset) 1222 { 1223 long l, i; 1224 Block *b; 1225 Ctlr *ctlr; 1226 uchar *p; 1227 1228 ctlr = uh->ctlr; 1229 if(e->iso) 1230 return isoio(ctlr, e, a, n, (ulong)offset, 0); 1231 1232 XPRINT("qlock(%p)\n", &e->rlock); 1233 qlock(&e->rlock); 1234 XPRINT("got qlock(%p)\n", &e->rlock); 1235 if(waserror()){ 1236 qunlock(&e->rlock); 1237 eptcancel(ctlr, e); 1238 nexterror(); 1239 } 1240 p = a; 1241 do { 1242 if(e->eof) { 1243 XPRINT("e->eof\n"); 1244 break; 1245 } 1246 if(e->err) 1247 error(e->err); 1248 qrcv(ctlr, e); 1249 if(!e->iso) 1250 e->rdata01 ^= 1; 1251 sleep(&e->rr, eptinput, e); 1252 if(e->err) 1253 error(e->err); 1254 b = qget(e->rq); /* TO DO */ 1255 if(b == nil) { 1256 XPRINT("b == nil\n"); 1257 break; 1258 } 1259 if(waserror()){ 1260 freeb(b); 1261 nexterror(); 1262 } 1263 l = BLEN(b); 1264 if((i = l) > n) 1265 i = n; 1266 if(i > 0){ 1267 memmove(p, b->rp, i); 1268 p += i; 1269 } 1270 poperror(); 1271 freeb(b); 1272 n -= i; 1273 if (l != e->maxpkt) 1274 break; 1275 } while (n > 0); 1276 poperror(); 1277 qunlock(&e->rlock); 1278 return p-(uchar*)a; 1279 } 1280 1281 static int 1282 qisempty(void *arg) 1283 { 1284 return ((QH*)arg)->entries & Terminate; 1285 } 1286 1287 static long 1288 write(Usbhost *uh, Endpt *e, void *a, long n, vlong offset, int tok) 1289 { 1290 int i, j; 1291 QH *qh; 1292 Block *b; 1293 Ctlr *ctlr; 1294 uchar *p; 1295 1296 ctlr = uh->ctlr; 1297 if(e->iso) 1298 return isoio(ctlr, e, a, n, (ulong)offset, 1); 1299 1300 p = a; 1301 qlock(&e->wlock); 1302 if(waserror()){ 1303 qunlock(&e->wlock); 1304 eptcancel(ctlr, e); 1305 nexterror(); 1306 } 1307 do { 1308 if(e->err) 1309 error(e->err); 1310 if((i = n) >= e->maxpkt) 1311 i = e->maxpkt; 1312 b = allocb(i); 1313 if(waserror()){ 1314 freeb(b); 1315 nexterror(); 1316 } 1317 XPRINT("out [%d]", i); 1318 for (j = 0; j < i; j++) XPRINT(" %.2x", p[j]); 1319 XPRINT("\n"); 1320 memmove(b->wp, p, i); 1321 b->wp += i; 1322 p += i; 1323 n -= i; 1324 poperror(); 1325 qh = qxmit(ctlr, e, b, tok); 1326 tok = TokOUT; 1327 e->wdata01 ^= 1; 1328 if(e->ntd >= e->nbuf) { 1329 XPRINT("qh %s: q=%p first=%p last=%p entries=%.8lux\n", 1330 "writeusb sleep", qh, qh->first, qh->last, qh->entries); 1331 XPRINT("write: sleep %lux\n", &e->wr); 1332 sleep(&e->wr, qisempty, qh); 1333 XPRINT("write: awake\n"); 1334 } 1335 } while(n > 0); 1336 poperror(); 1337 qunlock(&e->wlock); 1338 return p-(uchar*)a; 1339 } 1340 1341 static void 1342 init(Usbhost* uh) 1343 { 1344 Ctlr *ctlr; 1345 1346 ctlr = uh->ctlr; 1347 ilock(ctlr); 1348 outl(ctlr->io+Flbaseadd, PCIWADDR(ctlr->frames)); 1349 OUT(Frnum, 0); 1350 OUT(Usbintr, 0xF); /* enable all interrupts */ 1351 XPRINT("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(ctlr->io+SOFMod)); 1352 XPRINT("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1)); 1353 if((IN(Cmd)&1)==0) 1354 OUT(Cmd, 1); /* run */ 1355 // pprint("at: c=%x s=%x c0=%x\n", IN(Cmd), IN(Status), IN(Portsc0)); 1356 iunlock(ctlr); 1357 } 1358 1359 static void 1360 scanpci(void) 1361 { 1362 int io; 1363 Ctlr *ctlr; 1364 Pcidev *p; 1365 static int already = 0; 1366 1367 if(already) 1368 return; 1369 already = 1; 1370 p = nil; 1371 while(p = pcimatch(p, 0, 0)) { 1372 /* 1373 * Find UHCI controllers. Class = 12 (serial controller), 1374 * Sub-class = 3 (USB) and Programming Interface = 0. 1375 */ 1376 if(p->ccrb != 0x0C || p->ccru != 0x03) 1377 continue; 1378 switch(p->ccrp){ 1379 case 0x00: 1380 io = p->mem[4].bar & ~0x0F; 1381 break; 1382 case 0x10: 1383 case 0x20: 1384 print("usb%chci: %x/%x %sport 0x%lux size 0x%x irq %d (ignored)\n", 1385 (p->ccrp == 0x10? 'o': 'e'), p->vid, p->did, 1386 (p->ccrp == 0x10? "": "USB 2 "), 1387 p->mem[0].bar & ~0x0F, p->mem[0].size, p->intl); 1388 /* fallthrough */ 1389 default: 1390 continue; 1391 } 1392 if(io == 0) { 1393 print("usbuhci: failed to map registers\n"); 1394 continue; 1395 } 1396 if(ioalloc(io, p->mem[4].size, 0, "usbuhci") < 0){ 1397 print("usbuhci: port %d in use\n", io); 1398 continue; 1399 } 1400 if(p->intl == 0xFF || p->intl == 0) { 1401 print("usbuhci: no irq assigned for port %d\n", io); 1402 continue; 1403 } 1404 1405 XPRINT("usbuhci: %x/%x port 0x%ux size 0x%x irq %d\n", 1406 p->vid, p->did, io, p->mem[4].size, p->intl); 1407 1408 ctlr = malloc(sizeof(Ctlr)); 1409 ctlr->pcidev = p; 1410 ctlr->io = io; 1411 if(ctlrhead != nil) 1412 ctlrtail->next = ctlr; 1413 else 1414 ctlrhead = ctlr; 1415 ctlrtail = ctlr; 1416 } 1417 } 1418 1419 static int 1420 reset(Usbhost *uh) 1421 { 1422 int i; 1423 TD *t; 1424 ulong io; 1425 Ctlr *ctlr; 1426 Pcidev *p; 1427 1428 scanpci(); 1429 1430 /* 1431 * Any adapter matches if no uh->port is supplied, 1432 * otherwise the ports must match. 1433 */ 1434 for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ 1435 if(ctlr->active) 1436 continue; 1437 if(uh->port == 0 || uh->port == ctlr->io){ 1438 ctlr->active = 1; 1439 break; 1440 } 1441 } 1442 if(ctlr == nil) 1443 return -1; 1444 1445 io = ctlr->io; 1446 p = ctlr->pcidev; 1447 1448 uh->ctlr = ctlr; 1449 uh->port = io; 1450 uh->irq = p->intl; 1451 uh->tbdf = p->tbdf; 1452 1453 XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n", 1454 IN(Cmd), IN(Status), IN(Usbintr), inb(io+Frnum)); 1455 XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n", 1456 IN(Flbaseadd), inb(io+SOFMod), IN(Portsc0), IN(Portsc1)); 1457 1458 OUT(Cmd, 0); /* stop */ 1459 while((IN(Status) & (1<<5)) == 0) /* wait for halt */ 1460 ; 1461 OUT(Status, 0xFF); /* clear pending interrupts */ 1462 pcicfgw16(p, 0xc0, 0x2000); /* legacy support register: turn off lunacy mode */ 1463 1464 if(0){ 1465 i = inb(io+SOFMod); 1466 OUT(Cmd, 4); /* global reset */ 1467 delay(15); 1468 OUT(Cmd, 0); /* end reset */ 1469 delay(4); 1470 outb(io+SOFMod, i); 1471 } 1472 1473 ctlr->tdpool = xspanalloc(128*sizeof(TD), 16, 0); 1474 for(i=128; --i>=0;){ 1475 ctlr->tdpool[i].next = ctlr->freetd; 1476 ctlr->freetd = &ctlr->tdpool[i]; 1477 } 1478 ctlr->qhpool = xspanalloc(64*sizeof(QH), 16, 0); 1479 for(i=64; --i>=0;){ 1480 ctlr->qhpool[i].next = ctlr->freeqh; 1481 ctlr->freeqh = &ctlr->qhpool[i]; 1482 } 1483 1484 /* 1485 * the last entries of the periodic (interrupt & isochronous) scheduling TD entries 1486 * points to the control queue and the bandwidth sop for bulk traffic. 1487 * this is looped following the instructions in PIIX4 errata 29773804.pdf: 1488 * a QH links to a looped but inactive TD as its sole entry, 1489 * with its head entry leading on to the bulk traffic, the last QH of which 1490 * links back to the empty QH. 1491 */ 1492 ctlr->ctlq = allocqh(ctlr); 1493 ctlr->bwsop = allocqh(ctlr); 1494 ctlr->bulkq = allocqh(ctlr); 1495 ctlr->recvq = allocqh(ctlr); 1496 t = alloctd(ctlr); /* inactive TD, looped */ 1497 t->link = PCIWADDR(t); 1498 ctlr->bwsop->entries = PCIWADDR(t); 1499 1500 ctlr->ctlq->head = PCIWADDR(ctlr->bulkq) | IsQH; 1501 ctlr->bulkq->head = PCIWADDR(ctlr->recvq) | IsQH; 1502 ctlr->recvq->head = PCIWADDR(ctlr->bwsop) | IsQH; 1503 if (1) /* don't use loop back */ 1504 ctlr->bwsop->head = Terminate; 1505 else /* set up loop back */ 1506 ctlr->bwsop->head = PCIWADDR(ctlr->bwsop) | IsQH; 1507 1508 ctlr->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0); 1509 ctlr->frameld = xallocz(FRAMESIZE, 1); 1510 for (i = 0; i < NFRAME; i++) 1511 ctlr->frames[i] = PCIWADDR(ctlr->ctlq) | IsQH; 1512 1513 /* 1514 * Linkage to the generic USB driver. 1515 */ 1516 uh->init = init; 1517 uh->interrupt = interrupt; 1518 1519 uh->portinfo = portinfo; 1520 uh->portreset = portreset; 1521 uh->portenable = portenable; 1522 1523 uh->epalloc = epalloc; 1524 uh->epfree = epfree; 1525 uh->epopen = epopen; 1526 uh->epclose = epclose; 1527 uh->epmode = epmode; 1528 1529 uh->read = read; 1530 uh->write = write; 1531 1532 return 0; 1533 } 1534 1535 void 1536 usbuhcilink(void) 1537 { 1538 addusbtype("uhci", reset); 1539 } 1540