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

1991/0221/gnot/devcons.c (diff list | history)

gnot/devcons.c on 1990/03091
1990/03091    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
#include	"errno.h" 
 
#include	"devtab.h" 
 
1990/0831    
typedef struct IOQ	IOQ; 
 
1990/03091    
static struct 
{ 
	Lock; 
	int	printing; 
	int	c; 
}printq; 
 
1990/08101    
#define	NQ	2048 
1990/03091    
struct IOQ{ 
	union{ 
		Lock; 
		QLock; 
	}; 
	uchar	buf[NQ]; 
	uchar	*in; 
	uchar	*out; 
	int	state; 
	Rendez	r; 
}; 
 
1990/0515    
IOQ	lineq; 
1990/03091    
 
1990/0321    
struct{ 
1990/0707    
	IOQ; 
	Lock	put; 
}klogq; 
 
struct{ 
1990/0321    
	IOQ;		/* qlock to getc; interrupt putc's */ 
	int	c; 
	int	repeat; 
	int	count; 
}kbdq; 
 
1990/0515    
Ref	raw;		/* whether kbd i/o is raw (rcons is open) */ 
 
1990/0831    
/* 
 *  rs232 stream module 
 */ 
typedef struct Rs232	Rs232; 
typedef struct IOBQ	IOBQ; 
 
1990/0901    
#define NBQ 6 
1990/0831    
struct IOBQ{ 
	Block	*bp[NBQ]; 
	int	w; 
	int	r; 
	int	f; 
}; 
#define NEXT(x) ((x+1)%NBQ) 
 
struct Rs232{ 
	QLock; 
	QLock	outlock; 
	IOQ	in; 
	IOBQ	out; 
	int	kstarted;	/* true if kproc started */ 
	Queue	*wq; 
	Alarm	*a;		/* alarm for waking the rs232 kernel process */ 
1990/0901    
	int	started; 
1990/0911    
	int	delay;		/* time between character input and waking kproc */ 
1990/0831    
	Rendez	r; 
}; 
 
Rs232 rs232; 
 
static void	rs232output(Rs232*); 
static void	rs232input(Rs232*); 
static void	rs232timer(Alarm*); 
static void	rs232kproc(void*); 
static void	rs232open(Queue*, Stream*); 
static void	rs232close(Queue*); 
static void	rs232oput(Queue*, Block*); 
1990/11151    
Qinfo rs232info = 
{ 
	nullput, 
	rs232oput, 
	rs232open, 
	rs232close, 
	"rs232" 
}; 
1990/0831    
 
1990/03091    
void 
printinit(void) 
{ 
 
	lock(&printq);		/* allocate lock */ 
	unlock(&printq); 
 
	kbdq.in = kbdq.buf; 
	kbdq.out = kbdq.buf; 
1990/0707    
	klogq.in = klogq.buf; 
	klogq.out = klogq.buf; 
1990/03091    
	lineq.in = lineq.buf; 
	lineq.out = lineq.buf; 
1990/0914    
	rs232.in.in = rs232.in.buf; 
	rs232.in.out = rs232.in.buf; 
1990/03091    
	qlock(&kbdq);		/* allocate qlock */ 
	qunlock(&kbdq); 
	lock(&lineq);		/* allocate lock */ 
	unlock(&lineq); 
1990/0707    
	lock(&klogq);		/* allocate lock */ 
	unlock(&klogq); 
1990/0914    
	lock(&klogq.put);	/* allocate lock */ 
1990/0707    
	unlock(&klogq.put); 
1990/03091    
 
	screeninit(); 
} 
 
/* 
 * Print a string on the console. 
 */ 
void 
putstrn(char *str, long n) 
{ 
	int s; 
 
	s = splhi(); 
	lock(&printq); 
	printq.printing = 1; 
	while(--n >= 0) 
		screenputc(*str++); 
	printq.printing = 0; 
	unlock(&printq); 
	splx(s); 
} 
 
int 
1990/08101    
cangetc(void *arg) 
1990/03091    
{ 
1990/08101    
	IOQ *q = (IOQ *)arg; 
1990/0707    
	int n = q->in - q->out; 
	if (n < 0) 
		n += sizeof(q->buf); 
	return n; 
1990/03091    
} 
 
