plan 9 kernel history: overview | file list | diff list

1993/0807/power/devduart.c (diff list | history)

power/devduart.c on 1991/0607
1991/0607    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/0607    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
1992/0111    
#include	"../port/error.h" 
1991/0607    
 
1993/0806    
#include	"devtab.h" 
#include	"../port/netif.h" 
1991/0607    
 
/* 
1993/0806    
 * Register set for half the duart.  
 * There are really two sets in adjacent memory locations. 
1991/0607    
 */ 
1992/0520    
struct Duartreg 
{ 
1993/0806    
	uchar	mr12;		/* Mode Register Channels 1 & 2 */ 
	uchar	pad0[15]; 
	uchar	srcsr;		/* Status Register/Clock Select Register */ 
	uchar	pad1[15]; 
	uchar	cmnd;		/* Command Register */ 
	uchar	pad2[15]; 
	uchar	data;		/* RX Holding / TX Holding Register */ 
	uchar	pad3[15]; 
	uchar	ipcacr;		/* Input Uart Change/Aux. Control Register */ 
	uchar	pad4[15]; 
	uchar	isimr;		/* Interrupt Status/Interrupt Mask Register */ 
	uchar	pad5[15]; 
	uchar	ctur;		/* Counter/Timer Upper Register */ 
	uchar	pad6[15]; 
	uchar	ctlr;		/* Counter/Timer Lower Register */ 
	uchar	pad7[15]; 
1991/0607    
}; 
1993/0806    
#define	ppcr	isimr		/* in the second register set */ 
1991/0607    
 
1993/0806    
enum 
{ 
	DBD75		= 0, 
	DBD110		= 1, 
	DBD38400	= 2, 
	DBD150		= 3, 
	DBD300		= 4, 
	DBD600		= 5, 
	DBD1200		= 6, 
	DBD2000		= 7, 
	DBD2400		= 8, 
	DBD4800		= 9, 
	DBD1800		= 10, 
	DBD9600		= 11, 
	DBD19200	= 12, 
	CHARERR		= 0x00,	/* MR1x - Mode Register 1 */ 
	EVENPAR		= 0x00, 
	ODDPAR		= 0x04, 
	NOPAR		= 0x10, 
	CBITS8		= 0x03, 
	CBITS7		= 0x02, 
	CBITS6		= 0x01, 
	CBITS5		= 0x00, 
	NORMOP		= 0x00,	/* MR2x - Mode Register 2 */ 
	TWOSTOPB	= 0x0F, 
	ONESTOPB	= 0x07, 
	ENBRX		= 0x01,	/* CRx - Command Register */ 
	DISRX		= 0x02, 
	ENBTX		= 0x04, 
	DISTX		= 0x08, 
	RESETMR 	= 0x10, 
	RESETRCV  	= 0x20, 
	RESETTRANS  	= 0x30, 
	RESETERR  	= 0x40, 
	RESETBCH	= 0x50, 
	STRTBRK		= 0x60, 
	STOPBRK		= 0x70, 
	RCVRDY		= 0x01,	/* SRx - Channel Status Register */ 
	FIFOFULL	= 0x02, 
	XMTRDY		= 0x04, 
	XMTEMT		= 0x08, 
	OVRERR		= 0x10, 
	PARERR		= 0x20, 
	FRMERR		= 0x40, 
	RCVDBRK		= 0x80, 
	IMIPC		= 0x80,	/* IMRx/ISRx - Int Mask/Interrupt Status */ 
	IMDBB		= 0x40, 
	IMRRDYB		= 0x20, 
	IMXRDYB		= 0x10, 
	IMCRDY		= 0x08, 
	IMDBA		= 0x04, 
	IMRRDYA		= 0x02, 
	IMXRDYA		= 0x01, 
	BD38400		= 0xCC|0x0000, 
	BD19200		= 0xCC|0x0100, 
	BD9600		= 0xBB|0x0000, 
	BD4800		= 0x99|0x0000, 
	BD2400		= 0x88|0x0000, 
	BD1200		= 0x66|0x0000, 
	BD300		= 0x44|0x0000, 
1991/0607    
 
1993/0806    
	Maxduart	= 8, 
1991/0607    
}; 
 
/* 
 *  requests to perform on a duart 
 */ 
1993/0806    
enum 
{ 
1991/0607    
	Dnone=	0, 
	Dbaud, 
	Dbreak, 
	Ddtr, 
	Dprint, 
	Dena, 
	Dstate, 
}; 
 
