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

1990/0227/port/devcons.c (diff list | history)

port/devcons.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
#include	"errno.h" 
 
#include	"devtab.h" 
 
static struct 
{ 
	Lock; 
	uchar	buf[4000]; 
	uchar	*in; 
	uchar	*out; 
	int	printing; 
	int	c; 
}printq; 
 
typedef struct IOQ	IOQ; 
 
#define	NQ	4096 
struct IOQ{ 
	union{ 
		Lock; 
		QLock; 
	}; 
	uchar	buf[NQ]; 
	uchar	*in; 
	uchar	*out; 
	int	state; 
	Rendez	r; 
}; 
 
IOQ	kbdq;		/* qlock to getc; interrupt putc's */ 
IOQ	lineq;		/* lock to getc; interrupt putc's */ 
 
void 
printinit(void) 
{ 
 
	printq.in = printq.buf; 
	printq.out = printq.buf; 
	lock(&printq);		/* allocate lock */ 
	unlock(&printq); 
 
	kbdq.in = kbdq.buf; 
	kbdq.out = kbdq.buf; 
	lineq.in = lineq.buf; 
	lineq.out = lineq.buf; 
	qlock(&kbdq);		/* allocate qlock */ 
	qunlock(&kbdq); 
	lock(&lineq);		/* allocate lock */ 
	unlock(&lineq); 
 
	duartinit(); 
} 
 
/* 
 * Put a string on the console. 
 * n bytes of s are guaranteed to fit in the buffer and is ready to print. 
 * Must be called splhi() and with printq locked. 
 */ 
void 
puts(char *s, int n) 
{ 
	if(!printq.printing){ 
		printq.printing = 1; 
		printq.c = *s++; 
		n--; 
	} 
	memcpy(printq.in, s, n); 
	printq.in += n; 
	if(printq.in >= printq.buf+sizeof(printq.buf)) 
		printq.in = printq.buf; 
} 
 
/* 
 * Print a string on the console.  This is the high level routine 
 * with a queue to the interrupt handler.  BUG: There is no check against 
 * overflow. 
 */ 
void 
putstrn(char *str, int n) 
{ 
	int s, c, m; 
	char *t; 
 
	s = splhi(); 
	lock(&printq); 
	while(n > 0){ 
		if(*str == '\n') 
			puts("\r", 1); 
		m = printq.buf+sizeof(printq.buf) - printq.in; 
		if(n < m) 
			m = n; 
		t = memchr(str+1, '\n', m-1); 
		if(t) 
			if(t-str < m) 
				m = t - str; 
		puts(str, m); 
		n -= m; 
		str += m; 
	} 
	unlock(&printq); 
	splx(s); 
} 
 
int 
cangetc(IOQ *q) 
{ 
	return q->in != q->out; 
} 
 
int 
isbrkc(IOQ *q) 
{ 
	uchar *p; 
 
	for(p=q->out; p!=q->in; ){ 
		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; 
} 
 
int 
sprint(char *s, char *fmt, ...) 
{ 
	char *out; 
 
	out = donprint(s, s+PRINTSIZE, fmt, (&fmt+1)); 
	return out-s; 
} 
 
int 
print(char *fmt, ...) 
{ 
	char buf[PRINTSIZE]; 
	int n; 
 
	n = donprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
	putstrn(buf, n); 
	return n; 
} 
 
void 
panic(char *fmt, ...) 
{ 
	char buf[PRINTSIZE]; 
	int n; 
 
	strcpy(buf, "panic: "); 
	n = donprint(buf+7, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
	buf[n] = '\n'; 
	putstrn(buf, n+1); 
	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)) 
		return; 
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid); 
	n = donprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf; 
	qlock(c); 
	if(waserror()){ 
		qunlock(c); 
		return; 
	} 
	(*devtab[c->type].write)(c, buf, n); 
	c->offset += n; 
	qunlock(c); 
	return n; 
} 
 
void 
prflush(void) 
{ 
	while(printq.printing) 
		delay(100); 
} 
 
/* 
 * Get character to print at interrupt time. 
 * Always called splhi from proc 0. 
 */ 
int 
conschar(void) 
{ 
	uchar *p; 
	int c; 
 
	lock(&printq); 
	p = printq.out; 
	if(p == printq.in){ 
		printq.printing = 0; 
		c = -1; 
	}else{ 
		c = *p++; 
		if(p >= printq.buf+sizeof(printq.buf)) 
			p = printq.buf; 
		printq.out = p; 
	} 
	unlock(&printq); 
	return c; 
} 
 