int 
1990/08101    
canputc(void *arg) 
1990/0707    
{ 
1990/08101    
	IOQ *q = (IOQ *)arg; 
1990/0707    
	return sizeof(q->buf)-cangetc(q)-1; 
} 
 
int 
1990/08101    
isbrkc(void *arg) 
1990/03091    
{ 
1990/08101    
	IOQ *q = (IOQ *)arg; 
1990/03091    
	uchar *p; 
 
	for(p=q->out; p!=q->in; ){ 
1990/0515    
		if(raw.ref) 
			return 1; 
1990/03091    
		if(*p==0x04 || *p=='\n') 
			return 1; 
		p++; 
		if(p >= q->buf+sizeof(q->buf)) 
			p = q->buf; 
	} 
	return 0; 
} 
 
int 
getc(IOQ *q) 
{ 
	int c; 
 
	if(q->in == q->out) 
		return -1; 
	c = *q->out++; 
	if(q->out == q->buf+sizeof(q->buf)) 
		q->out = q->buf; 
	return c; 
} 
 
1990/0707    
int 
1990/0629    
putc(IOQ *q, int c) 
{ 
1990/0707    
	uchar *nextin; 
	if(q->in >= &q->buf[sizeof(q->buf)-1]) 
		nextin = q->buf; 
	else 
		nextin = q->in+1; 
	if(nextin == q->out) 
		return -1; 
	*q->in = c; 
	q->in = nextin; 
	return 0; 
1990/0629    
} 
 
1990/0707    
void 
putstrk(char *str, long n) 
{ 
	int s; 
 
	s = splhi(); 
	lock(&klogq.put); 
	while(--n >= 0){ 
		*klogq.in++ = *str++; 
		if(klogq.in == klogq.buf+sizeof(klogq.buf)) 
			klogq.in = klogq.buf; 
	} 
	unlock(&klogq.put); 
	splx(s); 
	wakeup(&klogq.r); 
} 
 
1990/03091    
int 
sprint(char *s, char *fmt, ...) 
{ 
1990/06111    
	return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s; 
1990/03091    
} 
 
int 
print(char *fmt, ...) 
{ 
	char buf[PRINTSIZE]; 
	int n; 
 
1990/06111    
	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
1990/03091    
	putstrn(buf, n); 
	return n; 
} 
 
1990/0707    
int 
kprint(char *fmt, ...) 
{ 
	char buf[PRINTSIZE]; 
	int n; 
 
	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
	putstrk(buf, n); 
	return n; 
} 
 
1990/03091    
void 
panic(char *fmt, ...) 
{ 
	char buf[PRINTSIZE]; 
	int n; 
 
	strcpy(buf, "panic: "); 
1990/06111    
	n = doprint(buf+7, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
1990/03091    
	buf[n] = '\n'; 
	putstrn(buf, n+1); 
1991/0221    
	dumpstack(); 
1990/03091    
	exit(); 
} 
int 
pprint(char *fmt, ...) 
{ 
	char buf[2*PRINTSIZE]; 
	Chan *c; 
	int n; 
 
	c = u->fd[2]; 
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) 
1990/0321    
		return 0; 
1990/03091    
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid); 
1990/06111    
	n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
1990/03091    
	qlock(c); 
	if(waserror()){ 
		qunlock(c); 
1990/0321    
		return 0; 
1990/03091    
	} 
	(*devtab[c->type].write)(c, buf, n); 
	c->offset += n; 
	qunlock(c); 
1990/0321    
	poperror(); 
1990/03091    
	return n; 
} 
 
void 
prflush(void) 
{ 
	while(printq.printing) 
		delay(100); 
} 
 
void 
echo(int c) 
{ 
	char ch; 
1990/0918    
	static int ctrlt; 
1990/03091    
 
	/* 
	 * ^t hack BUG 
	 */ 
1990/0918    
	if(ctrlt == 2){ 
		ctrlt = 0; 
		switch(c){ 
		case 0x14: 
			break;	/* pass it on */ 
		case 'p': 
			DEBUG(); 
			return; 
		case 'q': 
			dumpqueues(); 
			return; 
1991/0112    
		case 'r': 
			panic("you asked for it"); 
			break; 
1990/0918    
		case 'm': 
			mntdump(); 
			return; 
1990/1212    
		case 'i': 
			incontoggle(); 
			return; 
1990/0918    
		} 
	}else if(c == 0x14){ 
		ctrlt++; 
		return; 
	} 
	ctrlt = 0; 
1990/0515    
	if(raw.ref) 
		return; 
1990/03091    
	if(c == 0x15) 
		putstrn("^U\n", 3); 
	else{ 
		ch = c; 
		putstrn(&ch, 1); 
	} 
} 
 
