xref: /inferno-os/os/pc/usbuhci.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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