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

📄 usbuhci.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
#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"#define XPRINT if(debug)print#define XXPRINT if(0)printstatic int Chatty = 0;static int debug = 0;static	char	Estalled[] = "usb endpoint stalled";/* * UHCI interface registers and bits */enum{	/* i/o space */	Cmd = 0,	Status = 2,	Usbintr = 4,	Frnum = 6,	Flbaseadd = 8,	SOFMod = 0xC,	Portsc0 = 0x10,	Portsc1 = 0x12,	/* port status */	Suspend =	1<<12,	PortReset =	1<<9,	SlowDevice =	1<<8,	ResumeDetect =	1<<6,	PortChange =	1<<3,	/* write 1 to clear */	PortEnable =	1<<2,	StatusChange =	1<<1,	/* write 1 to clear */	DevicePresent =	1<<0,	NFRAME = 	1024,	FRAMESIZE=	NFRAME*sizeof(ulong),	/* fixed by hardware; aligned to same */	Vf =		1<<2,	/* TD only */	IsQH =		1<<1,	Terminate =	1<<0,	/* TD.status */	SPD =		1<<29,	ErrLimit0 =	0<<27,	ErrLimit1 =	1<<27,	ErrLimit2 =	2<<27,	ErrLimit3 =	3<<27,	LowSpeed =	1<<26,	IsoSelect =	1<<25,	IOC =		1<<24,	Active =	1<<23,	Stalled =	1<<22,	DataBufferErr =	1<<21,	Babbling =	1<<20,	NAKed =		1<<19,	CRCorTimeout =	1<<18,	BitstuffErr =	1<<17,	AnyError = (Stalled | DataBufferErr | Babbling | NAKed | CRCorTimeout | BitstuffErr),	/* TD.dev */	IsDATA1 =	1<<19,	/* TD.flags (software) */	CancelTD=	1<<0,	IsoClean=	1<<2,};static struct{	int	bit;	char	*name;}portstatus[] ={	{ Suspend,		"suspend", },	{ PortReset,		"reset", },	{ SlowDevice,		"lowspeed", },	{ ResumeDetect,		"resume", },	{ PortChange,		"portchange", },	{ PortEnable,		"enable", },	{ StatusChange,		"statuschange", },	{ DevicePresent,	"present", },};typedef struct Ctlr Ctlr;typedef struct Endptx Endptx;typedef struct QH QH;typedef struct TD TD;/* * software structures */struct Ctlr{	Lock;	/* protects state shared with interrupt (eg, free list) */	Ctlr*	next;	Pcidev*	pcidev;	int	active;	int	io;	ulong*	frames;	/* frame list */	ulong*	frameld;	/* real time load on each of the frame list entries */	QLock	resetl;	/* lock controller during USB reset */	TD*	tdpool;	TD*	freetd;	QH*	qhpool;	QH*	freeqh;	QH*	ctlq;	/* queue for control i/o */	QH*	bwsop;	/* empty bandwidth sop (to PIIX4 errata specifications) */	QH*	bulkq;	/* queue for bulk i/o (points back to bandwidth sop) */	QH*	recvq;	/* receive queues for bulk i/o */	Udev*	ports[2];	struct {		Lock;		Endpt*	f;	} activends;	long	usbints;	/* debugging */	long	framenumber;	long	frameptr;	long	usbbogus;};#define	IN(x)		ins(ctlr->io+(x))#define	OUT(x, v)	outs(ctlr->io+(x), (v))static Ctlr* ctlrhead;static Ctlr* ctlrtail;struct Endptx{	QH*	epq;		/* queue of TDs for this endpoint */	/* ISO related: */	void*	tdalloc;	void*	bpalloc;	uchar*	bp0;		/* first block in array */	TD*	td0;		/* first td in array */	TD*	etd;		/* pointer into circular list of TDs for isochronous ept */	TD*	xtd;		/* next td to be cleaned */};/* * UHCI hardware structures, aligned on 16-byte boundary */struct TD{	ulong	link;	ulong	status;	/* controller r/w */	ulong	dev;	ulong	buffer;	/* software */	ulong	flags;	union{		Block*	bp;	/* non-iso */		ulong	offset;	/* iso */	};	Endpt*	ep;	TD*	next;};#define	TFOL(p)	((TD*)KADDR((ulong)(p) & ~(0xF|PCIWINDOW)))struct QH{	ulong	head;	ulong	entries;	/* address of next TD or QH to process (updated by controller) */	/* software */	QH*	hlink;	TD*	first;	QH*	next;		/* free list */	TD*	last;	ulong	_d1;		/* fillers */	ulong	_d2;};#define	QFOL(p)	((QH*)KADDR((ulong)(p) & ~(0xF|PCIWINDOW)))static TD *alloctd(Ctlr *ctlr){	TD *t;	ilock(ctlr);	t = ctlr->freetd;	if(t == nil)		panic("alloctd");	/* TO DO */	ctlr->freetd = t->next;	t->next = nil;	iunlock(ctlr);	t->ep = nil;	t->bp = nil;	t->status = 0;	t->link = Terminate;	t->buffer = 0;	t->flags = 0;	return t;}static voidfreetd(Ctlr *ctlr, TD *t){	t->ep = nil;	if(t->bp)		freeb(t->bp);	t->bp = nil;	ilock(ctlr);	t->buffer = 0xdeadbeef;	t->next = ctlr->freetd;	ctlr->freetd = t;	iunlock(ctlr);}static voiddumpdata(Block *b, int n){	int i;	XPRINT("\tb %8.8lux[%d]: ", (ulong)b->rp, n);	if(n > 16)		n = 16;	for(i=0; i<n; i++)		XPRINT(" %2.2ux", b->rp[i]);	XPRINT("\n");}static voiddumptd(TD *t, int follow){	int i, n;	char buf[20], *s;	TD *t0;	t0 = t;	while(t){		i = t->dev & 0xFF;		if(i == TokOUT || i == TokSETUP)			n = ((t->dev>>21) + 1) & 0x7FF;		else if((t->status & Active) == 0)			n = (t->status + 1) & 0x7FF;		else			n = 0;		s = buf;		if(t->status & Active)			*s++ = 'A';		if(t->status & Stalled)			*s++ = 'S';		if(t->status & DataBufferErr)			*s++ = 'D';		if(t->status & Babbling)			*s++ = 'B';		if(t->status & NAKed)			*s++ = 'N';		if(t->status & CRCorTimeout)			*s++ = 'T';		if(t->status & BitstuffErr)			*s++ = 'b';		if(t->status & LowSpeed)			*s++ = 'L';		*s = 0;		XPRINT("td %8.8lux: ", t);		XPRINT("l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n",			t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags);		XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n",			buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1);		if(debug && t->bp && (t->flags & CancelTD) == 0)			dumpdata(t->bp, n);		if(!follow || t->link & Terminate || t->link & IsQH)			break;		t = TFOL(t->link);		if(t == t0)			break;	/* looped */	}}static TD *alloctde(Ctlr *ctlr, Endpt *e, int pid, int n){	TD *t;	int tog, id;	t = alloctd(ctlr);	id = (e->x<<7)|(e->dev->x&0x7F);	tog = 0;	if((pid == TokOUT && e->wdata01) || (pid == TokIN && e->rdata01))		tog = IsDATA1;	t->ep = e;	t->status = ErrLimit3 | Active | IOC;	/* or put IOC only on last? */	if(e->dev->ls)		t->status |= LowSpeed;	t->dev = ((n-1)<<21) | ((id&0x7FF)<<8) | pid | tog;	return t;}static QH *allocqh(Ctlr *ctlr){	QH *qh;	ilock(ctlr);	qh = ctlr->freeqh;	if(qh == nil)		panic("allocqh");	/* TO DO */	ctlr->freeqh = qh->next;	qh->next = nil;	iunlock(ctlr);	qh->head = Terminate;	qh->entries = Terminate;	qh->hlink = nil;	qh->first = nil;	qh->last = nil;	return qh;}static voidfreeqh(Ctlr *ctlr, QH *qh){	ilock(ctlr);	qh->next = ctlr->freeqh;	ctlr->freeqh = qh;	iunlock(ctlr);}static voiddumpqh(QH *q){	int i;	QH *q0;	q0 = q;	for(i = 0; q != nil && i < 10; i++){		XPRINT("qh %8.8lux: %8.8lux %8.8lux\n", q, q->head, q->entries);		if((q->entries & (IsQH|Terminate)) == 0)			dumptd(TFOL(q->entries), 1);		if(q->head & Terminate)			break;		if((q->head & IsQH) == 0){			XPRINT("head:");			dumptd(TFOL(q->head), 1);			break;		}		q = QFOL(q->head);		if(q == q0)			break;	/* looped */	}}static voidqueuetd(Ctlr *ctlr, QH *q, TD *t, int vf, char *why){	TD *lt;	for(lt = t; lt->next != nil; lt = lt->next)		lt->link = PCIWADDR(lt->next) | vf;	lt->link = Terminate;	ilock(ctlr);	XPRINT("queuetd %s: t=%p lt=%p q=%p first=%p last=%p entries=%.8lux\n",		why, t, lt, q, q->first, q->last, q->entries);	if(q->first != nil){		q->last->link = PCIWADDR(t) | vf;		q->last->next = t;	}else{		q->first = t;		q->entries = PCIWADDR(t);	}	q->last = lt;	XPRINT("	t=%p q=%p first=%p last=%p entries=%.8lux\n",		t, q, q->first, q->last, q->entries);	dumpqh(q);	iunlock(ctlr);}static voidcleantd(Ctlr *ctlr, TD *t, int discard){	Block *b;	int n, err;	XPRINT("cleanTD: %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer);	if(t->ep != nil && t->ep->debug)		dumptd(t, 0);	if(t->status & Active)		panic("cleantd Active");	err = t->status & (AnyError&~NAKed);	/* TO DO: on t->status&AnyError, q->entries will not have advanced */	if (err) {		XPRINT("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer);//		print("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer);	}	switch(t->dev&0xFF){	case TokIN:		if(discard || (t->flags & CancelTD) || t->ep == nil || t->ep->x!=0&&err){			if(t->ep != nil){				if(err != 0)					t->ep->err = err==Stalled? Estalled: Eio;				wakeup(&t->ep->rr);	/* in case anyone cares */			}			break;		}		b = t->bp;		n = (t->status + 1) & 0x7FF;		if(n > b->lim - b->wp)			n = 0;		b->wp += n;		if(Chatty)			dumpdata(b, n);		t->bp = nil;		t->ep->nbytes += n;		t->ep->nblocks++;		qpass(t->ep->rq, b);	/* TO DO: flow control */		wakeup(&t->ep->rr);	/* TO DO */		break;	case TokSETUP:		XPRINT("cleanTD: TokSETUP %lux\n", &t->ep);		/* don't really need to wakeup: subsequent IN or OUT gives status */		if(t->ep != nil) {			wakeup(&t->ep->wr);	/* TO DO */			XPRINT("cleanTD: wakeup %lux\n", &t->ep->wr);		}		break;	case TokOUT:		/* TO DO: mark it done somewhere */		XPRINT("cleanTD: TokOut %lux\n", &t->ep);		if(t->ep != nil){			if(t->bp){				n = BLEN(t->bp);				t->ep->nbytes += n;				t->ep->nblocks++;			}			if(t->ep->x!=0 && err != 0)				t->ep->err = err==Stalled? Estalled: Eio;			if(--t->ep->ntd < 0)				panic("cleantd ntd");			wakeup(&t->ep->wr);	/* TO DO */			XPRINT("cleanTD: wakeup %lux\n", &t->ep->wr);		}		break;	}	freetd(ctlr, t);}static voidcleanq(Ctlr *ctlr, QH *q, int discard, int vf){	TD *t, *tp;	ilock(ctlr);	tp = nil;	for(t = q->first; t != nil;){		XPRINT("cleanq: %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer, t->flags, t->next);		if(t->status & Active){			if(t->status & NAKed){				t->status = (t->status & ~NAKed) | IOC;	/* ensure interrupt next frame */				tp = t;				t = t->next;				continue;			}			if(t->flags & CancelTD){				XPRINT("cancelTD: %8.8lux\n", (ulong)t);				t->status = (t->status & ~Active) | IOC;	/* ensure interrupt next frame */				tp = t;				t = t->next;				continue;			}			tp = t;			t = t->next;			continue;		}		t->status &= ~IOC;		if (tp == nil) {			q->first = t->next;			if(q->first != nil)				q->entries = PCIWADDR(q->first);			else				q->entries = Terminate;		} else {			tp->next = t->next;			if (t->next != nil)				tp->link = PCIWADDR(t->next) | vf;			else				tp->link = Terminate;		}		if (q->last == t)			q->last = tp;		iunlock(ctlr);		cleantd(ctlr, t, discard);		ilock(ctlr);		if (tp)			t = tp->next;		else			t = q->first;		XPRINT("t = %8.8lux\n", t);		dumpqh(q);	}	if(q->first && q->entries != PCIWADDR(q->first)){		ctlr->usbbogus++;		q->entries = PCIWADDR(q->first);	}	iunlock(ctlr);}

⌨️ 快捷键说明

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