Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/pc/devuart.c

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


## diffname pc/devuart.c 1991/0801
## diff -e /dev/null /n/bootesdump/1991/0801/sys/src/9/safari/devuart.c
0a
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

#include	"devtab.h"

/*
 *  Driver for an NS16450 serial port
 */
enum
{
	/*
	 *  register numbers
	 */
	Data=	0,		/* xmit/rcv buffer */
	Iena=	1,		/* interrupt enable */
	 Ircv=	(1<<0),		/*  interrupt on receive */
	 Ixmt=	(1<<1),		/*  interrupt on xmit */
	Istat=	2,		/* interrupt flag */
	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 */
	 Dcd=	(1<<3),		/*  carrier */
	 Loop=	(1<<4),		/*  loop bask */
	Lstat=	5,		/* line status */
	 Inready=(1<<0),	/*  receive buffer full */
	 Outbusy=(1<<5),	/*  output buffer full */
	Mstat=	6,		/* modem status */
	Scratch=7,		/* scratchpad */
	Dlsb=	0,		/* divisor lsb */
	Dmsb=	1,		/* divisor msb */
};

typedef struct Uart	Uart;
struct Uart
{
	QLock;
	int	port;
	ushort	sticky[16];	/* sticky write register values */
	int	printing;	/* true if printing */

	/* console interface */
	int	nostream;	/* can't use the stream interface */
	IOQ	*iq;		/* input character queue */
	IOQ	*oq;		/* output character queue */

	/* stream interface */
	Queue	*wq;		/* write queue */
	Rendez	r;		/* kproc waiting for input */
	Alarm	*a;		/* alarm for waking the kernel process */
	int	delay;		/* between character input and waking kproc */
 	int	kstarted;	/* kproc started */
	uchar	delim[256/8];	/* characters that act as delimiters */
};

Uart uart[2];

#define UartFREQ 1846200

#define uartwrreg(u,r,v)	outb(u->port + r, u->sticky[r] | v)
#define uartrdreg(u,r)		inb(u->port + r)

void	uartintr(Uart*);
void	uartintr0(Ureg*);
void	uartintr1(Ureg*);
void	uartsetup(void);

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

	brconst = (UartFREQ+8*rate-1)/16*rate;

	uartwrreg(up, Format, Dra);
	uartwrreg(up, Dmsb, (brconst>>8) & 0xff);
	uartwrreg(up, Dlsb, brconst & 0xff);
	uartwrreg(up, Format, 0);
}

/*
 *  toggle DTR
 */
void
uartdtr(Uart *up, int n)
{
	if(n)
		up->sticky[Mctl] |= Dtr;
	else
		up->sticky[Mctl] &= ~Dtr;
	uartwrreg(up, Mctl, 0);
}

/*
 *  toggle RTS
 */
void
uartrts(Uart *up, int n)
{
	if(n)
		up->sticky[Mctl] |= Rts;
	else
		up->sticky[Mctl] &= ~Rts;
	uartwrreg(up, Mctl, 0);
}

/*
 *  send break
 */
void
uartbreak(Uart *up, int ms)
{
	uartwrreg(up, Format, Break);
	tsleep(&u->p->sleep, return0, 0, ms);
	uartwrreg(up, Format, 0);
}

/*
 *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
 *  transmit and receive enabled, interrupts disabled.
 */
void
uartsetup(void)
{
	Uart *up;
	static int already;

	if(already)
		return;
	already = 1;

	/*
	 *  get port addresses
	 */
	uart[0].port = 0x3F8;
	uart[1].port = 0x2F8;
	setvec(Uart0vec, uartintr0);
	setvec(Uart1vec, uartintr1);

	for(up = uart; up < &uart[2]; up++){
		memset(up->sticky, 0, sizeof(up->sticky));

		/*
		 *  set rate to 9600 baud.
		 *  8 bits/character.
		 *  1 stop bit.
		 */
		uartsetbaud(up, 9600);
		up->sticky[Format] = Bits8;
		uartwrreg(up, Format, 0);
	}
}

/*
 *  Queue n characters for output; if queue is full, we lose characters.
 *  Get the output going if it isn't already.
 */
void
uartputs(IOQ *cq, char *s, int n)
{
	Uart *up = cq->ptr;
	int st, ch, x;

	x = splhi();
	lock(cq);
	puts(cq, s, n);
	if(up->printing == 0){
		ch = getc(cq);
print("<start %2.2ux>", ch);/**/
		if(ch >= 0){
			up->printing = 1;
			while(uartrdreg(up, Lstat) & Outbusy)
				;
			outb(up->port + Data, ch);
		}
	}
	unlock(cq);
	splx(x);
}

/*
 *  a uart interrupt (a damn lot of work for one character)
 */
void
uartintr(Uart *up)
{
	int s;
	int ch;
	IOQ *cq;

	switch(uartrdreg(up, Istat)){
	case 3:
		/*
		 *  get any input characters
		 */
		cq = up->iq;
		while(uartrdreg(up, Lstat) & Inready){
			ch = uartrdreg(up, Data) & 0xff;
			if(cq->putc)
				(*cq->putc)(cq, ch);
			else {
				putc(cq, ch);
				if(up->delim[ch/8] & (1<<(ch&7)) )
					wakeup(&cq->r);
			}
		}
		break;
	case 5:
		/*
		 *  send next output character
		 */
		if((s & Outbusy)==0){
			cq = up->oq;
			lock(cq);
			ch = getc(cq);
			if(ch < 0){
				up->printing = 0;
				wakeup(&cq->r);
			}else
				outb(up->port + Data, ch);
			unlock(cq);
		}
		break;
	}
}
void
uartintr0(Ureg *ur)
{
	uartintr(&uart[0]);
}
void
uartintr1(Ureg *ur)
{
	uartintr(&uart[1]);
}

/*
 *  turn on a port's interrupts.  set DTR and RTS
 */
