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

📄 usbuhci.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
	uh = a;	ctlr = uh->ctlr;	s = IN(Status);	ctlr->frameptr = inl(ctlr->io+Flbaseadd);	ctlr->framenumber = IN(Frnum) & 0x3ff;	OUT(Status, s);	if ((s & 0x1f) == 0)		return;	ctlr->usbints++;	frnum = IN(Frnum) & 0x3ff;	if (s & 0x1a) {		XPRINT("cmd #%x sofmod #%x\n", IN(Cmd), inb(ctlr->io+SOFMod));		XPRINT("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1));	}	ilock(&ctlr->activends);	for(e = ctlr->activends.f; e != nil; e = e->activef) {		x = e->private;		if(!e->iso && x->epq != nil) {			XXPRINT("cleanq(ctlr, x->epq, 0, 0)\n");			cleanq(ctlr, x->epq, 0, 0);		}		if(e->iso) {			XXPRINT("cleaniso(e)\n");			cleaniso(e, frnum);		}	}	iunlock(&ctlr->activends);	XXPRINT("cleanq(ctlr, ctlr->ctlq, 0, 0)\n");	cleanq(ctlr, ctlr->ctlq, 0, 0);	XXPRINT("cleanq(ctlr, ctlr->bulkq, 0, Vf)\n");	cleanq(ctlr, ctlr->bulkq, 0, Vf);	XXPRINT("clean recvq\n");	for (q = ctlr->recvq->next; q; q = q->hlink) {		XXPRINT("cleanq(ctlr, q, 0, Vf)\n");		cleanq(ctlr, q, 0, Vf);	}}static inteptinput(void *arg){	Endpt *e;	e = arg;	return e->eof || e->err || qcanread(e->rq);}static intisoready(void *a){	Endptx *x;	TD *etd;	x = a;	return (etd = x->etd) == nil || (etd != x->xtd && (etd->status & Active) == 0);}static longisoio(Ctlr *ctlr, Endpt *e, void *a, long n, ulong offset, int w){	TD *td;	Endptx *x;	int i, frnum;	uchar *p, *q, *bp;	volatile int isolock;	x = e->private;	qlock(&e->rlock);	isolock = 0;	if(waserror()){		if (isolock){			isolock = 0;			iunlock(&ctlr->activends);		}		qunlock(&e->rlock);		eptcancel(ctlr, e);		nexterror();	}	p = a;	if (offset != 0 && offset != e->foffset){		iprint("offset %lud, foffset %lud\n", offset, e->foffset);		/* Seek to a specific position */		frnum = (IN(Frnum) + 8) & 0x3ff;		td = x->td0 +frnum;		if (offset < td->offset)			error("ancient history");		while (offset > e->toffset){			tsleep(&e->wr, return0, 0, 500);		}		while (offset >= td->offset + ((w?(td->dev >> 21):td->status) + 1) & 0x7ff){			td = td->next;			if (td == x->xtd)				iprint("trouble\n");		}		ilock(&ctlr->activends);		isolock = 1;		e->off = td->offset - offset;		if (e->off >= e->maxpkt){			iprint("I can't program: %d\n", e->off);			e->off = 0;		}		x->etd = td;		e->foffset = offset;	}	do {		if (isolock == 0){			ilock(&ctlr->activends);			isolock = 1;		}		td = x->etd;		if (td == nil || e->off == 0){			if (td == nil){				XPRINT("0");				if (w){					frnum = (IN(Frnum) + 1) & 0x3ff;					td = x->td0 + frnum;					while(td->status & Active)						td = td->next;				}else{					frnum = (IN(Frnum) - 4) & 0x3ff;					td = x->td0 + frnum;					while(td->next != x->xtd)						td = td->next;				}				x->etd = td;				e->off = 0;			}else{				/* New td, make sure it's ready */				while (isoready(x) == 0){					isolock = 0;					iunlock(&ctlr->activends);					sleep(&e->wr, isoready, x);					ilock(&ctlr->activends);					isolock = 1;				}				if (x->etd == nil){					XPRINT("!");					continue;				}			}			if (w)				e->psize = ((td->dev >> 21) + 1) & 0x7ff;			else				e->psize = (x->etd->status + 1) & 0x7ff;			if(e->psize > e->maxpkt)				panic("packet size > maximum");		}		if((i = n) >= e->psize)			i = e->psize;		if (w)			e->buffered += i;		else{			e->buffered -= i;			if (e->buffered < 0)				e->buffered = 0;		}		isolock = 0;		iunlock(&ctlr->activends);		td->flags &= ~IsoClean;		bp = x->bp0 + (td - x->td0) * e->maxpkt / e->pollms;		q = bp + e->off;		if (w){			memmove(q, p, i);		}else{			memmove(p, q, i);		}		p += i;		n -= i;		e->off += i;		e->psize -= i;		if (e->psize){			if (n != 0)				panic("usb iso: can't happen");			break;		}		if(w)			td->offset = offset + (p-(uchar*)a) - (((td->dev >> 21) + 1) & 0x7ff);		td->status = ErrLimit3 | Active | IsoSelect | IOC;		x->etd = td->next;		e->off = 0;	} while(n > 0);	n = p-(uchar*)a;	e->foffset += n;	poperror();	if (isolock)		iunlock(&ctlr->activends);	qunlock(&e->rlock);	return n;}static longread(Usbhost *uh, Endpt *e, void *a, long n, vlong offset){	long l, i;	Block *b;	Ctlr *ctlr;	uchar *p;	ctlr = uh->ctlr;	if(e->iso)		return isoio(ctlr, e, a, n, (ulong)offset, 0);	XPRINT("qlock(%p)\n", &e->rlock);	qlock(&e->rlock);	XPRINT("got qlock(%p)\n", &e->rlock);	if(waserror()){		qunlock(&e->rlock);		eptcancel(ctlr, e);		nexterror();	}	p = a;	do {		if(e->eof) {			XPRINT("e->eof\n");			break;		}		if(e->err)			error(e->err);		qrcv(ctlr, e);		if(!e->iso)			e->rdata01 ^= 1;		sleep(&e->rr, eptinput, e);		if(e->err)			error(e->err);		b = qget(e->rq);	/* TO DO */		if(b == nil) {			XPRINT("b == nil\n");			break;		}		if(waserror()){			freeb(b);			nexterror();		}		l = BLEN(b);		if((i = l) > n)			i = n;		if(i > 0){			memmove(p, b->rp, i);			p += i;		}		poperror();		freeb(b);		n -= i;		if (l != e->maxpkt)			break;	} while (n > 0);	poperror();	qunlock(&e->rlock);	return p-(uchar*)a;}static intqisempty(void *arg){	return ((QH*)arg)->entries & Terminate;}static longwrite(Usbhost *uh, Endpt *e, void *a, long n, vlong offset, int tok){	int i, j;	QH *qh;	Block *b;	Ctlr *ctlr;	uchar *p;	ctlr = uh->ctlr;	if(e->iso)		return isoio(ctlr, e, a, n, (ulong)offset, 1);	p = a;	qlock(&e->wlock);	if(waserror()){		qunlock(&e->wlock);		eptcancel(ctlr, e);		nexterror();	}	do {		if(e->err)			error(e->err);		if((i = n) >= e->maxpkt)			i = e->maxpkt;		b = allocb(i);		if(waserror()){			freeb(b);			nexterror();		}		XPRINT("out [%d]", i);		for (j = 0; j < i; j++) XPRINT(" %.2x", p[j]);		XPRINT("\n");		memmove(b->wp, p, i);		b->wp += i;		p += i;		n -= i;		poperror();		qh = qxmit(ctlr, e, b, tok);		tok = TokOUT;		e->wdata01 ^= 1;		if(e->ntd >= e->nbuf) {XPRINT("qh %s: q=%p first=%p last=%p entries=%.8lux\n", "writeusb sleep", qh, qh->first, qh->last, qh->entries);			XPRINT("write: sleep %lux\n", &e->wr);			sleep(&e->wr, qisempty, qh);			XPRINT("write: awake\n");		}	} while(n > 0);	poperror();	qunlock(&e->wlock);	return p-(uchar*)a;}static voidinit(Usbhost* uh){	Ctlr *ctlr;	ctlr = uh->ctlr;	ilock(ctlr);	outl(ctlr->io+Flbaseadd, PCIWADDR(ctlr->frames));	OUT(Frnum, 0);	OUT(Usbintr, 0xF);	/* enable all interrupts */	XPRINT("cmd 0x%x sofmod 0x%x\n", IN(Cmd), inb(ctlr->io+SOFMod));	XPRINT("sc0 0x%x sc1 0x%x\n", IN(Portsc0), IN(Portsc1));	if((IN(Cmd)&1)==0)		OUT(Cmd, 1);	/* run *///	pprint("at: c=%x s=%x c0=%x\n", IN(Cmd), IN(Status), IN(Portsc0));	iunlock(ctlr);}static voidscanpci(void){	int io;	Ctlr *ctlr;	Pcidev *p;	static int already = 0;	if(already)		return;	already = 1;	p = nil;	while(p = pcimatch(p, 0, 0)) {		/*		 * Find UHCI controllers.  Class = 12 (serial controller),		 * Sub-class = 3 (USB) and Programming Interface = 0.		 */		if(p->ccrb != 0x0C || p->ccru != 0x03)			continue;		switch(p->ccrp){		case 0x00:			io = p->mem[4].bar & ~0x0F;			break;		case 0x10:		case 0x20:			print("usb%chci: %x/%x %sport 0x%lux size 0x%x irq %d (ignored)\n",				(p->ccrp == 0x10? 'o': 'e'), p->vid, p->did,				(p->ccrp == 0x10? "": "USB 2 "),				p->mem[0].bar & ~0x0F, p->mem[0].size, p->intl);			/* fallthrough */		default:			continue;		}		if(io == 0) {			print("usbuhci: failed to map registers\n");			continue;		}		if(ioalloc(io, p->mem[4].size, 0, "usbuhci") < 0){			print("usbuhci: port %d in use\n", io);			continue;		}		if(p->intl == 0xFF || p->intl == 0) {			print("usbuhci: no irq assigned for port %d\n", io);			continue;		}		XPRINT("usbuhci: %x/%x port 0x%ux size 0x%x irq %d\n",			p->vid, p->did, io, p->mem[4].size, p->intl);		ctlr = malloc(sizeof(Ctlr));		ctlr->pcidev = p;		ctlr->io = io;		if(ctlrhead != nil)			ctlrtail->next = ctlr;		else			ctlrhead = ctlr;		ctlrtail = ctlr;	}}static intreset(Usbhost *uh){	int i;	TD *t;	ulong io;	Ctlr *ctlr;	Pcidev *p;	scanpci();	/*	 * Any adapter matches if no uh->port is supplied,	 * otherwise the ports must match.	 */	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){		if(ctlr->active)			continue;		if(uh->port == 0 || uh->port == ctlr->io){			ctlr->active = 1;			break;		}	}	if(ctlr == nil)		return -1;	io = ctlr->io;	p = ctlr->pcidev;	uh->ctlr = ctlr;	uh->port = io;	uh->irq = p->intl;	uh->tbdf = p->tbdf;	XPRINT("usbcmd\t0x%.4x\nusbsts\t0x%.4x\nusbintr\t0x%.4x\nfrnum\t0x%.2x\n",		IN(Cmd), IN(Status), IN(Usbintr), inb(io+Frnum));	XPRINT("frbaseadd\t0x%.4x\nsofmod\t0x%x\nportsc1\t0x%.4x\nportsc2\t0x%.4x\n",		IN(Flbaseadd), inb(io+SOFMod), IN(Portsc0), IN(Portsc1));	OUT(Cmd, 0);					/* stop */	while((IN(Status) & (1<<5)) == 0)	/* wait for halt */		;	OUT(Status, 0xFF);				/* clear pending interrupts */	pcicfgw16(p, 0xc0, 0x2000);		/* legacy support register: turn off lunacy mode */	if(0){		i = inb(io+SOFMod);		OUT(Cmd, 4);	/* global reset */		delay(15);		OUT(Cmd, 0);	/* end reset */		delay(4);		outb(io+SOFMod, i);	}	ctlr->tdpool = xspanalloc(128*sizeof(TD), 16, 0);	for(i=128; --i>=0;){		ctlr->tdpool[i].next = ctlr->freetd;		ctlr->freetd = &ctlr->tdpool[i];	}	ctlr->qhpool = xspanalloc(64*sizeof(QH), 16, 0);	for(i=64; --i>=0;){		ctlr->qhpool[i].next = ctlr->freeqh;		ctlr->freeqh = &ctlr->qhpool[i];	}	/*	 * the last entries of the periodic (interrupt & isochronous) scheduling TD entries	 * points to the control queue and the bandwidth sop for bulk traffic.	 * this is looped following the instructions in PIIX4 errata 29773804.pdf:	 * a QH links to a looped but inactive TD as its sole entry,	 * with its head entry leading on to the bulk traffic, the last QH of which	 * links back to the empty QH.	 */	ctlr->ctlq = allocqh(ctlr);	ctlr->bwsop = allocqh(ctlr);	ctlr->bulkq = allocqh(ctlr);	ctlr->recvq = allocqh(ctlr);	t = alloctd(ctlr);	/* inactive TD, looped */	t->link = PCIWADDR(t);	ctlr->bwsop->entries = PCIWADDR(t);	ctlr->ctlq->head = PCIWADDR(ctlr->bulkq) | IsQH;	ctlr->bulkq->head = PCIWADDR(ctlr->recvq) | IsQH;	ctlr->recvq->head = PCIWADDR(ctlr->bwsop) | IsQH;	if (1)	/* don't use loop back */ 		ctlr->bwsop->head = Terminate;	else	/* set up loop back */		ctlr->bwsop->head = PCIWADDR(ctlr->bwsop) | IsQH;	ctlr->frames = xspanalloc(FRAMESIZE, FRAMESIZE, 0);	ctlr->frameld = xallocz(FRAMESIZE, 1);	for (i = 0; i < NFRAME; i++)		ctlr->frames[i] = PCIWADDR(ctlr->ctlq) | IsQH;	/*	 * Linkage to the generic USB driver.	 */	uh->init = init;	uh->interrupt = interrupt;	uh->portinfo = portinfo;	uh->portreset = portreset;	uh->portenable = portenable;	uh->epalloc = epalloc;	uh->epfree = epfree;	uh->epopen = epopen;	uh->epclose = epclose;	uh->epmode = epmode;	uh->read = read;	uh->write = write;	return 0;}voidusbuhcilink(void){	addusbtype("uhci", reset);}

⌨️ 快捷键说明

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