/* 
 * Put character into read queue at interrupt time. 
 * Always called splhi from proc 0. 
 */ 
void 
kbdchar(int c) 
{ 
1990/0321    
	if(kbdq.repeat == 1){ 
		kbdq.c = c; 
		kbdq.count = 0; 
		kbdq.repeat = 2; 
	} 
1990/03091    
	echo(c); 
	*kbdq.in++ = c; 
	if(kbdq.in == kbdq.buf+sizeof(kbdq.buf)) 
		kbdq.in = kbdq.buf; 
1990/0515    
	if(raw.ref || c=='\n' || c==0x04) 
1990/03091    
		wakeup(&kbdq.r); 
1990/0321    
} 
 
void 
kbdrepeat(int rep) 
{ 
	if(rep) 
		kbdq.repeat = 1; 
	else 
		kbdq.repeat = 0; 
} 
 
void 
kbdclock(void) 
{ 
	if(kbdq.repeat==2 && (++kbdq.count&1)) 
		kbdchar(kbdq.c); 
1990/03091    
} 
 
int 
consactive(void) 
{ 
	return printq.printing; 
} 
 
/* 
 * I/O interface 
 */ 
enum{ 
	Qdir, 
	Qcons, 
	Qcputime, 
	Qnull, 
	Qpgrpid, 
	Qpid, 
	Qppid, 
1990/0515    
	Qrcons, 
1990/03091    
	Qtime, 
	Quser, 
1990/0707    
	Qklog, 
1990/08101    
	Qmsec, 
	Qclock, 
1990/0905    
	Qrs232ctl = STREAMQID(1, Sctlqid), 
1990/0831    
	Qrs232 = STREAMQID(1, Sdataqid), 
1990/03091    
}; 
 
Dirtab consdir[]={ 
1990/11211    
	"cons",		{Qcons},	0,		0600, 
	"cputime",	{Qcputime},	6*NUMSIZE,	0600, 
	"null",		{Qnull},	0,		0600, 
	"pgrpid",	{Qpgrpid},	NUMSIZE,	0600, 
	"pid",		{Qpid},		NUMSIZE,	0600, 
	"ppid",		{Qppid},	NUMSIZE,	0600, 
	"rcons",	{Qrcons},	0,		0600, 
	"rs232",	{Qrs232},	0,		0600, 
	"rs232ctl",	{Qrs232ctl},	0,		0600, 
	"time",		{Qtime},	NUMSIZE,	0600, 
	"user",		{Quser},	0,		0600, 
	"klog",		{Qklog},	0,		0400, 
	"msec",		{Qmsec},	NUMSIZE,	0400, 
	"clock",	{Qclock},	2*NUMSIZE,	0400, 
1990/03091    
}; 
 
#define	NCONS	(sizeof consdir/sizeof(Dirtab)) 
 
1990/0707    
static int 
consgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) 
{ 
	if(tab==0 || i>=ntab) 
		return -1; 
	tab += i; 
	devdir(c, tab->qid, tab->name, tab->length, tab->perm, dp); 
	return 1; 
} 
 
1990/03091    
ulong	boottime;		/* seconds since epoch at boot */ 
 
long 
seconds(void) 
{ 
1990/06111    
	return boottime + TK2SEC(MACHP(0)->ticks); 
1990/03091    
} 
 
int 
readnum(ulong off, char *buf, ulong n, ulong val, int size) 
{ 
	char tmp[64]; 
	Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG }; 
 
	numbconv(&op, 10); 
	tmp[size-1] = ' '; 
1990/0312    
	if(off >= size) 
		return 0; 
1990/03091    
	if(off+n > size) 
		n = size-off; 
	memcpy(buf, tmp+off, n); 
	return n; 
} 
 
