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