Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/ss/devcons.c

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


## diffname ss/devcons.c 1990/1223
## diff -e /dev/null /n/bootesdump/1990/1223/sys/src/9/sparc/devcons.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"

typedef struct IOQ	IOQ;

static struct
{
	Lock;
	int	printing;
	int	c;
}printq;

#define	NQ	2048
struct IOQ{
	union{
		Lock;
		QLock;
	};
	uchar	buf[NQ];
	uchar	*in;
	uchar	*out;
	int	state;
	Rendez	r;
};

IOQ	lineq;

struct{
	IOQ;
	Lock	put;
}klogq;

struct{
	IOQ;		/* qlock to getc; interrupt putc's */
	int	c;
	int	repeat;
	int	count;
}kbdq;

Ref	raw;		/* whether kbd i/o is raw (rcons is open) */

/*
 *  rs232 stream module
 */
typedef struct Rs232	Rs232;
typedef struct IOBQ	IOBQ;

#define NBQ 6
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 */
	int	started;
	int	delay;		/* time between character input and waking kproc */
	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*);
Qinfo rs232info =
{
	nullput,
	rs232oput,
	rs232open,
	rs232close,
	"rs232"
};

void
printinit(void)
{

	lock(&printq);		/* allocate lock */
	unlock(&printq);

	kbdq.in = kbdq.buf;
	kbdq.out = kbdq.buf;
	klogq.in = klogq.buf;
	klogq.out = klogq.buf;
	lineq.in = lineq.buf;
	lineq.out = lineq.buf;
	rs232.in.in = rs232.in.buf;
	rs232.in.out = rs232.in.buf;
	qlock(&kbdq);		/* allocate qlock */
	qunlock(&kbdq);
	lock(&lineq);		/* allocate lock */
	unlock(&lineq);
	lock(&klogq);		/* allocate lock */
	unlock(&klogq);
	lock(&klogq.put);	/* allocate lock */
	unlock(&klogq.put);

	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
cangetc(void *arg)
{
	IOQ *q = (IOQ *)arg;
	int n = q->in - q->out;
	if (n < 0)
		n += sizeof(q->buf);
	return n;
}

int
canputc(void *arg)
{
	IOQ *q = (IOQ *)arg;
	return sizeof(q->buf)-cangetc(q)-1;
}

int
isbrkc(void *arg)
{
	IOQ *q = (IOQ *)arg;
	uchar *p;

	for(p=q->out; p!=q->in; ){
		if(raw.ref)
			return 1;
		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
putc(IOQ *q, int c)
{
	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;
}

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);
}

int
sprint(char *s, char *fmt, ...)
{
	return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s;
}

int
print(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	putstrn(buf, n);
	return n;
}

int
kprint(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	putstrk(buf, n);
	return n;
}

void
panic(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	strcpy(buf, "panic: ");
	n = doprint(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 0;
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);
	n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	qlock(c);
	if(waserror()){
		qunlock(c);
		return 0;
	}
	(*devtab[c->type].write)(c, buf, n);
	c->offset += n;
	qunlock(c);
	poperror();
	return n;
}

void
prflush(void)
{
	while(printq.printing)
		delay(100);
}

void
echo(int c)
{
	char ch;
	static int ctrlt;

	/*
	 * ^t hack BUG
	 */
	if(ctrlt == 2){
		ctrlt = 0;
		switch(c){
		case 0x14:
			break;	/* pass it on */
		case 'p':
			DEBUG();
			return;
		case 'q':
			dumpqueues();
			return;
		case 'm':
			mntdump();
			return;
		case 'i':
			incontoggle();
			return;
		}
	}else if(c == 0x14){
		ctrlt++;
		return;
	}
	ctrlt = 0;
	if(raw.ref)
		return;
	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(kbdq.repeat == 1){
		kbdq.c = c;
		kbdq.count = 0;
		kbdq.repeat = 2;
	}
	echo(c);
	*kbdq.in++ = c;
	if(kbdq.in == kbdq.buf+sizeof(kbdq.buf))
		kbdq.in = kbdq.buf;
	if(raw.ref || c=='\n' || c==0x04)
		wakeup(&kbdq.r);
}

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);
}