int 
readstr(ulong off, char *buf, ulong n, char *str) 
{ 
	int size; 
 
	size = strlen(str); 
1990/0312    
	if(off >= size) 
		return 0; 
1990/03091    
	if(off+n > size) 
		n = size-off; 
	memcpy(buf, str+off, n); 
	return n; 
} 
 
void 
consreset(void) 
{ 
} 
 
void 
consinit(void) 
{ 
} 
 
Chan* 
consattach(char *spec) 
{ 
	return devattach('c', spec); 
} 
 
Chan* 
consclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
conswalk(Chan *c, char *name) 
{ 
1990/0707    
	return devwalk(c, name, consdir, NCONS, consgen); 
1990/03091    
} 
 
void 
consstat(Chan *c, char *dp) 
{ 
1990/11211    
	switch(c->qid.path){ 
1990/0831    
	case Qrs232: 
		streamstat(c, dp, "rs232"); 
		break; 
	default: 
		devstat(c, dp, consdir, NCONS, consgen); 
		break; 
	} 
1990/03091    
} 
 
Chan* 
consopen(Chan *c, int omode) 
{ 
1990/0515    
	int ch; 
 
1990/11211    
	switch(c->qid.path){ 
1990/0905    
	case Quser: 
		if(omode==(OWRITE|OTRUNC)){ 
			/* truncate? */ 
			if(strcmp(u->p->pgrp->user, "bootes") == 0)	/* BUG */ 
				u->p->pgrp->user[0] = 0; 
			else 
1990/11211    
				error(Eperm); 
1990/0905    
		} 
		break; 
	case Qrcons: 
1990/0629    
		if(incref(&raw) == 1){ 
1990/0515    
			lock(&lineq); 
			while((ch=getc(&kbdq)) != -1){ 
				*lineq.in++ = ch; 
				if(lineq.in == lineq.buf+sizeof(lineq.buf)) 
					lineq.in = lineq.buf; 
			} 
			unlock(&lineq); 
		} 
1990/0905    
		break; 
	case Qrs232: 
	case Qrs232ctl: 
1990/0831    
		streamopen(c, &rs232info); 
1990/0905    
		break; 
	} 
1990/0707    
	return devopen(c, omode, consdir, NCONS, consgen); 
1990/03091    
} 
 
void 
conscreate(Chan *c, char *name, int omode, ulong perm) 
{ 
1990/11211    
	error(Eperm); 
1990/03091    
} 
 
void 
consclose(Chan *c) 
{ 
1990/11211    
	if(c->qid.path==Qrcons && (c->flag&COPEN)) 
1990/0515    
		decref(&raw); 
1990/1024    
	if(c->stream) 
1990/0831    
		streamclose(c); 
1990/03091    
} 
 
