Charles.Forsyth20060303644188019 years agoHistory
1450 lines · 25.5 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	"../port/netif.h" enum {	Nbuf=	2,	/* double buffered */	Rbufsize=	512,	Bufsize=	(Rbufsize+CACHELINESZ-1)&~(CACHELINESZ-1),	Nuart=	2+4,	/* max in any 8xx architecture (2xSMC, 4xSCC) */	CTLS=	's'&037,	CTLQ=	'q'&037,}; enum {	/* status bits in SCC receive buffer descriptors */	RxBRK=	1<<7,	/* break ended frame (async hdlc) */	RxDE=	1<<7,	/* DPLL error (hdlc) */	RxBOF=	1<<6,	/* BOF ended frame (async hdlc) */	RxLG=	1<<5,	/* frame too large (hdlc) */	RxNO=	1<<4,	/* bad bit alignment (hdlc) */	RxBR=	1<<5,	/* break received during frame (uart) */	RxFR=	1<<4,	/* framing error (uart) */	RxPR=	1<<3,	/* parity error (uart) */	RxAB=	1<<3,	/* frame aborted (hdlc, async hdlc) */	RxCR=	1<<2,	/* bad CRC (hdlc, async hdlc) */	RxOV=	1<<1,	/* receiver overrun (all) */	RxCD=	1<<0,	/* CD lost (all) */ 	/* hdlc-specific Rx/Tx BDs */	TxTC=	1<<10,}; /* *  SMC in UART mode */ typedef struct Uartsmc Uartsmc;struct Uartsmc {	IOCparam;	ushort	maxidl;	ushort	idlc;	ushort	brkln;	ushort	brkec;	ushort	brkcr;	ushort	rmask;}; /* * SCC2 UART parameters */enum {	/* special mode bits */	SccAHDLC = 1<<0,	SccHDLC = 1<<1,	SccIR = 1<<2,	SccPPP = 1<<3,}; typedef struct Uartscc Uartscc;struct Uartscc {	SCCparam;	uchar	rsvd[8];	ushort	max_idl;	ushort	idlc;	ushort	brkcr;	ushort	parec;	ushort	frmec;	ushort	nosec;	ushort	brkec;	ushort	brkln;	ushort	uaddr1;	ushort	uaddr2;	ushort	rtemp;	ushort	toseq;	ushort	character[8];	ushort	rccm;	ushort	rccrp;	ushort	rlbc;}; typedef struct UartAHDLC UartAHDLC;struct UartAHDLC {	SCCparam;	ulong	rsvd1;	ulong	c_mask;	ulong	c_pres;	ushort	bof;	ushort	eof;	ushort	esc;	ushort	rsvd2[2];	ushort	zero;	ushort	rsvd3;	ushort	rfthr;	ushort	resvd4[2];	ulong	txctl_tbl;	ulong	rxctl_tbl;	ushort	nof;	ushort	rsvd5;}; typedef struct UartHDLC UartHDLC;struct UartHDLC {	SCCparam;	ulong	rsvd1;	ulong	c_mask;	ulong	c_pres;	ushort	disfc;	ushort	crcec;	ushort	abtsc;	ushort	nmarc;	ushort	retrc;	ushort	mflr;	ushort	max_cnt;	ushort	rfthr;	ushort	rfcnt;	ushort	hmask;	ushort	haddr[4];	ushort	tmp;	ushort	tmp_mb;}; enum {	/* SCC events of possible interest here eventually */	AB=	1<<9,	/* autobaud detected */	GRA= 1<<7,	/* graceful stop completed */	CCR= 1<<3,	/* control character detected */ 	/* SCC, SMC common interrupt events */	BSY=	1<<2,	/* receive buffer was busy (overrun) */	TXB= 1<<1,	/* block sent */	RXB= 1<<0,	/* block received */ 	/* SCC events */	TXE = 1<<4,	/* transmission error */	RXF = 1<<3,	/* final block received */ 	/* gsmr_l */	ENR = 1<<5,	/* enable receiver */	ENT = 1<<4,	/* enable transmitter */ 	/* port A */	RXD1=	SIBIT(15),	TXD1=	SIBIT(14), 	/* port B */	RTS1B=	IBIT(19), 	/* port C */	RTS1C=	SIBIT(15),	CTS1=	SIBIT(11),	CD1=	SIBIT(10),}; typedef struct Uart Uart;struct Uart{	QLock; 	Uart	*elist;		/* next enabled interface */	char	name[KNAMELEN]; 	int	x;		/* index: x in SMCx or SCCx */	int	cpmid;		/* eg, SCC1ID, SMC1ID */	CPMdev*	cpm;	int	opens;	uchar	bpc;	/* bits/char */	uchar	parity;	uchar	stopb;	uchar	setup;	uchar	enabled;	int	dev; 	ulong	frame;		/* framing errors */	ulong	perror;	ulong	overrun;	/* rcvr overruns */	ulong	crcerr;	ulong	interrupts;	int	baud;		/* baud rate */ 	/* flow control */	int	xonoff;		/* software flow control on */	int	blocked;	int	modem;		/* hardware flow control on */	int	cts;		/* ... cts state */	int	rts;		/* ... rts state */	Rendez	r; 	/* buffers */	int	(*putc)(Queue*, int);	Queue	*iq;	Queue	*oq; 	/* staging areas to avoid some of the per character costs */	/* TO DO: should probably use usual Ring */	Block*	istage[Nbuf];	/* double buffered */	int	rdrx;	/* last buffer read */ 	Lock	plock;		/* for output variables */	Block*	outb;	/* currently transmitting Block */ 	BD*	rxb;	BD*	txb; 	SMC*	smc;	SCC*	scc;	IOCparam*	param;	ushort*	brkcr;	/* brkcr location in appropriate block */	int	brgc;	int	mode;	Block*	partial;	int	loopback;}; static Uart *uart[Nuart];static int nuart; struct Uartalloc {	Lock;	Uart *elist;	/* list of enabled interfaces */} uartalloc; static void uartintr(Uart*, int);static void smcuintr(Ureg*, void*);static void sccuintr(Ureg*, void*); static voiduartsetbuf(Uart *up){	IOCparam *p;	BD *bd;	int i;	Block *bp; 	p = up->param;	p->rfcr = 0x18;	p->tfcr = 0x18;	p->mrblr = Rbufsize; 	if((bd = up->rxb) == nil){		bd = bdalloc(Nbuf);		up->rxb = bd;	}	p->rbase = (ushort)bd;	for(i=0; i<Nbuf; i++){		bd->status = BDEmpty|BDInt;		bd->length = 0;		if((bp = up->istage[i]) == nil)			up->istage[i] = bp = allocb(Bufsize);		bd->addr = PADDR(bp->wp);		dcflush(bp->wp, Bufsize);		bd++;	}	(bd-1)->status |= BDWrap;	up->rdrx = 0; 	if((bd = up->txb) == nil){		bd = bdalloc(1);		up->txb = bd;	}	p->tbase = (ushort)bd;	bd->status = BDWrap|BDInt;	bd->length = 0;	bd->addr = 0;} static voidsmcsetup(Uart *up){	IMM *io;	Uartsmc *p;	SMC *smc;	ulong txrx; 	archdisableuart(up->cpmid);	up->brgc = brgalloc();	if(up->brgc < 0)		error(Eio);	m->iomem->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;	smcnmsi(up->x, up->brgc); 	archenableuart(up->cpmid, 0); 	if(up->x == 1)		txrx = IBIT(24)|IBIT(25);	/* SMC1 RX/TX */	else		txrx = IBIT(20)|IBIT(21);	/* SMC2 */	io = ioplock();	io->pbpar |= txrx;	io->pbdir &= ~txrx;	iopunlock(); 	up->param = up->cpm->param;	uartsetbuf(up); 	cpmop(up->cpm, InitRxTx, 0); 	/* SMC protocol parameters */	p = (Uartsmc*)up->param;	up->brkcr = &p->brkcr;	p->maxidl = 1;	/* non-zero so buffer closes when idle before mrblr reached */	p->brkln = 0;	p->brkec = 0;	p->brkcr = 1;	smc = up->cpm->regs;	smc->smce = 0xff;	/* clear events */	smc->smcm = BSY|RXB|TXB;	/* enable all possible interrupts */	up->smc = smc;	smc->smcmr = ((1+8+1-1)<<11)|(2<<4);	/* 8-bit, 1 stop, no parity; UART mode */	intrenable(VectorCPIC+up->cpm->irq, smcuintr, up, BUSUNKNOWN, up->name);	/* enable when device opened */} static voidsmcuintr(Ureg*, void *a){	Uart *up;	int events; 	up = a;	events = up->smc->smce;	eieio();	up->smc->smce = events;	uartintr(up, events&(BSY|RXB|TXB));} /* * set the IO ports to enable the control signals for SCCx */static voidsccuartpins(int x, int mode){	IMM *io;	int i, w; 	x--;	io = ioplock();	i = 2*x;	w = (TXD1|RXD1)<<i;	/* TXDn and RXDn in port A */	io->papar |= w;	/* enable TXDn and RXDn pins */	io->padir &= ~w;	if((mode & SccIR) == 0)		io->paodr |= TXD1<<i;	else		io->paodr &= ~w;	/* not open drain */ 	w = (CD1|CTS1)<<i;	/* CDn and CTSn in port C */	io->pcpar &= ~w;	io->pcdir &= ~w;	if(conf.nocts2 || mode)		io->pcso &= ~w;	/* force CTS and CD on */	else		io->pcso |= w; 	w = RTS1B<<x;	io->pbpar &= ~w;	io->pbdir &= ~w; 	w = RTS1C<<x;	/* RTSn~ */	if((mode & SccIR) == 0)		io->pcpar |= w;	else		io->pcpar &= ~w;	/* don't use for IR */	iopunlock();} static voidsccsetup(Uart *up){	SCC *scc;	int i; 	scc = up->cpm->regs;	up->scc = scc;	up->param = up->cpm->param;	sccxstop(up->cpm);	archdisableuart(up->cpmid);	if(up->brgc < 0){		up->brgc = brgalloc();		if(up->brgc < 0)			error(Eio);	}	m->iomem->brgc[up->brgc] = baudgen(up->baud, 16) | BaudEnable;	sccnmsi(up->x, up->brgc, up->brgc);	sccuartpins(up->x, up->mode); 	uartsetbuf(up); 	cpmop(up->cpm, InitRxTx, 0); 	/* SCC protocol parameters */	if((up->mode & (SccAHDLC|SccHDLC)) == 0){		Uartscc *sp;		sp = (Uartscc*)up->param;		sp->max_idl = 1;		sp->brkcr = 1;		sp->parec = 0;		sp->frmec = 0;		sp->nosec = 0;		sp->brkec = 0;		sp->brkln = 0;		sp->brkec = 0;		sp->uaddr1 = 0;		sp->uaddr2 = 0;		sp->toseq = 0;		for(i=0; i<8; i++)			sp->character[i] = 0x8000;		sp->rccm = 0xC0FF;		up->brkcr = &sp->brkcr;		scc->irmode = 0;		scc->dsr = ~0;		scc->gsmrh = 1<<5;	/* 8-bit oriented receive fifo */		scc->gsmrl = 0x28004;	/* UART mode */	}else{		UartAHDLC *hp;		hp = (UartAHDLC*)up->param;		hp->c_mask = 0x0000F0B8;		hp->c_pres = 0x0000FFFF;		if(up->mode & SccIR){			hp->bof = 0xC0;			hp->eof = 0xC1;			//scc->dsr = 0xC0C0;			scc->dsr = 0x7E7E;		}else{			hp->bof = 0x7E;			hp->eof = 0x7E;			scc->dsr = 0x7E7E;		}		hp->esc = 0x7D;		hp->zero = 0;		if(up->mode & SccHDLC)			hp->rfthr = 1;		else			hp->rfthr = 0;	/* receive threshold of 1 doesn't work properly for Async HDLC */		hp->txctl_tbl = 0;		hp->rxctl_tbl = 0;		if(up->mode & SccIR){			/* low-speed infrared */			hp->nof = 12-1;	/* 12 flags */			scc->irsip = 0;			scc->irmode = (2<<8) | 1;			archsetirxcvr(0);			if(up->loopback)				scc->irmode = (3<<4)|1;	/* loopback */		}else{			scc->irmode = 0;			hp->txctl_tbl = ~0;			hp->rxctl_tbl = ~0;			hp->nof = 1-1;	/* one opening flag */		}		up->brkcr = nil;		scc->gsmrh = 1<<5;	/* 8-bit oriented receive fifo */		if(up->mode & SccHDLC)			scc->gsmrl = 0x28000;	/* HDLC */		else			scc->gsmrl = 0x28006;	/* async HDLC/IrDA */	}	archenableuart(up->cpmid, (up->mode&SccIR)!=0);	scc->scce = ~0;	/* clear events */	scc->sccm = TXE|BSY|RXF|TXB|RXB;	/* enable all interesting interrupts */	intrenable(VectorCPIC+up->cpm->irq, sccuintr, up, BUSUNKNOWN, up->name);	scc->psmr = 3<<12;	/* 8-bit, 1 stop, no parity; UART mode */	if(up->loopback && (up->mode & SccIR) == 0)		scc->gsmrl |= 1<<6;	/* internal loop back */	scc->gsmrl |= ENT|ENR;	/* enable rx/tx */	if(0){		print("gsmrl=%8.8lux gsmrh=%8.8lux dsr=%4.4ux irmode=%4.4ux\n", scc->gsmrl, scc->gsmrh, scc->dsr, scc->irmode);		for(i=0; i<sizeof(Uartscc); i+=4)			print("%2.2ux %8.8lux\n", i, *(ulong*)((uchar*)up->param+i));	}} static voidsccuintr(Ureg*, void *a){	Uart *up;	int events; 	up = a;	if(up->scc == nil)		return;	events = up->scc->scce;	eieio();	up->scc->scce = events;	if(up->enabled){		if(0)			print("#%ux|", events);		uartintr(up, events);	}} static voiduartsetbaud(Uart *p, int rate){	if(rate <= 0 || p->brgc < 0)

Lines 1–500 of 1450.