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

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


## diffname port/devscc.c 1991/0601
## diff -e /dev/null /n/bootesdump/1991/0601/sys/src/9/port/devscc.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 the Z8530.
 */
enum
{
	/* wr 0 */
	ResExtPend=	2<<3,
	ResTxPend=	5<<3,
	ResErr=		6<<3,

	/* wr 1 */
	ExtIntEna=	1<<0,
	TxIntEna=	1<<1,
	RxIntDis=	0<<3,
	RxIntFirstEna=	1<<3,
	RxIntAllEna=	2<<3,

	/* wr 3 */
	RxEna=		1,
	Rx5bits=	0<<6,
	Rx7bits=	1<<6,
	Rx6bits=	2<<6,
	Rx8bits=	3<<6,

	/* wr 4 */
	SyncMode=	0<<2,
	Rx1stop=	1<<2,
	Rx1hstop=	2<<2,
	Rx2stop=	3<<2,
	X16=		1<<6,

	/* wr 5 */
	TxRTS=		1<<1,
	TxEna=		1<<3,
	TxBreak=	1<<4,
	TxDTR=		1<<7,
	Tx5bits=	0<<5,
	Tx7bits=	1<<5,
	Tx6bits=	2<<5,
	Tx8bits=	3<<5,

	/* wr 9 */
	IntEna=		1<<3,
	ResetB=		1<<6,
	ResetA=		2<<6,
	HardReset=	3<<6,

	/* wr 11 */
	TRxCOutBR=	2,
	TxClockBR=	2<<3,
	RxClockBR=	2<<5,
	TRxCOI=		1<<2,

	/* wr 14 */
	BREna=		1,
	BRSource=	2,

	/* rr 0 */
	RxReady=	1,
	TxReady=	1<<2,
	RxDCD=		1<<3,
	RxCTS=		1<<5,
	RxBreak=	1<<7,

	/* rr 3 */
	ExtPendB=	1,	
	TxPendB=	1<<1,
	RxPendB=	1<<2,
	ExtPendA=	1<<3,	
	TxPendA=	1<<4,
	RxPendA=	1<<5,
};

typedef struct SCC	SCC;
struct SCC
{
	QLock;
	ushort	sticky[16];	/* sticky write register values */
	uchar	*ptr;		/* command/pointer register in Z8530 */
	uchar	*data;		/* data register in Z8530 */
	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];	/* characters that act as delimiters */
};
SCC	scc[2];

void
onepointseven(void)
{
	int i;
	for(i = 0; i < 20; i++)
		;
}

/*
 *  Access registers using the pointer in register 0.
 *  This is a bit stupid when accessing register 0.
 */
void
sccwrreg(SCC *sp, int addr, int value)
{
	onepointseven();
	*sp->ptr = addr;
	wbflush();
	onepointseven();
	*sp->ptr = sp->sticky[addr] | value;
	wbflush();
}
ushort
sccrdreg(SCC *sp, int addr)
{
	onepointseven();
	*sp->ptr = addr;
	wbflush();
	onepointseven();
	return *sp->ptr;
}

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

	brconst = (SCCFREQ+16*rate-1)/(2*16*rate) - 2;

	sccwrreg(sp, 12, brconst & 0xff);
	sccwrreg(sp, 13, (brconst>>8) & 0xff);
}

/*
 *  toggle DTR
 */
void
sccdtr(SCC *sp, int n)
{
	if(n)
		sp->sticky[5] |= TxDTR;
	else
		sp->sticky[5] &=~TxDTR;
	sccwrreg(sp, 5, 0);
}

/*
 *  toggle RTS
 */
void
sccrts(SCC *sp, int n)
{
	if(n)
		sp->sticky[5] |= TxRTS;
	else
		sp->sticky[5] &=~TxRTS;
	sccwrreg(sp, 5, 0);
}

/*
 *  send break
 */