/* 
1992/0520    
 *  a duart 
1991/0607    
 */ 
1992/0520    
typedef struct Duart	Duart; 
struct Duart 
1991/0607    
{ 
	QLock; 
1992/0520    
	Duartreg	*reg;		/* duart registers */ 
	uchar		imr;		/* sticky interrupt mask reg bits */ 
	uchar		acr;		/* sticky auxiliary reg bits */ 
	int		inited; 
}; 
Duart duart[Maxduart]; 
1991/0607    
 
1992/0520    
/* 
 *  values specific to a single duart port 
 */ 
1993/0806    
typedef struct Uart	Uart; 
struct Uart 
1992/0520    
{ 
	QLock; 
	Duart		*d;		/* device */ 
	Duartreg	*reg;		/* duart registers (for this port) */ 
	int		c;		/* character to restart output */ 
	int		op;		/* operation requested */ 
	int		val;		/* value of operation */ 
	Rendez		opr;		/* waiot here for op to complete */ 
 
1993/0806    
	int		printing;	/* need kick */ 
	int		opens; 
	Rendez		r; 
1991/0607    
 
1993/0806    
	/* buffers */ 
	int	(*putc)(Queue*, int); 
	Queue	*iq; 
	Queue	*oq; 
1991/0607    
}; 
1993/0806    
Uart uart[2*Maxduart]; 
1991/0607    
 
1993/0806    
void	duartkick(Uart*); 
 
1991/0607    
/* 
 *  configure a duart port, default is 9600 baud, 8 bits/char, 1 stop bit, 
 *  no parity 
 */ 
void 
1993/0806    
duartsetup(Uart *p, Duart *d, int devno) 
1991/0607    
{ 
1992/0520    
	Duartreg *reg; 
1991/0607    
 
1992/0520    
	p->d = d; 
	reg = &d->reg[devno]; 
	p->reg = reg; 
1991/0607    
 
1993/0806    
	reg->cmnd = RESETRCV|DISTX|DISRX; 
	reg->cmnd = RESETTRANS; 
	reg->cmnd = RESETERR; 
	reg->cmnd = STOPBRK; 
1991/0607    
 
1993/0806    
	reg->cmnd = RESETMR; 
	reg->mr12 = NOPAR|CBITS8; 
	reg->mr12 = ONESTOPB; 
	reg->srcsr = (DBD9600<<4)|DBD9600; 
	reg->cmnd = ENBTX|ENBRX; 
 
	p->iq = qopen(4*1024, 0, 0, 0); 
	p->oq = qopen(4*1024, 0, duartkick, p); 
1991/0607    
} 
 
/* 
 *  init the duart on the current processor 
 */ 
void 
duartinit(void) 
{ 
1993/0806    
	Uart *p; 
1992/0520    
	Duart *d; 
1991/0607    
 
1992/0520    
	d = &duart[m->machno]; 
	if(d->inited) 
1991/0607    
		return; 
1993/0806    
 
1992/0520    
	d->reg = DUARTREG; 
1993/0806    
	d->imr = IMRRDYA|IMXRDYA|IMRRDYB|IMXRDYB; 
	d->reg->isimr = d->imr; 
1992/0520    
	d->acr = 0x80;			/* baud rate set 2 */ 
1993/0806    
	d->reg->ipcacr = d->acr; 
1991/0607    
 
1993/0806    
	p = &uart[2*m->machno]; 
 
1992/0520    
	duartsetup(p, d, 0); 
	p++; 
	duartsetup(p, d, 1); 
1992/0608    
	d->inited = 1; 
1991/0607    
} 
 
/* 
 *  enable a duart port 
 */ 
void 
1993/0806    
duartenable(Uart *p) 
1991/0607    
{ 
1993/0806    
	p->reg->cmnd = ENBTX|ENBRX; 
1991/0607    
} 
 
void 
duartenable0(void) 
{ 
1993/0806    
	DUARTREG->cmnd = ENBTX|ENBRX; 
1991/0607    
} 
 