int
consactive(void)
{
	return printq.printing;
}

/*
 * I/O interface
 */
enum{
	Qdir,
	Qcons,
	Qcputime,
	Qnull,
	Qpgrpid,
	Qpid,
	Qppid,
	Qrcons,
	Qtime,
	Quser,
	Qklog,
	Qmsec,
	Qclock,
	Qrs232ctl = STREAMQID(1, Sctlqid),
	Qrs232 = STREAMQID(1, Sdataqid),
};

Dirtab consdir[]={
	"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,
};

#define	NCONS	(sizeof consdir/sizeof(Dirtab))

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;
}

ulong	boottime;		/* seconds since epoch at boot */

long
seconds(void)
{
	return boottime + TK2SEC(MACHP(0)->ticks);
}

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] = ' ';
	if(off >= size)
		return 0;
	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);
	if(off >= size)
		return 0;
	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, consgen);
}

void
consstat(Chan *c, char *dp)
{
	switch(c->qid.path){
	case Qrs232:
		streamstat(c, dp, "rs232");
		break;
	default:
		devstat(c, dp, consdir, NCONS, consgen);
		break;
	}
}

Chan*
consopen(Chan *c, int omode)
{
	int ch;

	switch(c->qid.path){
	case Quser:
		if(omode==(OWRITE|OTRUNC)){
			/* truncate? */
			if(strcmp(u->p->pgrp->user, "bootes") == 0)	/* BUG */
				u->p->pgrp->user[0] = 0;
			else
				error(Eperm);
		}
		break;
	case Qrcons:
		if(incref(&raw) == 1){
			lock(&lineq);
			while((ch=getc(&kbdq)) != -1){
				*lineq.in++ = ch;
				if(lineq.in == lineq.buf+sizeof(lineq.buf))
					lineq.in = lineq.buf;
			}
			unlock(&lineq);
		}
		break;
	case Qrs232:
	case Qrs232ctl:
		streamopen(c, &rs232info);
		break;
	}
	return devopen(c, omode, consdir, NCONS, consgen);
}

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

void
consclose(Chan *c)
{
	if(c->qid.path==Qrcons && (c->flag&COPEN))
		decref(&raw);
	if(c->stream)
		streamclose(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.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, consdir, NCONS, consgen);

	case Qrcons:
	case Qcons:
		qlock(&kbdq);
		if(waserror()){
			qunlock(&kbdq);
			nexterror();
		}
		while(!cangetc(&lineq)){
			sleep(&kbdq.r, isbrkc, &kbdq);
			do{
				lock(&lineq);
				ch = getc(&kbdq);
				if(raw.ref){
					unlock(&lineq);
					goto Default;
				}
				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:
				default:
					*lineq.in++ = ch;
					if(lineq.in == lineq.buf+sizeof(lineq.buf))
						lineq.in = lineq.buf;
				}
				unlock(&lineq);
			}while(raw.ref==0 && ch!='\n' && ch!=0x04);
		}
		i = 0;
		while(n > 0){
			ch = getc(&lineq);
			if(ch==-1 || (raw.ref==0 && ch==0x04))
				break;
			i++;
			*cbuf++ = ch;
			--n;
		}
		qunlock(&kbdq);
		return i;

	case Qrs232:
		return streamread(c, buf, n);

	case Qrs232ctl:
		if(c->offset)
			return 0;
		*(char *)buf = duartinputport();
		return 1;

	case Qcputime:
		k = c->offset;
		if(k >= sizeof tmp)
			return 0;
		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 = TK2MS(l);
			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+TK2SEC(MACHP(0)->ticks), NUMSIZE);

	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;

	case Quser:
		return readstr(c->offset, buf, n, u->p->pgrp->user);

	case Qnull:
		return 0;

	case Qklog:
		qlock(&klogq);
		if(waserror()){
			qunlock(&klogq);
			nexterror();
		}
		while(!cangetc(&klogq))
			sleep(&klogq.r, cangetc, &klogq);
		for(i=0; i<n; i++){
			if((ch=getc(&klogq)) == -1)
				break;
			*cbuf++ = ch;
		}
		poperror();
		qunlock(&klogq);
		return i;

	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.path){
	case Qcons:
	case Qrcons:
		/*
		 * 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 Qrs232:
	case Qrs232ctl:
		n = streamwrite(c, va, n, 1);
		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(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(Eperm);

	case Qnull:
		break;
	default:
		error(Egreg);
	}
	return n;
}

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

void
conswstat(Chan *c, char *dp)
{
	error(Eperm);
}

/*
 *  rs232 stream routines
 *
 *  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.
 */
static int
rs232empty(void *a)
{
	Rs232 *r;

	r = a;
	return r->out.w == r->out.r;
}

static void
rs232output(Rs232 *r)
{
	int next;
	Queue *q;
	Block *bp;
	long l;

	qlock(&r->outlock);
	q = r->wq;

	/*
	 *  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;

	/*
	 *  stage new blocks
	 *
	 *  if we run into a control block, wait till the queue
	 *  is empty before doing the control.
	 */
	for(next = NEXT(r->out.w); next != r->out.f; next = NEXT(next)){
		bp = getq(q);
		if(bp == 0)
			break;
		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':
			case 'b':
				duartbaud(l);
				break;
			case 'D':
			case 'd':
				duartdtr(l);
				break;
			case 'K':
			case 'k':
				duartbreak(l);
				break;
			case 'W':
			case 'w':
				if(l>=0 && l<1000)
					r->delay = l;
				break;
			}
			freeb(bp);
			break;
		}
		r->out.bp[r->out.w] = bp;
		r->out.w = next;
	}

	/*
	 *  start output, the spl's sync with interrupt level
	 *  this wouldn't work on a multi-processor
	 */
	splhi();
	if(r->started == 0){
		r->started = 1;
		duartstartrs232o();
	}
	spllo();
	qunlock(&r->outlock);
}

