Charles.Forsyth20060303644188019 years agoHistory
951 lines · 17.9 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"../port/error.h" #include	"usb.h" static int debug = 0; #define Chatty	1#define DPRINT if(Chatty)print#define XPRINT if(debug)iprint Usbhost*	usbhost[MaxUsb]; static char *devstates[] = {	[Disabled]		"Disabled",	[Attached]	"Attached",	[Enabled]		"Enabled",	[Assigned]	"Assigned",	[Configured]	"Configured",}; static	char	Ebadusbmsg[] = "invalid parameters to USB ctl message"; enum{	Qtopdir = 0,	Q2nd,	Qnew,	Qport,	Q3rd,	Qctl,	Qstatus,	Qep0,	/* other endpoint files */}; /* * Qid path is: *	8 bits of file type (qids above) *	8 bits of slot number; default address 0 used for per-controller files *	4 bits of controller number */enum {	TYPEBITS	= 8,	SLOTBITS	= 8,	CTLRBITS	= 4, 	SLOTSHIFT	= TYPEBITS,	CTLRSHIFT	= SLOTSHIFT+SLOTBITS, 	TYPEMASK	= (1<<TYPEBITS)-1,	SLOTMASK	= (1<<SLOTBITS)-1,	CTLRMASK	= (1<<CTLRBITS)-1,}; #define	TYPE(q)		(((ulong)(q).path)&TYPEMASK)#define	SLOT(q)		((((ulong)(q).path)>>SLOTSHIFT)&SLOTMASK)#define	CTLR(q)		((((ulong)(q).path)>>CTLRSHIFT)&CTLRMASK)#define	PATH(t, s, c)	((t)|((s)<<SLOTSHIFT)|((c)<<CTLRSHIFT)) static Dirtab usbdir2[] = {	"new",	{Qnew},			0,	0666,	"port",	{Qport},			0,	0666,}; static Dirtab usbdir3[]={	"ctl",		{Qctl},			0,	0666,	"status",	{Qstatus},			0,	0444,	"setup",	{Qep0},			0,	0666,	/* epNdata names are generated on demand */}; enum{	PMdisable,	PMenable,	PMreset,}; enum{	CMclass,	CMdata,	CMdebug,	CMep,	CMmaxpkt,	CMadjust,	CMspeed,	CMunstall,}; static Cmdtab usbportmsg[] ={	PMdisable,	"disable",	2,	PMenable,		"enable",	2,	PMreset,		"reset",	2,}; static Cmdtab usbctlmsg[] ={	CMclass,		"class",	0,	CMdata,		"data",	3,	CMdebug,		"debug",	3,	CMep,		"ep",		6,	CMmaxpkt,	"maxpkt",	3,	CMadjust,		"adjust",	3,	CMspeed,		"speed",	2,	CMunstall,	"unstall",	2,}; static struct{	char*	type;	int	(*reset)(Usbhost*);} usbtypes[MaxUsb+1]; voidaddusbtype(char* t, int (*r)(Usbhost*)){	static int ntype; 	if(ntype == MaxUsb)		panic("too many USB host interface types");	usbtypes[ntype].type = t;	usbtypes[ntype].reset = r;	ntype++;} static Udev*usbdeviceofslot(Usbhost *uh, int s){	if(s < 0 || s > nelem(uh->dev))		return nil;	return uh->dev[s];} static Udev*usbdevice(Chan *c){	int bus;	Udev *d;	Usbhost *uh; 	bus = CTLR(c->qid);	if(bus > nelem(usbhost) || (uh = usbhost[bus]) == nil) {		error(Egreg);		return nil;		/* for compiler */	}	d = usbdeviceofslot(uh, SLOT(c->qid));	if(d == nil || d->id != c->qid.vers || d->state == Disabled)		error(Ehungup);	return d;} static Endpt *devendpt(Udev *d, int id, int add){	Usbhost *uh;	Endpt *e, **p; 	p = &d->ep[id&0xF];	lock(d);	e = *p;	if(e != nil){		incref(e);		XPRINT("incref(0x%p) in devendpt, new value %ld\n", e, e->ref);		unlock(d);		return e;	}	unlock(d);	if(!add)		return nil; 	e = mallocz(sizeof(*e), 1);	e->ref = 1;	e->x = id&0xF;	e->id = id;	e->sched = -1;	e->maxpkt = 8;	e->nbuf = 1;	e->dev = d;	e->active = 0; 	uh = d->uh;	uh->epalloc(uh, e); 	lock(d);	if(*p != nil){		incref(*p);		XPRINT("incref(0x%p) in devendpt, new value %ld\n", *p, (*p)->ref);		unlock(d);		uh->epfree(uh, e);		free(e);		return *p;	}	*p = e;	unlock(d);	e->rq = qopen(8*1024, 0, nil, e);	e->wq = qopen(8*1024, 0, nil, e);	return e;} static voidfreept(Endpt *e){	Usbhost *uh; 	if(e != nil && decref(e) == 0){		XPRINT("freept(%d,%d)\n", e->dev->x, e->x);		uh = e->dev->uh;		uh->epclose(uh, e);		e->dev->ep[e->x] = nil;		uh->epfree(uh, e);		free(e);	}} static Udev*usbnewdevice(Usbhost *uh){	int i;	Udev *d;	Endpt *e; 	d = nil;	qlock(uh);	if(waserror()){		qunlock(uh);		nexterror();	}	for(i=0; i<nelem(uh->dev); i++)		if(uh->dev[i] == nil){			uh->idgen++;			d = mallocz(sizeof(*d), 1);			d->uh = uh;			d->ref = 1;			d->x = i;			d->id = (uh->idgen << 8) | i;			d->state = Enabled;			XPRINT("calling devendpt in usbnewdevice\n");			e = devendpt(d, 0, 1);	/* always provide control endpoint 0 */			e->mode = ORDWR;			e->iso = 0;			e->sched = -1;			uh->dev[i] = d;			break;		}	poperror();	qunlock(uh);	return d;} static voidfreedev(Udev *d, int ept){	int i;	Endpt *e;	Usbhost *uh; 	uh = d->uh;	if(decref(d) == 0){		XPRINT("freedev 0x%p, 0\n", d);		for(i=0; i<nelem(d->ep); i++)			freept(d->ep[i]);		if(d->x >= 0)			uh->dev[d->x] = nil;		free(d);	} else {		if(ept >= 0 && ept < nelem(d->ep)){			e = d->ep[ept];			XPRINT("freedev, freept 0x%p\n", e);			if(e != nil)				uh->epclose(uh, e);		}	}	} static intusbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp){	Qid q;	Udev *d;	Endpt *e;	Dirtab *tab;	Usbhost *uh;	int t, bus, slot, perm; 	/*	 * Top level directory contains the controller names.	 */	if(c->qid.path == Qtopdir){		if(s == DEVDOTDOT){			mkqid(&q, Qtopdir, 0, QTDIR);			devdir(c, q, "#U", 0, eve, 0555, dp);			return 1;		}		if(s >= nelem(usbhost) || usbhost[s] == nil)			return -1;		mkqid(&q, PATH(Q2nd, 0, s), 0, QTDIR);		snprint(up->genbuf, sizeof up->genbuf, "usb%d", s);		devdir(c, q, up->genbuf, 0, eve, 0555, dp);		return 1;	}	bus = CTLR(c->qid);	if(bus >= nelem(usbhost) || (uh = usbhost[bus]) == nil)			return -1; 	/*	 * Second level contains "new", "port", and a numbered	 * directory for each enumerated device on the bus.	 */	t = TYPE(c->qid);	if(t < Q3rd){		if(s == DEVDOTDOT){			mkqid(&q, Qtopdir, 0, QTDIR);			devdir(c, q, "#U", 0, eve, 0555, dp);			return 1;		}		if(s < nelem(usbdir2)){			d = uh->dev[0];			if(d == nil)				return -1;			tab = &usbdir2[s];			mkqid(&q, PATH(tab->qid.path, 0, bus), d->id, QTFILE);			devdir(c, q, tab->name, tab->length, eve, tab->perm, dp);			return 1;		}		s -= nelem(usbdir2);		if(s >= 0 && s < nelem(uh->dev)) {			d = uh->dev[s];			if(d == nil)				return 0;			sprint(up->genbuf, "%d", s);			mkqid(&q, PATH(Q3rd, s, bus), d->id, QTDIR);			devdir(c, q, up->genbuf, 0, eve, 0555, dp);			return 1;		}		return -1;	} 	/*	 * Third level.	 */	slot = SLOT(c->qid);	if(s == DEVDOTDOT) {		mkqid(&q, PATH(Q2nd, 0, bus), c->qid.vers, QTDIR);		snprint(up->genbuf, sizeof up->genbuf, "usb%d", bus);		devdir(c, q, up->genbuf, 0, eve, 0555, dp);		return 1;	}	if(s < nelem(usbdir3)) {		tab = &usbdir3[s];		mkqid(&q, PATH(tab->qid.path, slot, bus), c->qid.vers, QTFILE);		devdir(c, q, tab->name, tab->length, eve, tab->perm, dp);		return 1;	}	s -= nelem(usbdir3); 	/* active endpoints */	d = usbdeviceofslot(uh, slot);	if(d == nil || s >= nelem(d->ep))		return -1;	if(s == 0 || (e = d->ep[s]) == nil)	/* ep0data is called "setup" */		return 0;	sprint(up->genbuf, "ep%ddata", s);	mkqid(&q, PATH(Qep0+s, slot, bus), c->qid.vers, QTFILE);	switch(e->mode) {	case OREAD:		perm = 0444;		break;	case OWRITE:		perm = 0222;		break;	default:		perm = 0666;		break;	}	devdir(c, q, up->genbuf, e->buffered, eve, perm, dp);	return 1;} static Usbhost*usbprobe(int cardno, int ctlrno){	Usbhost *uh;	char buf[128], *ebuf, name[64], *p, *type; 	uh = malloc(sizeof(Usbhost));	memset(uh, 0, sizeof(Usbhost));	uh->tbdf = BUSUNKNOWN; 	if(cardno < 0){		if(isaconfig("usb", ctlrno, uh) == 0){			free(uh);			return nil;		}		for(cardno = 0; usbtypes[cardno].type; cardno++){			type = uh->type;			if(type==nil || *type==0)				type = "uhci";			if(cistrcmp(usbtypes[cardno].type, type))				continue;			break;		}	} 	if(cardno >= MaxUsb || usbtypes[cardno].type == nil){		free(uh);		return nil;	}	if(usbtypes[cardno].reset(uh) < 0){		free(uh);		return nil;	} 	/*	 * IRQ2 doesn't really exist, it's used to gang the interrupt	 * controllers together. A device set to IRQ2 will appear on	 * the second interrupt controller as IRQ9.	 */	if(uh->irq == 2)		uh->irq = 9;	snprint(name, sizeof(name), "usb%d", ctlrno);	intrenable(uh->irq, uh->interrupt, uh, uh->tbdf, name); 	ebuf = buf + sizeof buf;	p = seprint(buf, ebuf, "#U/usb%d: %s: port 0x%luX irq %d", ctlrno, usbtypes[cardno].type, uh->port, uh->irq);	if(uh->mem)		p = seprint(p, ebuf, " addr 0x%luX", PADDR(uh->mem));	if(uh->size)		seprint(p, ebuf, " size 0x%luX", uh->size);	print("%s\n", buf); 	return uh;} static voidusbreset(void){	int cardno, ctlrno;	Usbhost *uh; 	for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){		if((uh = usbprobe(-1, ctlrno)) == nil)			continue;		usbhost[ctlrno] = uh;	} 	if(getconf("*nousbprobe"))		return; 	cardno = ctlrno = 0;	while(usbtypes[cardno].type != nil && ctlrno < MaxUsb){		if(usbhost[ctlrno] != nil){			ctlrno++;			continue;		}		if((uh = usbprobe(cardno, ctlrno)) == nil){			cardno++;			continue;		}		usbhost[ctlrno] = uh;		ctlrno++;	}} voidusbinit(void){	Udev *d;	int ctlrno;	Usbhost *uh; 	for(ctlrno = 0; ctlrno < MaxUsb; ctlrno++){		uh = usbhost[ctlrno];		if(uh == nil)			continue;		if(uh->init != 0)			uh->init(uh); 		/* reserve device for configuration */		d = usbnewdevice(uh);		incref(d);		d->state = Attached;	}} Chan *usbattach(char *spec){	return devattach('U', spec);} static Walkqid*usbwalk(Chan *c, Chan *nc, char **name, int nname)

Lines 1–500 of 951.