void 
1993/0806    
duartbaud(Uart *p, int b) 
1991/0607    
{ 
1992/0519    
	int x; 
1991/0607    
 
	switch(b){ 
	case 38400: 
		x = BD38400; 
		break; 
	case 19200: 
		x = BD19200; 
		break; 
	case 9600: 
		x = BD9600; 
		break; 
	case 4800: 
		x = BD4800; 
		break; 
	case 2400: 
		x = BD2400; 
		break; 
	case 1200: 
		x = BD1200; 
		break; 
	case 300: 
		x = BD300; 
		break; 
	default: 
1992/0516    
		return; 
1991/0607    
	} 
	if(x & 0x0100) 
1992/0520    
		p->d->acr |= 0x80; 
1991/0607    
	else 
1992/0520    
		p->d->acr &= ~0x80; 
1993/0806    
	p->d->reg->ipcacr = p->d->acr; 
	p->reg->srcsr = x; 
1991/0607    
} 
 
void 
1993/0806    
duartdtr(Uart *p, int val) 
1991/0607    
{ 
	if (val) 
1992/0520    
		p->reg->ctlr = 0x01; 
1991/0607    
	else 
1992/0520    
		p->reg->ctur = 0x01; 
1991/0607    
} 
 
void 
1993/0806    
duartbreak(Uart *p, int val) 
1991/0607    
{ 
1992/0520    
	Duartreg *reg; 
1991/0607    
 
1992/0520    
	reg = p->reg; 
1991/0607    
	if (val){ 
1993/0806    
		p->d->imr &= ~IMXRDYB; 
		p->d->reg->isimr = p->d->imr; 
		reg->cmnd = STRTBRK|ENBTX; 
1991/0607    
	} else { 
1993/0806    
		reg->cmnd = STOPBRK|ENBTX; 
		p->d->imr |= IMXRDYB; 
		p->d->reg->isimr = p->d->imr; 
1991/0607    
	} 
} 
 
/* 
 *  do anything requested for this CPU's duarts 
 */ 
void 
1993/0806    
duartslave0(Uart *p) 
1991/0607    
{ 
1992/0520    
	switch(p->op){ 
1991/0607    
	case Ddtr: 
1992/0520    
		duartdtr(p, p->val); 
1991/0607    
		break; 
	case Dbaud: 
1992/0520    
		duartbaud(p, p->val); 
1991/0607    
		break; 
	case Dbreak: 
1992/0520    
		duartbreak(p, p->val); 
1991/0607    
		break; 
	case Dprint: 
1993/0806    
		p->reg->cmnd = ENBTX; 
1992/0520    
		p->reg->data = p->val; 
1991/0607    
		break; 
	case Dena: 
1992/0520    
		duartenable(p); 
1991/0607    
		break; 
	case Dstate: 
1992/0520    
		p->val = p->reg->ppcr; 
1991/0607    
		break; 
	} 
1992/0520    
	p->op = Dnone; 
	wakeup(&p->opr); 
1991/0607    
} 
void 
duartslave(void) 
{ 
1993/0806    
	Uart *p; 
1991/0607    
 
1993/0806    
	p = &uart[2*m->machno]; 
1992/0520    
	if(p->op != Dnone) 
		duartslave0(p); 
	p++; 
	if(p->op != Dnone) 
		duartslave0(p); 
1991/0607    
} 
 
1992/0519    
void 
1993/0806    
duartrintr(Uart *p) 
1991/0607    
{ 
	char ch; 
1993/0806    
	int status; 
	Duartreg *reg; 
1991/0607    
 
1992/0520    
	reg = p->reg; 
1993/0806    
	status = reg->srcsr; 
1992/0520    
	ch = reg->data; 
1993/0806    
	if(status & (FRMERR|OVRERR|PARERR)) 
		reg->cmnd = RESETERR; 
1991/0607    
 
1993/0806    
	if(p->putc) 
		(*p->putc)(p->iq, ch); 
1992/0519    
	else 
1993/0806    
		qproduce(p->iq, &ch, 1); 
1991/0607    
} 
 
1993/0806    
/* 
 *  (re)start output 
 */ 
1992/0519    
void 
1993/0806    
duartkick(Uart *p) 
1991/0607    
{ 
1993/0806    
	char ch; 
	int n, x; 
 
	x = splhi(); 
	if(p->printing) { 
		splx(x); 
		return; 
	} 
 
	n = qconsume(p->oq, &ch, 1); 
	if(n <= 0){ 
		splx(x); 
		return; 
	} 
 
	p->printing = 1; 
	p->val = ch; 
	p->op = Dprint; 
	splx(x); 
} 
 