static void
rs232input(Rs232 *r)
{
	Queue *q;
	int c;
	Block *bp;

	q = RD(r->wq);
	bp = 0;
	while((c = getc(&r->in)) >= 0){
		if(bp == 0){
			bp = allocb(64);
			bp->flags |= S_DELIM;
		}
		*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)
{
	if(bp->rptr >= bp->wptr)
		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);
}

/*
 *  called by input interrupt.  runs splhi
 */
void
rs232ichar(int c)
{
	Rs232 *r;

	r = &rs232;
	if(putc(&r->in, c) < 0)
		screenputc('^');

	/*
	 *  pass upstream within 1/16 second
	 */
	if(r->a==0){
		if(r->delay == 0)
			wakeup(&r->r);
		else
			r->a = alarm(r->delay, rs232timer, r);
	}
}

/*
 *  called by output interrupt.  runs splhi
 */
int
getrs232o(void)
{
	uchar c;
	Rs232 *r;
	Block *bp;

	r = &rs232;
	if(r->out.r == r->out.w){
		r->started = 0;
		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;
}
.
## diffname ss/devcons.c 1990/1226
## diff -e /n/bootesdump/1990/1223/sys/src/9/sparc/devcons.c /n/bootesdump/1990/1226/sys/src/9/sparc/devcons.c
313,315d
118d
98d
## diffname ss/devcons.c 1990/1231
## diff -e /n/bootesdump/1990/1226/sys/src/9/sparc/devcons.c /n/bootesdump/1990/1231/sys/src/9/sparc/devcons.c
856a
#endif
.
855a
panic("rs232o");
#ifdef asdf
.
841a
#endif
return;
.
822a
#ifdef asdf
.
620c
#endif
		return 0;
.
616a
#ifdef asdf
.
460a
	duartinit();
.
308a
		case 'l':
			lancetoggle();
			return;
.
## diffname ss/devcons.c 1991/0112
## diff -e /n/bootesdump/1990/1231/sys/src/9/sparc/devcons.c /n/bootesdump/1991/0112/sys/src/9/sparc/devcons.c
309,313c
		case 'r':
			reset();
.
302a
		case 'l':
			lancetoggle();
			return;
		case 'm':
			mntdump();
			return;
.
## diffname ss/devcons.c 1991/0201 # deleted
## diff -e /n/bootesdump/1991/0112/sys/src/9/sparc/devcons.c /n/bootesdump/1991/0201/sys/src/9/sparc/devcons.c
1,1031d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.