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