void
uartenable(Uart *up)
{
	/*
	 *  set up i/o routines
	 */
	if(up->oq){
		up->oq->puts = uartputs;
		up->oq->ptr = up;
		up->sticky[Iena] |= Ixmt;
	}
	if(up->iq){
		up->iq->ptr = up;
		up->sticky[Iena] |= Ircv;
	}

	/*
 	 *  turn on interrupts
	 */
	uartwrreg(up, Iena, 0);

	/*
	 *  turn on DTR and RTS
	 */
	uartdtr(up, 1);
	uartrts(up, 1);
}

/*
 *  set up an uart port as something other than a stream
 */
void
uartspecial(int port, IOQ *oq, IOQ *iq, int baud)
{
	Uart *up = &uart[port];

	uartsetup();
	up->nostream = 1;
	up->oq = oq;
	up->iq = iq;
	uartenable(up);
	uartsetbaud(up, baud);

	if(iq){
		/*
		 *  Stupid HACK to undo a stupid hack
		 */ 
		if(iq == &kbdq)
			kbdq.putc = kbdcr2nl;
	}
}

static void	uarttimer(Alarm*);
static int	uartputc(IOQ *, int);
static void	uartstopen(Queue*, Stream*);
static void	uartstclose(Queue*);
static void	uartoput(Queue*, Block*);
static void	uartkproc(void *);
Qinfo uartinfo =
{
	nullput,
	uartoput,
	uartstopen,
	uartstclose,
	"uart"
};

/*
 *  create a helper process per port
 */
static void
uarttimer(Alarm *a)
{
	Uart *up = a->arg;

	cancel(a);
	up->a = 0;
	wakeup(&up->iq->r);
}

static int
uartputc(IOQ *cq, int ch)
{
	Uart *up = cq->ptr; int r;

	r = putc(cq, ch);

	/*
	 *  pass upstream within up->delay milliseconds
	 */
	if(up->a==0){
		if(up->delay == 0)
			wakeup(&cq->r);
		else
			up->a = alarm(up->delay, uarttimer, up);
	}
	return r;
}

static void
uartstopen(Queue *q, Stream *s)
{
	Uart *up;
	char name[NAMELEN];

	kprint("uartstopen: q=0x%ux, inuse=%d, type=%d, dev=%d, id=%d\n",
		q, s->inuse, s->type, s->dev, s->id);
	up = &uart[s->id];
	qlock(up);
	up->wq = WR(q);
	WR(q)->ptr = up;
	RD(q)->ptr = up;
	up->delay = 64;
	up->iq->putc = uartputc;
	qunlock(up);

	/* start with all characters as delimiters */
	memset(up->delim, 1, sizeof(up->delim));
	
	if(up->kstarted == 0){
		up->kstarted = 1;
		sprint(name, "uart%d", s->id);
		kproc(name, uartkproc, up);
	}
}

static void
uartstclose(Queue *q)
{
	Uart *up = q->ptr;

	qlock(up);
	kprint("uartstclose: q=0x%ux, id=%d\n", q, up-uart);
	up->wq = 0;
	up->iq->putc = 0;
	WR(q)->ptr = 0;
	RD(q)->ptr = 0;
	qunlock(up);
}

static void
uartoput(Queue *q, Block *bp)
{
	Uart *up = q->ptr;
	IOQ *cq;
	int n, m;

	if(up == 0){
		freeb(bp);
		return;
	}
	cq = up->oq;
	if(waserror()){
		freeb(bp);
		nexterror();
	}
	if(bp->type == M_CTL){
		while (cangetc(cq))	/* let output drain */
			sleep(&cq->r, cangetc, cq);
		n = strtoul((char *)(bp->rptr+1), 0, 0);
		switch(*bp->rptr){
		case 'B':
		case 'b':
			uartsetbaud(up, n);
			break;
		case 'D':
		case 'd':
			uartdtr(up, n);
			break;
		case 'K':
		case 'k':
			uartbreak(up, n);
			break;
		case 'R':
		case 'r':
			uartrts(up, n);
			break;
		case 'W':
		case 'w':
			if(n>=0 && n<1000)
				up->delay = n;
			break;
		}
	}else while((m = BLEN(bp)) > 0){
		while ((n = canputc(cq)) == 0){
print("uartoput: sleeping\n");
			sleep(&cq->r, canputc, cq);
		}
		if(n > m)
			n = m;
		(*cq->puts)(cq, bp->rptr, n);
		bp->rptr += n;
	}
	freeb(bp);
	poperror();
}

/*
 *  process to send bytes upstream for a port
 */
static void
uartkproc(void *a)
{
	Uart *up = a;
	IOQ *cq = up->iq;
	Block *bp;
	int n;

loop:
	while ((n = cangetc(cq)) == 0){
print("uart0 sleeping/n");
		sleep(&cq->r, cangetc, cq);
	}
	qlock(up);
	if(up->wq == 0){
		cq->out = cq->in;
	}else{
		bp = allocb(n);
		bp->flags |= S_DELIM;
		bp->wptr += gets(cq, bp->wptr, n);
		PUTNEXT(RD(up->wq), bp);
	}
	qunlock(up);
	goto loop;
}

enum{
	Qdir=		0,
	Qtty0=		STREAMQID(0, Sdataqid),
	Qtty0ctl=	STREAMQID(0, Sctlqid),
	Qtty1=		STREAMQID(1, Sdataqid),
	Qtty1ctl=	STREAMQID(1, Sctlqid),
};

Dirtab uartdir[]={
	"tty0",		{Qtty0},	0,		0666,
	"tty0ctl",	{Qtty0ctl},	0,		0666,
	"tty1",		{Qtty1},	0,		0666,
	"tty1ctl",	{Qtty1ctl},	0,		0666,
};

#define	NUart	(sizeof uartdir/sizeof(Dirtab))

/*
 *  allocate the queues if no one else has
 */
void
uartreset(void)
{
	Uart *up;

	uartsetup();
	for(up = uart; up < &uart[2]; up++){
		if(up->nostream)
			continue;
		up->iq = ialloc(sizeof(IOQ), 0);
		initq(up->iq);
		up->oq = ialloc(sizeof(IOQ), 0);
		initq(up->oq);
		uartenable(up);
	}
}