void 
duartxintr(Uart *p) 
{ 
1993/0807    
	char ch; 
1993/0806    
	Duartreg *reg; 
1991/0607    
 
1992/0520    
	reg = p->reg; 
1993/0806    
	if(qconsume(p->oq, &ch, 1) <= 0) { 
1992/0520    
		p->printing = 0; 
1993/0806    
		reg->cmnd = DISTX; 
	} 
	else 
1992/0520    
		reg->data = ch; 
1991/0607    
} 
 
void 
duartintr(void) 
{ 
1992/0711    
	int cause; 
1992/0520    
	Duartreg *reg; 
1993/0806    
	Uart *p; 
1991/0607    
 
1993/0806    
	p = &uart[2*m->machno]; 
1992/0520    
	reg = p->reg; 
1993/0806    
	cause = reg->isimr; 
1992/0520    
 
1993/0806    
	if(cause & IMRRDYA) 
1992/0520    
		duartrintr(p); 
1993/0806    
 
	if(cause & IMXRDYA) 
1992/0520    
		duartxintr(p); 
1993/0806    
 
	if(cause & IMRRDYB) 
1992/0520    
		duartrintr(p+1); 
1993/0806    
 
	if(cause & IMXRDYB) 
1992/0520    
		duartxintr(p+1); 
1991/0607    
} 
 
/* 
 *  processor 0 only 
 */ 
int 
duartrawputc(int c) 
{ 
	int i; 
1993/0806    
	Duartreg *reg; 
1991/0607    
 
1992/0520    
	reg = DUARTREG; 
1993/0806    
	if(c == '\n') { 
1991/0607    
		duartrawputc('\r'); 
1993/0806    
		delay(100); 
	} 
	reg->cmnd = ENBTX; 
1991/0607    
	i = 0; 
1993/0806    
	while((reg->srcsr&XMTRDY) == 0 && i++ < 100000) 
		; 
1992/0520    
	reg->data = c; 
1991/0607    
	return c; 
} 
1993/0501    
 
1993/0806    
int 
1991/0607    
iprint(char *fmt, ...) 
{ 
1993/0806    
	int n, i; 
1993/0501    
	char buf[512]; 
1991/0607    
 
1993/0806    
	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
	for(i = 0; i < n; i++) 
		duartrawputc(buf[i]); 
	return n; 
1991/0607    
} 
 
void 
1993/0806    
duartspecial(int port, int s, Queue **in, Queue **out, int (*putc)(Queue*, int)) 
1991/0607    
{ 
1993/0806    
	Uart *p; 
1991/0607    
 
1993/0806    
	p = &uart[port]; 
1991/0607    
 
1993/0806    
	duartenable(p); 
	if(s) 
		duartbaud(p, s); 
1991/0607    
 
1993/0806    
	p->putc = putc; 
1993/0807    
	if(in != 0) 
1993/0806    
		*in = p->iq; 
1993/0807    
	if(out != 0) 
1993/0806    
		*out = p->oq; 
1991/0727    
 
1993/0806    
	p->opens++; 
1991/0607    
} 
 
static int 
1992/0519    
opdone(void *x) 
1991/0607    
{ 
1993/0806    
	Uart *p = x; 
1991/0607    
 
1992/0520    
	return p->op == Dnone; 
1991/0607    
} 
 
Dirtab *duartdir; 
1993/0806    
int nuart; 
1991/0607    
 
void 
duartreset(void) 
{ 
	int i; 
1993/0806    
	Dirtab *dp; 
1991/0607    
 
1993/0806    
	nuart = 2*conf.nmach; 
	duartdir = xalloc(2 * nuart * sizeof(Dirtab)); 
	dp = duartdir; 
	for(i = 0; i < nuart; i++){ 
		/* 2 directory entries per port */ 
		print(dp->name, "eia%d", i); 
		dp->qid.path = NETQID(i, Ndataqid); 
		dp->perm = 0666; 
		dp++; 
1991/0607    
 
1993/0806    
		print(dp->name, "eia%dctl", i); 
		dp->qid.path = NETQID(i, Nctlqid); 
		dp->perm = 0666; 
		dp++; 
1991/0607    
	} 
} 
 
Chan* 
duartattach(char *spec) 
{ 
	return devattach('t', spec); 
} 
 
Chan* 
duartclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
duartwalk(Chan *c, char *name) 
{ 
1993/0806    
	return devwalk(c, name, duartdir, 2*nuart, devgen); 
1991/0607    
} 
 
