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