void 
echo(int c) 
{ 
	char ch; 
	/* 
	 * ^t hack BUG 
	 */ 
	if(c == 0x14) 
		DEBUG(); 
	else if(c == 0x0c) 
		LANCEDEBUG(); 
	else if(c == 0x02) 
		LANCEPRDEBQ(); 
	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) 
{ 
	if(c == '\r') 
		c = '\n'; 
	echo(c); 
	*kbdq.in++ = c; 
	if(kbdq.in == kbdq.buf+sizeof(kbdq.buf)) 
		kbdq.in = kbdq.buf; 
	if(c=='\n' || c==0x04) 
		wakeup(&kbdq.r); 
} 
 
void 
printslave(void) 
{ 
	int c; 
 
	c = printq.c; 
	if(c){ 
		printq.c = 0; 
		duartxmit(c); 
	} 
} 
 
int 
consactive(void) 
{ 
	return printq.in != printq.out; 
} 
 
/* 
 * I/O interface 
 */ 
enum{ 
	Qdir, 
	Qcons, 
	Qcputime, 
	Qnull, 
	Qpgrpid, 
	Qpid, 
	Qppid, 
	Qtime, 
	Quser, 
}; 
 
Dirtab consdir[]={ 
	"cons",		Qcons,		0,	0600, 
	"cputime",	Qcputime,	72,	0600, 
	"null",		Qnull,		0,	0600, 
	"pgrpid",	Qpgrpid,	12,	0600, 
	"pid",		Qpid,		12,	0600, 
	"ppid",		Qppid,		12,	0600, 
	"time",		Qtime,		12,	0600, 
	"user",		Quser,		0,	0600, 
}; 
 
#define	NCONS	(sizeof consdir/sizeof(Dirtab)) 
 
ulong	boottime;		/* seconds since epoch at boot */ 
 
long 
seconds(void) 
{ 
	return boottime + MACHP(0)->ticks*MS2HZ/1000; 
} 
 
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] = ' '; 
	off %= size; 
	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); 
	off %= size; 
	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) 
{ 
	return devwalk(c, name, consdir, NCONS, devgen); 
} 
 
void 
consstat(Chan *c, char *dp) 
{ 
	devstat(c, dp, consdir, NCONS, devgen); 
} 
 
Chan* 
consopen(Chan *c, int omode) 
{ 
	if(c->qid==Quser && omode==(OWRITE|OTRUNC)){ 
		/* truncate? */ 
		if(strcmp(u->p->pgrp->user, "bootes") == 0)	/* BUG */ 
			u->p->pgrp->user[0] = 0; 
		else 
			error(0, Eperm); 
	} 
	return devopen(c, omode, consdir, NCONS, devgen); 
} 
 
void 
conscreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	error(0, Eperm); 
} 
 
void 
consclose(Chan *c) 
{ 
} 
 
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; 
	switch(c->qid&~CHDIR){ 
	case Qdir: 
		return devdirread(c, buf, n, consdir, NCONS, devgen); 
 
	case Qcons: 
		qlock(&kbdq); 
		while(!cangetc(&lineq)){ 
			sleep(&kbdq.r, (int(*)(void*))isbrkc, &kbdq); 
			do{ 
				ch = getc(&kbdq); 
				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; 
				default: 
					*lineq.in++ = ch; 
					if(lineq.in == lineq.buf+sizeof(lineq.buf)) 
					lineq.in = lineq.buf; 
				} 
			}while(ch!='\n' && ch!=0x04); 
		} 
		i = 0; 
		while(n>0){ 
			ch = getc(&lineq); 
			if(ch == 0x04 || ch == -1) 
				break; 
			i++; 
			*cbuf++ = ch; 
			--n; 
		} 
		qunlock(&kbdq); 
		return i; 
 
	case Qcputime: 
		k = c->offset % sizeof tmp; 
		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; 
			l *= MS2HZ; 
			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: 
		return readnum(c->offset, buf, n, boottime+MACHP(0)->ticks/(1000/MS2HZ), 12); 
 
	case Quser: 
		return readstr(c->offset, buf, n, u->p->pgrp->user); 
 
	case Qnull: 
		return 0; 
 
	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; 
 
	switch(c->qid){ 
	case Qcons: 
		/* 
		 * 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; 
 
	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 */ 
			error(0, Eperm); 
		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: 
		error(0, Eperm); 
 
	case Qnull: 
		break; 
	default: 
		error(0, Egreg); 
	} 
	return n; 
} 
 
void 
consremove(Chan *c) 
{ 
	error(0, Eperm); 
} 
 
void 
conswstat(Chan *c, char *dp) 
{ 
	error(0, Eperm); 
} 
 
void 
conserrstr(Error *e, char *buf) 
{ 
	rooterrstr(e, buf); 
} 
 
void 
consuserstr(Error *e, char *buf) 
{ 
	strcpy(buf, u->p->pgrp->user); 
} 


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