void 
1993/0806    
duartstat(Chan *c, char *dp) 
1991/0607    
{ 
1993/0806    
	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, duartdir[2*i].name, qlen(p->iq), eve, 0660, &dir); 
		convD2M(&dir, dp); 
1991/0607    
		break; 
	default: 
1993/0806    
		devstat(c, dp, duartdir, 2*nuart, devgen); 
1991/0607    
		break; 
	} 
} 
 
Chan* 
duartopen(Chan *c, int omode) 
{ 
1993/0806    
	Uart *p; 
1991/0607    
 
1993/0806    
	if(c->qid.path & CHDIR){ 
		if(omode != OREAD) 
			error(Ebadarg); 
	}  
	else { 
		p = &uart[NETID(c->qid.path)]; 
		qlock(p); 
		p->opens++; 
		if(p->opens == 1) { 
			/* enable the port */ 
			p->op = Dena; 
			sleep(&p->opr, opdone, p); 
		 
			qreopen(p->iq); 
			qreopen(p->oq); 
		} 
		qunlock(p); 
1991/0607    
	} 
 
1993/0806    
	c->mode = omode&~OTRUNC; 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
1991/0607    
} 
 
void 
duartcreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1993/0806    
	USED(c, name, omode, perm); 
1991/1120    
	error(Eperm); 
1991/0607    
} 
 
void 
duartclose(Chan *c) 
{ 
1993/0806    
	Uart *p; 
 
	if(c->qid.path & CHDIR) 
		return; 
 
	p = &uart[NETID(c->qid.path)]; 
	qlock(p); 
	p->opens++; 
	if(p->opens == 0){ 
		qclose(p->iq); 
		qclose(p->oq); 
	} 
	qunlock(p); 
1991/0607    
} 
 
long 
duartread(Chan *c, void *buf, long n, ulong offset) 
{ 
1993/0806    
	Uart *p; 
1991/0607    
 
1993/0806    
	if(c->qid.path & CHDIR) 
		return devdirread(c, buf, n, duartdir, 2*nuart, devgen); 
1991/0607    
 
1993/0806    
	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); 
1991/0607    
	} 
 
1993/0806    
	return 0; 
1991/0607    
} 
 
1993/0806    
static void 
duartctl(Uart *p, char *cmd) 
{ 
	int n, i; 
 
	/* let output drain for a while */ 
	for(i = 0; i < 16 && qlen(p->oq); i++) 
		tsleep(&p->r, qlen, p->oq, 125); 
 
	n = atoi(cmd+1); 
	switch(cmd[0]){ 
	case 'B': 
	case 'b': 
		p->val = n; 
		p->op = Dbaud; 
		sleep(&p->opr, opdone, p); 
		break; 
	case 'D': 
	case 'd': 
		p->val = n; 
		p->op = Ddtr; 
		sleep(&p->opr, opdone, p); 
		break; 
	case 'K': 
	case 'k': 
		p->val = 1; 
		p->op = Dbreak; 
		if(!waserror()){ 
			sleep(&p->opr, opdone, p); 
			tsleep(&p->opr, return0, 0, n); 
			poperror(); 
		} 
		p->val = 0; 
		p->op = Dbreak; 
		sleep(&p->opr, opdone, p); 
		break; 
	case 'R': 
	case 'r': 
		/* can't control? */ 
		break; 
	} 
} 
 
1991/0607    
long 
duartwrite(Chan *c, void *va, long n, ulong offset) 
{ 
1993/0806    
	Uart *p; 
	char cmd[32]; 
 
1992/0711    
	USED(offset); 
1993/0806    
 
	if(c->qid.path & CHDIR) 
		error(Eperm); 
 
	p = &uart[NETID(c->qid.path)]; 
	switch(NETTYPE(c->qid.path)){ 
	case Ndataqid: 
		return qwrite(p->oq, va, n, 0); 
	case Nctlqid: 
		if(n >= sizeof(cmd)) 
			n = sizeof(cmd)-1; 
		memmove(cmd, va, n); 
		cmd[n] = 0; 
		duartctl(p, cmd); 
		return n; 
	} 
1991/0607    
} 
 
void 
duartremove(Chan *c) 
{ 
1991/1214    
	USED(c); 
1992/0114    
	error(Eperm); 
1991/0607    
} 
 
void 
1992/0520    
duartwstat(Chan *c, char *p) 
1991/0607    
{ 
1993/0806    
	USED(c, p); 
1992/0114    
	error(Eperm); 
1991/1214    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)