xref: /plan9-contrib/sys/src/9/loongson/usbohci.c (revision a81c3ea0c7f009a3088ab7fe55ea9013d9d77a74)
1*a81c3ea0SDavid du Colombier /*
2*a81c3ea0SDavid du Colombier  * USB Open Host Controller Interface (Ohci) driver
3*a81c3ea0SDavid du Colombier  *
4*a81c3ea0SDavid du Colombier  * BUGS:
5*a81c3ea0SDavid du Colombier  * - Missing isochronous input streams.
6*a81c3ea0SDavid du Colombier  * - Too many delays and ilocks.
7*a81c3ea0SDavid du Colombier  * - bandwidth admission control must be done per-frame.
8*a81c3ea0SDavid du Colombier  * - Buffering could be handled like in uhci, to avoid
9*a81c3ea0SDavid du Colombier  * needed block allocation and avoid allocs for small Tds.
10*a81c3ea0SDavid du Colombier  * - must warn of power overruns.
11*a81c3ea0SDavid du Colombier  */
12*a81c3ea0SDavid du Colombier 
13*a81c3ea0SDavid du Colombier #include	"u.h"
14*a81c3ea0SDavid du Colombier #include	"../port/lib.h"
15*a81c3ea0SDavid du Colombier #include	"mem.h"
16*a81c3ea0SDavid du Colombier #include	"dat.h"
17*a81c3ea0SDavid du Colombier #include	"fns.h"
18*a81c3ea0SDavid du Colombier #include	"io.h"
19*a81c3ea0SDavid du Colombier #include	"../port/error.h"
20*a81c3ea0SDavid du Colombier 
21*a81c3ea0SDavid du Colombier #include	"../port/usb.h"
22*a81c3ea0SDavid du Colombier 
23*a81c3ea0SDavid du Colombier typedef struct Ctlio Ctlio;
24*a81c3ea0SDavid du Colombier typedef struct Ctlr Ctlr;
25*a81c3ea0SDavid du Colombier typedef struct Ed Ed;
26*a81c3ea0SDavid du Colombier typedef struct Edpool Edpool;
27*a81c3ea0SDavid du Colombier typedef struct Epx Epx;
28*a81c3ea0SDavid du Colombier typedef struct Hcca Hcca;
29*a81c3ea0SDavid du Colombier typedef struct Isoio Isoio;
30*a81c3ea0SDavid du Colombier typedef struct Ohci Ohci;
31*a81c3ea0SDavid du Colombier typedef struct Qio Qio;
32*a81c3ea0SDavid du Colombier typedef struct Qtree Qtree;
33*a81c3ea0SDavid du Colombier typedef struct Td Td;
34*a81c3ea0SDavid du Colombier typedef struct Tdpool Tdpool;
35*a81c3ea0SDavid du Colombier 
36*a81c3ea0SDavid du Colombier enum
37*a81c3ea0SDavid du Colombier {
38*a81c3ea0SDavid du Colombier 	Incr		= 64,		/* for Td and Ed pools */
39*a81c3ea0SDavid du Colombier 
40*a81c3ea0SDavid du Colombier 	Align		= 0x20,		/* OHCI only requires 0x10 */
41*a81c3ea0SDavid du Colombier 					/* use always a power of 2 */
42*a81c3ea0SDavid du Colombier 
43*a81c3ea0SDavid du Colombier 	Abortdelay	= 1,		/* delay after cancelling Tds (ms) */
44*a81c3ea0SDavid du Colombier 	Tdatomic		= 8,		/* max nb. of Tds per bulk I/O op. */
45*a81c3ea0SDavid du Colombier 	Enabledelay	= 100,		/* waiting for a port to enable */
46*a81c3ea0SDavid du Colombier 
47*a81c3ea0SDavid du Colombier 
48*a81c3ea0SDavid du Colombier 	/* Queue states (software) */
49*a81c3ea0SDavid du Colombier 	Qidle		= 0,
50*a81c3ea0SDavid du Colombier 	Qinstall,
51*a81c3ea0SDavid du Colombier 	Qrun,
52*a81c3ea0SDavid du Colombier 	Qdone,
53*a81c3ea0SDavid du Colombier 	Qclose,
54*a81c3ea0SDavid du Colombier 	Qfree,
55*a81c3ea0SDavid du Colombier 
56*a81c3ea0SDavid du Colombier 	/* Ed control bits */
57*a81c3ea0SDavid du Colombier 	Edmpsmask	= 0x7ff,	/* max packet size */
58*a81c3ea0SDavid du Colombier 	Edmpsshift	= 16,
59*a81c3ea0SDavid du Colombier 	Edlow		= 1 << 13,	/* low speed */
60*a81c3ea0SDavid du Colombier 	Edskip		= 1 << 14,	/* skip this ed */
61*a81c3ea0SDavid du Colombier 	Ediso		= 1 << 15,	/* iso Tds used */
62*a81c3ea0SDavid du Colombier 	Edtddir		= 0,		/* get dir from td */
63*a81c3ea0SDavid du Colombier 	Edin		= 2 << 11,	/* direction in */
64*a81c3ea0SDavid du Colombier 	Edout		= 1 << 11,	/* direction out */
65*a81c3ea0SDavid du Colombier 	Eddirmask	= 3 << 11,	/* direction bits */
66*a81c3ea0SDavid du Colombier 	Edhalt		= 1,		/* halted (in head ptr) */
67*a81c3ea0SDavid du Colombier 	Edtoggle	= 2,		/* toggle (in head ptr) 1 == data1 */
68*a81c3ea0SDavid du Colombier 
69*a81c3ea0SDavid du Colombier 	/* Td control bits */
70*a81c3ea0SDavid du Colombier 	Tdround		= 1<<18,	/* (rounding) short packets ok */
71*a81c3ea0SDavid du Colombier 	Tdtoksetup	= 0<<19,	/* setup packet */
72*a81c3ea0SDavid du Colombier 	Tdtokin		= 2<<19,	/* in packet */
73*a81c3ea0SDavid du Colombier 	Tdtokout	= 1<<19,	/* out packet */
74*a81c3ea0SDavid du Colombier 	Tdtokmask	= 3<<19,	/* in/out/setup bits */
75*a81c3ea0SDavid du Colombier 	Tdnoioc		= 7<<21,	/* intr. cnt. value for no interrupt */
76*a81c3ea0SDavid du Colombier 	Tdusetog	= 1<<25,	/* use toggle from Td (1) or Ed (0) */
77*a81c3ea0SDavid du Colombier 	Tddata1		= 1<<24,	/* data toggle (1 == data1) */
78*a81c3ea0SDavid du Colombier 	Tddata0		= 0<<24,
79*a81c3ea0SDavid du Colombier 	Tdfcmask	= 7,		/* frame count (iso) */
80*a81c3ea0SDavid du Colombier 	Tdfcshift	= 24,
81*a81c3ea0SDavid du Colombier 	Tdsfmask	= 0xFFFF,	/* starting frame (iso) */
82*a81c3ea0SDavid du Colombier 	Tderrmask	= 3,		/* error counter */
83*a81c3ea0SDavid du Colombier 	Tderrshift	= 26,
84*a81c3ea0SDavid du Colombier 	Tdccmask	= 0xf,		/* condition code (status) */
85*a81c3ea0SDavid du Colombier 	Tdccshift	= 28,
86*a81c3ea0SDavid du Colombier 	Tdiccmask	= 0xf,		/* condition code (iso, offsets) */
87*a81c3ea0SDavid du Colombier 	Tdiccshift	= 12,
88*a81c3ea0SDavid du Colombier 
89*a81c3ea0SDavid du Colombier 	Ntdframes	= 0x10000,	/* # of different iso frame numbers */
90*a81c3ea0SDavid du Colombier 
91*a81c3ea0SDavid du Colombier 	/* Td errors (condition code) */
92*a81c3ea0SDavid du Colombier 	Tdok		= 0,
93*a81c3ea0SDavid du Colombier 	Tdcrc		= 1,
94*a81c3ea0SDavid du Colombier 	Tdbitstuff	= 2,
95*a81c3ea0SDavid du Colombier 	Tdbadtog	= 3,
96*a81c3ea0SDavid du Colombier 	Tdstalled	= 4,
97*a81c3ea0SDavid du Colombier 	Tdtmout		= 5,
98*a81c3ea0SDavid du Colombier 	Tdpidchk	= 6,
99*a81c3ea0SDavid du Colombier 	Tdbadpid	= 7,
100*a81c3ea0SDavid du Colombier 	Tddataovr	= 8,
101*a81c3ea0SDavid du Colombier 	Tddataund	= 9,
102*a81c3ea0SDavid du Colombier 	Tdbufovr	= 0xC,
103*a81c3ea0SDavid du Colombier 	Tdbufund	= 0xD,
104*a81c3ea0SDavid du Colombier 	Tdnotacc	= 0xE,
105*a81c3ea0SDavid du Colombier 
106*a81c3ea0SDavid du Colombier 	/* control register */
107*a81c3ea0SDavid du Colombier 	Cple		= 0x04,		/* periodic list enable */
108*a81c3ea0SDavid du Colombier 	Cie		= 0x08,		/* iso. list enable */
109*a81c3ea0SDavid du Colombier 	Ccle		= 0x10,		/* ctl list enable */
110*a81c3ea0SDavid du Colombier 	Cble		= 0x20,		/* bulk list enable */
111*a81c3ea0SDavid du Colombier 	Cfsmask		= 3 << 6,	/* functional state... */
112*a81c3ea0SDavid du Colombier 	Cfsreset	= 0 << 6,
113*a81c3ea0SDavid du Colombier 	Cfsresume	= 1 << 6,
114*a81c3ea0SDavid du Colombier 	Cfsoper		= 2 << 6,
115*a81c3ea0SDavid du Colombier 	Cfssuspend	= 3 << 6,
116*a81c3ea0SDavid du Colombier 
117*a81c3ea0SDavid du Colombier 	/* command status */
118*a81c3ea0SDavid du Colombier 	Sblf =	1 << 2,			/* bulk list (load) flag */
119*a81c3ea0SDavid du Colombier 	Sclf =	1 << 1,			/* control list (load) flag */
120*a81c3ea0SDavid du Colombier 	Shcr =	1 << 0,			/* host controller reset */
121*a81c3ea0SDavid du Colombier 
122*a81c3ea0SDavid du Colombier 	/* intr enable */
123*a81c3ea0SDavid du Colombier 	Mie =	1 << 31,
124*a81c3ea0SDavid du Colombier 	Oc =	1 << 30,
125*a81c3ea0SDavid du Colombier 	Rhsc =	1 << 6,
126*a81c3ea0SDavid du Colombier 	Fno =	1 << 5,
127*a81c3ea0SDavid du Colombier 	Ue =	1 << 4,
128*a81c3ea0SDavid du Colombier 	Rd =	1 << 3,
129*a81c3ea0SDavid du Colombier 	Sf =	1 << 2,
130*a81c3ea0SDavid du Colombier 	Wdh =	1 << 1,
131*a81c3ea0SDavid du Colombier 	So =	1 << 0,
132*a81c3ea0SDavid du Colombier 
133*a81c3ea0SDavid du Colombier 	Fmaxpktmask = 0x7fff,
134*a81c3ea0SDavid du Colombier 	Fmaxpktshift = 16,
135*a81c3ea0SDavid du Colombier 	HcRhDescA_POTPGT_MASK =	0xff << 24,
136*a81c3ea0SDavid du Colombier 	HcRhDescA_POTPGT_SHIFT =	24,
137*a81c3ea0SDavid du Colombier 
138*a81c3ea0SDavid du Colombier 	/* Rh status */
139*a81c3ea0SDavid du Colombier 	Lps =	1 << 0,
140*a81c3ea0SDavid du Colombier 	Cgp =	1 << 0,
141*a81c3ea0SDavid du Colombier 	Oci =	1 << 1,
142*a81c3ea0SDavid du Colombier 	Psm =	1 << 8,
143*a81c3ea0SDavid du Colombier 	Nps =	1 << 9,
144*a81c3ea0SDavid du Colombier 	Drwe =	1 << 15,
145*a81c3ea0SDavid du Colombier 	Srwe =	1 << 15,
146*a81c3ea0SDavid du Colombier 	Lpsc =	1 << 16,
147*a81c3ea0SDavid du Colombier 	Ccic =	1 << 17,
148*a81c3ea0SDavid du Colombier 	Crwe =	1 << 31,
149*a81c3ea0SDavid du Colombier 
150*a81c3ea0SDavid du Colombier 	/* port status */
151*a81c3ea0SDavid du Colombier 	Ccs =	0x00001,	/* current connect status */
152*a81c3ea0SDavid du Colombier 	Pes =	0x00002,	/* port enable status */
153*a81c3ea0SDavid du Colombier 	Pss =	0x00004,	/* port suspend status */
154*a81c3ea0SDavid du Colombier 	Poci =	0x00008,	/* over current indicator */
155*a81c3ea0SDavid du Colombier 	Prs =	0x00010,	/* port reset status */
156*a81c3ea0SDavid du Colombier 	Pps =	0x00100,	/* port power status */
157*a81c3ea0SDavid du Colombier 	Lsda =	0x00200,	/* low speed device attached */
158*a81c3ea0SDavid du Colombier 	Csc =	0x10000,	/* connect status change */
159*a81c3ea0SDavid du Colombier 	Pesc =	0x20000,	/* enable status change */
160*a81c3ea0SDavid du Colombier 	Pssc =	0x40000,	/* suspend status change */
161*a81c3ea0SDavid du Colombier 	Ocic =	0x80000,	/* over current ind. change */
162*a81c3ea0SDavid du Colombier 	Prsc =	0x100000,	/* reset status change */
163*a81c3ea0SDavid du Colombier 
164*a81c3ea0SDavid du Colombier 	/* port status write bits */
165*a81c3ea0SDavid du Colombier 	Cpe =	0x001,		/* clear port enable */
166*a81c3ea0SDavid du Colombier 	Spe =	0x002,		/* set port enable */
167*a81c3ea0SDavid du Colombier 	Spr =	0x010,		/* set port reset */
168*a81c3ea0SDavid du Colombier 	Spp =	0x100,		/* set port power */
169*a81c3ea0SDavid du Colombier 	Cpp =	0x200,		/* clear port power */
170*a81c3ea0SDavid du Colombier 
171*a81c3ea0SDavid du Colombier };
172*a81c3ea0SDavid du Colombier 
173*a81c3ea0SDavid du Colombier /*
174*a81c3ea0SDavid du Colombier  * Endpoint descriptor. (first 4 words used by hardware)
175*a81c3ea0SDavid du Colombier  */
176*a81c3ea0SDavid du Colombier struct Ed {
177*a81c3ea0SDavid du Colombier 	ulong	ctrl;
178*a81c3ea0SDavid du Colombier 	ulong	tail;		/* transfer descriptor */
179*a81c3ea0SDavid du Colombier 	ulong	head;
180*a81c3ea0SDavid du Colombier 	ulong	nexted;
181*a81c3ea0SDavid du Colombier 
182*a81c3ea0SDavid du Colombier 	Ed*	next;		/* sw; in free list or next in list */
183*a81c3ea0SDavid du Colombier 	Td*	tds;		/* in use by current xfer; all for iso */
184*a81c3ea0SDavid du Colombier 	Ep*	ep;		/* debug/align */
185*a81c3ea0SDavid du Colombier 	Ed*	inext;		/* debug/align (dump interrupt eds). */
186*a81c3ea0SDavid du Colombier };
187*a81c3ea0SDavid du Colombier 
188*a81c3ea0SDavid du Colombier /*
189*a81c3ea0SDavid du Colombier  * Endpoint I/O state (software), per direction.
190*a81c3ea0SDavid du Colombier  */
191*a81c3ea0SDavid du Colombier struct Qio
192*a81c3ea0SDavid du Colombier {
193*a81c3ea0SDavid du Colombier 	QLock;			/* for the entire I/O process */
194*a81c3ea0SDavid du Colombier 	Rendez;			/* wait for completion */
195*a81c3ea0SDavid du Colombier 	Ed*	ed;		/* to place Tds on it */
196*a81c3ea0SDavid du Colombier 	int	sched;		/* queue number (intr/iso) */
197*a81c3ea0SDavid du Colombier 	int	toggle;		/* Tddata0/Tddata1 */
198*a81c3ea0SDavid du Colombier 	ulong	usbid;		/* device/endpoint address */
199*a81c3ea0SDavid du Colombier 	int	tok;		/* Tdsetup, Tdtokin, Tdtokout */
200*a81c3ea0SDavid du Colombier 	long	iotime;		/* last I/O time; to hold interrupt polls */
201*a81c3ea0SDavid du Colombier 	int	debug;		/* for the endpoint */
202*a81c3ea0SDavid du Colombier 	char*	err;		/* error status */
203*a81c3ea0SDavid du Colombier 	int	state;		/* Qidle -> Qinstall -> Qrun -> Qdone | Qclose */
204*a81c3ea0SDavid du Colombier 	long	bw;		/* load (intr/iso) */
205*a81c3ea0SDavid du Colombier };
206*a81c3ea0SDavid du Colombier 
207*a81c3ea0SDavid du Colombier struct Ctlio
208*a81c3ea0SDavid du Colombier {
209*a81c3ea0SDavid du Colombier 	Qio;			/* single Ed for all transfers */
210*a81c3ea0SDavid du Colombier 	uchar*	data;		/* read from last ctl req. */
211*a81c3ea0SDavid du Colombier 	int	ndata;		/* number of bytes read */
212*a81c3ea0SDavid du Colombier };
213*a81c3ea0SDavid du Colombier 
214*a81c3ea0SDavid du Colombier struct Isoio
215*a81c3ea0SDavid du Colombier {
216*a81c3ea0SDavid du Colombier 	Qio;
217*a81c3ea0SDavid du Colombier 	int	nframes;	/* number of frames for a full second */
218*a81c3ea0SDavid du Colombier 	Td*	atds;		/* Tds avail for further I/O */
219*a81c3ea0SDavid du Colombier 	int	navail;		/* number of avail Tds */
220*a81c3ea0SDavid du Colombier 	ulong	frno;		/* next frame number avail for I/O */
221*a81c3ea0SDavid du Colombier 	ulong	left;		/* remainder after rounding Hz to samples/ms */
222*a81c3ea0SDavid du Colombier 	int	nerrs;		/* consecutive errors on iso I/O */
223*a81c3ea0SDavid du Colombier };
224*a81c3ea0SDavid du Colombier 
225*a81c3ea0SDavid du Colombier /*
226*a81c3ea0SDavid du Colombier  * Transfer descriptor. Size must be multiple of 32
227*a81c3ea0SDavid du Colombier  * First block is used by hardware (aligned to 32).
228*a81c3ea0SDavid du Colombier  */
229*a81c3ea0SDavid du Colombier struct Td
230*a81c3ea0SDavid du Colombier {
231*a81c3ea0SDavid du Colombier 	ulong	ctrl;
232*a81c3ea0SDavid du Colombier 	ulong	cbp;		/* current buffer pointer */
233*a81c3ea0SDavid du Colombier 	ulong	nexttd;
234*a81c3ea0SDavid du Colombier 	ulong	be;
235*a81c3ea0SDavid du Colombier 	ushort	offsets[8];	/* used by Iso Tds only */
236*a81c3ea0SDavid du Colombier 
237*a81c3ea0SDavid du Colombier 	Td*	next;		/* in free or Ed tds list */
238*a81c3ea0SDavid du Colombier 	Td*	anext;		/* in avail td list (iso) */
239*a81c3ea0SDavid du Colombier 	Ep*	ep;		/* using this Td for I/O */
240*a81c3ea0SDavid du Colombier 	Qio*	io;		/* using this Td for I/O */
241*a81c3ea0SDavid du Colombier 	Block*	bp;		/* data for this Td */
242*a81c3ea0SDavid du Colombier 	ulong	nbytes;		/* bytes in this Td */
243*a81c3ea0SDavid du Colombier 	ulong	cbp0;		/* initial value for cbp */
244*a81c3ea0SDavid du Colombier 	ulong	last;		/* true for last Td in Qio */
245*a81c3ea0SDavid du Colombier };
246*a81c3ea0SDavid du Colombier 
247*a81c3ea0SDavid du Colombier /*
248*a81c3ea0SDavid du Colombier  * Host controller communication area (hardware)
249*a81c3ea0SDavid du Colombier  */
250*a81c3ea0SDavid du Colombier struct Hcca
251*a81c3ea0SDavid du Colombier {
252*a81c3ea0SDavid du Colombier 	ulong	intrtable[32];
253*a81c3ea0SDavid du Colombier 	ushort	framenumber;
254*a81c3ea0SDavid du Colombier 	ushort	pad1;
255*a81c3ea0SDavid du Colombier 	ulong	donehead;
256*a81c3ea0SDavid du Colombier 	uchar	reserved[116];
257*a81c3ea0SDavid du Colombier };
258*a81c3ea0SDavid du Colombier 
259*a81c3ea0SDavid du Colombier /*
260*a81c3ea0SDavid du Colombier  * I/O registers
261*a81c3ea0SDavid du Colombier  */
262*a81c3ea0SDavid du Colombier struct Ohci
263*a81c3ea0SDavid du Colombier {
264*a81c3ea0SDavid du Colombier 	/* control and status group */
265*a81c3ea0SDavid du Colombier 	ulong	revision;		/*00*/
266*a81c3ea0SDavid du Colombier 	ulong	control;		/*04*/
267*a81c3ea0SDavid du Colombier 	ulong	cmdsts;			/*08*/
268*a81c3ea0SDavid du Colombier 	ulong	intrsts;			/*0c*/
269*a81c3ea0SDavid du Colombier 	ulong	intrenable;		/*10*/
270*a81c3ea0SDavid du Colombier 	ulong	intrdisable;		/*14*/
271*a81c3ea0SDavid du Colombier 
272*a81c3ea0SDavid du Colombier 	/* memory pointer group */
273*a81c3ea0SDavid du Colombier 	ulong	hcca;			/*18*/
274*a81c3ea0SDavid du Colombier 	ulong	periodcurred;		/*1c*/
275*a81c3ea0SDavid du Colombier 	ulong	ctlheaded;		/*20*/
276*a81c3ea0SDavid du Colombier 	ulong	ctlcurred;		/*24*/
277*a81c3ea0SDavid du Colombier 	ulong	bulkheaded;		/*28*/
278*a81c3ea0SDavid du Colombier 	ulong	bulkcurred;		/*2c*/
279*a81c3ea0SDavid du Colombier 	ulong	donehead;		/*30*/
280*a81c3ea0SDavid du Colombier 
281*a81c3ea0SDavid du Colombier 	/* frame counter group */
282*a81c3ea0SDavid du Colombier 	ulong	fminterval;		/*34*/
283*a81c3ea0SDavid du Colombier 	ulong	fmremaining;		/*38*/
284*a81c3ea0SDavid du Colombier 	ulong	fmnumber;		/*3c*/
285*a81c3ea0SDavid du Colombier 	ulong	periodicstart;		/*40*/
286*a81c3ea0SDavid du Colombier 	ulong	lsthreshold;		/*44*/
287*a81c3ea0SDavid du Colombier 
288*a81c3ea0SDavid du Colombier 	/* root hub group */
289*a81c3ea0SDavid du Colombier 	ulong	rhdesca;		/*48*/
290*a81c3ea0SDavid du Colombier 	ulong	rhdescb;		/*4c*/
291*a81c3ea0SDavid du Colombier 	ulong	rhsts;			/*50*/
292*a81c3ea0SDavid du Colombier 	ulong	rhportsts[15];		/*54*/
293*a81c3ea0SDavid du Colombier 	ulong	pad25[20];		/*90*/
294*a81c3ea0SDavid du Colombier 
295*a81c3ea0SDavid du Colombier 	/* unknown */
296*a81c3ea0SDavid du Colombier 	ulong	hostueaddr;		/*e0*/
297*a81c3ea0SDavid du Colombier 	ulong	hostuests;		/*e4*/
298*a81c3ea0SDavid du Colombier 	ulong	hosttimeoutctrl;		/*e8*/
299*a81c3ea0SDavid du Colombier 	ulong	pad59;			/*ec*/
300*a81c3ea0SDavid du Colombier 	ulong	pad60;			/*f0*/
301*a81c3ea0SDavid du Colombier 	ulong	hostrevision;		/*f4*/
302*a81c3ea0SDavid du Colombier 	ulong	pad62[2];
303*a81c3ea0SDavid du Colombier 					/*100*/
304*a81c3ea0SDavid du Colombier };
305*a81c3ea0SDavid du Colombier 
306*a81c3ea0SDavid du Colombier /*
307*a81c3ea0SDavid du Colombier  * Endpoint tree (software)
308*a81c3ea0SDavid du Colombier  */
309*a81c3ea0SDavid du Colombier struct Qtree
310*a81c3ea0SDavid du Colombier {
311*a81c3ea0SDavid du Colombier 	int	nel;
312*a81c3ea0SDavid du Colombier 	int	depth;
313*a81c3ea0SDavid du Colombier 	ulong*	bw;
314*a81c3ea0SDavid du Colombier 	Ed**	root;
315*a81c3ea0SDavid du Colombier };
316*a81c3ea0SDavid du Colombier 
317*a81c3ea0SDavid du Colombier struct Tdpool
318*a81c3ea0SDavid du Colombier {
319*a81c3ea0SDavid du Colombier 	Lock;
320*a81c3ea0SDavid du Colombier 	Td*	free;
321*a81c3ea0SDavid du Colombier 	int	nalloc;
322*a81c3ea0SDavid du Colombier 	int	ninuse;
323*a81c3ea0SDavid du Colombier 	int	nfree;
324*a81c3ea0SDavid du Colombier };
325*a81c3ea0SDavid du Colombier 
326*a81c3ea0SDavid du Colombier struct Edpool
327*a81c3ea0SDavid du Colombier {
328*a81c3ea0SDavid du Colombier 	Lock;
329*a81c3ea0SDavid du Colombier 	Ed*	free;
330*a81c3ea0SDavid du Colombier 	int	nalloc;
331*a81c3ea0SDavid du Colombier 	int	ninuse;
332*a81c3ea0SDavid du Colombier 	int	nfree;
333*a81c3ea0SDavid du Colombier };
334*a81c3ea0SDavid du Colombier 
335*a81c3ea0SDavid du Colombier struct Ctlr
336*a81c3ea0SDavid du Colombier {
337*a81c3ea0SDavid du Colombier 	Lock;			/* for ilock; lists and basic ctlr I/O */
338*a81c3ea0SDavid du Colombier 	QLock	resetl;		/* lock controller during USB reset */
339*a81c3ea0SDavid du Colombier 	int	active;
340*a81c3ea0SDavid du Colombier 	Ctlr*	next;
341*a81c3ea0SDavid du Colombier 	int	nports;
342*a81c3ea0SDavid du Colombier 
343*a81c3ea0SDavid du Colombier 	Ohci*	ohci;		/* base I/O address */
344*a81c3ea0SDavid du Colombier 	Hcca*	hcca;		/* intr/done Td lists (used by hardware) */
345*a81c3ea0SDavid du Colombier 	int	overrun;	/* sched. overrun */
346*a81c3ea0SDavid du Colombier 	Ed*	intrhd;		/* list of intr. eds in tree */
347*a81c3ea0SDavid du Colombier 	Qtree*	tree;		/* tree for t Ep i/o */
348*a81c3ea0SDavid du Colombier 	int	ntree;		/* number of dummy Eds in tree */
349*a81c3ea0SDavid du Colombier 	Pcidev*	pcidev;
350*a81c3ea0SDavid du Colombier };
351*a81c3ea0SDavid du Colombier 
352*a81c3ea0SDavid du Colombier #define dqprint		if(debug || io && io->debug)print
353*a81c3ea0SDavid du Colombier #define ddqprint		if(debug>1 || (io && io->debug>1))print
354*a81c3ea0SDavid du Colombier #define diprint		if(debug || iso && iso->debug)print
355*a81c3ea0SDavid du Colombier #define ddiprint		if(debug>1 || (iso && iso->debug>1))print
356*a81c3ea0SDavid du Colombier #define TRUNC(x, sz)	((x) & ((sz)-1))
357*a81c3ea0SDavid du Colombier 
358*a81c3ea0SDavid du Colombier static int ohciinterrupts[Nttypes];
359*a81c3ea0SDavid du Colombier static char* iosname[] = { "idle", "install", "run", "done", "close", "FREE" };
360*a81c3ea0SDavid du Colombier 
361*a81c3ea0SDavid du Colombier static int debug;
362*a81c3ea0SDavid du Colombier static Edpool edpool;
363*a81c3ea0SDavid du Colombier static Tdpool tdpool;
364*a81c3ea0SDavid du Colombier static Ctlr* ctlrs[Nhcis];
365*a81c3ea0SDavid du Colombier 
366*a81c3ea0SDavid du Colombier static	QLock	usbhstate;	/* protects name space state */
367*a81c3ea0SDavid du Colombier 
368*a81c3ea0SDavid du Colombier static int	schedendpt(Ctlr *ub, Ep *ep);
369*a81c3ea0SDavid du Colombier static void	unschedendpt(Ctlr *ub, Ep *ep);
370*a81c3ea0SDavid du Colombier static long	qtd(Ctlr*, Ep*, int, Block*, uchar*, uchar*, int, ulong);
371*a81c3ea0SDavid du Colombier 
372*a81c3ea0SDavid du Colombier static char* errmsgs[] =
373*a81c3ea0SDavid du Colombier {
374*a81c3ea0SDavid du Colombier [Tdcrc]		"crc error",
375*a81c3ea0SDavid du Colombier [Tdbitstuff]	"bit stuffing error",
376*a81c3ea0SDavid du Colombier [Tdbadtog]	"bad toggle",
377*a81c3ea0SDavid du Colombier [Tdstalled]	Estalled,
378*a81c3ea0SDavid du Colombier [Tdtmout]	"timeout error",
379*a81c3ea0SDavid du Colombier [Tdpidchk]	"pid check error",
380*a81c3ea0SDavid du Colombier [Tdbadpid]	"bad pid",
381*a81c3ea0SDavid du Colombier [Tddataovr]	"data overrun",
382*a81c3ea0SDavid du Colombier [Tddataund]	"data underrun",
383*a81c3ea0SDavid du Colombier [Tdbufovr]	"buffer overrun",
384*a81c3ea0SDavid du Colombier [Tdbufund]	"buffer underrun",
385*a81c3ea0SDavid du Colombier [Tdnotacc]	"not accessed"
386*a81c3ea0SDavid du Colombier };
387*a81c3ea0SDavid du Colombier 
388*a81c3ea0SDavid du Colombier static void*
pa2ptr(ulong pa)389*a81c3ea0SDavid du Colombier pa2ptr(ulong pa)
390*a81c3ea0SDavid du Colombier {
391*a81c3ea0SDavid du Colombier 	if(pa == 0)
392*a81c3ea0SDavid du Colombier 		return nil;
393*a81c3ea0SDavid du Colombier 	else
394*a81c3ea0SDavid du Colombier 		return KSEG1ADDR(pa);
395*a81c3ea0SDavid du Colombier }
396*a81c3ea0SDavid du Colombier 
397*a81c3ea0SDavid du Colombier static ulong
ptr2pa(void * p)398*a81c3ea0SDavid du Colombier ptr2pa(void *p)
399*a81c3ea0SDavid du Colombier {
400*a81c3ea0SDavid du Colombier 	if(p == nil)
401*a81c3ea0SDavid du Colombier 		return 0;
402*a81c3ea0SDavid du Colombier 	else
403*a81c3ea0SDavid du Colombier 		return PCIWADDR(p);	// XXX
404*a81c3ea0SDavid du Colombier }
405*a81c3ea0SDavid du Colombier 
406*a81c3ea0SDavid du Colombier static void
waitSOF(Ctlr * ub)407*a81c3ea0SDavid du Colombier waitSOF(Ctlr *ub)
408*a81c3ea0SDavid du Colombier {
409*a81c3ea0SDavid du Colombier 	int frame = ub->hcca->framenumber & 0x3f;
410*a81c3ea0SDavid du Colombier 
411*a81c3ea0SDavid du Colombier 	do {
412*a81c3ea0SDavid du Colombier 		delay(2);
413*a81c3ea0SDavid du Colombier 	} while(frame == (ub->hcca->framenumber & 0x3f));
414*a81c3ea0SDavid du Colombier }
415*a81c3ea0SDavid du Colombier 
416*a81c3ea0SDavid du Colombier static char*
errmsg(int err)417*a81c3ea0SDavid du Colombier errmsg(int err)
418*a81c3ea0SDavid du Colombier {
419*a81c3ea0SDavid du Colombier 
420*a81c3ea0SDavid du Colombier 	if(err < nelem(errmsgs))
421*a81c3ea0SDavid du Colombier 		return errmsgs[err];
422*a81c3ea0SDavid du Colombier 	return nil;
423*a81c3ea0SDavid du Colombier }
424*a81c3ea0SDavid du Colombier 
425*a81c3ea0SDavid du Colombier static Ed*
ctlhd(Ctlr * ctlr)426*a81c3ea0SDavid du Colombier ctlhd(Ctlr *ctlr)
427*a81c3ea0SDavid du Colombier {
428*a81c3ea0SDavid du Colombier 	return pa2ptr(ctlr->ohci->ctlheaded);
429*a81c3ea0SDavid du Colombier }
430*a81c3ea0SDavid du Colombier 
431*a81c3ea0SDavid du Colombier static Ed*
bulkhd(Ctlr * ctlr)432*a81c3ea0SDavid du Colombier bulkhd(Ctlr *ctlr)
433*a81c3ea0SDavid du Colombier {
434*a81c3ea0SDavid du Colombier 	return pa2ptr(ctlr->ohci->bulkheaded);
435*a81c3ea0SDavid du Colombier }
436*a81c3ea0SDavid du Colombier 
437*a81c3ea0SDavid du Colombier static void
edlinked(Ed * ed,Ed * next)438*a81c3ea0SDavid du Colombier edlinked(Ed *ed, Ed *next)
439*a81c3ea0SDavid du Colombier {
440*a81c3ea0SDavid du Colombier 	if(ed == nil)
441*a81c3ea0SDavid du Colombier 		print("edlinked: nil ed: pc %#p\n", getcallerpc(&ed));
442*a81c3ea0SDavid du Colombier 	ed->nexted = ptr2pa(next);
443*a81c3ea0SDavid du Colombier 	ed->next = next;
444*a81c3ea0SDavid du Colombier }
445*a81c3ea0SDavid du Colombier 
446*a81c3ea0SDavid du Colombier static void
setctlhd(Ctlr * ctlr,Ed * ed)447*a81c3ea0SDavid du Colombier setctlhd(Ctlr *ctlr, Ed *ed)
448*a81c3ea0SDavid du Colombier {
449*a81c3ea0SDavid du Colombier 	ctlr->ohci->ctlheaded = ptr2pa(ed);
450*a81c3ea0SDavid du Colombier 	if(ed != nil)
451*a81c3ea0SDavid du Colombier 		ctlr->ohci->cmdsts |= Sclf;	/* reload it on next pass */
452*a81c3ea0SDavid du Colombier }
453*a81c3ea0SDavid du Colombier 
454*a81c3ea0SDavid du Colombier static void
setbulkhd(Ctlr * ctlr,Ed * ed)455*a81c3ea0SDavid du Colombier setbulkhd(Ctlr *ctlr, Ed *ed)
456*a81c3ea0SDavid du Colombier {
457*a81c3ea0SDavid du Colombier 	ctlr->ohci->bulkheaded = ptr2pa(ed);
458*a81c3ea0SDavid du Colombier 	if(ed != nil)
459*a81c3ea0SDavid du Colombier 		ctlr->ohci->cmdsts |= Sblf;	/* reload it on next pass */
460*a81c3ea0SDavid du Colombier }
461*a81c3ea0SDavid du Colombier 
462*a81c3ea0SDavid du Colombier static void
unlinkctl(Ctlr * ctlr,Ed * ed)463*a81c3ea0SDavid du Colombier unlinkctl(Ctlr *ctlr, Ed *ed)
464*a81c3ea0SDavid du Colombier {
465*a81c3ea0SDavid du Colombier 	Ed *this, *prev, *next;
466*a81c3ea0SDavid du Colombier 
467*a81c3ea0SDavid du Colombier 	ctlr->ohci->control &= ~Ccle;
468*a81c3ea0SDavid du Colombier 	waitSOF(ctlr);
469*a81c3ea0SDavid du Colombier 	this = ctlhd(ctlr);
470*a81c3ea0SDavid du Colombier 	ctlr->ohci->ctlcurred = 0;
471*a81c3ea0SDavid du Colombier 	prev = nil;
472*a81c3ea0SDavid du Colombier 	while(this != nil && this != ed){
473*a81c3ea0SDavid du Colombier 		prev = this;
474*a81c3ea0SDavid du Colombier 		this = this->next;
475*a81c3ea0SDavid du Colombier 	}
476*a81c3ea0SDavid du Colombier 	if(this == nil){
477*a81c3ea0SDavid du Colombier 		print("unlinkctl: not found\n");
478*a81c3ea0SDavid du Colombier 		return;
479*a81c3ea0SDavid du Colombier 	}
480*a81c3ea0SDavid du Colombier 	next = this->next;
481*a81c3ea0SDavid du Colombier 	if(prev == nil)
482*a81c3ea0SDavid du Colombier 		setctlhd(ctlr, next);
483*a81c3ea0SDavid du Colombier 	else
484*a81c3ea0SDavid du Colombier 		edlinked(prev, next);
485*a81c3ea0SDavid du Colombier 	ctlr->ohci->control |= Ccle;
486*a81c3ea0SDavid du Colombier 	edlinked(ed, nil);		/* wipe out next field */
487*a81c3ea0SDavid du Colombier }
488*a81c3ea0SDavid du Colombier 
489*a81c3ea0SDavid du Colombier static void
unlinkbulk(Ctlr * ctlr,Ed * ed)490*a81c3ea0SDavid du Colombier unlinkbulk(Ctlr *ctlr, Ed *ed)
491*a81c3ea0SDavid du Colombier {
492*a81c3ea0SDavid du Colombier 	Ed *this, *prev, *next;
493*a81c3ea0SDavid du Colombier 
494*a81c3ea0SDavid du Colombier 	ctlr->ohci->control &= ~Cble;
495*a81c3ea0SDavid du Colombier 	waitSOF(ctlr);
496*a81c3ea0SDavid du Colombier 	this = bulkhd(ctlr);
497*a81c3ea0SDavid du Colombier 	ctlr->ohci->bulkcurred = 0;
498*a81c3ea0SDavid du Colombier 	prev = nil;
499*a81c3ea0SDavid du Colombier 	while(this != nil && this != ed){
500*a81c3ea0SDavid du Colombier 		prev = this;
501*a81c3ea0SDavid du Colombier 		this = this->next;
502*a81c3ea0SDavid du Colombier 	}
503*a81c3ea0SDavid du Colombier 	if(this == nil){
504*a81c3ea0SDavid du Colombier 		print("unlinkbulk: not found\n");
505*a81c3ea0SDavid du Colombier 		return;
506*a81c3ea0SDavid du Colombier 	}
507*a81c3ea0SDavid du Colombier 	next = this->next;
508*a81c3ea0SDavid du Colombier 	if(prev == nil)
509*a81c3ea0SDavid du Colombier 		setbulkhd(ctlr, next);
510*a81c3ea0SDavid du Colombier 	else
511*a81c3ea0SDavid du Colombier 		edlinked(prev, next);
512*a81c3ea0SDavid du Colombier 	ctlr->ohci->control |= Cble;
513*a81c3ea0SDavid du Colombier 	edlinked(ed, nil);		/* wipe out next field */
514*a81c3ea0SDavid du Colombier }
515*a81c3ea0SDavid du Colombier 
516*a81c3ea0SDavid du Colombier static void
edsetaddr(Ed * ed,ulong addr)517*a81c3ea0SDavid du Colombier edsetaddr(Ed *ed, ulong addr)
518*a81c3ea0SDavid du Colombier {
519*a81c3ea0SDavid du Colombier 	ulong ctrl;
520*a81c3ea0SDavid du Colombier 
521*a81c3ea0SDavid du Colombier 	ctrl = ed->ctrl & ~((Epmax<<7)|Devmax);
522*a81c3ea0SDavid du Colombier 	ctrl |= (addr & ((Epmax<<7)|Devmax));
523*a81c3ea0SDavid du Colombier 	ed->ctrl = ctrl;
524*a81c3ea0SDavid du Colombier }
525*a81c3ea0SDavid du Colombier 
526*a81c3ea0SDavid du Colombier static void
edsettog(Ed * ed,int c)527*a81c3ea0SDavid du Colombier edsettog(Ed *ed, int c)
528*a81c3ea0SDavid du Colombier {
529*a81c3ea0SDavid du Colombier 	if(c != 0)
530*a81c3ea0SDavid du Colombier 		ed->head |= Edtoggle;
531*a81c3ea0SDavid du Colombier 	else
532*a81c3ea0SDavid du Colombier 		ed->head &= ~Edtoggle;
533*a81c3ea0SDavid du Colombier }
534*a81c3ea0SDavid du Colombier 
535*a81c3ea0SDavid du Colombier static int
edtoggle(Ed * ed)536*a81c3ea0SDavid du Colombier edtoggle(Ed *ed)
537*a81c3ea0SDavid du Colombier {
538*a81c3ea0SDavid du Colombier 	return ed->head & Edtoggle;
539*a81c3ea0SDavid du Colombier }
540*a81c3ea0SDavid du Colombier 
541*a81c3ea0SDavid du Colombier static int
edhalted(Ed * ed)542*a81c3ea0SDavid du Colombier edhalted(Ed *ed)
543*a81c3ea0SDavid du Colombier {
544*a81c3ea0SDavid du Colombier 	return ed->head & Edhalt;
545*a81c3ea0SDavid du Colombier }
546*a81c3ea0SDavid du Colombier 
547*a81c3ea0SDavid du Colombier static int
edmaxpkt(Ed * ed)548*a81c3ea0SDavid du Colombier edmaxpkt(Ed *ed)
549*a81c3ea0SDavid du Colombier {
550*a81c3ea0SDavid du Colombier 	return (ed->ctrl >> Edmpsshift) & Edmpsmask;
551*a81c3ea0SDavid du Colombier }
552*a81c3ea0SDavid du Colombier 
553*a81c3ea0SDavid du Colombier static void
edsetmaxpkt(Ed * ed,int m)554*a81c3ea0SDavid du Colombier edsetmaxpkt(Ed *ed, int m)
555*a81c3ea0SDavid du Colombier {
556*a81c3ea0SDavid du Colombier 	ulong c;
557*a81c3ea0SDavid du Colombier 
558*a81c3ea0SDavid du Colombier 	c = ed->ctrl & ~(Edmpsmask << Edmpsshift);
559*a81c3ea0SDavid du Colombier 	ed->ctrl = c | ((m&Edmpsmask) << Edmpsshift);
560*a81c3ea0SDavid du Colombier }
561*a81c3ea0SDavid du Colombier 
562*a81c3ea0SDavid du Colombier static int
tderrs(Td * td)563*a81c3ea0SDavid du Colombier tderrs(Td *td)
564*a81c3ea0SDavid du Colombier {
565*a81c3ea0SDavid du Colombier 	return (td->ctrl >> Tdccshift) & Tdccmask;
566*a81c3ea0SDavid du Colombier }
567*a81c3ea0SDavid du Colombier 
568*a81c3ea0SDavid du Colombier static int
tdtok(Td * td)569*a81c3ea0SDavid du Colombier tdtok(Td *td)
570*a81c3ea0SDavid du Colombier {
571*a81c3ea0SDavid du Colombier 	return (td->ctrl & Tdtokmask);
572*a81c3ea0SDavid du Colombier }
573*a81c3ea0SDavid du Colombier 
574*a81c3ea0SDavid du Colombier static Td*
tdalloc(void)575*a81c3ea0SDavid du Colombier tdalloc(void)
576*a81c3ea0SDavid du Colombier {
577*a81c3ea0SDavid du Colombier 	Td *td;
578*a81c3ea0SDavid du Colombier 	Td *pool;
579*a81c3ea0SDavid du Colombier 	int i;
580*a81c3ea0SDavid du Colombier 
581*a81c3ea0SDavid du Colombier 	lock(&tdpool);
582*a81c3ea0SDavid du Colombier 	if(tdpool.free == nil){
583*a81c3ea0SDavid du Colombier 		ddprint("ohci: tdalloc %d Tds\n", Incr);
584*a81c3ea0SDavid du Colombier 		pool = xspanalloc(Incr*sizeof(Td), Align, 0);
585*a81c3ea0SDavid du Colombier 		if(pool == nil)
586*a81c3ea0SDavid du Colombier 			panic("tdalloc");
587*a81c3ea0SDavid du Colombier 		pool = KSEG1ADDR(pool);	// XXX
588*a81c3ea0SDavid du Colombier 		for(i=Incr; --i>=0;){
589*a81c3ea0SDavid du Colombier 			pool[i].next = tdpool.free;
590*a81c3ea0SDavid du Colombier 			tdpool.free = &pool[i];
591*a81c3ea0SDavid du Colombier 		}
592*a81c3ea0SDavid du Colombier 		tdpool.nalloc += Incr;
593*a81c3ea0SDavid du Colombier 		tdpool.nfree += Incr;
594*a81c3ea0SDavid du Colombier 	}
595*a81c3ea0SDavid du Colombier 	tdpool.ninuse++;
596*a81c3ea0SDavid du Colombier 	tdpool.nfree--;
597*a81c3ea0SDavid du Colombier 	td = tdpool.free;
598*a81c3ea0SDavid du Colombier 	tdpool.free = td->next;
599*a81c3ea0SDavid du Colombier 	memset(td, 0, sizeof(Td));
600*a81c3ea0SDavid du Colombier 	unlock(&tdpool);
601*a81c3ea0SDavid du Colombier 
602*a81c3ea0SDavid du Colombier 	assert(((uintptr)td & 0xF) == 0);
603*a81c3ea0SDavid du Colombier 	return td;
604*a81c3ea0SDavid du Colombier }
605*a81c3ea0SDavid du Colombier 
606*a81c3ea0SDavid du Colombier static void
tdfree(Td * td)607*a81c3ea0SDavid du Colombier tdfree(Td *td)
608*a81c3ea0SDavid du Colombier {
609*a81c3ea0SDavid du Colombier 	if(td == 0)
610*a81c3ea0SDavid du Colombier 		return;
611*a81c3ea0SDavid du Colombier 	freeb(td->bp);
612*a81c3ea0SDavid du Colombier 	td->bp = nil;
613*a81c3ea0SDavid du Colombier 	lock(&tdpool);
614*a81c3ea0SDavid du Colombier 	if(td->nexttd == 0x77777777)
615*a81c3ea0SDavid du Colombier 		panic("ohci: tdfree: double free");
616*a81c3ea0SDavid du Colombier 	memset(td, 7, sizeof(Td));	/* poison */
617*a81c3ea0SDavid du Colombier 	td->next = tdpool.free;
618*a81c3ea0SDavid du Colombier 	tdpool.free = td;
619*a81c3ea0SDavid du Colombier 	tdpool.ninuse--;
620*a81c3ea0SDavid du Colombier 	tdpool.nfree++;
621*a81c3ea0SDavid du Colombier 	unlock(&tdpool);
622*a81c3ea0SDavid du Colombier }
623*a81c3ea0SDavid du Colombier 
624*a81c3ea0SDavid du Colombier static Ed*
edalloc(void)625*a81c3ea0SDavid du Colombier edalloc(void)
626*a81c3ea0SDavid du Colombier {
627*a81c3ea0SDavid du Colombier 	Ed *ed, *pool;
628*a81c3ea0SDavid du Colombier 	int i;
629*a81c3ea0SDavid du Colombier 
630*a81c3ea0SDavid du Colombier 	lock(&edpool);
631*a81c3ea0SDavid du Colombier 	if(edpool.free == nil){
632*a81c3ea0SDavid du Colombier 		ddprint("ohci: edalloc %d Eds\n", Incr);
633*a81c3ea0SDavid du Colombier 		pool = xspanalloc(Incr*sizeof(Ed), Align, 0);
634*a81c3ea0SDavid du Colombier 		if(pool == nil)
635*a81c3ea0SDavid du Colombier 			panic("edalloc");
636*a81c3ea0SDavid du Colombier 		pool = KSEG1ADDR(pool);	// XXX
637*a81c3ea0SDavid du Colombier 		for(i=Incr; --i>=0;){
638*a81c3ea0SDavid du Colombier 			pool[i].next = edpool.free;
639*a81c3ea0SDavid du Colombier 			edpool.free = &pool[i];
640*a81c3ea0SDavid du Colombier 		}
641*a81c3ea0SDavid du Colombier 		edpool.nalloc += Incr;
642*a81c3ea0SDavid du Colombier 		edpool.nfree += Incr;
643*a81c3ea0SDavid du Colombier 	}
644*a81c3ea0SDavid du Colombier 	edpool.ninuse++;
645*a81c3ea0SDavid du Colombier 	edpool.nfree--;
646*a81c3ea0SDavid du Colombier 	ed = edpool.free;
647*a81c3ea0SDavid du Colombier 	edpool.free = ed->next;
648*a81c3ea0SDavid du Colombier 	memset(ed, 0, sizeof(Ed));
649*a81c3ea0SDavid du Colombier 	unlock(&edpool);
650*a81c3ea0SDavid du Colombier 
651*a81c3ea0SDavid du Colombier 	return ed;
652*a81c3ea0SDavid du Colombier }
653*a81c3ea0SDavid du Colombier 
654*a81c3ea0SDavid du Colombier static void
edfree(Ed * ed)655*a81c3ea0SDavid du Colombier edfree(Ed *ed)
656*a81c3ea0SDavid du Colombier {
657*a81c3ea0SDavid du Colombier 	Td *td, *next;
658*a81c3ea0SDavid du Colombier 	int i;
659*a81c3ea0SDavid du Colombier 
660*a81c3ea0SDavid du Colombier 	if(ed == 0)
661*a81c3ea0SDavid du Colombier 		return;
662*a81c3ea0SDavid du Colombier 	i = 0;
663*a81c3ea0SDavid du Colombier 	for(td = ed->tds; td != nil; td = next){
664*a81c3ea0SDavid du Colombier 		next = td->next;
665*a81c3ea0SDavid du Colombier 		tdfree(td);
666*a81c3ea0SDavid du Colombier 		if(i++ > 2000){
667*a81c3ea0SDavid du Colombier 			print("ohci: bug: ed with more than 2000 tds\n");
668*a81c3ea0SDavid du Colombier 			break;
669*a81c3ea0SDavid du Colombier 		}
670*a81c3ea0SDavid du Colombier 	}
671*a81c3ea0SDavid du Colombier 	lock(&edpool);
672*a81c3ea0SDavid du Colombier 	if(ed->nexted == 0x99999999)
673*a81c3ea0SDavid du Colombier 		panic("ohci: edfree: double free");
674*a81c3ea0SDavid du Colombier 	memset(ed, 9, sizeof(Ed));	/* poison */
675*a81c3ea0SDavid du Colombier 	ed->next = edpool.free;
676*a81c3ea0SDavid du Colombier 	edpool.free = ed;
677*a81c3ea0SDavid du Colombier 	edpool.ninuse--;
678*a81c3ea0SDavid du Colombier 	edpool.nfree++;
679*a81c3ea0SDavid du Colombier 	unlock(&edpool);
680*a81c3ea0SDavid du Colombier 	ddprint("edfree: ed %#p\n", ed);
681*a81c3ea0SDavid du Colombier }
682*a81c3ea0SDavid du Colombier 
683*a81c3ea0SDavid du Colombier /*
684*a81c3ea0SDavid du Colombier  * return smallest power of 2 >= n
685*a81c3ea0SDavid du Colombier  */
686*a81c3ea0SDavid du Colombier static int
flog2(int n)687*a81c3ea0SDavid du Colombier flog2(int n)
688*a81c3ea0SDavid du Colombier {
689*a81c3ea0SDavid du Colombier 	int i;
690*a81c3ea0SDavid du Colombier 
691*a81c3ea0SDavid du Colombier 	for(i = 0; (1 << i) < n; i++)
692*a81c3ea0SDavid du Colombier 		;
693*a81c3ea0SDavid du Colombier 	return i;
694*a81c3ea0SDavid du Colombier }
695*a81c3ea0SDavid du Colombier 
696*a81c3ea0SDavid du Colombier /*
697*a81c3ea0SDavid du Colombier  * return smallest power of 2 <= n
698*a81c3ea0SDavid du Colombier  */
699*a81c3ea0SDavid du Colombier static int
flog2lower(int n)700*a81c3ea0SDavid du Colombier flog2lower(int n)
701*a81c3ea0SDavid du Colombier {
702*a81c3ea0SDavid du Colombier 	int i;
703*a81c3ea0SDavid du Colombier 
704*a81c3ea0SDavid du Colombier 	for(i = 0; (1 << (i + 1)) <= n; i++)
705*a81c3ea0SDavid du Colombier 		;
706*a81c3ea0SDavid du Colombier 	return i;
707*a81c3ea0SDavid du Colombier }
708*a81c3ea0SDavid du Colombier 
709*a81c3ea0SDavid du Colombier static int
pickschedq(Qtree * qt,int pollival,ulong bw,ulong limit)710*a81c3ea0SDavid du Colombier pickschedq(Qtree *qt, int pollival, ulong bw, ulong limit)
711*a81c3ea0SDavid du Colombier {
712*a81c3ea0SDavid du Colombier 	int i, j, d, upperb, q;
713*a81c3ea0SDavid du Colombier 	ulong best, worst, total;
714*a81c3ea0SDavid du Colombier 
715*a81c3ea0SDavid du Colombier 	d = flog2lower(pollival);
716*a81c3ea0SDavid du Colombier 	if(d > qt->depth)
717*a81c3ea0SDavid du Colombier 		d = qt->depth;
718*a81c3ea0SDavid du Colombier 	q = -1;
719*a81c3ea0SDavid du Colombier 	worst = 0;
720*a81c3ea0SDavid du Colombier 	best = ~0;
721*a81c3ea0SDavid du Colombier 	upperb = (1 << (d+1)) - 1;
722*a81c3ea0SDavid du Colombier 	for(i = (1 << d) - 1; i < upperb; i++){
723*a81c3ea0SDavid du Colombier 		total = qt->bw[0];
724*a81c3ea0SDavid du Colombier 		for(j = i; j > 0; j = (j - 1) / 2)
725*a81c3ea0SDavid du Colombier 			total += qt->bw[j];
726*a81c3ea0SDavid du Colombier 		if(total < best){
727*a81c3ea0SDavid du Colombier 			best = total;
728*a81c3ea0SDavid du Colombier 			q = i;
729*a81c3ea0SDavid du Colombier 		}
730*a81c3ea0SDavid du Colombier 		if(total > worst)
731*a81c3ea0SDavid du Colombier 			worst = total;
732*a81c3ea0SDavid du Colombier 	}
733*a81c3ea0SDavid du Colombier 	if(worst + bw >= limit)
734*a81c3ea0SDavid du Colombier 		return -1;
735*a81c3ea0SDavid du Colombier 	return q;
736*a81c3ea0SDavid du Colombier }
737*a81c3ea0SDavid du Colombier 
738*a81c3ea0SDavid du Colombier static int
schedq(Ctlr * ctlr,Qio * io,int pollival)739*a81c3ea0SDavid du Colombier schedq(Ctlr *ctlr, Qio *io, int pollival)
740*a81c3ea0SDavid du Colombier {
741*a81c3ea0SDavid du Colombier 	int q;
742*a81c3ea0SDavid du Colombier 	Ed *ted;
743*a81c3ea0SDavid du Colombier 
744*a81c3ea0SDavid du Colombier 	q = pickschedq(ctlr->tree, pollival, io->bw, ~0);
745*a81c3ea0SDavid du Colombier 	ddqprint("ohci: sched %#p q %d, ival %d, bw %ld\n", io, q, pollival, io->bw);
746*a81c3ea0SDavid du Colombier 	if(q < 0){
747*a81c3ea0SDavid du Colombier 		print("ohci: no room for ed\n");
748*a81c3ea0SDavid du Colombier 		return -1;
749*a81c3ea0SDavid du Colombier 	}
750*a81c3ea0SDavid du Colombier 	ctlr->tree->bw[q] += io->bw;
751*a81c3ea0SDavid du Colombier 	ted = ctlr->tree->root[q];
752*a81c3ea0SDavid du Colombier 	io->sched = q;
753*a81c3ea0SDavid du Colombier 	edlinked(io->ed, ted->next);
754*a81c3ea0SDavid du Colombier 	edlinked(ted, io->ed);
755*a81c3ea0SDavid du Colombier 	io->ed->inext = ctlr->intrhd;
756*a81c3ea0SDavid du Colombier 	ctlr->intrhd = io->ed;
757*a81c3ea0SDavid du Colombier 	return 0;
758*a81c3ea0SDavid du Colombier }
759*a81c3ea0SDavid du Colombier 
760*a81c3ea0SDavid du Colombier static void
unschedq(Ctlr * ctlr,Qio * qio)761*a81c3ea0SDavid du Colombier unschedq(Ctlr *ctlr, Qio *qio)
762*a81c3ea0SDavid du Colombier {
763*a81c3ea0SDavid du Colombier 	int q;
764*a81c3ea0SDavid du Colombier 	Ed *prev, *this, *next;
765*a81c3ea0SDavid du Colombier 	Ed **l;
766*a81c3ea0SDavid du Colombier 
767*a81c3ea0SDavid du Colombier 	q = qio->sched;
768*a81c3ea0SDavid du Colombier 	if(q < 0)
769*a81c3ea0SDavid du Colombier 		return;
770*a81c3ea0SDavid du Colombier 	ctlr->tree->bw[q] -= qio->bw;
771*a81c3ea0SDavid du Colombier 
772*a81c3ea0SDavid du Colombier 	prev = ctlr->tree->root[q];
773*a81c3ea0SDavid du Colombier 	this = prev->next;
774*a81c3ea0SDavid du Colombier 	while(this != nil && this != qio->ed){
775*a81c3ea0SDavid du Colombier 		prev = this;
776*a81c3ea0SDavid du Colombier 		this = this->next;
777*a81c3ea0SDavid du Colombier 	}
778*a81c3ea0SDavid du Colombier 	if(this == nil)
779*a81c3ea0SDavid du Colombier 		print("ohci: unschedq %d: not found\n", q);
780*a81c3ea0SDavid du Colombier 	else{
781*a81c3ea0SDavid du Colombier 		next = this->next;
782*a81c3ea0SDavid du Colombier 		edlinked(prev, next);
783*a81c3ea0SDavid du Colombier 	}
784*a81c3ea0SDavid du Colombier 	waitSOF(ctlr);
785*a81c3ea0SDavid du Colombier 	for(l = &ctlr->intrhd; *l != nil; l = &(*l)->inext)
786*a81c3ea0SDavid du Colombier 		if(*l == qio->ed){
787*a81c3ea0SDavid du Colombier 			*l = (*l)->inext;
788*a81c3ea0SDavid du Colombier 			return;
789*a81c3ea0SDavid du Colombier 		}
790*a81c3ea0SDavid du Colombier 	print("ohci: unschedq: ed %#p not found\n", qio->ed);
791*a81c3ea0SDavid du Colombier }
792*a81c3ea0SDavid du Colombier 
793*a81c3ea0SDavid du Colombier static char*
seprinttdtok(char * s,char * e,int tok)794*a81c3ea0SDavid du Colombier seprinttdtok(char *s, char *e, int tok)
795*a81c3ea0SDavid du Colombier {
796*a81c3ea0SDavid du Colombier 	switch(tok){
797*a81c3ea0SDavid du Colombier 	case Tdtoksetup:
798*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " setup");
799*a81c3ea0SDavid du Colombier 		break;
800*a81c3ea0SDavid du Colombier 	case Tdtokin:
801*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " in");
802*a81c3ea0SDavid du Colombier 		break;
803*a81c3ea0SDavid du Colombier 	case Tdtokout:
804*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " out");
805*a81c3ea0SDavid du Colombier 		break;
806*a81c3ea0SDavid du Colombier 	}
807*a81c3ea0SDavid du Colombier 	return s;
808*a81c3ea0SDavid du Colombier }
809*a81c3ea0SDavid du Colombier 
810*a81c3ea0SDavid du Colombier 
811*a81c3ea0SDavid du Colombier static char*
seprinttd(char * s,char * e,Td * td,int iso)812*a81c3ea0SDavid du Colombier seprinttd(char *s, char *e, Td *td, int iso)
813*a81c3ea0SDavid du Colombier {
814*a81c3ea0SDavid du Colombier 	int i;
815*a81c3ea0SDavid du Colombier 	Block *bp;
816*a81c3ea0SDavid du Colombier 
817*a81c3ea0SDavid du Colombier 	if(td == nil)
818*a81c3ea0SDavid du Colombier 		return seprint(s, e, "<nil td>\n");
819*a81c3ea0SDavid du Colombier 	s = seprint(s, e, "%#p ep %#p ctrl %#p", td, td->ep, td->ctrl);
820*a81c3ea0SDavid du Colombier 	s = seprint(s, e, " cc=%#ulx", (td->ctrl >> Tdccshift) & Tdccmask);
821*a81c3ea0SDavid du Colombier 	if(iso == 0){
822*a81c3ea0SDavid du Colombier 		if((td->ctrl & Tdround) != 0)
823*a81c3ea0SDavid du Colombier 			s = seprint(s, e, " rnd");
824*a81c3ea0SDavid du Colombier 		s = seprinttdtok(s, e, td->ctrl & Tdtokmask);
825*a81c3ea0SDavid du Colombier 		if((td->ctrl & Tdusetog) != 0)
826*a81c3ea0SDavid du Colombier 			s = seprint(s, e, " d%d", (td->ctrl & Tddata1) ? 1 : 0);
827*a81c3ea0SDavid du Colombier 		else
828*a81c3ea0SDavid du Colombier 			s = seprint(s, e, " d-");
829*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " ec=%uld", (td->ctrl >> Tderrshift) & Tderrmask);
830*a81c3ea0SDavid du Colombier 	}else{
831*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " fc=%uld", (td->ctrl >> Tdfcshift) & Tdfcmask);
832*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " sf=%uld", td->ctrl & Tdsfmask);
833*a81c3ea0SDavid du Colombier 	}
834*a81c3ea0SDavid du Colombier 	s = seprint(s, e, " cbp0 %#p cbp %#p next %#p be %#p %s",
835*a81c3ea0SDavid du Colombier 		td->cbp0, td->cbp, td->nexttd, td->be, td->last ? "last" : "");
836*a81c3ea0SDavid du Colombier 	s = seprint(s, e, "\n\t\t%ld bytes", td->nbytes);
837*a81c3ea0SDavid du Colombier 	if((bp = td->bp) != nil){
838*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " rp %#p wp %#p ", bp->rp, bp->wp);
839*a81c3ea0SDavid du Colombier 		if(BLEN(bp) > 0)
840*a81c3ea0SDavid du Colombier 			s = seprintdata(s, e, bp->rp, bp->wp - bp->rp);
841*a81c3ea0SDavid du Colombier 	}
842*a81c3ea0SDavid du Colombier 	if(iso == 0)
843*a81c3ea0SDavid du Colombier 		return seprint(s, e, "\n");
844*a81c3ea0SDavid du Colombier 	s = seprint(s, e, "\n\t\t");
845*a81c3ea0SDavid du Colombier 	/* we use only offsets[0] */
846*a81c3ea0SDavid du Colombier 	i = 0;
847*a81c3ea0SDavid du Colombier 	s = seprint(s, e, "[%d] %#ux cc=%#ux sz=%ud\n", i, td->offsets[i],
848*a81c3ea0SDavid du Colombier 		(td->offsets[i] >> Tdiccshift) & Tdiccmask,
849*a81c3ea0SDavid du Colombier 		td->offsets[i] & 0x7FF);
850*a81c3ea0SDavid du Colombier 	return s;
851*a81c3ea0SDavid du Colombier }
852*a81c3ea0SDavid du Colombier 
853*a81c3ea0SDavid du Colombier static void
dumptd(Td * td,char * p,int iso)854*a81c3ea0SDavid du Colombier dumptd(Td *td, char *p, int iso)
855*a81c3ea0SDavid du Colombier {
856*a81c3ea0SDavid du Colombier 	static char buf[512];	/* Too much */
857*a81c3ea0SDavid du Colombier 	char *s;
858*a81c3ea0SDavid du Colombier 
859*a81c3ea0SDavid du Colombier 	s = seprint(buf, buf+sizeof(buf), "%s: ", p);
860*a81c3ea0SDavid du Colombier 	s = seprinttd(s, buf+sizeof(buf), td, iso);
861*a81c3ea0SDavid du Colombier 	if(s > buf && s[-1] != '\n')
862*a81c3ea0SDavid du Colombier 		s[-1] = '\n';
863*a81c3ea0SDavid du Colombier 	print("\t%s", buf);
864*a81c3ea0SDavid du Colombier }
865*a81c3ea0SDavid du Colombier 
866*a81c3ea0SDavid du Colombier static void
dumptds(Td * td,char * p,int iso)867*a81c3ea0SDavid du Colombier dumptds(Td *td, char *p, int iso)
868*a81c3ea0SDavid du Colombier {
869*a81c3ea0SDavid du Colombier 	int i;
870*a81c3ea0SDavid du Colombier 
871*a81c3ea0SDavid du Colombier 	for(i = 0; td != nil; td = td->next){
872*a81c3ea0SDavid du Colombier 		dumptd(td, p, iso);
873*a81c3ea0SDavid du Colombier 		if(td->last)
874*a81c3ea0SDavid du Colombier 			break;
875*a81c3ea0SDavid du Colombier 		if(tdtok(td) == Tdtokin && ++i > 2){
876*a81c3ea0SDavid du Colombier 			print("\t\t...\n");
877*a81c3ea0SDavid du Colombier 			break;
878*a81c3ea0SDavid du Colombier 		}
879*a81c3ea0SDavid du Colombier 	}
880*a81c3ea0SDavid du Colombier }
881*a81c3ea0SDavid du Colombier 
882*a81c3ea0SDavid du Colombier static void
dumped(Ed * ed)883*a81c3ea0SDavid du Colombier dumped(Ed *ed)
884*a81c3ea0SDavid du Colombier {
885*a81c3ea0SDavid du Colombier 	char *buf, *s, *e;
886*a81c3ea0SDavid du Colombier 
887*a81c3ea0SDavid du Colombier 	if(ed == nil){
888*a81c3ea0SDavid du Colombier 		print("<null ed>\n");
889*a81c3ea0SDavid du Colombier 		return;
890*a81c3ea0SDavid du Colombier 	}
891*a81c3ea0SDavid du Colombier 	buf = malloc(512);
892*a81c3ea0SDavid du Colombier 	/* no waserror; may want to use from interrupt context */
893*a81c3ea0SDavid du Colombier 	if(buf == nil)
894*a81c3ea0SDavid du Colombier 		return;
895*a81c3ea0SDavid du Colombier 	e = buf+512;
896*a81c3ea0SDavid du Colombier 	s = seprint(buf, e, "\ted %#p: ctrl %#p", ed, ed->ctrl);
897*a81c3ea0SDavid du Colombier 	if((ed->ctrl & Edskip) != 0)
898*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " skip");
899*a81c3ea0SDavid du Colombier 	if((ed->ctrl & Ediso) != 0)
900*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " iso");
901*a81c3ea0SDavid du Colombier 	if((ed->ctrl & Edlow) != 0)
902*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " low");
903*a81c3ea0SDavid du Colombier 	s = seprint(s, e, " d%d", (ed->head & Edtoggle) ? 1 : 0);
904*a81c3ea0SDavid du Colombier 	if((ed->ctrl & Eddirmask) == Edin)
905*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " in");
906*a81c3ea0SDavid du Colombier 	if((ed->ctrl & Eddirmask) == Edout)
907*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " out");
908*a81c3ea0SDavid du Colombier 	if(edhalted(ed))
909*a81c3ea0SDavid du Colombier 		s = seprint(s, e, " hlt");
910*a81c3ea0SDavid du Colombier 	s = seprint(s, e, " ep%uld.%uld", (ed->ctrl>>7)&Epmax, ed->ctrl&0x7f);
911*a81c3ea0SDavid du Colombier 	s = seprint(s, e, " maxpkt %uld", (ed->ctrl>>Edmpsshift)&Edmpsmask);
912*a81c3ea0SDavid du Colombier 	seprint(s, e, " tail %#p head %#p next %#p\n",ed->tail,ed->head,ed->nexted);
913*a81c3ea0SDavid du Colombier 	print("%s", buf);
914*a81c3ea0SDavid du Colombier 	free(buf);
915*a81c3ea0SDavid du Colombier 	if(ed->tds != nil && (ed->ctrl & Ediso) == 0)
916*a81c3ea0SDavid du Colombier 		dumptds(ed->tds, "td", 0);
917*a81c3ea0SDavid du Colombier }
918*a81c3ea0SDavid du Colombier 
919*a81c3ea0SDavid du Colombier static char*
seprintio(char * s,char * e,Qio * io,char * pref)920*a81c3ea0SDavid du Colombier seprintio(char *s, char *e, Qio *io, char *pref)
921*a81c3ea0SDavid du Colombier {
922*a81c3ea0SDavid du Colombier 	s = seprint(s, e, "%s qio %#p ed %#p", pref, io, io->ed);
923*a81c3ea0SDavid du Colombier 	s = seprint(s, e, " tog %d iot %ld err %s id %#ulx",
924*a81c3ea0SDavid du Colombier 		io->toggle, io->iotime, io->err, io->usbid);
925*a81c3ea0SDavid du Colombier 	s = seprinttdtok(s, e, io->tok);
926*a81c3ea0SDavid du Colombier 	s = seprint(s, e, " %s\n", iosname[io->state]);
927*a81c3ea0SDavid du Colombier 	return s;
928*a81c3ea0SDavid du Colombier }
929*a81c3ea0SDavid du Colombier 
930*a81c3ea0SDavid du Colombier static char*
seprintep(char * s,char * e,Ep * ep)931*a81c3ea0SDavid du Colombier seprintep(char* s, char* e, Ep *ep)
932*a81c3ea0SDavid du Colombier {
933*a81c3ea0SDavid du Colombier 	Isoio *iso;
934*a81c3ea0SDavid du Colombier 	Qio *io;
935*a81c3ea0SDavid du Colombier 	Ctlio *cio;
936*a81c3ea0SDavid du Colombier 
937*a81c3ea0SDavid du Colombier 	if(ep == nil)
938*a81c3ea0SDavid du Colombier 		return seprint(s, e, "<nil ep>\n");
939*a81c3ea0SDavid du Colombier 	if(ep->aux == nil)
940*a81c3ea0SDavid du Colombier 		return seprint(s, e, "no mdep\n");
941*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
942*a81c3ea0SDavid du Colombier 	case Tctl:
943*a81c3ea0SDavid du Colombier 		cio = ep->aux;
944*a81c3ea0SDavid du Colombier 		s = seprintio(s, e, cio, "c");
945*a81c3ea0SDavid du Colombier 		s = seprint(s, e, "\trepl %d ndata %d\n", ep->rhrepl, cio->ndata);
946*a81c3ea0SDavid du Colombier 		break;
947*a81c3ea0SDavid du Colombier 	case Tbulk:
948*a81c3ea0SDavid du Colombier 	case Tintr:
949*a81c3ea0SDavid du Colombier 		io = ep->aux;
950*a81c3ea0SDavid du Colombier 		if(ep->mode != OWRITE)
951*a81c3ea0SDavid du Colombier 			s = seprintio(s, e, &io[OREAD], "r");
952*a81c3ea0SDavid du Colombier 		if(ep->mode != OREAD)
953*a81c3ea0SDavid du Colombier 			s = seprintio(s, e, &io[OWRITE], "w");
954*a81c3ea0SDavid du Colombier 		break;
955*a81c3ea0SDavid du Colombier 	case Tiso:
956*a81c3ea0SDavid du Colombier 		iso = ep->aux;
957*a81c3ea0SDavid du Colombier 		s = seprintio(s, e, iso, "w");
958*a81c3ea0SDavid du Colombier 		s = seprint(s, e, "\tntds %d avail %d frno %uld left %uld next avail %#p\n",
959*a81c3ea0SDavid du Colombier 			iso->nframes, iso->navail, iso->frno, iso->left, iso->atds);
960*a81c3ea0SDavid du Colombier 		break;
961*a81c3ea0SDavid du Colombier 	}
962*a81c3ea0SDavid du Colombier 	return s;
963*a81c3ea0SDavid du Colombier }
964*a81c3ea0SDavid du Colombier 
965*a81c3ea0SDavid du Colombier static char*
seprintctl(char * s,char * se,ulong ctl)966*a81c3ea0SDavid du Colombier seprintctl(char *s, char *se, ulong ctl)
967*a81c3ea0SDavid du Colombier {
968*a81c3ea0SDavid du Colombier 	s = seprint(s, se, "en=");
969*a81c3ea0SDavid du Colombier 	if((ctl&Cple) != 0)
970*a81c3ea0SDavid du Colombier 		s = seprint(s, se, "p");
971*a81c3ea0SDavid du Colombier 	if((ctl&Cie) != 0)
972*a81c3ea0SDavid du Colombier 		s = seprint(s, se, "i");
973*a81c3ea0SDavid du Colombier 	if((ctl&Ccle) != 0)
974*a81c3ea0SDavid du Colombier 		s = seprint(s, se, "c");
975*a81c3ea0SDavid du Colombier 	if((ctl&Cble) != 0)
976*a81c3ea0SDavid du Colombier 		s = seprint(s, se, "b");
977*a81c3ea0SDavid du Colombier 	switch(ctl & Cfsmask){
978*a81c3ea0SDavid du Colombier 	case Cfsreset:
979*a81c3ea0SDavid du Colombier 		return seprint(s, se, " reset");
980*a81c3ea0SDavid du Colombier 	case Cfsresume:
981*a81c3ea0SDavid du Colombier 		return seprint(s, se, " resume");
982*a81c3ea0SDavid du Colombier 	case Cfsoper:
983*a81c3ea0SDavid du Colombier 		return seprint(s, se, " run");
984*a81c3ea0SDavid du Colombier 	case Cfssuspend:
985*a81c3ea0SDavid du Colombier 		return seprint(s, se, " suspend");
986*a81c3ea0SDavid du Colombier 	default:
987*a81c3ea0SDavid du Colombier 		return seprint(s, se, " ???");
988*a81c3ea0SDavid du Colombier 	}
989*a81c3ea0SDavid du Colombier }
990*a81c3ea0SDavid du Colombier 
991*a81c3ea0SDavid du Colombier static void
dump(Hci * hp)992*a81c3ea0SDavid du Colombier dump(Hci *hp)
993*a81c3ea0SDavid du Colombier {
994*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
995*a81c3ea0SDavid du Colombier 	Ed *ed;
996*a81c3ea0SDavid du Colombier 	char cs[20];
997*a81c3ea0SDavid du Colombier 
998*a81c3ea0SDavid du Colombier 	ctlr = hp->aux;
999*a81c3ea0SDavid du Colombier 	ilock(ctlr);
1000*a81c3ea0SDavid du Colombier 	seprintctl(cs, cs+sizeof(cs), ctlr->ohci->control);
1001*a81c3ea0SDavid du Colombier 	print("ohci ctlr %#p: frno %#ux ctl %#lux %s sts %#lux intr %#lux\n",
1002*a81c3ea0SDavid du Colombier 		ctlr, ctlr->hcca->framenumber, ctlr->ohci->control, cs,
1003*a81c3ea0SDavid du Colombier 		ctlr->ohci->cmdsts, ctlr->ohci->intrsts);
1004*a81c3ea0SDavid du Colombier 	print("ctlhd %#ulx cur %#ulx bulkhd %#ulx cur %#ulx done %#ulx\n",
1005*a81c3ea0SDavid du Colombier 		ctlr->ohci->ctlheaded, ctlr->ohci->ctlcurred,
1006*a81c3ea0SDavid du Colombier 		ctlr->ohci->bulkheaded, ctlr->ohci->bulkcurred,
1007*a81c3ea0SDavid du Colombier 		ctlr->ohci->donehead);
1008*a81c3ea0SDavid du Colombier 	if(ctlhd(ctlr) != nil)
1009*a81c3ea0SDavid du Colombier 		print("[ctl]\n");
1010*a81c3ea0SDavid du Colombier 	for(ed = ctlhd(ctlr); ed != nil; ed = ed->next)
1011*a81c3ea0SDavid du Colombier 		dumped(ed);
1012*a81c3ea0SDavid du Colombier 	if(bulkhd(ctlr) != nil)
1013*a81c3ea0SDavid du Colombier 		print("[bulk]\n");
1014*a81c3ea0SDavid du Colombier 	for(ed = bulkhd(ctlr); ed != nil; ed = ed->next)
1015*a81c3ea0SDavid du Colombier 		dumped(ed);
1016*a81c3ea0SDavid du Colombier 	if(ctlr->intrhd != nil)
1017*a81c3ea0SDavid du Colombier 		print("[intr]\n");
1018*a81c3ea0SDavid du Colombier 	for(ed = ctlr->intrhd; ed != nil; ed = ed->inext)
1019*a81c3ea0SDavid du Colombier 		dumped(ed);
1020*a81c3ea0SDavid du Colombier 	if(ctlr->tree->root[0]->next != nil)
1021*a81c3ea0SDavid du Colombier 		print("[iso]");
1022*a81c3ea0SDavid du Colombier 	for(ed = ctlr->tree->root[0]->next; ed != nil; ed = ed->next)
1023*a81c3ea0SDavid du Colombier 		dumped(ed);
1024*a81c3ea0SDavid du Colombier 	print("%d eds in tree\n", ctlr->ntree);
1025*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
1026*a81c3ea0SDavid du Colombier 	lock(&tdpool);
1027*a81c3ea0SDavid du Colombier 	print("%d tds allocated = %d in use + %d free\n",
1028*a81c3ea0SDavid du Colombier 		tdpool.nalloc, tdpool.ninuse, tdpool.nfree);
1029*a81c3ea0SDavid du Colombier 	unlock(&tdpool);
1030*a81c3ea0SDavid du Colombier 	lock(&edpool);
1031*a81c3ea0SDavid du Colombier 	print("%d eds allocated = %d in use + %d free\n",
1032*a81c3ea0SDavid du Colombier 		edpool.nalloc, edpool.ninuse, edpool.nfree);
1033*a81c3ea0SDavid du Colombier 	unlock(&edpool);
1034*a81c3ea0SDavid du Colombier }
1035*a81c3ea0SDavid du Colombier 
1036*a81c3ea0SDavid du Colombier /*
1037*a81c3ea0SDavid du Colombier  * Compute size for the next iso Td and setup its
1038*a81c3ea0SDavid du Colombier  * descriptor for I/O according to the buffer size.
1039*a81c3ea0SDavid du Colombier  */
1040*a81c3ea0SDavid du Colombier static void
isodtdinit(Ep * ep,Isoio * iso,Td * td)1041*a81c3ea0SDavid du Colombier isodtdinit(Ep *ep, Isoio *iso, Td *td)
1042*a81c3ea0SDavid du Colombier {
1043*a81c3ea0SDavid du Colombier 	Block *bp;
1044*a81c3ea0SDavid du Colombier 	long size;
1045*a81c3ea0SDavid du Colombier 	int i;
1046*a81c3ea0SDavid du Colombier 
1047*a81c3ea0SDavid du Colombier 	bp = td->bp;
1048*a81c3ea0SDavid du Colombier 	assert(bp != nil && BLEN(bp) == 0);
1049*a81c3ea0SDavid du Colombier 	size = (ep->hz+iso->left) * ep->pollival / 1000;
1050*a81c3ea0SDavid du Colombier 	iso->left = (ep->hz+iso->left) * ep->pollival % 1000;
1051*a81c3ea0SDavid du Colombier 	size *= ep->samplesz;
1052*a81c3ea0SDavid du Colombier 	if(size > ep->maxpkt){
1053*a81c3ea0SDavid du Colombier 		print("ohci: ep%d.%d: size > maxpkt\n",
1054*a81c3ea0SDavid du Colombier 			ep->dev->nb, ep->nb);
1055*a81c3ea0SDavid du Colombier 		print("size = %uld max = %ld\n", size, ep->maxpkt);
1056*a81c3ea0SDavid du Colombier 		size = ep->maxpkt;
1057*a81c3ea0SDavid du Colombier 	}
1058*a81c3ea0SDavid du Colombier 	td->nbytes = size;
1059*a81c3ea0SDavid du Colombier 	memset(KSEG1ADDR(bp->wp), 0, size);	/* in case we don't fill it on time */
1060*a81c3ea0SDavid du Colombier 	td->cbp0 = td->cbp = ptr2pa(bp->rp) & ~0xFFF;
1061*a81c3ea0SDavid du Colombier 	td->ctrl = TRUNC(iso->frno, Ntdframes);
1062*a81c3ea0SDavid du Colombier 	td->offsets[0] = (ptr2pa(bp->rp) & 0xFFF);
1063*a81c3ea0SDavid du Colombier 	td->offsets[0] |= (Tdnotacc << Tdiccshift);
1064*a81c3ea0SDavid du Colombier 	/* in case the controller checks out the offests... */
1065*a81c3ea0SDavid du Colombier 	for(i = 1; i < nelem(td->offsets); i++)
1066*a81c3ea0SDavid du Colombier 		td->offsets[i] = td->offsets[0];
1067*a81c3ea0SDavid du Colombier 	td->be = ptr2pa(bp->rp + size - 1);
1068*a81c3ea0SDavid du Colombier 	td->ctrl |= (0 << Tdfcshift);	/* frame count is 1 */
1069*a81c3ea0SDavid du Colombier 
1070*a81c3ea0SDavid du Colombier 	iso->frno = TRUNC(iso->frno + ep->pollival, Ntdframes);
1071*a81c3ea0SDavid du Colombier }
1072*a81c3ea0SDavid du Colombier 
1073*a81c3ea0SDavid du Colombier /*
1074*a81c3ea0SDavid du Colombier  * start I/O on the dummy td and setup a new dummy to fill up.
1075*a81c3ea0SDavid du Colombier  */
1076*a81c3ea0SDavid du Colombier static void
isoadvance(Ep * ep,Isoio * iso,Td * td)1077*a81c3ea0SDavid du Colombier isoadvance(Ep *ep, Isoio *iso, Td *td)
1078*a81c3ea0SDavid du Colombier {
1079*a81c3ea0SDavid du Colombier 	Td *dtd;
1080*a81c3ea0SDavid du Colombier 
1081*a81c3ea0SDavid du Colombier 	dtd = iso->atds;
1082*a81c3ea0SDavid du Colombier 	iso->atds = dtd->anext;
1083*a81c3ea0SDavid du Colombier 	iso->navail--;
1084*a81c3ea0SDavid du Colombier 	dtd->anext = nil;
1085*a81c3ea0SDavid du Colombier 	dtd->bp->wp = dtd->bp->rp;
1086*a81c3ea0SDavid du Colombier 	dtd->nexttd = 0;
1087*a81c3ea0SDavid du Colombier 	td->nexttd = ptr2pa(dtd);
1088*a81c3ea0SDavid du Colombier 	isodtdinit(ep, iso, dtd);
1089*a81c3ea0SDavid du Colombier 	iso->ed->tail = ptr2pa(dtd);
1090*a81c3ea0SDavid du Colombier }
1091*a81c3ea0SDavid du Colombier 
1092*a81c3ea0SDavid du Colombier static int
isocanwrite(void * a)1093*a81c3ea0SDavid du Colombier isocanwrite(void *a)
1094*a81c3ea0SDavid du Colombier {
1095*a81c3ea0SDavid du Colombier 	Isoio *iso;
1096*a81c3ea0SDavid du Colombier 
1097*a81c3ea0SDavid du Colombier 	iso = a;
1098*a81c3ea0SDavid du Colombier 	return iso->state == Qclose || iso->err != nil ||
1099*a81c3ea0SDavid du Colombier 		iso->navail > iso->nframes / 2;
1100*a81c3ea0SDavid du Colombier }
1101*a81c3ea0SDavid du Colombier 
1102*a81c3ea0SDavid du Colombier /*
1103*a81c3ea0SDavid du Colombier  * Service a completed/failed Td from the done queue.
1104*a81c3ea0SDavid du Colombier  * It may be of any transfer type.
1105*a81c3ea0SDavid du Colombier  * The queue is not in completion order.
1106*a81c3ea0SDavid du Colombier  * (It's actually in reverse completion order).
1107*a81c3ea0SDavid du Colombier  *
1108*a81c3ea0SDavid du Colombier  * When an error, a short packet, or a last Td is found
1109*a81c3ea0SDavid du Colombier  * we awake the process waiting for the transfer.
1110*a81c3ea0SDavid du Colombier  * Although later we will process other Tds completed
1111*a81c3ea0SDavid du Colombier  * before, epio won't be able to touch the current Td
1112*a81c3ea0SDavid du Colombier  * until interrupt returns and releases the lock on the
1113*a81c3ea0SDavid du Colombier  * controller.
1114*a81c3ea0SDavid du Colombier  */
1115*a81c3ea0SDavid du Colombier static void
qhinterrupt(Ctlr *,Ep * ep,Qio * io,Td * td,int)1116*a81c3ea0SDavid du Colombier qhinterrupt(Ctlr *, Ep *ep, Qio *io, Td *td, int)
1117*a81c3ea0SDavid du Colombier {
1118*a81c3ea0SDavid du Colombier 	Block *bp;
1119*a81c3ea0SDavid du Colombier 	int mode, err;
1120*a81c3ea0SDavid du Colombier 	Ed *ed;
1121*a81c3ea0SDavid du Colombier 
1122*a81c3ea0SDavid du Colombier 	ed = io->ed;
1123*a81c3ea0SDavid du Colombier 	if(io->state != Qrun)
1124*a81c3ea0SDavid du Colombier 		return;
1125*a81c3ea0SDavid du Colombier 	if(tdtok(td) == Tdtokin)
1126*a81c3ea0SDavid du Colombier 		mode = OREAD;
1127*a81c3ea0SDavid du Colombier 	else
1128*a81c3ea0SDavid du Colombier 		mode = OWRITE;
1129*a81c3ea0SDavid du Colombier 	bp = td->bp;
1130*a81c3ea0SDavid du Colombier 	err = tderrs(td);
1131*a81c3ea0SDavid du Colombier 
1132*a81c3ea0SDavid du Colombier 	switch(err){
1133*a81c3ea0SDavid du Colombier 	case Tddataovr:			/* Overrun is not an error */
1134*a81c3ea0SDavid du Colombier 		break;
1135*a81c3ea0SDavid du Colombier 	case Tdok:
1136*a81c3ea0SDavid du Colombier 		/* virtualbox doesn't always report underflow on short packets */
1137*a81c3ea0SDavid du Colombier 		if(td->cbp == 0)
1138*a81c3ea0SDavid du Colombier 			break;
1139*a81c3ea0SDavid du Colombier 		/* fall through */
1140*a81c3ea0SDavid du Colombier 	case Tddataund:
1141*a81c3ea0SDavid du Colombier 		/* short input packets are ok */
1142*a81c3ea0SDavid du Colombier 		if(mode == OREAD){
1143*a81c3ea0SDavid du Colombier 			if(td->cbp == 0)
1144*a81c3ea0SDavid du Colombier 				panic("ohci: short packet but cbp == 0");
1145*a81c3ea0SDavid du Colombier 			/*
1146*a81c3ea0SDavid du Colombier 			 * td->cbp and td->cbp0 are the real addresses
1147*a81c3ea0SDavid du Colombier 			 * corresponding to virtual addresses bp->wp and
1148*a81c3ea0SDavid du Colombier 			 * bp->rp respectively.
1149*a81c3ea0SDavid du Colombier 			 */
1150*a81c3ea0SDavid du Colombier 			bp->wp = bp->rp + (td->cbp - td->cbp0);
1151*a81c3ea0SDavid du Colombier 			if(bp->wp < bp->rp)
1152*a81c3ea0SDavid du Colombier 				panic("ohci: wp < rp");
1153*a81c3ea0SDavid du Colombier 			/*
1154*a81c3ea0SDavid du Colombier 			 * It's ok. clear error and flag as last in xfer.
1155*a81c3ea0SDavid du Colombier 			 * epio must ignore following Tds.
1156*a81c3ea0SDavid du Colombier 			 */
1157*a81c3ea0SDavid du Colombier 			td->last = 1;
1158*a81c3ea0SDavid du Colombier 			td->ctrl &= ~(Tdccmask << Tdccshift);
1159*a81c3ea0SDavid du Colombier 			break;
1160*a81c3ea0SDavid du Colombier 		}
1161*a81c3ea0SDavid du Colombier 		/* else fall; it's an error */
1162*a81c3ea0SDavid du Colombier 	case Tdcrc:
1163*a81c3ea0SDavid du Colombier 	case Tdbitstuff:
1164*a81c3ea0SDavid du Colombier 	case Tdbadtog:
1165*a81c3ea0SDavid du Colombier 	case Tdstalled:
1166*a81c3ea0SDavid du Colombier 	case Tdtmout:
1167*a81c3ea0SDavid du Colombier 	case Tdpidchk:
1168*a81c3ea0SDavid du Colombier 	case Tdbadpid:
1169*a81c3ea0SDavid du Colombier 		bp->wp = bp->rp;	/* no bytes in xfer. */
1170*a81c3ea0SDavid du Colombier 		io->err = errmsg(err);
1171*a81c3ea0SDavid du Colombier 		if(debug || ep->debug){
1172*a81c3ea0SDavid du Colombier 			print("tdinterrupt: failed err %d (%s)\n", err, io->err);
1173*a81c3ea0SDavid du Colombier 			dumptd(td, "failed", ed->ctrl & Ediso);
1174*a81c3ea0SDavid du Colombier 		}
1175*a81c3ea0SDavid du Colombier 		td->last = 1;
1176*a81c3ea0SDavid du Colombier 		break;
1177*a81c3ea0SDavid du Colombier 	default:
1178*a81c3ea0SDavid du Colombier 		panic("ohci: td cc %ud unknown", err);
1179*a81c3ea0SDavid du Colombier 	}
1180*a81c3ea0SDavid du Colombier 
1181*a81c3ea0SDavid du Colombier 	if(td->last != 0){
1182*a81c3ea0SDavid du Colombier 		/*
1183*a81c3ea0SDavid du Colombier 		 * clear td list and halt flag.
1184*a81c3ea0SDavid du Colombier 		 */
1185*a81c3ea0SDavid du Colombier 		ed->head = (ed->head & Edtoggle) | ed->tail;
1186*a81c3ea0SDavid du Colombier 		ed->tds = pa2ptr(ed->tail);
1187*a81c3ea0SDavid du Colombier 		io->state = Qdone;
1188*a81c3ea0SDavid du Colombier 		wakeup(io);
1189*a81c3ea0SDavid du Colombier 	}
1190*a81c3ea0SDavid du Colombier }
1191*a81c3ea0SDavid du Colombier 
1192*a81c3ea0SDavid du Colombier /*
1193*a81c3ea0SDavid du Colombier  * BUG: Iso input streams are not implemented.
1194*a81c3ea0SDavid du Colombier  */
1195*a81c3ea0SDavid du Colombier static void
isointerrupt(Ctlr * ctlr,Ep * ep,Qio * io,Td * td,int)1196*a81c3ea0SDavid du Colombier isointerrupt(Ctlr *ctlr, Ep *ep, Qio *io, Td *td, int)
1197*a81c3ea0SDavid du Colombier {
1198*a81c3ea0SDavid du Colombier 	Isoio *iso;
1199*a81c3ea0SDavid du Colombier 	Block *bp;
1200*a81c3ea0SDavid du Colombier 	Ed *ed;
1201*a81c3ea0SDavid du Colombier 	int err, isoerr;
1202*a81c3ea0SDavid du Colombier 
1203*a81c3ea0SDavid du Colombier 	iso = ep->aux;
1204*a81c3ea0SDavid du Colombier 	ed = io->ed;
1205*a81c3ea0SDavid du Colombier 	if(io->state == Qclose)
1206*a81c3ea0SDavid du Colombier 		return;
1207*a81c3ea0SDavid du Colombier 	bp = td->bp;
1208*a81c3ea0SDavid du Colombier 	/*
1209*a81c3ea0SDavid du Colombier 	 * When we get more than half the frames consecutive errors
1210*a81c3ea0SDavid du Colombier 	 * we signal an actual error. Errors in the entire Td are
1211*a81c3ea0SDavid du Colombier 	 * more serious and are always singaled.
1212*a81c3ea0SDavid du Colombier 	 * Errors like overrun are not really errors. In fact, for
1213*a81c3ea0SDavid du Colombier 	 * output, errors cannot be really detected. The driver will
1214*a81c3ea0SDavid du Colombier 	 * hopefully notice I/O errors on input endpoints and detach the device.
1215*a81c3ea0SDavid du Colombier 	 */
1216*a81c3ea0SDavid du Colombier 	err = tderrs(td);
1217*a81c3ea0SDavid du Colombier 	isoerr = (td->offsets[0] >> Tdiccshift) & Tdiccmask;
1218*a81c3ea0SDavid du Colombier 	if(isoerr == Tdok || isoerr == Tdnotacc)
1219*a81c3ea0SDavid du Colombier 		iso->nerrs = 0;
1220*a81c3ea0SDavid du Colombier 	else if(iso->nerrs++ > iso->nframes/2)
1221*a81c3ea0SDavid du Colombier 		err = Tdstalled;
1222*a81c3ea0SDavid du Colombier 	if(err != Tdok && err != Tddataovr){
1223*a81c3ea0SDavid du Colombier 		bp->wp = bp->rp;
1224*a81c3ea0SDavid du Colombier 		io->err = errmsg(err);
1225*a81c3ea0SDavid du Colombier 		if(debug || ep->debug){
1226*a81c3ea0SDavid du Colombier 			print("ohci: isointerrupt: ep%d.%d: err %d (%s) frnum 0x%lux\n",
1227*a81c3ea0SDavid du Colombier 				ep->dev->nb, ep->nb,
1228*a81c3ea0SDavid du Colombier 				err, errmsg(err), ctlr->ohci->fmnumber);
1229*a81c3ea0SDavid du Colombier 			dumptd(td, "failed", ed->ctrl & Ediso);
1230*a81c3ea0SDavid du Colombier 		}
1231*a81c3ea0SDavid du Colombier 	}
1232*a81c3ea0SDavid du Colombier 	td->bp->wp = td->bp->rp;
1233*a81c3ea0SDavid du Colombier 	td->nbytes = 0;
1234*a81c3ea0SDavid du Colombier 	td->anext = iso->atds;
1235*a81c3ea0SDavid du Colombier 	iso->atds = td;
1236*a81c3ea0SDavid du Colombier 	iso->navail++;
1237*a81c3ea0SDavid du Colombier 	/*
1238*a81c3ea0SDavid du Colombier 	 * If almost all Tds are avail the user is not doing I/O at the
1239*a81c3ea0SDavid du Colombier 	 * required rate. We put another Td in place to keep the polling rate.
1240*a81c3ea0SDavid du Colombier 	 */
1241*a81c3ea0SDavid du Colombier 	if(iso->err == nil && iso->navail > iso->nframes - 10)
1242*a81c3ea0SDavid du Colombier 		isoadvance(ep, iso, pa2ptr(iso->ed->tail));
1243*a81c3ea0SDavid du Colombier 	/*
1244*a81c3ea0SDavid du Colombier 	 * If there's enough buffering futher I/O can be done.
1245*a81c3ea0SDavid du Colombier 	 */
1246*a81c3ea0SDavid du Colombier 	if(isocanwrite(iso))
1247*a81c3ea0SDavid du Colombier 		wakeup(iso);
1248*a81c3ea0SDavid du Colombier }
1249*a81c3ea0SDavid du Colombier 
1250*a81c3ea0SDavid du Colombier static void
interrupt(Ureg *,void * arg)1251*a81c3ea0SDavid du Colombier interrupt(Ureg *, void *arg)
1252*a81c3ea0SDavid du Colombier {
1253*a81c3ea0SDavid du Colombier 	Td *td, *ntd;
1254*a81c3ea0SDavid du Colombier 	Hci *hp;
1255*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
1256*a81c3ea0SDavid du Colombier 	ulong status, curred;
1257*a81c3ea0SDavid du Colombier 	int i, frno;
1258*a81c3ea0SDavid du Colombier 
1259*a81c3ea0SDavid du Colombier 	hp = arg;
1260*a81c3ea0SDavid du Colombier 	ctlr = hp->aux;
1261*a81c3ea0SDavid du Colombier 	ilock(ctlr);
1262*a81c3ea0SDavid du Colombier 	ctlr->ohci->intrdisable = Mie;
1263*a81c3ea0SDavid du Colombier 	coherence();
1264*a81c3ea0SDavid du Colombier 	status = ctlr->ohci->intrsts & ctlr->ohci->intrenable;
1265*a81c3ea0SDavid du Colombier 	status &= Oc|Rhsc|Fno|Ue|Rd|Sf|Wdh|So;
1266*a81c3ea0SDavid du Colombier 	frno = TRUNC(ctlr->ohci->fmnumber, Ntdframes);
1267*a81c3ea0SDavid du Colombier 	if(status & Wdh){
1268*a81c3ea0SDavid du Colombier 		/* lsb of donehead has bit to flag other intrs.  */
1269*a81c3ea0SDavid du Colombier 		td = pa2ptr(ctlr->hcca->donehead & ~0xF);
1270*a81c3ea0SDavid du Colombier 
1271*a81c3ea0SDavid du Colombier 		for(i = 0; td != nil && i < 1024; i++){
1272*a81c3ea0SDavid du Colombier //			if(0)ddprint("ohci tdinterrupt: td %#p\n", td);
1273*a81c3ea0SDavid du Colombier 			ntd = pa2ptr(td->nexttd & ~0xF);
1274*a81c3ea0SDavid du Colombier 			td->nexttd = 0;
1275*a81c3ea0SDavid du Colombier 			if(td->ep == nil || td->io == nil)
1276*a81c3ea0SDavid du Colombier 				panic("ohci: interrupt: ep %#p io %#p",
1277*a81c3ea0SDavid du Colombier 					td->ep, td->io);
1278*a81c3ea0SDavid du Colombier 			ohciinterrupts[td->ep->ttype]++;
1279*a81c3ea0SDavid du Colombier 			if(td->ep->ttype == Tiso)
1280*a81c3ea0SDavid du Colombier 				isointerrupt(ctlr, td->ep, td->io, td, frno);
1281*a81c3ea0SDavid du Colombier 			else
1282*a81c3ea0SDavid du Colombier 				qhinterrupt(ctlr, td->ep, td->io, td, frno);
1283*a81c3ea0SDavid du Colombier 			td = ntd;
1284*a81c3ea0SDavid du Colombier 		}
1285*a81c3ea0SDavid du Colombier 		if(i >= 1024)
1286*a81c3ea0SDavid du Colombier 			print("ohci: bug: more than 1024 done Tds?\n");
1287*a81c3ea0SDavid du Colombier 		ctlr->hcca->donehead = 0;
1288*a81c3ea0SDavid du Colombier 	}
1289*a81c3ea0SDavid du Colombier 
1290*a81c3ea0SDavid du Colombier 	ctlr->ohci->intrsts = status;
1291*a81c3ea0SDavid du Colombier 	status &= ~Wdh;
1292*a81c3ea0SDavid du Colombier 	status &= ~Sf;
1293*a81c3ea0SDavid du Colombier 	if(status & So){
1294*a81c3ea0SDavid du Colombier 		print("ohci: sched overrun: too much load\n");
1295*a81c3ea0SDavid du Colombier 		ctlr->overrun++;
1296*a81c3ea0SDavid du Colombier 		status &= ~So;
1297*a81c3ea0SDavid du Colombier 	}
1298*a81c3ea0SDavid du Colombier 	if((status & Ue) != 0){
1299*a81c3ea0SDavid du Colombier 		curred = ctlr->ohci->periodcurred;
1300*a81c3ea0SDavid du Colombier 		print("ohci: unrecoverable error frame 0x%.8lux ed 0x%.8lux, "
1301*a81c3ea0SDavid du Colombier 			"ints %d %d %d %d\n",
1302*a81c3ea0SDavid du Colombier 			ctlr->ohci->fmnumber, curred,
1303*a81c3ea0SDavid du Colombier 			ohciinterrupts[Tctl], ohciinterrupts[Tintr],
1304*a81c3ea0SDavid du Colombier 			ohciinterrupts[Tbulk], ohciinterrupts[Tiso]);
1305*a81c3ea0SDavid du Colombier 		if(curred != 0)
1306*a81c3ea0SDavid du Colombier 			dumped(pa2ptr(curred));
1307*a81c3ea0SDavid du Colombier 		status &= ~Ue;
1308*a81c3ea0SDavid du Colombier 	}
1309*a81c3ea0SDavid du Colombier 	if(status != 0)
1310*a81c3ea0SDavid du Colombier 		print("ohci interrupt: unhandled sts 0x%.8lux\n", status);
1311*a81c3ea0SDavid du Colombier 	ctlr->ohci->intrenable = Mie | Wdh | Ue;
1312*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
1313*a81c3ea0SDavid du Colombier }
1314*a81c3ea0SDavid du Colombier 
1315*a81c3ea0SDavid du Colombier /*
1316*a81c3ea0SDavid du Colombier  * The old dummy Td is used to implement the new Td.
1317*a81c3ea0SDavid du Colombier  * A new dummy is linked at the end of the old one and
1318*a81c3ea0SDavid du Colombier  * returned, to link further Tds if needed.
1319*a81c3ea0SDavid du Colombier  */
1320*a81c3ea0SDavid du Colombier static Td*
epgettd(Ep * ep,Qio * io,Td ** dtdp,int flags,void * a,int count)1321*a81c3ea0SDavid du Colombier epgettd(Ep *ep, Qio *io, Td **dtdp, int flags, void *a, int count)
1322*a81c3ea0SDavid du Colombier {
1323*a81c3ea0SDavid du Colombier 	Td *td, *dtd;
1324*a81c3ea0SDavid du Colombier 	Block *bp;
1325*a81c3ea0SDavid du Colombier 
1326*a81c3ea0SDavid du Colombier 	if(count <= BY2PG)
1327*a81c3ea0SDavid du Colombier 		bp = allocb(count);
1328*a81c3ea0SDavid du Colombier 	else{
1329*a81c3ea0SDavid du Colombier 		if(count > 2*BY2PG)
1330*a81c3ea0SDavid du Colombier 			panic("ohci: transfer > two pages");
1331*a81c3ea0SDavid du Colombier 		/* maximum of one physical page crossing allowed */
1332*a81c3ea0SDavid du Colombier 		bp = allocb(count+BY2PG);
1333*a81c3ea0SDavid du Colombier 		bp->rp = (uchar*)PGROUND((uintptr)bp->rp);
1334*a81c3ea0SDavid du Colombier 		bp->wp = bp->rp;
1335*a81c3ea0SDavid du Colombier 	}
1336*a81c3ea0SDavid du Colombier 	dtd = *dtdp;
1337*a81c3ea0SDavid du Colombier 	td = dtd;
1338*a81c3ea0SDavid du Colombier 	td->bp = bp;
1339*a81c3ea0SDavid du Colombier 	if(count > 0){
1340*a81c3ea0SDavid du Colombier 		td->cbp0 = td->cbp = ptr2pa(bp->wp);
1341*a81c3ea0SDavid du Colombier 		td->be = ptr2pa(bp->wp + count - 1);
1342*a81c3ea0SDavid du Colombier 		if(a != nil){
1343*a81c3ea0SDavid du Colombier 			/* validaddr((uintptr)a, count, 0); DEBUG */
1344*a81c3ea0SDavid du Colombier 			memmove(KSEG1ADDR(bp->wp), a, count);
1345*a81c3ea0SDavid du Colombier 		}
1346*a81c3ea0SDavid du Colombier 		bp->wp += count;
1347*a81c3ea0SDavid du Colombier 	}
1348*a81c3ea0SDavid du Colombier 	td->nbytes = count;
1349*a81c3ea0SDavid du Colombier 	td->ctrl = io->tok|Tdusetog|io->toggle|flags;
1350*a81c3ea0SDavid du Colombier 	if(io->toggle == Tddata0)
1351*a81c3ea0SDavid du Colombier 		io->toggle = Tddata1;
1352*a81c3ea0SDavid du Colombier 	else
1353*a81c3ea0SDavid du Colombier 		io->toggle = Tddata0;
1354*a81c3ea0SDavid du Colombier 	assert(td->ep == ep);
1355*a81c3ea0SDavid du Colombier 	td->io = io;
1356*a81c3ea0SDavid du Colombier 	dtd = tdalloc();	/* new dummy */
1357*a81c3ea0SDavid du Colombier 	dtd->ep = ep;
1358*a81c3ea0SDavid du Colombier 	td->nexttd = ptr2pa(dtd);
1359*a81c3ea0SDavid du Colombier 	td->next = dtd;
1360*a81c3ea0SDavid du Colombier 	*dtdp = dtd;
1361*a81c3ea0SDavid du Colombier 	return td;
1362*a81c3ea0SDavid du Colombier }
1363*a81c3ea0SDavid du Colombier 
1364*a81c3ea0SDavid du Colombier /*
1365*a81c3ea0SDavid du Colombier  * Try to get them idle
1366*a81c3ea0SDavid du Colombier  */
1367*a81c3ea0SDavid du Colombier static void
aborttds(Qio * io)1368*a81c3ea0SDavid du Colombier aborttds(Qio *io)
1369*a81c3ea0SDavid du Colombier {
1370*a81c3ea0SDavid du Colombier 	Ed *ed;
1371*a81c3ea0SDavid du Colombier 	Td *td;
1372*a81c3ea0SDavid du Colombier 
1373*a81c3ea0SDavid du Colombier 	ed = io->ed;
1374*a81c3ea0SDavid du Colombier 	if(ed == nil)
1375*a81c3ea0SDavid du Colombier 		return;
1376*a81c3ea0SDavid du Colombier 	ed->ctrl |= Edskip;
1377*a81c3ea0SDavid du Colombier 	for(td = ed->tds; td != nil; td = td->next)
1378*a81c3ea0SDavid du Colombier 		if(td->bp != nil)
1379*a81c3ea0SDavid du Colombier 			td->bp->wp = td->bp->rp;
1380*a81c3ea0SDavid du Colombier 	ed->head = (ed->head&0xF) | ed->tail;
1381*a81c3ea0SDavid du Colombier 	if((ed->ctrl & Ediso) == 0)
1382*a81c3ea0SDavid du Colombier 		ed->tds = pa2ptr(ed->tail);
1383*a81c3ea0SDavid du Colombier }
1384*a81c3ea0SDavid du Colombier 
1385*a81c3ea0SDavid du Colombier static int
epiodone(void * a)1386*a81c3ea0SDavid du Colombier epiodone(void *a)
1387*a81c3ea0SDavid du Colombier {
1388*a81c3ea0SDavid du Colombier 	Qio *io;
1389*a81c3ea0SDavid du Colombier 
1390*a81c3ea0SDavid du Colombier 	io = a;
1391*a81c3ea0SDavid du Colombier 	return io->state != Qrun;
1392*a81c3ea0SDavid du Colombier }
1393*a81c3ea0SDavid du Colombier 
1394*a81c3ea0SDavid du Colombier static void
epiowait(Ctlr * ctlr,Qio * io,int tmout,ulong)1395*a81c3ea0SDavid du Colombier epiowait(Ctlr *ctlr, Qio *io, int tmout, ulong)
1396*a81c3ea0SDavid du Colombier {
1397*a81c3ea0SDavid du Colombier 	Ed *ed;
1398*a81c3ea0SDavid du Colombier 	int timedout;
1399*a81c3ea0SDavid du Colombier 
1400*a81c3ea0SDavid du Colombier 	ed = io->ed;
1401*a81c3ea0SDavid du Colombier //	if(0)ddqprint("ohci io %#p sleep on ed %#p state %s\n",
1402*a81c3ea0SDavid du Colombier //		io, ed, iosname[io->state]);
1403*a81c3ea0SDavid du Colombier 	timedout = 0;
1404*a81c3ea0SDavid du Colombier 	if(waserror()){
1405*a81c3ea0SDavid du Colombier 		dqprint("ohci io %#p ed %#p timed out\n", io, ed);
1406*a81c3ea0SDavid du Colombier 		timedout++;
1407*a81c3ea0SDavid du Colombier 	}else{
1408*a81c3ea0SDavid du Colombier 		if(tmout == 0)
1409*a81c3ea0SDavid du Colombier 			sleep(io, epiodone, io);
1410*a81c3ea0SDavid du Colombier 		else
1411*a81c3ea0SDavid du Colombier 			tsleep(io, epiodone, io, tmout);
1412*a81c3ea0SDavid du Colombier 		poperror();
1413*a81c3ea0SDavid du Colombier 	}
1414*a81c3ea0SDavid du Colombier 	ilock(ctlr);
1415*a81c3ea0SDavid du Colombier 	if(io->state == Qrun)
1416*a81c3ea0SDavid du Colombier 		timedout = 1;
1417*a81c3ea0SDavid du Colombier 	else if(io->state != Qdone && io->state != Qclose)
1418*a81c3ea0SDavid du Colombier 		panic("epio: ed not done and not closed");
1419*a81c3ea0SDavid du Colombier 	if(timedout){
1420*a81c3ea0SDavid du Colombier 		aborttds(io);
1421*a81c3ea0SDavid du Colombier 		io->err = "request timed out";
1422*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
1423*a81c3ea0SDavid du Colombier 		if(!waserror()){
1424*a81c3ea0SDavid du Colombier 			tsleep(&up->sleep, return0, 0, Abortdelay);
1425*a81c3ea0SDavid du Colombier 			poperror();
1426*a81c3ea0SDavid du Colombier 		}
1427*a81c3ea0SDavid du Colombier 		ilock(ctlr);
1428*a81c3ea0SDavid du Colombier 	}
1429*a81c3ea0SDavid du Colombier 	if(io->state != Qclose)
1430*a81c3ea0SDavid du Colombier 		io->state = Qidle;
1431*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
1432*a81c3ea0SDavid du Colombier }
1433*a81c3ea0SDavid du Colombier 
1434*a81c3ea0SDavid du Colombier /*
1435*a81c3ea0SDavid du Colombier  * Non iso I/O.
1436*a81c3ea0SDavid du Colombier  * To make it work for control transfers, the caller may
1437*a81c3ea0SDavid du Colombier  * lock the Qio for the entire control transfer.
1438*a81c3ea0SDavid du Colombier  */
1439*a81c3ea0SDavid du Colombier static long
epio(Ep * ep,Qio * io,void * a,long count,int mustlock)1440*a81c3ea0SDavid du Colombier epio(Ep *ep, Qio *io, void *a, long count, int mustlock)
1441*a81c3ea0SDavid du Colombier {
1442*a81c3ea0SDavid du Colombier 	Ed *ed;
1443*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
1444*a81c3ea0SDavid du Colombier 	char buf[80];
1445*a81c3ea0SDavid du Colombier 	char *err;
1446*a81c3ea0SDavid du Colombier 	uchar *c;
1447*a81c3ea0SDavid du Colombier 	Td *td, *ltd, *ntd, *td0;
1448*a81c3ea0SDavid du Colombier 	int last, ntds, tmout;
1449*a81c3ea0SDavid du Colombier 	long tot, n;
1450*a81c3ea0SDavid du Colombier 	ulong load;
1451*a81c3ea0SDavid du Colombier 
1452*a81c3ea0SDavid du Colombier 	ed = io->ed;
1453*a81c3ea0SDavid du Colombier 	ctlr = ep->hp->aux;
1454*a81c3ea0SDavid du Colombier 	io->debug = ep->debug;
1455*a81c3ea0SDavid du Colombier 	tmout = ep->tmout;
1456*a81c3ea0SDavid du Colombier 	ddeprint("ohci: %s ep%d.%d io %#p count %ld\n",
1457*a81c3ea0SDavid du Colombier 		io->tok == Tdtokin ? "in" : "out",
1458*a81c3ea0SDavid du Colombier 		ep->dev->nb, ep->nb, io, count);
1459*a81c3ea0SDavid du Colombier 	if((debug > 1 || ep->debug > 1) && io->tok != Tdtokin){
1460*a81c3ea0SDavid du Colombier 		seprintdata(buf, buf+sizeof(buf), a, count);
1461*a81c3ea0SDavid du Colombier 		print("\t%s\n", buf);
1462*a81c3ea0SDavid du Colombier 	}
1463*a81c3ea0SDavid du Colombier 	if(mustlock){
1464*a81c3ea0SDavid du Colombier 		qlock(io);
1465*a81c3ea0SDavid du Colombier 		if(waserror()){
1466*a81c3ea0SDavid du Colombier 			qunlock(io);
1467*a81c3ea0SDavid du Colombier 			nexterror();
1468*a81c3ea0SDavid du Colombier 		}
1469*a81c3ea0SDavid du Colombier 	}
1470*a81c3ea0SDavid du Colombier 	io->err = nil;
1471*a81c3ea0SDavid du Colombier 	ilock(ctlr);
1472*a81c3ea0SDavid du Colombier 	if(io->state == Qclose){	/* Tds released by cancelio */
1473*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
1474*a81c3ea0SDavid du Colombier 		error(io->err ? io->err : Eio);
1475*a81c3ea0SDavid du Colombier 	}
1476*a81c3ea0SDavid du Colombier 	if(io->state != Qidle)
1477*a81c3ea0SDavid du Colombier 		panic("epio: qio not idle");
1478*a81c3ea0SDavid du Colombier 	io->state = Qinstall;
1479*a81c3ea0SDavid du Colombier 
1480*a81c3ea0SDavid du Colombier 	c = a;
1481*a81c3ea0SDavid du Colombier 	ltd = td0 = ed->tds;
1482*a81c3ea0SDavid du Colombier 	load = tot = 0;
1483*a81c3ea0SDavid du Colombier 	do{
1484*a81c3ea0SDavid du Colombier 		n = 2*BY2PG;
1485*a81c3ea0SDavid du Colombier 		if(count-tot < n)
1486*a81c3ea0SDavid du Colombier 			n = count-tot;
1487*a81c3ea0SDavid du Colombier 		if(c != nil && io->tok != Tdtokin)
1488*a81c3ea0SDavid du Colombier 			td = epgettd(ep, io, &ltd, 0, c+tot, n);
1489*a81c3ea0SDavid du Colombier 		else
1490*a81c3ea0SDavid du Colombier 			td = epgettd(ep, io, &ltd, 0, nil, n);
1491*a81c3ea0SDavid du Colombier 		tot += n;
1492*a81c3ea0SDavid du Colombier 		load += ep->load;
1493*a81c3ea0SDavid du Colombier 	}while(tot < count);
1494*a81c3ea0SDavid du Colombier 	if(td0 == nil || ltd == nil || td0 == ltd)
1495*a81c3ea0SDavid du Colombier 		panic("epio: no td");
1496*a81c3ea0SDavid du Colombier 	td->last = 1;
1497*a81c3ea0SDavid du Colombier 	if(debug > 2 || ep->debug > 2)
1498*a81c3ea0SDavid du Colombier 		dumptds(td0, "put td", ep->ttype == Tiso);
1499*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
1500*a81c3ea0SDavid du Colombier 
1501*a81c3ea0SDavid du Colombier 	ilock(ctlr);
1502*a81c3ea0SDavid du Colombier 	if(io->state != Qclose){
1503*a81c3ea0SDavid du Colombier 		io->iotime = TK2MS(MACHP(0)->ticks);
1504*a81c3ea0SDavid du Colombier 		io->state = Qrun;
1505*a81c3ea0SDavid du Colombier 		ed->tail = ptr2pa(ltd);
1506*a81c3ea0SDavid du Colombier 		if(ep->ttype == Tctl)
1507*a81c3ea0SDavid du Colombier 			ctlr->ohci->cmdsts |= Sclf;
1508*a81c3ea0SDavid du Colombier 		else if(ep->ttype == Tbulk)
1509*a81c3ea0SDavid du Colombier 			ctlr->ohci->cmdsts |= Sblf;
1510*a81c3ea0SDavid du Colombier 	}
1511*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
1512*a81c3ea0SDavid du Colombier 
1513*a81c3ea0SDavid du Colombier 	epiowait(ctlr, io, tmout, load);
1514*a81c3ea0SDavid du Colombier 	ilock(ctlr);
1515*a81c3ea0SDavid du Colombier 	if(debug > 1 || ep->debug > 1)
1516*a81c3ea0SDavid du Colombier 		dumptds(td0, "got td", 0);
1517*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
1518*a81c3ea0SDavid du Colombier 
1519*a81c3ea0SDavid du Colombier 	tot = 0;
1520*a81c3ea0SDavid du Colombier 	c = a;
1521*a81c3ea0SDavid du Colombier 	ntds = last = 0;
1522*a81c3ea0SDavid du Colombier 	for(td = td0; td != ltd; td = ntd){
1523*a81c3ea0SDavid du Colombier 		ntds++;
1524*a81c3ea0SDavid du Colombier 		/*
1525*a81c3ea0SDavid du Colombier 		 * If the Td is flagged as last we must
1526*a81c3ea0SDavid du Colombier 		 * ignore any following Td. The block may
1527*a81c3ea0SDavid du Colombier 		 * seem to have bytes but interrupt has not seen
1528*a81c3ea0SDavid du Colombier 		 * those Tds through the done queue, and they are void.
1529*a81c3ea0SDavid du Colombier 		 */
1530*a81c3ea0SDavid du Colombier 		if(last == 0 && tderrs(td) == Tdok){
1531*a81c3ea0SDavid du Colombier 			n = BLEN(td->bp);
1532*a81c3ea0SDavid du Colombier 			tot += n;
1533*a81c3ea0SDavid du Colombier 			if(c != nil && tdtok(td) == Tdtokin && n > 0){
1534*a81c3ea0SDavid du Colombier 				memmove(c, KSEG1ADDR(td->bp->rp), n);
1535*a81c3ea0SDavid du Colombier 				c += n;
1536*a81c3ea0SDavid du Colombier 			}
1537*a81c3ea0SDavid du Colombier 		}
1538*a81c3ea0SDavid du Colombier 		last |= td->last;
1539*a81c3ea0SDavid du Colombier 		ntd = td->next;
1540*a81c3ea0SDavid du Colombier 		tdfree(td);
1541*a81c3ea0SDavid du Colombier 	}
1542*a81c3ea0SDavid du Colombier 	if(edtoggle(ed) == 0)
1543*a81c3ea0SDavid du Colombier 		io->toggle = Tddata0;
1544*a81c3ea0SDavid du Colombier 	else
1545*a81c3ea0SDavid du Colombier 		io->toggle = Tddata1;
1546*a81c3ea0SDavid du Colombier 
1547*a81c3ea0SDavid du Colombier 	err = io->err;
1548*a81c3ea0SDavid du Colombier 	if(mustlock){
1549*a81c3ea0SDavid du Colombier 		qunlock(io);
1550*a81c3ea0SDavid du Colombier 		poperror();
1551*a81c3ea0SDavid du Colombier 	}
1552*a81c3ea0SDavid du Colombier 	ddeprint("ohci: io %#p: %d tds: return %ld err '%s'\n\n",
1553*a81c3ea0SDavid du Colombier 		io, ntds, tot, err);
1554*a81c3ea0SDavid du Colombier 	if(err != nil)
1555*a81c3ea0SDavid du Colombier 		error(err);
1556*a81c3ea0SDavid du Colombier 	if(tot < 0)
1557*a81c3ea0SDavid du Colombier 		error(Eio);
1558*a81c3ea0SDavid du Colombier 	return tot;
1559*a81c3ea0SDavid du Colombier }
1560*a81c3ea0SDavid du Colombier 
1561*a81c3ea0SDavid du Colombier /*
1562*a81c3ea0SDavid du Colombier  * halt condition was cleared on the endpoint. update our toggles.
1563*a81c3ea0SDavid du Colombier  */
1564*a81c3ea0SDavid du Colombier static void
clrhalt(Ep * ep)1565*a81c3ea0SDavid du Colombier clrhalt(Ep *ep)
1566*a81c3ea0SDavid du Colombier {
1567*a81c3ea0SDavid du Colombier 	Qio *io;
1568*a81c3ea0SDavid du Colombier 
1569*a81c3ea0SDavid du Colombier 	ep->clrhalt = 0;
1570*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
1571*a81c3ea0SDavid du Colombier 	case Tbulk:
1572*a81c3ea0SDavid du Colombier 	case Tintr:
1573*a81c3ea0SDavid du Colombier 		io = ep->aux;
1574*a81c3ea0SDavid du Colombier 		if(ep->mode != OREAD){
1575*a81c3ea0SDavid du Colombier 			qlock(&io[OWRITE]);
1576*a81c3ea0SDavid du Colombier 			io[OWRITE].toggle = Tddata0;
1577*a81c3ea0SDavid du Colombier 			deprint("ep clrhalt for io %#p\n", io+OWRITE);
1578*a81c3ea0SDavid du Colombier 			qunlock(&io[OWRITE]);
1579*a81c3ea0SDavid du Colombier 		}
1580*a81c3ea0SDavid du Colombier 		if(ep->mode != OWRITE){
1581*a81c3ea0SDavid du Colombier 			qlock(&io[OREAD]);
1582*a81c3ea0SDavid du Colombier 			io[OREAD].toggle = Tddata0;
1583*a81c3ea0SDavid du Colombier 			deprint("ep clrhalt for io %#p\n", io+OREAD);
1584*a81c3ea0SDavid du Colombier 			qunlock(&io[OREAD]);
1585*a81c3ea0SDavid du Colombier 		}
1586*a81c3ea0SDavid du Colombier 		break;
1587*a81c3ea0SDavid du Colombier 	}
1588*a81c3ea0SDavid du Colombier }
1589*a81c3ea0SDavid du Colombier 
1590*a81c3ea0SDavid du Colombier static long
epread(Ep * ep,void * a,long count)1591*a81c3ea0SDavid du Colombier epread(Ep *ep, void *a, long count)
1592*a81c3ea0SDavid du Colombier {
1593*a81c3ea0SDavid du Colombier 	Ctlio *cio;
1594*a81c3ea0SDavid du Colombier 	Qio *io;
1595*a81c3ea0SDavid du Colombier 	char buf[80];
1596*a81c3ea0SDavid du Colombier 	ulong delta;
1597*a81c3ea0SDavid du Colombier 
1598*a81c3ea0SDavid du Colombier 	if(ep->aux == nil)
1599*a81c3ea0SDavid du Colombier 		panic("epread: not open");
1600*a81c3ea0SDavid du Colombier 
1601*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
1602*a81c3ea0SDavid du Colombier 	case Tctl:
1603*a81c3ea0SDavid du Colombier 		cio = ep->aux;
1604*a81c3ea0SDavid du Colombier 		qlock(cio);
1605*a81c3ea0SDavid du Colombier 		if(waserror()){
1606*a81c3ea0SDavid du Colombier 			qunlock(cio);
1607*a81c3ea0SDavid du Colombier 			nexterror();
1608*a81c3ea0SDavid du Colombier 		}
1609*a81c3ea0SDavid du Colombier 		ddeprint("epread ctl ndata %d\n", cio->ndata);
1610*a81c3ea0SDavid du Colombier 		if(cio->ndata < 0)
1611*a81c3ea0SDavid du Colombier 			error("request expected");
1612*a81c3ea0SDavid du Colombier 		else if(cio->ndata == 0){
1613*a81c3ea0SDavid du Colombier 			cio->ndata = -1;
1614*a81c3ea0SDavid du Colombier 			count = 0;
1615*a81c3ea0SDavid du Colombier 		}else{
1616*a81c3ea0SDavid du Colombier 			if(count > cio->ndata)
1617*a81c3ea0SDavid du Colombier 				count = cio->ndata;
1618*a81c3ea0SDavid du Colombier 			if(count > 0)
1619*a81c3ea0SDavid du Colombier 				memmove(a, KSEG1ADDR(cio->data), count);
1620*a81c3ea0SDavid du Colombier 			/* BUG for big transfers */
1621*a81c3ea0SDavid du Colombier 			free(cio->data);
1622*a81c3ea0SDavid du Colombier 			cio->data = nil;
1623*a81c3ea0SDavid du Colombier 			cio->ndata = 0;	/* signal EOF next time */
1624*a81c3ea0SDavid du Colombier 		}
1625*a81c3ea0SDavid du Colombier 		qunlock(cio);
1626*a81c3ea0SDavid du Colombier 		poperror();
1627*a81c3ea0SDavid du Colombier 		if(debug>1 || ep->debug){
1628*a81c3ea0SDavid du Colombier 			seprintdata(buf, buf+sizeof(buf), a, count);
1629*a81c3ea0SDavid du Colombier 			print("epread: %s\n", buf);
1630*a81c3ea0SDavid du Colombier 		}
1631*a81c3ea0SDavid du Colombier 		return count;
1632*a81c3ea0SDavid du Colombier 	case Tbulk:
1633*a81c3ea0SDavid du Colombier 		io = ep->aux;
1634*a81c3ea0SDavid du Colombier 		if(ep->clrhalt)
1635*a81c3ea0SDavid du Colombier 			clrhalt(ep);
1636*a81c3ea0SDavid du Colombier 		return epio(ep, &io[OREAD], a, count, 1);
1637*a81c3ea0SDavid du Colombier 	case Tintr:
1638*a81c3ea0SDavid du Colombier 		io = ep->aux;
1639*a81c3ea0SDavid du Colombier 		delta = TK2MS(MACHP(0)->ticks) - io[OREAD].iotime + 1;
1640*a81c3ea0SDavid du Colombier 		if(delta < ep->pollival / 2)
1641*a81c3ea0SDavid du Colombier 			tsleep(&up->sleep, return0, 0, ep->pollival/2 - delta);
1642*a81c3ea0SDavid du Colombier 		if(ep->clrhalt)
1643*a81c3ea0SDavid du Colombier 			clrhalt(ep);
1644*a81c3ea0SDavid du Colombier 		return epio(ep, &io[OREAD], a, count, 1);
1645*a81c3ea0SDavid du Colombier 	case Tiso:
1646*a81c3ea0SDavid du Colombier 		panic("ohci: iso read not implemented");
1647*a81c3ea0SDavid du Colombier 		break;
1648*a81c3ea0SDavid du Colombier 	default:
1649*a81c3ea0SDavid du Colombier 		panic("epread: bad ep ttype %d", ep->ttype);
1650*a81c3ea0SDavid du Colombier 	}
1651*a81c3ea0SDavid du Colombier 	return -1;
1652*a81c3ea0SDavid du Colombier }
1653*a81c3ea0SDavid du Colombier 
1654*a81c3ea0SDavid du Colombier /*
1655*a81c3ea0SDavid du Colombier  * Control transfers are one setup write (data0)
1656*a81c3ea0SDavid du Colombier  * plus zero or more reads/writes (data1, data0, ...)
1657*a81c3ea0SDavid du Colombier  * plus a final write/read with data1 to ack.
1658*a81c3ea0SDavid du Colombier  * For both host to device and device to host we perform
1659*a81c3ea0SDavid du Colombier  * the entire transfer when the user writes the request,
1660*a81c3ea0SDavid du Colombier  * and keep any data read from the device for a later read.
1661*a81c3ea0SDavid du Colombier  * We call epio three times instead of placing all Tds at
1662*a81c3ea0SDavid du Colombier  * the same time because doing so leads to crc/tmout errors
1663*a81c3ea0SDavid du Colombier  * for some devices.
1664*a81c3ea0SDavid du Colombier  * Upon errors on the data phase we must still run the status
1665*a81c3ea0SDavid du Colombier  * phase or the device may cease responding in the future.
1666*a81c3ea0SDavid du Colombier  */
1667*a81c3ea0SDavid du Colombier static long
epctlio(Ep * ep,Ctlio * cio,void * a,long count)1668*a81c3ea0SDavid du Colombier epctlio(Ep *ep, Ctlio *cio, void *a, long count)
1669*a81c3ea0SDavid du Colombier {
1670*a81c3ea0SDavid du Colombier 	uchar *c;
1671*a81c3ea0SDavid du Colombier 	long len;
1672*a81c3ea0SDavid du Colombier 
1673*a81c3ea0SDavid du Colombier 	ddeprint("epctlio: cio %#p ep%d.%d count %ld\n",
1674*a81c3ea0SDavid du Colombier 		cio, ep->dev->nb, ep->nb, count);
1675*a81c3ea0SDavid du Colombier 	if(count < Rsetuplen)
1676*a81c3ea0SDavid du Colombier 		error("short usb command");
1677*a81c3ea0SDavid du Colombier 	qlock(cio);
1678*a81c3ea0SDavid du Colombier 	free(cio->data);
1679*a81c3ea0SDavid du Colombier 	cio->data = nil;
1680*a81c3ea0SDavid du Colombier 	cio->ndata = 0;
1681*a81c3ea0SDavid du Colombier 	if(waserror()){
1682*a81c3ea0SDavid du Colombier 		qunlock(cio);
1683*a81c3ea0SDavid du Colombier 		free(cio->data);
1684*a81c3ea0SDavid du Colombier 		cio->data = nil;
1685*a81c3ea0SDavid du Colombier 		cio->ndata = 0;
1686*a81c3ea0SDavid du Colombier 		nexterror();
1687*a81c3ea0SDavid du Colombier 	}
1688*a81c3ea0SDavid du Colombier 
1689*a81c3ea0SDavid du Colombier 	/* set the address if unset and out of configuration state */
1690*a81c3ea0SDavid du Colombier 	if(ep->dev->state != Dconfig && ep->dev->state != Dreset)
1691*a81c3ea0SDavid du Colombier 		if(cio->usbid == 0){
1692*a81c3ea0SDavid du Colombier 			cio->usbid = (ep->nb<<7)|(ep->dev->nb & Devmax);
1693*a81c3ea0SDavid du Colombier 			edsetaddr(cio->ed, cio->usbid);
1694*a81c3ea0SDavid du Colombier 		}
1695*a81c3ea0SDavid du Colombier 	/* adjust maxpkt if the user has learned a different one */
1696*a81c3ea0SDavid du Colombier 	if(edmaxpkt(cio->ed) != ep->maxpkt)
1697*a81c3ea0SDavid du Colombier 		edsetmaxpkt(cio->ed, ep->maxpkt);
1698*a81c3ea0SDavid du Colombier 	c = a;
1699*a81c3ea0SDavid du Colombier 	cio->tok = Tdtoksetup;
1700*a81c3ea0SDavid du Colombier 	cio->toggle = Tddata0;
1701*a81c3ea0SDavid du Colombier 	if(epio(ep, cio, a, Rsetuplen, 0) < Rsetuplen)
1702*a81c3ea0SDavid du Colombier 		error(Eio);
1703*a81c3ea0SDavid du Colombier 
1704*a81c3ea0SDavid du Colombier 	a = c + Rsetuplen;
1705*a81c3ea0SDavid du Colombier 	count -= Rsetuplen;
1706*a81c3ea0SDavid du Colombier 
1707*a81c3ea0SDavid du Colombier 	cio->toggle = Tddata1;
1708*a81c3ea0SDavid du Colombier 	if(c[Rtype] & Rd2h){
1709*a81c3ea0SDavid du Colombier 		cio->tok = Tdtokin;
1710*a81c3ea0SDavid du Colombier 		len = GET2(c+Rcount);
1711*a81c3ea0SDavid du Colombier 		if(len <= 0)
1712*a81c3ea0SDavid du Colombier 			error("bad length in d2h request");
1713*a81c3ea0SDavid du Colombier 		if(len > Maxctllen)
1714*a81c3ea0SDavid du Colombier 			error("d2h data too large to fit in ohci");
1715*a81c3ea0SDavid du Colombier 		a = cio->data = smalloc(len+1);
1716*a81c3ea0SDavid du Colombier 	}else{
1717*a81c3ea0SDavid du Colombier 		cio->tok = Tdtokout;
1718*a81c3ea0SDavid du Colombier 		len = count;
1719*a81c3ea0SDavid du Colombier 	}
1720*a81c3ea0SDavid du Colombier 	if(len > 0)
1721*a81c3ea0SDavid du Colombier 		if(waserror())
1722*a81c3ea0SDavid du Colombier 			len = -1;
1723*a81c3ea0SDavid du Colombier 		else{
1724*a81c3ea0SDavid du Colombier 			len = epio(ep, cio, a, len, 0);
1725*a81c3ea0SDavid du Colombier 			poperror();
1726*a81c3ea0SDavid du Colombier 		}
1727*a81c3ea0SDavid du Colombier 	if(c[Rtype] & Rd2h){
1728*a81c3ea0SDavid du Colombier 		count = Rsetuplen;
1729*a81c3ea0SDavid du Colombier 		cio->ndata = len;
1730*a81c3ea0SDavid du Colombier 		cio->tok = Tdtokout;
1731*a81c3ea0SDavid du Colombier 	}else{
1732*a81c3ea0SDavid du Colombier 		if(len < 0)
1733*a81c3ea0SDavid du Colombier 			count = -1;
1734*a81c3ea0SDavid du Colombier 		else
1735*a81c3ea0SDavid du Colombier 			count = Rsetuplen + len;
1736*a81c3ea0SDavid du Colombier 		cio->tok = Tdtokin;
1737*a81c3ea0SDavid du Colombier 	}
1738*a81c3ea0SDavid du Colombier 	cio->toggle = Tddata1;
1739*a81c3ea0SDavid du Colombier 	epio(ep, cio, nil, 0, 0);
1740*a81c3ea0SDavid du Colombier 	qunlock(cio);
1741*a81c3ea0SDavid du Colombier 	poperror();
1742*a81c3ea0SDavid du Colombier 	ddeprint("epctlio cio %#p return %ld\n", cio, count);
1743*a81c3ea0SDavid du Colombier 	return count;
1744*a81c3ea0SDavid du Colombier }
1745*a81c3ea0SDavid du Colombier 
1746*a81c3ea0SDavid du Colombier /*
1747*a81c3ea0SDavid du Colombier  * Put new samples in the dummy Td.
1748*a81c3ea0SDavid du Colombier  * BUG: This does only a transfer per Td. We could do up to 8.
1749*a81c3ea0SDavid du Colombier  */
1750*a81c3ea0SDavid du Colombier static long
putsamples(Ctlr * ctlr,Ep * ep,Isoio * iso,uchar * b,long count)1751*a81c3ea0SDavid du Colombier putsamples(Ctlr *ctlr, Ep *ep, Isoio *iso, uchar *b, long count)
1752*a81c3ea0SDavid du Colombier {
1753*a81c3ea0SDavid du Colombier 	Td *td;
1754*a81c3ea0SDavid du Colombier 	ulong n;
1755*a81c3ea0SDavid du Colombier 
1756*a81c3ea0SDavid du Colombier 	td = pa2ptr(iso->ed->tail);
1757*a81c3ea0SDavid du Colombier 	n = count;
1758*a81c3ea0SDavid du Colombier 	if(n > td->nbytes - BLEN(td->bp))
1759*a81c3ea0SDavid du Colombier 		n = td->nbytes - BLEN(td->bp);
1760*a81c3ea0SDavid du Colombier 	assert(td->bp->wp + n <= td->bp->lim);
1761*a81c3ea0SDavid du Colombier 	memmove(KSEG1ADDR(td->bp->wp), b, n);
1762*a81c3ea0SDavid du Colombier 	td->bp->wp += n;
1763*a81c3ea0SDavid du Colombier 	if(BLEN(td->bp) == td->nbytes){	/* full Td: activate it */
1764*a81c3ea0SDavid du Colombier 		ilock(ctlr);
1765*a81c3ea0SDavid du Colombier 		isoadvance(ep, iso, td);
1766*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
1767*a81c3ea0SDavid du Colombier 	}
1768*a81c3ea0SDavid du Colombier 	return n;
1769*a81c3ea0SDavid du Colombier }
1770*a81c3ea0SDavid du Colombier 
1771*a81c3ea0SDavid du Colombier static long
episowrite(Ep * ep,void * a,long count)1772*a81c3ea0SDavid du Colombier episowrite(Ep *ep, void *a, long count)
1773*a81c3ea0SDavid du Colombier {
1774*a81c3ea0SDavid du Colombier 	long tot, nw;
1775*a81c3ea0SDavid du Colombier 	char *err;
1776*a81c3ea0SDavid du Colombier 	uchar *b;
1777*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
1778*a81c3ea0SDavid du Colombier 	Isoio *iso;
1779*a81c3ea0SDavid du Colombier 
1780*a81c3ea0SDavid du Colombier 	ctlr = ep->hp->aux;
1781*a81c3ea0SDavid du Colombier 	iso = ep->aux;
1782*a81c3ea0SDavid du Colombier 	iso->debug = ep->debug;
1783*a81c3ea0SDavid du Colombier 
1784*a81c3ea0SDavid du Colombier 	qlock(iso);
1785*a81c3ea0SDavid du Colombier 	if(waserror()){
1786*a81c3ea0SDavid du Colombier 		qunlock(iso);
1787*a81c3ea0SDavid du Colombier 		nexterror();
1788*a81c3ea0SDavid du Colombier 	}
1789*a81c3ea0SDavid du Colombier 	diprint("ohci: episowrite: %#p ep%d.%d\n", iso, ep->dev->nb, ep->nb);
1790*a81c3ea0SDavid du Colombier 	ilock(ctlr);
1791*a81c3ea0SDavid du Colombier 	if(iso->state == Qclose){
1792*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
1793*a81c3ea0SDavid du Colombier 		error(iso->err ? iso->err : Eio);
1794*a81c3ea0SDavid du Colombier 	}
1795*a81c3ea0SDavid du Colombier 	iso->state = Qrun;
1796*a81c3ea0SDavid du Colombier 	b = a;
1797*a81c3ea0SDavid du Colombier 	for(tot = 0; tot < count; tot += nw){
1798*a81c3ea0SDavid du Colombier 		while(isocanwrite(iso) == 0){
1799*a81c3ea0SDavid du Colombier 			iunlock(ctlr);
1800*a81c3ea0SDavid du Colombier 			diprint("ohci: episowrite: %#p sleep\n", iso);
1801*a81c3ea0SDavid du Colombier 			if(waserror()){
1802*a81c3ea0SDavid du Colombier 				if(iso->err == nil)
1803*a81c3ea0SDavid du Colombier 					iso->err = "I/O timed out";
1804*a81c3ea0SDavid du Colombier 				ilock(ctlr);
1805*a81c3ea0SDavid du Colombier 				break;
1806*a81c3ea0SDavid du Colombier 			}
1807*a81c3ea0SDavid du Colombier 			tsleep(iso, isocanwrite, iso, ep->tmout);
1808*a81c3ea0SDavid du Colombier 			poperror();
1809*a81c3ea0SDavid du Colombier 			ilock(ctlr);
1810*a81c3ea0SDavid du Colombier 		}
1811*a81c3ea0SDavid du Colombier 		err = iso->err;
1812*a81c3ea0SDavid du Colombier 		iso->err = nil;
1813*a81c3ea0SDavid du Colombier 		if(iso->state == Qclose || err != nil){
1814*a81c3ea0SDavid du Colombier 			iunlock(ctlr);
1815*a81c3ea0SDavid du Colombier 			error(err ? err : Eio);
1816*a81c3ea0SDavid du Colombier 		}
1817*a81c3ea0SDavid du Colombier 		if(iso->state != Qrun)
1818*a81c3ea0SDavid du Colombier 			panic("episowrite: iso not running");
1819*a81c3ea0SDavid du Colombier 		iunlock(ctlr);		/* We could page fault here */
1820*a81c3ea0SDavid du Colombier 		nw = putsamples(ctlr, ep, iso, b+tot, count-tot);
1821*a81c3ea0SDavid du Colombier 		ilock(ctlr);
1822*a81c3ea0SDavid du Colombier 	}
1823*a81c3ea0SDavid du Colombier 	if(iso->state != Qclose)
1824*a81c3ea0SDavid du Colombier 		iso->state = Qdone;
1825*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
1826*a81c3ea0SDavid du Colombier 	err = iso->err;		/* in case it failed early */
1827*a81c3ea0SDavid du Colombier 	iso->err = nil;
1828*a81c3ea0SDavid du Colombier 	qunlock(iso);
1829*a81c3ea0SDavid du Colombier 	poperror();
1830*a81c3ea0SDavid du Colombier 	if(err != nil)
1831*a81c3ea0SDavid du Colombier 		error(err);
1832*a81c3ea0SDavid du Colombier 	diprint("ohci: episowrite: %#p %ld bytes\n", iso, tot);
1833*a81c3ea0SDavid du Colombier 	return tot;
1834*a81c3ea0SDavid du Colombier }
1835*a81c3ea0SDavid du Colombier 
1836*a81c3ea0SDavid du Colombier static long
epwrite(Ep * ep,void * a,long count)1837*a81c3ea0SDavid du Colombier epwrite(Ep *ep, void *a, long count)
1838*a81c3ea0SDavid du Colombier {
1839*a81c3ea0SDavid du Colombier 	Qio *io;
1840*a81c3ea0SDavid du Colombier 	Ctlio *cio;
1841*a81c3ea0SDavid du Colombier 	ulong delta;
1842*a81c3ea0SDavid du Colombier 	uchar *b;
1843*a81c3ea0SDavid du Colombier 	long tot, nw;
1844*a81c3ea0SDavid du Colombier 
1845*a81c3ea0SDavid du Colombier 	if(ep->aux == nil)
1846*a81c3ea0SDavid du Colombier 		panic("ohci: epwrite: not open");
1847*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
1848*a81c3ea0SDavid du Colombier 	case Tctl:
1849*a81c3ea0SDavid du Colombier 		cio = ep->aux;
1850*a81c3ea0SDavid du Colombier 		return epctlio(ep, cio, a, count);
1851*a81c3ea0SDavid du Colombier 	case Tbulk:
1852*a81c3ea0SDavid du Colombier 		io = ep->aux;
1853*a81c3ea0SDavid du Colombier 		if(ep->clrhalt)
1854*a81c3ea0SDavid du Colombier 			clrhalt(ep);
1855*a81c3ea0SDavid du Colombier 		/*
1856*a81c3ea0SDavid du Colombier 		 * Put at most Tdatomic Tds (512 bytes) at a time.
1857*a81c3ea0SDavid du Colombier 		 * Otherwise some devices produce babble errors.
1858*a81c3ea0SDavid du Colombier 		 */
1859*a81c3ea0SDavid du Colombier 		b = a;
1860*a81c3ea0SDavid du Colombier 		assert(a != nil);
1861*a81c3ea0SDavid du Colombier 		for(tot = 0; tot < count ; tot += nw){
1862*a81c3ea0SDavid du Colombier 			nw = count - tot;
1863*a81c3ea0SDavid du Colombier 			if(nw > Tdatomic * ep->maxpkt)
1864*a81c3ea0SDavid du Colombier 				nw = Tdatomic * ep->maxpkt;
1865*a81c3ea0SDavid du Colombier 			nw = epio(ep, &io[OWRITE], b+tot, nw, 1);
1866*a81c3ea0SDavid du Colombier 		}
1867*a81c3ea0SDavid du Colombier 		return tot;
1868*a81c3ea0SDavid du Colombier 	case Tintr:
1869*a81c3ea0SDavid du Colombier 		io = ep->aux;
1870*a81c3ea0SDavid du Colombier 		delta = TK2MS(MACHP(0)->ticks) - io[OWRITE].iotime + 1;
1871*a81c3ea0SDavid du Colombier 		if(delta < ep->pollival)
1872*a81c3ea0SDavid du Colombier 			tsleep(&up->sleep, return0, 0, ep->pollival - delta);
1873*a81c3ea0SDavid du Colombier 		if(ep->clrhalt)
1874*a81c3ea0SDavid du Colombier 			clrhalt(ep);
1875*a81c3ea0SDavid du Colombier 		return epio(ep, &io[OWRITE], a, count, 1);
1876*a81c3ea0SDavid du Colombier 	case Tiso:
1877*a81c3ea0SDavid du Colombier 		return episowrite(ep, a, count);
1878*a81c3ea0SDavid du Colombier 	default:
1879*a81c3ea0SDavid du Colombier 		panic("ohci: epwrite: bad ep ttype %d", ep->ttype);
1880*a81c3ea0SDavid du Colombier 	}
1881*a81c3ea0SDavid du Colombier 	return -1;
1882*a81c3ea0SDavid du Colombier }
1883*a81c3ea0SDavid du Colombier 
1884*a81c3ea0SDavid du Colombier static Ed*
newed(Ctlr * ctlr,Ep * ep,Qio * io,char *)1885*a81c3ea0SDavid du Colombier newed(Ctlr *ctlr, Ep *ep, Qio *io, char *)
1886*a81c3ea0SDavid du Colombier {
1887*a81c3ea0SDavid du Colombier 	Ed *ed;
1888*a81c3ea0SDavid du Colombier 	Td *td;
1889*a81c3ea0SDavid du Colombier 
1890*a81c3ea0SDavid du Colombier 	ed = io->ed = edalloc();	/* no errors raised here, really */
1891*a81c3ea0SDavid du Colombier 	td = tdalloc();
1892*a81c3ea0SDavid du Colombier 	td->ep = ep;
1893*a81c3ea0SDavid du Colombier 	td->io = io;
1894*a81c3ea0SDavid du Colombier 	ed->tail =  ptr2pa(td);
1895*a81c3ea0SDavid du Colombier 	ed->head = ptr2pa(td);
1896*a81c3ea0SDavid du Colombier 	ed->tds = td;
1897*a81c3ea0SDavid du Colombier 	ed->ep = ep;
1898*a81c3ea0SDavid du Colombier 	ed->ctrl = (ep->maxpkt & Edmpsmask) << Edmpsshift;
1899*a81c3ea0SDavid du Colombier 	if(ep->ttype == Tiso)
1900*a81c3ea0SDavid du Colombier 		ed->ctrl |= Ediso;
1901*a81c3ea0SDavid du Colombier 	if(waserror()){
1902*a81c3ea0SDavid du Colombier 		edfree(ed);
1903*a81c3ea0SDavid du Colombier 		io->ed = nil;
1904*a81c3ea0SDavid du Colombier 		nexterror();
1905*a81c3ea0SDavid du Colombier 	}
1906*a81c3ea0SDavid du Colombier 	/* For setup endpoints we start with the config address */
1907*a81c3ea0SDavid du Colombier 	if(ep->ttype != Tctl)
1908*a81c3ea0SDavid du Colombier 		edsetaddr(io->ed, io->usbid);
1909*a81c3ea0SDavid du Colombier 	if(ep->dev->speed == Lowspeed)
1910*a81c3ea0SDavid du Colombier 		ed->ctrl |= Edlow;
1911*a81c3ea0SDavid du Colombier 	switch(io->tok){
1912*a81c3ea0SDavid du Colombier 	case Tdtokin:
1913*a81c3ea0SDavid du Colombier 		ed->ctrl |= Edin;
1914*a81c3ea0SDavid du Colombier 		break;
1915*a81c3ea0SDavid du Colombier 	case Tdtokout:
1916*a81c3ea0SDavid du Colombier 		ed->ctrl |= Edout;
1917*a81c3ea0SDavid du Colombier 		break;
1918*a81c3ea0SDavid du Colombier 	default:
1919*a81c3ea0SDavid du Colombier 		ed->ctrl |= Edtddir;	/* Td will say */
1920*a81c3ea0SDavid du Colombier 		break;
1921*a81c3ea0SDavid du Colombier 	}
1922*a81c3ea0SDavid du Colombier 
1923*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
1924*a81c3ea0SDavid du Colombier 	case Tctl:
1925*a81c3ea0SDavid du Colombier 		ilock(ctlr);
1926*a81c3ea0SDavid du Colombier 		edlinked(ed, ctlhd(ctlr));
1927*a81c3ea0SDavid du Colombier 		setctlhd(ctlr, ed);
1928*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
1929*a81c3ea0SDavid du Colombier 		break;
1930*a81c3ea0SDavid du Colombier 	case Tbulk:
1931*a81c3ea0SDavid du Colombier 		ilock(ctlr);
1932*a81c3ea0SDavid du Colombier 		edlinked(ed, bulkhd(ctlr));
1933*a81c3ea0SDavid du Colombier 		setbulkhd(ctlr, ed);
1934*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
1935*a81c3ea0SDavid du Colombier 		break;
1936*a81c3ea0SDavid du Colombier 	case Tintr:
1937*a81c3ea0SDavid du Colombier 	case Tiso:
1938*a81c3ea0SDavid du Colombier 		ilock(ctlr);
1939*a81c3ea0SDavid du Colombier 		schedq(ctlr, io, ep->pollival);
1940*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
1941*a81c3ea0SDavid du Colombier 		break;
1942*a81c3ea0SDavid du Colombier 	default:
1943*a81c3ea0SDavid du Colombier 		panic("ohci: newed: bad ttype");
1944*a81c3ea0SDavid du Colombier 	}
1945*a81c3ea0SDavid du Colombier 	poperror();
1946*a81c3ea0SDavid du Colombier 	return ed;
1947*a81c3ea0SDavid du Colombier }
1948*a81c3ea0SDavid du Colombier 
1949*a81c3ea0SDavid du Colombier static void
isoopen(Ctlr * ctlr,Ep * ep)1950*a81c3ea0SDavid du Colombier isoopen(Ctlr *ctlr, Ep *ep)
1951*a81c3ea0SDavid du Colombier {
1952*a81c3ea0SDavid du Colombier 	Td *td, *edtds;
1953*a81c3ea0SDavid du Colombier 	Isoio *iso;
1954*a81c3ea0SDavid du Colombier 	int i;
1955*a81c3ea0SDavid du Colombier 
1956*a81c3ea0SDavid du Colombier 	iso = ep->aux;
1957*a81c3ea0SDavid du Colombier 	iso->usbid = (ep->nb<<7)|(ep->dev->nb & Devmax);
1958*a81c3ea0SDavid du Colombier 	iso->bw = ep->hz * ep->samplesz;	/* bytes/sec */
1959*a81c3ea0SDavid du Colombier 	if(ep->mode != OWRITE){
1960*a81c3ea0SDavid du Colombier 		print("ohci: bug: iso input streams not implemented\n");
1961*a81c3ea0SDavid du Colombier 		error("ohci iso input streams not implemented");
1962*a81c3ea0SDavid du Colombier 	}else
1963*a81c3ea0SDavid du Colombier 		iso->tok = Tdtokout;
1964*a81c3ea0SDavid du Colombier 
1965*a81c3ea0SDavid du Colombier 	iso->left = 0;
1966*a81c3ea0SDavid du Colombier 	iso->nerrs = 0;
1967*a81c3ea0SDavid du Colombier 	iso->frno = TRUNC(ctlr->ohci->fmnumber + 10, Ntdframes);
1968*a81c3ea0SDavid du Colombier 	iso->nframes = 1000 / ep->pollival;
1969*a81c3ea0SDavid du Colombier 	if(iso->nframes < 10){
1970*a81c3ea0SDavid du Colombier 		print("ohci: isoopen: less than 10 frames; using 10.\n");
1971*a81c3ea0SDavid du Colombier 		iso->nframes = 10;
1972*a81c3ea0SDavid du Colombier 	}
1973*a81c3ea0SDavid du Colombier 	iso->navail = iso->nframes;
1974*a81c3ea0SDavid du Colombier 	iso->atds = edtds = nil;
1975*a81c3ea0SDavid du Colombier 	for(i = 0; i < iso->nframes-1; i++){	/* -1 for dummy */
1976*a81c3ea0SDavid du Colombier 		td = tdalloc();
1977*a81c3ea0SDavid du Colombier 		td->ep = ep;
1978*a81c3ea0SDavid du Colombier 		td->io = iso;
1979*a81c3ea0SDavid du Colombier 		td->bp = allocb(ep->maxpkt);
1980*a81c3ea0SDavid du Colombier 		td->anext = iso->atds;		/* link as avail */
1981*a81c3ea0SDavid du Colombier 		iso->atds = td;
1982*a81c3ea0SDavid du Colombier 		td->next = edtds;
1983*a81c3ea0SDavid du Colombier 		edtds = td;
1984*a81c3ea0SDavid du Colombier 	}
1985*a81c3ea0SDavid du Colombier 	newed(ctlr, ep, iso, "iso");		/* allocates a dummy td */
1986*a81c3ea0SDavid du Colombier 	iso->ed->tds->bp = allocb(ep->maxpkt);	/* but not its block */
1987*a81c3ea0SDavid du Colombier 	iso->ed->tds->next = edtds;
1988*a81c3ea0SDavid du Colombier 	isodtdinit(ep, iso, iso->ed->tds);
1989*a81c3ea0SDavid du Colombier }
1990*a81c3ea0SDavid du Colombier 
1991*a81c3ea0SDavid du Colombier /*
1992*a81c3ea0SDavid du Colombier  * Allocate the endpoint and set it up for I/O
1993*a81c3ea0SDavid du Colombier  * in the controller. This must follow what's said
1994*a81c3ea0SDavid du Colombier  * in Ep regarding configuration, including perhaps
1995*a81c3ea0SDavid du Colombier  * the saved toggles (saved on a previous close of
1996*a81c3ea0SDavid du Colombier  * the endpoint data file by epclose).
1997*a81c3ea0SDavid du Colombier  */
1998*a81c3ea0SDavid du Colombier static void
epopen(Ep * ep)1999*a81c3ea0SDavid du Colombier epopen(Ep *ep)
2000*a81c3ea0SDavid du Colombier {
2001*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2002*a81c3ea0SDavid du Colombier 	Qio *io;
2003*a81c3ea0SDavid du Colombier 	Ctlio *cio;
2004*a81c3ea0SDavid du Colombier 	ulong usbid;
2005*a81c3ea0SDavid du Colombier 
2006*a81c3ea0SDavid du Colombier 	ctlr = ep->hp->aux;
2007*a81c3ea0SDavid du Colombier 	deprint("ohci: epopen ep%d.%d\n", ep->dev->nb, ep->nb);
2008*a81c3ea0SDavid du Colombier 	if(ep->aux != nil)
2009*a81c3ea0SDavid du Colombier 		panic("ohci: epopen called with open ep");
2010*a81c3ea0SDavid du Colombier 	if(waserror()){
2011*a81c3ea0SDavid du Colombier 		free(ep->aux);
2012*a81c3ea0SDavid du Colombier 		ep->aux = nil;
2013*a81c3ea0SDavid du Colombier 		nexterror();
2014*a81c3ea0SDavid du Colombier 	}
2015*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
2016*a81c3ea0SDavid du Colombier 	case Tnone:
2017*a81c3ea0SDavid du Colombier 		error("endpoint not configured");
2018*a81c3ea0SDavid du Colombier 	case Tiso:
2019*a81c3ea0SDavid du Colombier 		ep->aux = smalloc(sizeof(Isoio));
2020*a81c3ea0SDavid du Colombier 		isoopen(ctlr, ep);
2021*a81c3ea0SDavid du Colombier 		break;
2022*a81c3ea0SDavid du Colombier 	case Tctl:
2023*a81c3ea0SDavid du Colombier 		cio = ep->aux = smalloc(sizeof(Ctlio));
2024*a81c3ea0SDavid du Colombier 		cio->debug = ep->debug;
2025*a81c3ea0SDavid du Colombier 		cio->ndata = -1;
2026*a81c3ea0SDavid du Colombier 		cio->data = nil;
2027*a81c3ea0SDavid du Colombier 		cio->tok = -1;	/* invalid; Tds will say */
2028*a81c3ea0SDavid du Colombier 		if(ep->dev->isroot != 0 && ep->nb == 0)	/* root hub */
2029*a81c3ea0SDavid du Colombier 			break;
2030*a81c3ea0SDavid du Colombier 		newed(ctlr, ep, cio, "epc");
2031*a81c3ea0SDavid du Colombier 		break;
2032*a81c3ea0SDavid du Colombier 	case Tbulk:
2033*a81c3ea0SDavid du Colombier 		ep->pollival = 1;	/* assume this; doesn't really matter */
2034*a81c3ea0SDavid du Colombier 		/* and fall... */
2035*a81c3ea0SDavid du Colombier 	case Tintr:
2036*a81c3ea0SDavid du Colombier 		io = ep->aux = smalloc(sizeof(Qio)*2);
2037*a81c3ea0SDavid du Colombier 		io[OREAD].debug = io[OWRITE].debug = ep->debug;
2038*a81c3ea0SDavid du Colombier 		usbid = (ep->nb<<7)|(ep->dev->nb & Devmax);
2039*a81c3ea0SDavid du Colombier 		if(ep->mode != OREAD){
2040*a81c3ea0SDavid du Colombier 			if(ep->toggle[OWRITE] != 0)
2041*a81c3ea0SDavid du Colombier 				io[OWRITE].toggle = Tddata1;
2042*a81c3ea0SDavid du Colombier 			else
2043*a81c3ea0SDavid du Colombier 				io[OWRITE].toggle = Tddata0;
2044*a81c3ea0SDavid du Colombier 			io[OWRITE].tok = Tdtokout;
2045*a81c3ea0SDavid du Colombier 			io[OWRITE].usbid = usbid;
2046*a81c3ea0SDavid du Colombier 			io[OWRITE].bw = ep->maxpkt*1000/ep->pollival; /* bytes/s */
2047*a81c3ea0SDavid du Colombier 			newed(ctlr, ep, io+OWRITE, "epw");
2048*a81c3ea0SDavid du Colombier 		}
2049*a81c3ea0SDavid du Colombier 		if(ep->mode != OWRITE){
2050*a81c3ea0SDavid du Colombier 			if(ep->toggle[OREAD] != 0)
2051*a81c3ea0SDavid du Colombier 				io[OREAD].toggle = Tddata1;
2052*a81c3ea0SDavid du Colombier 			else
2053*a81c3ea0SDavid du Colombier 				io[OREAD].toggle = Tddata0;
2054*a81c3ea0SDavid du Colombier 			io[OREAD].tok = Tdtokin;
2055*a81c3ea0SDavid du Colombier 			io[OREAD].usbid = usbid;
2056*a81c3ea0SDavid du Colombier 			io[OREAD].bw = ep->maxpkt*1000/ep->pollival; /* bytes/s */
2057*a81c3ea0SDavid du Colombier 			newed(ctlr, ep, io+OREAD, "epr");
2058*a81c3ea0SDavid du Colombier 		}
2059*a81c3ea0SDavid du Colombier 		break;
2060*a81c3ea0SDavid du Colombier 	}
2061*a81c3ea0SDavid du Colombier 	deprint("ohci: epopen done:\n");
2062*a81c3ea0SDavid du Colombier 	if(debug || ep->debug)
2063*a81c3ea0SDavid du Colombier 		dump(ep->hp);
2064*a81c3ea0SDavid du Colombier 	poperror();
2065*a81c3ea0SDavid du Colombier }
2066*a81c3ea0SDavid du Colombier 
2067*a81c3ea0SDavid du Colombier static void
cancelio(Ep * ep,Qio * io)2068*a81c3ea0SDavid du Colombier cancelio(Ep *ep, Qio *io)
2069*a81c3ea0SDavid du Colombier {
2070*a81c3ea0SDavid du Colombier 	Ed *ed;
2071*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2072*a81c3ea0SDavid du Colombier 
2073*a81c3ea0SDavid du Colombier 	ctlr = ep->hp->aux;
2074*a81c3ea0SDavid du Colombier 
2075*a81c3ea0SDavid du Colombier 	ilock(ctlr);
2076*a81c3ea0SDavid du Colombier 	if(io == nil || io->state == Qclose){
2077*a81c3ea0SDavid du Colombier 		assert(io == nil || io->ed == nil);
2078*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
2079*a81c3ea0SDavid du Colombier 		return;
2080*a81c3ea0SDavid du Colombier 	}
2081*a81c3ea0SDavid du Colombier 	ed = io->ed;
2082*a81c3ea0SDavid du Colombier 	io->state = Qclose;
2083*a81c3ea0SDavid du Colombier 	io->err = Eio;
2084*a81c3ea0SDavid du Colombier 	aborttds(io);
2085*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
2086*a81c3ea0SDavid du Colombier 	if(!waserror()){
2087*a81c3ea0SDavid du Colombier 		tsleep(&up->sleep, return0, 0, Abortdelay);
2088*a81c3ea0SDavid du Colombier 		poperror();
2089*a81c3ea0SDavid du Colombier 	}
2090*a81c3ea0SDavid du Colombier 
2091*a81c3ea0SDavid du Colombier 	wakeup(io);
2092*a81c3ea0SDavid du Colombier 	qlock(io);
2093*a81c3ea0SDavid du Colombier 	/* wait for epio if running */
2094*a81c3ea0SDavid du Colombier 	qunlock(io);
2095*a81c3ea0SDavid du Colombier 
2096*a81c3ea0SDavid du Colombier 	ilock(ctlr);
2097*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
2098*a81c3ea0SDavid du Colombier 	case Tctl:
2099*a81c3ea0SDavid du Colombier 		unlinkctl(ctlr, ed);
2100*a81c3ea0SDavid du Colombier 		break;
2101*a81c3ea0SDavid du Colombier 	case Tbulk:
2102*a81c3ea0SDavid du Colombier 		unlinkbulk(ctlr, ed);
2103*a81c3ea0SDavid du Colombier 		break;
2104*a81c3ea0SDavid du Colombier 	case Tintr:
2105*a81c3ea0SDavid du Colombier 	case Tiso:
2106*a81c3ea0SDavid du Colombier 		unschedq(ctlr, io);
2107*a81c3ea0SDavid du Colombier 		break;
2108*a81c3ea0SDavid du Colombier 	default:
2109*a81c3ea0SDavid du Colombier 		panic("ohci cancelio: bad ttype");
2110*a81c3ea0SDavid du Colombier 	}
2111*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
2112*a81c3ea0SDavid du Colombier 	edfree(io->ed);
2113*a81c3ea0SDavid du Colombier 	io->ed = nil;
2114*a81c3ea0SDavid du Colombier }
2115*a81c3ea0SDavid du Colombier 
2116*a81c3ea0SDavid du Colombier static void
epclose(Ep * ep)2117*a81c3ea0SDavid du Colombier epclose(Ep *ep)
2118*a81c3ea0SDavid du Colombier {
2119*a81c3ea0SDavid du Colombier 	Ctlio *cio;
2120*a81c3ea0SDavid du Colombier 	Isoio *iso;
2121*a81c3ea0SDavid du Colombier 	Qio *io;
2122*a81c3ea0SDavid du Colombier 
2123*a81c3ea0SDavid du Colombier 	deprint("ohci: epclose ep%d.%d\n", ep->dev->nb, ep->nb);
2124*a81c3ea0SDavid du Colombier 	if(ep->aux == nil)
2125*a81c3ea0SDavid du Colombier 		panic("ohci: epclose called with closed ep");
2126*a81c3ea0SDavid du Colombier 	switch(ep->ttype){
2127*a81c3ea0SDavid du Colombier 	case Tctl:
2128*a81c3ea0SDavid du Colombier 		cio = ep->aux;
2129*a81c3ea0SDavid du Colombier 		cancelio(ep, cio);
2130*a81c3ea0SDavid du Colombier 		free(cio->data);
2131*a81c3ea0SDavid du Colombier 		cio->data = nil;
2132*a81c3ea0SDavid du Colombier 		break;
2133*a81c3ea0SDavid du Colombier 	case Tbulk:
2134*a81c3ea0SDavid du Colombier 	case Tintr:
2135*a81c3ea0SDavid du Colombier 		io = ep->aux;
2136*a81c3ea0SDavid du Colombier 		if(ep->mode != OWRITE){
2137*a81c3ea0SDavid du Colombier 			cancelio(ep, &io[OREAD]);
2138*a81c3ea0SDavid du Colombier 			if(io[OREAD].toggle == Tddata1)
2139*a81c3ea0SDavid du Colombier 				ep->toggle[OREAD] = 1;
2140*a81c3ea0SDavid du Colombier 		}
2141*a81c3ea0SDavid du Colombier 		if(ep->mode != OREAD){
2142*a81c3ea0SDavid du Colombier 			cancelio(ep, &io[OWRITE]);
2143*a81c3ea0SDavid du Colombier 			if(io[OWRITE].toggle == Tddata1)
2144*a81c3ea0SDavid du Colombier 				ep->toggle[OWRITE] = 1;
2145*a81c3ea0SDavid du Colombier 		}
2146*a81c3ea0SDavid du Colombier 		break;
2147*a81c3ea0SDavid du Colombier 	case Tiso:
2148*a81c3ea0SDavid du Colombier 		iso = ep->aux;
2149*a81c3ea0SDavid du Colombier 		cancelio(ep, iso);
2150*a81c3ea0SDavid du Colombier 		break;
2151*a81c3ea0SDavid du Colombier 	default:
2152*a81c3ea0SDavid du Colombier 		panic("epclose: bad ttype %d", ep->ttype);
2153*a81c3ea0SDavid du Colombier 	}
2154*a81c3ea0SDavid du Colombier 
2155*a81c3ea0SDavid du Colombier 	deprint("ohci: epclose ep%d.%d: done\n", ep->dev->nb, ep->nb);
2156*a81c3ea0SDavid du Colombier 	free(ep->aux);
2157*a81c3ea0SDavid du Colombier 	ep->aux = nil;
2158*a81c3ea0SDavid du Colombier }
2159*a81c3ea0SDavid du Colombier 
2160*a81c3ea0SDavid du Colombier static int
portreset(Hci * hp,int port,int on)2161*a81c3ea0SDavid du Colombier portreset(Hci *hp, int port, int on)
2162*a81c3ea0SDavid du Colombier {
2163*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2164*a81c3ea0SDavid du Colombier 	Ohci *ohci;
2165*a81c3ea0SDavid du Colombier 
2166*a81c3ea0SDavid du Colombier 	if(on == 0)
2167*a81c3ea0SDavid du Colombier 		return 0;
2168*a81c3ea0SDavid du Colombier 
2169*a81c3ea0SDavid du Colombier 	ctlr = hp->aux;
2170*a81c3ea0SDavid du Colombier 	qlock(&ctlr->resetl);
2171*a81c3ea0SDavid du Colombier 	if(waserror()){
2172*a81c3ea0SDavid du Colombier 		qunlock(&ctlr->resetl);
2173*a81c3ea0SDavid du Colombier 		nexterror();
2174*a81c3ea0SDavid du Colombier 	}
2175*a81c3ea0SDavid du Colombier 	ilock(ctlr);
2176*a81c3ea0SDavid du Colombier 	ohci = ctlr->ohci;
2177*a81c3ea0SDavid du Colombier 	ohci->rhportsts[port - 1] = Spp;
2178*a81c3ea0SDavid du Colombier 	if((ohci->rhportsts[port - 1] & Ccs) == 0){
2179*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
2180*a81c3ea0SDavid du Colombier 		error("port not connected");
2181*a81c3ea0SDavid du Colombier 	}
2182*a81c3ea0SDavid du Colombier 	ohci->rhportsts[port - 1] = Spr;
2183*a81c3ea0SDavid du Colombier 	while((ohci->rhportsts[port - 1] & Prsc) == 0){
2184*a81c3ea0SDavid du Colombier 		iunlock(ctlr);
2185*a81c3ea0SDavid du Colombier 		dprint("ohci: portreset, wait for reset complete\n");
2186*a81c3ea0SDavid du Colombier 		ilock(ctlr);
2187*a81c3ea0SDavid du Colombier 	}
2188*a81c3ea0SDavid du Colombier 	ohci->rhportsts[port - 1] = Prsc;
2189*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
2190*a81c3ea0SDavid du Colombier 	poperror();
2191*a81c3ea0SDavid du Colombier 	qunlock(&ctlr->resetl);
2192*a81c3ea0SDavid du Colombier 	return 0;
2193*a81c3ea0SDavid du Colombier }
2194*a81c3ea0SDavid du Colombier 
2195*a81c3ea0SDavid du Colombier static int
portenable(Hci * hp,int port,int on)2196*a81c3ea0SDavid du Colombier portenable(Hci *hp, int port, int on)
2197*a81c3ea0SDavid du Colombier {
2198*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2199*a81c3ea0SDavid du Colombier 
2200*a81c3ea0SDavid du Colombier 	ctlr = hp->aux;
2201*a81c3ea0SDavid du Colombier 	dprint("ohci: %#p port %d enable=%d\n", ctlr->ohci, port, on);
2202*a81c3ea0SDavid du Colombier 	qlock(&ctlr->resetl);
2203*a81c3ea0SDavid du Colombier 	if(waserror()){
2204*a81c3ea0SDavid du Colombier 		qunlock(&ctlr->resetl);
2205*a81c3ea0SDavid du Colombier 		nexterror();
2206*a81c3ea0SDavid du Colombier 	}
2207*a81c3ea0SDavid du Colombier 	ilock(ctlr);
2208*a81c3ea0SDavid du Colombier 	if(on)
2209*a81c3ea0SDavid du Colombier 		ctlr->ohci->rhportsts[port - 1] = Spe | Spp;
2210*a81c3ea0SDavid du Colombier 	else
2211*a81c3ea0SDavid du Colombier 		ctlr->ohci->rhportsts[port - 1] = Cpe;
2212*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
2213*a81c3ea0SDavid du Colombier 	tsleep(&up->sleep, return0, 0, Enabledelay);
2214*a81c3ea0SDavid du Colombier 	poperror();
2215*a81c3ea0SDavid du Colombier 	qunlock(&ctlr->resetl);
2216*a81c3ea0SDavid du Colombier 	return 0;
2217*a81c3ea0SDavid du Colombier }
2218*a81c3ea0SDavid du Colombier 
2219*a81c3ea0SDavid du Colombier static int
portstatus(Hci * hp,int port)2220*a81c3ea0SDavid du Colombier portstatus(Hci *hp, int port)
2221*a81c3ea0SDavid du Colombier {
2222*a81c3ea0SDavid du Colombier 	int v;
2223*a81c3ea0SDavid du Colombier 	Ctlr *ub;
2224*a81c3ea0SDavid du Colombier 	ulong ohcistatus;
2225*a81c3ea0SDavid du Colombier 
2226*a81c3ea0SDavid du Colombier 	/*
2227*a81c3ea0SDavid du Colombier 	 * We must return status bits as a
2228*a81c3ea0SDavid du Colombier 	 * get port status hub request would do.
2229*a81c3ea0SDavid du Colombier 	 */
2230*a81c3ea0SDavid du Colombier 	ub = hp->aux;
2231*a81c3ea0SDavid du Colombier 	ohcistatus = ub->ohci->rhportsts[port - 1];
2232*a81c3ea0SDavid du Colombier 	v = 0;
2233*a81c3ea0SDavid du Colombier 	if(ohcistatus & Ccs)
2234*a81c3ea0SDavid du Colombier 		v |= HPpresent;
2235*a81c3ea0SDavid du Colombier 	if(ohcistatus & Pes)
2236*a81c3ea0SDavid du Colombier 		v |= HPenable;
2237*a81c3ea0SDavid du Colombier 	if(ohcistatus & Pss)
2238*a81c3ea0SDavid du Colombier 		v |= HPsuspend;
2239*a81c3ea0SDavid du Colombier 	if(ohcistatus & Prs)
2240*a81c3ea0SDavid du Colombier 		v |= HPreset;
2241*a81c3ea0SDavid du Colombier 	else {
2242*a81c3ea0SDavid du Colombier 		/* port is not in reset; these potential writes are ok */
2243*a81c3ea0SDavid du Colombier 		if(ohcistatus & Csc){
2244*a81c3ea0SDavid du Colombier 			v |= HPstatuschg;
2245*a81c3ea0SDavid du Colombier 			ub->ohci->rhportsts[port - 1] = Csc;
2246*a81c3ea0SDavid du Colombier 		}
2247*a81c3ea0SDavid du Colombier 		if(ohcistatus & Pesc){
2248*a81c3ea0SDavid du Colombier 			v |= HPchange;
2249*a81c3ea0SDavid du Colombier 			ub->ohci->rhportsts[port - 1] = Pesc;
2250*a81c3ea0SDavid du Colombier 		}
2251*a81c3ea0SDavid du Colombier 	}
2252*a81c3ea0SDavid du Colombier 	if(ohcistatus & Lsda)
2253*a81c3ea0SDavid du Colombier 		v |= HPslow;
2254*a81c3ea0SDavid du Colombier 	if(v & (HPstatuschg|HPchange))
2255*a81c3ea0SDavid du Colombier 		ddprint("ohci port %d sts %#ulx hub sts %#x\n", port, ohcistatus, v);
2256*a81c3ea0SDavid du Colombier 	return v;
2257*a81c3ea0SDavid du Colombier }
2258*a81c3ea0SDavid du Colombier 
2259*a81c3ea0SDavid du Colombier static void
dumpohci(Ctlr * ctlr)2260*a81c3ea0SDavid du Colombier dumpohci(Ctlr *ctlr)
2261*a81c3ea0SDavid du Colombier {
2262*a81c3ea0SDavid du Colombier 	int i;
2263*a81c3ea0SDavid du Colombier 	ulong *ohci;
2264*a81c3ea0SDavid du Colombier 
2265*a81c3ea0SDavid du Colombier 	ohci = &ctlr->ohci->revision;
2266*a81c3ea0SDavid du Colombier 	print("ohci registers: \n");
2267*a81c3ea0SDavid du Colombier 	for(i = 0; i < sizeof(Ohci)/sizeof(ulong); i++)
2268*a81c3ea0SDavid du Colombier 		if(i < 3 || ohci[i] != 0)
2269*a81c3ea0SDavid du Colombier 			print("\t[%#2.2x]\t%#8.8ulx\n", i * 4, ohci[i]);
2270*a81c3ea0SDavid du Colombier 	print("\n");
2271*a81c3ea0SDavid du Colombier }
2272*a81c3ea0SDavid du Colombier 
2273*a81c3ea0SDavid du Colombier static void
init(Hci * hp)2274*a81c3ea0SDavid du Colombier init(Hci *hp)
2275*a81c3ea0SDavid du Colombier {
2276*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2277*a81c3ea0SDavid du Colombier 	Ohci *ohci;
2278*a81c3ea0SDavid du Colombier 	int i;
2279*a81c3ea0SDavid du Colombier 	ulong ival, ctrl, fmi;
2280*a81c3ea0SDavid du Colombier 
2281*a81c3ea0SDavid du Colombier 	ctlr = hp->aux;
2282*a81c3ea0SDavid du Colombier 	dprint("ohci %#p init\n", ctlr->ohci);
2283*a81c3ea0SDavid du Colombier 	ohci = ctlr->ohci;
2284*a81c3ea0SDavid du Colombier 
2285*a81c3ea0SDavid du Colombier 	fmi =  ctlr->ohci->fminterval;
2286*a81c3ea0SDavid du Colombier 	ctlr->ohci->cmdsts = Shcr;         /* reset the block */
2287*a81c3ea0SDavid du Colombier 	while(ctlr->ohci->cmdsts & Shcr)
2288*a81c3ea0SDavid du Colombier 		delay(1);  /* wait till reset complete, Ohci says 10us max. */
2289*a81c3ea0SDavid du Colombier 	ctlr->ohci->fminterval = fmi;
2290*a81c3ea0SDavid du Colombier 
2291*a81c3ea0SDavid du Colombier 	/*
2292*a81c3ea0SDavid du Colombier 	 * now that soft reset is done we are in suspend state.
2293*a81c3ea0SDavid du Colombier 	 * Setup registers which take in suspend state
2294*a81c3ea0SDavid du Colombier 	 * (will only be here for 2ms).
2295*a81c3ea0SDavid du Colombier 	 */
2296*a81c3ea0SDavid du Colombier 
2297*a81c3ea0SDavid du Colombier 	ctlr->ohci->hcca = ptr2pa(ctlr->hcca);
2298*a81c3ea0SDavid du Colombier 	setctlhd(ctlr, nil);
2299*a81c3ea0SDavid du Colombier 	ctlr->ohci->ctlcurred = 0;
2300*a81c3ea0SDavid du Colombier 	setbulkhd(ctlr, nil);
2301*a81c3ea0SDavid du Colombier 	ctlr->ohci->bulkcurred = 0;
2302*a81c3ea0SDavid du Colombier 
2303*a81c3ea0SDavid du Colombier 	ohci->intrenable = Mie | Wdh | Ue;
2304*a81c3ea0SDavid du Colombier 	ohci->control |= Ccle | Cble | Cple | Cie | Cfsoper;
2305*a81c3ea0SDavid du Colombier 
2306*a81c3ea0SDavid du Colombier 	/* set frame after operational */
2307*a81c3ea0SDavid du Colombier 	ohci->rhdesca = Nps;	/* no power switching */
2308*a81c3ea0SDavid du Colombier 	if(ohci->rhdesca & Nps){
2309*a81c3ea0SDavid du Colombier 		dprint("ohci: ports are not power switched\n");
2310*a81c3ea0SDavid du Colombier 	}else{
2311*a81c3ea0SDavid du Colombier 		dprint("ohci: ports are power switched\n");
2312*a81c3ea0SDavid du Colombier 		ohci->rhdesca &= ~Psm;
2313*a81c3ea0SDavid du Colombier 		ohci->rhsts &= ~Lpsc;
2314*a81c3ea0SDavid du Colombier 	}
2315*a81c3ea0SDavid du Colombier 	for(i = 0; i < ctlr->nports; i++)	/* paranoia */
2316*a81c3ea0SDavid du Colombier 		ohci->rhportsts[i] = 0;		/* this has no effect */
2317*a81c3ea0SDavid du Colombier 	delay(50);
2318*a81c3ea0SDavid du Colombier 
2319*a81c3ea0SDavid du Colombier 	for(i = 0; i < ctlr->nports; i++){
2320*a81c3ea0SDavid du Colombier 		ohci->rhportsts[i] =  Spp;
2321*a81c3ea0SDavid du Colombier 		if((ohci->rhportsts[i] & Ccs) != 0)
2322*a81c3ea0SDavid du Colombier 			ohci->rhportsts[i] |= Spr;
2323*a81c3ea0SDavid du Colombier 	}
2324*a81c3ea0SDavid du Colombier 	delay(100);
2325*a81c3ea0SDavid du Colombier 
2326*a81c3ea0SDavid du Colombier 	ctrl = ohci->control;
2327*a81c3ea0SDavid du Colombier 	if((ctrl & Cfsmask) != Cfsoper){
2328*a81c3ea0SDavid du Colombier 		ctrl = (ctrl & ~Cfsmask) | Cfsoper;
2329*a81c3ea0SDavid du Colombier 		ohci->control = ctrl;
2330*a81c3ea0SDavid du Colombier 		ohci->rhsts = Lpsc;
2331*a81c3ea0SDavid du Colombier 	}
2332*a81c3ea0SDavid du Colombier 	ival = ohci->fminterval & ~(Fmaxpktmask << Fmaxpktshift);
2333*a81c3ea0SDavid du Colombier 	ohci->fminterval = ival | (5120 << Fmaxpktshift);
2334*a81c3ea0SDavid du Colombier 
2335*a81c3ea0SDavid du Colombier 	if(debug > 1)
2336*a81c3ea0SDavid du Colombier 		dumpohci(ctlr);
2337*a81c3ea0SDavid du Colombier }
2338*a81c3ea0SDavid du Colombier 
2339*a81c3ea0SDavid du Colombier static void
scanpci(void)2340*a81c3ea0SDavid du Colombier scanpci(void)
2341*a81c3ea0SDavid du Colombier {
2342*a81c3ea0SDavid du Colombier 	ulong mem;
2343*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2344*a81c3ea0SDavid du Colombier 	Pcidev *p;
2345*a81c3ea0SDavid du Colombier 	int i;
2346*a81c3ea0SDavid du Colombier 	static int already = 0;
2347*a81c3ea0SDavid du Colombier 
2348*a81c3ea0SDavid du Colombier 	if(already)
2349*a81c3ea0SDavid du Colombier 		return;
2350*a81c3ea0SDavid du Colombier 	already = 1;
2351*a81c3ea0SDavid du Colombier 	p = nil;
2352*a81c3ea0SDavid du Colombier 	while(p = pcimatch(p, 0, 0)) {
2353*a81c3ea0SDavid du Colombier 		/*
2354*a81c3ea0SDavid du Colombier 		 * Find Ohci controllers (Programming Interface = 0x10).
2355*a81c3ea0SDavid du Colombier 		 */
2356*a81c3ea0SDavid du Colombier 		if(p->ccrb != Pcibcserial || p->ccru != Pciscusb ||
2357*a81c3ea0SDavid du Colombier 		    p->ccrp != 0x10)
2358*a81c3ea0SDavid du Colombier 			continue;
2359*a81c3ea0SDavid du Colombier 		mem = p->mem[0].bar & ~0x0F;
2360*a81c3ea0SDavid du Colombier 		dprint("ohci: %x/%x port 0x%lux size 0x%x irq %d\n",
2361*a81c3ea0SDavid du Colombier 			p->vid, p->did, mem, p->mem[0].size, p->intl);
2362*a81c3ea0SDavid du Colombier 		if(mem == 0){
2363*a81c3ea0SDavid du Colombier 			print("ohci: failed to map registers\n");
2364*a81c3ea0SDavid du Colombier 			continue;
2365*a81c3ea0SDavid du Colombier 		}
2366*a81c3ea0SDavid du Colombier //		if(p->intl == 0xFF || p->intl == 0) {
2367*a81c3ea0SDavid du Colombier //			print("ohci: no irq assigned for port %#lux\n", mem);
2368*a81c3ea0SDavid du Colombier //			continue;
2369*a81c3ea0SDavid du Colombier //		}
2370*a81c3ea0SDavid du Colombier 
2371*a81c3ea0SDavid du Colombier 		ctlr = malloc(sizeof(Ctlr));
2372*a81c3ea0SDavid du Colombier 		if (ctlr == nil)
2373*a81c3ea0SDavid du Colombier 			panic("ohci: out of memory");
2374*a81c3ea0SDavid du Colombier 		ctlr->pcidev = p;
2375*a81c3ea0SDavid du Colombier 		ctlr->ohci = KSEG1ADDR(PCIMEMADDR(mem));
2376*a81c3ea0SDavid du Colombier 		dprint("scanpci: ctlr %#p, ohci %#p\n", ctlr, ctlr->ohci);
2377*a81c3ea0SDavid du Colombier 		pcisetbme(p);
2378*a81c3ea0SDavid du Colombier 		pcisetpms(p, 0);
2379*a81c3ea0SDavid du Colombier 		for(i = 0; i < Nhcis; i++)
2380*a81c3ea0SDavid du Colombier 			if(ctlrs[i] == nil){
2381*a81c3ea0SDavid du Colombier 				ctlrs[i] = ctlr;
2382*a81c3ea0SDavid du Colombier 				break;
2383*a81c3ea0SDavid du Colombier 			}
2384*a81c3ea0SDavid du Colombier 		if(i == Nhcis)
2385*a81c3ea0SDavid du Colombier 			print("ohci: bug: no more controllers\n");
2386*a81c3ea0SDavid du Colombier 	}
2387*a81c3ea0SDavid du Colombier }
2388*a81c3ea0SDavid du Colombier 
2389*a81c3ea0SDavid du Colombier static void
usbdebug(Hci *,int d)2390*a81c3ea0SDavid du Colombier usbdebug(Hci*, int d)
2391*a81c3ea0SDavid du Colombier {
2392*a81c3ea0SDavid du Colombier 	debug = d;
2393*a81c3ea0SDavid du Colombier }
2394*a81c3ea0SDavid du Colombier 
2395*a81c3ea0SDavid du Colombier /*
2396*a81c3ea0SDavid du Colombier  * build the periodic scheduling tree:
2397*a81c3ea0SDavid du Colombier  * framesize must be a multiple of the tree size
2398*a81c3ea0SDavid du Colombier  */
2399*a81c3ea0SDavid du Colombier static void
mkqhtree(Ctlr * ctlr)2400*a81c3ea0SDavid du Colombier mkqhtree(Ctlr *ctlr)
2401*a81c3ea0SDavid du Colombier {
2402*a81c3ea0SDavid du Colombier 	int i, n, d, o, leaf0, depth;
2403*a81c3ea0SDavid du Colombier 	Ed **tree;
2404*a81c3ea0SDavid du Colombier 	Qtree *qt;
2405*a81c3ea0SDavid du Colombier 
2406*a81c3ea0SDavid du Colombier 	depth = flog2(32);
2407*a81c3ea0SDavid du Colombier 	n = (1 << (depth+1)) - 1;
2408*a81c3ea0SDavid du Colombier 	qt = mallocz(sizeof(*qt), 1);
2409*a81c3ea0SDavid du Colombier 	if(qt == nil)
2410*a81c3ea0SDavid du Colombier 		panic("usb: can't allocate scheduling tree");
2411*a81c3ea0SDavid du Colombier 	qt->nel = n;
2412*a81c3ea0SDavid du Colombier 	qt->depth = depth;
2413*a81c3ea0SDavid du Colombier 	qt->bw = mallocz(n * sizeof(qt->bw), 1);
2414*a81c3ea0SDavid du Colombier 	qt->root = tree = mallocz(n * sizeof(Ed *), 1);
2415*a81c3ea0SDavid du Colombier 	if(qt->bw == nil || qt->root == nil)
2416*a81c3ea0SDavid du Colombier 		panic("usb: can't allocate scheduling tree");
2417*a81c3ea0SDavid du Colombier 	for(i = 0; i < n; i++){
2418*a81c3ea0SDavid du Colombier 		if((tree[i] = edalloc()) == nil)
2419*a81c3ea0SDavid du Colombier 			panic("mkqhtree");
2420*a81c3ea0SDavid du Colombier 		tree[i]->ctrl = (8 << Edmpsshift);	/* not needed */
2421*a81c3ea0SDavid du Colombier 		tree[i]->ctrl |= Edskip;
2422*a81c3ea0SDavid du Colombier 
2423*a81c3ea0SDavid du Colombier 		if(i > 0)
2424*a81c3ea0SDavid du Colombier 			edlinked(tree[i], tree[(i-1)/2]);
2425*a81c3ea0SDavid du Colombier 		else
2426*a81c3ea0SDavid du Colombier 			edlinked(tree[i], nil);
2427*a81c3ea0SDavid du Colombier 	}
2428*a81c3ea0SDavid du Colombier 	ctlr->ntree = i;
2429*a81c3ea0SDavid du Colombier 	dprint("ohci: tree: %d endpoints allocated\n", i);
2430*a81c3ea0SDavid du Colombier 
2431*a81c3ea0SDavid du Colombier 	/* distribute leaves evenly round the frame list */
2432*a81c3ea0SDavid du Colombier 	leaf0 = n / 2;
2433*a81c3ea0SDavid du Colombier 	for(i = 0; i < 32; i++){
2434*a81c3ea0SDavid du Colombier 		o = 0;
2435*a81c3ea0SDavid du Colombier 		for(d = 0; d < depth; d++){
2436*a81c3ea0SDavid du Colombier 			o <<= 1;
2437*a81c3ea0SDavid du Colombier 			if(i & (1 << d))
2438*a81c3ea0SDavid du Colombier 				o |= 1;
2439*a81c3ea0SDavid du Colombier 		}
2440*a81c3ea0SDavid du Colombier 		if(leaf0 + o >= n){
2441*a81c3ea0SDavid du Colombier 			print("leaf0=%d o=%d i=%d n=%d\n", leaf0, o, i, n);
2442*a81c3ea0SDavid du Colombier 			break;
2443*a81c3ea0SDavid du Colombier 		}
2444*a81c3ea0SDavid du Colombier 		ctlr->hcca->intrtable[i] = ptr2pa(tree[leaf0 + o]);
2445*a81c3ea0SDavid du Colombier 	}
2446*a81c3ea0SDavid du Colombier 	ctlr->tree = qt;
2447*a81c3ea0SDavid du Colombier }
2448*a81c3ea0SDavid du Colombier 
2449*a81c3ea0SDavid du Colombier static void
ohcimeminit(Ctlr * ctlr)2450*a81c3ea0SDavid du Colombier ohcimeminit(Ctlr *ctlr)
2451*a81c3ea0SDavid du Colombier {
2452*a81c3ea0SDavid du Colombier 	Hcca *hcca;
2453*a81c3ea0SDavid du Colombier 
2454*a81c3ea0SDavid du Colombier 	edfree(edalloc());	/* allocate pools now */
2455*a81c3ea0SDavid du Colombier 	tdfree(tdalloc());
2456*a81c3ea0SDavid du Colombier 
2457*a81c3ea0SDavid du Colombier 	hcca = xspanalloc(sizeof(Hcca), 256, 0);
2458*a81c3ea0SDavid du Colombier 	if(hcca == nil)
2459*a81c3ea0SDavid du Colombier 		panic("usbhreset: no memory for Hcca");
2460*a81c3ea0SDavid du Colombier 	hcca = KSEG1ADDR(hcca);	// XXX
2461*a81c3ea0SDavid du Colombier 	memset(hcca, 0, sizeof(*hcca));
2462*a81c3ea0SDavid du Colombier 	ctlr->hcca = hcca;
2463*a81c3ea0SDavid du Colombier 
2464*a81c3ea0SDavid du Colombier 	mkqhtree(ctlr);
2465*a81c3ea0SDavid du Colombier }
2466*a81c3ea0SDavid du Colombier 
2467*a81c3ea0SDavid du Colombier static void
ohcireset(Ctlr * ctlr)2468*a81c3ea0SDavid du Colombier ohcireset(Ctlr *ctlr)
2469*a81c3ea0SDavid du Colombier {
2470*a81c3ea0SDavid du Colombier 	ilock(ctlr);
2471*a81c3ea0SDavid du Colombier 	dprint("ohci %#p reset\n", ctlr->ohci);
2472*a81c3ea0SDavid du Colombier 
2473*a81c3ea0SDavid du Colombier 	/*
2474*a81c3ea0SDavid du Colombier 	 * usually enter here in reset, wait till its through,
2475*a81c3ea0SDavid du Colombier 	 * then do our own so we are on known timing conditions.
2476*a81c3ea0SDavid du Colombier 	 * Is this needed?
2477*a81c3ea0SDavid du Colombier 	 */
2478*a81c3ea0SDavid du Colombier 	delay(100);
2479*a81c3ea0SDavid du Colombier 	ctlr->ohci->control = 0;
2480*a81c3ea0SDavid du Colombier 	delay(100);
2481*a81c3ea0SDavid du Colombier 
2482*a81c3ea0SDavid du Colombier 	/* legacy support register: turn off lunacy mode */
2483*a81c3ea0SDavid du Colombier 	pcicfgw16(ctlr->pcidev, 0xc0, 0x2000);
2484*a81c3ea0SDavid du Colombier 
2485*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
2486*a81c3ea0SDavid du Colombier }
2487*a81c3ea0SDavid du Colombier 
2488*a81c3ea0SDavid du Colombier static void
shutdown(Hci * hp)2489*a81c3ea0SDavid du Colombier shutdown(Hci *hp)
2490*a81c3ea0SDavid du Colombier {
2491*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2492*a81c3ea0SDavid du Colombier 
2493*a81c3ea0SDavid du Colombier 	ctlr = hp->aux;
2494*a81c3ea0SDavid du Colombier 
2495*a81c3ea0SDavid du Colombier 	ilock(ctlr);
2496*a81c3ea0SDavid du Colombier 	ctlr->ohci->intrdisable = Mie;
2497*a81c3ea0SDavid du Colombier 	ctlr->ohci->control = 0;
2498*a81c3ea0SDavid du Colombier 	coherence();
2499*a81c3ea0SDavid du Colombier 	delay(100);
2500*a81c3ea0SDavid du Colombier 	iunlock(ctlr);
2501*a81c3ea0SDavid du Colombier }
2502*a81c3ea0SDavid du Colombier 
2503*a81c3ea0SDavid du Colombier static int
reset(Hci * hp)2504*a81c3ea0SDavid du Colombier reset(Hci *hp)
2505*a81c3ea0SDavid du Colombier {
2506*a81c3ea0SDavid du Colombier 	int i;
2507*a81c3ea0SDavid du Colombier 	Ctlr *ctlr;
2508*a81c3ea0SDavid du Colombier 	Pcidev *p;
2509*a81c3ea0SDavid du Colombier 	static Lock resetlck;
2510*a81c3ea0SDavid du Colombier 
2511*a81c3ea0SDavid du Colombier 	if(getconf("*nousbohci"))
2512*a81c3ea0SDavid du Colombier 		return -1;
2513*a81c3ea0SDavid du Colombier 	ilock(&resetlck);
2514*a81c3ea0SDavid du Colombier 	scanpci();
2515*a81c3ea0SDavid du Colombier 
2516*a81c3ea0SDavid du Colombier 	/*
2517*a81c3ea0SDavid du Colombier 	 * Any adapter matches if no hp->port is supplied,
2518*a81c3ea0SDavid du Colombier 	 * otherwise the ports must match.
2519*a81c3ea0SDavid du Colombier 	 */
2520*a81c3ea0SDavid du Colombier 	ctlr = nil;
2521*a81c3ea0SDavid du Colombier 	for(i = 0; i < Nhcis && ctlrs[i] != nil; i++){
2522*a81c3ea0SDavid du Colombier 		ctlr = ctlrs[i];
2523*a81c3ea0SDavid du Colombier 		if(ctlr->active == 0)
2524*a81c3ea0SDavid du Colombier 		if(hp->port == 0 || hp->port == (uintptr)ctlr->ohci){
2525*a81c3ea0SDavid du Colombier 			ctlr->active = 1;
2526*a81c3ea0SDavid du Colombier 			break;
2527*a81c3ea0SDavid du Colombier 		}
2528*a81c3ea0SDavid du Colombier 	}
2529*a81c3ea0SDavid du Colombier 	iunlock(&resetlck);
2530*a81c3ea0SDavid du Colombier 	if(ctlrs[i] == nil || i == Nhcis)
2531*a81c3ea0SDavid du Colombier 		return -1;
2532*a81c3ea0SDavid du Colombier 	if(ctlr->ohci->control == ~0)
2533*a81c3ea0SDavid du Colombier 		return -1;
2534*a81c3ea0SDavid du Colombier 
2535*a81c3ea0SDavid du Colombier 
2536*a81c3ea0SDavid du Colombier 	p = ctlr->pcidev;
2537*a81c3ea0SDavid du Colombier 	hp->aux = ctlr;
2538*a81c3ea0SDavid du Colombier 	hp->port = (uintptr)ctlr->ohci;
2539*a81c3ea0SDavid du Colombier 	hp->irq = ILpci;
2540*a81c3ea0SDavid du Colombier 	hp->tbdf = p->tbdf;
2541*a81c3ea0SDavid du Colombier 	ctlr->nports = hp->nports = ctlr->ohci->rhdesca & 0xff;
2542*a81c3ea0SDavid du Colombier 
2543*a81c3ea0SDavid du Colombier 	ohcireset(ctlr);
2544*a81c3ea0SDavid du Colombier 	ohcimeminit(ctlr);
2545*a81c3ea0SDavid du Colombier 
2546*a81c3ea0SDavid du Colombier 	/*
2547*a81c3ea0SDavid du Colombier 	 * Linkage to the generic HCI driver.
2548*a81c3ea0SDavid du Colombier 	 */
2549*a81c3ea0SDavid du Colombier 	hp->init = init;
2550*a81c3ea0SDavid du Colombier 	hp->dump = dump;
2551*a81c3ea0SDavid du Colombier 	hp->interrupt = interrupt;
2552*a81c3ea0SDavid du Colombier 	hp->epopen = epopen;
2553*a81c3ea0SDavid du Colombier 	hp->epclose = epclose;
2554*a81c3ea0SDavid du Colombier 	hp->epread = epread;
2555*a81c3ea0SDavid du Colombier 	hp->epwrite = epwrite;
2556*a81c3ea0SDavid du Colombier 	hp->seprintep = seprintep;
2557*a81c3ea0SDavid du Colombier 	hp->portenable = portenable;
2558*a81c3ea0SDavid du Colombier 	hp->portreset = portreset;
2559*a81c3ea0SDavid du Colombier 	hp->portstatus = portstatus;
2560*a81c3ea0SDavid du Colombier 	hp->shutdown = shutdown;
2561*a81c3ea0SDavid du Colombier 	hp->debug = usbdebug;
2562*a81c3ea0SDavid du Colombier 	hp->type = "ohci";
2563*a81c3ea0SDavid du Colombier 	return 0;
2564*a81c3ea0SDavid du Colombier }
2565*a81c3ea0SDavid du Colombier 
2566*a81c3ea0SDavid du Colombier void
usbohcilink(void)2567*a81c3ea0SDavid du Colombier usbohcilink(void)
2568*a81c3ea0SDavid du Colombier {
2569*a81c3ea0SDavid du Colombier 	addhcitype("ohci", reset);
2570*a81c3ea0SDavid du Colombier }
2571