long 
consread(Chan *c, void *buf, long n) 
{ 
	int ch, i, j, k; 
	ulong l; 
	uchar *out; 
	char *cbuf = buf; 
	char *user; 
	int userlen; 
	char tmp[6*NUMSIZE]; 
 
	if(n <= 0) 
		return n; 
1990/11211    
	switch(c->qid.path&~CHDIR){ 
1990/03091    
	case Qdir: 
1990/0707    
		return devdirread(c, buf, n, consdir, NCONS, consgen); 
1990/03091    
 
1990/0515    
	case Qrcons: 
1990/03091    
	case Qcons: 
		qlock(&kbdq); 
1990/0617    
		if(waserror()){ 
			qunlock(&kbdq); 
			nexterror(); 
		} 
1990/03091    
		while(!cangetc(&lineq)){ 
1990/08101    
			sleep(&kbdq.r, isbrkc, &kbdq); 
1990/03091    
			do{ 
1990/0515    
				lock(&lineq); 
1990/03091    
				ch = getc(&kbdq); 
1990/0515    
				if(raw.ref){ 
					unlock(&lineq); 
					goto Default; 
				} 
1990/03091    
				switch(ch){ 
				case '\b': 
					if(lineq.in != lineq.out){ 
						if(lineq.in == lineq.buf) 
							lineq.in = lineq.buf+sizeof(lineq.buf); 
						lineq.in--; 
					} 
					break; 
				case 0x15: 
					lineq.in = lineq.out; 
					break; 
1990/0515    
				Default: 
1990/03091    
				default: 
					*lineq.in++ = ch; 
					if(lineq.in == lineq.buf+sizeof(lineq.buf)) 
1990/0515    
						lineq.in = lineq.buf; 
1990/03091    
				} 
1990/0515    
				unlock(&lineq); 
			}while(raw.ref==0 && ch!='\n' && ch!=0x04); 
1990/03091    
		} 
		i = 0; 
1990/0515    
		while(n > 0){ 
1990/03091    
			ch = getc(&lineq); 
1990/0515    
			if(ch==-1 || (raw.ref==0 && ch==0x04)) 
1990/03091    
				break; 
			i++; 
			*cbuf++ = ch; 
			--n; 
		} 
		qunlock(&kbdq); 
		return i; 
 
1990/0629    
	case Qrs232: 
1990/0831    
		return streamread(c, buf, n); 
1990/0629    
 
1990/0808    
	case Qrs232ctl: 
1990/0830    
		if(c->offset) 
			return 0; 
		*(char *)buf = duartinputport(); 
		return 1; 
1990/0808    
 
1990/03091    
	case Qcputime: 
1990/0312    
		k = c->offset; 
		if(k >= sizeof tmp) 
			return 0; 
1990/03091    
		if(k+n > sizeof tmp) 
			n = sizeof tmp - k; 
		/* easiest to format in a separate buffer and copy out */ 
		for(i=0; i<6 && NUMSIZE*i<k+n; i++){ 
			l = u->p->time[i]; 
			if(i == TReal) 
				l = MACHP(0)->ticks - l; 
1990/06111    
			l = TK2MS(l); 
1990/03091    
			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 
		} 
		memcpy(buf, tmp+k, n); 
		return n; 
 
	case Qpgrpid: 
		return readnum(c->offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE); 
 
	case Qpid: 
		return readnum(c->offset, buf, n, u->p->pid, NUMSIZE); 
 
	case Qppid: 
		return readnum(c->offset, buf, n, u->p->parentpid, NUMSIZE); 
 
	case Qtime: 
1990/08101    
		return readnum(c->offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), NUMSIZE); 
1990/03091    
 
1990/08101    
	case Qmsec: 
		return readnum(c->offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE); 
	case Qclock: 
		k = c->offset; 
		if(k >= 2*NUMSIZE) 
			return 0; 
		if(k+n > 2*NUMSIZE) 
			n = 2*NUMSIZE - k; 
		readnum(0, tmp, NUMSIZE, MACHP(0)->ticks, NUMSIZE); 
		readnum(0, tmp+NUMSIZE, NUMSIZE, HZ, NUMSIZE); 
		memcpy(buf, tmp+k, n); 
		return n; 
 
1990/03091    
	case Quser: 
		return readstr(c->offset, buf, n, u->p->pgrp->user); 
 
	case Qnull: 
		return 0; 
 
1990/0707    
	case Qklog: 
		qlock(&klogq); 
		if(waserror()){ 
			qunlock(&klogq); 
			nexterror(); 
		} 
		while(!cangetc(&klogq)) 
1990/08101    
			sleep(&klogq.r, cangetc, &klogq); 
1990/0707    
		for(i=0; i<n; i++){ 
			if((ch=getc(&klogq)) == -1) 
				break; 
			*cbuf++ = ch; 
		} 
1990/08101    
		poperror(); 
1990/0707    
		qunlock(&klogq); 
		return i; 
 
1990/03091    
	default: 
		panic("consread %lux\n", c->qid); 
		return 0; 
	} 
} 
 
