Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devns16552.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devns16552.c 1994/0902
## diff -e /dev/null /n/fornaxdump/1994/0902/sys/src/brazil/port/devns16552.c
0a
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"

#include	"devtab.h"
#include	"../port/netif.h"

/*
 *  Driver for the ns16552.
 */
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 */
	Istat=	2,		/* interrupt flag (read) */
	 Fenabd=(3<<6),		/*  on if fifo's enabled */
	Fifoctl=2,		/* fifo control (write) */
	 Fena=	(1<<0),		/*  enable xmit/rcv fifos */
	 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 */
	 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 */
	 Ring=	(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=	32,		/* max per machine */
};

typedef struct Uart Uart;
struct Uart
{
	QLock;

	Uart	*elist;		/* next enabled interface */

	uchar	sticky[8];	/* sticky write register values */
	ulong	port;
	Lock	plock;		/* for printing variable */
	int	printing;	/* true if printing */
	ulong	freq;		/* clock frequency */
	int	opens;
	uchar	mask;		/* bits/char */
	uchar	istat;		/* last istat read */
	uchar	fifoon;		/* fifo's enabled */
	uchar	nofifo;		/* earlier chip version with nofifo */
	int	enabled;
	int	dev;

	int	frame;
	int	overrun;

	/* flow control */
	int	xonoff;		/* software flow control on */
	int	blocked;
	int	modem;		/* hardware flow control on */
	int	cts;
	int	ctsbackoff;
	Rendez	r;

	/* buffers */
	int	(*putc)(Queue*, int);
	Queue	*iq;
	Queue	*oq;

	/* staging areas to avoid some of the per character costs */
	uchar	istage[Stagesize];
	uchar	*ip;
	uchar	*ie;

	uchar	ostage[Stagesize];
	uchar	*op;
	uchar	*oe;
};

static Uart *uart[Nuart];
static int nuart;

static int haveinput;
struct Uartalloc {
	Lock;
	Uart *elist;	/* list of enabled interfaces */
} uartalloc;

void ns16552intr(int);

/*
 *  pick up architecture specific routines and definitions
 */
#include "ns16552.h"

/*
 *  set the baud rate by calculating and setting the baudrate
 *  generator constant.  This will work with fairly non-standard
 *  baud rates.
 */
static void
ns16552setbaud(Uart *p, int rate)
{
	ulong brconst;

	brconst = (p->freq+8*rate-1)/(16*rate);

	uartwrreg(p, Format, Dra);
	outb(p->port + Dmsb, (brconst>>8) & 0xff);
	outb(p->port + Dlsb, brconst & 0xff);
	uartwrreg(p, Format, 0);
}