void
uartinit(void)
{
}

Chan*
uartattach(char *upec)
{
	return devattach('t', upec);
}

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

int
uartwalk(Chan *c, char *name)
{
	return devwalk(c, name, uartdir, NUart, devgen);
}

void
uartstat(Chan *c, char *dp)
{
	switch(c->qid.path){
	case Qtty0:
		streamstat(c, dp, "tty0");
		break;
	case Qtty1:
		streamstat(c, dp, "tty1");
		break;
	default:
		devstat(c, dp, uartdir, NUart, devgen);
		break;
	}
}

Chan*
uartopen(Chan *c, int omode)
{
	Uart *up;

	switch(c->qid.path){
	case Qtty0:
	case Qtty0ctl:
		up = &uart[0];
		break;
	case Qtty1:
	case Qtty1ctl:
		up = &uart[1];
		break;
	default:
		up = 0;
		break;
	}

	if(up && up->nostream)
		errors("in use");

	if((c->qid.path & CHDIR) == 0)
		streamopen(c, &uartinfo);
	return devopen(c, omode, uartdir, NUart, devgen);
}

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

void
uartclose(Chan *c)
{
	if(c->stream)
		streamclose(c);
}

long
uartread(Chan *c, void *buf, long n, ulong offset)
{
	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, uartdir, NUart, devgen);
	case Qtty1ctl:
	case Qtty0ctl:
		return 0;
	}
	return streamread(c, buf, n);
}

long
uartwrite(Chan *c, void *va, long n, ulong offset)
{
	return streamwrite(c, va, n, 0);
}

void
uartremove(Chan *c)
{
	error(Eperm);
}

void
uartwstat(Chan *c, char *dp)
{
	error(Eperm);
}
.
## diffname pc/devuart.c 1991/0803
## diff -e /n/bootesdump/1991/0801/sys/src/9/safari/devuart.c /n/bootesdump/1991/0803/sys/src/9/safari/devuart.c
507a

	if(serial(0) < 0)
		print("can't turn on power\n");
.
468d
272a
	up->sticky[Iena] |= (1<<2) | (1<<3);
