1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "../port/lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "io.h"
7*74a4d8c2SCharles.Forsyth #include "../port/error.h"
8*74a4d8c2SCharles.Forsyth
9*74a4d8c2SCharles.Forsyth #include "usb.h"
10*74a4d8c2SCharles.Forsyth
11*74a4d8c2SCharles.Forsyth static int debug = 0;
12*74a4d8c2SCharles.Forsyth
13*74a4d8c2SCharles.Forsyth #define Chatty 1
14*74a4d8c2SCharles.Forsyth #define DPRINT if(Chatty)print
15*74a4d8c2SCharles.Forsyth #define XPRINT if(debug)iprint
16*74a4d8c2SCharles.Forsyth
17*74a4d8c2SCharles.Forsyth Usbhost* usbhost[MaxUsb];
18*74a4d8c2SCharles.Forsyth
19*74a4d8c2SCharles.Forsyth static char *devstates[] = {
20*74a4d8c2SCharles.Forsyth [Disabled] "Disabled",
21*74a4d8c2SCharles.Forsyth [Attached] "Attached",
22*74a4d8c2SCharles.Forsyth [Enabled] "Enabled",
23*74a4d8c2SCharles.Forsyth [Assigned] "Assigned",
24*74a4d8c2SCharles.Forsyth [Configured] "Configured",
25*74a4d8c2SCharles.Forsyth };
26*74a4d8c2SCharles.Forsyth
27*74a4d8c2SCharles.Forsyth static char Ebadusbmsg[] = "invalid parameters to USB ctl message";
28*74a4d8c2SCharles.Forsyth
29*74a4d8c2SCharles.Forsyth enum
30*74a4d8c2SCharles.Forsyth {
31*74a4d8c2SCharles.Forsyth Qtopdir = 0,
32*74a4d8c2SCharles.Forsyth Q2nd,
33*74a4d8c2SCharles.Forsyth Qnew,
34*74a4d8c2SCharles.Forsyth Qport,
35*74a4d8c2SCharles.Forsyth Q3rd,
36*74a4d8c2SCharles.Forsyth Qctl,
37*74a4d8c2SCharles.Forsyth Qstatus,
38*74a4d8c2SCharles.Forsyth Qep0,
39*74a4d8c2SCharles.Forsyth /* other endpoint files */
40*74a4d8c2SCharles.Forsyth };
41*74a4d8c2SCharles.Forsyth
42*74a4d8c2SCharles.Forsyth /*
43*74a4d8c2SCharles.Forsyth * Qid path is:
44*74a4d8c2SCharles.Forsyth * 8 bits of file type (qids above)
45*74a4d8c2SCharles.Forsyth * 8 bits of slot number; default address 0 used for per-controller files
46*74a4d8c2SCharles.Forsyth * 4 bits of controller number
47*74a4d8c2SCharles.Forsyth */
48*74a4d8c2SCharles.Forsyth enum {
49*74a4d8c2SCharles.Forsyth TYPEBITS = 8,
50*74a4d8c2SCharles.Forsyth SLOTBITS = 8,
51*74a4d8c2SCharles.Forsyth CTLRBITS = 4,
52*74a4d8c2SCharles.Forsyth
53*74a4d8c2SCharles.Forsyth SLOTSHIFT = TYPEBITS,
54*74a4d8c2SCharles.Forsyth CTLRSHIFT = SLOTSHIFT+SLOTBITS,
55*74a4d8c2SCharles.Forsyth
56*74a4d8c2SCharles.Forsyth TYPEMASK = (1<<TYPEBITS)-1,
57*74a4d8c2SCharles.Forsyth SLOTMASK = (1<<SLOTBITS)-1,
58*74a4d8c2SCharles.Forsyth CTLRMASK = (1<<CTLRBITS)-1,
59*74a4d8c2SCharles.Forsyth };
60*74a4d8c2SCharles.Forsyth
61*74a4d8c2SCharles.Forsyth #define TYPE(q) (((ulong)(q).path)&TYPEMASK)
62*74a4d8c2SCharles.Forsyth #define SLOT(q) ((((ulong)(q).path)>>SLOTSHIFT)&SLOTMASK)
63*74a4d8c2SCharles.Forsyth #define CTLR(q) ((((ulong)(q).path)>>CTLRSHIFT)&CTLRMASK)
64*74a4d8c2SCharles.Forsyth #define PATH(t, s, c) ((t)|((s)<<SLOTSHIFT)|((c)<<CTLRSHIFT))
65*74a4d8c2SCharles.Forsyth
66*74a4d8c2SCharles.Forsyth static Dirtab usbdir2[] = {
67*74a4d8c2SCharles.Forsyth "new", {Qnew}, 0, 0666,
68*74a4d8c2SCharles.Forsyth "port", {Qport}, 0, 0666,
69*74a4d8c2SCharles.Forsyth };
70*74a4d8c2SCharles.Forsyth
71*74a4d8c2SCharles.Forsyth static Dirtab usbdir3[]={
72*74a4d8c2SCharles.Forsyth "ctl", {Qctl}, 0, 0666,
73*74a4d8c2SCharles.Forsyth "status", {Qstatus}, 0, 0444,
74*74a4d8c2SCharles.Forsyth "setup", {Qep0}, 0, 0666,
75*74a4d8c2SCharles.Forsyth /* epNdata names are generated on demand */
76*74a4d8c2SCharles.Forsyth };
77*74a4d8c2SCharles.Forsyth
78*74a4d8c2SCharles.Forsyth enum
79*74a4d8c2SCharles.Forsyth {
80*74a4d8c2SCharles.Forsyth PMdisable,
81*74a4d8c2SCharles.Forsyth PMenable,
82*74a4d8c2SCharles.Forsyth PMreset,
83*74a4d8c2SCharles.Forsyth };
84*74a4d8c2SCharles.Forsyth
85*74a4d8c2SCharles.Forsyth enum
86*74a4d8c2SCharles.Forsyth {
87*74a4d8c2SCharles.Forsyth CMclass,
88*74a4d8c2SCharles.Forsyth CMdata,
89*74a4d8c2SCharles.Forsyth CMdebug,
90*74a4d8c2SCharles.Forsyth CMep,
91*74a4d8c2SCharles.Forsyth CMmaxpkt,
92*74a4d8c2SCharles.Forsyth CMadjust,
93*74a4d8c2SCharles.Forsyth CMspeed,
94*74a4d8c2SCharles.Forsyth CMunstall,
95*74a4d8c2SCharles.Forsyth };
96*74a4d8c2SCharles.Forsyth
97*74a4d8c2SCharles.Forsyth static Cmdtab usbportmsg[] =
98*74a4d8c2SCharles.Forsyth {
99*74a4d8c2SCharles.Forsyth PMdisable, "disable", 2,
100*74a4d8c2SCharles.Forsyth PMenable, "enable", 2,
101*74a4d8c2SCharles.Forsyth PMreset, "reset", 2,
102*74a4d8c2SCharles.Forsyth };
103*74a4d8c2SCharles.Forsyth
104*74a4d8c2SCharles.Forsyth static Cmdtab usbctlmsg[] =
105*74a4d8c2SCharles.Forsyth {
106*74a4d8c2SCharles.Forsyth CMclass, "class", 0,
107*74a4d8c2SCharles.Forsyth CMdata, "data", 3,
108*74a4d8c2SCharles.Forsyth CMdebug, "debug", 3,
109*74a4d8c2SCharles.Forsyth CMep, "ep", 6,
110*74a4d8c2SCharles.Forsyth CMmaxpkt, "maxpkt", 3,
111*74a4d8c2SCharles.Forsyth CMadjust, "adjust", 3,
112*74a4d8c2SCharles.Forsyth CMspeed, "speed", 2,
113*74a4d8c2SCharles.Forsyth CMunstall, "unstall", 2,
114*74a4d8c2SCharles.Forsyth };
115*74a4d8c2SCharles.Forsyth
116*74a4d8c2SCharles.Forsyth static struct
117*74a4d8c2SCharles.Forsyth {
118*74a4d8c2SCharles.Forsyth char* type;
119*74a4d8c2SCharles.Forsyth int (*reset)(Usbhost*);
120*74a4d8c2SCharles.Forsyth } usbtypes[MaxUsb+1];
121*74a4d8c2SCharles.Forsyth
122*74a4d8c2SCharles.Forsyth void
addusbtype(char * t,int (* r)(Usbhost *))123*74a4d8c2SCharles.Forsyth addusbtype(char* t, int (*r)(Usbhost*))
124*74a4d8c2SCharles.Forsyth {
125*74a4d8c2SCharles.Forsyth static int ntype;
126*74a4d8c2SCharles.Forsyth
127*74a4d8c2SCharles.Forsyth if(ntype == MaxUsb)
128*74a4d8c2SCharles.Forsyth panic("too many USB host interface types");
129*74a4d8c2SCharles.Forsyth usbtypes[ntype].type = t;
130*74a4d8c2SCharles.Forsyth usbtypes[ntype].reset = r;
131*74a4d8c2SCharles.Forsyth ntype++;
132*74a4d8c2SCharles.Forsyth }
133*74a4d8c2SCharles.Forsyth
134*74a4d8c2SCharles.Forsyth static Udev*
usbdeviceofslot(Usbhost * uh,int s)135*74a4d8c2SCharles.Forsyth usbdeviceofslot(Usbhost *uh, int s)
136*74a4d8c2SCharles.Forsyth {
137*74a4d8c2SCharles.Forsyth if(s < 0 || s > nelem(uh->dev))
138*74a4d8c2SCharles.Forsyth return nil;
139*74a4d8c2SCharles.Forsyth return uh->dev[s];
140*74a4d8c2SCharles.Forsyth }
141*74a4d8c2SCharles.Forsyth
142*74a4d8c2SCharles.Forsyth static Udev*
usbdevice(Chan * c)143*74a4d8c2SCharles.Forsyth usbdevice(Chan *c)
144*74a4d8c2SCharles.Forsyth {
145*74a4d8c2SCharles.Forsyth int bus;
146*74a4d8c2SCharles.Forsyth Udev *d;
147*74a4d8c2SCharles.Forsyth Usbhost *uh;
148*74a4d8c2SCharles.Forsyth
149*74a4d8c2SCharles.Forsyth bus = CTLR(c->qid);
150*74a4d8c2SCharles.Forsyth if(bus > nelem(usbhost) || (uh = usbhost[bus]) == nil) {
151*74a4d8c2SCharles.Forsyth error(Egreg);
152*74a4d8c2SCharles.Forsyth return nil; /* for compiler */
153*74a4d8c2SCharles.Forsyth }
154*74a4d8c2SCharles.Forsyth d = usbdeviceofslot(uh, SLOT(c->qid));
155*74a4d8c2SCharles.Forsyth if(d == nil || d->id != c->qid.vers || d->state == Disabled)
156*74a4d8c2SCharles.Forsyth error(Ehungup);
157*74a4d8c2SCharles.Forsyth return d;
158*74a4d8c2SCharles.Forsyth }
159*74a4d8c2SCharles.Forsyth
160*74a4d8c2SCharles.Forsyth static Endpt *
devendpt(Udev * d,int id,int add)161*74a4d8c2SCharles.Forsyth devendpt(Udev *d, int id, int add)
162*74a4d8c2SCharles.Forsyth {
163*74a4d8c2SCharles.Forsyth Usbhost *uh;
164*74a4d8c2SCharles.Forsyth Endpt *e, **p;
165*74a4d8c2SCharles.Forsyth
166*74a4d8c2SCharles.Forsyth p = &d->ep[id&0xF];
167*74a4d8c2SCharles.Forsyth lock(d);
168*74a4d8c2SCharles.Forsyth e = *p;
169*74a4d8c2SCharles.Forsyth if(e != nil){
170*74a4d8c2SCharles.Forsyth incref(e);
171*74a4d8c2SCharles.Forsyth XPRINT("incref(0x%p) in devendpt, new value %ld\n", e, e->ref);
172*74a4d8c2SCharles.Forsyth unlock(d);
173*74a4d8c2SCharles.Forsyth return e;
174*74a4d8c2SCharles.Forsyth }
175*74a4d8c2SCharles.Forsyth unlock(d);
176*74a4d8c2SCharles.Forsyth if(!add)
177*74a4d8c2SCharles.Forsyth return nil;
178*74a4d8c2SCharles.Forsyth
179*74a4d8c2SCharles.Forsyth e = mallocz(sizeof(*e), 1);
180*74a4d8c2SCharles.Forsyth e->ref = 1;
181*74a4d8c2SCharles.Forsyth e->x = id&0xF;
182*74a4d8c2SCharles.Forsyth e->id = id;
183*74a4d8c2SCharles.Forsyth e->sched = -1;
184*74a4d8c2SCharles.Forsyth e->maxpkt = 8;
185*74a4d8c2SCharles.Forsyth e->nbuf = 1;
186*74a4d8c2SCharles.Forsyth e->dev = d;
187*74a4d8c2SCharles.Forsyth e->active = 0;
188*74a4d8c2SCharles.Forsyth
189*74a4d8c2SCharles.Forsyth uh = d->uh;
190*74a4d8c2SCharles.Forsyth uh->epalloc(uh, e);
191*74a4d8c2SCharles.Forsyth
192*74a4d8c2SCharles.Forsyth lock(d);
193*74a4d8c2SCharles.Forsyth if(*p != nil){
194*74a4d8c2SCharles.Forsyth incref(*p);
195*74a4d8c2SCharles.Forsyth XPRINT("incref(0x%p) in devendpt, new value %ld\n", *p, (*p)->ref);
196*74a4d8c2SCharles.Forsyth unlock(d);
197*74a4d8c2SCharles.Forsyth uh->epfree(uh, e);
198*74a4d8c2SCharles.Forsyth free(e);
199*74a4d8c2SCharles.Forsyth return *p;
200*74a4d8c2SCharles.Forsyth }
201*74a4d8c2SCharles.Forsyth *p = e;
202*74a4d8c2SCharles.Forsyth unlock(d);
203*74a4d8c2SCharles.Forsyth e->rq = qopen(8*1024, 0, nil, e);
204*74a4d8c2SCharles.Forsyth e->wq = qopen(8*1024, 0, nil, e);
205*74a4d8c2SCharles.Forsyth return e;
206*74a4d8c2SCharles.Forsyth }
207*74a4d8c2SCharles.Forsyth
208*74a4d8c2SCharles.Forsyth static void
freept(Endpt * e)209*74a4d8c2SCharles.Forsyth freept(Endpt *e)
210*74a4d8c2SCharles.Forsyth {
211*74a4d8c2SCharles.Forsyth Usbhost *uh;
212*74a4d8c2SCharles.Forsyth
213*74a4d8c2SCharles.Forsyth if(e != nil && decref(e) == 0){
214*74a4d8c2SCharles.Forsyth XPRINT("freept(%d,%d)\n", e->dev->x, e->x);
215*74a4d8c2SCharles.Forsyth uh = e->dev->uh;
216*74a4d8c2SCharles.Forsyth uh->epclose(uh, e);
217*74a4d8c2SCharles.Forsyth e->dev->ep[e->x] = nil;
218*74a4d8c2SCharles.Forsyth uh->epfree(uh, e);
219*74a4d8c2SCharles.Forsyth free(e);
220*74a4d8c2SCharles.Forsyth }
221*74a4d8c2SCharles.Forsyth }
222*74a4d8c2SCharles.Forsyth
223*74a4d8c2SCharles.Forsyth static Udev*
usbnewdevice(Usbhost * uh)224*74a4d8c2SCharles.Forsyth usbnewdevice(Usbhost *uh)
225*74a4d8c2SCharles.Forsyth {
226*74a4d8c2SCharles.Forsyth int i;
227*74a4d8c2SCharles.Forsyth Udev *d;
228*74a4d8c2SCharles.Forsyth Endpt *e;
229*74a4d8c2SCharles.Forsyth
230*74a4d8c2SCharles.Forsyth d = nil;
231*74a4d8c2SCharles.Forsyth qlock(uh);
232*74a4d8c2SCharles.Forsyth if(waserror()){
233*74a4d8c2SCharles.Forsyth qunlock(uh);
234*74a4d8c2SCharles.Forsyth nexterror();
235*74a4d8c2SCharles.Forsyth }
236*74a4d8c2SCharles.Forsyth for(i=0; i<nelem(uh->dev); i++)
237*74a4d8c2SCharles.Forsyth if(uh->dev[i] == nil){
238*74a4d8c2SCharles.Forsyth uh->idgen++;
239*74a4d8c2SCharles.Forsyth d = mallocz(sizeof(*d), 1);
240*74a4d8c2SCharles.Forsyth d->uh = uh;
241*74a4d8c2SCharles.Forsyth d->ref = 1;
242*74a4d8c2SCharles.Forsyth d->x = i;
243*74a4d8c2SCharles.Forsyth d->id = (uh->idgen << 8) | i;
244*74a4d8c2SCharles.Forsyth d->state = Enabled;
245*74a4d8c2SCharles.Forsyth XPRINT("calling devendpt in usbnewdevice\n");
246*74a4d8c2SCharles.Forsyth e = devendpt(d, 0, 1); /* always provide control endpoint 0 */
247*74a4d8c2SCharles.Forsyth e->mode = ORDWR;
248*74a4d8c2SCharles.Forsyth e->iso = 0;
249*74a4d8c2SCharles.Forsyth e->sched = -1;
250*74a4d8c2SCharles.Forsyth uh->dev[i] = d;
251*74a4d8c2SCharles.Forsyth break;
252*74a4d8c2SCharles.Forsyth }
253*74a4d8c2SCharles.Forsyth poperror();
254*74a4d8c2SCharles.Forsyth qunlock(uh);
255*74a4d8c2SCharles.Forsyth return d;
256*74a4d8c2SCharles.Forsyth }
257*74a4d8c2SCharles.Forsyth
258*74a4d8c2SCharles.Forsyth static void
freedev(Udev * d,int ept)259*74a4d8c2SCharles.Forsyth freedev(Udev *d, int ept)
260*74a4d8c2SCharles.Forsyth {
261*74a4d8c2SCharles.Forsyth int i;
262*74a4d8c2SCharles.Forsyth Endpt *e;
263*74a4d8c2SCharles.Forsyth Usbhost *uh;
264*74a4d8c2SCharles.Forsyth
265*74a4d8c2SCharles.Forsyth uh = d->uh;
266*74a4d8c2SCharles.Forsyth if(decref(d) == 0){
267*74a4d8c2SCharles.Forsyth XPRINT("freedev 0x%p, 0\n", d);
268*74a4d8c2SCharles.Forsyth for(i=0; i<nelem(d->ep); i++)
269*74a4d8c2SCharles.Forsyth freept(d->ep[i]);
270*74a4d8c2SCharles.Forsyth if(d->x >= 0)
271*74a4d8c2SCharles.Forsyth uh->dev[d->x] = nil;
272*74a4d8c2SCharles.Forsyth free(d);
273*74a4d8c2SCharles.Forsyth } else {
274*74a4d8c2SCharles.Forsyth if(ept >= 0 && ept < nelem(d->ep)){
275*74a4d8c2SCharles.Forsyth e = d->ep[ept];
276*74a4d8c2SCharles.Forsyth XPRINT("freedev, freept 0x%p\n", e);
277*74a4d8c2SCharles.Forsyth if(e != nil)
278*74a4d8c2SCharles.Forsyth uh->epclose(uh, e);
279*74a4d8c2SCharles.Forsyth }
280*74a4d8c2SCharles.Forsyth }
281*74a4d8c2SCharles.Forsyth }
282*74a4d8c2SCharles.Forsyth
283*74a4d8c2SCharles.Forsyth static int
usbgen(Chan * c,char *,Dirtab *,int,int s,Dir * dp)284*74a4d8c2SCharles.Forsyth usbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
285*74a4d8c2SCharles.Forsyth {
286*74a4d8c2SCharles.Forsyth Qid q;
287*74a4d8c2SCharles.Forsyth Udev *d;
288*74a4d8c2SCharles.Forsyth Endpt *e;
289*74a4d8c2SCharles.Forsyth Dirtab *tab;
290*74a4d8c2SCharles.Forsyth Usbhost *uh;
291*74a4d8c2SCharles.Forsyth int t, bus, slot, perm;
292*74a4d8c2SCharles.Forsyth
293*74a4d8c2SCharles.Forsyth /*
294*74a4d8c2SCharles.Forsyth * Top level directory contains the controller names.
295*74a4d8c2SCharles.Forsyth */
296*74a4d8c2SCharles.Forsyth if(c->qid.path == Qtopdir){
297*74a4d8c2SCharles.Forsyth if(s == DEVDOTDOT){
298*74a4d8c2SCharles.Forsyth mkqid(&q, Qtopdir, 0, QTDIR);
299*74a4d8c2SCharles.Forsyth devdir(c, q, "#U", 0, eve, 0555, dp);
300*74a4d8c2SCharles.Forsyth return 1;
301*74a4d8c2SCharles.Forsyth }
302*74a4d8c2SCharles.Forsyth if(s >= nelem(usbhost) || usbhost[s] == nil)
303*74a4d8c2SCharles.Forsyth return -1;
304*74a4d8c2SCharles.Forsyth mkqid(&q, PATH(Q2nd, 0, s), 0, QTDIR);
305*74a4d8c2SCharles.Forsyth snprint(up->genbuf, sizeof up->genbuf, "usb%d", s);
306*74a4d8c2SCharles.Forsyth devdir(c, q, up->genbuf, 0, eve, 0555, dp);
307*74a4d8c2SCharles.Forsyth return 1;
308*74a4d8c2SCharles.Forsyth }
309*74a4d8c2SCharles.Forsyth bus = CTLR(c->qid);
310*74a4d8c2SCharles.Forsyth if(bus >= nelem(usbhost) || (uh = usbhost[bus]) == nil)
311*74a4d8c2SCharles.Forsyth return -1;
312*74a4d8c2SCharles.Forsyth
313*74a4d8c2SCharles.Forsyth /*
314*74a4d8c2SCharles.Forsyth * Second level contains "new", "port", and a numbered
315*74a4d8c2SCharles.Forsyth * directory for each enumerated device on the bus.
316*74a4d8c2SCharles.Forsyth */
317*74a4d8c2SCharles.Forsyth t = TYPE(c->qid);
318*74a4d8c2SCharles.Forsyth if(t < Q3rd){
319*74a4d8c2SCharles.Forsyth if(s == DEVDOTDOT){
320*74a4d8c2SCharles.Forsyth mkqid(&q, Qtopdir, 0, QTDIR);
321*74a4d8c2SCharles.Forsyth devdir(c, q, "#U", 0, eve, 0555, dp);
322*74a4d8c2SCharles.Forsyth return 1;
323*74a4d8c2SCharles.Forsyth }
324*74a4d8c2SCharles.Forsyth if(s < nelem(usbdir2)){
325*74a4d8c2SCharles.Forsyth d = uh->dev[0];
326*74a4d8c2SCharles.Forsyth if(d == nil)
327*74a4d8c2SCharles.Forsyth return -1;
328*74a4d8c2SCharles.Forsyth tab = &usbdir2[s];
329*74a4d8c2SCharles.Forsyth mkqid(&q, PATH(tab->qid.path, 0, bus), d->id, QTFILE);
330*74a4d8c2SCharles.Forsyth devdir(c, q, tab->name, tab->length, eve, tab->perm, dp);
331*74a4d8c2SCharles.Forsyth return 1;
332*74a4d8c2SCharles.Forsyth }
333*74a4d8c2SCharles.Forsyth s -= nelem(usbdir2);
334*74a4d8c2SCharles.Forsyth if(s >= 0 && s < nelem(uh->dev)) {
335*74a4d8c2SCharles.Forsyth d = uh->dev[s];
336*74a4d8c2SCharles.Forsyth if(d == nil)
337*74a4d8c2SCharles.Forsyth return 0;
338*74a4d8c2SCharles.Forsyth sprint(up->genbuf, "%d", s);
339*74a4d8c2SCharles.Forsyth mkqid(&q, PATH(Q3rd, s, bus), d->id, QTDIR);
340*74a4d8c2SCharles.Forsyth devdir(c, q, up->genbuf, 0, eve, 0555, dp);
341*74a4d8c2SCharles.Forsyth return 1;
342*74a4d8c2SCharles.Forsyth }
343*74a4d8c2SCharles.Forsyth return -1;
344*74a4d8c2SCharles.Forsyth }
345*74a4d8c2SCharles.Forsyth
346*74a4d8c2SCharles.Forsyth /*
347*74a4d8c2SCharles.Forsyth * Third level.
348*74a4d8c2SCharles.Forsyth */
349*74a4d8c2SCharles.Forsyth slot = SLOT(c->qid);
350*74a4d8c2SCharles.Forsyth if(s == DEVDOTDOT) {
351*74a4d8c2SCharles.Forsyth mkqid(&q, PATH(Q2nd, 0, bus), c->qid.vers, QTDIR);
352*74a4d8c2SCharles.Forsyth snprint(up->genbuf, sizeof up->genbuf, "usb%d", bus);
353*74a4d8c2SCharles.Forsyth devdir(c, q, up->genbuf, 0, eve, 0555, dp);
354*74a4d8c2SCharles.Forsyth return 1;
355*74a4d8c2SCharles.Forsyth }
356*74a4d8c2SCharles.Forsyth if(s < nelem(usbdir3)) {
357*74a4d8c2SCharles.Forsyth tab = &usbdir3[s];
358*74a4d8c2SCharles.Forsyth mkqid(&q, PATH(tab->qid.path, slot, bus), c->qid.vers, QTFILE);
359*74a4d8c2SCharles.Forsyth devdir(c, q, tab->name, tab->length, eve, tab->perm, dp);
360*74a4d8c2SCharles.Forsyth return 1;
361*74a4d8c2SCharles.Forsyth }
362*74a4d8c2SCharles.Forsyth s -= nelem(usbdir3);
363*74a4d8c2SCharles.Forsyth
364*74a4d8c2SCharles.Forsyth /* active endpoints */
365*74a4d8c2SCharles.Forsyth d = usbdeviceofslot(uh, slot);
366*74a4d8c2SCharles.Forsyth if(d == nil || s >= nelem(d->ep))
367*74a4d8c2SCharles.Forsyth return -1;
368*74a4d8c2SCharles.Forsyth if(s == 0 || (e = d->ep[s]) == nil) /* ep0data is called "setup" */
369*74a4d8c2SCharles.Forsyth return 0;
370*74a4d8c2SCharles.Forsyth sprint(up->genbuf, "ep%ddata", s);
371*74a4d8c2SCharles.Forsyth mkqid(&q, PATH(Qep0+s, slot, bus), c->qid.vers, QTFILE);
372*74a4d8c2SCharles.Forsyth switch(e->mode) {
373*74a4d8c2SCharles.Forsyth case OREAD:
374*74a4d8c2SCharles.Forsyth perm = 0444;
375*74a4d8c2SCharles.Forsyth break;
376*74a4d8c2SCharles.Forsyth case OWRITE:
377*74a4d8c2SCharles.Forsyth perm = 0222;
378*74a4d8c2SCharles.Forsyth break;
379*74a4d8c2SCharles.Forsyth default:
380*74a4d8c2SCharles.Forsyth perm = 0666;
381*74a4d8c2SCharles.Forsyth break;
382*74a4d8c2SCharles.Forsyth }
383*74a4d8c2SCharles.Forsyth devdir(c, q, up->genbuf, e->buffered, eve, perm, dp);
384*74a4d8c2SCharles.Forsyth return 1;
385*74a4d8c2SCharles.Forsyth }
386*74a4d8c2SCharles.Forsyth
387*74a4d8c2SCharles.Forsyth static Usbhost*
usbprobe(int cardno,int ctlrno)388*74a4d8c2SCharles.Forsyth usbprobe(int cardno, int ctlrno)
389*74a4d8c2SCharles.Forsyth {
390*74a4d8c2SCharles.Forsyth Usbhost *uh;
391*74a4d8c2SCharles.Forsyth char buf[128], *ebuf, name[64], *p, *type;
392*74a4d8c2SCharles.Forsyth
393*74a4d8c2SCharles.Forsyth uh = malloc(sizeof(Usbhost));
394*74a4d8c2SCharles.Forsyth memset(uh, 0, sizeof(Usbhost));
395*74a4d8c2SCharles.Forsyth uh->tbdf = BUSUNKNOWN;
396*74a4d8c2SCharles.Forsyth
397*74a4d8c2SCharles.Forsyth if(cardno < 0){
398*74a4d8c2SCharles.Forsyth if(isaconfig("usb", ctlrno, uh) == 0){
399*74a4d8c2SCharles.Forsyth free(uh);
400*74a4d8c2SCharles.Forsyth return nil;
401*74a4d8c2SCharles.Forsyth }
402*74a4d8c2SCharles.Forsyth for(cardno = 0; usbtypes[cardno].type; cardno++){
403*74a4d8c2SCharles.Forsyth type = uh->type;
404*74a4d8c2SCharles.Forsyth if(type==nil || *type==0)
405*74a4d8c2SCharles.Forsyth type = "uhci";
406*74a4d8c2SCharles.Forsyth if(cistrcmp(usbtypes[cardno].type, type))
407*74a4d8c2SCharles.Forsyth continue;
408*74a4d8c2SCharles.Forsyth break;
409*74a4d8c2SCharles.Forsyth }
410*74a4d8c2SCharles.Forsyth }
411*74a4d8c2SCharles.Forsyth
412*74a4d8c2SCharles.Forsyth if(cardno >= MaxUsb || usbtypes[cardno].type == nil){
413*74a4d8c2SCharles.Forsyth free(uh);
414*74a4d8c2SCharles.Forsyth return nil;
415*74a4d8c2SCharles.Forsyth }
416*74a4d8c2SCharles.Forsyth if(usbtypes[cardno].reset(uh) < 0){
417*74a4d8c2SCharles.Forsyth free(uh);
418*74a4d8c2SCharles.Forsyth return nil;
419*74a4d8c2SCharles.Forsyth }
420*74a4d8c2SCharles.Forsyth
421*74a4d8c2SCharles.Forsyth /*
422*74a4d8c2SCharles.Forsyth * IRQ2 doesn't really exist, it's used to gang the interrupt
423*74a4d8c2SCharles.Forsyth * controllers together. A device set to IRQ2 will appear on
424*74a4d8c2SCharles.Forsyth * the second interrupt controller as IRQ9.
425*74a4d8c2SCharles.Forsyth */
426*74a4d8c2SCharles.Forsyth if(uh->irq == 2)
427*74a4d8c2SCharles.Forsyth uh->irq = 9;
428*74a4d8c2SCharles.Forsyth snprint(name, sizeof(name), "usb%d", ctlrno);
429*74a4d8c2SCharles.Forsyth intrenable(uh->irq, uh->interrupt, uh, uh->tbdf, name);
430*74a4d8c2SCharles.Forsyth
431*74a4d8c2SCharles.Forsyth ebuf = buf + sizeof buf;
432*74a4d8c2SCharles.Forsyth p = seprint(buf, ebuf, "#U/usb%d: %s: port 0x%luX irq %d", ctlrno, usbtypes[cardno].type, uh->port, uh->irq);
433*74a4d8c2SCharles.Forsyth if(uh->mem)
434*74a4d8c2SCharles.Forsyth p = seprint(p, ebuf, " addr 0x%luX", PADDR(uh->mem));
435*74a4d8c2SCharles.Forsyth if(uh->size)
436*74a4d8c2SCharles.Forsyth seprint(p, ebuf, " size 0x%luX", uh->size);
437*74a4d8c2SCharles.Forsyth print("%s\n", buf);
438*74a4d8c2SCharles.Forsyth
439*74a4d8c2SCharles.Forsyth return uh;
440*74a4d8c2SCharles.Forsyth }
441*74a4d8c2SCharles.Forsyth
442*74a4d8c2SCharles.Forsyth static void
usbreset(void)443*74a4d8c2SCharles.Forsyth usbreset(void)
444*74a4d8c2SCharles.Forsyth {
445*74a4d8c2SCharles.Forsyth int cardno, ctlrno;
446*74a4d8c2SCharles.Forsyth Usbhost *uh;
447*74a4d8c2SCharles.Forsyth
448*74a4d8c2SCharles.Forsyth for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){
449*74a4d8c2SCharles.Forsyth if((uh = usbprobe(-1, ctlrno)) == nil)
450*74a4d8c2SCharles.Forsyth continue;
451*74a4d8c2SCharles.Forsyth usbhost[ctlrno] = uh;
452*74a4d8c2SCharles.Forsyth }
453*74a4d8c2SCharles.Forsyth
454*74a4d8c2SCharles.Forsyth if(getconf("*nousbprobe"))
455*74a4d8c2SCharles.Forsyth return;
456*74a4d8c2SCharles.Forsyth
457*74a4d8c2SCharles.Forsyth cardno = ctlrno = 0;
458*74a4d8c2SCharles.Forsyth while(usbtypes[cardno].type != nil && ctlrno < MaxUsb){
459*74a4d8c2SCharles.Forsyth if(usbhost[ctlrno] != nil){
460*74a4d8c2SCharles.Forsyth ctlrno++;
461*74a4d8c2SCharles.Forsyth continue;
462*74a4d8c2SCharles.Forsyth }
463*74a4d8c2SCharles.Forsyth if((uh = usbprobe(cardno, ctlrno)) == nil){
464*74a4d8c2SCharles.Forsyth cardno++;
465*74a4d8c2SCharles.Forsyth continue;
466*74a4d8c2SCharles.Forsyth }
467*74a4d8c2SCharles.Forsyth usbhost[ctlrno] = uh;
468*74a4d8c2SCharles.Forsyth ctlrno++;
469*74a4d8c2SCharles.Forsyth }
470*74a4d8c2SCharles.Forsyth }
471*74a4d8c2SCharles.Forsyth
472*74a4d8c2SCharles.Forsyth void
usbinit(void)473*74a4d8c2SCharles.Forsyth usbinit(void)
474*74a4d8c2SCharles.Forsyth {
475*74a4d8c2SCharles.Forsyth Udev *d;
476*74a4d8c2SCharles.Forsyth int ctlrno;
477*74a4d8c2SCharles.Forsyth Usbhost *uh;
478*74a4d8c2SCharles.Forsyth
479*74a4d8c2SCharles.Forsyth for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){
480*74a4d8c2SCharles.Forsyth uh = usbhost[ctlrno];
481*74a4d8c2SCharles.Forsyth if(uh == nil)
482*74a4d8c2SCharles.Forsyth continue;
483*74a4d8c2SCharles.Forsyth if(uh->init != 0)
484*74a4d8c2SCharles.Forsyth uh->init(uh);
485*74a4d8c2SCharles.Forsyth
486*74a4d8c2SCharles.Forsyth /* reserve device for configuration */
487*74a4d8c2SCharles.Forsyth d = usbnewdevice(uh);
488*74a4d8c2SCharles.Forsyth incref(d);
489*74a4d8c2SCharles.Forsyth d->state = Attached;
490*74a4d8c2SCharles.Forsyth }
491*74a4d8c2SCharles.Forsyth }
492*74a4d8c2SCharles.Forsyth
493*74a4d8c2SCharles.Forsyth Chan *
usbattach(char * spec)494*74a4d8c2SCharles.Forsyth usbattach(char *spec)
495*74a4d8c2SCharles.Forsyth {
496*74a4d8c2SCharles.Forsyth return devattach('U', spec);
497*74a4d8c2SCharles.Forsyth }
498*74a4d8c2SCharles.Forsyth
499*74a4d8c2SCharles.Forsyth static Walkqid*
usbwalk(Chan * c,Chan * nc,char ** name,int nname)500*74a4d8c2SCharles.Forsyth usbwalk(Chan *c, Chan *nc, char **name, int nname)
501*74a4d8c2SCharles.Forsyth {
502*74a4d8c2SCharles.Forsyth return devwalk(c, nc, name, nname, nil, 0, usbgen);
503*74a4d8c2SCharles.Forsyth }
504*74a4d8c2SCharles.Forsyth
505*74a4d8c2SCharles.Forsyth static int
usbstat(Chan * c,uchar * db,int n)506*74a4d8c2SCharles.Forsyth usbstat(Chan *c, uchar *db, int n)
507*74a4d8c2SCharles.Forsyth {
508*74a4d8c2SCharles.Forsyth return devstat(c, db, n, nil, 0, usbgen);
509*74a4d8c2SCharles.Forsyth }
510*74a4d8c2SCharles.Forsyth
511*74a4d8c2SCharles.Forsyth Chan*
usbopen(Chan * c,int omode)512*74a4d8c2SCharles.Forsyth usbopen(Chan *c, int omode)
513*74a4d8c2SCharles.Forsyth {
514*74a4d8c2SCharles.Forsyth Udev *d;
515*74a4d8c2SCharles.Forsyth Endpt *e;
516*74a4d8c2SCharles.Forsyth int f, s, type;
517*74a4d8c2SCharles.Forsyth Usbhost *uh;
518*74a4d8c2SCharles.Forsyth
519*74a4d8c2SCharles.Forsyth if(c->qid.type == QTDIR)
520*74a4d8c2SCharles.Forsyth return devopen(c, omode, nil, 0, usbgen);
521*74a4d8c2SCharles.Forsyth
522*74a4d8c2SCharles.Forsyth f = 0;
523*74a4d8c2SCharles.Forsyth type = TYPE(c->qid);
524*74a4d8c2SCharles.Forsyth if(type == Qnew){
525*74a4d8c2SCharles.Forsyth d = usbdevice(c);
526*74a4d8c2SCharles.Forsyth d = usbnewdevice(d->uh);
527*74a4d8c2SCharles.Forsyth XPRINT("usbopen, new dev 0x%p\n", d);
528*74a4d8c2SCharles.Forsyth if(d == nil) {
529*74a4d8c2SCharles.Forsyth XPRINT("usbopen failed (usbnewdevice)\n");
530*74a4d8c2SCharles.Forsyth error(Enodev);
531*74a4d8c2SCharles.Forsyth }
532*74a4d8c2SCharles.Forsyth type = Qctl;
533*74a4d8c2SCharles.Forsyth mkqid(&c->qid, PATH(type, d->x, CTLR(c->qid)), d->id, QTFILE);
534*74a4d8c2SCharles.Forsyth f = 1;
535*74a4d8c2SCharles.Forsyth }
536*74a4d8c2SCharles.Forsyth
537*74a4d8c2SCharles.Forsyth if(type < Q3rd){
538*74a4d8c2SCharles.Forsyth XPRINT("usbopen, devopen < Q3rd\n");
539*74a4d8c2SCharles.Forsyth return devopen(c, omode, nil, 0, usbgen);
540*74a4d8c2SCharles.Forsyth }
541*74a4d8c2SCharles.Forsyth
542*74a4d8c2SCharles.Forsyth d = usbdevice(c);
543*74a4d8c2SCharles.Forsyth uh = d->uh;
544*74a4d8c2SCharles.Forsyth qlock(uh);
545*74a4d8c2SCharles.Forsyth if(waserror()){
546*74a4d8c2SCharles.Forsyth qunlock(uh);
547*74a4d8c2SCharles.Forsyth nexterror();
548*74a4d8c2SCharles.Forsyth }
549*74a4d8c2SCharles.Forsyth
550*74a4d8c2SCharles.Forsyth switch(type){
551*74a4d8c2SCharles.Forsyth case Qctl:
552*74a4d8c2SCharles.Forsyth if(0&&d->busy)
553*74a4d8c2SCharles.Forsyth error(Einuse);
554*74a4d8c2SCharles.Forsyth d->busy = 1;
555*74a4d8c2SCharles.Forsyth if(!f)
556*74a4d8c2SCharles.Forsyth incref(d);
557*74a4d8c2SCharles.Forsyth XPRINT("usbopen, Qctl 0x%p\n", d);
558*74a4d8c2SCharles.Forsyth break;
559*74a4d8c2SCharles.Forsyth
560*74a4d8c2SCharles.Forsyth default:
561*74a4d8c2SCharles.Forsyth s = type - Qep0;
562*74a4d8c2SCharles.Forsyth XPRINT("usbopen, default 0x%p, %d\n", d, s);
563*74a4d8c2SCharles.Forsyth if(s >= 0 && s < nelem(d->ep)){
564*74a4d8c2SCharles.Forsyth if((e = d->ep[s]) == nil) {
565*74a4d8c2SCharles.Forsyth XPRINT("usbopen failed (endpoint)\n");
566*74a4d8c2SCharles.Forsyth error(Enodev);
567*74a4d8c2SCharles.Forsyth }
568*74a4d8c2SCharles.Forsyth XPRINT("usbopen: dev 0x%p, ept 0x%p\n", d, e);
569*74a4d8c2SCharles.Forsyth uh->epopen(uh, e);
570*74a4d8c2SCharles.Forsyth e->foffset = 0;
571*74a4d8c2SCharles.Forsyth e->toffset = 0;
572*74a4d8c2SCharles.Forsyth e->poffset = 0;
573*74a4d8c2SCharles.Forsyth e->buffered = 0;
574*74a4d8c2SCharles.Forsyth }
575*74a4d8c2SCharles.Forsyth incref(d);
576*74a4d8c2SCharles.Forsyth break;
577*74a4d8c2SCharles.Forsyth }
578*74a4d8c2SCharles.Forsyth poperror();
579*74a4d8c2SCharles.Forsyth qunlock(uh);
580*74a4d8c2SCharles.Forsyth c->mode = openmode(omode);
581*74a4d8c2SCharles.Forsyth c->flag |= COPEN;
582*74a4d8c2SCharles.Forsyth c->offset = 0;
583*74a4d8c2SCharles.Forsyth return c;
584*74a4d8c2SCharles.Forsyth }
585*74a4d8c2SCharles.Forsyth
586*74a4d8c2SCharles.Forsyth void
usbclose(Chan * c)587*74a4d8c2SCharles.Forsyth usbclose(Chan *c)
588*74a4d8c2SCharles.Forsyth {
589*74a4d8c2SCharles.Forsyth Udev *d;
590*74a4d8c2SCharles.Forsyth int ept, type;
591*74a4d8c2SCharles.Forsyth Usbhost *uh;
592*74a4d8c2SCharles.Forsyth
593*74a4d8c2SCharles.Forsyth type = TYPE(c->qid);
594*74a4d8c2SCharles.Forsyth if(c->qid.type == QTDIR || type < Q3rd)
595*74a4d8c2SCharles.Forsyth return;
596*74a4d8c2SCharles.Forsyth d = usbdevice(c);
597*74a4d8c2SCharles.Forsyth uh = d->uh;
598*74a4d8c2SCharles.Forsyth qlock(uh);
599*74a4d8c2SCharles.Forsyth if(waserror()){
600*74a4d8c2SCharles.Forsyth qunlock(uh);
601*74a4d8c2SCharles.Forsyth nexterror();
602*74a4d8c2SCharles.Forsyth }
603*74a4d8c2SCharles.Forsyth if(type == Qctl)
604*74a4d8c2SCharles.Forsyth d->busy = 0;
605*74a4d8c2SCharles.Forsyth XPRINT("usbclose: dev 0x%p\n", d);
606*74a4d8c2SCharles.Forsyth if(c->flag & COPEN){
607*74a4d8c2SCharles.Forsyth ept = (type != Qctl) ? type - Qep0 : -1;
608*74a4d8c2SCharles.Forsyth XPRINT("usbclose: freedev 0x%p\n", d);
609*74a4d8c2SCharles.Forsyth freedev(d, ept);
610*74a4d8c2SCharles.Forsyth }
611*74a4d8c2SCharles.Forsyth poperror();
612*74a4d8c2SCharles.Forsyth qunlock(uh);
613*74a4d8c2SCharles.Forsyth }
614*74a4d8c2SCharles.Forsyth
615*74a4d8c2SCharles.Forsyth static char *
epstatus(char * s,char * se,Endpt * e,int i)616*74a4d8c2SCharles.Forsyth epstatus(char *s, char *se, Endpt *e, int i)
617*74a4d8c2SCharles.Forsyth {
618*74a4d8c2SCharles.Forsyth char *p;
619*74a4d8c2SCharles.Forsyth
620*74a4d8c2SCharles.Forsyth p = seprint(s, se, "%2d %#6.6lux %10lud bytes %10lud blocks\n", i, e->csp, e->nbytes, e->nblocks);
621*74a4d8c2SCharles.Forsyth if(e->iso){
622*74a4d8c2SCharles.Forsyth p = seprint(p, se, "bufsize %6d buffered %6d", e->maxpkt, e->buffered);
623*74a4d8c2SCharles.Forsyth if(e->toffset)
624*74a4d8c2SCharles.Forsyth p = seprint(p, se, " offset %10lud time %19lld\n", e->toffset, e->time);
625*74a4d8c2SCharles.Forsyth p = seprint(p, se, "\n");
626*74a4d8c2SCharles.Forsyth }
627*74a4d8c2SCharles.Forsyth return p;
628*74a4d8c2SCharles.Forsyth }
629*74a4d8c2SCharles.Forsyth
630*74a4d8c2SCharles.Forsyth long
usbread(Chan * c,void * a,long n,vlong offset)631*74a4d8c2SCharles.Forsyth usbread(Chan *c, void *a, long n, vlong offset)
632*74a4d8c2SCharles.Forsyth {
633*74a4d8c2SCharles.Forsyth int t, i;
634*74a4d8c2SCharles.Forsyth Udev *d;
635*74a4d8c2SCharles.Forsyth Endpt *e;
636*74a4d8c2SCharles.Forsyth Usbhost *uh;
637*74a4d8c2SCharles.Forsyth char *s, *se, *p;
638*74a4d8c2SCharles.Forsyth
639*74a4d8c2SCharles.Forsyth if(c->qid.type == QTDIR)
640*74a4d8c2SCharles.Forsyth return devdirread(c, a, n, nil, 0, usbgen);
641*74a4d8c2SCharles.Forsyth
642*74a4d8c2SCharles.Forsyth d = usbdevice(c);
643*74a4d8c2SCharles.Forsyth uh = d->uh;
644*74a4d8c2SCharles.Forsyth t = TYPE(c->qid);
645*74a4d8c2SCharles.Forsyth
646*74a4d8c2SCharles.Forsyth if(t >= Qep0) {
647*74a4d8c2SCharles.Forsyth t -= Qep0;
648*74a4d8c2SCharles.Forsyth if(t >= nelem(d->ep))
649*74a4d8c2SCharles.Forsyth error(Eio);
650*74a4d8c2SCharles.Forsyth e = d->ep[t];
651*74a4d8c2SCharles.Forsyth if(e == nil || e->mode == OWRITE)
652*74a4d8c2SCharles.Forsyth error(Egreg);
653*74a4d8c2SCharles.Forsyth if(t == 0) {
654*74a4d8c2SCharles.Forsyth if(e->iso)
655*74a4d8c2SCharles.Forsyth error(Egreg);
656*74a4d8c2SCharles.Forsyth e->data01 = 1;
657*74a4d8c2SCharles.Forsyth n = uh->read(uh, e, a, n, 0LL);
658*74a4d8c2SCharles.Forsyth if(e->setin){
659*74a4d8c2SCharles.Forsyth e->setin = 0;
660*74a4d8c2SCharles.Forsyth e->data01 = 1;
661*74a4d8c2SCharles.Forsyth uh->write(uh, e, "", 0, 0LL, TokOUT);
662*74a4d8c2SCharles.Forsyth }
663*74a4d8c2SCharles.Forsyth return n;
664*74a4d8c2SCharles.Forsyth }
665*74a4d8c2SCharles.Forsyth return uh->read(uh, e, a, n, offset);
666*74a4d8c2SCharles.Forsyth }
667*74a4d8c2SCharles.Forsyth
668*74a4d8c2SCharles.Forsyth s = smalloc(READSTR);
669*74a4d8c2SCharles.Forsyth se = s+READSTR;
670*74a4d8c2SCharles.Forsyth if(waserror()){
671*74a4d8c2SCharles.Forsyth free(s);
672*74a4d8c2SCharles.Forsyth nexterror();
673*74a4d8c2SCharles.Forsyth }
674*74a4d8c2SCharles.Forsyth switch(t){
675*74a4d8c2SCharles.Forsyth case Qport:
676*74a4d8c2SCharles.Forsyth uh->portinfo(uh, s, se);
677*74a4d8c2SCharles.Forsyth break;
678*74a4d8c2SCharles.Forsyth
679*74a4d8c2SCharles.Forsyth case Qctl:
680*74a4d8c2SCharles.Forsyth seprint(s, se, "%11d %11d\n", d->x, d->id);
681*74a4d8c2SCharles.Forsyth break;
682*74a4d8c2SCharles.Forsyth
683*74a4d8c2SCharles.Forsyth case Qstatus:
684*74a4d8c2SCharles.Forsyth if (d->did || d->vid)
685*74a4d8c2SCharles.Forsyth p = seprint(s, se, "%s %#6.6lux %#4.4ux %#4.4ux\n", devstates[d->state], d->csp, d->vid, d->did);
686*74a4d8c2SCharles.Forsyth else
687*74a4d8c2SCharles.Forsyth p = seprint(s, se, "%s %#6.6lux\n", devstates[d->state], d->csp);
688*74a4d8c2SCharles.Forsyth for(i=0; i<nelem(d->ep); i++) {
689*74a4d8c2SCharles.Forsyth e = d->ep[i];
690*74a4d8c2SCharles.Forsyth if(e == nil)
691*74a4d8c2SCharles.Forsyth continue;
692*74a4d8c2SCharles.Forsyth /* TO DO: freeze e */
693*74a4d8c2SCharles.Forsyth p = epstatus(p, se, e, i);
694*74a4d8c2SCharles.Forsyth }
695*74a4d8c2SCharles.Forsyth }
696*74a4d8c2SCharles.Forsyth n = readstr(offset, a, n, s);
697*74a4d8c2SCharles.Forsyth poperror();
698*74a4d8c2SCharles.Forsyth free(s);
699*74a4d8c2SCharles.Forsyth return n;
700*74a4d8c2SCharles.Forsyth }
701*74a4d8c2SCharles.Forsyth
702*74a4d8c2SCharles.Forsyth long
usbwrite(Chan * c,void * a,long n,vlong offset)703*74a4d8c2SCharles.Forsyth usbwrite(Chan *c, void *a, long n, vlong offset)
704*74a4d8c2SCharles.Forsyth {
705*74a4d8c2SCharles.Forsyth Udev *d;
706*74a4d8c2SCharles.Forsyth Endpt *e;
707*74a4d8c2SCharles.Forsyth Cmdtab *ct;
708*74a4d8c2SCharles.Forsyth Cmdbuf *cb;
709*74a4d8c2SCharles.Forsyth Usbhost *uh;
710*74a4d8c2SCharles.Forsyth int id, nw, t, i;
711*74a4d8c2SCharles.Forsyth char cmd[50];
712*74a4d8c2SCharles.Forsyth
713*74a4d8c2SCharles.Forsyth if(c->qid.type == QTDIR)
714*74a4d8c2SCharles.Forsyth error(Egreg);
715*74a4d8c2SCharles.Forsyth d = usbdevice(c);
716*74a4d8c2SCharles.Forsyth uh = d->uh;
717*74a4d8c2SCharles.Forsyth t = TYPE(c->qid);
718*74a4d8c2SCharles.Forsyth switch(t){
719*74a4d8c2SCharles.Forsyth case Qport:
720*74a4d8c2SCharles.Forsyth cb = parsecmd(a, n);
721*74a4d8c2SCharles.Forsyth if(waserror()){
722*74a4d8c2SCharles.Forsyth free(cb);
723*74a4d8c2SCharles.Forsyth nexterror();
724*74a4d8c2SCharles.Forsyth }
725*74a4d8c2SCharles.Forsyth
726*74a4d8c2SCharles.Forsyth ct = lookupcmd(cb, usbportmsg, nelem(usbportmsg));
727*74a4d8c2SCharles.Forsyth id = strtol(cb->f[1], nil, 0);
728*74a4d8c2SCharles.Forsyth switch(ct->index){
729*74a4d8c2SCharles.Forsyth case PMdisable:
730*74a4d8c2SCharles.Forsyth uh->portenable(uh, id, 0);
731*74a4d8c2SCharles.Forsyth break;
732*74a4d8c2SCharles.Forsyth case PMenable:
733*74a4d8c2SCharles.Forsyth uh->portenable(uh, id, 1);
734*74a4d8c2SCharles.Forsyth break;
735*74a4d8c2SCharles.Forsyth case PMreset:
736*74a4d8c2SCharles.Forsyth uh->portreset(uh, id);
737*74a4d8c2SCharles.Forsyth break;
738*74a4d8c2SCharles.Forsyth }
739*74a4d8c2SCharles.Forsyth
740*74a4d8c2SCharles.Forsyth poperror();
741*74a4d8c2SCharles.Forsyth free(cb);
742*74a4d8c2SCharles.Forsyth return n;
743*74a4d8c2SCharles.Forsyth case Qctl:
744*74a4d8c2SCharles.Forsyth cb = parsecmd(a, n);
745*74a4d8c2SCharles.Forsyth if(waserror()){
746*74a4d8c2SCharles.Forsyth free(cb);
747*74a4d8c2SCharles.Forsyth nexterror();
748*74a4d8c2SCharles.Forsyth }
749*74a4d8c2SCharles.Forsyth
750*74a4d8c2SCharles.Forsyth ct = lookupcmd(cb, usbctlmsg, nelem(usbctlmsg));
751*74a4d8c2SCharles.Forsyth switch(ct->index){
752*74a4d8c2SCharles.Forsyth case CMspeed:
753*74a4d8c2SCharles.Forsyth d->ls = strtoul(cb->f[1], nil, 0) == 0;
754*74a4d8c2SCharles.Forsyth break;
755*74a4d8c2SCharles.Forsyth case CMclass:
756*74a4d8c2SCharles.Forsyth if (cb->nf != 4 && cb->nf != 6)
757*74a4d8c2SCharles.Forsyth cmderror(cb, Ebadusbmsg);
758*74a4d8c2SCharles.Forsyth /* class #ifc ept csp ( == class subclass proto) [vendor product] */
759*74a4d8c2SCharles.Forsyth d->npt = strtoul(cb->f[1], nil, 0); /* # of interfaces */
760*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[2], nil, 0); /* endpoint */
761*74a4d8c2SCharles.Forsyth if (i < 0 || i >= nelem(d->ep)
762*74a4d8c2SCharles.Forsyth || d->npt > nelem(d->ep) || i >= d->npt)
763*74a4d8c2SCharles.Forsyth cmderror(cb, Ebadusbmsg);
764*74a4d8c2SCharles.Forsyth if (cb->nf == 6) {
765*74a4d8c2SCharles.Forsyth d->vid = strtoul(cb->f[4], nil, 0);
766*74a4d8c2SCharles.Forsyth d->did = strtoul(cb->f[5], nil, 0);
767*74a4d8c2SCharles.Forsyth }
768*74a4d8c2SCharles.Forsyth if (i == 0)
769*74a4d8c2SCharles.Forsyth d->csp = strtoul(cb->f[3], nil, 0);
770*74a4d8c2SCharles.Forsyth if(d->ep[i] == nil){
771*74a4d8c2SCharles.Forsyth XPRINT("calling devendpt in usbwrite (CMclass)\n");
772*74a4d8c2SCharles.Forsyth d->ep[i] = devendpt(d, i, 1);
773*74a4d8c2SCharles.Forsyth }
774*74a4d8c2SCharles.Forsyth d->ep[i]->csp = strtoul(cb->f[3], nil, 0);
775*74a4d8c2SCharles.Forsyth break;
776*74a4d8c2SCharles.Forsyth case CMdata:
777*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[1], nil, 0);
778*74a4d8c2SCharles.Forsyth if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
779*74a4d8c2SCharles.Forsyth error(Ebadusbmsg);
780*74a4d8c2SCharles.Forsyth e = d->ep[i];
781*74a4d8c2SCharles.Forsyth e->data01 = strtoul(cb->f[2], nil, 0) != 0;
782*74a4d8c2SCharles.Forsyth break;
783*74a4d8c2SCharles.Forsyth case CMmaxpkt:
784*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[1], nil, 0);
785*74a4d8c2SCharles.Forsyth if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
786*74a4d8c2SCharles.Forsyth error(Ebadusbmsg);
787*74a4d8c2SCharles.Forsyth e = d->ep[i];
788*74a4d8c2SCharles.Forsyth e->maxpkt = strtoul(cb->f[2], nil, 0);
789*74a4d8c2SCharles.Forsyth if(e->maxpkt > 1500)
790*74a4d8c2SCharles.Forsyth e->maxpkt = 1500;
791*74a4d8c2SCharles.Forsyth break;
792*74a4d8c2SCharles.Forsyth case CMadjust:
793*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[1], nil, 0);
794*74a4d8c2SCharles.Forsyth if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
795*74a4d8c2SCharles.Forsyth error(Ebadusbmsg);
796*74a4d8c2SCharles.Forsyth e = d->ep[i];
797*74a4d8c2SCharles.Forsyth if (e->iso == 0)
798*74a4d8c2SCharles.Forsyth error(Eperm);
799*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[2], nil, 0);
800*74a4d8c2SCharles.Forsyth /* speed may not result in change of maxpkt */
801*74a4d8c2SCharles.Forsyth if (i < (e->maxpkt-1)/e->samplesz * 1000/e->pollms
802*74a4d8c2SCharles.Forsyth || i > e->maxpkt/e->samplesz * 1000/e->pollms){
803*74a4d8c2SCharles.Forsyth snprint(cmd, sizeof(cmd), "%d < %d < %d?",
804*74a4d8c2SCharles.Forsyth (e->maxpkt-1)/e->samplesz * 1000/e->pollms,
805*74a4d8c2SCharles.Forsyth i,
806*74a4d8c2SCharles.Forsyth e->maxpkt/e->samplesz * 1000/e->pollms);
807*74a4d8c2SCharles.Forsyth error(cmd);
808*74a4d8c2SCharles.Forsyth }
809*74a4d8c2SCharles.Forsyth e->hz = i;
810*74a4d8c2SCharles.Forsyth break;
811*74a4d8c2SCharles.Forsyth case CMdebug:
812*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[1], nil, 0);
813*74a4d8c2SCharles.Forsyth if(i < -1 || i >= nelem(d->ep) || d->ep[i] == nil)
814*74a4d8c2SCharles.Forsyth error(Ebadusbmsg);
815*74a4d8c2SCharles.Forsyth if (i == -1)
816*74a4d8c2SCharles.Forsyth debug = 0;
817*74a4d8c2SCharles.Forsyth else {
818*74a4d8c2SCharles.Forsyth debug = 1;
819*74a4d8c2SCharles.Forsyth e = d->ep[i];
820*74a4d8c2SCharles.Forsyth e->debug = strtoul(cb->f[2], nil, 0);
821*74a4d8c2SCharles.Forsyth }
822*74a4d8c2SCharles.Forsyth break;
823*74a4d8c2SCharles.Forsyth case CMunstall:
824*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[1], nil, 0);
825*74a4d8c2SCharles.Forsyth if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
826*74a4d8c2SCharles.Forsyth error(Ebadusbmsg);
827*74a4d8c2SCharles.Forsyth e = d->ep[i];
828*74a4d8c2SCharles.Forsyth e->err = nil;
829*74a4d8c2SCharles.Forsyth break;
830*74a4d8c2SCharles.Forsyth case CMep:
831*74a4d8c2SCharles.Forsyth /* ep n `bulk' mode maxpkt nbuf OR
832*74a4d8c2SCharles.Forsyth * ep n period mode samplesize Hz
833*74a4d8c2SCharles.Forsyth */
834*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[1], nil, 0);
835*74a4d8c2SCharles.Forsyth if(i < 0 || i >= nelem(d->ep)) {
836*74a4d8c2SCharles.Forsyth XPRINT("field 1: 0 <= %d < %d\n", i, nelem(d->ep));
837*74a4d8c2SCharles.Forsyth error(Ebadarg);
838*74a4d8c2SCharles.Forsyth }
839*74a4d8c2SCharles.Forsyth if((e = d->ep[i]) == nil){
840*74a4d8c2SCharles.Forsyth XPRINT("calling devendpt in usbwrite (CMep)\n");
841*74a4d8c2SCharles.Forsyth e = devendpt(d, i, 1);
842*74a4d8c2SCharles.Forsyth }
843*74a4d8c2SCharles.Forsyth qlock(uh);
844*74a4d8c2SCharles.Forsyth if(waserror()){
845*74a4d8c2SCharles.Forsyth freept(e);
846*74a4d8c2SCharles.Forsyth qunlock(uh);
847*74a4d8c2SCharles.Forsyth nexterror();
848*74a4d8c2SCharles.Forsyth }
849*74a4d8c2SCharles.Forsyth if(e->active)
850*74a4d8c2SCharles.Forsyth error(Eperm);
851*74a4d8c2SCharles.Forsyth if(strcmp(cb->f[2], "bulk") == 0){
852*74a4d8c2SCharles.Forsyth /* ep n `bulk' mode maxpkt nbuf */
853*74a4d8c2SCharles.Forsyth e->iso = 0;
854*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[4], nil, 0);
855*74a4d8c2SCharles.Forsyth if(i < 8 || i > 1023)
856*74a4d8c2SCharles.Forsyth i = 8;
857*74a4d8c2SCharles.Forsyth e->maxpkt = i;
858*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[5], nil, 0);
859*74a4d8c2SCharles.Forsyth if(i >= 1 && i <= 32)
860*74a4d8c2SCharles.Forsyth e->nbuf = i;
861*74a4d8c2SCharles.Forsyth } else {
862*74a4d8c2SCharles.Forsyth /* ep n period mode samplesize Hz */
863*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[2], nil, 0);
864*74a4d8c2SCharles.Forsyth if(i > 0 && i <= 1000){
865*74a4d8c2SCharles.Forsyth e->pollms = i;
866*74a4d8c2SCharles.Forsyth }else {
867*74a4d8c2SCharles.Forsyth XPRINT("field 4: 0 <= %d <= 1000\n", i);
868*74a4d8c2SCharles.Forsyth error(Ebadarg);
869*74a4d8c2SCharles.Forsyth }
870*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[4], nil, 0);
871*74a4d8c2SCharles.Forsyth if(i >= 1 && i <= 8){
872*74a4d8c2SCharles.Forsyth e->samplesz = i;
873*74a4d8c2SCharles.Forsyth }else {
874*74a4d8c2SCharles.Forsyth XPRINT("field 4: 0 < %d <= 8\n", i);
875*74a4d8c2SCharles.Forsyth error(Ebadarg);
876*74a4d8c2SCharles.Forsyth }
877*74a4d8c2SCharles.Forsyth i = strtoul(cb->f[5], nil, 0);
878*74a4d8c2SCharles.Forsyth if(i >= 1 && i*e->samplesz <= 12*1000*1000){
879*74a4d8c2SCharles.Forsyth /* Hz */
880*74a4d8c2SCharles.Forsyth e->hz = i;
881*74a4d8c2SCharles.Forsyth e->remain = 0;
882*74a4d8c2SCharles.Forsyth }else {
883*74a4d8c2SCharles.Forsyth XPRINT("field 5: 1 < %d <= 100000 Hz\n", i);
884*74a4d8c2SCharles.Forsyth error(Ebadarg);
885*74a4d8c2SCharles.Forsyth }
886*74a4d8c2SCharles.Forsyth e->maxpkt = (e->hz * e->pollms + 999)/1000 * e->samplesz;
887*74a4d8c2SCharles.Forsyth e->iso = 1;
888*74a4d8c2SCharles.Forsyth }
889*74a4d8c2SCharles.Forsyth e->mode = strcmp(cb->f[3],"r") == 0? OREAD :
890*74a4d8c2SCharles.Forsyth strcmp(cb->f[3],"w") == 0? OWRITE : ORDWR;
891*74a4d8c2SCharles.Forsyth uh->epmode(uh, e);
892*74a4d8c2SCharles.Forsyth poperror();
893*74a4d8c2SCharles.Forsyth qunlock(uh);
894*74a4d8c2SCharles.Forsyth }
895*74a4d8c2SCharles.Forsyth
896*74a4d8c2SCharles.Forsyth poperror();
897*74a4d8c2SCharles.Forsyth free(cb);
898*74a4d8c2SCharles.Forsyth return n;
899*74a4d8c2SCharles.Forsyth
900*74a4d8c2SCharles.Forsyth case Qep0: /* SETUP endpoint 0 */
901*74a4d8c2SCharles.Forsyth /* should canqlock etc */
902*74a4d8c2SCharles.Forsyth e = d->ep[0];
903*74a4d8c2SCharles.Forsyth if(e == nil || e->iso)
904*74a4d8c2SCharles.Forsyth error(Egreg);
905*74a4d8c2SCharles.Forsyth if(n < 8)
906*74a4d8c2SCharles.Forsyth error(Eio);
907*74a4d8c2SCharles.Forsyth nw = *(uchar*)a & RD2H;
908*74a4d8c2SCharles.Forsyth e->data01 = 0;
909*74a4d8c2SCharles.Forsyth n = uh->write(uh, e, a, n, 0LL, TokSETUP);
910*74a4d8c2SCharles.Forsyth if(nw == 0) { /* host to device: use IN[DATA1] to ack */
911*74a4d8c2SCharles.Forsyth e->data01 = 1;
912*74a4d8c2SCharles.Forsyth nw = uh->read(uh, e, cmd, 0LL, 8);
913*74a4d8c2SCharles.Forsyth if(nw != 0)
914*74a4d8c2SCharles.Forsyth error(Eio); /* could provide more status */
915*74a4d8c2SCharles.Forsyth }else
916*74a4d8c2SCharles.Forsyth e->setin = 1; /* two-phase */
917*74a4d8c2SCharles.Forsyth break;
918*74a4d8c2SCharles.Forsyth
919*74a4d8c2SCharles.Forsyth default: /* sends DATA[01] */
920*74a4d8c2SCharles.Forsyth t -= Qep0;
921*74a4d8c2SCharles.Forsyth if(t < 0 || t >= nelem(d->ep))
922*74a4d8c2SCharles.Forsyth error(Egreg);
923*74a4d8c2SCharles.Forsyth e = d->ep[t];
924*74a4d8c2SCharles.Forsyth if(e == nil || e->mode == OREAD)
925*74a4d8c2SCharles.Forsyth error(Egreg);
926*74a4d8c2SCharles.Forsyth n = uh->write(uh, e, a, n, offset, TokOUT);
927*74a4d8c2SCharles.Forsyth break;
928*74a4d8c2SCharles.Forsyth }
929*74a4d8c2SCharles.Forsyth return n;
930*74a4d8c2SCharles.Forsyth }
931*74a4d8c2SCharles.Forsyth
932*74a4d8c2SCharles.Forsyth Dev usbdevtab = {
933*74a4d8c2SCharles.Forsyth 'U',
934*74a4d8c2SCharles.Forsyth "usb",
935*74a4d8c2SCharles.Forsyth
936*74a4d8c2SCharles.Forsyth usbreset,
937*74a4d8c2SCharles.Forsyth usbinit,
938*74a4d8c2SCharles.Forsyth devshutdown,
939*74a4d8c2SCharles.Forsyth usbattach,
940*74a4d8c2SCharles.Forsyth usbwalk,
941*74a4d8c2SCharles.Forsyth usbstat,
942*74a4d8c2SCharles.Forsyth usbopen,
943*74a4d8c2SCharles.Forsyth devcreate,
944*74a4d8c2SCharles.Forsyth usbclose,
945*74a4d8c2SCharles.Forsyth usbread,
946*74a4d8c2SCharles.Forsyth devbread,
947*74a4d8c2SCharles.Forsyth usbwrite,
948*74a4d8c2SCharles.Forsyth devbwrite,
949*74a4d8c2SCharles.Forsyth devremove,
950*74a4d8c2SCharles.Forsyth devwstat,
951*74a4d8c2SCharles.Forsyth };
952