long 
conswrite(Chan *c, void *va, long n) 
{ 
	char cbuf[64]; 
	char buf[256]; 
	long l, m; 
	char *a = va; 
 
1990/11211    
	switch(c->qid.path){ 
1990/03091    
	case Qcons: 
1990/0515    
	case Qrcons: 
1990/03091    
		/* 
		 * Damn. Can't page fault in putstrn, so copy the data locally. 
		 */ 
		l = n; 
		while(l > 0){ 
			m = l; 
			if(m > sizeof buf) 
				m = sizeof buf; 
			memcpy(buf, a, m); 
			putstrn(a, m); 
			a += m; 
			l -= m; 
		} 
		break; 
 
1990/0629    
	case Qrs232: 
1990/0905    
	case Qrs232ctl: 
1990/0831    
		n = streamwrite(c, va, n, 1); 
1990/0808    
		break; 
 
1990/03091    
	case Qtime: 
		if(n<=0 || boottime!=0)	/* only one write please */ 
			return 0; 
		if(n >= sizeof cbuf) 
			n = sizeof cbuf - 1; 
		memcpy(cbuf, a, n); 
		cbuf[n-1] = 0; 
		boottime = strtoul(a, 0, 0); 
		break; 
 
	case Quser: 
		if(u->p->pgrp->user[0])		/* trying to overwrite /dev/user */ 
1990/11211    
			error(Eperm); 
1990/03091    
		if(c->offset >= NAMELEN-1) 
			return 0; 
		if(c->offset+n >= NAMELEN-1) 
			n = NAMELEN-1 - c->offset; 
		memcpy(u->p->pgrp->user+c->offset, a, n); 
		u->p->pgrp->user[c->offset+n] = 0; 
		break; 
 
	case Qcputime: 
	case Qpgrpid: 
	case Qpid: 
	case Qppid: 
1990/11211    
		error(Eperm); 
1990/03091    
 
	case Qnull: 
		break; 
	default: 
1990/11211    
		error(Egreg); 
1990/03091    
	} 
	return n; 
} 
 
void 
consremove(Chan *c) 
{ 
1990/11211    
	error(Eperm); 
1990/03091    
} 
 
void 
conswstat(Chan *c, char *dp) 
{ 
1990/11211    
	error(Eperm); 
1990/0831    
} 
 
/* 
 *  rs232 stream routines 
1990/0905    
 * 
 *  A kernel process, rs232kproc, stages blocks to be output and 
 *  packages input bytes into stream blocks to send upstream. 
 *  The process is awakened whenever the interrupt side is almost 
 *  out of bytes to xmit or 1/16 second has elapsed since a byte 
 *  was input. 
1990/0831    
 */ 
1990/0905    
static int 
rs232empty(void *a) 
{ 
	Rs232 *r; 
 
	r = a; 
	return r->out.w == r->out.r; 
} 
 
1990/0831    
static void 
rs232output(Rs232 *r) 
{ 
	int next; 
	Queue *q; 
	Block *bp; 
1990/0905    
	long l; 
1990/0831    
 
	qlock(&r->outlock); 
	q = r->wq; 
 
	/* 
1990/0911    
	 *  free old blocks 
	 */ 
	for(next = r->out.f; next != r->out.r; next = NEXT(next)){ 
		freeb(r->out.bp[next]); 
		r->out.bp[next] = 0; 
	} 
	r->out.f = next; 
 
	/* 
1990/0831    
	 *  stage new blocks 
1990/0905    
	 * 
	 *  if we run into a control block, wait till the queue 
	 *  is empty before doing the control. 
1990/0831    
	 */ 
1990/0911    
	for(next = NEXT(r->out.w); next != r->out.f; next = NEXT(next)){ 
1990/0831    
		bp = getq(q); 
1990/0901    
		if(bp == 0) 
			break; 
1990/0905    
		if(bp->type == M_CTL){ 
			while(!rs232empty(r)) 
				sleep(&r->r, rs232empty, r); 
			l = strtoul((char *)(bp->rptr+1), 0, 0); 
			switch(*bp->rptr){ 
			case 'B': 
1990/0911    
			case 'b': 
				duartbaud(l); 
				break; 
1990/0905    
			case 'D': 
1990/0911    
			case 'd': 
				duartdtr(l); 
				break; 
1990/0905    
			case 'K': 
1990/0911    
			case 'k': 
				duartbreak(l); 
				break; 
			case 'W': 
			case 'w': 
				if(l>=0 && l<1000) 
					r->delay = l; 
				break; 
1990/0905    
			} 
			freeb(bp); 
			break; 
		} 
1990/0901    
		r->out.bp[r->out.w] = bp; 
1990/0831    
		r->out.w = next; 
	} 
 
	/* 
1990/0901    
	 *  start output, the spl's sync with interrupt level 
	 *  this wouldn't work on a multi-processor 
1990/0831    
	 */ 
1990/0901    
	splhi(); 
	if(r->started == 0){ 
		r->started = 1; 
1990/0831    
		duartstartrs232o(); 
	} 
1990/0901    
	spllo(); 
1990/0831    
	qunlock(&r->outlock); 
} 
 