.
233a
print("<cont %2.2ux>", ch);/**/
.
230c
		if(uartrdreg(up, Lstat)&Outready){
.
209c
	s = uartrdreg(up, Istat);
print("uartintr %lux\n", s);
	switch(s){
.
207a
	int s;
.
205d
190c
			for(tries = 0; tries<10000 && !(uartrdreg(up, Lstat)&Outready);
				tries++)
.
180a
	int tries;
.
91c
	brconst = (UartFREQ+8*rate-1)/(16*rate);
.
40c
	 Outready=(1<<5),	/*  output buffer full */
.
## diffname pc/devuart.c 1991/0804
## diff -e /n/bootesdump/1991/0803/sys/src/9/safari/devuart.c /n/bootesdump/1991/0804/sys/src/9/safari/devuart.c
151c
	 *  set port addresses
.
94,95c
	outb(up->port+Dmsb, (brconst>>8) & 0xff);
	outb(up->port+Dlsb, brconst & 0xff);
.
73,74c
#define uartwrreg(u,r,v)	outb((u)->port + r, (u)->sticky[r] | (v))
#define uartrdreg(u,r)		inb((u)->port + r)
.
52c
	uchar	sticky[8];	/* sticky write register values */
.
## diffname pc/devuart.c 1991/0806
## diff -e /n/bootesdump/1991/0804/sys/src/9/safari/devuart.c /n/bootesdump/1991/0806/sys/src/9/safari/devuart.c
525d
514,516d
401a

	if(serial(1) < 0)
		print("can't turn off serial power\n");
.
371a
	uartenable(up);
	if(s->id==0 && serial(0)<0)
		print("can't turn on serial power\n");

.
370a

.
369c
print("uartstopen: q=0x%ux, inuse=%d, type=%d, dev=%d, id=%d\n",
.
305a
	if(port == 0){
		if(serial(0) < 0)
			print("can't turn on serial port power\n");
	}
.
289a

	/*
	 *  read interrupt status till there aren't any pending
	 */
	while(uartrdreg(up, Istat) != 1){
		x = splhi();
		uartintr(up);
		splx(x);
	}
.
265a
	int x;

.
247a

	/*
	 *  send next output character
	 */
	if(up->printing && (l&Outready)){
		cq = up->oq;
		lock(cq);
		ch = getc(cq);
print("<put %2.2ux>", ch);/**/
		if(ch < 0){
			up->printing = 0;
			wakeup(&cq->r);
		}else
			outb(up->port + Data, ch);
		unlock(cq);
	}
.
246c
		l = uartrdreg(up, Lstat);
.
242,244d
212,240c

	cq = up->iq;
	while(l & Inready){
		ch = uartrdreg(up, Data) & 0xff;
print("<get %2.2ux>", ch);
		if(cq->putc)
			(*cq->putc)(cq, ch);
		else {
			putc(cq, ch);
			if(up->delim[ch/8] & (1<<(ch&7)) )
.
210a
	l = uartrdreg(up, Lstat);
.
209c
	int s, l;
.
## diffname pc/devuart.c 1991/0807
## diff -e /n/bootesdump/1991/0806/sys/src/9/safari/devuart.c /n/bootesdump/1991/0807/sys/src/9/safari/devuart.c
417,419d
409a
	uartdisable(up);

.
384,385d
312,315d
291,294c
	up->sticky[Iena] = 0;
	uartwrreg(up, Iena, 0);

	/*
	 *  turn off DTR and RTS
	 */
	uartdtr(up, 0);
	uartrts(up, 0);
	up->enabled = 0;

	/*
	 *  turn off power
	 */
	if(up == &uart[0]){
		if(serial(1) < 0)
			print("can't turn off serial power\n");
.
289c
 	 *  turn off interrupts
.
287a
/*
 *  turn off the uart
 */
uartdisable(Uart *up)
{

.
286a
}
.
274a
	up->enabled = 1;
.
263a
	 *  turn on power to the port
	 */
	if(up == &uart[0]){
		if(serial(0) < 0)
			print("can't turn on serial port power\n");
	}

	/*
.
247c
	if(uart[0].enabled)
		uartintr(&uart[0]);
.
235d
217d
188d
53a
	int	enabled;
.
## diffname pc/devuart.c 1991/0808
## diff -e /n/bootesdump/1991/0807/sys/src/9/safari/devuart.c /n/bootesdump/1991/0808/sys/src/9/safari/devuart.c
514,524d
512a
		qlock(up);
		if(up->wq == 0){
			cq->out = cq->in;
		}else{
			n = cangetc(cq);
			bp = allocb(n);
			bp->flags |= S_DELIM;
			bp->wptr += gets(cq, bp->wptr, n);
			PUTNEXT(RD(up->wq), bp);
		}
		qunlock(up);
.
510,511c
	if(waserror())
		print("uartkproc got an error\n");

	for(;;){
.
487d
479,483d
470a
		case 'e':
		case 'E':
			/*
			 *  the characters in the block are the message
			 *  delimiters to use upstream
			 */
			memset(up->delim, 0, sizeof(up->delim));
			while(++(bp->rptr) < bp->wptr){
				m = *bp->rptr;
				up->delim[m/8] |= 1<<(m&7);
			}
			break;
.
417c
	memset(up->delim, 0xff, sizeof(up->delim));
.
412,413d
405a
	up->iq->putc = 0;
.
377,395d
322a

	/*
	 *  slow the clock down again
	 */
	clockinit();
.
319c
	if(up == &uart[Serial]){
.
294a

print("uart enabled: Iena=%lux\n", uartrdreg(up, Iena));
.
288a
	uartwrreg(up, Tctl, 0x0);
.
283c
	up->sticky[Iena] = 0xf;
.
280d
276d
270a
	 *  speed up the clock to poll the uart
	 */
	fclockinit();

	/*
.
265c
	if(up == &uart[Serial]){
.
251c
	if(uart[1].enabled)
		uartintr(&uart[1]);
.
65d
44a

	Serial=	0,
	Modem=	1,
.
21,23c
	Istat=	2,		/* interrupt flag (read) */
	Tctl=	2,		/* test control (write) */
.
1c

#include	"u.h"
.
## diffname pc/devuart.c 1991/0810
## diff -e /n/bootesdump/1991/0808/sys/src/9/safari/devuart.c /n/bootesdump/1991/0810/sys/src/9/safari/devuart.c
395,397d
301,302d
294d
292a
	up->sticky[Iena] = 0x7;
.
288d
275a
	 */
.
274d
252,253c
	uartintr(&uart[1]);
.
246,247c
	uartintr(&uart[0]);
.
227,241d
225d
223a
			}else
				outb(up->port + Data, ch);
			unlock(cq);
			break;
	
		case 0:	/* modem status */
			l = uartrdreg(up, Mstat);
			break;
	
		default:
			if(s&1)
				return;
			print("weird modem interrupt\n");
			break;
.
212,222c
	for(;;){
		s = uartrdreg(up, Istat);
		switch(s){
		case 6:	/* receiver line status */
			l = uartrdreg(up, Lstat);
			break;
	
		case 4:	/* received data available */
			cq = up->iq;
			ch = uartrdreg(up, Data) & 0xff;
			if(cq->putc)
				(*cq->putc)(cq, ch);
			else {
				putc(cq, ch);
				if(up->delim[ch/8] & (1<<(ch&7)) )
					wakeup(&cq->r);
			}
			break;
	
		case 2:	/* transmitter empty */
			cq = up->oq;
			lock(cq);
			ch = getc(cq);
			if(ch < 0){
				up->printing = 0;
.
170a
		up->sticky[Mctl] |= Inton;
		uartwrreg(up, Mctl, 0x0);
.
166a
		 *  interrupts enabled.
.
35c
	 Inton=	(1<<3),		/*  turn on interrupts */
.
## diffname pc/devuart.c 1991/0822
## diff -e /n/bootesdump/1991/0810/sys/src/9/safari/devuart.c /n/bootesdump/1991/0822/sys/src/9/safari/devuart.c
284,288d
231a
			l = uartrdreg(up, Lstat);
			if(l & Overrun)
				screenputc('!');
.
214a
	/*
	 *  the for loop takes care of multiple events per interrupt
	 */
.
38a
	 Overrun=(1<<1),	/*  we lost an input char */
.
## diffname pc/devuart.c 1991/0823
## diff -e /n/bootesdump/1991/0822/sys/src/9/safari/devuart.c /n/bootesdump/1991/0823/sys/src/9/safari/devuart.c
533a
		if(up->frame != frame){
			kprint("uart%d: %d framing\n", up-uart, up->frame);
			frame = up->frame;
		}
		if(up->overrun != overrun){
			kprint("uart%d: %d overruns\n", up-uart, up->overrun);
			overrun = up->overrun;
		}
.
516a
	ulong frame, overrun;
.
307c
	up->sticky[Iena] = Ircv | Ixmt | Irstat;
.
292a
	 *  speed up the clock to poll the uart
	fclockinit();
	 */

	/*
.
260c
/*			print("weird modem interrupt\n");/**/
.
236,238d
223a
			if(l & Ferror)
				up->frame++;
			if(l & Oerror)
				up->overrun++;
.
216,218d
69a

	/* error statistics */
	ulong	frame;
	ulong	overrun;
.
39c
	 Oerror=(1<<1),		/*  receiver overrun */
	 Perror=(1<<2),		/*  receiver parity error */
	 Ferror=(1<<3),		/*  rcv framing error */
.
20a
	 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 */
.
1c
#include	"u.h"
.
## diffname pc/devuart.c 1991/0904
## diff -e /n/bootesdump/1991/0823/sys/src/9/safari/devuart.c /n/bootesdump/1991/0904/sys/src/9/safari/devuart.c
530a

	frame = 0;
	overrun = 0;
.
262c
			uartrdreg(up, Mstat);
.
## diffname pc/devuart.c 1991/1001
## diff -e /n/bootesdump/1991/0904/sys/src/9/safari/devuart.c /n/bootesdump/1991/1001/sys/src/9/safari/devuart.c
297a
	} else {
		if(modem(0) < 0)
			print("can't turn on modem speaker\n");
.
## diffname pc/devuart.c 1991/1113
## diff -e /n/bootesdump/1991/1001/sys/src/9/safari/devuart.c /n/bootesdump/1991/1113/sys/src/9/safari/devuart.c
542a
		if((ints++ & 0x1f) == 0)
			owl(ints>>5);
.
533a
	static ulong ints;
.
489,500d
434,436d
304,308d
283a
void
uartclock(void)
{
	Uart *up;
	IOQ *cq;

	for(up = uart; up < &uart[2]; up++){
		cq = up->iq;
		if(up->wq && cangetc(cq))
			wakeup(&cq->r);
	}
}


.
244,246d
242c
			else
.
75d
## diffname pc/devuart.c 1991/1115
## diff -e /n/bootesdump/1991/1113/sys/src/9/safari/devuart.c /n/bootesdump/1991/1115/sys/src/9/safari/devuart.c
679,680c
	case Qeia1ctl:
	case Qeia0ctl:
.
643,644c
	case Qeia1:
	case Qeia1ctl:
.
639,640c
	case Qeia0:
	case Qeia0ctl:
.
624,625c
	case Qeia1:
		streamstat(c, dp, "eia1");
.
621,622c
	case Qeia0:
		streamstat(c, dp, "eia0");
.
567,570c
	"eia0",		{Qeia0},	0,		0666,
	"eia0ctl",	{Qeia0ctl},	0,		0666,
	"eia1",		{Qeia1},	0,		0666,
	"eia1ctl",	{Qeia1ctl},	0,		0666,
.
560,563c
	Qeia0=		STREAMQID(0, Sdataqid),
	Qeia0ctl=	STREAMQID(0, Sctlqid),
	Qeia1=		STREAMQID(1, Sdataqid),
	Qeia1ctl=	STREAMQID(1, Sctlqid),
.
## diffname pc/devuart.c 1991/1210
## diff -e /n/bootesdump/1991/1115/sys/src/9/safari/devuart.c /n/bootesdump/1991/1210/sys/src/9/safari/devuart.c
535c
			lights((ints>>5)&1);
.
362a
	} else {
		if(modem(0) < 0)
			print("can't turn off modem speaker\n");
.
361c
		if(serial(0) < 0)
.
309c
		if(modem(1) < 0)
.
306c
		if(serial(1) < 0)
.
## diffname pc/devuart.c 1992/0101
## diff -e /n/bootesdump/1991/1210/sys/src/9/safari/devuart.c /n/bootesdump/1992/0101/sys/src/9/safari/devuart.c
142a
	if(ms == 0)
		ms = 200;
.
## diffname pc/devuart.c 1992/0111
## diff -e /n/bootesdump/1992/0101/sys/src/9/safari/devuart.c /n/bootesdump/1992/0111/sys/src/9/safari/devuart.c
7c
#include	"../port/error.h"
.
## diffname pc/devuart.c 1992/0114
## diff -e /n/bootesdump/1992/0111/sys/src/9/safari/devuart.c /n/bootesdump/1992/0114/sys/src/9/safari/devuart.c
658c
		error(Einuse);
.
## diffname pc/devuart.c 1992/0321
## diff -e /n/bootesdump/1992/0114/sys/src/9/safari/devuart.c /n/bootesdump/1992/0321/sys/src/9/safari/devuart.c
2c
#include	"../port/lib.h"
.
## diffname pc/devuart.c 1992/0409
## diff -e /n/bootesdump/1992/0321/sys/src/9/safari/devuart.c /n/bootesdump/1992/0409/sys/src/9/safari/devuart.c
266c
			print("weird modem interrupt\n");
.
248a
			if(cq == 0)
				break;
.
240a
			cq = up->iq;
			if(cq == 0)
				break;
.
239d
## diffname pc/devuart.c 1992/0602
## diff -e /n/bootesdump/1992/0409/sys/src/9/safari/devuart.c /n/bootesdump/1992/0602/sys/src/9/safari/devuart.c
418,430d
404d
73d
## diffname pc/devuart.c 1992/0625
## diff -e /n/bootesdump/1992/0602/sys/src/9/safari/devuart.c /n/bootesdump/1992/0625/sys/src/9/safari/devuart.c
583c
		up->oq = xalloc(sizeof(IOQ));
.
581c
		up->iq = xalloc(sizeof(IOQ));
.
## diffname pc/devuart.c 1992/0711
## diff -e /n/bootesdump/1992/0625/sys/src/9/safari/devuart.c /n/bootesdump/1992/0711/sys/src/9/safari/devuart.c
694a
	USED(c, dp);
.
688a
	USED(c);
.
682a
	USED(offset);
.
669a
	USED(offset);
.
656a
	USED(c, name, omode, perm);
.
345a
void
.
305,306d
281a
	USED(ur);
.
276a
	USED(ur);
.
196c
	int ch, x;
.
## diffname pc/devuart.c 1992/0826
## diff -e /n/bootesdump/1992/0808/sys/src/9/safari/devuart.c /n/bootesdump/1992/0826/sys/src/9/pc/devuart.c
620c
		streamstat(c, dp, uartdir[2].name, uartdir[2].perm);
.
617c
		streamstat(c, dp, uartdir[0].name, uartdir[0].perm);
.
## diffname pc/devuart.c 1992/1016
## diff -e /n/bootesdump/1992/0826/sys/src/9/pc/devuart.c /n/bootesdump/1992/1016/sys/src/9/pc/devuart.c
492a
			break;
		case 'S':
		case 's':
			uartstop(up, n);
.
489a
		case 'L':
		case 'l':
			uartbits(up, n);
			break;
		case 'P':
		case 'p':
			uartparity(up, *(bp->rptr+1));
			break;
.
360a
	 */
.
358d
184a

		uartdtr(up, 1);
		uartrts(up, 1);
.
149a
 *  set bits/char
 */
void
uartbits(Uart *up, int bits)
{
	if(bits < 5 || bits > 8)
		error(Ebadarg);
	up->sticky[Format] &= ~3;
	up->sticky[Format] |= bits-5;
	uartwrreg(up, Format, 0);
}

/*
 *  set parity
 */
void
uartparity(Uart *up, int c)
{
	switch(c&0xff){
	case 'e':
		up->sticky[Format] |= Pena|Peven;
		break;
	case 'o':
		up->sticky[Format] &= ~Peven;
		up->sticky[Format] |= Pena;
		break;
	default:
		up->sticky[Format] &= ~(Pena|Peven);
		break;
	}
	uartwrreg(up, Format, 0);
}

/*
 *  set stop bits
 */
void
uartstop(Uart *up, int n)
{
	switch(n){
	case 1:
		up->sticky[Format] &= ~Stop2;
		break;
	case 2:
	default:
		up->sticky[Format] |= Stop2;
		break;
	}
	uartwrreg(up, Format, 0);
}

/*
.
40c
	 Loop=	(1<<4),		/*  loop back */
.
## diffname pc/devuart.c 1992/1017
## diff -e /n/bootesdump/1992/1016/sys/src/9/pc/devuart.c /n/bootesdump/1992/1017/sys/src/9/pc/devuart.c
714c
	if(up && up->special)
.
647c
		if(up->special)
.
500a
	if(up->special)
		return;

.
448c
	if(baud)
		uartsetbaud(up, baud);
.
444c
	up->special = 1;
.
428,432d
415d
412a
	 */
.
411a
	 *  revert to default settings
	 */
	up->sticky[Format] = Bits8;
	uartwrreg(up, Format, 0);

	/*
.
237,239d
66c
	int	special;	/* can't use the stream interface */
.
## diffname pc/devuart.c 1992/1210
## diff -e /n/bootesdump/1992/1017/sys/src/9/pc/devuart.c /n/bootesdump/1992/1210/sys/src/9/pc/devuart.c
549a
			break;
		case 'm':
		case 'M':
			uartmflow(up, n);
.
392a

	/*
	 *  assume we can send
	 */
	up->cts = 1;
.
315c
			ch = uartrdreg(up, Mstat);
			if(ch & Ctsc){
				up->cts = ch & Cts;
				cq = up->oq;
				if(cq == 0)
					break;
				if(multiprocessor)
					lock(cq);
				if(up->cts && up->printing == 0){
					ch = getc(cq);
					if(ch >= 0){
						up->printing = 1;
						outb(up->port + Data, getc(cq));
					} else
						wakeup(&cq->r);
				}
				if(multiprocessor)
					unlock(cq);
			}
.
308,311c
			else {
				ch = getc(cq);
				if(ch < 0){
					up->printing = 0;
					wakeup(&cq->r);
				}else
					outb(up->port + Data, ch);
			}
			if(multiprocessor)
				unlock(cq);
.
304,306c
			if(multiprocessor)
				lock(cq);
			if(up->cts == 0)
.
277a
	multiprocessor = active.machs > 1;
.
276c
	int s, l, multiprocessor;
.
264c
	if(multiprocessor)
		unlock(cq);
.
252c
	if(multiprocessor)
		lock(cq);
.
250a
	multiprocessor = active.machs > 1;
.
248c
	int ch, x, multiprocessor;
.
201a
 *  modem flow control on/off (rts/cts)
 */
void
uartmflow(Uart *up, int n)
{
	if(n){
		up->sticky[Iena] |= Imstat;
		uartwrreg(up, Iena, 0);
		up->cts = uartrdreg(up, Mstat) & Cts;
	} else {
		up->sticky[Iena] &= ~Imstat;
		uartwrreg(up, Iena, 0);
		up->cts = 1;
	}
}


/*
.
63a
	int	cts;
.
47a
	 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 */
.
## diffname pc/devuart.c 1993/0326
## diff -e /n/bootesdump/1992/1210/sys/src/9/pc/devuart.c /n/bootesdump/1993/0326/sys/src/9/pc/devuart.c
811c
		return uartstatus(&uart[0], buf, n, offset);
.
809a
		return uartstatus(&uart[1], buf, n, offset);
.
802a
uartstatus(Uart *up, void *buf, long n, ulong offset)
{
	uchar mstat;
	uchar tstat;
	char str[128];

	str[0] = 0;
	tstat = up->sticky[Mctl];
	mstat = uartrdreg(up, Mstat);
	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 & Dtr)
		strcat(str, " rts");
	return readstr(offset, buf, n, str);
}

long
.
## diffname pc/devuart.c 1993/0915
## diff -e /n/bootesdump/1993/0326/sys/src/9/pc/devuart.c /n/fornaxdump/1993/0915/sys/src/brazil/pc/devuart.c
859c
	USED(c, dir);
.
857c
uartwstat(Chan *c, char *dir)
.
831,838c
	qpath = c->qid.path & ~CHDIR;
	if(qpath == Qdir)
		return devdirread(c, buf, n, uartdir, Nuart * 2, devgen);
	for(i=1; i < 2*Nuart; i += 2)
		if(qpath == uartdir[i].qid.path)
			return uartstatus(&uart[i/2], buf, n, offset);
.
829a
	int i;
	long qpath;

.
810,811c
	tstat = dp->sticky[Mctl];
	mstat = uartrdreg(dp, Mstat);
.
803c
uartstatus(Uart *dp, void *buf, long n, ulong offset)
.
785c
	return devopen(c, omode, uartdir, Nuart * 2, devgen);
.
782d
780c
	if(dp && dp->special)
.
766,778c
	dp = 0;
	for(i=0; i < 2*Nuart; ++i)
		if(c->qid.path == uartdir[i].qid.path) {
			dp = &uart[i/2];
			break;
		}
.
764c
	Uart *dp;
	int	i;
.
748,758c
	int	i;

	for(i=0; i < 2*Nuart; i += 2)
		if(c->qid.path == uartdir[i].qid.path) {
			streamstat(c, dir, uartdir[i].name, uartdir[i].perm);
			return;
		}
	devstat(c, dir, uartdir, Nuart * 2, devgen);
.
746c
uartstat(Chan *c, char *dir)
.
742c
	return devwalk(c, name, uartdir, Nuart * 2, devgen);
.
730c
	return devattach('t', dpec);
.
728c
uartattach(char *dpec)
.
724a
	int	i;

	for(i=0; i < 2*Nuart; ++i) {
		if(i & 1 != 0) {
			sprint(uartdir[i].name, "eia%dctl", i/2);
			uartdir[i].qid.path = STREAMQID(i/2, Sctlqid);
		} else {
			sprint(uartdir[i].name, "eia%d", i/2);
			uartdir[i].qid.path = STREAMQID(i/2, Sdataqid);
		}
		uartdir[i].length = 0;
		uartdir[i].perm = 0666;
	}
.
715,718c
		dp->iq = xalloc(sizeof(IOQ));
		initq(dp->iq);
		dp->oq = xalloc(sizeof(IOQ));
		initq(dp->oq);
.
712,713c
	for(dp = uart; dp < &uart[Nuart]; dp++){
		if(dp->special)
.
709c
	Uart *dp;
.
701,702d
694,699c
Dirtab uartdir[2*nelem(uart)];
.
688,691d
679,681c
		if(dp->overrun != overrun){
			kprint("uart%d: %d overruns\n", dp-uart, dp->overrun);
			overrun = dp->overrun;
.
674,677c
		qunlock(dp);
		if(dp->frame != frame){
			kprint("uart%d: %d framing\n", dp-uart, dp->frame);
			frame = dp->frame;
.
672c
			PUTNEXT(RD(dp->wq), bp);
.
664,665c
		qlock(dp);
		if(dp->wq == 0){
.
647,648c
	Uart *dp = a;
	IOQ *cq = dp->iq;
.
642c
 *  process to send bytes dpstream for a port
.
625c
			uartstop(dp, n);
.
621c
			uartrts(dp, n);
.
617c
			uartparity(dp, *(bp->rptr+1));
.
613c
			uartmflow(dp, n);
.
609c
			uartbits(dp, n);
.
605c
			uartbreak(dp, n);
.
601c
			uartdtr(dp, n);
.
597c
			if(n <= 0)
				error(Ebadctl);
			uartsetbaud(dp, n);
.
585c
	cq = dp->oq;
.
581c
	if(dp == 0){
.
577c
	Uart *dp = q->ptr;
.
571c
	qunlock(dp);
.
565,568c
	qlock(dp);
	kprint("uartstclose: q=0x%ux, id=%d\n", q, dp-uart);
	dp->wq = 0;
	dp->iq->putc = 0;
.
563c
	uartdisable(dp);
.
560c
	if(dp->special)
.
558c
	Uart *dp = q->ptr;
.
551c
		kproc(name, uartkproc, dp);
.
548,549c
	if(dp->kstarted == 0){
		dp->kstarted = 1;
.
542,546c
	qlock(dp);
	dp->wq = WR(q);
	WR(q)->ptr = dp;
	RD(q)->ptr = dp;
	qunlock(dp);
.
538,540c
	dp = &uart[s->id];
	dp->iq->putc = 0;
	uartenable(dp);
.
535c
	Uart *dp;
.
511c
		 *  Stdpid HACK to undo a stdpid hack
.
507c
		uartsetbaud(dp, baud);
.
502,505c
	dp->special = 1;
	dp->oq = oq;
	dp->iq = iq;
	uartenable(dp);
.
499c
	Uart *dp = &uart[port];
.
494c
 *  set dp an uart port as something other than a stream
.
489a
	} else {
		if(serial(0) < 0)
			print("can't turn off serial power\n");
.
484,487c
	if(dp == &uart[Modem]){
.
477,479c
	uartdtr(dp, 0);
	uartrts(dp, 0);
	dp->enabled = 0;
.
471,472c
	dp->sticky[Format] = Bits8;
	uartwrreg(dp, Format, 0);
.
465,466c
	dp->sticky[Iena] = 0;
	uartwrreg(dp, Iena, 0);
.
463c
 	 *  turn off interrdpts
.
459c
uartdisable(Uart *dp)
.
452c
	dp->cts = 1;
.
446,447c
	uartdtr(dp, 1);
	uartrts(dp, 1);
.
440,441c
	dp->sticky[Iena] = Ircv | Ixmt | Irstat;
	uartwrreg(dp, Iena, 0);
.
438c
 	 *  turn on interrdpts
.
435c
	dp->enabled = 1;
.
432,433c
	if(dp->iq){
		dp->iq->ptr = dp;
.
428,430c
	if(dp->oq){
		dp->oq->puts = uartputs;
		dp->oq->ptr = dp;
.
426c
	 *  set dp i/o routines
.
422a
	} else {
		if(serial(1) < 0)
			print("can't turn on serial port power\n");
.
417,420c
	if(dp == &uart[Modem]){
.
412c
uartenable(Uart *dp)
.
409c
 *  turn on a port's interrdpts.  set DTR and RTS
.
400,403c
	for(dp = uart; dp < &uart[Nuart]; dp++){
		cq = dp->iq;
		if(dp->wq && cangetc(cq))
			wakedp(&cq->r);
.
397c
	Uart *dp;
.
393a
	USED(ur);
	for(nuart=2, j = 0; j < Nscard; nuart += scard[j].size, j++) {
		n = ~inb(scard[j].port);
		if(n == 0)
			continue;
		for(i = 0; n; i++){
			if(n & 1)
				uartintr(&uart[nuart + i]);
			n >>= 1;
		}
	}
}

.
392a
void
uartintr2(Ureg *ur)
{
	uchar	i, j, nuart, n;
.
376c
			print("weird modem interrdpt #%2.2ux\n", s);
.
366c
						wakedp(&cq->r);
.
363,364c
						dp->printing = 1;
						outb(dp->port + Data, getc(cq));
.
360c
				if(dp->cts && dp->printing == 0){
.
354,355c
				dp->cts = ch & Cts;
				cq = dp->oq;
.
352c
			ch = uartrdreg(dp, Mstat);
.
345c
					outb(dp->port + Data, ch);
.
342,343c
					dp->printing = 0;
					wakedp(&cq->r);
.
337,338c
			if(dp->cts == 0)
				dp->printing = 0;
.
332c
			cq = dp->oq;
.
321,322c
			ch = uartrdreg(dp, Data) & 0xff;
			cq = dp->iq;
.
317c
				dp->overrun++;
.
315c
				dp->frame++;
.
313c
			l = uartrdreg(dp, Lstat);
.
310c
		s = uartrdreg(dp, Istat);
.
302c
uartintr(Uart *dp)
.
299c
 *  a uart interrdpt (a damn lot of work for one character)
.
290c
			outb(dp->port + Data, ch);
.
286,287c
			dp->printing = 1;
			for(tries = 0; tries<10000 && !(uartrdreg(dp, Lstat)&Outready);
.
283c
	if(dp->printing == 0){
.
274c
	Uart *dp = cq->ptr;
.
259,263c
		uartsetbaud(dp, 9600);
		dp->sticky[Format] = Bits8;
		uartwrreg(dp, Format, 0);
		dp->sticky[Mctl] |= Inton;
		uartwrreg(dp, Mctl, 0x0);
.
257c
		 *  interrdpts enabled.
.
253a
		 * mem gives base port address for uarts
		 * irq is interrdpt
		 * port is the polling port
		 * size is the number of serial ports on the same polling port
		 */
		setvec(Int0vec + scard[i].irq, uartintr2);
		baddr = scard[i].mem;
		for(j=0, dp = &uart[Nuart]; j < scard[i].size; baddr += 8, j++, dp++)
			dp->port = baddr;
		Nuart += scard[i].size;
	}
	Nscard = i;
	for(dp = uart; dp < &uart[Nuart]; dp++){
		memset(dp->sticky, 0, sizeof(dp->sticky));
		/*
.
249,252c
	Nuart = 2;
	for(i = 0; isaconfig("serial", i, &scard[i]) && i < nelem(scard); i++) {
.
235c
	Uart	*dp;
	int	i, j, baddr;
.
229,230c
 *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrdpts,
 *  transmit and receive enabled, interrdpts disabled.
.
221,223c
		dp->sticky[Iena] &= ~Imstat;
		uartwrreg(dp, Iena, 0);
		dp->cts = 1;
.
217,219c
		dp->sticky[Iena] |= Imstat;
		uartwrreg(dp, Iena, 0);
		dp->cts = uartrdreg(dp, Mstat) & Cts;
.
214c
uartmflow(Uart *dp, int n)
.
207c
	uartwrreg(dp, Format, 0);
.
204c
		dp->sticky[Format] |= Stop2;
.
200c
		dp->sticky[Format] &= ~Stop2;
.
196c
uartstop(Uart *dp, int n)
.
189c
	uartwrreg(dp, Format, 0);
.
186c
		dp->sticky[Format] &= ~(Pena|Peven);
.
182,183c
		dp->sticky[Format] &= ~Peven;
		dp->sticky[Format] |= Pena;
.
179c
		dp->sticky[Format] |= Pena|Peven;
.
175c
uartparity(Uart *dp, int c)
.
166,168c
	dp->sticky[Format] &= ~3;
	dp->sticky[Format] |= bits-5;
	uartwrreg(dp, Format, 0);
.
162c
uartbits(Uart *dp, int bits)
.
153,155c
	uartwrreg(dp, Format, Break);
	tsleep(&dp->sleep, return0, 0, ms);
	uartwrreg(dp, Format, 0);
.
149c
uartbreak(Uart *dp, int ms)
.
141,142c
		dp->sticky[Mctl] &= ~Rts;
	uartwrreg(dp, Mctl, 0);
.
139c
		dp->sticky[Mctl] |= Rts;
.
136c
uartrts(Uart *dp, int n)
.
128,129c
		dp->sticky[Mctl] &= ~Dtr;
	uartwrreg(dp, Mctl, 0);
.
126c
		dp->sticky[Mctl] |= Dtr;
.
123c
uartdtr(Uart *dp, int n)
.
113,116c
	uartwrreg(dp, Format, Dra);
	outb(dp->port+Dmsb, (brconst>>8) & 0xff);
	outb(dp->port+Dlsb, brconst & 0xff);
	uartwrreg(dp, Format, 0);
.
107c
uartsetbaud(Uart *dp, int rate)
.
98a
void	uartintr2(Ureg*);
.
91c
#define UartFREQ 1843200
.
89c
Uart	uart[34];
int	Nuart;		/* total no of uarts in the machine */
int	Nscard;		/* number of serial cards */
ISAConf	scard[5];	/* configs for the serial card */
.
39c
	 Inton=	(1<<3),		/*  turn on interrdpts */
.
25c
	Istat=	2,		/* interrdpt flag (read) */
.
20c
	Iena=	1,		/* interrdpt enable */
.
10c
#define		nelem(x)	(sizeof(x)/sizeof(x[0]))
.
## diffname pc/devuart.c 1993/1124 # deleted
## diff -e /n/fornaxdump/1993/0915/sys/src/brazil/pc/devuart.c /n/fornaxdump/1993/1124/sys/src/brazil/pc/devuart.c
1,891d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].