~kris/9p

9hist

cbb4650fd0b62564b623638a03eb5d538ae3cd7c — David du Colombier 35 years ago 0840ca4
Plan 9 from Bell Labs 1991-08-03
12 files changed, 399 insertions(+), 36 deletions(-)

M pc/devfloppy.c
M pc/devhard.c
M pc/devuart.c
A pc/dma.c
M pc/fns.h
M pc/kbd.c
M pc/main.c
M pc/trap.c
M port/segment.c
M power/conf.h
M power/dat.h
M power/main.c
M pc/devfloppy.c => pc/devfloppy.c +7 -0
@@ 367,6 367,7 @@ static void
floppykproc(void *a)
{
	Drive *dp;
	int disp = 0;

	waserror();
	for(;;){


@@ 378,7 379,13 @@ floppykproc(void *a)
				qunlock(dp);
			}
		}
		disp++;
		if(owl(disp&1) < 0)
			print("owl failed\n");
		if(mail((disp>>1)&1) < 0)
			print("mail failed\n");
		tsleep(&floppy.kr, return0, 0, 5*1000);
		
	}
}


M pc/devhard.c => pc/devhard.c +25 -2
@@ 116,6 116,10 @@ Dirtab harddir[]={
};
#define NHDIR	(sizeof(harddir)/sizeof(Dirtab))

static void	hardintr(Ureg*);
static long	hardxfer(Drive*, int, void*, long, long);
static long	hardident(Drive*);

