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

📄 uartaxp.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	if(ibtr > i)		ibtr = i;	ccb->ibtr = ibtr;	axpcc(uart->regs, Ccu);	return 0;}static voidaxpbreak(Uart* uart, int ms){	Ccb *ccb;	u16int mc;	/*	 * Send a break.	 */	if(ms <= 0)		ms = 200;	ccb = ((Cc*)(uart->regs))->ccb;	mc = ccb->mc;	ccb->mc = Ab|mc;	tsleep(&up->sleep, return0, 0, ms);	ccb->mc = mc & ~Ab;}/* only called from interrupt service */static voidaxpmc(Cc* cc){	int old;	Ccb *ccb;	u16int ms;	ccb = cc->ccb;	ms = ccb->ms;	if(ms & Scts){		ilock(&cc->tlock);		old = cc->cts;		cc->cts = ms & Scts;		if(old == 0 && cc->cts)			cc->ctsbackoff = 2;		iunlock(&cc->tlock);	}	if(ms & Sdsr){		old = ms & Sdsr;		if(cc->hup_dsr && cc->dsr && !old)			cc->dohup = 1;		cc->dsr = old;	}	if(ms & Sdcd){		old = ms & Sdcd;		if(cc->hup_dcd && cc->dcd && !old)			cc->dohup = 1;		cc->dcd = old;	}}/* called from uartkick() with uart->tlock ilocked */static voidaxpkick(Uart* uart){	Cc *cc;	Ccb *ccb;	uchar *ep, *mem, *rp, *wp, *bp;	if(uart->cts == 0 || uart->blocked)		return;	cc = uart->regs;	ccb = cc->ccb;	mem = (uchar*)cc->ctlr->gcb;	bp = mem + ccb->obsa;	rp = mem + ccb->obrp;	wp = mem + ccb->obwp;	ep = mem + ccb->obea;	while(wp != rp-1 && (rp != bp || wp != ep)){		/*		 * if we've exhausted the uart's output buffer,		 * ask for more from the output queue, and quit if there		 * isn't any.		 */		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)			break;		*wp++ = *(uart->op++);		if(wp > ep)			wp = bp;		ccb->obwp = wp - mem;	}}/* only called from interrupt service */static voidaxprecv(Cc* cc){	Ccb *ccb;	uchar *ep, *mem, *rp, *wp;	ccb = cc->ccb;	mem = (uchar*)cc->ctlr->gcb;	rp = mem + ccb->ibrp;	wp = mem + ccb->ibwp;	ep = mem + ccb->ibea;	while(rp != wp){		uartrecv(cc, *rp++);		/* ilocks cc->tlock */		if(rp > ep)			rp = mem + ccb->ibsa;		ccb->ibrp = rp - mem;	}}static voidaxpinterrupt(Ureg*, void* arg){	int work;	Cc *cc;	Ctlr *ctlr;	u32int ics;	u16int r, sr;	work = 0;	ctlr = arg;	ics = csr32r(ctlr, Ics);	if(ics & 0x0810C000)		print("%s: unexpected interrupt %#ux\n", ctlr->name, ics);	if(!(ics & 0x00002000)) {		print("%s: non-doorbell interrupt\n", ctlr->name);		// ctlr->gcb->gcw2 = 0x0001;	/* set Gintack */		return;	}//	while(work to do){		cc = ctlr->cc;		for(sr = xchgw(&ctlr->gcb->isr, 0); sr != 0; sr >>= 1){			if(sr & 0x0001)				work++, axprecv(cc);			cc++;		}		cc = ctlr->cc;		for(sr = xchgw(&ctlr->gcb->osr, 0); sr != 0; sr >>= 1){			if(sr & 0x0001)				work++, uartkick(&cc->Uart);			cc++;		}		cc = ctlr->cc;		for(sr = xchgw(&ctlr->gcb->csr, 0); sr != 0; sr >>= 1){			if(sr & 0x0001)				work++, wakeup(cc);			cc++;		}		cc = ctlr->cc;		for(sr = xchgw(&ctlr->gcb->msr, 0); sr != 0; sr >>= 1){			if(sr & 0x0001)				work++, axpmc(cc);			cc++;		}		cc = ctlr->cc;		for(sr = xchgw(&ctlr->gcb->esr, 0); sr != 0; sr >>= 1){			if(sr & 0x0001){				r = cc->ccb->ms;				if(r & Oe)					cc->oerr++;				if(r & Pe)					cc->perr++;				if(r & Fe)					cc->ferr++;				if (r & (Oe|Pe|Fe))					work++;			}			cc++;		}//	}	/* only meaningful if we don't share the irq */	if (0 && !work)		print("%s: interrupt with no work\n", ctlr->name);	csr32w(ctlr, Pdb, 1);		/* clear doorbell interrupt */	ctlr->gcb->gcw2 = 0x0001;	/* set Gintack */}static voidaxpdisable(Uart* uart){	Cc *cc;	u16int lp;	Ctlr *ctlr;	/* 	 * Turn off DTR and RTS, disable interrupts.	 */	(*uart->phys->dtr)(uart, 0);	(*uart->phys->rts)(uart, 0);	cc = uart->regs;	lp = cc->ccb->lp;	cc->ccb->lp = Emcs|lp;	axpcc(cc, Dt|Dr|Fob|Fib|Ccu);	/*	 * The Uart is qlocked.	 */	ctlr = cc->ctlr;	ctlr->im &= ~(1<<cc->uartno);	if(ctlr->im == 0)		intrdisable(ctlr->pcidev->intl, axpinterrupt, ctlr,			ctlr->pcidev->tbdf, ctlr->name);}static voidaxpenable(Uart* uart, int ie){	Cc *cc;	Ctlr *ctlr;	u16int lp;	cc = uart->regs;	ctlr = cc->ctlr;	/* 	 * Enable interrupts and turn on DTR and RTS.	 * Be careful if this is called to set up a polled serial line	 * early on not to try to enable interrupts as interrupt-	 * -enabling mechanisms might not be set up yet.	 */	if(ie){		/*		 * The Uart is qlocked.		 */		if(ctlr->im == 0){			intrenable(ctlr->pcidev->intl, axpinterrupt, ctlr,				ctlr->pcidev->tbdf, ctlr->name);			csr32w(ctlr, Ics, 0x00031F00);			csr32w(ctlr, Pdb, 1);			ctlr->gcb->gcw2 = 1;		}		ctlr->im |= 1<<cc->uartno;	}	(*uart->phys->dtr)(uart, 1);	(*uart->phys->rts)(uart, 1);	/*	 * Make sure we control RTS, DTR and break.	 */	lp = cc->ccb->lp;	cc->ccb->lp = Emcs|lp;	cc->ccb->oblw = 64;	axpcc(cc, Et|Er|Ccu);}static void*axpdealloc(Ctlr* ctlr){	int i;	for(i = 0; i < 16; i++){		if(ctlr->cc[i].name != nil)			free(ctlr->cc[i].name);	}	if(ctlr->reg != nil)		vunmap(ctlr->reg, ctlr->pcidev->mem[0].size);	if(ctlr->mem != nil)		vunmap(ctlr->mem, ctlr->pcidev->mem[2].size);	if(ctlr->name != nil)		free(ctlr->name);	free(ctlr);	return nil;}static Uart*axpalloc(int ctlrno, Pcidev* pcidev){	Cc *cc;	uchar *p;	Ctlr *ctlr;	void *addr;	char name[64];	u32int bar, r;	int i, n, timeo;	ctlr = malloc(sizeof(Ctlr));	seprint(name, name+sizeof(name), "uartaxp%d", ctlrno);	kstrdup(&ctlr->name, name);	ctlr->pcidev = pcidev;	ctlr->ctlrno = ctlrno;	/*	 * Access to runtime registers.	 */	bar = pcidev->mem[0].bar;	if((addr = vmap(bar & ~0x0F, pcidev->mem[0].size)) == 0){		print("%s: can't map registers at %#ux\n", ctlr->name, bar);		return axpdealloc(ctlr);	}	ctlr->reg = addr;	print("%s: port 0x%ux irq %d ", ctlr->name, bar, pcidev->intl);	/*	 * Local address space 0.	 */	bar = pcidev->mem[2].bar;	if((addr = vmap(bar & ~0x0F, pcidev->mem[2].size)) == 0){		print("%s: can't map memory at %#ux\n", ctlr->name, bar);		return axpdealloc(ctlr);	}	ctlr->mem = addr;	ctlr->gcb = (Gcb*)(ctlr->mem+0x10000);	print("mem 0x%ux size %d: ", bar, pcidev->mem[2].size);	/*	 * Toggle the software reset and wait for	 * the adapter local init status to indicate done.	 *	 * The two 'delay(100)'s below are important,	 * without them the board seems to become confused	 * (perhaps it needs some 'quiet time' because the	 * timeout loops are not sufficient in themselves).	 */	r = csr32r(ctlr, Mcc);	csr32w(ctlr, Mcc, r|Asr);	microdelay(1);	csr32w(ctlr, Mcc, r&~Asr);	delay(100);	for(timeo = 0; timeo < 100000; timeo++){		if(csr32r(ctlr, Mcc) & Lis)			break;		microdelay(1);	}	if(!(csr32r(ctlr, Mcc) & Lis)){		print("%s: couldn't reset\n", ctlr->name);		return axpdealloc(ctlr);	}	print("downloading...");	/*	 * Copy the control programme to the card memory.	 * The card's i960 control structures live at 0xD000.	 */	if(sizeof(uartaxpcp) > 0xD000){		print("%s: control programme too big\n", ctlr->name);		return axpdealloc(ctlr);	}	/* TODO: is this right for more than 1 card? devastar does the same */	csr32w(ctlr, Remap, 0xA0000001);	for(i = 0; i < sizeof(uartaxpcp); i++)		ctlr->mem[i] = uartaxpcp[i];	/*	 * Execute downloaded code and wait for it	 * to signal ready.	 */	csr32w(ctlr, Mb0, Edcc);	delay(100);	/* the manual says to wait for Cpr for 1 second */	for(timeo = 0; timeo < 10000; timeo++){		if(csr32r(ctlr, Mb0) & Cpr)			break;		microdelay(100);	}	if(!(csr32r(ctlr, Mb0) & Cpr)){		print("control programme not ready; Mb0 %#ux\n",			csr32r(ctlr, Mb0));		print("%s: might not be fully seated in its PCI slot\n",			ctlr->name);		return axpdealloc(ctlr);	}	print("\n");	n = ctlr->gcb->ccbn;	if(ctlr->gcb->bt != 0x12 || n > 16){		print("%s: wrong board type %#ux, %d channels\n",			ctlr->name, ctlr->gcb->bt, ctlr->gcb->ccbn);		return axpdealloc(ctlr);	}	p = ((uchar*)ctlr->gcb) + ctlr->gcb->ccboff;	for(i = 0; i < n; i++){		cc = &ctlr->cc[i];		cc->ccb = (Ccb*)p;		p += ctlr->gcb->ccbsz;		cc->uartno = i;		cc->ctlr = ctlr;		cc->regs = cc;		/* actually Uart->regs */		seprint(name, name+sizeof(name), "uartaxp%d%2.2d", ctlrno, i);		kstrdup(&cc->name, name);		cc->freq = 0;		cc->bits = 8;		cc->stop = 1;		cc->parity = 'n';		cc->baud = 9600;		cc->phys = &axpphysuart;		cc->console = 0;		cc->special = 0;		cc->next = &ctlr->cc[i+1];	}	ctlr->cc[n-1].next = nil;	ctlr->next = nil;	if(axpctlrhead != nil)		axpctlrtail->next = ctlr;	else		axpctlrhead = ctlr;	axpctlrtail = ctlr;	return ctlr->cc;}static Uart*axppnp(void){	Pcidev *p;	int ctlrno;	Uart *head, *tail, *uart;	/*	 * Loop through all PCI devices looking for simple serial	 * controllers (ccrb == 0x07) and configure the ones which	 * are familiar.	 */	head = tail = nil;	ctlrno = 0;	for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){		if(p->ccrb != 0x07)			continue;		switch((p->did<<16)|p->vid){		default:			continue;		case (0x6001<<16)|0x114F:	/* AvanstarXp */			if((uart = axpalloc(ctlrno, p)) == nil)				continue;			break;		}		if(head != nil)			tail->next = uart;		else			head = uart;		for(tail = uart; tail->next != nil; tail = tail->next)			;		ctlrno++;	}	return head;}PhysUart axpphysuart = {	.name		= "AvanstarXp",	.pnp		= axppnp,	.enable		= axpenable,	.disable	= axpdisable,	.kick		= axpkick,	.dobreak	= axpbreak,	.baud		= axpbaud,	.bits		= axpbits,	.stop		= axpstop,	.parity		= axpparity,	.modemctl	= axpmodemctl,	.rts		= axprts,	.dtr		= axpdtr,	.status		= axpstatus,	.fifo		= axpfifo,	.getc		= nil,	.putc		= nil,};

⌨️ 快捷键说明

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