void
sccbreak(SCC *sp, int ms)
{
	sp->sticky[1] &=~TxIntEna;
	sccwrreg(sp, 1, 0);
	sccwrreg(sp, 5, TxBreak|TxEna);
	tsleep(&u->p->sleep, return0, 0, ms);
	sccwrreg(sp, 5, 0);
	if(sp->oq){
		sp->sticky[1] |= TxIntEna;
		sccwrreg(sp, 1, 0);
	}
}

/*
 *  9600 baud, 1 stop bit, 8 bit chars, no interrupts,
 *  transmit and receive enabled, interrupts disabled.
 */
void
sccsetup(void)
{
	SCC *sp;
	static int already;

	if(already)
		return;
	already = 1;

	/*
	 *  get port addresses
	 */
	scc[0].ptr = &SCCADDR->ptra;
	scc[0].data = &SCCADDR->dataa;
	scc[1].ptr = &SCCADDR->ptrb;
	scc[1].data = &SCCADDR->datab;

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

		/*
		 *  turn on baud rate generator and set rate to 9600 baud.
		 *  use 1 stop bit.
		 */
		sp->sticky[14] = BRSource;
		sccwrreg(sp, 14, 0);
		sccsetbaud(sp, 9600);
		sp->sticky[4] = Rx1stop | X16;
		sccwrreg(sp, 4, 0);
		sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR | TRxCOI;
		sccwrreg(sp, 11, 0);
		sp->sticky[14] = BREna | BRSource;
		sccwrreg(sp, 14, 0);

		/*
		 *  enable I/O, 8 bits/character
		 */
		sp->sticky[3] = RxEna | Rx8bits;
		sccwrreg(sp, 3, 0);
		sp->sticky[5] = TxEna | Tx8bits;
		sccwrreg(sp, 5, 0);
	}
}

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

	x = splhi();
	lock(cq);
	puts(cq, s, n);
	if(sp->printing == 0){
		ch = getc(cq);
		/*kprint("<start %2.2ux>", ch);*/
		if(ch >= 0){
			sp->printing = 1;
			while((*sp->ptr&TxReady)==0)
				;
			*sp->data = ch;
		}
	}
	unlock(cq);
	splx(x);
}

/*
 *  an scc interrupt (a damn lot of work for one character)
 */
void
sccintr0(SCC *sp, uchar x)
{
	int ch;
	IOQ *cq;

	if(x & ExtPendB){
		/*kprint("scc %d: %2.2ux\n", sp-scc, *sp->ptr);*/
		sccwrreg(sp, 0, ResExtPend);
	}
	if(x & RxPendB){
		cq = sp->iq;
		while(*sp->ptr&RxReady){
			onepointseven();
			ch = *sp->data;
			if(cq->putc)
				(*cq->putc)(cq, ch);
			else {
				putc(cq, ch);
				if(sp->delim[ch])
					wakeup(&cq->r);
			}
		}
	}
	if(x & TxPendB){
		cq = sp->oq;
		lock(cq);
		ch = getc(cq);
		/*kprint("<%2.2ux>", ch);*/
		onepointseven();
		if(ch < 0){
			/*kprint("<done>", ch);*/
			sccwrreg(sp, 0, ResTxPend);
			sp->printing = 0;
			wakeup(&cq->r);
		}else
			*sp->data = ch;
		unlock(cq);
	}
}
void
sccintr(void)
{
	uchar x;

	x = sccrdreg(&scc[0], 3);
	sccintr0(&scc[1], x);
	sccintr0(&scc[0], x>>3);
}

/*
 *  turn on a port's interrupts.  set DTR and RTS
 */
void
sccdevice(SCC *sp)
{
	/*
	 *  turn on both ports
	 */
	sccsetup();

	/*
	 *  set up i/o routines
	 */
	if(sp->oq){
		sp->oq->puts = sccputs;
		sp->oq->ptr = sp;
		sp->sticky[1] |= TxIntEna | ExtIntEna;
	}
	if(sp->iq){
		sp->iq->ptr = sp;
		sp->sticky[1] |= RxIntAllEna | ExtIntEna;
	}

	/*
 	 *  turn on interrupts
	 */
	sccwrreg(sp, 1, 0);
	sp->sticky[9] |= IntEna;
	sccwrreg(sp, 9, 0);

	/*
	 *  turn on DTR and RTS
	 */
	sccdtr(sp, 1);
	sccrts(sp, 1);
}