void
hardreset(void)
{


@@ 213,6 217,8 @@ hardread(Chan *c, void *a, long n)
		break;
	case Qstruct:
		hardident(dp);
		dp->cap = 512 * dp->id->lcyls * dp->id->lheads *dp->id->ls2t;
		dp->bytes = 512;
		if (n < 2*sizeof(ulong))
			error(Ebadarg);
		if (c->offset >= 2*sizeof(ulong))


@@ 257,7 263,7 @@ hardwrite(Chan *c, void *a, long n)
 *  did an interrupt happen?
 */
static int
interrupted(Drive *dp)
interrupted(void *a)
{
	return hard.intr;
}


@@ 265,16 271,33 @@ interrupted(Drive *dp)
/*
 *  get parameters from the drive
 */
static long
hardident(Drive *dp)
{
	qlock(&hard);
	hard.intr = 0;
	outb(Pdh, dp->dev<<4);
	outb(Pcmd, Cident);
	sleep(&hard.r, interrupted, 0);
	insw(Pdata, &hard.id, 512);
	qunlock(&hard);
}

long
static long
hardxfer(Drive *dp, int cmd, void *va, long off, long len)
{
	errors("not implemented");
}

/*
 *  take/clear a disk interrupt
 */
static void
hardintr(Ureg *ur)
{
	hard.status = inb(Pstatus);
	hard.intr = 1;
	print("hardintr\n");
	wakeup(&hard.r);
}


M pc/devuart.c => pc/devuart.c +15 -7
@@ 37,7 37,7 @@ enum
	 Loop=	(1<<4),		/*  loop bask */
	Lstat=	5,		/* line status */
	 Inready=(1<<0),	/*  receive buffer full */
	 Outbusy=(1<<5),	/*  output buffer full */
	 Outready=(1<<5),	/*  output buffer full */
	Mstat=	6,		/* modem status */
	Scratch=7,		/* scratchpad */
	Dlsb=	0,		/* divisor lsb */


@@ 88,7 88,7 @@ uartsetbaud(Uart *up, int rate)
{
	ulong brconst;

	brconst = (UartFREQ+8*rate-1)/16*rate;
	brconst = (UartFREQ+8*rate-1)/(16*rate);

	uartwrreg(up, Format, Dra);
	uartwrreg(up, Dmsb, (brconst>>8) & 0xff);


@@ 178,6 178,7 @@ uartputs(IOQ *cq, char *s, int n)
{
	Uart *up = cq->ptr;
	int st, ch, x;
	int tries;

	x = splhi();
	lock(cq);


@@ 187,7 188,8 @@ uartputs(IOQ *cq, char *s, int n)
print("<start %2.2ux>", ch);/**/
		if(ch >= 0){
			up->printing = 1;
			while(uartrdreg(up, Lstat) & Outbusy)
			for(tries = 0; tries<10000 && !(uartrdreg(up, Lstat)&Outready);
				tries++)
				;
			outb(up->port + Data, ch);
		}


@@ 202,11 204,13 @@ print("<start %2.2ux>", ch);/**/
void
uartintr(Uart *up)
{
	int s;
	int ch;
	IOQ *cq;
	int s;

	switch(uartrdreg(up, Istat)){
	s = uartrdreg(up, Istat);
print("uartintr %lux\n", s);
	switch(s){
	case 3:
		/*
		 *  get any input characters


@@ 227,10 231,11 @@ uartintr(Uart *up)
		/*
		 *  send next output character
		 */
		if((s & Outbusy)==0){
		if(uartrdreg(up, Lstat)&Outready){
			cq = up->oq;
			lock(cq);
			ch = getc(cq);
print("<cont %2.2ux>", ch);/**/
			if(ch < 0){
				up->printing = 0;
				wakeup(&cq->r);


@@ 270,6 275,7 @@ uartenable(Uart *up)
		up->iq->ptr = up;
		up->sticky[Iena] |= Ircv;
	}
	up->sticky[Iena] |= (1<<2) | (1<<3);

	/*
 	 *  turn on interrupts


@@ 465,7 471,6 @@ uartkproc(void *a)

loop:
	while ((n = cangetc(cq)) == 0){
print("uart0 sleeping/n");
		sleep(&cq->r, cangetc, cq);
	}
	qlock(up);


@@ 506,6 511,9 @@ uartreset(void)
{
	Uart *up;

	if(serial(0) < 0)
		print("can't turn on power\n");

	uartsetup();
	for(up = uart; up < &uart[2]; up++){
		if(up->nostream)

A pc/dma.c => pc/dma.c +173 -0
@@ 0,0 1,173 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"

/*
 *  headland chip set for the safari.
 */
typedef struct DMAport	DMAport;
typedef struct DMA	DMA;
typedef struct DMAxfer	DMAxfer;

enum
{
	/*
	 *  the byte registers for DMA0 are all one byte apart
	 */
	Dma0=		0x00,
	Dma0status=	Dma0+0x8,	/* status port */
	Dma0reset=	Dma0+0xD,	/* reset port */

	/*
	 *  the byte registers for DMA1 are all two bytes apart (why?)
	 */
	Dma1=		0xC0,
	Dma1status=	Dma1+2*0x8,	/* status port */
	Dma1reset=	Dma1+2*0xD,	/* reset port */
};

/*
 *  state of a dma transfer
 */
struct DMAxfer
{
	Page	*pg;		/* page used by dma */
	void	*va;		/* virtual address destination/src */
	long	len;		/* bytes to be transferred */
	int	isread;
};

/*
 *  the dma controllers.  the first half of this structure specifies
 *  the I/O ports used by the DMA controllers.
 */
struct DMAport
{
	uchar	addr[4];	/* current address (4 channels) */
	uchar	count[4];	/* current count (4 channels) */
	uchar	page[4];	/* page registers (4 channels) */
	uchar	cmd;		/* command status register */
	uchar	req;		/* request registers */
	uchar	sbm;		/* single bit mask register */
	uchar	mode;		/* mode register */
	uchar	cbp;		/* clear byte pointer */
	uchar	mc;		/* master clear */
	uchar	cmask;		/* clear mask register */
	uchar	wam;		/* write all mask register bit */

	Lock;
};

struct DMA
{
	DMAport;
	Lock;
	DMAxfer	x[4];
};

DMA dma[2] = {
	{ 0x00, 0x02, 0x04, 0x06,
	  0x01, 0x03, 0x05, 0x07,
	  0x87, 0x83, 0x81, 0x82,
	  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
	{ 0xc0, 0xc6, 0xca, 0xce,
	  0xc4, 0xc8, 0xcc, 0xcf,
	  0x80, 0x8b, 0x89, 0x8a,
	  0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde },
};

/*
 *  setup a dma transfer.  if the destination is not in kernel
 *  memory, allocate a page for the transfer.
 *
 *  we assume BIOS has set up the command register before we
 *  are booted.
 *
 *  return the updated transfer length (we can't transfer across 64k
 *  boundaries)
 */
long
dmasetup(int chan, void *va, long len, int isread)
{
	DMA *dp;
	DMAxfer *xp;
	ulong pa;
	uchar mode;

	dp = &dma[(chan>>2)&1];
	chan = chan & 3;
	xp = &dp->x[chan];

	/*
	 *  if this isn't kernel memory (or crossing 64k boundary),
	 *  allocate a page for the DMA.
	 */
	pa = ((ulong)va) & ~KZERO;
	if(!isphys(va) || (pa&0xFFFF0000)!=((pa+len)&0xFFFF0000)){
		xp->pg = newpage(1, 0, 0);
		if(len > BY2PG)
			len = BY2PG;
		if(!isread)
			memmove((void*)(KZERO|xp->pg->pa), va, len);
		xp->va = va;
		xp->len = len;
		xp->isread = isread;
		pa = xp->pg->pa;
	}

	/*
	 * this setup must be atomic
	 */
	lock(dp);
	outb(dp->cbp, 0);		/* set count & address to their first byte */
	mode = (isread ? 0x44 : 0x48) | chan;
	outb(dp->mode, mode);		/* single mode dma (give CPU a chance at mem) */
	outb(dp->addr[chan], pa);		/* set address */
	outb(dp->addr[chan], pa>>8);
	outb(dp->page[chan], pa>>16);
	outb(dp->count[chan], len-1);		/* set count */
	outb(dp->count[chan], (len-1)>>8);
	outb(dp->sbm, chan);		/* enable the channel */
	unlock(dp);

	return len;
}

/*
 *  this must be called after a dma has been completed.
 *
 *  if a page has been allocated for the dma,
 *  copy the data into the actual destination
 *  and free the page.
 */
void
dmaend(int chan)
{
	DMA *dp;
	DMAxfer *xp;
	ulong addr;
	uchar mode;

	dp = &dma[(chan>>2)&1];
	chan = chan & 3;

	/*
	 *  disable the channel
	 */
	lock(dp);
	outb(dp->sbm, 4|chan);
	unlock(dp);

	xp = &dp->x[chan];
	if(xp->pg == 0)
		return;

	/*
	 *  copy out of temporary page
	 */
	memmove(xp->va, (void*)(KZERO|xp->pg->pa), xp->len);
	putpage(xp->pg);
	xp->pg = 0;
}

M pc/fns.h => pc/fns.h +3 -0
@@ 16,6 16,8 @@ void	fprestore(FPsave*);
ulong	getcr2(void);
void	idle(void);
int	inb(int);
int	inss(int, void*, int);
int	outss(int, void*, int);
void	kbdinit(void);
void	kbdintr(Ureg*);
void	mmuinit(void);


@@ 31,6 33,7 @@ void	puttr(ulong);
void	screeninit(void);
void	screenputc(int);
void	screenputs(char*, int);
int	serial(int);
void	setvec(int, void (*)(Ureg*));
void	systrap(void);
void	touser(void);

M pc/kbd.c => pc/kbd.c +52 -25
@@ 240,35 240,64 @@ latin1(int k1, int k2)
	return 0;
}

static void
mousecmd(int cmd, int arg)
/*
 *  wait for output no longer busy
 */
static int
outready(void)
{
	int tries;

	for(tries = 0; (inb(Status) & Outbusy); tries++)
		if(tries > 1000)
			return -1;
	return 0;
}

/*
 *  wait for input
 */
static int
inready(void)
{
	int tries;

	for(tries = 0; !(inb(Status) & Inready); tries++)
		if(tries > 1000)
			return -1;
	return 0;
}

/*
 *  send a command to the mouse
 */
static int
mousecmd(int cmd)
{
	unsigned int c;
	int tries;

	do {
		while(inb(Status) & Outbusy)
			;
	for(tries=0; tries < 10; tries++){
		if(outready() < 0)
			return -1;
		outb(Cmd, 0xD4);
		while(inb(Status) & Outbusy)
			;
		if(outready() < 0)
			return -1;
		outb(Data, cmd);
		if(arg >= 0){
			while(inb(Status) & Outbusy)
				;
			outb(Data, arg);
		}
		while(!(inb(Status) & Inready))
			;
		if(inready() < 0)
			return -1;
		c = inb(Data);
	} while(c == 0xFE);
	if(c != 0xFA)
		print("mouse command returns bad status %lux", c);
		return -1;
	return 0;
}

void
kbdinit(void)
{
	int c, s;
	int tries;

	initq(&kbdq);
	setvec(Kbdvec, kbdintr);


@@ 282,19 311,17 @@ kbdinit(void)

	/* enable kbd/mouse xfers and interrupts */
	outb(Cmd, 0x60);
	while(inb(Status) & Outbusy)
		;
	if(outready() < 0)
		print("kbd init failed\n");
	outb(Data, 0x47);
	while(inb(Status) & Outbusy)
		;
	if(outready() < 0)
		print("kbd init failed\n");
	outb(Cmd, 0xA8);

	/* make mouse streaming (and enabled) */
	mousecmd(0xEA, -1);
	mousecmd(0xF4, -1);

	/* resolution */
/*	mousecmd(0xE8, 0x03); /**/
	/* make mouse streaming, enabled */
	if(mousecmd(0xEA) < 0
	|| mousecmd(0xF4) < 0)
		print("can't initialize mouse\n");
}

/*

M pc/main.c => pc/main.c +117 -0
@@ 265,3 265,120 @@ void
lights(int val)
{
}


/*
 *  special stuff for 80c51 power management and headland system controller
 */
enum
{
	/*
	 *  system control port
	 */
	Head=		0x92,		/* control port */
	 Reset=		(1<<0),		/* reset the 386 */
	 A20ena=	(1<<1),		/* enable address line 20 */

	/*
	 *  power management unit ports
	 */
	Pmudata=	0x198,

	Pmucsr=		0x199,
	 Busy=	0x1,
};

/*
 *  enable address bit 20
 */
void
a20enable(void)
{
	outb(Head, A20ena);
}

/*
 *  reset the chip
 */
void
exit(void)
{
	int i;

	u = 0;
	print("exiting\n");
	outb(Head, Reset);
}

/*
 *  return when pmu ready
 */
static int
pmuready(void)
{
	int tries;

	for(tries = 0; (inb(Pmucsr) & Busy); tries++)
		if(tries > 1000)
			return -1;
	return 0;
}

/*
 *  return when pmu busy
 */
static int
pmubusy(void)
{
	int tries;

	for(tries = 0; !(inb(Pmucsr) & Busy); tries++)
		if(tries > 1000)
			return -1;
	return 0;
}

/*
 *  set a bit in the PMU
 */
int
pmuwrbit(int index, int bit, int pos)
{
	outb(Pmucsr, 0x02);		/* next is command request */
	if(pmuready() < 0)
		return -1;
	outb(Pmudata, (2<<4) | index);	/* send write bit command */
	outb(Pmucsr, 0x01);		/* send available */
	if(pmubusy() < 0)
		return -1;
	outb(Pmucsr, 0x01);		/* next is data */
	if(pmuready() < 0)
		return -1;
	outb(Pmudata, (bit<<3) | pos);	/* send bit to write */
	outb(Pmucsr, 0x01);		/* send available */
	if(pmubusy() < 0)
		return -1;
}

/*
 *  control power to the serial line
 *	onoff == 0 means turn power on
 *	onoff == 1 means off
 */
int
serial(int onoff)
{
	return pmuwrbit(1, onoff, 6);
}

int
owl(int onoff)
{
	return pmuwrbit(0, onoff, 4);
}

int
mail(int onoff)
{
	return pmuwrbit(0, onoff, 1);
}

M pc/trap.c => pc/trap.c +1 -1
@@ 35,7 35,7 @@ enum
};

int	int0mask = 0xff;	/* interrupts enabled for first 8259 */
int	int1mask = 0xff;		/* interrupts enabled for second 8259 */
int	int1mask = 0xff;	/* interrupts enabled for second 8259 */

/*
 *  trap/interrupt gates

M port/segment.c => port/segment.c +2 -1
@@ 438,7 438,8 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
		ns = u->p->seg[i];
		if(ns == 0)
			continue;	
		if(newtop >= ns->base && newtop < ns->top) 
		if((newtop > ns->base && newtop <= ns->top) ||
		   (va >= ns->base && va < ns->top))
			errors("segments overlap");
	}


M power/conf.h => power/conf.h +1 -0
@@ 3,6 3,7 @@ Conftab conftab[] = {
	{"nproc", &conf.nproc },
	{"npgrp", &conf.npgrp },
	{"npage0", &conf.npage0 },
	{"npage1", &conf.npage1 },
	{"npage", &conf.npage },
	{"nseg", &conf.nseg },
	{"nimage", &conf.nimage },

M power/dat.h => power/dat.h +1 -0
@@ 40,6 40,7 @@ struct Conf
	ulong	nproc;		/* processes */
	ulong	npgrp;		/* process groups */
	ulong	npage0;		/* total physical pages of memory */
	ulong	npage1;		/* total physical pages of memory */
	ulong	npage;		/* total physical pages of memory */
	ulong	nseg;		/* number of segments */
	ulong	nimage;		/* number of page cache image headers */

M power/main.c => power/main.c +2 -0
@@ 539,6 539,8 @@ confinit(void)
	conf.npage0 = i*1024/4;
	conf.base0 = 0;
	conf.npage = conf.npage0;
	conf.npage1 = 0;
	conf.base1 = 0;
	conf.maxialloc = (128*1024*1024-256*1024-BY2PG);

	/*