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