static void 
rs232input(Rs232 *r) 
{ 
	Queue *q; 
1990/0901    
	int c; 
1990/0831    
	Block *bp; 
 
	q = RD(r->wq); 
	bp = 0; 
	while((c = getc(&r->in)) >= 0){ 
		if(bp == 0){ 
			bp = allocb(64); 
1990/0901    
			bp->flags |= S_DELIM; 
1990/0831    
		} 
		*bp->wptr++ = c; 
		if(bp->wptr == bp->lim){ 
			if(QFULL(q->next)) 
				freeb(bp); 
			else 
				PUTNEXT(q, bp); 
			bp = 0; 
		} 
	} 
	if(bp){ 
		if(QFULL(q->next)) 
			freeb(bp); 
		else 
			PUTNEXT(q, bp); 
	} 
} 
 
static int 
rs232stuff(void *arg) 
{ 
	Rs232 *r; 
 
	r = arg; 
	return (r->in.in != r->in.out) || (r->out.r != r->out.w) 
		|| (r->out.f != r->out.r); 
} 
 
static void 
rs232kproc(void *a) 
{ 
	Rs232 *r; 
 
	r = a; 
	for(;;){ 
		qlock(r); 
		if(r->wq != 0){ 
			rs232output(r); 
			rs232input(r); 
		} 
		qunlock(r); 
		sleep(&r->r, rs232stuff, r); 
	} 
} 
 
static void 
rs232open(Queue *q, Stream *c) 
{ 
	Rs232 *r; 
 
	r = &rs232; 
 
	RD(q)->ptr = r; 
	WR(q)->ptr = r; 
	r->wq = WR(q); 
 
	if(r->kstarted == 0){ 
		r->in.in = r->in.out = r->in.buf; 
		kproc("rs232", rs232kproc, r); 
		r->kstarted = 1; 
	} 
} 
 
static void 
rs232close(Queue *q) 
{ 
	Rs232 *r; 
 
	r = q->ptr; 
	qlock(r); 
	r->wq = 0; 
	qunlock(r); 
} 
 
static void 
rs232oput(Queue *q, Block *bp) 
{ 
1990/0911    
	if(bp->rptr >= bp->wptr) 
1990/0831    
		freeb(bp); 
	else 
		putq(q, bp); 
	rs232output(q->ptr); 
} 
 
static void 
rs232timer(Alarm *a) 
{ 
	Rs232 *r; 
 
	r = a->arg; 
	cancel(a); 
	r->a = 0; 
	wakeup(&r->r); 
} 
 
1990/0901    
/* 
 *  called by input interrupt.  runs splhi 
 */ 
1990/0831    
void 
rs232ichar(int c) 
{ 
	Rs232 *r; 
 
	r = &rs232; 
1990/0901    
	if(putc(&r->in, c) < 0) 
		screenputc('^'); 
 
	/* 
	 *  pass upstream within 1/16 second 
	 */ 
1990/0911    
	if(r->a==0){ 
		if(r->delay == 0) 
			wakeup(&r->r); 
		else 
			r->a = alarm(r->delay, rs232timer, r); 
	} 
1990/0831    
} 
 
1990/0901    
/* 
 *  called by output interrupt.  runs splhi 
 */ 
1990/0831    
int 
getrs232o(void) 
{ 
1990/0901    
	uchar c; 
1990/0831    
	Rs232 *r; 
	Block *bp; 
 
	r = &rs232; 
	if(r->out.r == r->out.w){ 
1990/0901    
		r->started = 0; 
1990/0831    
		return -1; 
	} 
	bp = r->out.bp[r->out.r]; 
	c = *bp->rptr++; 
	if(bp->rptr >= bp->wptr){ 
		r->out.r = NEXT(r->out.r); 
		if(r->out.r==r->out.w || NEXT(r->out.r)==r->out.w) 
			wakeup(&r->r); 
	} 
	return c; 
1990/03091    
} 


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