/*
 *  set up an scc port as something other than a stream
 */
void
sccspecial(int port, IOQ *oq, IOQ *iq, int baud)
{
	SCC *sp = &scc[port];

	sp->nostream = 1;
	sp->oq = oq;
	sp->iq = iq;
	sccdevice(sp);
	sccsetbaud(sp, baud);
}

static void	scctimer(Alarm*);
static int	sccputc(IOQ *, int);
static void	sccstopen(Queue*, Stream*);
static void	sccstclose(Queue*);
static void	sccoput(Queue*, Block*);
static void	scckproc(void *);
Qinfo sccinfo =
{
	nullput,
	sccoput,
	sccstopen,
	sccstclose,
	"scc"
};

/*
 *  create a helper process per port
 */
static void
scctimer(Alarm *a)
{
	SCC *sp = a->arg;

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

static int
sccputc(IOQ *cq, int ch)
{
	SCC *sp = cq->ptr; int r;

	r = putc(cq, ch);

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

static void
sccstopen(Queue *q, Stream *s)
{
	SCC *sp;
	char name[NAMELEN];

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

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

static void
sccstclose(Queue *q)
{
	SCC *sp = q->ptr;

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

static void
sccoput(Queue *q, Block *bp)
{
	SCC *sp = q->ptr;
	IOQ *cq;
	int n, m;

	if(sp == 0){
		freeb(bp);
		return;
	}
	cq = sp->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':
			sccsetbaud(sp, n);
			break;
		case 'D':
		case 'd':
			sccdtr(sp, n);
			break;
		case 'K':
		case 'k':
			sccbreak(sp, n);
			break;
		case 'R':
		case 'r':
			sccrts(sp, n);
			break;
		case 'W':
		case 'w':
			if(n>=0 && n<1000)
				sp->delay = n;
			break;
		}
	}else while((m = BLEN(bp)) > 0){
		while ((n = canputc(cq)) == 0){
			kprint(" sccoput: 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
scckproc(void *a)
{
	SCC *sp = a;
	IOQ *cq = sp->iq;
	Block *bp;
	int n;

loop:
	while ((n = cangetc(cq)) == 0)
		sleep(&cq->r, cangetc, cq);
	/*kprint(" scckproc: %d\n", n);*/
	qlock(sp);
	if(sp->wq == 0){
		cq->out = cq->in;
	}else{
		bp = allocb(n);
		bp->flags |= S_DELIM;
		bp->wptr += gets(cq, bp->wptr, n);
		PUTNEXT(RD(sp->wq), bp);
	}
	qunlock(sp);
	goto loop;
}

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

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

#define	NSCC	(sizeof sccdir/sizeof(Dirtab))

/*
 *  allocate the queues if no one else has
 */
void
sccreset(void)
{
	SCC *sp;

	for(sp = scc; sp < &scc[2]; sp++){
		if(sp->nostream)
			continue;
		sp->iq = ialloc(sizeof(IOQ), 0);
		initq(sp->iq);
		sp->oq = ialloc(sizeof(IOQ), 0);
		initq(sp->oq);
		sccdevice(sp);
	}
}

void
sccinit(void)
{
}

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

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

int
sccwalk(Chan *c, char *name)
{
	return devwalk(c, name, sccdir, NSCC, devgen);
}

void
sccstat(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, sccdir, NSCC, devgen);
		break;
	}
}

Chan*
sccopen(Chan *c, int omode)
{
	SCC *sp;

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

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

	if((c->qid.path & CHDIR) == 0)
		streamopen(c, &sccinfo);
	return devopen(c, omode, sccdir, NSCC, devgen);
}

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

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

long
sccread(Chan *c, void *buf, long n, ulong offset)
{
	SCC *sp = &scc[0]; int s;

	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, sccdir, NSCC, devgen);
	case Qtty1ctl:
		++sp;
		/* fall through */
	case Qtty0ctl:
		if(offset)
			return 0;
		s = splhi();
		*(uchar *)buf = *sp->ptr;
		splx(s);
		return 1;
	}
	return streamread(c, buf, n);
}

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

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

void
sccwstat(Chan *c, char *dp)
{
	error(Eperm);
}
.
## diffname port/devscc.c 1991/0604
## diff -e /n/bootesdump/1991/0601/sys/src/9/port/devscc.c /n/bootesdump/1991/0604/sys/src/9/port/devscc.c
334,338d
216,219c
	scc[0].ptr = &dev->ptra;
	scc[0].data = &dev->dataa;
	scc[1].ptr = &dev->ptrb;
	scc[1].data = &dev->datab;
.
211a
	dev = addr;
.
205a
	SCCdev *dev;
.
204c
sccsetup(void *addr)
.
200c
 *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
.
## diffname port/devscc.c 1991/0606
## diff -e /n/bootesdump/1991/0604/sys/src/9/port/devscc.c /n/bootesdump/1991/0606/sys/src/9/port/devscc.c
583c
		sccenable(sp);
.
374c
	sccenable(sp);
.
334c
sccenable(SCC *sp)
.
299c
				if(sp->delim[ch/8] & (1<<(ch&7)) )
.
104c
	uchar	delim[256/8];	/* characters that act as delimiters */
.
## diffname port/devscc.c 1991/0607
## diff -e /n/bootesdump/1991/0606/sys/src/9/port/devscc.c /n/bootesdump/1991/0607/sys/src/9/port/devscc.c
311d
308d
287d
## diffname port/devscc.c 1991/0727
## diff -e /n/bootesdump/1991/0607/sys/src/9/port/devscc.c /n/bootesdump/1991/0727/sys/src/9/port/devscc.c
372a

	if(iq){
		/*
		 *  Stupid HACK to undo a stupid hack
		 */ 
		if(iq == &kbdq)
			kbdq.putc = kbdcr2nl;
	}
.
## diffname port/devscc.c 1991/1003
## diff -e /n/bootesdump/1991/0727/sys/src/9/port/devscc.c /n/bootesdump/1991/1003/sys/src/9/port/devscc.c
510,511c
			/* obsolete */
.
447,449d
443,444d
402,430d
398,400d
383d
326a
void
sccclock(void)
{
	SCC *sp;
	IOQ *cq;

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

.
298,300d
296c
			else
.
104d
102d
## diffname port/devscc.c 1991/1115
## diff -e /n/bootesdump/1991/1003/sys/src/9/port/devscc.c /n/bootesdump/1991/1115/sys/src/9/port/devscc.c
676a
	USED(c, dp);
.
670a
	USED(c);
.
651c
	case Qeia0ctl:
.
648c
	case Qeia1ctl:
.
629a
	USED(c, name, omode, perm);
.
610,611c
	case Qeia1:
	case Qeia1ctl:
.
606,607c
	case Qeia0:
	case Qeia0ctl:
.
591,592c
	case Qeia1:
		streamstat(c, dp, "eia1");
.
588,589c
	case Qeia0:
		streamstat(c, dp, "eia0");
.
534,537c
	"eia0",		{Qeia0},	0,		0666,
	"eia0ctl",	{Qeia0ctl},	0,		0666,
	"eia1",		{Qeia1},	0,		0666,
	"eia1ctl",	{Qeia1ctl},	0,		0666,
.
527,530c
	Qeia0=		STREAMQID(0, Sdataqid),
	Qeia0ctl=	STREAMQID(0, Sctlqid),
	Qeia1=		STREAMQID(1, Sdataqid),
	Qeia1ctl=	STREAMQID(1, Sctlqid),
.
## diffname port/devscc.c 1991/1225
## diff -e /n/bootesdump/1991/1115/sys/src/9/port/devscc.c /n/bootesdump/1991/1225/sys/src/9/port/devscc.c
660c
	errors("bad qid");
.
646,658c
	if(c->qid.path == CHDIR)
		return devdirread(c, buf, n, sccdir, 2*nscc, devgen);

	switch(STREAMTYPE(c->qid.path)){
	case Sdataqid:
		return streamread(c, buf, n);
	case Sctlqid:
		sprint(b, "%d", STREAMID(c->qid.path));
		return stringread(buf, n, b, offset);
.
644c
	SCC *sp;
	char b[8];
.
624c
	}
	return devopen(c, omode, sccdir, 2*nscc, devgen);
.
605,622c
	if(c->qid.path != CHDIR){
		sp = scc[STREAMID(c->qid.path)];
		if(sp->nostream)
			errors("in use");
.
595c
		devstat(c, dp, sccdir, 2*nscc, devgen);
.
591,593d
587,589c
	int i;

	i = STREAMID(c->qid.path);
	switch(STREAMTYPE(c->qid.path)){
	case Sdataqid:
		streamstat(c, dp, sccdir[2*i].name);
.
581c
	return devwalk(c, name, sccdir, 2*nscc, devgen);
.
550c
	sccdir = ialloc(2 * nscc * sizeof(Dirtab), 0);
	dp = sccdir;
	for(i = 0; i < nscc; i++){
		/* 2 directory entries per port */
		sprint(dp->name, "eia%d", i);
		dp->qid.path = STREAMQID(i, Sdataqid);
		dp->perm = 0666;
		dp++;
		sprint(dp->name, "eia%dctl", i);
		dp->qid.path = STREAMQID(i, Sctlqid);
		dp->perm = 0666;
		dp++;

		/* set up queues if a stream port */
		sp = scc[i];
.
548a
	int i;
	Dirtab *dp;
.
543c
 *  create 2 directory entries for each 'sccsetup' ports.
 *  allocate the queues if no one else has.
.
533,541d
525,531c
Dirtab *sccdir;
.
464c
			if(BLEN(bp)>4 && strncmp((char*)(bp->rptr+1), "reak", 4) == 0)
				sccbreak(sp, 0);
			else
				sccsetbaud(sp, n);
.
433d
413c
	sp = scc[s->id];
.
374c
	SCC *sp = scc[port];
.
328c
	for(i = 0; i < nscc; i++){
		sp = scc[i];
.
326a
	int i;
.
317,319c
	for(i = 0; i < nscc; i += 2){
		x = sccrdreg(scc[i], 3);
		if(x & (ExtPendB|RxPendB|TxPendB))
			sccintr0(scc[i+1], x);
		x = x >> 3;
		if(x & (ExtPendB|RxPendB|TxPendB))
			sccintr0(scc[i], x);
	}
.
315a
	int i;
.
216,245c
	sp = ialloc(sizeof(SCC), 0);
	scc[nscc] = sp;
	sp->ptr = &dev->ptra;
	sp->data = &dev->dataa;
	sp->freq = freq;
	sccsetup0(sp);
	sp = ialloc(sizeof(SCC), 0);
	scc[nscc+1] = sp;
	sp->ptr = &dev->ptrb;
	sp->data = &dev->datab;
	sp->freq = freq;
	sccsetup0(sp);
	nscc += 2;
.
214c
	 *  allocate a structure, set port addresses, and setup the line
.
208,210d
206d
202c
sccsetup(void *addr, ulong freq)
.
200a
static void
sccsetup0(SCC *sp)
{
	memset(sp->sticky, 0, sizeof(sp->sticky));

	/*
	 *  turn on baud rate generator and set rate to 9600 baud.
	 *  use 1 stop bit.
	 */
	sp->sticky[14] = BRSource;
	sccwrreg(sp, 14, 0);
	sccsetbaud(sp, 9600);
	sp->sticky[4] = Rx1stop | X16;
	sccwrreg(sp, 4, 0);
	sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR | TRxCOI;
	sccwrreg(sp, 11, 0);
	sp->sticky[14] = BREna | BRSource;
	sccwrreg(sp, 14, 0);

	/*
	 *  enable I/O, 8 bits/character
	 */
	sp->sticky[3] = RxEna | Rx8bits;
	sccwrreg(sp, 3, 0);
	sp->sticky[5] = TxEna | Tx8bits;
	sccwrreg(sp, 5, 0);
}
.
185a
	if(ms == 0)
		ms = 100;
.
149a
	brconst = (sp->freq+16*rate-1)/(2*16*rate) - 2;

.
148c
	if(rate == 0)
		errors("bad baud rate");
.
105a
int	nscc;
SCC	*scc[8];	/* up to 4 8530's */

.
104d
91a
	ulong	freq;		/* clock frequency */
.
## diffname port/devscc.c 1992/0111
## diff -e /n/bootesdump/1991/1225/sys/src/9/port/devscc.c /n/bootesdump/1992/0111/sys/src/9/port/devscc.c
7c
#include	"../port/error.h"
.
## diffname port/devscc.c 1992/0114
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/devscc.c /n/bootesdump/1992/0114/sys/src/9/port/devscc.c
670c
	error(Egreg);
.
634c
			error(Einuse);
.
152c
		error(Ebadctl);
.
## diffname port/devscc.c 1992/0129
## diff -e /n/bootesdump/1992/0114/sys/src/9/port/devscc.c /n/bootesdump/1992/0129/sys/src/9/port/devscc.c
504a
			break;
		case 'X':
		case 'x':
			sp->xonoff = n;
.
312a
		if (sp->blocked) {
			sccwrreg(sp, 0, ResTxPend);
			sp->printing = 0;
			return;
		}
.
305a
			if (ch == CTLS && sp->xonoff)
				sp->blocked = 1;
			else if (ch == CTLQ && sp->xonoff) {
				sp->blocked = 0;
				sccputs(sp->oq, "", 0);
			}
.
275c
	if(sp->printing == 0 && sp->blocked==0){
.
107a
#define CTLS	023
#define CTLQ	021
.
103a

	/* idiot flow control */
	int	xonoff;		/* true if we obey this tradition */
	int	blocked;	/* abstinence */
.
## diffname port/devscc.c 1992/0321
## diff -e /n/bootesdump/1992/0129/sys/src/9/port/devscc.c /n/bootesdump/1992/0321/sys/src/9/port/devscc.c
2c
#include	"../port/lib.h"
.
## diffname port/devscc.c 1992/0326
## diff -e /n/bootesdump/1992/0321/sys/src/9/port/devscc.c /n/bootesdump/1992/0326/sys/src/9/port/devscc.c
509a
			break;
		case 'P':
		case 'p':
			sccparity(sp, *(bp->rptr+1));
.
165a
void
sccparity(SCC *sp, char type)
{
	int val;

	switch(type){
	case 'e':
		val = ParEven;
		break;
	case 'o':
		val = ParOdd;
		break;
	default:
		val = ParOff;
		break;
	}
	sp->sticky[4] = (sp->sticky[4] & ~ParMask) | val;
	sccwrreg(sp, 4, 0);
}

.
35a
	ParEven=	3<<0,
	ParOdd=		1<<0,
	ParOff=		0<<0,
	ParMask=	3<<0,
.
## diffname port/devscc.c 1992/0519
## diff -e /n/bootesdump/1992/0326/sys/src/9/port/devscc.c /n/bootesdump/1992/0519/sys/src/9/port/devscc.c
454d
## diffname port/devscc.c 1992/0522
## diff -e /n/bootesdump/1992/0519/sys/src/9/port/devscc.c /n/bootesdump/1992/0522/sys/src/9/port/devscc.c
718a
	return 0;	/* not reached */
.
## diffname port/devscc.c 1992/0602
## diff -e /n/bootesdump/1992/0522/sys/src/9/port/devscc.c /n/bootesdump/1992/0602/sys/src/9/port/devscc.c
106d
## diffname port/devscc.c 1992/0617
## diff -e /n/bootesdump/1992/0602/sys/src/9/port/devscc.c /n/bootesdump/1992/0617/sys/src/9/port/devscc.c
532a
		case 'L':
		case 'l':
			sccbits(sp, n);
			break;

.
189a
 *  set bits/character, default 8
 */
void
sccbits(SCC *sp, int n)
{
	int val;
	int rbits, tbits;

	switch(n){
	case 5:
		rbits = Rx5bits;
		tbits = Tx5bits;
		break;
	case 6:
		rbits = Rx6bits;
		tbits = Tx6bits;
		break;
	case 7:
		rbits = Rx7bits;
		tbits = Tx7bits;
		break;
	case 8:
	default:
		rbits = Rx8bits;
		tbits = Tx8bits;
		break;
	}
	sp->sticky[3] = (sp->sticky[3]&~Rxbitmask) | rbits;
	sccwrreg(sp, 3, 0);
	sp->sticky[5] = (sp->sticky[5]&~Txbitmask) | tbits;
	sccwrreg(sp, 5, 0);
}

/*
.
54a
	Txbitmask=	3<<5,
.
33a
	Rxbitmask=	3<<6,
.
## diffname port/devscc.c 1992/0620
## diff -e /n/bootesdump/1992/0617/sys/src/9/port/devscc.c /n/bootesdump/1992/0620/sys/src/9/port/devscc.c
650c
	sccdir = xalloc(2 * nscc * sizeof(Dirtab));
.
318c
	sp = xalloc(sizeof(SCC));
.
312c
	sp = xalloc(sizeof(SCC));
.
300a

.
## diffname port/devscc.c 1992/0622
## diff -e /n/bootesdump/1992/0620/sys/src/9/port/devscc.c /n/bootesdump/1992/0622/sys/src/9/port/devscc.c
670c
		sp->oq = xalloc(sizeof(IOQ));
.
668c
		sp->iq = xalloc(sizeof(IOQ));
.
## diffname port/devscc.c 1992/0623
## diff -e /n/bootesdump/1992/0622/sys/src/9/port/devscc.c /n/bootesdump/1992/0623/sys/src/9/port/devscc.c
757c
		return readstr(offset, buf, n, b);
.
## diffname port/devscc.c 1992/0711
## diff -e /n/bootesdump/1992/0623/sys/src/9/port/devscc.c /n/bootesdump/1992/0711/sys/src/9/port/devscc.c
765a
	USED(offset);
.
746d
197d
## diffname port/devscc.c 1992/0722
## diff -e /n/bootesdump/1992/0711/sys/src/9/port/devscc.c /n/bootesdump/1992/0722/sys/src/9/port/devscc.c
488a
void
sccrawput(int port, int c)
{
	SCC *sp = scc[port];

	if(c == '\n') {
		sccrawput(port, '\r');
		delay(100);
	}

	while((*sp->ptr&TxReady)==0)
		;
	*sp->data = c;
}

.
## diffname port/devscc.c 1992/0826
## diff -e /n/bootesdump/1992/0722/sys/src/9/port/devscc.c /n/bootesdump/1992/0826/sys/src/9/port/devscc.c
721c
		streamstat(c, dp, sccdir[2*i].name, sccdir[2*i].perm);
.
## diffname port/devscc.c 1992/0922
## diff -e /n/bootesdump/1992/0826/sys/src/9/port/devscc.c /n/bootesdump/1992/0922/sys/src/9/port/devscc.c
323c
	sccsetup0(sp, brsource);
.
317c
	sccsetup0(sp, brsource);
.
302c
sccsetup(void *addr, ulong freq, int brsource)
.
289c
	sp->sticky[14] = BREna;
	if(brsource)
		sp->sticky[14] |= BRSource;
.
287c
	sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR /*| TRxCOI*/;
.
274c
sccsetup0(SCC *sp, int brsource)
.
## diffname port/devscc.c 1992/1020
## diff -e /n/bootesdump/1992/0922/sys/src/9/port/devscc.c /n/bootesdump/1992/1020/sys/src/9/port/devscc.c
738c
		if(sp->special)
.
682c
		if(sp->special)
.
545a
	if(sp->special)
		return;

.
476c
	sp->special = 1;
.
101c
	int	special;	/* can't use the stream interface */
.
## diffname port/devscc.c 1992/1021
## diff -e /n/bootesdump/1992/1020/sys/src/9/port/devscc.c /n/bootesdump/1992/1021/sys/src/9/port/devscc.c
480c
	if(baud)
		sccsetbaud(sp, baud);
.
372c
			ch = *sp->data & sp->mask;
.
300a
	sp->mask = 0xff;
.
213a
		sp->mask = 0xff;
.
208a
		sp->mask = 0x7f;
.
204a
		sp->mask = 0x3f;
.
200a
		sp->mask = 0x1f;
.
98a
	uchar	mask;		/* bits/char */
.
## diffname port/devscc.c 1992/1104
## diff -e /n/bootesdump/1992/1021/sys/src/9/port/devscc.c /n/bootesdump/1992/1104/sys/src/9/port/devscc.c
287c
	sp->sticky[14] = brsource ? BRSource : 0;
.
## diffname port/devscc.c 1992/1201
## diff -e /n/bootesdump/1992/1104/sys/src/9/port/devscc.c /n/bootesdump/1992/1201/sys/src/9/port/devscc.c
710c
	return devattach(SCCTYPE, spec);
.
423a
	return j;
.
422c
			++j, sccintr0(scc[i], x);
.
419c
			++j, sccintr0(scc[i+1], x);
.
416c
	for(i = j = 0; i < nscc; i += 2){
.
414c
	int i, j;
.
410c
int
.
127a
#endif
.
120a
#ifdef	Zduart
#define	SCCTYPE	'z'
#define	onepointseven()
#else
#define	SCCTYPE	't'
.
## diffname port/devscc.c 1993/0226
## diff -e /n/bootesdump/1992/1201/sys/src/9/port/devscc.c /n/bootesdump/1993/0226/sys/src/9/port/devscc.c
597a
			break;
		case 'C':
		case 'c':
			sccextclk(sp, n);
.
588c
		if(*bp->rptr == '!')	/* do it now! */
			++bp->rptr;
		else while(cangetc(cq))	/* else let output drain */
.
488a
	/* let output drain */
	if(sp->oq){
		while(cangetc(sp->oq))
			sleep(&sp->oq->r, cangetc, sp->oq);
		tsleep(&sp->oq->r, cangetc, sp->oq, 50);
	}

.
235a
 *  set/clear external clock mode; the indigo uses the CTS pin,
 *  so we disable external interrupts.
 */
void
sccextclk(SCC *sp, int n)
{
	if(n){
		sp->sticky[1] &= ~ExtIntEna;
		sp->sticky[11] = TxClockTRxC | RxClockTRxC;
	}else{
		sp->sticky[1] |= ExtIntEna;
		sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR;
	}
	sccwrreg(sp, 1, 0);
	sccwrreg(sp, 11, 0);
}

/*
.
66a
	RxClockTRxC=	1<<5,
.
65a
	TxClockTRxC=	1<<3,
.
## diffname port/devscc.c 1993/0501
## diff -e /n/bootesdump/1993/0226/sys/src/9/port/devscc.c /n/fornaxdump/1993/0501/sys/src/brazil/port/devscc.c
627,630d
615,617c
		while (cangetc(cq))	/* let output drain */
.
509,515d
238,255d
68d
66d
## diffname port/devscc.c 1993/1124 # deleted
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/devscc.c /n/fornaxdump/1993/1124/sys/src/brazil/port/devscc.c
1,814d

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].