forsyth20121205-174063a80cc13 years agoHistory
1070 lines · 18.9 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" /* *  Driver for the uart. *	TO DO: replace by uartpxa.c */enum{	/*	 *  register numbers	 */	Data=	0,		/* xmit/rcv buffer */	Iena=	1,		/* interrupt enable */	 Ircv=	(1<<0),		/*  for char rcv'd */	 Ixmt=	(1<<1),		/*  for xmit buffer empty */	 Irstat=(1<<2),		/*  for change in rcv'er status */	 Imstat=(1<<3),		/*  for change in modem status */	 Rtoie=	1<<4,	/* character timeout indication */	 Nrze=	1<<5,	/* NRZ encoding enabled */	 Uue=	1<<6,	/* Uart unit enabled */	 Dmae=	1<<7,	/* DMA requests enabled */	Istat=	2,		/* interrupt flag (read) */	 Ipend=	1,		/* interrupt pending (not) */	 Fenabd=(3<<6),   		/*  on if fifo's enabled */	Fifoctl=2,		/* fifo control (write) */	 Fena=	(1<<0),		/*  enable xmit/rcv fifos */	 Fdma=	(1<<3),		/* dma on */	 Ftrig=	(1<<6),		/*  trigger after 4 input characters */	 Fclear=(3<<1),		/*  clear xmit & rcv fifos */	Format=	3,		/* byte format */	 Bits8=	(3<<0),		/*  8 bits/byte */	 Stop2=	(1<<2),		/*  2 stop bits */	 Pena=	(1<<3),		/*  generate parity */	 Peven=	(1<<4),		/*  even parity */	 Pforce=(1<<5),		/*  force parity */	 Break=	(1<<6),		/*  generate a break */	 Dra=	(1<<7),		/*  address the divisor */	Mctl=	4,		/* modem control */	 Dtr=	(1<<0),		/*  data terminal ready */	 Rts=	(1<<1),		/*  request to send */	 Ri=	(1<<2),		/*  ring */	 Inton=	(1<<3),		/*  turn on interrupts */	 Loop=	(1<<4),		/*  loop back */	Lstat=	5,		/* line status */	 Inready=(1<<0),	/*  receive buffer full */	 Oerror=(1<<1),		/*  receiver overrun */	 Perror=(1<<2),		/*  receiver parity error */	 Ferror=(1<<3),		/*  rcv framing error */	 Berror=(1<<4),		/* break alarm */	 Outready=(1<<5),	/*  output buffer full */	Mstat=	6,		/* modem status */	 Ctsc=	(1<<0),		/*  clear to send changed */	 Dsrc=	(1<<1),		/*  data set ready changed */	 Rire=	(1<<2),		/*  rising edge of ring indicator */	 Dcdc=	(1<<3),		/*  data carrier detect changed */	 Cts=	(1<<4),		/*  complement of clear to send line */	 Dsr=	(1<<5),		/*  complement of data set ready line */	 Ringl=	(1<<6),		/*  complement of ring indicator line */	 Dcd=	(1<<7),		/*  complement of data carrier detect line */	Scratch=7,		/* scratchpad */	Dlsb=	0,		/* divisor lsb */	Dmsb=	1,		/* divisor msb */ 	CTLS= 023,	CTLQ= 021, 	Stagesize= 1024,	Nuart=	4,		/* max per machine */}; typedef struct Uart Uart;struct Uart{	QLock;	int	opens; 	int	enabled;	Uart	*elist;			/* next enabled interface */	char	name[KNAMELEN]; 	ulong	sticky[8];		/* sticky write register values */	void*	regs;	ulong	port;	ulong	freq;			/* clock frequency */	uchar	mask;			/* bits/char */	int	dev;	int	baud;			/* baud rate */ 	uchar	istat;			/* last istat read */	int	frame;			/* framing errors */	int	overrun;		/* rcvr overruns */ 	/* buffers */	int	(*putc)(Queue*, int);	Queue	*iq;	Queue	*oq; 	Lock	flock;			/* fifo */	uchar	fifoon;			/* fifo's enabled */	uchar	nofifo;			/* earlier chip version with nofifo */ 	Lock	rlock;			/* receive */	uchar	istage[Stagesize];	uchar	*ip;	uchar	*ie; 	int	haveinput; 	Lock	tlock;			/* transmit */	uchar	ostage[Stagesize];	uchar	*op;	uchar	*oe; 	int	modem;			/* hardware flow control on */	int	xonoff;			/* software flow control on */	int	blocked;	int	cts, dsr, dcd;		/* keep track of modem status */ 	int	ctsbackoff;	int	hup_dsr, hup_dcd;	/* send hangup upstream? */	int	dohup; 	Rendez	r;}; static Uart *uart[Nuart];static int nuart; struct Uartalloc {	Lock;	Uart *elist;	/* list of enabled interfaces */} uartalloc; static void uartintr(Uart*); /* *  pick up architecture specific routines and definitions */#include "uart.h" /* *  set the baud rate by calculating and setting the baudrate *  generator constant.  This will work with fairly non-standard *  baud rates. */static voiduartsetbaud(Uart *p, int rate){	ulong brconst; 	if(rate <= 0)		return; 	p->freq = archuartclock(p->port, rate);	if(p->freq == 0)		return; 	brconst = (p->freq+8*rate-1)/(16*rate); 	uartwrreg(p, Format, Dra);	uartwr(p, Dmsb, (brconst>>8) & 0xff);	uartwr(p, Dlsb, brconst & 0xff);	uartwrreg(p, Format, 0); 	p->baud = rate;} /* * decide if we should hangup when dsr or dcd drops. */static voiduartdsrhup(Uart *p, int n){	p->hup_dsr = n;} static voiduartdcdhup(Uart *p, int n){	p->hup_dcd = n;} static voiduartparity(Uart *p, char type){	switch(type){	case 'e':		p->sticky[Format] |= Pena|Peven;		break;	case 'o':		p->sticky[Format] &= ~Peven;		p->sticky[Format] |= Pena;		break;	default:		p->sticky[Format] &= ~(Pena|Peven);		break;	}	uartwrreg(p, Format, 0);} /* *  set bits/character, default 8 */voiduartbits(Uart *p, int bits){	if(bits < 5 || bits > 8)		error(Ebadarg); 	p->sticky[Format] &= ~3;	p->sticky[Format] |= bits-5; 	uartwrreg(p, Format, 0);}  /* *  toggle DTR */voiduartdtr(Uart *p, int n){	if(n)		p->sticky[Mctl] |= Dtr;	else		p->sticky[Mctl] &= ~Dtr; 	uartwrreg(p, Mctl, 0);} /* *  toggle RTS */voiduartrts(Uart *p, int n){	if(n)		p->sticky[Mctl] |= Rts;	else		p->sticky[Mctl] &= ~Rts; 	uartwrreg(p, Mctl, 0);} /* *  send break */static voiduartbreak(Uart *p, int ms){	if(ms == 0)		ms = 200; 	uartwrreg(p, Format, Break);	tsleep(&up->sleep, return0, 0, ms);	uartwrreg(p, Format, 0);} static voiduartfifoon(Uart *p){	ulong i, x; 	if(p->nofifo || uartrdreg(p, Istat) & Fenabd)		return; 	x = splhi(); 	/* reset fifos */	p->sticky[Fifoctl] = 0;	uartwrreg(p, Fifoctl, Fclear); 	/* empty buffer and interrupt conditions */	for(i = 0; i < 16; i++){		if(uartrdreg(p, Istat)){			/* nothing to do */		}		if(uartrdreg(p, Data)){			/* nothing to do */		}	} 	/* turn on fifo */	p->fifoon = 1;	p->sticky[Fifoctl] = Fena|Ftrig;	uartwrreg(p, Fifoctl, 0);	p->istat = uartrdreg(p, Istat);	if((p->istat & Fenabd) == 0) {		/* didn't work, must be an earlier chip type */		p->nofifo = 1;	} 	splx(x);} /* *  modem flow control on/off (rts/cts) */static voiduartmflow(Uart *p, int n){	ilock(&p->tlock);	if(n){		p->sticky[Iena] |= Imstat;		uartwrreg(p, Iena, 0);		p->modem = 1;		p->cts = uartrdreg(p, Mstat) & Cts;	} else {		p->sticky[Iena] &= ~Imstat;		uartwrreg(p, Iena, 0);		p->modem = 0;		p->cts = 1;	}	iunlock(&p->tlock); //	ilock(&p->flock);//	if(1)//		/* turn on fifo's *///		uartfifoon(p);//	else {//		/* turn off fifo's *///		p->fifoon = 0;//		p->sticky[Fifoctl] = 0;//		uartwrreg(p, Fifoctl, Fclear);//	}//	iunlock(&p->flock);} /* *  turn on a port's interrupts.  set DTR and RTS */static voiduartenable(Uart *p){	Uart **l; 	if(p->enabled)		return; 	uartportpower(p, 1); 	p->hup_dsr = p->hup_dcd = 0;	p->cts = p->dsr = p->dcd = 0; 	/* 	 *  turn on interrupts	 */	p->sticky[Iena] = Ircv | Ixmt | Irstat | Uue;	uartwrreg(p, Iena, 0); 	/*	 *  turn on DTR and RTS	 */	uartdtr(p, 1);	uartrts(p, 1); 	uartfifoon(p); 	/*	 *  assume we can send	 */	ilock(&p->tlock);	p->cts = 1;	p->blocked = 0;	iunlock(&p->tlock); 	/*	 *  set baud rate to the last used	 */	uartsetbaud(p, p->baud); 	lock(&uartalloc);	for(l = &uartalloc.elist; *l; l = &(*l)->elist){		if(*l == p)			break;	}	if(*l == 0){		p->elist = uartalloc.elist;		uartalloc.elist = p;	}	p->enabled = 1;	unlock(&uartalloc);} /* *  turn off a port's interrupts.  reset DTR and RTS */static voiduartdisable(Uart *p){	Uart **l; 	/* 	 *  turn off interrupts	 */	p->sticky[Iena] = Uue;	uartwrreg(p, Iena, 0); 	/*	 *  revert to default settings	 */	p->sticky[Format] = Bits8;	uartwrreg(p, Format, 0); 	/*	 *  turn off DTR, RTS, hardware flow control & fifo's	 */	uartdtr(p, 0);	uartrts(p, 0);	uartmflow(p, 0);	ilock(&p->tlock);	p->xonoff = p->blocked = 0;	iunlock(&p->tlock); 	uartportpower(p, 0); 	lock(&uartalloc);	for(l = &uartalloc.elist; *l; l = &(*l)->elist){		if(*l == p){			*l = p->elist;			break;		}	}	p->enabled = 0;	unlock(&uartalloc);} /* *  put some bytes into the local queue to avoid calling *  qconsume for every character */static intstageoutput(Uart *p){	int n; 	n = qconsume(p->oq, p->ostage, Stagesize);	if(n <= 0)		return 0;	p->op = p->ostage;	p->oe = p->ostage + n;	return n;} /* *  (re)start output */static voiduartkick0(Uart *p){	int i;	if((p->modem && (p->cts == 0)) || p->blocked)		return; 	/*	 *  128 here is an arbitrary limit to make sure	 *  we don't stay in this loop too long.  If the	 *  chips output queue is longer than 128, too	 *  bad -- presotto	 */	for(i = 0; i < 128; i++){		if(!(uartrdreg(p, Lstat) & Outready))			break;		if(p->op >= p->oe && stageoutput(p) == 0)			break;		uartwr(p, Data, *p->op++);	}} static voiduartkick(void *v){	Uart *p; 	p = v;	ilock(&p->tlock);	uartkick0(p);	iunlock(&p->tlock);} /* *  restart input if it's off */static voiduartflow(void *v){	Uart *p; 	p = v;	if(p->modem)		uartrts(p, 1);	ilock(&p->rlock);	p->haveinput = 1;

Lines 1–500 of 1070.