⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usbuhci.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
static voidcanceltds(Ctlr *ctlr, QH *q, Endpt *e){	TD *t;	if(q != nil){		ilock(ctlr);		for(t = q->first; t != nil; t = t->next)			if(t->ep == e)				t->flags |= CancelTD;		iunlock(ctlr);		XPRINT("cancel:\n");		dumpqh(q);	}}static voideptcancel(Ctlr *ctlr, Endpt *e){	Endptx *x;	if(e == nil)		return;	x = e->private;	canceltds(ctlr, x->epq, e);	canceltds(ctlr, ctlr->ctlq, e);	canceltds(ctlr, ctlr->bulkq, e);}static voideptactivate(Ctlr *ctlr, Endpt *e){	ilock(&ctlr->activends);	if(e->active == 0){		XPRINT("activate 0x%p\n", e);		e->active = 1;		e->activef = ctlr->activends.f;		ctlr->activends.f = e;	}	iunlock(&ctlr->activends);}static voideptdeactivate(Ctlr *ctlr, Endpt *e){	Endpt **l;	/* could be O(1) but not worth it yet */	ilock(&ctlr->activends);	if(e->active){		e->active = 0;		XPRINT("deactivate 0x%p\n", e);		for(l = &ctlr->activends.f; *l != e; l = &(*l)->activef)			if(*l == nil){				iunlock(&ctlr->activends);				panic("usb eptdeactivate");			}		*l = e->activef;	}	iunlock(&ctlr->activends);}static voidqueueqh(Ctlr *ctlr, QH *qh){	QH *q;	// See if it's already queued	for (q = ctlr->recvq->next; q; q = q->hlink)		if (q == qh)			return;	if ((qh->hlink = ctlr->recvq->next) == nil)		qh->head = Terminate;	else		qh->head = PCIWADDR(ctlr->recvq->next) | IsQH;	ctlr->recvq->next = qh;	ctlr->recvq->entries = PCIWADDR(qh) | IsQH;}static QH*qxmit(Ctlr *ctlr, Endpt *e, Block *b, int pid){	TD *t;	int n, vf;	QH *qh;	Endptx *x;	x = e->private;	if(b != nil){		n = BLEN(b);		t = alloctde(ctlr, e, pid, n);		t->bp = b;		t->buffer = PCIWADDR(b->rp);	}else		t = alloctde(ctlr, e, pid, 0);	ilock(ctlr);	e->ntd++;	iunlock(ctlr);	if(e->debug) pprint("QTD: %8.8lux n=%ld\n", t, b?BLEN(b): 0);	vf = 0;	if(e->x == 0){		qh = ctlr->ctlq;		vf = 0;	}else if((qh = x->epq) == nil || e->mode != OWRITE){		qh = ctlr->bulkq;		vf = Vf;	}	queuetd(ctlr, qh, t, vf, "qxmit");	return qh;}static QH*qrcv(Ctlr *ctlr, Endpt *e){	TD *t;	Block *b;	QH *qh;	int vf;	Endptx *x;	x = e->private;	t = alloctde(ctlr, e, TokIN, e->maxpkt);	b = allocb(e->maxpkt);	t->bp = b;	t->buffer = PCIWADDR(b->wp);	vf = 0;	if(e->x == 0){		qh = ctlr->ctlq;	}else if((qh = x->epq) == nil || e->mode != OREAD){		qh = ctlr->bulkq;		vf = Vf;	}	queuetd(ctlr, qh, t, vf, "qrcv");	return qh;}static intusbsched(Ctlr *ctlr, int pollms, ulong load){	int i, d, q;	ulong best, worst;	best = 1000000;	q = -1;	for (d = 0; d < pollms; d++){		worst = 0;		for (i = d; i < NFRAME; i++){			if (ctlr->frameld[i] + load > worst)				worst = ctlr->frameld[i] + load;		}		if (worst < best){			best = worst;			q = d;		}	}	return q;}static intschedendpt(Ctlr *ctlr, Endpt *e){	TD *td;	Endptx *x;	uchar *bp;	int i, id, ix, size, frnum;	if(!e->iso || e->sched >= 0)		return 0;	if (e->active){		return -1;	}	e->off = 0;	e->sched = usbsched(ctlr, e->pollms, e->maxpkt);	if(e->sched < 0)		return -1;	x = e->private;	if (x->tdalloc || x->bpalloc)		panic("usb: tdalloc/bpalloc");	x->tdalloc = mallocz(0x10 + NFRAME*sizeof(TD), 1);	x->bpalloc = mallocz(0x10 + e->maxpkt*NFRAME/e->pollms, 1);	x->td0 = (TD*)(((ulong)x->tdalloc + 0xf) & ~0xf);	x->bp0 = (uchar *)(((ulong)x->bpalloc + 0xf) & ~0xf);	frnum = (IN(Frnum) + 1) & 0x3ff;	frnum = (frnum & ~(e->pollms - 1)) + e->sched;	x->xtd = &x->td0[(frnum+8)&0x3ff];	/* Next td to finish */	x->etd = nil;	e->remain = 0;	e->nbytes = 0;	td = x->td0;	for(i = e->sched; i < NFRAME; i += e->pollms){		bp = x->bp0 + e->maxpkt*i/e->pollms;		td->buffer = PCIWADDR(bp);		td->ep = e;		td->next = &td[1];		ctlr->frameld[i] += e->maxpkt;		td++;	}	td[-1].next = x->td0;	for(i = e->sched; i < NFRAME; i += e->pollms){		ix = (frnum+i) & 0x3ff;		td = &x->td0[ix];		id = (e->x<<7)|(e->dev->x&0x7F);		if (e->mode == OREAD)			/* enable receive on this entry */			td->dev = ((e->maxpkt-1)<<21) | ((id&0x7FF)<<8) | TokIN;		else{			size = (e->hz + e->remain)*e->pollms/1000;			e->remain = (e->hz + e->remain)*e->pollms%1000;			size *= e->samplesz;			td->dev = ((size-1)<<21) | ((id&0x7FF)<<8) | TokOUT;		}		td->status = ErrLimit1 | Active | IsoSelect | IOC;		td->link = ctlr->frames[ix];		td->flags |= IsoClean;		ctlr->frames[ix] = PCIWADDR(td);	}	return 0;}static voidunschedendpt(Ctlr *ctlr, Endpt *e){	int q;	TD *td;	Endptx *x;	ulong *addr;	if(!e->iso || e->sched < 0)		return;	x = e->private;	if (x->tdalloc == nil)		panic("tdalloc");	for (q = e->sched; q < NFRAME; q += e->pollms){		td = x->td0++;		addr = &ctlr->frames[q];		while(*addr != PADDR(td)) {			if(*addr & IsQH)				panic("usb: TD expected");			addr = &TFOL(*addr)->link;		}		*addr = td->link;		ctlr->frameld[q] -= e->maxpkt;	}	free(x->tdalloc);	free(x->bpalloc);	x->tdalloc = nil;	x->bpalloc = nil;	x->etd = nil;	x->td0 = nil;	e->sched = -1;}static voidepalloc(Usbhost *uh, Endpt *e){	Endptx *x;	x = malloc(sizeof(Endptx));	e->private = x;	x->epq = allocqh(uh->ctlr);	if(x->epq == nil)		panic("devendptx");}static voidepfree(Usbhost *uh, Endpt *e){	Ctlr *ctlr;	Endptx *x;	ctlr = uh->ctlr;	x = e->private;	if(x->epq != nil)		freeqh(ctlr, x->epq);}static voidepopen(Usbhost *uh, Endpt *e){	Ctlr *ctlr;	ctlr = uh->ctlr;	if(e->iso && e->active)		error("already open");	if(schedendpt(ctlr, e) < 0){		if(e->active)			error("cannot schedule USB endpoint, active");		else			error("cannot schedule USB endpoint");	}	eptactivate(ctlr, e);}static voidepclose(Usbhost *uh, Endpt *e){	Ctlr *ctlr;	ctlr = uh->ctlr;	eptdeactivate(ctlr, e);	unschedendpt(ctlr, e);}static voidepmode(Usbhost *uh, Endpt *e){	Ctlr *ctlr;	Endptx *x;	ctlr = uh->ctlr;	x = e->private;	if(e->iso) {		if(x->epq != nil) {			freeqh(ctlr, x->epq);			x->epq = nil;		}	}	else {		/* Each bulk device gets a queue head hanging off the		 * bulk queue head		 */		if(x->epq == nil) {			x->epq = allocqh(ctlr);			if(x->epq == nil)				panic("epbulk: allocqh");		}		queueqh(ctlr, x->epq);	}}static	int	ioport[] = {-1, Portsc0, Portsc1};static voidportreset(Usbhost *uh, int port){	int i, p;	Ctlr *ctlr;	ctlr = uh->ctlr;	if(port != 1 && port != 2)		error(Ebadarg);	/* should check that device not being configured on other port? */	p = ioport[port];	qlock(&ctlr->resetl);	if(waserror()){		qunlock(&ctlr->resetl);		nexterror();	}	XPRINT("r: %x\n", IN(p));	ilock(ctlr);	OUT(p, PortReset);	delay(12);	/* BUG */	XPRINT("r2: %x\n", IN(p));	OUT(p, IN(p) & ~PortReset);	XPRINT("r3: %x\n", IN(p));	OUT(p, IN(p) | PortEnable);	microdelay(64);	for(i=0; i<1000 && (IN(p) & PortEnable) == 0; i++)		;	XPRINT("r': %x %d\n", IN(p), i);	OUT(p, (IN(p) & ~PortReset)|PortEnable);	iunlock(ctlr);	poperror();	qunlock(&ctlr->resetl);}static voidportenable(Usbhost *uh, int port, int on){	int w, p;	Ctlr *ctlr;	ctlr = uh->ctlr;	if(port != 1 && port != 2)		error(Ebadarg);	/* should check that device not being configured on other port? */	p = ioport[port];	qlock(&ctlr->resetl);	if(waserror()){		qunlock(&ctlr->resetl);		nexterror();	}	ilock(ctlr);	w = IN(p);	if(on)		w |= PortEnable;	else		w &= ~PortEnable;	OUT(p, w);	microdelay(64);	iunlock(ctlr);	XPRINT("e: %x\n", IN(p));	poperror();	qunlock(&ctlr->resetl);}static voidportinfo(Usbhost *uh, char *s, char *se){	int x, i, j;	Ctlr *ctlr;	ctlr = uh->ctlr;	for(i = 1; i <= 2; i++) {		ilock(ctlr);		x = IN(ioport[i]);		if((x & (PortChange|StatusChange)) != 0)			OUT(ioport[i], x);		iunlock(ctlr);		s = seprint(s, se, "%d %ux", i, x);		for(j = 0; j < nelem(portstatus); j++) {			if((x & portstatus[j].bit) != 0)				s = seprint(s, se, " %s", portstatus[j].name);		}		s = seprint(s, se, "\n");	}}static voidcleaniso(Endpt *e, int frnum){	TD *td;	int id, n, i;	Endptx *x;	uchar *bp;	x = e->private;	td = x->xtd;	if (td->status & Active)		return;	id = (e->x<<7)|(e->dev->x&0x7F);	do {		if (td->status & AnyError)			XPRINT("usbisoerror 0x%lux\n", td->status);		n = (td->status + 1) & 0x3ff;		e->nbytes += n;		if ((td->flags & IsoClean) == 0)			e->nblocks++;		if (e->mode == OREAD){			e->buffered += n;			e->poffset += (td->status + 1) & 0x3ff;			td->offset = e->poffset;			td->dev = ((e->maxpkt -1)<<21) | ((id&0x7FF)<<8) | TokIN;			e->toffset = td->offset;		}else{			if ((td->flags & IsoClean) == 0){				e->buffered -= n;				if (e->buffered < 0){//					print("e->buffered %d?\n", e->buffered);					e->buffered = 0;				}			}			e->toffset = td->offset;			n = (e->hz + e->remain)*e->pollms/1000;			e->remain = (e->hz + e->remain)*e->pollms%1000;			n *= e->samplesz;			td->dev = ((n -1)<<21) | ((id&0x7FF)<<8) | TokOUT;			td->offset = e->poffset;			e->poffset += n;		}		td = td->next;		if (x->xtd == td){			XPRINT("@");			break;		}	} while ((td->status & Active) == 0);	e->time = todget(nil);	x->xtd = td;	for (n = 2; n < 4; n++){		i = ((frnum + n)&0x3ff);		td = x->td0 + i;		bp = x->bp0 + e->maxpkt*i/e->pollms;		if (td->status & Active)			continue;		if (e->mode == OWRITE){			if (td == x->etd) {				XPRINT("*");				memset(bp+e->off, 0, e->maxpkt-e->off);				if (e->off == 0)					td->flags |= IsoClean;				else					e->buffered += (((td->dev>>21) +1) & 0x3ff) - e->off;				x->etd = nil;			}else if ((td->flags & IsoClean) == 0){				XPRINT("-");				memset(bp, 0, e->maxpkt);				td->flags |= IsoClean;			}		} else {			/* Unread bytes are now lost */			e->buffered -= (td->status + 1) & 0x3ff;		}		td->status = ErrLimit1 | Active | IsoSelect | IOC;	}	wakeup(&e->wr);}static voidinterrupt(Ureg*, void *a){	QH *q;	Ctlr *ctlr;	Endpt *e;	Endptx *x;	int s, frnum;	Usbhost *uh;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -