~kris/9p

9hist

ab29c2601af861cdfa1457c4050fb5d5d6fe9da5 — David du Colombier 35 years ago 25bfe49
Plan 9 from Bell Labs 1991-06-05
M gnot/dat.h => gnot/dat.h +42 -0
@@ 1,6 1,8 @@
typedef struct Conf	Conf;
typedef struct FFrame	FFrame;
typedef struct FPsave	FPsave;
typedef struct IOQ	IOQ;
typedef struct KIOQ	KIOQ;
typedef struct KMap	KMap;
typedef struct Label	Label;
typedef struct Lock	Lock;


@@ 118,6 120,38 @@ struct KMap
};
#define	VA(k)	((k)->va)

/*
 *  character based IO (mouse, keyboard, console screen)
 */
#define NQ	4096
struct IOQ
{
	Lock;
	uchar	buf[NQ];
	uchar	*in;
	uchar	*out;
	int	state;
	Rendez	r;
	union{
		void	(*puts)(IOQ*, void*, int);	/* output */
		int	(*putc)(IOQ*, int);		/* input */
	};
	void	*ptr;
};
struct KIOQ
{
	QLock;
	IOQ;
	int	repeat;
	int	c;
	int	count;
};

extern IOQ	lineq;
extern IOQ	printq;
extern IOQ	mouseq;
extern KIOQ	kbdq;

struct Mach
{
	int	machno;			/* physical id of processor */


@@ 130,6 164,7 @@ struct Mach
	void	*alarm;			/* alarms bound to this clock */
	int	fpstate;		/* state of fp registers on machine */

	int	tlbpurge;
	int	tlbfault;
	int	pfault;
	int	cs;


@@ 229,5 264,12 @@ struct User
	MMUCache mc;
};

struct
{
	Lock;
	short	machs;
	short	exiting;
}active;

extern Mach	*m;
extern User	*u;

M gnot/devcons.c => gnot/devcons.c +193 -526
@@ 8,157 8,89 @@

#include	"devtab.h"

typedef struct IOQ	IOQ;
struct {
	IOQ;			/* lock to klogputs */
	QLock;			/* qlock to getc */
}	klogq;

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;
IOQ	lineq;			/* lock to getc; interrupt putc's */
IOQ	printq;
IOQ	mouseq;
KIOQ	kbdq;

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

/*
 *  rs232 stream module
 *  init the queues and set the output routine
 */
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;	/* true if output interrupt pending */
	int	delay;		/* between character input and waking kproc */
	Rendez	r;
	Rendez	rempty;
};

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)
{
	screeninit();

	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;
	rs232.delay = 64;	/* msec */
	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);
	initq(&printq);
	initq(&lineq);
	initq(&kbdq);
	initq(&klogq);
	initq(&mouseq);
	mouseq.putc = mouseputc;
}

/*
 * Print a string on the console.
 *   Print a string on the console.  Convert \n to \r\n
 */
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);
putstrn(char *str, int n)
{
	int s, c, m;
	char *t;

	while(n > 0){
		if(printq.puts && *str=='\n')
			(*printq.puts)(&printq, "\r", 1);
		m = n;
		t = memchr(str+1, '\n', m-1);
		if(t)
			if(t-str < m)
				m = t - str;
		if(printq.puts)
			(*printq.puts)(&printq, str, m);
		screenputs(str, m);
		n -= m;
		str += m;
	}
}

int
cangetc(void *arg)
/*
 *   Print a string in the kernel log.  Ignore overflow.
 */
void
klogputs(char *str, long n)
{
	IOQ *q = (IOQ *)arg;
	int n = q->in - q->out;
	if (n < 0)
		n += sizeof(q->buf);
	return n;
}
	int s, m;
	uchar *nextin;

int
canputc(void *arg)
{
	IOQ *q = (IOQ *)arg;
	return sizeof(q->buf)-cangetc(q)-1;
	s = splhi();
	lock(&klogq);
	while(n){
		m = &klogq.buf[NQ] - klogq.in;
		if(m > n)
			m = n;
		memmove(klogq.in, str, m);
		n -= m;
		str += m;
		nextin = klogq.in + m;
		if(nextin >= &klogq.buf[NQ])
			klogq.in = klogq.buf;
		else
			klogq.in = nextin;
	}
	unlock(&klogq);
	splx(s);
	wakeup(&klogq.r);
}

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

	for(p=q->out; p!=q->in; ){


@@ 174,51 106,6 @@ isbrkc(void *arg)
}

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;


@@ 242,7 129,7 @@ kprint(char *fmt, ...)
	int n;

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



@@ 257,8 144,9 @@ panic(char *fmt, ...)
	buf[n] = '\n';
	putstrn(buf, n+1);
	dumpstack();
	exit();
	for(;;);
}

int
pprint(char *fmt, ...)
{


@@ 286,8 174,7 @@ pprint(char *fmt, ...)
void
prflush(void)
{
	while(printq.printing)
		delay(100);
	while(printq.in != printq.out) ;
}

void


@@ 295,7 182,6 @@ echo(int c)
{
	char ch;
	static int ctrlt;
	extern void DEBUG(void), dumpqueues(void), mntdump(void);

	/*
	 * ^t hack BUG


@@ 305,6 191,9 @@ echo(int c)
		switch(c){
		case 0x14:
			break;	/* pass it on */
		case 'm':
			mntdump();
			return;
		case 'p':
			DEBUG();
			return;


@@ 312,14 201,8 @@ echo(int c)
			dumpqueues();
			return;
		case 'r':
			panic("you asked for it");
			firmware();
			break;
		case 'm':
			mntdump();
			return;
		case 'i':
			incontoggle();
			return;
		}
	}else if(c == 0x14){
		ctrlt++;


@@ 340,43 223,44 @@ echo(int c)
 * Put character into read queue at interrupt time.
 * Always called splhi from proc 0.
 */

void
kbdchar(int c)
int
kbdputc(IOQ *q, int ch)
{
	if(kbdq.repeat == 1){
		kbdq.c = c;
		kbdq.count = 0;
		kbdq.repeat = 2;
	}
	echo(c);
	*kbdq.in++ = c;
	echo(ch);
	kbdq.c = ch;
	*kbdq.in++ = ch;
	if(kbdq.in == kbdq.buf+sizeof(kbdq.buf))
		kbdq.in = kbdq.buf;
	if(raw.ref || c=='\n' || c==0x04)
	if(raw.ref || ch=='\n' || ch==0x04)
		wakeup(&kbdq.r);
	return 0;
}

void
kbdrepeat(int rep)
{
	if(rep)
		kbdq.repeat = 1;
	else
		kbdq.repeat = 0;
	kbdq.repeat = rep;
	kbdq.count = 0;
}

void
kbdclock(void)
{
	if(kbdq.repeat==2 && (++kbdq.count&1))
		kbdchar(kbdq.c);
	if(kbdq.repeat == 0)
		return;
	if(kbdq.repeat==1 && ++kbdq.count>HZ){
		kbdq.repeat = 2;
		kbdq.count = 0;
		return;
	}
	if(++kbdq.count&1)
		kbdputc(&kbdq, kbdq.c);
}

int
consactive(void)
{
	return printq.printing;
	return printq.in != printq.out;
}

/*


@@ 386,6 270,8 @@ enum{
	Qdir,
	Qcons,
	Qcputime,
	Qlights,
	Qnoise,
	Qnull,
	Qpgrpid,
	Qpid,


@@ 396,39 282,29 @@ enum{
	Qklog,
	Qmsec,
	Qclock,
	Qrs232ctl = STREAMQID(1, Sctlqid),
	Qrs232 = STREAMQID(1, Sdataqid),
	Qsysstat,
};

Dirtab consdir[]={
	"cons",		{Qcons},	0,		0600,
	"cputime",	{Qcputime},	6*NUMSIZE,	0600,
	"lights",	{Qlights},	0,		0600,
	"noise",	{Qnoise},	0,		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,
	"sysstat",	{Qsysstat},	0,		0600,
};

#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


@@ 492,20 368,13 @@ consclone(Chan *c, Chan *nc)
int
conswalk(Chan *c, char *name)
{
	return devwalk(c, name, consdir, NCONS, consgen);
	return devwalk(c, name, consdir, NCONS, devgen);
}

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;
	}
	devstat(c, dp, consdir, NCONS, devgen);
}

Chan*


@@ 534,12 403,8 @@ consopen(Chan *c, int omode)
			unlock(&lineq);
		}
		break;
	case Qrs232:
	case Qrs232ctl:
		streamopen(c, &rs232info);
		break;
	}
	return devopen(c, omode, consdir, NCONS, consgen);
	return devopen(c, omode, consdir, NCONS, devgen);
}

void


@@ 553,26 418,26 @@ 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, ulong offset)
{
	int ch, i, j, k;
	int ch, i, j, k, id;
	ulong l;
	uchar *out;
	char *cbuf = buf;
	char *user;
	int userlen;
	char tmp[6*NUMSIZE];
	char tmp[6*NUMSIZE], xbuf[1024];
	Mach *mp;

	if(n <= 0)
		return n;
	switch(c->qid.path&~CHDIR){
	switch(c->qid.path & ~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, consdir, NCONS, consgen);
		return devdirread(c, buf, n, consdir, NCONS, devgen);

	case Qrcons:
	case Qcons:


@@ 603,9 468,11 @@ consread(Chan *c, void *buf, long n, ulong offset)
					break;
				Default:
				default:
					*lineq.in++ = ch;
					if(lineq.in == lineq.buf+sizeof(lineq.buf))
					*lineq.in = ch;
					if(lineq.in >= lineq.buf+sizeof(lineq.buf)-1)
						lineq.in = lineq.buf;
					else
						lineq.in++;
				}
				unlock(&lineq);
			}while(raw.ref==0 && ch!='\n' && ch!=0x04);


@@ 622,15 489,6 @@ consread(Chan *c, void *buf, long n, ulong offset)
		qunlock(&kbdq);
		return i;

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

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

	case Qcputime:
		k = offset;
		if(k >= sizeof tmp)


@@ 658,10 516,8 @@ consread(Chan *c, void *buf, long n, ulong offset)
		return readnum(offset, buf, n, u->p->parentpid, NUMSIZE);

	case Qtime:
		return readnum(offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), NUMSIZE);
		return readnum(offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), 12);

	case Qmsec:
		return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);
	case Qclock:
		k = offset;
		if(k >= 2*NUMSIZE)


@@ 696,12 552,69 @@ consread(Chan *c, void *buf, long n, ulong offset)
		qunlock(&klogq);
		return i;

	case Qmsec:
		return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);

	case Qsysstat:
		j = 0;
		for(id = 0; id < 32; id++) {
			if(active.machs & (1<<id)) {
				mp = MACHP(id);
				j += sprint(&xbuf[j], "%d %d %d %d %d %d %d %d\n",
					id, mp->cs, mp->intr, mp->syscall, mp->pfault,
					    mp->tlbfault, mp->tlbpurge, m->spinlock);
			}
		}
		return readstr(offset, buf, n, xbuf);

	default:
		panic("consread %lux\n", c->qid.path);
		panic("consread %lux\n", c->qid);
		return 0;
	}
}

void
conslights(char *a, int n)
{
	int l;
	char line[128];
	char *lp;
	int c;

	lp = line;
	while(n--){
		*lp++ = c = *a++;
		if(c=='\n' || n==0 || lp==&line[sizeof(line)-1])
			break;
	}
	*lp = 0;
	lights(strtoul(line, 0, 0));
}

void
consnoise(char *a, int n)
{
	int freq;
	int duration;
	char line[128];
	char *lp;
	int c;

	lp = line;
	while(n--){
		*lp++ = c = *a++;
		if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]){
			*lp = 0;
			freq = strtoul(line, &lp, 0);
			while(*lp==' ' || *lp=='\t')
				lp++;
			duration = strtoul(lp, &lp, 0);
			buzz(freq, duration);
			lp = line;
		}
	}
}

long
conswrite(Chan *c, void *va, long n, ulong offset)
{


@@ 709,10 622,12 @@ conswrite(Chan *c, void *va, long n, ulong offset)
	char buf[256];
	long l, m;
	char *a = va;
	Mach *mp;
	int id;

	switch(c->qid.path){
	case Qcons:
	case Qrcons:
	case Qcons:
		/*
		 * Damn. Can't page fault in putstrn, so copy the data locally.
		 */


@@ 728,11 643,6 @@ conswrite(Chan *c, void *va, long n, ulong offset)
		}
		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;


@@ 762,6 672,30 @@ conswrite(Chan *c, void *va, long n, ulong offset)

	case Qnull:
		break;

	case Qnoise:
		consnoise(a, n);
		break;

	case Qlights:
		conslights(a, n);
		break;

	case Qsysstat:
		for(id = 0; id < 32; id++) {
			if(active.machs & (1<<id)) {
				mp = MACHP(id);
				mp->cs = 0;
				mp->intr = 0;
				mp->syscall = 0;
				mp->pfault = 0;
				mp->tlbfault = 0;
				mp->tlbpurge = 0;
				mp->spinlock = 0;
			}
		}
		break;

	default:
		error(Egreg);
	}


@@ 779,270 713,3 @@ 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;

	if(q==0){
		kprint("rs232output: null q\n");
		qunlock(&r->outlock);
		return;
	}

	/*
	 *  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){
			if(waserror()){
				freeb(bp);
				qunlock(&r->outlock);
				nexterror();
			}
			while(!rs232empty(r))
				sleep(&r->rempty, 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;
			}
			poperror();
			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
	 */
	if(r->started == 0)
		duartstartrs232o();
	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);

	kprint("rs232open: q=0x%ux, inuse=%d, type=%d, dev=%d, id=%d\n",
		q, c->inuse, c->type, c->dev, c->id);
	if(r->kstarted == 0){
		r->in.in = r->in.out = r->in.buf;
		kproc("rs232", rs232kproc, r);
		r->kstarted = 1;
	}else
		wakeup(&r->r);	/* pick up any input characters */
}

static void
rs232close(Queue *q)
{
	Rs232 *r;

	kprint("rs232close: q=0x%ux\n", q);
	r = q->ptr;
	qlock(&r->outlock);
	while(!rs232empty(r))
		sleep(&r->rempty, rs232empty, r);
	qunlock(&r->outlock);
	kprint("rs232close: emptied\n");
	rs232output(r);	/* reclaim blocks written */
	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 r->delay milliseconds
	 */
	if(r->a==0){
		if(r->delay == 0)
			wakeup(&r->r);
		else
			r->a = alarm(r->delay, rs232timer, r);
	}
}

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

	r = &rs232;
	if(r->out.r == r->out.w){
		wakeup(&r->rempty);
		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);
	}
	r->started = 1;
	return c;
}

A gnot/devduart.c => gnot/devduart.c +914 -0
@@ 0,0 1,914 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"
#include	"errno.h"

#include	"devtab.h"

int	duartacr;
int	duartimr;
void	(*kprofp)(ulong);

/*
 * Register set for half the duart.  There are really two sets.
 */
struct Duart{
	uchar	mr1_2;		/* Mode Register Channels 1 & 2 */
	uchar	sr_csr;		/* Status Register/Clock Select Register */
	uchar	cmnd;		/* Command Register */
	uchar	data;		/* RX Holding / TX Holding Register */
	uchar	ipc_acr;	/* Input Port Change/Aux. Control Register */
#define	ivr	ivr		/* Interrupt Vector Register */
	uchar	is_imr;		/* Interrupt Status/Interrupt Mask Register */
#define	ip_opcr	is_imr		/* Input Port/Output Port Configuration Register */
	uchar	ctur;		/* Counter/Timer Upper Register */
#define	scc_sopbc ctur		/* Start Counter Command/Set Output Port Bits Command */
	uchar	ctlr;		/* Counter/Timer Lower Register */
#define	scc_ropbc ctlr		/* Stop Counter Command/Reset Output Port Bits Command */
};

enum{
	CHAR_ERR	=0x00,	/* MR1x - Mode Register 1 */
	PAR_ENB		=0x00,
	EVEN_PAR	=0x00,
	ODD_PAR		=0x04,
	NO_PAR		=0x10,
	CBITS8		=0x03,
	CBITS7		=0x02,
	CBITS6		=0x01,
	CBITS5		=0x00,
	NORM_OP		=0x00,	/* MR2x - Mode Register 2 */
	TWOSTOPB	=0x0F,
	ONESTOPB	=0x07,
	ENB_RX		=0x01,	/* CRx - Command Register */
	DIS_RX		=0x02,
	ENB_TX		=0x04,
	DIS_TX		=0x08,
	RESET_MR 	=0x10,
	RESET_RCV  	=0x20,
	RESET_TRANS  	=0x30,
	RESET_ERR  	=0x40,
	RESET_BCH	=0x50,
	STRT_BRK	=0x60,
	STOP_BRK	=0x70,
	RCV_RDY		=0x01,	/* SRx - Channel Status Register */
	FIFOFULL	=0x02,
	XMT_RDY		=0x04,
	XMT_EMT		=0x08,
	OVR_ERR		=0x10,
	PAR_ERR		=0x20,
	FRM_ERR		=0x40,
	RCVD_BRK	=0x80,
	BD38400		=0xCC|0x0000,
	BD19200		=0xCC|0x0100,
	BD9600		=0xBB|0x0000,
	BD4800		=0x99|0x0000,
	BD2400		=0x88|0x0000,
	BD1200		=0x66|0x0000,
	BD300		=0x44|0x0000,
	IM_IPC		=0x80,	/* IMRx/ISRx - Interrupt Mask/Interrupt Status */
	IM_DBB		=0x40,
	IM_RRDYB	=0x20,
	IM_XRDYB	=0x10,
	IM_CRDY		=0x08,
	IM_DBA		=0x04,
	IM_RRDYA	=0x02,
	IM_XRDYA	=0x01,
};

/*
 *  software info for a serial duart interface
 */
typedef struct Duartport	Duartport;
struct Duartport
{
	QLock;
	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 */
};
Duartport	duartport[1];

uchar keymap[]={
/*80*/	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x8e,	0x58,
/*90*/	0x90,	0x91,	0x92,	0x93,	0x94,	0x95,	0x96,	0x97,
	0x98,	0x99,	0x9a,	0x9b,	0x58,	0x58,	0x58,	0x58,
/*A0*/	0x58,	0xa1,	0xa2,	0xa3,	0xa4,	0xa5,	0xa6,	0xa7,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0xae,	0xaf,
/*B0*/	0xb0,	0xb1,	0xb2,	0xb3,	0xb4,	0xb5,	0xb6,	0xb7,
	0xb8,	0xb9,	0x00,	0xbb,	0x1e,	0xbd,	0x60,	0x1f,
/*C0*/	0xc0,	0xc1,	0xc2,	0xc3,	0xc4,	0x58,	0xc6,	0x0a,
	0xc8,	0xc9,	0xca,	0xcb,	0xcc,	0xcd,	0xce,	0xcf,
/*D0*/	0x09,	0x08,	0xd2,	0xd3,	0xd4,	0xd5,	0xd6,	0xd7,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x7f,	0x58,
/*E0*/	0x58,	0x58,	0xe2,	0x1b,	0x0d,	0xe5,	0x58,	0x0a,
	0xe8,	0xe9,	0xea,	0xeb,	0xec,	0xed,	0xee,	0xef,
/*F0*/	0x09,	0x08,	0xb2,	0x1b,	0x0d,	0xf5,	0x81,	0x58,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x7f,	0x80,
};

void
duartinit(void)
{
	Duart *duart;
	static int already;

	if(already)
		return;
	already = 1;

	duart  =  DUARTREG;

	/*
	 * Keyboard
	 */
	duart[0].cmnd = RESET_RCV|DIS_TX|DIS_RX;
	duart[0].cmnd = RESET_TRANS;
	duart[0].cmnd = RESET_ERR;
	duart[0].cmnd = RESET_MR;
	duart[0].mr1_2 = CHAR_ERR|PAR_ENB|EVEN_PAR|CBITS8;
	duart[0].mr1_2 = NORM_OP|ONESTOPB;
	duart[0].sr_csr = BD4800;

	/*
	 * RS232
	 */
	duart[1].cmnd = RESET_RCV|DIS_TX|DIS_RX;
	duart[1].cmnd = RESET_TRANS;
	duart[1].cmnd = RESET_ERR;
	duart[1].cmnd = RESET_MR;
	duart[1].mr1_2 = CHAR_ERR|NO_PAR|CBITS8;
	duart[1].mr1_2 = NORM_OP|ONESTOPB;
	duart[1].sr_csr = BD9600;

	/*
	 * Output port
	 */
	duart[0].ipc_acr = duartacr = 0xB7;	/* allow change	of state interrupt */
	duart[1].ip_opcr = 0x00;
	duart[1].scc_ropbc = 0xFF;	/* make sure the port is reset first */
	duart[1].scc_sopbc = 0x04;	/* dtr = 1, pp = 01 */
	duart[0].is_imr = duartimr = IM_IPC|IM_RRDYB|IM_XRDYB|IM_RRDYA|IM_XRDYA;
	duart[0].cmnd = ENB_TX|ENB_RX;	/* enable TX and RX last */
	duart[1].cmnd = ENB_TX|ENB_RX;

	/*
	 * Initialize keyboard
	 */
	while (!(duart[0].sr_csr & (XMT_EMT|XMT_RDY)))
		;
	duart[0].data = 0x02;
}


void
duartbaud(int b)
{
	int x = 0;
	Duart *duart = DUARTREG;

	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:
		error(Ebadarg);
	}
	if(x & 0x0100)
		duart[0].ipc_acr = duartacr |= 0x80;
	else
		duart[0].ipc_acr = duartacr &= ~0x80;
	duart[1].sr_csr = x;
}

void
duartdtr(int val)
{
	Duart *duart = DUARTREG;
	if (val)
		duart[1].scc_ropbc=0x01;
	else
		duart[1].scc_sopbc=0x01;
}

void
duartbreak(int ms)
{
	static QLock brk;
	Duart *duart = DUARTREG;
	if (ms<=0 || ms >20000)
		error(Ebadarg);
	qlock(&brk);
	duart[0].is_imr = duartimr &= ~IM_XRDYB;
	duart[1].cmnd = STRT_BRK|ENB_TX;
	tsleep(&u->p->sleep, return0, 0, ms);
	duart[1].cmnd = STOP_BRK|ENB_TX;
	duart[0].is_imr = duartimr |= IM_XRDYB;
	qunlock(&brk);
}

enum{
	Kptime=200
};
void
duartstarttimer(void)
{
	Duart *duart;
	char x;

	duart = DUARTREG;
	duart[0].ctur = (Kptime)>>8;
	duart[0].ctlr = (Kptime)&255;
	duart[0].is_imr = duartimr |= IM_CRDY;
	x = duart[1].scc_sopbc;
	USED(x);
}

void
duartstoptimer(void)
{
	Duart *duart;
	char x;

	duart = DUARTREG;
	x = duart[1].scc_ropbc;
	USED(x);
	duart[0].is_imr = duartimr &= ~IM_CRDY;
}

struct latin
{
	uchar	l;
	char	c[2];
}latintab[] = {
	'€',	"!!",	/* spanish initial ! */
	'€',	"c|",	/* cent */
	'€',	"c$",	/* cent */
	'€',	"l$",	/* pound sterling */
	'€',	"g$",	/* general currency */
	'€',	"y$",	/* yen */
	'€',	"j$",	/* yen */
	'€',	"||",	/* broken vertical bar */
	'€',	"SS",	/* section symbol */
	'€',	"\"\"",	/* dieresis */
	'€',	"cr",	/* copyright */
	'€',	"cO",	/* copyright */
	'€',	"sa",	/* super a, feminine ordinal */
	'€',	"<<",	/* left angle quotation */
	'€',	"no",	/* not sign, hooked overbar */
	'€',	"--",	/* soft hyphen */
	'€',	"rg",	/* registered trademark */
	'€',	"__",	/* macron */
	'€',	"s0",	/* degree (sup o) */
	'€',	"+-",	/* plus-minus */
	'€',	"s2",	/* sup 2 */
	'€',	"s3",	/* sup 3 */
	'€',	"''",	/* grave accent */
	'€',	"mu",	/* mu */
	'€',	"pg",	/* paragraph (pilcrow) */
	'€',	"..",	/* centered . */
	'€',	",,",	/* cedilla */
	'€',	"s1",	/* sup 1 */
	'€',	"so",	/* sup o */
	'€',	">>",	/* right angle quotation */
	'€',	"14",	/* 1/4 */
	'€',	"12",	/* 1/2 */
	'€',	"34",	/* 3/4 */
	'€',	"??",	/* spanish initial ? */
	'€',	"A`",	/* A grave */
	'€',	"A'",	/* A acute */
	'€',	"A^",	/* A circumflex */
	'€',	"A~",	/* A tilde */
	'€',	"A\"",	/* A dieresis */
	'€',	"A:",	/* A dieresis */
	'€',	"Ao",	/* A circle */
	'€',	"AO",	/* A circle */
	'€',	"Ae",	/* AE ligature */
	'€',	"AE",	/* AE ligature */
	'€',	"C,",	/* C cedilla */
	'€',	"E`",	/* E grave */
	'€',	"E'",	/* E acute */
	'€',	"E^",	/* E circumflex */
	'€',	"E\"",	/* E dieresis */
	'€',	"E:",	/* E dieresis */
	'€',	"I`",	/* I grave */
	'€',	"I'",	/* I acute */
	'€',	"I^",	/* I circumflex */
	'€',	"I\"",	/* I dieresis */
	'€',	"I:",	/* I dieresis */
	'€',	"D-",	/* Eth */
	'€',	"N~",	/* N tilde */
	'€',	"O`",	/* O grave */
	'€',	"O'",	/* O acute */
	'€',	"O^",	/* O circumflex */
	'€',	"O~",	/* O tilde */
	'€',	"O\"",	/* O dieresis */
	'€',	"O:",	/* O dieresis */
	'€',	"OE",	/* O dieresis */
	'€',	"Oe",	/* O dieresis */
	'€',	"xx",	/* times sign */
	'€',	"O/",	/* O slash */
	'€',	"U`",	/* U grave */
	'€',	"U'",	/* U acute */
	'€',	"U^",	/* U circumflex */
	'€',	"U\"",	/* U dieresis */
	'€',	"U:",	/* U dieresis */
	'€',	"UE",	/* U dieresis */
	'€',	"Ue",	/* U dieresis */
	'€',	"Y'",	/* Y acute */
	'€',	"P|",	/* Thorn */
	'€',	"Th",	/* Thorn */
	'€',	"TH",	/* Thorn */
	'€',	"ss",	/* shadp s */
	'€',	"a`",	/* a grave */
	'€',	"a'",	/* a acute */
	'€',	"a^",	/* a circumflex */
	'€',	"a~",	/* a tilde */
	'€',	"a\"",	/* a dieresis */
	'€',	"a:",	/* a dieresis */
	'€',	"ao",	/* a circle */
	'€',	"ae",	/* ae ligature */
	'€',	"c,",	/* c cedilla */
	'€',	"e`",	/* e grave */
	'€',	"e'",	/* e acute */
	'€',	"e^",	/* e circumflex */
	'€',	"e\"",	/* e dieresis */
	'€',	"e:",	/* e dieresis */
	'€',	"i`",	/* i grave */
	'€',	"i'",	/* i acute */
	'€',	"i^",	/* i circumflex */
	'€',	"i\"",	/* i dieresis */
	'€',	"i:",	/* i dieresis */
	'€',	"d-",	/* eth */
	'€',	"n~",	/* n tilde */
	'€',	"o`",	/* o grave */
	'€',	"o'",	/* o acute */
	'€',	"o^",	/* o circumflex */
	'€',	"o~",	/* o tilde */
	'€',	"o\"",	/* o dieresis */
	'€',	"o:",	/* o dieresis */
	'€',	"oe",	/* o dieresis */
	'€',	"-:",	/* divide sign */
	'€',	"o/",	/* o slash */
	'€',	"u`",	/* u grave */
	'€',	"u'",	/* u acute */
	'€',	"u^",	/* u circumflex */
	'€',	"u\"",	/* u dieresis */
	'€',	"u:",	/* u dieresis */
	'€',	"ue",	/* u dieresis */
	'€',	"y'",	/* y acute */
	'€',	"th",	/* thorn */
	'€',	"p|",	/* thorn */
	'€',	"y\"",	/* y dieresis */
	'€',	"y:",	/* y dieresis */
	0,	0,
};

int
latin1(int k1, int k2)
{
	int i;
	struct latin *l;

	for(l=latintab; l->l; l++)
		if(k1==l->c[0] && k2==l->c[1])
			return l->l;
	return 0;
}

/*
 *  a serial line input interrupt
 */
void
duartrintr(char ch)
{
	IOQ *cq;
	Duartport *dp = duartport;

	cq = dp->iq;
	if(cq->putc)
		(*cq->putc)(cq, ch);
	else {
		putc(cq, ch);
		if(dp->delim[ch])
			wakeup(&cq->r);
	}
}

/*
 *  a serial line output interrupt
 */
void
duartxintr(void)
{
	int ch;
	IOQ *cq;
	Duartport *dp = duartport;
	Duart *duart;

	cq = dp->oq;
	lock(cq);
	ch = getc(cq);
	duart = DUARTREG;
	if(ch < 0){
		dp->printing = 0;
		wakeup(&cq->r);
		duart[1].cmnd = DIS_TX;
	} else
		duart[1].data = ch;
	unlock(cq);
}


void
duartintr(Ureg *ur)
{
	int cause, status, c;
	Duart *duart;
	static int kbdstate, k1, k2;

	duart = DUARTREG;
	cause = duart->is_imr;
	/*
	 * I can guess your interrupt.
	 */
	/*
	 * Is it 0?
	 */
	if(cause & IM_CRDY){
		if(kprofp)
			(*kprofp)(ur->pc);
		c = duart[1].scc_ropbc;
		USED(c);
		duart[0].ctur = (Kptime)>>8;
		duart[0].ctlr = (Kptime)&255;
		c = duart[1].scc_sopbc;
		USED(c);
		return;
	}
	/*
	 * Is it 1?
	 */
	if(cause & IM_RRDYA){		/* keyboard input */
		status = duart->sr_csr;
		c = duart->data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart->cmnd = RESET_ERR;
		if(status & PAR_ERR) /* control word: caps lock (0x4) or repeat (0x10) */
			kbdrepeat((c&0x10) == 0);
		else{
			if(c == 0x7F)	/* VIEW key (bizarre) */
				c = 0xFF;
			if(c == 0xB6)	/* NUM PAD */
				kbdstate = 1;
			else{
				if(c & 0x80)
					c = keymap[c&0x7F];
				switch(kbdstate){
				case 1:
					k1 = c;
					kbdstate = 2;
					break;
				case 2:
					k2 = c;
					c = latin1(k1, k2);
					if(c == 0){
						kbdputc(&kbdq, k1);
						c = k2;
					}
					/* fall through */
				default:
					kbdstate = 0;
					kbdputc(&kbdq, c);
				}
			}
		}
	}
	/*
	 * Is it 2?
	 */
	while(cause & IM_RRDYB){	/* duart input */
		status = duart[1].sr_csr;
		c = duart[1].data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart[1].cmnd = RESET_ERR;
		else
			duartrintr(c);
		cause = duart->is_imr;
	}
	/*
	 * Is it 3?
	 */
	if(cause & IM_XRDYB)		/* duart output */
		duartxintr();
	/*
	 * Is it 4?
	 */
	if(cause & IM_XRDYA)
		duart[0].cmnd = DIS_TX;
	/*
	 * Is it 5?
	 */
	if(cause & IM_IPC)
		mousebuttons((~duart[0].ipc_acr) & 7);
}


/*
 *  Queue n characters for output; if queue is full, we lose characters.
 *  Get the output going if it isn't already.
 */
void
duartputs(IOQ *cq, char *s, int n)
{
	int ch, x;
	Duartport *dp = duartport;
	Duart *duart;

	x = splduart();
	lock(cq);
	puts(cq, s, n);
	if(dp->printing == 0){
		ch = getc(cq);
		if(ch >= 0){
			dp->printing = 1;
			duart = DUARTREG;
			duart[1].cmnd = ENB_TX;
			while(!(duart[1].sr_csr & (XMT_RDY|XMT_EMT)))
				;
			duart[1].data = ch;
		}
	}
	unlock(cq);
	splx(x);
}

void
duartdevice(Duartport *dp)
{
	/*
	 *  set up i/o routines
	 */
	if(dp->oq){
		dp->oq->puts = duartputs;
		dp->oq->ptr = dp;
	}
	if(dp->iq)
		dp->iq->ptr = dp;
}

/*
 *  set up an duart port as something other than a stream
 */
void
duartspecial(int port, IOQ *oq, IOQ *iq, int baud)
{
	Duartport *dp = &duartport[port];

	dp->nostream = 1;
	dp->oq = oq;
	dp->iq = iq;
	duartdevice(dp);
	duartbaud(baud);
}

static void	duarttimer(Alarm*);
static int	duartputc(IOQ *, int);
static void	duartstopen(Queue*, Stream*);
static void	duartstclose(Queue*);
static void	duartoput(Queue*, Block*);
static void	duartkproc(void *);
Qinfo duartinfo =
{
	nullput,
	duartoput,
	duartstopen,
	duartstclose,
	"duart"
};

/*
 *  wakeup the helper process to do input
 */
static void
duarttimer(Alarm *a)
{
	Duartport *dp = a->arg;

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

static int
duartputc(IOQ *cq, int ch)
{
	Duartport *dp = cq->ptr; int r;

	r = putc(cq, ch);

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

static void
duartstopen(Queue *q, Stream *s)
{
	Duartport *dp;
	char name[NAMELEN];

	if(s->id > 0)
		panic("duartstopen");
	dp = &duartport[s->id];

	qlock(dp);
	dp->wq = WR(q);
	WR(q)->ptr = dp;
	RD(q)->ptr = dp;
	dp->delay = 64;
	dp->iq->putc = duartputc;
	qunlock(dp);

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

static void
duartstclose(Queue *q)
{
	Duartport *dp = q->ptr;

	qlock(dp);
	dp->wq = 0;
	dp->iq->putc = 0;
	WR(q)->ptr = 0;
	RD(q)->ptr = 0;
	qunlock(dp);
}

static void
duartoput(Queue *q, Block *bp)
{
	Duartport *dp = q->ptr;
	IOQ *cq;
	int n, m;

	if(dp == 0){
		freeb(bp);
		return;
	}
	cq = dp->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':
			duartbaud(n);
			break;
		case 'D':
		case 'd':
			duartdtr(n);
			break;
		case 'K':
		case 'k':
			duartbreak(n);
			break;
		case 'R':
		case 'r':
			/* can't control? */
			break;
		case 'W':
		case 'w':
			if(n>=0 && n<1000)
				dp->delay = n;
			break;
		}
	}else while((m = BLEN(bp)) > 0){
		while ((n = canputc(cq)) == 0){
			kprint(" duartoput: 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
duartkproc(void *a)
{
	Duartport *dp = a;
	IOQ *cq = dp->iq;
	Block *bp;
	int n;

loop:
	while ((n = cangetc(cq)) == 0)
		sleep(&cq->r, cangetc, cq);
	qlock(dp);
	if(dp->wq == 0){
		cq->out = cq->in;
	}else{
		bp = allocb(n);
		bp->flags |= S_DELIM;
		bp->wptr += gets(cq, bp->wptr, n);
		PUTNEXT(RD(dp->wq), bp);
	}
	qunlock(dp);
	goto loop;
}

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

Dirtab duartdir[]={
	"tty0",		{Qtty0},	0,		0666,
	"tty0ctl",	{Qtty0ctl},	0,		0666,
};

#define	NDuartport	(sizeof duartdir/sizeof(Dirtab))

/*
 *  allocate the queues if no one else has
 */
void
duartreset(void)
{
	Duartport *dp = duartport;

	if(dp->nostream)
		return;
	dp->iq = ialloc(sizeof(IOQ), 0);
	initq(dp->iq);
	dp->oq = ialloc(sizeof(IOQ), 0);
	initq(dp->oq);
	duartdevice(dp);
}

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

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

int
duartwalk(Chan *c, char *name)
{
	return devwalk(c, name, duartdir, NDuartport, devgen);
}

void
duartstat(Chan *c, char *dp)
{
	switch(c->qid.path){
	case Qtty0:
		streamstat(c, dp, "tty0");
		break;
	default:
		devstat(c, dp, duartdir, NDuartport, devgen);
		break;
	}
}

Chan*
duartopen(Chan *c, int omode)
{
	Duartport *dp;

	switch(c->qid.path){
	case Qtty0:
	case Qtty0ctl:
		dp = &duartport[0];
		break;
	default:
		dp = 0;
		break;
	}

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

	if((c->qid.path & CHDIR) == 0)
		streamopen(c, &duartinfo);
	return devopen(c, omode, duartdir, NDuartport, devgen);
}

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

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

long
duartread(Chan *c, void *buf, long n, ulong offset)
{
	int s;
	Duart *duart = DUARTREG;

	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, duartdir, NDuartport, devgen);
	case Qtty0ctl:
		if(offset)
			return 0;
		s = splhi();
		*(uchar *)buf = duart[1].ip_opcr;
		splx(s);
		return 1;
	}
	return streamread(c, buf, n);
}

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

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

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

M gnot/fns.h => gnot/fns.h +16 -4
@@ 7,12 7,16 @@
#define	P_write(sel, addr, val, type)	P_oper(sel, *(type *)(PORT+addr) = val)

void	addportintr(int (*)(void));
int	cangetc(void*);
int	canputc(void*);
void	clearmmucache(void);
void	duartbaud(int);
void	duartbreak(int);
void	duartdtr(int);
int	duartinputport(void);
void	duartstartrs232o(void);
void	duartrs232start(char);
void	duartrs232stop(void);
void	duartrs232xmit(char);
void	duartstarttimer(void);
void	duartstoptimer(void);
#define	evenaddr(x)	/* 68020 doesn't care */


@@ 26,9 30,11 @@ void	fpregrestore(char*);
void	fpregsave(char*);
void	fprestore(FPsave*);
void	fpsave(FPsave*);
int	getrs232o(void);
int	getc(IOQ*);
int	gets(IOQ*, void*, int);
void	incontoggle(void);
void	kbdchar(int);
void	initq(IOQ*);
int	kbdputc(IOQ*, int);
void	kbdclock(void);
void	kbdrepeat(int);
KMap*	kmap(Page*);


@@ 38,19 44,25 @@ void	kunmap(KMap*);
void	mmuinit(void);
void	mousebuttons(int);
void	mouseclock(void);
int	mouseputc(IOQ*, int);
int	portprobe(char*, int, int, int, long);
void	printinit(void);
void	procrestore(Proc*, uchar*);
void	procsave(uchar*, int);
void	procsetup(Proc*);
int	putc(IOQ*, int);
void	puts(IOQ*, void*, int);
void	putkmmu(ulong, ulong);
void	putstr(char*);
void	putstrn(char*, long);
void	restartprint(Alarm*);
void	restfpregs(FPsave*);
void	rs232ichar(int);
void	rs232puts(IOQ*, char*, int);
void	rs232rintr(char);
void	rs232xintr(void);
void	screeninit(void);
void	screenputc(int);
void	screenputs(char*, int);
int	scsicap(int, uchar *);
Scsi*	scsicmd(int, int, long);
void	scsictrlintr(void);

M gnot/main.c => gnot/main.c +18 -0
@@ 40,6 40,8 @@ main(void)
	mmuinit();
	confinit();
	kmapinit();
	duartinit();
	screeninit();
	printinit();
	print("bank 0: %dM  bank 1: %dM\n", bank[0], bank[1]);
	flushmmu();


@@ 410,3 412,19 @@ procrestore(Proc *p, uchar *state)
	if(balu->cr0 != 0xFFFFFFFF)	/* balu busy */
		memmove(BALU, balu, sizeof balu);
}

void
buzz(int f, int d)
{
}

void
lights(int val)
{
}

void
firmware(void)
{
	panic("you asked for it");
}

M gnot/mem.h => gnot/mem.h +1 -2
@@ 97,9 97,8 @@
#define	USTKTOP	(TSTKTOP-TSTKSIZ*BY2PG) /* byte just beyond user stack */
#define	KZERO	KSEG			/* base of kernel address space */
#define	KTZERO	(KZERO+BY2PG)		/* first address in kernel text */
#define	USTACKSIZE	(4*1024*1024)	/* size of user stack */
#define	USTKSIZE	(4*1024*1024)	/* size of user stack */

#define	NSEG		5
#define	MACHSIZE	4096



M gnot/screen.c => gnot/screen.c +3 -493
@@ 20,12 20,6 @@ struct{
	int	bwid;
}out;

void	duartinit(void);
int	duartacr;
int	duartimr;

void	(*kprofp)(ulong);

GBitmap	gscreen =
{
	(ulong*)((4*1024*1024-256*1024)|KZERO),	/* BUG */


@@ 39,7 33,6 @@ GBitmap	gscreen =
void
screeninit(void)
{
	duartinit();
	/*
	 * Read HEX switch to set ldepth
	 */


@@ 84,492 77,9 @@ screenputc(int c)
	}
}

/*
 * Register set for half the duart.  There are really two sets.
 */
struct Duart{
	uchar	mr1_2;		/* Mode Register Channels 1 & 2 */
	uchar	sr_csr;		/* Status Register/Clock Select Register */
	uchar	cmnd;		/* Command Register */
	uchar	data;		/* RX Holding / TX Holding Register */
	uchar	ipc_acr;	/* Input Port Change/Aux. Control Register */
#define	ivr	ivr		/* Interrupt Vector Register */
	uchar	is_imr;		/* Interrupt Status/Interrupt Mask Register */
#define	ip_opcr	is_imr		/* Input Port/Output Port Configuration Register */
	uchar	ctur;		/* Counter/Timer Upper Register */
#define	scc_sopbc ctur		/* Start Counter Command/Set Output Port Bits Command */
	uchar	ctlr;		/* Counter/Timer Lower Register */
#define	scc_ropbc ctlr		/* Stop Counter Command/Reset Output Port Bits Command */
};

enum{
	CHAR_ERR	=0x00,	/* MR1x - Mode Register 1 */
	PAR_ENB		=0x00,
	EVEN_PAR	=0x00,
	ODD_PAR		=0x04,
	NO_PAR		=0x10,
	CBITS8		=0x03,
	CBITS7		=0x02,
	CBITS6		=0x01,
	CBITS5		=0x00,
	NORM_OP		=0x00,	/* MR2x - Mode Register 2 */
	TWOSTOPB	=0x0F,
	ONESTOPB	=0x07,
	ENB_RX		=0x01,	/* CRx - Command Register */
	DIS_RX		=0x02,
	ENB_TX		=0x04,
	DIS_TX		=0x08,
	RESET_MR 	=0x10,
	RESET_RCV  	=0x20,
	RESET_TRANS  	=0x30,
	RESET_ERR  	=0x40,
	RESET_BCH	=0x50,
	STRT_BRK	=0x60,
	STOP_BRK	=0x70,
	RCV_RDY		=0x01,	/* SRx - Channel Status Register */
	FIFOFULL	=0x02,
	XMT_RDY		=0x04,
	XMT_EMT		=0x08,
	OVR_ERR		=0x10,
	PAR_ERR		=0x20,
	FRM_ERR		=0x40,
	RCVD_BRK	=0x80,
	BD38400		=0xCC|0x0000,
	BD19200		=0xCC|0x0100,
	BD9600		=0xBB|0x0000,
	BD4800		=0x99|0x0000,
	BD2400		=0x88|0x0000,
	BD1200		=0x66|0x0000,
	BD300		=0x44|0x0000,
	IM_IPC		=0x80,	/* IMRx/ISRx - Interrupt Mask/Interrupt Status */
	IM_DBB		=0x40,
	IM_RRDYB	=0x20,
	IM_XRDYB	=0x10,
	IM_CRDY		=0x08,
	IM_DBA		=0x04,
	IM_RRDYA	=0x02,
	IM_XRDYA	=0x01,
};

uchar keymap[]={
/*80*/	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x8e,	0x58,
/*90*/	0x90,	0x91,	0x92,	0x93,	0x94,	0x95,	0x96,	0x97,
	0x98,	0x99,	0x9a,	0x9b,	0x58,	0x58,	0x58,	0x58,
/*A0*/	0x58,	0xa1,	0xa2,	0xa3,	0xa4,	0xa5,	0xa6,	0xa7,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0xae,	0xaf,
/*B0*/	0xb0,	0xb1,	0xb2,	0xb3,	0xb4,	0xb5,	0xb6,	0xb7,
	0xb8,	0xb9,	0x00,	0xbb,	0x1e,	0xbd,	0x60,	0x1f,
/*C0*/	0xc0,	0xc1,	0xc2,	0xc3,	0xc4,	0x58,	0xc6,	0x0a,
	0xc8,	0xc9,	0xca,	0xcb,	0xcc,	0xcd,	0xce,	0xcf,
/*D0*/	0x09,	0x08,	0xd2,	0xd3,	0xd4,	0xd5,	0xd6,	0xd7,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x7f,	0x58,
/*E0*/	0x58,	0x58,	0xe2,	0x1b,	0x0d,	0xe5,	0x58,	0x0a,
	0xe8,	0xe9,	0xea,	0xeb,	0xec,	0xed,	0xee,	0xef,
/*F0*/	0x09,	0x08,	0xb2,	0x1b,	0x0d,	0xf5,	0x81,	0x58,
	0x58,	0x58,	0x58,	0x58,	0x58,	0x58,	0x7f,	0x80,
};

void
duartinit(void)
{
	Duart *duart;

	duart  =  DUARTREG;

	/*
	 * Keyboard
	 */
	duart[0].cmnd = RESET_RCV|DIS_TX|DIS_RX;
	duart[0].cmnd = RESET_TRANS;
	duart[0].cmnd = RESET_ERR;
	duart[0].cmnd = RESET_MR;
	duart[0].mr1_2 = CHAR_ERR|PAR_ENB|EVEN_PAR|CBITS8;
	duart[0].mr1_2 = NORM_OP|ONESTOPB;
	duart[0].sr_csr = BD4800;

	/*
	 * RS232
	 */
	duart[1].cmnd = RESET_RCV|DIS_TX|DIS_RX;
	duart[1].cmnd = RESET_TRANS;
	duart[1].cmnd = RESET_ERR;
	duart[1].cmnd = RESET_MR;
	duart[1].mr1_2 = CHAR_ERR|NO_PAR|CBITS8;
	duart[1].mr1_2 = NORM_OP|ONESTOPB;
	duart[1].sr_csr = BD9600;

	/*
	 * Output port
	 */
	duart[0].ipc_acr = duartacr = 0xB7;	/* allow change	of state interrupt */
	duart[1].ip_opcr = 0x00;
	duart[1].scc_ropbc = 0xFF;	/* make sure the port is reset first */
	duart[1].scc_sopbc = 0x04;	/* dtr = 1, pp = 01 */
	duart[0].is_imr = duartimr = IM_IPC|IM_RRDYB|IM_XRDYB|IM_RRDYA|IM_XRDYA;
	duart[0].cmnd = ENB_TX|ENB_RX;	/* enable TX and RX last */
	duart[1].cmnd = ENB_TX|ENB_RX;

	/*
	 * Initialize keyboard
	 */
	while (!(duart[0].sr_csr & (XMT_EMT|XMT_RDY)))
		;
	duart[0].data = 0x02;
}

int
duartinputport(void)
{
	Duart *duart = DUARTREG;
	return duart[1].ip_opcr;
}
void
duartbaud(int b)
{
	int x = 0;
	Duart *duart = DUARTREG;

	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:
		error(Ebadarg);
	}
	if(x & 0x0100)
		duart[0].ipc_acr = duartacr |= 0x80;
	else
		duart[0].ipc_acr = duartacr &= ~0x80;
	duart[1].sr_csr = x;
}

void
duartdtr(int val)
{
	Duart *duart = DUARTREG;
	if (val)
		duart[1].scc_ropbc=0x01;
	else
		duart[1].scc_sopbc=0x01;
}

void
duartbreak(int ms)
{
	static QLock brk;
	Duart *duart = DUARTREG;
	if (ms<=0 || ms >20000)
		error(Ebadarg);
	qlock(&brk);
	duart[0].is_imr = duartimr &= ~IM_XRDYB;
	duart[1].cmnd = STRT_BRK|ENB_TX;
	tsleep(&u->p->sleep, return0, 0, ms);
	duart[1].cmnd = STOP_BRK|ENB_TX;
	duart[0].is_imr = duartimr |= IM_XRDYB;
	qunlock(&brk);
}

enum{
	Kptime=200
};
void
duartstarttimer(void)
{
	Duart *duart;
	char x;

	duart = DUARTREG;
	duart[0].ctur = (Kptime)>>8;
	duart[0].ctlr = (Kptime)&255;
	duart[0].is_imr = duartimr |= IM_CRDY;
	x = duart[1].scc_sopbc;
}

void
duartstoptimer(void)
{
	Duart *duart;
	char x;

	duart = DUARTREG;
	x = duart[1].scc_ropbc;
	duart[0].is_imr = duartimr &= ~IM_CRDY;
}

void
duartrs232intr(void)
{
	int c;
	Duart *duart;

	duart = DUARTREG;
	c = getrs232o();
	if(c == -1)
		duart[1].cmnd = DIS_TX;
	else
		duart[1].data = c;
}

void
duartstartrs232o(void)
{
	int s;
	Duart *duart;

	duart = DUARTREG;
	s = splduart();
	duart[1].cmnd = ENB_TX;
	if(duart[1].sr_csr & (XMT_RDY|XMT_EMT))
		duartrs232intr();
	splx(s);
}

struct latin
{
	uchar	l;
	char	c[2];
}latintab[] = {
	'€',	"!!",	/* spanish initial ! */
	'€',	"c|",	/* cent */
	'€',	"c$",	/* cent */
	'€',	"l$",	/* pound sterling */
	'€',	"g$",	/* general currency */
	'€',	"y$",	/* yen */
	'€',	"j$",	/* yen */
	'€',	"||",	/* broken vertical bar */
	'€',	"SS",	/* section symbol */
	'€',	"\"\"",	/* dieresis */
	'€',	"cr",	/* copyright */
	'€',	"cO",	/* copyright */
	'€',	"sa",	/* super a, feminine ordinal */
	'€',	"<<",	/* left angle quotation */
	'€',	"no",	/* not sign, hooked overbar */
	'€',	"--",	/* soft hyphen */
	'€',	"rg",	/* registered trademark */
	'€',	"__",	/* macron */
	'€',	"s0",	/* degree (sup o) */
	'€',	"+-",	/* plus-minus */
	'€',	"s2",	/* sup 2 */
	'€',	"s3",	/* sup 3 */
	'€',	"''",	/* grave accent */
	'€',	"mu",	/* mu */
	'€',	"pg",	/* paragraph (pilcrow) */
	'€',	"..",	/* centered . */
	'€',	",,",	/* cedilla */
	'€',	"s1",	/* sup 1 */
	'€',	"so",	/* sup o */
	'€',	">>",	/* right angle quotation */
	'€',	"14",	/* 1/4 */
	'€',	"12",	/* 1/2 */
	'€',	"34",	/* 3/4 */
	'€',	"??",	/* spanish initial ? */
	'€',	"A`",	/* A grave */
	'€',	"A'",	/* A acute */
	'€',	"A^",	/* A circumflex */
	'€',	"A~",	/* A tilde */
	'€',	"A\"",	/* A dieresis */
	'€',	"A:",	/* A dieresis */
	'€',	"Ao",	/* A circle */
	'€',	"AO",	/* A circle */
	'€',	"Ae",	/* AE ligature */
	'€',	"AE",	/* AE ligature */
	'€',	"C,",	/* C cedilla */
	'€',	"E`",	/* E grave */
	'€',	"E'",	/* E acute */
	'€',	"E^",	/* E circumflex */
	'€',	"E\"",	/* E dieresis */
	'€',	"E:",	/* E dieresis */
	'€',	"I`",	/* I grave */
	'€',	"I'",	/* I acute */
	'€',	"I^",	/* I circumflex */
	'€',	"I\"",	/* I dieresis */
	'€',	"I:",	/* I dieresis */
	'€',	"D-",	/* Eth */
	'€',	"N~",	/* N tilde */
	'€',	"O`",	/* O grave */
	'€',	"O'",	/* O acute */
	'€',	"O^",	/* O circumflex */
	'€',	"O~",	/* O tilde */
	'€',	"O\"",	/* O dieresis */
	'€',	"O:",	/* O dieresis */
	'€',	"OE",	/* O dieresis */
	'€',	"Oe",	/* O dieresis */
	'€',	"xx",	/* times sign */
	'€',	"O/",	/* O slash */
	'€',	"U`",	/* U grave */
	'€',	"U'",	/* U acute */
	'€',	"U^",	/* U circumflex */
	'€',	"U\"",	/* U dieresis */
	'€',	"U:",	/* U dieresis */
	'€',	"UE",	/* U dieresis */
	'€',	"Ue",	/* U dieresis */
	'€',	"Y'",	/* Y acute */
	'€',	"P|",	/* Thorn */
	'€',	"Th",	/* Thorn */
	'€',	"TH",	/* Thorn */
	'€',	"ss",	/* sharp s */
	'€',	"a`",	/* a grave */
	'€',	"a'",	/* a acute */
	'€',	"a^",	/* a circumflex */
	'€',	"a~",	/* a tilde */
	'€',	"a\"",	/* a dieresis */
	'€',	"a:",	/* a dieresis */
	'€',	"ao",	/* a circle */
	'€',	"ae",	/* ae ligature */
	'€',	"c,",	/* c cedilla */
	'€',	"e`",	/* e grave */
	'€',	"e'",	/* e acute */
	'€',	"e^",	/* e circumflex */
	'€',	"e\"",	/* e dieresis */
	'€',	"e:",	/* e dieresis */
	'€',	"i`",	/* i grave */
	'€',	"i'",	/* i acute */
	'€',	"i^",	/* i circumflex */
	'€',	"i\"",	/* i dieresis */
	'€',	"i:",	/* i dieresis */
	'€',	"d-",	/* eth */
	'€',	"n~",	/* n tilde */
	'€',	"o`",	/* o grave */
	'€',	"o'",	/* o acute */
	'€',	"o^",	/* o circumflex */
	'€',	"o~",	/* o tilde */
	'€',	"o\"",	/* o dieresis */
	'€',	"o:",	/* o dieresis */
	'€',	"oe",	/* o dieresis */
	'€',	"-:",	/* divide sign */
	'€',	"o/",	/* o slash */
	'€',	"u`",	/* u grave */
	'€',	"u'",	/* u acute */
	'€',	"u^",	/* u circumflex */
	'€',	"u\"",	/* u dieresis */
	'€',	"u:",	/* u dieresis */
	'€',	"ue",	/* u dieresis */
	'€',	"y'",	/* y acute */
	'€',	"th",	/* thorn */
	'€',	"p|",	/* thorn */
	'€',	"y\"",	/* y dieresis */
	'€',	"y:",	/* y dieresis */
	0,	0,
};

int
latin1(int k1, int k2)
{
	int i;
	struct latin *l;

	for(l=latintab; l->l; l++)
		if(k1==l->c[0] && k2==l->c[1])
			return l->l;
	return 0;
}

void
duartintr(Ureg *ur)
screenputs(char *s, int n)
{
	int cause, status, c;
	Duart *duart;
	static int kbdstate, k1, k2;

	duart = DUARTREG;
	cause = duart->is_imr;
	/*
	 * I can guess your interrupt.
	 */
	/*
	 * Is it 0?
	 */
	if(cause & IM_CRDY){
		if(kprofp)
			(*kprofp)(ur->pc);
		c = duart[1].scc_ropbc;
		duart[0].ctur = (Kptime)>>8;
		duart[0].ctlr = (Kptime)&255;
		c = duart[1].scc_sopbc;
		return;
	}
	/*
	 * Is it 1?
	 */
	if(cause & IM_RRDYA){		/* keyboard input */
		status = duart->sr_csr;
		c = duart->data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart->cmnd = RESET_ERR;
		if(status & PAR_ERR) /* control word: caps lock (0x4) or repeat (0x10) */
			kbdrepeat((c&0x10) == 0);
		else{
			if(c == 0x7F)	/* VIEW key (bizarre) */
				c = 0xFF;
			if(c == 0xB6)	/* NUM PAD */
				kbdstate = 1;
			else{
				if(c & 0x80)
					c = keymap[c&0x7F];
				switch(kbdstate){
				case 1:
					k1 = c;
					kbdstate = 2;
					break;
				case 2:
					k2 = c;
					c = latin1(k1, k2);
					if(c == 0){
						kbdchar(k1);
						c = k2;
					}
					/* fall through */
				default:
					kbdstate = 0;
					kbdchar(c);
				}
			}
		}
	}
	/*
	 * Is it 2?
	 */
	while(cause & IM_RRDYB){	/* rs232 input */
		status = duart[1].sr_csr;
		c = duart[1].data;
		if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
			duart[1].cmnd = RESET_ERR;
		else
			rs232ichar(c);
		cause = duart->is_imr;
	}
	/*
	 * Is it 3?
	 */
	if(cause & IM_XRDYB)		/* rs232 output */
		duartrs232intr();
	/*
	 * Is it 4?
	 */
	if(cause & IM_XRDYA)
		duart[0].cmnd = DIS_TX;
	/*
	 * Is it 5?
	 */
	if(cause & IM_IPC)
		mousebuttons((~duart[0].ipc_acr) & 7);
	while(n-- > 0)
		screenputc(*s++);
}

M port/devbit.c => port/devbit.c +8 -0
@@ 1145,6 1145,14 @@ mousetry(Ureg *ur)
	}
}

int
mouseputc(IOQ *q, int c)
{
	/*
	 *  put your favorite serial mouse code here
	 */
}

void
mouseupdate(int dolock)
{

M port/devproc.c => port/devproc.c +5 -1
@@ 130,11 130,13 @@ procopen(Chan *c, int omode)
	switch(QID(c->qid)){
	case Qtext:
		o = p->seg[TSEG].o;
		if(o==0 || p->state==Dead)
		if(o==0 || p->state==Dead) 
			goto Died;

		tc = o->chan;
		if(tc == 0)
			goto Died;

		if(incref(tc) == 0){
    Close:
			close(tc);


@@ 142,8 144,10 @@ procopen(Chan *c, int omode)
		}
		if(!(tc->flag&COPEN) || tc->mode!=OREAD)
			goto Close;

		if(p->pid != PID(c->qid))
			goto Close;

		qlock(&tc->rdl);
		tc->offset = 0;
		qunlock(&tc->rdl);

M port/fault.c => port/fault.c +2 -2
@@ 25,7 25,7 @@ fault(ulong addr, int read)
		if(addr > USTKTOP)
			return -1;
		s = &u->p->seg[SSEG];
		if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
		if(s->o==0 || addr<s->maxva-USTKSIZE || addr>=s->maxva)
			return -1;
		/* grow stack */
		o = s->o;


@@ 220,7 220,7 @@ validaddr(ulong addr, ulong len, int write)
	s = seg(u->p, addr);
	if(s==0){
		s = &u->p->seg[SSEG];
		if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
		if(s->o==0 || addr<s->maxva-USTKSIZE || addr>=s->maxva)
			goto Err;
	}
	if(write && (s->o->flag&OWRPERM)==0)

M port/portdat.h => port/portdat.h +5 -6
@@ 283,13 283,12 @@ enum					/* Argument to forkpgrp call */
};

/*
 *  process memory segments
 *  process memory segments - NSEG always last !
 */
#define	SSEG	0
#define	TSEG	1
#define	DSEG	2
#define	BSEG	3
#define	ESEG	4	/* used by exec to build new stack */
enum
{
	SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, NSEG
};

struct Seg
{

M port/portfns.h => port/portfns.h +0 -4
@@ 128,10 128,6 @@ void	resched(char*);
int	return0(void*);
Proc*	runproc(void);
void	savefpregs(FPsave*);
void	sccintr(void);
void	sccputs(IOQ*, char*, int);
void	sccsetup(void*);
void	sccspecial(int, IOQ*, IOQ*, int);
void	schedinit(void);
void	sched(void);
long	seconds(void);

M port/sturp.c => port/sturp.c +10 -4
@@ 157,10 157,12 @@ urpopen(Queue *q, Stream *s)
	 *  find a free urp structure
	 */
	for(up = urp; up < &urp[conf.nurp]; up++){
		qlock(up);
		if(up->state == 0)
			break;
		qunlock(up);
		if(up->state == 0){
			qlock(up);
			if(up->state == 0)
				break;
			qunlock(up);
		}
	}
	if(up == &urp[conf.nurp]){
		q->ptr = 0;


@@ 265,6 267,8 @@ urpciput(Queue *q, Block *bp)
	int ctl;

	up = (Urp *)q->ptr;
	if(up == 0)
		return;
	if(bp->type != M_DATA){
		urpctliput(up, q, bp);
		return;


@@ 364,6 368,8 @@ urpiput(Queue *q, Block *bp)
	int ctl;

	up = (Urp *)q->ptr;
	if(up == 0)
		return;
	if(bp->type != M_DATA){
		urpctliput(up, q, bp);
		return;

M port/sysproc.c => port/sysproc.c +35 -0
@@ 545,3 545,38 @@ sysbrk_(ulong *arg)
	u->p->bssend = addr;
	return 0;
}
/*
long
syslkbrk(ulong *arg)
{
	ulong addr;
	Orig *o;
	Seg *s;

	addr = arg[0];
	s = &u->p->seg[LSEG];
	if(addr < LKSEGBASE)
		error(Esegaddr);

	/* If we have never seen a lock segment create one */
	if(s->o == 0) {
		s->proc = u->p;
		s->minva = LKSEGBASE;
		s->maxva = addr;
		o = neworig(s->minva, (addr-LKSEGBASE)>>PGSHIFT, OWRPERM, 0);
		o->minca = 0;
		o->maxca = 0;
		s->o = o;
		s->mod = 0;
	}
	if(addr < s->maxva)
		return 0;
	if(segaddr(&u->p->seg[LSEG], s->minva, addr) == 0) {
		pprint("bad segaddr in brk\n");
		pexit("Suicide", 0);
		error(Esegaddr);

	}
	return 0;
}
*/

M power/lock.c => power/lock.c +34 -9
@@ 13,29 13,58 @@
 */

#define	SEMPERPG	64		/* hardware semaphores per page */
#define	NONSEMPERPG	(WD2PG-64)	/* words of non-semaphore per page */
#define NSEMPG		1024

struct
{
	Lock	lock;			/* lock to allocate */
	ulong	*nextsem;		/* next one to allocate */
	int	nsem;			/* at SEMPERPG, jump to next page */
	uchar	bmap[NSEMPG];		/* allocation map */
}semalloc;

void
lockinit(void)
{
	memset(semalloc.bmap, 0, sizeof(semalloc.bmap));
	semalloc.bmap[0] = 1;
	semalloc.lock.sbsem = SBSEM;
	semalloc.nextsem = SBSEM+1;
	semalloc.nsem = 1;
	unlock(&semalloc.lock);
}

/* return the address of the next free page of locks */
ulong*
lkpgalloc(void)
{
	uchar *p, *top;

	top = &semalloc.bmap[NSEMPG];
	for(p = semalloc.bmap; *p && p < top; p++)
		;
	if(p == top)
		panic("lkpgalloc");

	*p = 1;
	return (p-semalloc.bmap)*WD2PG + SBSEM;
}

void
lkpgfree(ulong *lpa)
{
	uchar *p;

	p = &semalloc.bmap[(lpa-SBSEM)/WD2PG];
	if(!*p)
		panic("lkpgfree");
	*p = 0;
}

#define PCOFF -9

/*
 * If l->sbsem is zero, allocate a hardware semaphore first.
 * There is no way to free a semaphore.
 */
void
lock(Lock *ll)


@@ 49,9 78,7 @@ lock(Lock *ll)
		lock(&semalloc.lock);
		if(semalloc.nsem == SEMPERPG){
			semalloc.nsem = 0;
			semalloc.nextsem += NONSEMPERPG;
			if(semalloc.nextsem == SBSEMTOP)
				panic("sem");
			semalloc.nextsem = lkpgalloc();
		}
		l->sbsem = semalloc.nextsem;
		semalloc.nextsem++;


@@ 74,7 101,7 @@ lock(Lock *ll)
	}
	*sbsem = 0;
	print("lock loop %lux pc %lux held by pc %lux\n", l, ((ulong*)&ll)[PCOFF], l->pc);
dumpstack();
	dumpstack();
}

int


@@ 87,9 114,7 @@ canlock(Lock *l)
		lock(&semalloc.lock);
		if(semalloc.nsem == SEMPERPG){
			semalloc.nsem = 0;
			semalloc.nextsem += NONSEMPERPG;
			if(semalloc.nextsem == SBSEMTOP)
				panic("sem");
			semalloc.nextsem = lkpgalloc();
		}
		l->sbsem = semalloc.nextsem;
		semalloc.nextsem++;

M power/mem.h => power/mem.h +10 -11
@@ 98,7 98,6 @@
#define	PTEPID(n)	((n)<<6)
#define TLBPID(n)	(((n)>>6)&0x3F)

/* N.B. MUST CHANGE l.s utlbmiss if you want to change this */
#define STLBLOG		11
#define STLBSIZE	(1<<STLBLOG)



@@ 110,14 109,16 @@
 * Address spaces
 */

#define	UZERO	KUSEG			/* base of user address space */
#define	UTZERO	(UZERO+BY2PG)		/* first address in user text */
#define	USTKTOP	KZERO			/* byte just beyond user stack */
#define	TSTKTOP	(USERADDR+TSTKSIZ*BY2PG)/* top of temporary stack */
#define TSTKSIZ 100
#define	KZERO	KSEG0			/* base of kernel address space */
#define	KTZERO	(KZERO+0x20000)		/* first address in kernel text */
#define	USTACKSIZE	(4*1024*1024)	/* size of user stack */
#define	UZERO		KUSEG			/* base of user address space */
#define	UTZERO		(UZERO+BY2PG)		/* first address in user text */
#define	USTKTOP		KZERO			/* byte just beyond user stack */
#define	TSTKTOP		(USERADDR+TSTKSIZ*BY2PG)/* top of temporary stack */
#define TSTKSIZ 	100
#define	KZERO		KSEG0			/* base of kernel address space */
#define	KTZERO		(KZERO+0x20000)		/* first address in kernel text */
#define	USTKSIZE	(4*1024*1024)		/* size of user stack */
#define LKSEGSIZE	(25*BY2PG)
#define LKSEGBASE	(USTKTOP-USTKSIZE-LKSEGSIZE)	
/*
 * Exception codes
 */


@@ 138,6 139,4 @@
#define	CUNK14	14		/* undefined 14 */
#define	CUNK15	15		/* undefined 15 */

#define	NSEG	5

#define isphys(x) ((ulong)(x) & KZERO)

M ss/fns.h => ss/fns.h +4 -0
@@ 77,6 77,10 @@ void	reset(void);
void	restartprint(Alarm*);
void	restfpregs(FPsave*);
void	rs232ichar(int);
void	sccintr(void);
void	sccputs(IOQ*, char*, int);
void	sccsetup(void*);
void	sccspecial(int, IOQ*, IOQ*, int);
void	screeninit(void);
void	screenputc(int);
void	spldone(void);

M ss/mem.h => ss/mem.h +1 -2
@@ 128,9 128,8 @@
#define	USTKTOP	(TSTKTOP-TSTKSIZ*BY2PG)	/* byte just beyond user stack */
#define	KZERO	0xE0000000		/* base of kernel address space */
#define	KTZERO	(KZERO+4*BY2PG)		/* first address in kernel text */
#define	USTACKSIZE	(4*1024*1024)	/* size of user stack */
#define	USTKSIZE	(4*1024*1024)	/* size of user stack */

#define	NSEG		5
#define	MACHSIZE	4096

#define isphys(x) (((ulong)(x)&0xF0000000) == KZERO)