static void
ns16552parity(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
 */
void
ns16552bits(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
 */
void
ns16552dtr(Uart *p, int n)
{
	if(n)
		p->sticky[Mctl] |= Dtr;
	else
		p->sticky[Mctl] &= ~Dtr;

	uartwrreg(p, Mctl, 0);
}

/*
 *  toggle RTS
 */
void
ns16552rts(Uart *p, int n)
{
	if(n)
		p->sticky[Mctl] |= Rts;
	else
		p->sticky[Mctl] &= ~Rts;

	uartwrreg(p, Mctl, 0);
}

/*
 *  send break
 */
void
ns16552break(Uart *p, int ms)
{
	if(ms == 0)
		ms = 200;

	uartwrreg(p, Format, Break);
	tsleep(&up->sleep, return0, 0, ms);
	uartwrreg(p, Format, 0);
}

void
ns16552fifoon(Uart *p)
{
	ulong i, x, c;

	if(p->nofifo)
		return;

	x = splhi();

	/* empty buffer */
	c = 0;				/* c is to to avoid an unused warning */
	for(i = 0; i < 16; i++)
		c = uartrdreg(p, Data);
	USED(c);
	ns16552intr(p->dev);

	/* turn on fifo */
	p->fifoon = 1;
	uartwrreg(p, Fifoctl, Fena|Ftrig);

	ns16552intr(p->dev);
	USED(c);
	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)
 */
void
ns16552mflow(Uart *p, int n)
{
	if(n){
		p->sticky[Iena] |= Imstat;
		uartwrreg(p, Iena, 0);
		p->modem = 1;
		p->cts = uartrdreg(p, Mstat) & Cts;

		/* turn on fifo's */
		ns16552fifoon(p);
	} else {
		p->sticky[Iena] &= ~Imstat;
		uartwrreg(p, Iena, 0);
		p->modem = 0;
		p->cts = 1;

		/* turn off fifo's */
		p->fifoon = 0;
		uartwrreg(p, Fifoctl, 0);
	}
}

/*
 *  turn on a port's interrupts.  set DTR and RTS
 */
void
ns16552enable(Uart *p)
{
	Uart **l;

	if(p->enabled)
		return;

	uartpower(p->dev, 1);

	/*
 	 *  turn on interrupts
	 */
	p->sticky[Iena] = Ircv | Ixmt | Irstat;
	uartwrreg(p, Iena, 0);

	/*
	 *  turn on DTR and RTS
	 */
	ns16552dtr(p, 1);
	ns16552rts(p, 1);

	/*
	 *  assume we can send
	 */
	p->cts = 1;
	p->blocked = 0;

	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
 */
void
ns16552disable(Uart *p)
{
	Uart **l;

	/*
 	 *  turn off interrpts
	 */
	p->sticky[Iena] = 0;
	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
	 */
	ns16552dtr(p, 0);
	ns16552rts(p, 0);
	ns16552mflow(p, 0);
	p->xonoff = p->blocked = 0;

	uartpower(p->dev, 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 int
stageoutput(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 void
ns16552kick(Uart *p)
{
	int x, n;

	x = splhi();
	lock(&p->plock);
	if(p->printing == 0 || (uartrdreg(p, Lstat) & Outready))
	if(p->cts && p->blocked == 0){
		n = 0;
		while((uartrdreg(p, Lstat) & Outready) == 0){
			if(++n > 10000){
				print("stuck serial line\n");
				break;
			}
		}
		do{
			if(p->op >= p->oe && stageoutput(p) == 0)
				break;
			outb(p->port + Data, *(p->op++));
		}while(uartrdreg(p, Lstat) & Outready);
	}
	unlock(&p->plock);
	splx(x);
}

/*
 *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
 *  transmit and receive enabled, interrupts disabled.
 */
static void
ns16552setup0(Uart *p)
{
	memset(p->sticky, 0, sizeof(p->sticky));
	/*
	 *  set rate to 9600 baud.
	 *  8 bits/character.
	 *  1 stop bit.
	 *  interrpts enabled.
	 */
	p->sticky[Format] = Bits8;
	uartwrreg(p, Format, 0);
	p->sticky[Mctl] |= Inton;
	uartwrreg(p, Mctl, 0x0);

	ns16552setbaud(p, 9600);

	p->iq = qopen(4*1024, 0, 0, 0);
	p->oq = qopen(4*1024, 0, ns16552kick, p);

	p->ip = p->istage;
	p->ie = &p->istage[Stagesize];
	p->op = p->ostage;
	p->oe = p->ostage;
}

/*
 *  called by main() to create a new duart
 */
void
ns16552setup(ulong port, ulong freq)
{
	Uart *p;

	if(nuart >= Nuart)
		return;

	p = xalloc(sizeof(Uart));
	uart[nuart] = p;
	p->dev = nuart;
	nuart++;
	p->port = port;
	p->freq = freq;
	ns16552setup0(p);
}

/*
 *  called by main() to configure a duart port as a console or a mouse
 */
void
ns16552special(int port, int baud, Queue **in, Queue **out, int (*putc)(Queue*, int))
{
	Uart *p = uart[port];

	ns16552enable(p);
	if(baud)
		ns16552setbaud(p, baud);
	p->putc = putc;
	if(in)
		*in = p->iq;
	if(out)
		*out = p->oq;
	p->opens++;
}

/*
 *  handle an interrupt to a single uart
 */
void
ns16552intr(int dev)
{
	uchar ch;
	int s, l, loops;
	Uart *p = uart[dev];

	for(loops = 0;; loops++){
		if(loops > 100000)
			panic("ns16552intr");
		p->istat = s = uartrdreg(p, Istat);
		switch(s&0x3f){
		case 6:	/* receiver line status */
			l = uartrdreg(p, Lstat);
			if(l & Ferror)
				p->frame++;
			if(l & Oerror)
				p->overrun++;
			break;
	
		case 4:	/* received data available */
		case 12:
			ch = uartrdreg(p, Data) & 0xff;
			if(p->xonoff){
				if(ch == CTLS){
					p->blocked = 1;
				}else if (ch == CTLQ){
					p->blocked = 0;
					 /* clock gets output going again */
				}
			}
			if(p->putc)
				(*p->putc)(p->iq, ch);
			else {
				if(p->ip < p->ie)
					*p->ip++ = ch;
				haveinput = 1;
			}
			break;
	
		case 2:	/* transmitter not full */
			lock(&p->plock);
			l = uartrdreg(p, Lstat) & Outready;
			if(l && p->cts && p->blocked == 0)
			if(p->op < p->oe || stageoutput(p)){
				do{
					outb(p->port + Data, *(p->op++));
					if(p->op >= p->oe && stageoutput(p) == 0)
						break;
					l = uartrdreg(p, Lstat) & Outready;
				}while(l);
			}
			if(l)
				p->printing = 0;
			unlock(&p->plock);
			break;
	
		case 0:	/* modem status */
			ch = uartrdreg(p, Mstat);
			if(ch & Ctsc){
				p->cts = ch & Cts; /* clock gets output going again */
				p->ctsbackoff += 1;
			}
			break;
	
		default:
			if(s&1)
				return;
			print("weird modem interrupt #%2.2ux\n", s);
			break;
		}
	}
}

/*
 *  we save up input characters till clock time
 *
 *  There's also a bit of code to get a stalled print going.
 *  It shouldn't happen, but it does.  Obviously I don't
 *  understand interrupts. -- presotto
 */
void
uartclock(void)
{
	int n;
	Uart *p;

	for(p = uartalloc.elist; p; p = p->elist){
		ns16552intr(p->dev);
		if(haveinput){
			n = p->ip - p->istage;
			if(n > 0 && p->iq){
				if(n > Stagesize)
					panic("uartclock");
				if(qproduce(p->iq, p->istage, n) != n)
					;
				p->ip = p->istage;
			}
		}
		if(p->ctsbackoff-- < 0){
			p->ctsbackoff = 0;
			ns16552kick(p);
		}
	}
	haveinput = 0;
}

Dirtab *ns16552dir;

/*
 *  all uarts must be ns16552setup() by this point or inside of ns16552install()
 */
void
ns16552reset(void)
{
	int i;
	Dirtab *dp;

	ns16552install();	/* architecture specific */

	ns16552dir = xalloc(3 * nuart * sizeof(Dirtab));
	dp = ns16552dir;
	for(i = 0; i < nuart; i++){
		/* 3 directory entries per port */
		sprint(dp->name, "eia%d", i);
		dp->qid.path = NETQID(i, Ndataqid);
		dp->perm = 0666;
		dp++;
		sprint(dp->name, "eia%dctl", i);
		dp->qid.path = NETQID(i, Nctlqid);
		dp->perm = 0666;
		dp++;
		sprint(dp->name, "eia%dstat", i);
		dp->qid.path = NETQID(i, Nstatqid);
		dp->perm = 0444;
		dp++;
	}
}

void
ns16552init(void)
{
}

Chan*
ns16552attach(char *spec)
{
	return devattach('t', spec);
}

Chan*
ns16552clone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
ns16552walk(Chan *c, char *name)
{
	return devwalk(c, name, ns16552dir, 3*nuart, devgen);
}

void
ns16552stat(Chan *c, char *dp)
{
	int i;
	Uart *p;
	Dir dir;

	i = NETID(c->qid.path);
	switch(NETTYPE(c->qid.path)){
	case Ndataqid:
		p = uart[i];
		devdir(c, c->qid, ns16552dir[3*i].name, qlen(p->iq), eve, 0660, &dir);
		convD2M(&dir, dp);
		break;
	default:
		devstat(c, dp, ns16552dir, 3*nuart, devgen);
		break;
	}
}

Chan*
ns16552open(Chan *c, int omode)
{
	Uart *p;

	if(c->qid.path & CHDIR){
		if(omode != OREAD)
			error(Ebadarg);
	} else if(NETTYPE(c->qid.path) == Nstatqid){
		;
	} else {
		p = uart[NETID(c->qid.path)];
		qlock(p);
		p->opens++;
		ns16552enable(p);
		qreopen(p->iq);
		qreopen(p->oq);
		qunlock(p);
	}

	c->mode = omode&~OTRUNC;
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

void
ns16552create(Chan *c, char *name, int omode, ulong perm)
{
	USED(c, name, omode, perm);
	error(Eperm);
}

void
ns16552close(Chan *c)
{
	Uart *p;

	if(c->qid.path & CHDIR)
		return;
	if(NETTYPE(c->qid.path) == Nstatqid)
		return;

	p = uart[NETID(c->qid.path)];
	if(c->flag & COPEN){
		qlock(p);
		p->opens--;
		if(p->opens == 0){
			ns16552disable(p);
			qclose(p->iq);
			qclose(p->oq);
			p->ip = p->istage;
		}
		qunlock(p);
	}
}

static long
uartstatus(Chan *c, Uart *p, void *buf, long n, long offset)
{
	uchar mstat;
	uchar tstat;
	char str[256];
	int i;

	str[0] = 0;
	tstat = p->sticky[Mctl];
	mstat = uartrdreg(p, Mstat);
	i = sprint(str, "%d printing %d cts %d qlen %d/%d", NETID(c->qid.path),
		p->printing, p->cts, qlen(p->iq), qlen(p->oq));
	sprint(str+i, " lstat %ux mstat %ux istat %ux ier %ux ferr %d oerr %d",
		uartrdreg(p, Lstat), mstat, uartrdreg(p, Istat), uartrdreg(p, Iena),
		p->frame, p->overrun);
	if(mstat & Cts)
		strcat(str, " cts");
	if(mstat & Dsr)
		strcat(str, " dsr");
	if(mstat & Ring)
		strcat(str, " ring");
	if(mstat & Dcd)
		strcat(str, " dcd");
	if(tstat & Dtr)
		strcat(str, " dtr");
	if(tstat & Rts)
		strcat(str, " rts");
	strcat(str, "\n");
	return readstr(offset, buf, n, str);
}

long
ns16552read(Chan *c, void *buf, long n, ulong offset)
{
	Uart *p;

	if(c->qid.path & CHDIR)
		return devdirread(c, buf, n, ns16552dir, 3*nuart, devgen);

	p = uart[NETID(c->qid.path)];
	switch(NETTYPE(c->qid.path)){
	case Ndataqid:
		return qread(p->iq, buf, n);
	case Nctlqid:
		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
	case Nstatqid:
		return uartstatus(c, p, buf, n, offset);
	}

	return 0;
}

static void
ns16552ctl(Uart *p, char *cmd)
{
	int i, n;

	/* let output drain for a while */
	for(i = 0; i < 16 && qlen(p->oq); i++)
		tsleep(&p->r, qlen, p->oq, 125);

	if(strncmp(cmd, "break", 5) == 0){
		ns16552break(p, 0);
		return;
	}
		

	n = atoi(cmd+1);
	switch(*cmd){
	case 'B':
	case 'b':
		ns16552setbaud(p, n);
		break;
	case 'D':
	case 'd':
		ns16552dtr(p, n);
		break;
	case 'H':
	case 'h':
		qhangup(p->iq);
		qhangup(p->oq);
		break;
	case 'L':
	case 'l':
		ns16552bits(p, n);
		break;
	case 'm':
	case 'M':
		ns16552mflow(p, n);
		break;
	case 'n':
	case 'N':
		qnoblock(p->oq, n);
		break;
	case 'P':
	case 'p':
		ns16552parity(p, *(cmd+1));
		break;
	case 'K':
	case 'k':
		ns16552break(p, n);
		break;
	case 'R':
	case 'r':
		ns16552rts(p, n);
		break;
	case 'Q':
	case 'q':
		qsetlimit(p->iq, n);
		qsetlimit(p->oq, n);
		break;
	case 'W':
	case 'w':
		/* obsolete */
		break;
	case 'X':
	case 'x':
		p->xonoff = n;
		break;
	}
}

long
ns16552write(Chan *c, void *buf, long n, ulong offset)
{
	Uart *p;
	char cmd[32];

	USED(offset);

	if(c->qid.path & CHDIR)
		error(Eperm);

	p = uart[NETID(c->qid.path)];

	/*
	 *  The fifo's turn themselves off sometimes.
	 *  It must be something I don't understand. -- presotto
	 */
	if((p->istat & Fenabd) == 0 && p->fifoon && p->nofifo == 0)
		ns16552fifoon(p);

	switch(NETTYPE(c->qid.path)){
	case Ndataqid:
		return qwrite(p->oq, buf, n);
	case Nctlqid:
		if(n >= sizeof(cmd))
			n = sizeof(cmd)-1;
		memmove(cmd, buf, n);
		cmd[n] = 0;
		ns16552ctl(p, cmd);
		return n;
	}
}

void
ns16552remove(Chan *c)
{
	USED(c);
	error(Eperm);
}

void
ns16552wstat(Chan *c, char *dp)
{
	USED(c, dp);
	error(Eperm);
}
.
## diffname port/devns16552.c 1994/0908
## diff -e /n/fornaxdump/1994/0902/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/0908/sys/src/brazil/port/devns16552.c
498a
		if(loops > 50000){
			if(shakes++ < 3){
				/* try resetting the interface */
				ns16552shake(p);
				continue;
			}
			print("lstat %ux mstat %ux istat %ux iena %ux ferr %d oerr %d",
				uartrdreg(p, Lstat), uartrdreg(p, Mstat),
				s, uartrdreg(p, Iena), p->frame, p->overrun);
			panic("ns16552intr");
		}
.
496,497d
494a
	shakes = 0;
.
492c
	int s, l, loops, shakes;
.
485a
 *  reset the interface
 */
void
ns16552shake(Uart *p)
{
	int xonoff, modem;

	xonoff = p->xonoff;
	modem = p->modem;
	ns16552disable(p);
	ns16552enable(p);
	p->xonoff = xonoff;
	ns16552mflow(p, modem);
}

/*
.
249,250d
244a
	/* empty buffer and interrupt conditions */
	for(i = 0; i < 16; i++){
		if(uartrdreg(p, Istat))
			;
		if(uartrdreg(p, Data))
			;
	}
  
.
238,243c
	/* reset fifos */
	uartwrreg(p, Fifoctl, Fclear);
.
231c
	ulong i, x;
.
## diffname port/devns16552.c 1994/0927
## diff -e /n/fornaxdump/1994/0908/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/0927/sys/src/brazil/port/devns16552.c
832a
	case 'f':
	case 'F':
		qflush(p->oq);
		break;
.
## diffname port/devns16552.c 1994/0929
## diff -e /n/fornaxdump/1994/0927/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/0929/sys/src/brazil/port/devns16552.c
752a
	qunlock(p);
.
742,751c
	qlock(p);
	p->opens--;
	if(p->opens == 0){
		ns16552disable(p);
		qclose(p->iq);
		qclose(p->oq);
		p->ip = p->istage;
.
739a
	if((c->flag & COPEN) == 0)
		return;
.
610,611c
				qproduce(p->iq, p->istage, n);
.
595c
 *  understand something.  Since it was there, I bundled a
 *  restart after flow control with it to give some histeresis
 *  to the hardware flow control.  This makes compressing
 *  modems happier but will probably bother something else.
 *	 -- presotto
.
516c
		if(loops > 100000){
.
## diffname port/devns16552.c 1994/1017
## diff -e /n/fornaxdump/1994/0929/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1017/sys/src/brazil/port/devns16552.c
928,929c
	Dir d;
	Dirtab *dt;

	if(!iseve())
		error(Eperm);
	if(CHDIR & c->qid.path)
		error(Eperm);
	if(NETTYPE(c->qid.path) == Nstatqid)
		error(Eperm);

	dt = &ns16552dir[3 * NETID(c->qid.path)];
	convM2D(dp, &d);
	d.mode &= 0x666;
	dt[0].perm = dt[1].perm = d.mode;
.
795,796c
	if(c->qid.path & CHDIR){
		setlength(-1);
		return devdirread(c, buf, n, ns16552dir, ndir, devgen);
	}
.
721,723d
706,711c
	c = devopen(c, omode, ns16552dir, ndir, devgen);

	switch(NETTYPE(c->qid.path)){
	case Nctlqid:
	case Ndataqid:
.
684,698c
	if(NETTYPE(c->qid.path) == Ndataqid)
		setlength(NETID(c->qid.path));
	devstat(c, dp, ns16552dir, ndir, devgen);
.
678c
	return devwalk(c, name, ns16552dir, ndir, devgen);
.
649c
		dp->perm = 0660;
.
645c
		dp->perm = 0660;
.
639c
	ndir = 3*nuart;
	ns16552dir = xalloc(ndir * sizeof(Dirtab));
.
627a
static void
setlength(int i)
{
	Uart *p;

	if(i > 0){
		p = uart[i];
		if(p && p->opens && p->iq)
			ns16552dir[3*i].length = qlen(p->iq);
	} else for(i = 0; i < nuart; i++){
		p = uart[i];
		if(p && p->opens && p->iq)
			ns16552dir[3*i].length = qlen(p->iq);
	}
		
}

.
626a
int ndir;
.
## diffname port/devns16552.c 1994/1018
## diff -e /n/fornaxdump/1994/1017/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1018/sys/src/brazil/port/devns16552.c
945c
	d.mode &= 0666;
.
## diffname port/devns16552.c 1994/1025
## diff -e /n/fornaxdump/1994/1018/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1025/sys/src/brazil/port/devns16552.c
403c
			if(++n > 100000){
.
## diffname port/devns16552.c 1994/1108
## diff -e /n/fornaxdump/1994/1025/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1108/sys/src/brazil/port/devns16552.c
670c
		sprint(dp->name, "%sstat", uart[i]->name);
.
666c
		sprint(dp->name, "%sctl", uart[i]->name);
.
662c
		strcpy(dp->name, uart[i]->name);
.
460a
	strcpy(p->name, name);
.
452c
ns16552setup(ulong port, ulong freq, char *name)
.
77a
	char	name[NAMELEN];
.
## diffname port/devns16552.c 1994/1117
## diff -e /n/fornaxdump/1994/1108/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1117/sys/src/brazil/port/devns16552.c
616,617c
				if(qproduce(p->iq, p->istage, n) < 0)
					ns16552rts(p, 0);
				else
					p->ip = p->istage;
.
440c
	p->iq = qopen(4*1024, 0, ns16552flow, p);
.
419a
 *  restart input if its off
 */
static void
ns16552flow(Uart *p)
{
	if(p->modem){
		ns16552rts(p, 1);
		haveinput = 1;
	}
}

/*
.
311a
	ns16552setbaud(p, 9600);
.
212a
	p->rts = n;

	unlock(&p->plock);
	splx(x);
.
206a
	int x;

	x = splhi();
	lock(&p->plock);

.
101a
	int	rts;		/* ... rts state */
.
100c
	int	cts;		/* ... cts state */
.
## diffname port/devns16552.c 1994/1118
## diff -e /n/fornaxdump/1994/1117/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1118/sys/src/brazil/port/devns16552.c
785d
775,783c
	switch(NETTYPE(c->qid.path)){
	case Ndataqid:
	case Nctlqid:
		p = uart[NETID(c->qid.path)];
		qlock(p);
		if(--(p->opens) == 0){
			ns16552disable(p);
			qclose(p->iq);
			qclose(p->oq);
			p->ip = p->istage;
		}
		qunlock(p);
		break;
.
771,772d
751a
		break;
.
747,750c
		if(p->opens++ == 0){
			ns16552enable(p);
			qreopen(p->iq);
			qreopen(p->oq);
		}
.
541,546c
		if(loops > 10000000){
.
538d
535c
	int s, l, loops;
.
322d
## diffname port/devns16552.c 1994/1121
## diff -e /n/fornaxdump/1994/1118/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1121/sys/src/brazil/port/devns16552.c
795,799c
	sprint(str, "ferr %d oerr %d baud %d", p->frame, p->overrun, p->baud);
.
791a
	USED(c);

.
790d
151a

	p->baud = rate;
.
93,94c
	int	frame;		/* framing errors */
	int	overrun;	/* rcvr overruns */
	int	baud;		/* baud rate */
.
## diffname port/devns16552.c 1994/1122
## diff -e /n/fornaxdump/1994/1121/sys/src/brazil/port/devns16552.c /n/fornaxdump/1994/1122/sys/src/brazil/port/devns16552.c
799c
	sprint(str, "opens %d ferr %d oerr %d baud %d", p->opens,
		p->frame, p->overrun, p->baud);
.
## diffname port/devns16552.c 1995/0108
## diff -e /n/fornaxdump/1994/1122/sys/src/brazil/port/devns16552.c /n/fornaxdump/1995/0108/sys/src/brazil/port/devns16552.c
944a
}

long
ns16552bwrite(Chan *c, Block *bp, ulong offset)
{
	return devbwrite(c, bp, offset);
.
839a
Block*
ns16552bread(Chan *c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

.
## diffname port/devns16552.c 1995/0205
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/port/devns16552.c /n/fornaxdump/1995/0205/sys/src/brazil/port/devns16552.c
146a
	if(rate <= 0)
		return;

.
## diffname port/devns16552.c 1995/0329
## diff -e /n/fornaxdump/1995/0205/sys/src/brazil/port/devns16552.c /n/fornaxdump/1995/0329/sys/src/brazil/port/devns16552.c
815a
{
int i, j;

i = strlen(str);
for(j = 0; j < 8; j++) i+=sprint(str+i, " %ux", uartrdreg(p, j));
}
.
428d
425a
			outb(p->port + Data, *(p->op++));
.
417c
	if(p->cts && p->blocked == 0)
	if(p->op < p->oe || stageoutput(p)){
.
## diffname port/devns16552.c 1995/0330
## diff -e /n/fornaxdump/1995/0329/sys/src/brazil/port/devns16552.c /n/fornaxdump/1995/0330/sys/src/brazil/port/devns16552.c
334a
	/*
	 *  set baud rate to the last used
	 */
	ns16552setbaud(p, p->baud);

.
## diffname port/devns16552.c 1995/0804
## diff -e /n/fornaxdump/1995/0330/sys/src/brazil/port/devns16552.c /n/fornaxdump/1995/0804/sys/src/brazil/port/devns16552.c
977d
975c
ns16552remove(Chan*)
.
941,942d
936c
ns16552write(Chan *c, void *buf, long n, ulong)
.
803,804d
797c
uartstatus(Chan*, Uart *p, void *buf, long n, long offset)
.
767d
765c
ns16552create(Chan*, char*, int, ulong)
.
## diffname port/devns16552.c 1996/0111
## diff -e /n/fornaxdump/1995/0804/sys/src/brazil/port/devns16552.c /n/fornaxdump/1996/0111/sys/src/brazil/port/devns16552.c
465c
	 *  interrupts enabled.
.
362c
 	 *  turn off interrupts
.
## diffname port/devns16552.c 1996/0117
## diff -e /n/fornaxdump/1996/0111/sys/src/brazil/port/devns16552.c /n/fornaxdump/1996/0117/sys/src/brazil/port/devns16552.c
442c
 *  restart input if it's off
.
## diffname port/devns16552.c 1996/01171
## diff -e /n/fornaxdump/1996/0117/sys/src/brazil/port/devns16552.c /n/fornaxdump/1996/01171/sys/src/brazil/port/devns16552.c
650,652c

		/* this adds histeresis to hardware flow control */
		if(p->ctsbackoff){
			if(--(p->ctsbackoff) == 0)
				ns16552kick(p);
.
638c
		/* this amortizes cost of qproduce to many chars */
.
606,607c
				l = p->cts;
				p->cts = ch & Cts;
				if(l == 0 && p->cts)
					p->ctsbackoff = 2; /* clock gets output going again */
.
598,599d
421c
	if((uartrdreg(p, Lstat) & Outready))
.
83d
## diffname port/devns16552.c 1996/0119
## diff -e /n/fornaxdump/1996/01171/sys/src/brazil/port/devns16552.c /n/fornaxdump/1996/0119/sys/src/brazil/port/devns16552.c
650c
		/* this adds hysteresis to hardware flow control */
.
625c
 *  restart after flow control with it to give some hysteresis
.
## diffname port/devns16552.c 1996/0223
## diff -e /n/fornaxdump/1996/0119/sys/src/brazil/port/devns16552.c /n/fornaxdump/1996/0223/sys/src/brazil/port/devns16552.c
9d
## diffname port/devns16552.c 1996/0608
## diff -e /n/fornaxdump/1996/0223/sys/src/brazil/port/devns16552.c /n/fornaxdump/1996/0608/sys/src/brazil/port/devns16552.c
948a
	unlock(&p->flock);
.
946a
	lock(&p->flock);
.
858c
void
.
795c
long
.
675d
655d
653a
		unlock(&p->tlock);
.
652c
				ns16552kick0(p);
.
649a
		lock(&p->tlock);
.
647a
		unlock(&p->rlock);
.
646a
			p->haveinput = 0;
.
637c
		lock(&p->rlock);
		if(p->haveinput){
.
635a

.
605a
				unlock(&p->tlock);
.
601a
				lock(&p->tlock);
.
585,596c
			ns16552kick(p);
.
580c
				p->haveinput = 1;
				unlock(&p->rlock);
.
577a
				lock(&p->rlock);
.
574a
			unlock(&p->tlock);
.
566a
			lock(&p->tlock);
.
522,537d
447c
		ilock(&p->rlock);
		p->haveinput = 1;
		iunlock(&p->rlock);
.
438a
static void
ns16552kick(Uart *p)
{
	ilock(&p->tlock);
	ns16552kick0(p);
	iunlock(&p->tlock);
}

.
435,436d
415,433c
	if(p->cts == 0 || p->blocked)
		return;
	while(uartrdreg(p, Lstat) & Outready){
		if(p->op >= p->oe && stageoutput(p) == 0)
			break;
		outb(p->port + Data, *(p->op++));
.
413c
ns16552kick0(Uart *p)
.
377c
	ilock(&p->tlock);
	p->blocked = 0;
	iunlock(&p->tlock);
	p->xonoff = 0;
.
354c
static void
.
331a
	iunlock(&p->tlock);
.
329a
	ilock(&p->tlock);
.
305c
static void
.
299a
	iunlock(&p->flock);
.
295a
	ilock(&p->flock);
	if(n)
		/* turn on fifo's */
		ns16552fifoon(p);
	else {
.
294a
		iunlock(&p->tlock);
	}
	iunlock(&p->tlock);
.
287,289d
281a
	ilock(&p->tlock);
.
279c
static void
.
243c
static void
.
232c
static void
.
223,226d
212,216d
122d
116a

	int	modem;			/* hardware flow control on */
	int	xonoff;			/* software flow control on */
	int	blocked;
	int	cts;
	int	ctsbackoff;

	Rendez	r;
.
113a
	int	haveinput;

	Lock	tlock;			/* transmit */
.
109c
	Lock	flock;			/* fifo */
	uchar	fifoon;			/* fifo's enabled */
	uchar	nofifo;			/* earlier chip version with nofifo */

	Lock	rlock;			/* receive */
.
95,103d
91,93c
	uchar	istat;			/* last istat read */
	int	frame;			/* framing errors */
	int	overrun;		/* rcvr overruns */
.
89a
	int	baud;			/* baud rate */
.
81,88c
	ulong	freq;			/* clock frequency */
	uchar	mask;			/* bits/char */
.
79c
	uchar	sticky[8];		/* sticky write register values */
.
76c
	int	enabled;
	Uart	*elist;			/* next enabled interface */
.
74a
	int	opens;
.
## diffname port/devns16552.c 1997/0327
## diff -e /n/fornaxdump/1996/0608/sys/src/brazil/port/devns16552.c /n/emeliedump/1997/0327/sys/src/brazil/port/devns16552.c
977a

Dev ns16552devtab = {
	ns16552reset,
	devinit,
	ns16552attach,
	devclone,
	ns16552walk,
	ns16552stat,
	ns16552open,
	devcreate,
	ns16552close,
	ns16552read,
	devbread,
	ns16552write,
	devbwrite,
	devremove,
	ns16552wstat,
};
.
948,960c
static void
.
915c
static long
.
910a
		iunlock(&p->tlock);
.
909a
		ilock(&p->tlock);
.
872,873c
		qhangup(p->iq, 0);
		qhangup(p->oq, 0);
.
835,841c
static void
.
812c
static long
.
778c
static long
.
747,753c
static void
.
723c
static Chan*
.
715c
static void
.
703,709c
static int
.
692,697c
static Chan*
.
664c
static void
.
562c
				p->putc(p->iq, ch);
.
382d
380c
	p->xonoff = p->blocked = 0;
.
286d
## diffname port/devns16552.c 1997/0408
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/port/devns16552.c /n/emeliedump/1997/0408/sys/src/brazil/port/devns16552.c
944a
	't',
	"ns16552",

.
## diffname port/devns16552.c 1997/0814
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/port/devns16552.c /n/emeliedump/1997/0814/sys/src/brazil/port/devns16552.c
636d
633,634c
			lock(&p->tlock);
			if(p->ctsbackoff){
				if(--(p->ctsbackoff) == 0)
					ns16552kick0(p);
			}
			unlock(&p->tlock);
.
631d
628d
626c
			unlock(&p->rlock);
.
617,624c
			lock(&p->rlock);
			if(p->haveinput){
				n = p->ip - p->istage;
				if(n > 0 && p->iq){
					if(n > Stagesize)
						panic("uartclock");
					if(qproduce(p->iq, p->istage, n) < 0)
						ns16552rts(p, 0);
					else
						p->ip = p->istage;
				}
				p->haveinput = 0;
.
615d
420c

	/*
	 *  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;
.
417a
	int i;

.
## diffname port/devns16552.c 1997/1105
## diff -e /n/emeliedump/1997/0814/sys/src/brazil/port/devns16552.c /n/emeliedump/1997/1105/sys/src/brazil/port/devns16552.c
482a
	if(p->iq == nil || p->oq == nil)
		panic("ns16552setup0");
.
## diffname port/devns16552.c 1998/0319
## diff -e /n/emeliedump/1997/1105/sys/src/brazil/port/devns16552.c /n/emeliedump/1998/0319/sys/src/brazil/port/devns16552.c
910c
ns16552write(Chan *c, void *buf, long n, vlong)
.
813a
	ulong offset = off;
.
811c
ns16552read(Chan *c, void *buf, long n, vlong off)
.
## diffname port/devns16552.c 1998/0331
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/port/devns16552.c /n/emeliedump/1998/0331/sys/src/brazil/port/devns16552.c
652c
			iunlock(&p->tlock);
.
647c
			ilock(&p->tlock);
.
642c
			iunlock(&p->rlock);
.
629c
			ilock(&p->rlock);
.
595c
				iunlock(&p->tlock);
.
590c
				ilock(&p->tlock);
.
579c
				iunlock(&p->rlock);
.
575c
				ilock(&p->rlock);
.
571c
			iunlock(&p->tlock);
.
562c
			ilock(&p->tlock);
.
## diffname port/devns16552.c 1998/0512
## diff -e /n/emeliedump/1998/0331/sys/src/brazil/port/devns16552.c /n/emeliedump/1998/0512/sys/src/brazil/port/devns16552.c
847c

.
598c

.
586c

.
582c

.
558c

.
265c

.
256c

.
## diffname port/devns16552.c 1999/0315
## diff -e /n/emeliedump/1998/0512/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0315/sys/src/brazil/port/devns16552.c
857a
		break;
	case 'E':
	case 'e':
		ns16552dsrhup(p, n);
.
854a
	case 'C':
	case 'c':
		ns16552dcdhup(p, n);
		break;
.
803,806c
		p->baud,
		p->hup_dcd, 
		(tstat & Dtr) != 0,
		p->hup_dsr,
		(fstat & Bits8) + 5,
		(istat & Imstat) != 0, 
		(fstat & Pena) ? ((fstat & Peven) ? 'e' : 'o') : 'n',
		(tstat & Rts) != 0,
		(fstat & Stop2) ? 2 : 1,

		p->dev,
		p->frame,
		p->overrun, 
		p->fifoon       ? " fifo" : "",
		(mstat & Cts)    ? " cts"  : "",
		(mstat & Dsr)    ? " dsr"  : "",
		(mstat & Dcd)    ? " dcd"  : "",
		(mstat & Ring)   ? " ring" : ""
	);
.
786,801c
	istat = p->sticky[Iena];
	fstat = p->sticky[Format];
	snprint(str, sizeof str,
		"b%d c%d d%d e%d l%d m%d p%c r%d s%d\n"
		"%d %d %d%s%s%s%s%s\n",
.
779,780c
	uchar mstat, fstat, istat, tstat;
.
769a
			p->dcd = p->dsr = p->dohup = 0;
.
643a
		if(p->dohup){
			ilock(&p->rlock);
			if(p->dohup){
				qhangup(p->iq, 0);
				qhangup(p->oq, 0);
			}
			p->dohup = 0;
			iunlock(&p->rlock);
		}
.
596a
	 		if (ch & Dsrc) {
				l = ch & Dsr;
				if(p->hup_dsr && p->dsr && !l){
					ilock(&p->rlock);
					p->dohup = 1;
					iunlock(&p->rlock);
				}
				p->dsr = l;
			}
	 		if (ch & Dcdc) {
				l = ch & Dcd;
				if(p->hup_dcd && p->dcd && !l){
					ilock(&p->rlock);
					p->dohup = 1;
					iunlock(&p->rlock);
				}
				p->dcd = l;
			}
.
313a
	p->hup_dsr = p->hup_dcd = 0;
	p->cts = p->dsr = p->dcd = 0;

.
160a
ns16552dsrhup(Uart *p, int n)
{
	p->hup_dsr = n;
}

static void
ns16552dcdhup(Uart *p, int n)
{
	p->hup_dcd = n;
}

static void
.
159a
/*
 * decide if we should hangup when dsr or dcd drops.
 */
.
117a
	int	hup_dsr, hup_dcd;	/* send hangup upstream? */
	int	dohup;
.
116c
	int	cts, dsr, dcd;		/* keep track of modem status */ 
.
## diffname port/devns16552.c 1999/0320
## diff -e /n/emeliedump/1999/0315/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0320/sys/src/brazil/port/devns16552.c
892c
		tsleep(&p->r, (int(*)(void*))qlen, p->oq, 125);
.
471a
	Uart *p;

	p = v;
.
470c
ns16552flow(void *v)
.
460a
	Uart *p;

	p = v;
.
459c
ns16552kick(void *v)
.
439a
	p = v;
.
438a
	Uart *p;
.
436c
ns16552kick0(void *v)
.
## diffname port/devns16552.c 1999/0513
## diff -e /n/emeliedump/1999/0320/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0513/sys/src/brazil/port/devns16552.c
993c
	if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550)
.
537a
	p->type = type;
.
524c
ns16552setup(ulong port, ulong freq, char *name, int type)
.
299,301c
		if(p->type == Ns650){
			outb(p->port + Format, 0xbf);
			outb(p->port + Efr, Eena|Arts|Acts);
			uartwrreg(p, Format, 0);
		} else {
			p->sticky[Iena] &= ~Imstat;
			uartwrreg(p, Iena, 0);
			p->modem = 0;
		}
.
294,297c
print("mflow type %d\n", p->type);
		if(p->type == Ns650){
			outb(p->port + Format, 0xbf);
			outb(p->port + Efr, Eena|Arts|Acts);
			uartwrreg(p, Format, 0);
			p->cts = 1;
		} else {
			p->sticky[Iena] |= Imstat;
			uartwrreg(p, Iena, 0);
			p->modem = 1;
			p->cts = uartrdreg(p, Mstat) & Cts;
		}
.
291a


.
280c
		p->type = Ns450;
.
276c
	if(p->type == Ns650)
		uartwrreg(p, Fifoctl, Fena|Ftrig24);
	else
		uartwrreg(p, Fifoctl, Fena|Ftrig4);
.
258c
	if(p->type < Ns550)
.
210d
99c
	uchar	type;			/* chip version */
.
82c
	ulong	port;			/* io ports */
.
68a

	Ns450=	0,
	Ns550,
	Ns650,
.
62a
	Efr=	2,		/* enhanced features for 16C650 */
	 Eena=	(1<<4),		/* enable enhanced bits in normal registers */
	 Arts=	(1<<6),		/* auto rts */
	 Acts=	(1<<7),		/* auto cts */
.
44a
	 Intsel=(1<<5),		/*  NO! open source interrupts; 16C650 */
	 Irda=	(1<<6),		/*  infrared interface; 16C650 */
	 Cdiv=	(1<<7),		/*  divide clock by four; 16C650 */
.
38a
	 Ers=	0xbf,		/*  enable enhaced register set on 16C650 */
.
29c
	 Ftrig4=	(1<<6),		/*  trigger after 4 input characters */
	 Ftrig24=	(2<<6),		/*  trigger after 24 input characters */
.
26a
	 Irctsd=(1<<4),		/*  auto rts or cts changed state */
.
24a
	 Isleep=(1<<4),		/*  put in sleep mode; 16C650 */
	 Ixoff=	(1<<5),		/*  for xoff received; 16C650 */
	 Irts=	(1<<6),		/*  for !rts asserted in auto mode; 16C650 */
	 Icts=	(1<<7),		/*  for !cts asserted in auto mode; 16C650 */
.
## diffname port/devns16552.c 1999/0514
## diff -e /n/emeliedump/1999/0513/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0514/sys/src/brazil/port/devns16552.c
316d
## diffname port/devns16552.c 1999/0601
## diff -e /n/emeliedump/1999/0514/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0601/sys/src/brazil/port/devns16552.c
998a
		break;
	case 'T':
	case 't':
		ns16552dcdts(p, n);
.
671a
				if(l == 0 && p->dcd != 0 && p->dcdts)
					savets();
.
256a
 *  save dcd timestamps for gps clock
 */
static void
ns16552dcdts(Uart *p, int n)
{
	p->dcdts = n;
}

/*
.
151a
/* interrupt timestamps, l.s fills intrts each interupt */
uvlong	intrts;
static	struct {
	Lock;
	int	vno;		/* vector to save timestamps for */
	int	n;		/* number of valid timestamps in ts[] */
	uvlong	ts[128];	/* time stamps */
} tsalloc;

/* called with interrupts off by interrupt routine */
static void
savets(void)
{
	lock(&tsalloc);
	if(tsalloc.n < nelem(tsalloc.ts))
		tsalloc.ts[tsalloc.n++] = intrts;
	unlock(&tsalloc);
}

/* read interrupt timestamps */
long
readintrts(void *buf, int n)
{
	n /= sizeof(uvlong);
	if(n <= 0)
		return 0;
	ilock(&tsalloc);
	if(n > tsalloc.n)
		n = tsalloc.n;
	memmove(buf, tsalloc.ts, n*sizeof(uvlong));
	tsalloc.n = 0;
	iunlock(&tsalloc);
	return n*sizeof(uvlong);
}

.
134c
	int	cts, dsr, dcd, dcdts;		/* keep track of modem status */ 
.
## diffname port/devns16552.c 1999/0701
## diff -e /n/emeliedump/1999/0601/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0701/sys/src/brazil/port/devns16552.c
716,717c
				if(l == 0 && p->dcd != 0 && p->dcdts && saveintrts != nil)
					(*saveintrts)();
.
152,186d
## diffname port/devns16552.c 1999/0711
## diff -e /n/emeliedump/1999/0701/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0711/sys/src/brazil/port/devns16552.c
747c
		/* this adds hysteresis to hardware/software flow control */
.
683,687c
				if(p->hup_dcd && p->dcd && !l)
					p->dohup = 1;	 /* clock peforms hangup */
.
672,676c
				if(p->hup_dsr && p->dsr && !l)
					p->dohup = 1;	 /* clock peforms hangup */
.
668d
663d
644d
641c
					p->ctsbackoff = 2; /* clock gets output going again */
.
635d
## diffname port/devns16552.c 1999/0820
## diff -e /n/emeliedump/1999/0711/sys/src/brazil/port/devns16552.c /n/emeliedump/1999/0820/sys/src/brazil/port/devns16552.c
1089a

/*
 * Polling I/O routines for kernel debugging helps.
 */
static void
ns16552setuppoll(Uart *p, int rate)
{
	ulong brconst;

	/*
	 * 8 bits/character, 1 stop bit;
	 * set rate to rate baud;
	 * turn on Rts and Dtr.
	 */
	memmove(p->osticky, p->sticky, sizeof p->osticky);
	
	p->sticky[Format] = Bits8;
	uartwrreg(p, Format, 0);

	brconst = (UartFREQ+8*rate-1)/(16*rate);
	uartwrreg(p, Format, Dra);
	outb(p->port+Dmsb, (brconst>>8) & 0xff);
	outb(p->port+Dlsb, brconst & 0xff);
	uartwrreg(p, Format, 0);

	p->sticky[Mctl] = Rts|Dtr;
	uartwrreg(p, Mctl, 0);

	p->kinuse = 1;
}

/*
 * Restore serial state from before kernel took over.
 */
static void
ns16552restore(Uart *p)
{
	ulong brconst;

	memmove(p->sticky, p->osticky, sizeof p->sticky);
	uartwrreg(p, Format, 0);

	brconst = (UartFREQ+8*p->baud-1)/(16*p->baud);
	uartwrreg(p, Format, Dra);
	outb(p->port+Dmsb, (brconst>>8) & 0xff);
	outb(p->port+Dlsb, brconst & 0xff);
	uartwrreg(p, Format, 0);

	uartwrreg(p, Mctl, 0);
	p->kinuse = 0;
}

/* BUG should be configurable */
enum {
	WHICH = 0,
	RATE = 9600,
};

int
serialgetc(void)
{
	Uart *p;
	int c;

	if((p=uart[WHICH]) == nil)
		return -1;
	if(!p->kinuse)
		ns16552setuppoll(p, RATE);

	while((uartrdreg(p, Lstat)&Inready) == 0)
		;
	c = inb(p->port+Data) & 0xFF;
	return c;
	// there should be a restore here but i think it will slow things down too much.
}

static void
serialputc(Uart *p, int c)
{
	while((uartrdreg(p, Lstat)&Outready) == 0)
		;
	outb(p->port+Data, c);
	while((uartrdreg(p, Lstat)&Outready) == 0)
		;
}

void
serialputs(char *s, int n)
{
	Uart *p;

	if((p=uart[WHICH]) == nil)
		return;
	if(!p->kinuse)
		ns16552setuppoll(p, RATE);

	while(n-- > 0){
		serialputc(p, *s);
		if(*s == '\n')
			serialputc(p, '\r');
		s++;
	}
	ns16552restore(p);
}
.
1027a
	if(p->kinuse)
		error(Ekinuse);
.
917a
	if(p->kinuse)
		error(Ekinuse);
.
855a
		if(p->kinuse)
			error(Ekinuse);
.
829a
		if(p->kinuse)
			error(Ekinuse);
.
322d
152a
 * means the kernel is using this for debugging output
 */
static char	Ekinuse[] = "device in use by kernel";

/*
.
138a
	int	kinuse;		/* device in use by kernel */

.
99a
	uchar	osticky[8];		/* kernel saved sticky write register values */
.
## diffname port/devns16552.c 2000/0614
## diff -e /n/emeliedump/1999/0820/sys/src/brazil/port/devns16552.c /n/emeliedump/2000/0614/sys/src/9/port/devns16552.c
905a
		p->type,
.
893c
		"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s%s\n",
.
314a
	/* fix from Scott Schwartz <schwartz@bio.cse.psu.edu> */
 	p->istat = uartrdreg(p, Istat); 
.
## diffname port/devns16552.c 2000/0708
## diff -e /n/emeliedump/2000/0614/sys/src/9/port/devns16552.c /n/emeliedump/2000/0708/sys/src/9/port/devns16552.c
1051,1054c
	if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550){
		lock(&p->flock);
		if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550)
			ns16552fifo(p, 1);
		unlock(&p->flock);
	}
.
987a
	case 'i':
	case 'I':
		lock(&p->flock);
		ns16552fifo(p, n);
		unlock(&p->flock);
		break;
.
359,368c
	/* modem needs fifo */
	lock(&p->flock);
	ns16552fifo(p, n);
	unlock(&p->flock);
.
321d
296a
	if(n == 0){
		/* turn off fifo's */
		p->fifoon = 0;
		uartwrreg(p, Fifoctl, 0);
		splx(x);
		return;
	}

.
290c
	ulong i;
	int x;
.
288c
ns16552fifo(Uart *p, int n)
.
286a
/*
 *  always called under lock(&p->flock)
 */
.
## diffname port/devns16552.c 2000/0709
## diff -e /n/emeliedump/2000/0708/sys/src/9/port/devns16552.c /n/emeliedump/2000/0709/sys/src/9/port/devns16552.c
966,1041c
		if(strncmp(f[i], "break", 5) == 0){
			ns16552break(p, 0);
			continue;
		}

		n = atoi(f[i]+1);
		switch(*f[i]){
		case 'B':
		case 'b':
			ns16552setbaud(p, n);
			break;
		case 'C':
		case 'c':
			ns16552dcdhup(p, n);
			break;
		case 'D':
		case 'd':
			ns16552dtr(p, n);
			break;
		case 'E':
		case 'e':
			ns16552dsrhup(p, n);
			break;
		case 'f':
		case 'F':
			qflush(p->oq);
			break;
		case 'H':
		case 'h':
			qhangup(p->iq, 0);
			qhangup(p->oq, 0);
			break;
		case 'i':
		case 'I':
			lock(&p->flock);
			ns16552fifo(p, n);
			unlock(&p->flock);
			break;
		case 'L':
		case 'l':
			ns16552bits(p, n);
			break;
		case 'm':
		case 'M':
			ns16552mflow(p, n);
			break;
		case 'n':
		case 'N':
			qnoblock(p->oq, n);
			break;
		case 'P':
		case 'p':
			ns16552parity(p, *(cmd+1));
			break;
		case 'K':
		case 'k':
			ns16552break(p, n);
			break;
		case 'R':
		case 'r':
			ns16552rts(p, n);
			break;
		case 'Q':
		case 'q':
			qsetlimit(p->iq, n);
			qsetlimit(p->oq, n);
			break;
		case 'T':
		case 't':
			ns16552dcdts(p, n);
			break;
		case 'W':
		case 'w':
			/* obsolete */
			break;
		case 'X':
		case 'x':
			ilock(&p->tlock);
			p->xonoff = n;
			iunlock(&p->tlock);
			break;
		}
.
964a
	for(i = 0; i < nf; i++){
.
960,963c
	nf = getfields(cmd, f, nelem(f), 1, " \t\n");
.
954a
	char *f[32];
	int nf;
.
916d
910a
		p->fifoon,
.
899,900c
		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
		"dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
.
## diffname port/devns16552.c 2001/0518
## diff -e /n/emeliedump/2000/0709/sys/src/9/port/devns16552.c /n/emeliedump/2001/0518/sys/src/9/port/devns16552.c
314,317c
		uartrdreg(p, Istat);
		uartrdreg(p, Data);
.
## diffname port/devns16552.c 2001/0527 # deleted
## diff -e /n/emeliedump/2001/0518/sys/src/9/port/devns16552.c /n/emeliedump/2001/0527/sys/src/9/port/devns16552.c
1,1228d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.