~kris/9p

9hist

c35f9ac12ce1b4ada6fa52887455fd2d439fde20 — David du Colombier 33 years ago 2b67be2
Plan 9 from Bell Labs 1993-09-15
M carrera/io.h => carrera/io.h +4 -0
@@ 1,5 1,8 @@
/*
 * These register addresses have already been adjusted for BE operation
 *
 * The EISA memory address is completely fictional. Look at mmu.c for
 * a translation of Eisamphys into a 33 bit address.
 */
enum
{


@@ 35,6 38,7 @@ enum
	I386ack		= 0xE000023f,
	EisaControl	= 0xE0010000,	/* Second 64K Page from Devicevirt */
	Eisamphys	= 0x91000000,
	  Eisavgaphys	= Eisamphys+0xA0000,
	Eisamvirt	= 0xE0300000,	/* Second 1M page entry from Intctl */
	Intctlphys	= 0xF0000000,	
	Intctlvirt	= 0xE0200000,

M carrera/main.c => carrera/main.c +2 -2
@@ 51,8 51,8 @@ main(void)
	pageinit();
	procinit0();
	initseg();
	links();
	chandevreset();
	rootfiles();
	swapinit();
	userinit();
	schedinit();


@@ 179,7 179,7 @@ ioinit(void)
	 * Map Interrupt control & Eisa memory
	 */
	intphys  = IOPTE|PPN(Intctlphys);
	isamphys = IOPTE|PPN(Eisamphys);
	isamphys = /* IOPTE|PPN(Eisamphys) */ PTEGLOBL;

	puttlbx(2, Intctlvirt, intphys, isamphys, PGSZ1M);


M carrera/mmu.c => carrera/mmu.c +10 -1
@@ 3,6 3,7 @@
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

/*
 *  tlb entry 0 is used only by mmuswitch() to set the current tlb pid.


@@ 258,16 259,24 @@ newtlbpid(Proc *p)
void
putmmu(ulong tlbvirt, ulong tlbphys, Page *pg)
{
	int s;
	short tp;
	char *ctl;
	Softtlb *entry;
	int s;

	s = splhi();
	tp = up->pidonmach[m->machno];
	if(tp == 0)
		tp = newtlbpid(up);

	/*
	 * Fix up EISA memory address which are greater
	 * than 32 bits physical: 0x100000000
	 */
	if((tlbphys&0xffff0000) == PPN(Eisamphys)) {
		tlbphys &= ~PPN(Eisamphys);
		tlbphys |= 0x04000000;
	}
	tlbvirt |= PTEPID(tp);
	if((tlbphys & PTEALGMASK) != PTEUNCACHED) {
		tlbphys &= ~PTEALGMASK;

M carrera/segment.h => carrera/segment.h +5 -4
@@ 4,8 4,9 @@

Physseg physseg[] =
{
	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE,	0, 0 },
	{ SG_BSS,	"memory",	0,	SEGMAXSIZE,	0, 0 },
	{ SG_PHYSICAL,	"eisaio",	Eisaphys, 64*1024,	0, 0 },
	{ 0,		0,		0,	0,		0, 0 },
	{ SG_SHARED,	"shared",	0,		SEGMAXSIZE,	0, 0 },
	{ SG_BSS,	"memory",	0,		SEGMAXSIZE,	0, 0 },
	{ SG_PHYSICAL,	"eisaio",	Eisaphys,	64*1024,	0, 0 },
	{ SG_PHYSICAL,	"eisavga",	Eisavgaphys,	128*1024,	0, 0 },
	{ 0,		0,		0,		0,		0, 0 },
};

M pc/adaptec.c => pc/adaptec.c +37 -79
@@ 1,5 1,9 @@
/*
 * Adaptec AHA-154[02]B Intelligent Host Adapter.
 * Adaptec AHA-154[02][BC] Intelligent Host Adapter.
 * Needs work:
 *	handle multiple controllers;
 *	set options from user-level;
 *	split out to handle ultrastor too;
 */
#include "u.h"
#include "../port/lib.h"


@@ 11,12 15,6 @@

#include "ureg.h"

/*
 * Uniprocessors can't (don't need to) lock.
 */
#define lock(l)
#define unlock(l)

enum {
	NCtlr		= 1,
	NTarget		= 8,		/* targets per controller */


@@ 314,7 312,8 @@ scsiio(int bus, Scsi *p, int rw)
	 * requests off the queue in any order.
	 */
	s = splhi();
	lock(ctlr);
	if(active.machs > 1)
		lock(ctlr);

	tp->done = 0;
	tp->active = ctlr->active;


@@ 334,7 333,8 @@ scsiio(int bus, Scsi *p, int rw)
	if(ctlr->mbox >= &ctlr->mb[NTarget])
		ctlr->mbox = ctlr->mb;

	unlock(ctlr);
	if(active.machs > 1)
		unlock(ctlr);
	splx(s);

	/*


@@ 364,8 364,8 @@ scsiio(int bus, Scsi *p, int rw)
	return status;
}

int
scsiexec(Scsi *p, int rw)
static int
aha1542exec(Scsi *p, int rw)
{
	Ctlr *ctlr = &softctlr[0];



@@ 387,7 387,8 @@ interrupt(Ureg *ur)

	USED(ur);

	lock(ctlr);
	if(active.machs > 1)
		lock(ctlr);

	/*
	 * Save and clear the interrupt(s). The only


@@ 430,7 431,8 @@ interrupt(Ureg *ur)
			ctlr->mbix = &ctlr->mb[NTarget];
	}

	unlock(ctlr);
	if(active.machs > 1)
		unlock(ctlr);
}

static void


@@ 465,83 467,39 @@ reset(Ctlr *ctlr, ulong port, ulong id)
	issue(ctlr);
}

void
resetscsi(void)
static ISAConf aha1542 = {
	"aha1542",
	Port,
	Irq,
	0,
	0,
};

int (*
aha1542reset(void))(Scsi*, int)
{
	ulong port;
	ISAConf *isa = &aha1542;

	/*
	 * For the moment assume the factory default settings.
	 * See if we have any configuration info.
	 * Only one controller for now.
	 */
	port = Port;
	if(isaconfig("scsi", 0, &aha1542) == 0)
		return 0;

	/*
	 * Attempt to soft-reset the board and reset
	 * Attempt to hard-reset the board and reset
	 * the SCSI bus. If the board state doesn't settle to
	 * idle with mailbox initialisation required, either
	 * it isn't an Adaptec or it's broken.
	 */
	outb(port+Rc, Srst|Scrst);
	outb(isa->port+Rc, Hrst|Scrst);
	delay(500);
	if(inb(port+Rs) != (Init|Idle))
		return;

	setvec(Int0vec+Irq, interrupt);
	reset(&softctlr[0], port, CtlrID);
}

/*
 * Known to devscsi.c.
 */
int scsidebugs[8];
int scsiownid = CtlrID;

void
initscsi(void)
{
}

/*
 * Quick hack. Need to do a better job of dynamic initialisation
 * for machines with peculiar memory/cache restictions.
 * Also, what about 16Mb address limit on the Adaptec?
 */
static ulong bufdatasize;

void
scsibufreset(ulong datasize)
{
	bufdatasize = datasize;
}

Scsibuf *
scsibuf(void)
{
	Scsibuf *b;
	if(inb(isa->port+Rs) != (Init|Idle))
		return 0;

	b = smalloc(sizeof(*b));
	b->virt = smalloc(bufdatasize);
	b->phys = (void *)(PADDR(b->virt));
	return b;
}

void
scsifree(Scsibuf *b)
{
	free(b->virt);
	free(b);
}

/*
 * Hack for devvid
 */
Scsibuf *
scsialloc(ulong n)
{
	Scsibuf *b;
	setvec(Int0vec+isa->irq, interrupt);
	reset(&softctlr[0], isa->port, CtlrID);

	b = smalloc(sizeof(*b));
	b->virt = smalloc(n);
	b->phys = (void *)(PADDR(b->virt));
	return b;
	return aha1542exec;
}

M pc/clock.c => pc/clock.c +11 -17
@@ 72,7 72,7 @@ clockinit(void)
	x -= y;

	/*
	 *  fix count, the factor of 2 is a hack
	 *  fix count
	 */
	delayloop = (delayloop*1193*10)/x;
	if(delayloop == 0)


@@ 104,20 104,14 @@ clock(Ureg *ur)
	nrun = (nrdy+nrun)*1000;
	MACHP(0)->load = (MACHP(0)->load*19+nrun)/20;

	if(u && p && p->state==Running){
		/*
		 *  preemption
		 */
		if(anyready()){
			if(p->hasspin)
				p->hasspin = 0;
			else
				sched();
		}
		if((ur->cs&0xffff) == UESEL){
			spllo();		/* in case we fault */
			(*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);	/* profiling clock */
			splhi();
		}
	}
	if(up == 0 || (ur->cs&0xffff) != UESEL || up->state != Running)
		return;

	if(anyready())
		sched();

	/* user profiling clock */
	spllo();		/* in case we fault */
	(*(ulong*)(USTKTOP-BY2WD)) += TK2MS(1);
	splhi();
}

M pc/dat.h => pc/dat.h +16 -36
@@ 1,5 1,6 @@
typedef struct Conf	Conf;
typedef struct FPsave	FPsave;
typedef struct ISAConf	ISAConf;
typedef struct Label	Label;
typedef struct Lock	Lock;
typedef struct MMU	MMU;


@@ 9,7 10,6 @@ typedef struct Page	Page;
typedef struct PMMU	PMMU;
typedef struct Segdesc	Segdesc;
typedef struct Ureg	Ureg;
typedef struct User	User;

#define	MACHP(n)	(n==0? &mach0 : *(Mach**)0)



@@ 88,6 88,7 @@ struct Conf
 */
#define MAXMMU	4
#define MAXSMMU	1
#define NCOLOR 1
struct PMMU
{
	Page	*mmutop;	/* 1st level table */


@@ 131,36 132,6 @@ typedef void		KMap;
#define	kmap(p)		(KMap*)((p)->pa|KZERO)
#define	kunmap(k)

#define	NERR	15
#define	NNOTE	5
struct User
{
	Proc	*p;
	FPsave	fpsave;			/* address of this is known by vdb */
	int	scallnr;		/* sys call number - known by db */
	Sargs	s;			/* address of this is known by db */
	int	nerrlab;
	Label	errlab[NERR];
	char	error[ERRLEN];
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.
	 */
	Note	note[NNOTE];
	short	nnote;
	short	notified;		/* sysnoted is due */
	Note	lastnote;
	int	(*notify)(void*, char*);
	void	*ureg;
	void	*dbgreg;		/* User registers for debugging in proc */
	ulong	svcs;		/* cs before a notify */
	ulong	svss;		/* ss before a notify */
	ulong	svflags;		/* flags before a notify */
};

/*
 *  segment descriptor/gate
 */


@@ 192,11 163,20 @@ struct PCArch
	int	(*extvga)(int);		/* 1 == external, 0 == internal */
};

extern Mach	*m;
extern User	*u;
struct ISAConf {
	char	type[NAMELEN];
	ulong	port;
	ulong	irq;
	ulong	mem;
	ulong	size;
	uchar	ea[6];
};

extern int	flipD[];	/* for flipping bitblt destination polarity */
#define MAXPCMCIA 8			/* maximum number of PCMCIA cards */
#define BOOTLINE ((char *)0x80000100)	/*  bootline passed by boot program */

#define BOOTLINE ((char *)0x80000100) /*  bootline passed by boot program */
extern int	flipD[];		/* for flipping bitblt destination polarity */
extern PCArch	*arch;			/* PC architecture */

extern PCArch *arch;			/* PC architecture */
extern Mach	*m;
extern Proc	*up;

M pc/devfloppy.c => pc/devfloppy.c +26 -21
@@ 440,12 440,33 @@ changed(Chan *c, Drive *dp)
		error(Eio);
}

static int
readtrack(Drive *dp, int cyl, int head)
{
	int i, nn, sofar;
	ulong pos;

	nn = dp->t->tsize;
	if(dp->ccyl==cyl && dp->chead==head)
		return nn;
	pos = (cyl*dp->t->heads+head) * nn;
	for(sofar = 0; sofar < nn; sofar += i){
		dp->ccyl = -1;
		i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
		if(i <= 0)
			return -1;
	}
	dp->ccyl = cyl;
	dp->chead = head;
	return nn;
}

long
floppyread(Chan *c, void *a, long n, ulong offset)
{
	Drive *dp;
	long rv, i;
	int nn, sec, head, cyl;
	long rv;
	int sec, head, cyl;
	long len;
	uchar *aa;



@@ 468,7 489,7 @@ floppyread(Chan *c, void *a, long n, ulong offset)
		changed(c, dp);
		for(rv = 0; rv < n; rv += len){
			/*
			 *  truncate xfer at track boundary
			 *  all xfers come out of the track cache
			 */
			dp->len = n - rv;
			floppypos(dp, offset+rv);


@@ 476,24 497,8 @@ floppyread(Chan *c, void *a, long n, ulong offset)
			head = dp->thead;
			len = dp->len;
			sec = dp->tsec;
			nn = dp->t->tsize;

			/*
			 *  read the track
			 */
			if(dp->ccyl!=cyl || dp->chead!=head){
				dp->ccyl = -1;
				i = floppyxfer(dp, Fread, dp->cache,
					(cyl*dp->t->heads+head)*nn, nn);
				if(i != nn){
					if(i == 0)
						break;
					len = 0;
					continue;
				}
				dp->ccyl = cyl;
				dp->chead = head;
			}
			if(readtrack(dp, cyl, head) < 0)
				break;
			memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
		}
		qunlock(&fl);

M pc/devhard.c => pc/devhard.c +31 -13
@@ 155,7 155,7 @@ hardgen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dirp)
	name[NAMELEN] = 0;
	qid.path = MKQID(drive, s);
	l = (pp->end - pp->start) * dp->bytes;
	devdir(c, qid, name, l, eve, 0666, dirp);
	devdir(c, qid, name, l, eve, 0660, dirp);
	return 1;
}



@@ 447,7 447,7 @@ hardxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf)
	Controller *cp;
	long lblk;
	int cyl, sec, head;
	int loop, s;
	int loop, s, stat;

	if(dp->online == 0)
		error(Eio);


@@ 502,12 502,15 @@ hardxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf)
	outb(cp->pbase+Pcmd, cmd);
	if(cmd == Cwrite){
		loop = 0;
		while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
		while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0)
			if(++loop > 10000)
				panic("hardxfer");
		outss(cp->pbase+Pdata, cp->buf, dp->bytes/2);
	}
	} else
		stat = 0;
	splx(s);
	if(stat & Serr)
		error(Eio);

	/*
	 *  wait for command to complete.  if we get a note,


@@ 856,15 859,30 @@ hardpart(Drive *dp)
	}

	/*
	 *  read partition table from disk, null terminate
	 *  read last sector from disk, null terminate.  This used
	 *  to be the sector we used for the partition tables.
	 *  However, this sector is special on some PC's so we've
	 *  started to use the second last sector as the partition
	 *  table instead.  To avoid reconfiguring all our old systems
	 *  we first look to see if there is a valid partition
	 *  table in the last sector.  If so, we use it.  Otherwise
	 *  we switch to the second last.
	 */
	hardxfer(dp, pp, Cread, 0, dp->bytes, buf);
	buf[dp->bytes-1] = 0;
	n = getfields(buf, line, Npart+1, '\n');
	if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){
		dp->p[0].end--;
		dp->p[1].start--;
		dp->p[1].end--;
		hardxfer(dp, pp, Cread, 0, dp->bytes, buf);
		buf[dp->bytes-1] = 0;
		n = getfields(buf, line, Npart+1, '\n');
	}

	/*
	 *  parse partition table.
	 */
	n = getfields(buf, line, Npart+1, '\n');
	if(n && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){
		for(i = 1; i < n; i++){
			pp++;


@@ 946,13 964,6 @@ hardintr(Ureg *ur)
		break;
	case Cread:
	case Cident:
		loop = 0;
		while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
			if(++loop > 10000) {
				DPRINT("cmd=%lux status=%lux\n",
					cp->cmd, inb(cp->pbase+Pstatus));
				panic("hardintr: read/ident");
		}
		if(cp->status & Serr){
			cp->lastcmd = cp->cmd;
			cp->cmd = 0;


@@ 960,6 971,13 @@ hardintr(Ureg *ur)
			wakeup(&cp->r);
			return;
		}
		loop = 0;
		while((inb(cp->pbase+Pstatus) & Sdrq) == 0)
			if(++loop > 10000) {
				DPRINT("cmd=%lux status=%lux\n",
					cp->cmd, inb(cp->pbase+Pstatus));
				panic("hardintr: read/ident");
		}
		addr = cp->buf;
		if(addr){
			addr += cp->sofar*dp->bytes;

M pc/devincon.c => pc/devincon.c +28 -9
@@ 184,6 184,19 @@ Dirtab incondir[]={
#define NINCON	(sizeof incondir/sizeof incondir[0])

static void
nop(void)
{
}

static int
slowinb(int x)
{
	nop();
	nop();
	return inb(x);
}

static void
reset(int dev)				/* hardware reset */
{
	outb(dev+Qpcr, Finitbar);


@@ 261,9 274,9 @@ irdstatus(Incon *ip)			/* read status at interrupt level */

	outb(dev+Qdlr, 0x01);
	outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
	data = (inb(dev+Qpsr)&0xf8)<<2;
	data = (slowinb(dev+Qpsr)&0xf8)<<2;
	outb(dev+Qpcr, Finitbar|Faf|Fsi);
	data |= inb(dev+Qpsr)>>3;
	data |= slowinb(dev+Qpsr)>>3;
	if(data&(OVERFLOW|CRC_ERROR)){
		if(data&OVERFLOW)
			ip->overflow++;


@@ 281,9 294,9 @@ irddata(int dev)			/* read data at interrupt level */

	outb(dev+Qdlr, 0x00);
	outb(dev+Qpcr, Finitbar|Faf|Fsi|Fstrobe);
	data = (inb(dev+Qpsr)&0xf8)<<2;
	data = (slowinb(dev+Qpsr)&0xf8)<<2;
	outb(dev+Qpcr, Finitbar|Faf|Fsi);
	data |= inb(dev+Qpsr)>>3;
	data |= slowinb(dev+Qpsr)>>3;

	return data;
}


@@ 311,6 324,7 @@ irdnop(int dev, int pcr)		/* read nop (mux reset) */

int		Irdnext(int);
#define	irdnext	Irdnext
/**/

/*
 *  set the incon parameters


@@ 366,11 380,6 @@ inconsetctl(Incon *ip, Block *bp)
	freeb(bp);
}

static void
nop(void)
{
}

/*
 *  poll for a station number
 */


@@ 472,6 481,14 @@ void
inconreset(void)
{
	int i;
	char *p;

	/*
	 *  get incondev from p9rc
 	 */
	p = getconf("incondev");
	if(p)
		incondev = atoi(p);

	/*
	 * state is Selected if we used incon as the boot device


@@ 1089,6 1106,8 @@ inconintr(Ureg *ur)
	USED(ur);
	ip = &incon[0];
	pcr = inb(ip->dev+Qpcr);
	if(!(pcr & Fie))
		return;
	status = irdstatus(ip);
	if(incondebug){
		kprint("pcr=%2.2x status=%2.2x\n", pcr, status);

M pc/devrtc.c => pc/devrtc.c +5 -5
@@ 23,7 23,7 @@ enum {
	Status=		0x0A,

	Nvoff=		128,	/* where usable nvram lives */
	Nvsize=		128,
	Nvsize=		256,

	Nbcd=		6,
};


@@ 48,8 48,8 @@ enum{

#define	NRTC	2
Dirtab rtcdir[]={
	"nvram",	{Qnvram, 0},	Nvsize,	0666,
	"rtc",		{Qrtc, 0},	0,	0666,
	"nvram",	{Qnvram, 0},	Nvsize,	0664,
	"rtc",		{Qrtc, 0},	0,	0664,
};

ulong rtc2sec(Rtc*);


@@ 96,11 96,11 @@ rtcopen(Chan *c, int omode)
	omode = openmode(omode);
	switch(c->qid.path){
	case Qrtc:
		if(strcmp(u->p->user, eve)!=0 && omode!=OREAD)
		if(strcmp(up->user, eve)!=0 && omode!=OREAD)
			error(Eperm);
		break;
	case Qnvram:
		if(strcmp(u->p->user, eve)!=0)
		if(strcmp(up->user, eve)!=0)
			error(Eperm);
	}
	return devopen(c, omode, rtcdir, NRTC, devgen);

M pc/devuart.c => pc/devuart.c +267 -237
@@ 7,7 7,7 @@
#include	"../port/error.h"

#include	"devtab.h"

#define		nelem(x)	(sizeof(x)/sizeof(x[0]))
/*
 *  Driver for an NS16450 serial port
 */


@@ 17,12 17,12 @@ enum
	 *  register numbers
	 */
	Data=	0,		/* xmit/rcv buffer */
	Iena=	1,		/* interrupt enable */
	Iena=	1,		/* interrdpt enable */
	 Ircv=	(1<<0),		/*  for char rcv'd */
	 Ixmt=	(1<<1),		/*  for xmit buffer empty */
	 Irstat=(1<<2),		/*  for change in rcv'er status */
	 Imstat=(1<<3),		/*  for change in modem status */
	Istat=	2,		/* interrupt flag (read) */
	Istat=	2,		/* interrdpt flag (read) */
	Tctl=	2,		/* test control (write) */
	Format=	3,		/* byte format */
	 Bits8=	(3<<0),		/*  8 bits/byte */


@@ 36,7 36,7 @@ enum
	 Dtr=	(1<<0),		/*  data terminal ready */
	 Rts=	(1<<1),		/*  request to send */
	 Ri=	(1<<2),		/*  ring */
	 Inton=	(1<<3),		/*  turn on interrupts */
	 Inton=	(1<<3),		/*  turn on interrdpts */
	 Loop=	(1<<4),		/*  loop back */
	Lstat=	5,		/* line status */
	 Inready=(1<<0),	/*  receive buffer full */


@@ 86,9 86,12 @@ struct Uart
	ulong	overrun;
};

Uart uart[2];
Uart	uart[34];
int	Nuart;		/* total no of uarts in the machine */
int	Nscard;		/* number of serial cards */
ISAConf	scard[5];	/* configs for the serial card */

#define UartFREQ 1846200
#define UartFREQ 1843200

#define uartwrreg(u,r,v)	outb((u)->port + r, (u)->sticky[r] | (v))
#define uartrdreg(u,r)		inb((u)->port + r)


@@ 96,6 99,7 @@ Uart uart[2];
void	uartintr(Uart*);
void	uartintr0(Ureg*);
void	uartintr1(Ureg*);
void	uartintr2(Ureg*);
void	uartsetup(void);

/*


@@ 104,135 108,136 @@ void	uartsetup(void);
 *  baud rates.
 */
void
uartsetbaud(Uart *up, int rate)
uartsetbaud(Uart *dp, int rate)
{
	ulong brconst;

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

	uartwrreg(up, Format, Dra);
	outb(up->port+Dmsb, (brconst>>8) & 0xff);
	outb(up->port+Dlsb, brconst & 0xff);
	uartwrreg(up, Format, 0);
	uartwrreg(dp, Format, Dra);
	outb(dp->port+Dmsb, (brconst>>8) & 0xff);
	outb(dp->port+Dlsb, brconst & 0xff);
	uartwrreg(dp, Format, 0);
}

/*
 *  toggle DTR
 */
void
uartdtr(Uart *up, int n)
uartdtr(Uart *dp, int n)
{
	if(n)
		up->sticky[Mctl] |= Dtr;
		dp->sticky[Mctl] |= Dtr;
	else
		up->sticky[Mctl] &= ~Dtr;
	uartwrreg(up, Mctl, 0);
		dp->sticky[Mctl] &= ~Dtr;
	uartwrreg(dp, Mctl, 0);
}

/*
 *  toggle RTS
 */
void
uartrts(Uart *up, int n)
uartrts(Uart *dp, int n)
{
	if(n)
		up->sticky[Mctl] |= Rts;
		dp->sticky[Mctl] |= Rts;
	else
		up->sticky[Mctl] &= ~Rts;
	uartwrreg(up, Mctl, 0);
		dp->sticky[Mctl] &= ~Rts;
	uartwrreg(dp, Mctl, 0);
}

/*
 *  send break
 */
void
uartbreak(Uart *up, int ms)
uartbreak(Uart *dp, int ms)
{
	if(ms == 0)
		ms = 200;
	uartwrreg(up, Format, Break);
	tsleep(&u->p->sleep, return0, 0, ms);
	uartwrreg(up, Format, 0);
	uartwrreg(dp, Format, Break);
	tsleep(&dp->sleep, return0, 0, ms);
	uartwrreg(dp, Format, 0);
}

/*
 *  set bits/char
 */
void
uartbits(Uart *up, int bits)
uartbits(Uart *dp, int bits)
{
	if(bits < 5 || bits > 8)
		error(Ebadarg);
	up->sticky[Format] &= ~3;
	up->sticky[Format] |= bits-5;
	uartwrreg(up, Format, 0);
	dp->sticky[Format] &= ~3;
	dp->sticky[Format] |= bits-5;
	uartwrreg(dp, Format, 0);
}

/*
 *  set parity
 */
void
uartparity(Uart *up, int c)
uartparity(Uart *dp, int c)
{
	switch(c&0xff){
	case 'e':
		up->sticky[Format] |= Pena|Peven;
		dp->sticky[Format] |= Pena|Peven;
		break;
	case 'o':
		up->sticky[Format] &= ~Peven;
		up->sticky[Format] |= Pena;
		dp->sticky[Format] &= ~Peven;
		dp->sticky[Format] |= Pena;
		break;
	default:
		up->sticky[Format] &= ~(Pena|Peven);
		dp->sticky[Format] &= ~(Pena|Peven);
		break;
	}
	uartwrreg(up, Format, 0);
	uartwrreg(dp, Format, 0);
}

/*
 *  set stop bits
 */
void
uartstop(Uart *up, int n)
uartstop(Uart *dp, int n)
{
	switch(n){
	case 1:
		up->sticky[Format] &= ~Stop2;
		dp->sticky[Format] &= ~Stop2;
		break;
	case 2:
	default:
		up->sticky[Format] |= Stop2;
		dp->sticky[Format] |= Stop2;
		break;
	}
	uartwrreg(up, Format, 0);
	uartwrreg(dp, Format, 0);
}

/*
 *  modem flow control on/off (rts/cts)
 */
void
uartmflow(Uart *up, int n)
uartmflow(Uart *dp, int n)
{
	if(n){
		up->sticky[Iena] |= Imstat;
		uartwrreg(up, Iena, 0);
		up->cts = uartrdreg(up, Mstat) & Cts;
		dp->sticky[Iena] |= Imstat;
		uartwrreg(dp, Iena, 0);
		dp->cts = uartrdreg(dp, Mstat) & Cts;
	} else {
		up->sticky[Iena] &= ~Imstat;
		uartwrreg(up, Iena, 0);
		up->cts = 1;
		dp->sticky[Iena] &= ~Imstat;
		uartwrreg(dp, Iena, 0);
		dp->cts = 1;
	}
}


/*
 *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
 *  transmit and receive enabled, interrupts disabled.
 *  default is 9600 baud, 1 stop bit, 8 bit chars, no interrdpts,
 *  transmit and receive enabled, interrdpts disabled.
 */
void
uartsetup(void)
{
	Uart *up;
	Uart	*dp;
	int	i, j, baddr;
	static int already;

	if(already)


@@ 246,21 251,34 @@ uartsetup(void)
	uart[1].port = 0x2F8;
	setvec(Uart0vec, uartintr0);
	setvec(Uart1vec, uartintr1);

	for(up = uart; up < &uart[2]; up++){
		memset(up->sticky, 0, sizeof(up->sticky));

	Nuart = 2;
	for(i = 0; isaconfig("serial", i, &scard[i]) && i < nelem(scard); i++) {
		/*
		 * mem gives base port address for uarts
		 * irq is interrdpt
		 * port is the polling port
		 * size is the number of serial ports on the same polling port
		 */
		setvec(Int0vec + scard[i].irq, uartintr2);
		baddr = scard[i].mem;
		for(j=0, dp = &uart[Nuart]; j < scard[i].size; baddr += 8, j++, dp++)
			dp->port = baddr;
		Nuart += scard[i].size;
	}
	Nscard = i;
	for(dp = uart; dp < &uart[Nuart]; dp++){
		memset(dp->sticky, 0, sizeof(dp->sticky));
		/*
		 *  set rate to 9600 baud.
		 *  8 bits/character.
		 *  1 stop bit.
		 *  interrupts enabled.
		 *  interrdpts enabled.
		 */
		uartsetbaud(up, 9600);
		up->sticky[Format] = Bits8;
		uartwrreg(up, Format, 0);
		up->sticky[Mctl] |= Inton;
		uartwrreg(up, Mctl, 0x0);
		uartsetbaud(dp, 9600);
		dp->sticky[Format] = Bits8;
		uartwrreg(dp, Format, 0);
		dp->sticky[Mctl] |= Inton;
		uartwrreg(dp, Mctl, 0x0);
	}
}



@@ 271,7 289,7 @@ uartsetup(void)
void
uartputs(IOQ *cq, char *s, int n)
{
	Uart *up = cq->ptr;
	Uart *dp = cq->ptr;
	int ch, x, multiprocessor;
	int tries;



@@ 280,14 298,14 @@ uartputs(IOQ *cq, char *s, int n)
	if(multiprocessor)
		lock(cq);
	puts(cq, s, n);
	if(up->printing == 0){
	if(dp->printing == 0){
		ch = getc(cq);
		if(ch >= 0){
			up->printing = 1;
			for(tries = 0; tries<10000 && !(uartrdreg(up, Lstat)&Outready);
			dp->printing = 1;
			for(tries = 0; tries<10000 && !(uartrdreg(dp, Lstat)&Outready);
				tries++)
				;
			outb(up->port + Data, ch);
			outb(dp->port + Data, ch);
		}
	}
	if(multiprocessor)


@@ 296,10 314,10 @@ uartputs(IOQ *cq, char *s, int n)
}

/*
 *  a uart interrupt (a damn lot of work for one character)
 *  a uart interrdpt (a damn lot of work for one character)
 */
void
uartintr(Uart *up)
uartintr(Uart *dp)
{
	int ch;
	IOQ *cq;


@@ 307,19 325,19 @@ uartintr(Uart *up)

	multiprocessor = active.machs > 1;
	for(;;){
		s = uartrdreg(up, Istat);
		s = uartrdreg(dp, Istat);
		switch(s){
		case 6:	/* receiver line status */
			l = uartrdreg(up, Lstat);
			l = uartrdreg(dp, Lstat);
			if(l & Ferror)
				up->frame++;
				dp->frame++;
			if(l & Oerror)
				up->overrun++;
				dp->overrun++;
			break;
	
		case 4:	/* received data available */
			ch = uartrdreg(up, Data) & 0xff;
			cq = up->iq;
			ch = uartrdreg(dp, Data) & 0xff;
			cq = dp->iq;
			if(cq == 0)
				break;
			if(cq->putc)


@@ 329,41 347,41 @@ uartintr(Uart *up)
			break;
	
		case 2:	/* transmitter empty */
			cq = up->oq;
			cq = dp->oq;
			if(cq == 0)
				break;
			if(multiprocessor)
				lock(cq);
			if(up->cts == 0)
				up->printing = 0;
			if(dp->cts == 0)
				dp->printing = 0;
			else {
				ch = getc(cq);
				if(ch < 0){
					up->printing = 0;
					wakeup(&cq->r);
					dp->printing = 0;
					wakedp(&cq->r);
				}else
					outb(up->port + Data, ch);
					outb(dp->port + Data, ch);
			}
			if(multiprocessor)
				unlock(cq);
			break;
	
		case 0:	/* modem status */
			ch = uartrdreg(up, Mstat);
			ch = uartrdreg(dp, Mstat);
			if(ch & Ctsc){
				up->cts = ch & Cts;
				cq = up->oq;
				dp->cts = ch & Cts;
				cq = dp->oq;
				if(cq == 0)
					break;
				if(multiprocessor)
					lock(cq);
				if(up->cts && up->printing == 0){
				if(dp->cts && dp->printing == 0){
					ch = getc(cq);
					if(ch >= 0){
						up->printing = 1;
						outb(up->port + Data, getc(cq));
						dp->printing = 1;
						outb(dp->port + Data, getc(cq));
					} else
						wakeup(&cq->r);
						wakedp(&cq->r);
				}
				if(multiprocessor)
					unlock(cq);


@@ 373,7 391,7 @@ uartintr(Uart *up)
		default:
			if(s&1)
				return;
			print("weird modem interrupt\n");
			print("weird modem interrdpt #%2.2ux\n", s);
			break;
		}
	}


@@ 390,125 408,142 @@ uartintr1(Ureg *ur)
	USED(ur);
	uartintr(&uart[1]);
}
void
uartintr2(Ureg *ur)
{
	uchar	i, j, nuart, n;

	USED(ur);
	for(nuart=2, j = 0; j < Nscard; nuart += scard[j].size, j++) {
		n = ~inb(scard[j].port);
		if(n == 0)
			continue;
		for(i = 0; n; i++){
			if(n & 1)
				uartintr(&uart[nuart + i]);
			n >>= 1;
		}
	}
}

void
uartclock(void)
{
	Uart *up;
	Uart *dp;
	IOQ *cq;

	for(up = uart; up < &uart[2]; up++){
		cq = up->iq;
		if(up->wq && cangetc(cq))
			wakeup(&cq->r);
	for(dp = uart; dp < &uart[Nuart]; dp++){
		cq = dp->iq;
		if(dp->wq && cangetc(cq))
			wakedp(&cq->r);
	}
}


/*
 *  turn on a port's interrupts.  set DTR and RTS
 *  turn on a port's interrdpts.  set DTR and RTS
 */
void
uartenable(Uart *up)
uartenable(Uart *dp)
{
	/*
	 *  turn on power to the port
	 */
	if(up == &uart[Serial]){
		if(serial(1) < 0)
			print("can't turn on serial port power\n");
	} else {
	if(dp == &uart[Modem]){
		if(modem(1) < 0)
			print("can't turn on modem speaker\n");
	} else {
		if(serial(1) < 0)
			print("can't turn on serial port power\n");
	}

	/*
	 *  set up i/o routines
	 *  set dp i/o routines
	 */
	if(up->oq){
		up->oq->puts = uartputs;
		up->oq->ptr = up;
	if(dp->oq){
		dp->oq->puts = uartputs;
		dp->oq->ptr = dp;
	}
	if(up->iq){
		up->iq->ptr = up;
	if(dp->iq){
		dp->iq->ptr = dp;
	}
	up->enabled = 1;
	dp->enabled = 1;

	/*
 	 *  turn on interrupts
 	 *  turn on interrdpts
	 */
	up->sticky[Iena] = Ircv | Ixmt | Irstat;
	uartwrreg(up, Iena, 0);
	dp->sticky[Iena] = Ircv | Ixmt | Irstat;
	uartwrreg(dp, Iena, 0);

	/*
	 *  turn on DTR and RTS
	 */
	uartdtr(up, 1);
	uartrts(up, 1);
	uartdtr(dp, 1);
	uartrts(dp, 1);

	/*
	 *  assume we can send
	 */
	up->cts = 1;
	dp->cts = 1;
}

/*
 *  turn off the uart
 */
void
uartdisable(Uart *up)
uartdisable(Uart *dp)
{

	/*
 	 *  turn off interrupts
 	 *  turn off interrdpts
	 */
	up->sticky[Iena] = 0;
	uartwrreg(up, Iena, 0);
	dp->sticky[Iena] = 0;
	uartwrreg(dp, Iena, 0);

	/*
	 *  revert to default settings
	 */
	up->sticky[Format] = Bits8;
	uartwrreg(up, Format, 0);
	dp->sticky[Format] = Bits8;
	uartwrreg(dp, Format, 0);

	/*
	 *  turn off DTR and RTS
	 */
	uartdtr(up, 0);
	uartrts(up, 0);
	up->enabled = 0;
	uartdtr(dp, 0);
	uartrts(dp, 0);
	dp->enabled = 0;

	/*
	 *  turn off power
	 */
	if(up == &uart[Serial]){
		if(serial(0) < 0)
			print("can't turn off serial power\n");
	} else {
	if(dp == &uart[Modem]){
		if(modem(0) < 0)
			print("can't turn off modem speaker\n");
	} else {
		if(serial(0) < 0)
			print("can't turn off serial power\n");
	}
}

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

	uartsetup();
	up->special = 1;
	up->oq = oq;
	up->iq = iq;
	uartenable(up);
	dp->special = 1;
	dp->oq = oq;
	dp->iq = iq;
	uartenable(dp);
	if(baud)
		uartsetbaud(up, baud);
		uartsetbaud(dp, baud);

	if(iq){
		/*
		 *  Stupid HACK to undo a stupid hack
		 *  Stdpid HACK to undo a stdpid hack
		 */ 
		if(iq == &kbdq)
			kbdq.putc = kbdcr2nl;


@@ 532,57 567,57 @@ Qinfo uartinfo =
static void
uartstopen(Queue *q, Stream *s)
{
	Uart *up;
	Uart *dp;
	char name[NAMELEN];

	up = &uart[s->id];
	up->iq->putc = 0;
	uartenable(up);
	dp = &uart[s->id];
	dp->iq->putc = 0;
	uartenable(dp);

	qlock(up);
	up->wq = WR(q);
	WR(q)->ptr = up;
	RD(q)->ptr = up;
	qunlock(up);
	qlock(dp);
	dp->wq = WR(q);
	WR(q)->ptr = dp;
	RD(q)->ptr = dp;
	qunlock(dp);

	if(up->kstarted == 0){
		up->kstarted = 1;
	if(dp->kstarted == 0){
		dp->kstarted = 1;
		sprint(name, "uart%d", s->id);
		kproc(name, uartkproc, up);
		kproc(name, uartkproc, dp);
	}
}

static void
uartstclose(Queue *q)
{
	Uart *up = q->ptr;
	Uart *dp = q->ptr;

	if(up->special)
	if(dp->special)
		return;

	uartdisable(up);
	uartdisable(dp);

	qlock(up);
	kprint("uartstclose: q=0x%ux, id=%d\n", q, up-uart);
	up->wq = 0;
	up->iq->putc = 0;
	qlock(dp);
	kprint("uartstclose: q=0x%ux, id=%d\n", q, dp-uart);
	dp->wq = 0;
	dp->iq->putc = 0;
	WR(q)->ptr = 0;
	RD(q)->ptr = 0;
	qunlock(up);
	qunlock(dp);
}

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

	if(up == 0){
	if(dp == 0){
		freeb(bp);
		return;
	}
	cq = up->oq;
	cq = dp->oq;
	if(waserror()){
		freeb(bp);
		nexterror();


@@ 594,35 629,37 @@ uartoput(Queue *q, Block *bp)
		switch(*bp->rptr){
		case 'B':
		case 'b':
			uartsetbaud(up, n);
			if(n <= 0)
				error(Ebadctl);
			uartsetbaud(dp, n);
			break;
		case 'D':
		case 'd':
			uartdtr(up, n);
			uartdtr(dp, n);
			break;
		case 'K':
		case 'k':
			uartbreak(up, n);
			uartbreak(dp, n);
			break;
		case 'L':
		case 'l':
			uartbits(up, n);
			uartbits(dp, n);
			break;
		case 'm':
		case 'M':
			uartmflow(up, n);
			uartmflow(dp, n);
			break;
		case 'P':
		case 'p':
			uartparity(up, *(bp->rptr+1));
			uartparity(dp, *(bp->rptr+1));
			break;
		case 'R':
		case 'r':
			uartrts(up, n);
			uartrts(dp, n);
			break;
		case 'S':
		case 's':
			uartstop(up, n);
			uartstop(dp, n);
			break;
		}
	}else while((m = BLEN(bp)) > 0){


@@ 639,13 676,13 @@ uartoput(Queue *q, Block *bp)
}

/*
 *  process to send bytes upstream for a port
 *  process to send bytes dpstream for a port
 */
static void
uartkproc(void *a)
{
	Uart *up = a;
	IOQ *cq = up->iq;
	Uart *dp = a;
	IOQ *cq = dp->iq;
	Block *bp;
	int n;
	ulong frame, overrun;


@@ 661,44 698,33 @@ uartkproc(void *a)
		sleep(&cq->r, cangetc, cq);
		if((ints++ & 0x1f) == 0)
			lights((ints>>5)&1);
		qlock(up);
		if(up->wq == 0){
		qlock(dp);
		if(dp->wq == 0){
			cq->out = cq->in;
		}else{
			n = cangetc(cq);
			bp = allocb(n);
			bp->flags |= S_DELIM;
			bp->wptr += gets(cq, bp->wptr, n);
			PUTNEXT(RD(up->wq), bp);
			PUTNEXT(RD(dp->wq), bp);
		}
		qunlock(up);
		if(up->frame != frame){
			kprint("uart%d: %d framing\n", up-uart, up->frame);
			frame = up->frame;
		qunlock(dp);
		if(dp->frame != frame){
			kprint("uart%d: %d framing\n", dp-uart, dp->frame);
			frame = dp->frame;
		}
		if(up->overrun != overrun){
			kprint("uart%d: %d overruns\n", up-uart, up->overrun);
			overrun = up->overrun;
		if(dp->overrun != overrun){
			kprint("uart%d: %d overruns\n", dp-uart, dp->overrun);
			overrun = dp->overrun;
		}
	}
}

enum{
	Qdir=		0,
	Qeia0=		STREAMQID(0, Sdataqid),
	Qeia0ctl=	STREAMQID(0, Sctlqid),
	Qeia1=		STREAMQID(1, Sdataqid),
	Qeia1ctl=	STREAMQID(1, Sctlqid),
};

Dirtab uartdir[]={
	"eia0",		{Qeia0},	0,		0666,
	"eia0ctl",	{Qeia0ctl},	0,		0666,
	"eia1",		{Qeia1},	0,		0666,
	"eia1ctl",	{Qeia1ctl},	0,		0666,
};

#define	NUart	(sizeof uartdir/sizeof(Dirtab))
Dirtab uartdir[2*nelem(uart)];

/*
 *  allocate the queues if no one else has


@@ 706,28 732,41 @@ Dirtab uartdir[]={
void
uartreset(void)
{
	Uart *up;
	Uart *dp;

	uartsetup();
	for(up = uart; up < &uart[2]; up++){
		if(up->special)
	for(dp = uart; dp < &uart[Nuart]; dp++){
		if(dp->special)
			continue;
		up->iq = xalloc(sizeof(IOQ));
		initq(up->iq);
		up->oq = xalloc(sizeof(IOQ));
		initq(up->oq);
		dp->iq = xalloc(sizeof(IOQ));
		initq(dp->iq);
		dp->oq = xalloc(sizeof(IOQ));
		initq(dp->oq);
	}
}

void
uartinit(void)
{
	int	i;

	for(i=0; i < 2*Nuart; ++i) {
		if(i & 1 != 0) {
			sprint(uartdir[i].name, "eia%dctl", i/2);
			uartdir[i].qid.path = STREAMQID(i/2, Sctlqid);
		} else {
			sprint(uartdir[i].name, "eia%d", i/2);
			uartdir[i].qid.path = STREAMQID(i/2, Sdataqid);
		}
		uartdir[i].length = 0;
		uartdir[i].perm = 0666;
	}
}

Chan*
uartattach(char *upec)
uartattach(char *dpec)
{
	return devattach('t', upec);
	return devattach('t', dpec);
}

Chan*


@@ 739,50 778,40 @@ uartclone(Chan *c, Chan *nc)
int
uartwalk(Chan *c, char *name)
{
	return devwalk(c, name, uartdir, NUart, devgen);
	return devwalk(c, name, uartdir, Nuart * 2, devgen);
}

void
uartstat(Chan *c, char *dp)
uartstat(Chan *c, char *dir)
{
	switch(c->qid.path){
	case Qeia0:
		streamstat(c, dp, uartdir[0].name, uartdir[0].perm);
		break;
	case Qeia1:
		streamstat(c, dp, uartdir[2].name, uartdir[2].perm);
		break;
	default:
		devstat(c, dp, uartdir, NUart, devgen);
		break;
	}
	int	i;

	for(i=0; i < 2*Nuart; i += 2)
		if(c->qid.path == uartdir[i].qid.path) {
			streamstat(c, dir, uartdir[i].name, uartdir[i].perm);
			return;
		}
	devstat(c, dir, uartdir, Nuart * 2, devgen);
}

Chan*
uartopen(Chan *c, int omode)
{
	Uart *up;
	Uart *dp;
	int	i;

	switch(c->qid.path){
	case Qeia0:
	case Qeia0ctl:
		up = &uart[0];
		break;
	case Qeia1:
	case Qeia1ctl:
		up = &uart[1];
		break;
	default:
		up = 0;
		break;
	}
	dp = 0;
	for(i=0; i < 2*Nuart; ++i)
		if(c->qid.path == uartdir[i].qid.path) {
			dp = &uart[i/2];
			break;
		}

	if(up && up->special)
	if(dp && dp->special)
		error(Einuse);

	if((c->qid.path & CHDIR) == 0)
		streamopen(c, &uartinfo);
	return devopen(c, omode, uartdir, NUart, devgen);
	return devopen(c, omode, uartdir, Nuart * 2, devgen);
}

void


@@ 800,15 829,15 @@ uartclose(Chan *c)
}

long
uartstatus(Uart *up, void *buf, long n, ulong offset)
uartstatus(Uart *dp, void *buf, long n, ulong offset)
{
	uchar mstat;
	uchar tstat;
	char str[128];

	str[0] = 0;
	tstat = up->sticky[Mctl];
	mstat = uartrdreg(up, Mstat);
	tstat = dp->sticky[Mctl];
	mstat = uartrdreg(dp, Mstat);
	if(mstat & Cts)
		strcat(str, " cts");
	if(mstat & Dsr)


@@ 827,15 856,16 @@ uartstatus(Uart *up, void *buf, long n, ulong offset)
long
uartread(Chan *c, void *buf, long n, ulong offset)
{
	int i;
	long qpath;

	USED(offset);
	switch(c->qid.path&~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, uartdir, NUart, devgen);
	case Qeia1ctl:
		return uartstatus(&uart[1], buf, n, offset);
	case Qeia0ctl:
		return uartstatus(&uart[0], buf, n, offset);
	}
	qpath = c->qid.path & ~CHDIR;
	if(qpath == Qdir)
		return devdirread(c, buf, n, uartdir, Nuart * 2, devgen);
	for(i=1; i < 2*Nuart; i += 2)
		if(qpath == uartdir[i].qid.path)
			return uartstatus(&uart[i/2], buf, n, offset);
	return streamread(c, buf, n);
}



@@ 854,8 884,8 @@ uartremove(Chan *c)
}

void
uartwstat(Chan *c, char *dp)
uartwstat(Chan *c, char *dir)
{
	USED(c, dp);
	USED(c, dir);
	error(Eperm);
}

M pc/devvga.c => pc/devvga.c +13 -8
@@ 103,7 103,7 @@ VGAmode mode13 =
static	Rectangle mbb;
static	Rectangle NULLMBB = {10000, 10000, -10000, -10000};
static	void nopage(int), tsengpage(int), tridentpage(int), parapage(int);
static	void atipage(int);
static	void atipage(int), cirruspage(int);
static	void vgaupdate(void);

/*


@@ 122,6 122,7 @@ enum
	Pvga1a,		/* paradise */
	Trident,	/* Trident 8900 */
	Tseng,		/* tseng labs te4000 */
	Cirrus,		/* Cirrus CLGD542X */
	Generic,
};



@@ 131,6 132,7 @@ Vgacard vgachips[] =
[Pvga1a]	{ "pvga1a", parapage, },
[Trident]	{ "trident", tridentpage, },
[Tseng]		{ "tseng", tsengpage, },
[Cirrus]	{ "cirrus", cirruspage, },
[Generic]	{ "generic", nopage, },
		{ 0, 0, },
};


@@ 659,7 661,7 @@ atipage(int page)
static void
tridentpage(int page)
{
	srout(0x0e, (srin(0x0e)&0xf0) | page^0x02);
	srout(0xe, (srin(0xe)&0xf0) | page^0x2);
}
static void
tsengpage(int page)


@@ 667,9 669,14 @@ tsengpage(int page)
	outb(0x3cd, (page<<4)|page);
}
static void
cirruspage(int page)
{
	grout(0x9, page<<4);
}
static void
parapage(int page)
{
	grout(9, page<<4);
	grout(0x9, page<<4);
}

/*


@@ 918,18 925,16 @@ setcolor(ulong p, ulong r, ulong g, ulong b)
	return ~0;
}

int
hwcursset(uchar *s, uchar *c, int ox, int oy)
void
hwcursset(ulong *s, ulong *c, int ox, int oy)
{
	USED(s, c, ox, oy);
	return 0;
}

int
void
hwcursmove(int x, int y)
{
	USED(x, y);
	return 0;
}

/*

M pc/dma.c => pc/dma.c +30 -10
@@ 33,7 33,7 @@ enum
 */
struct DMAxfer
{
	Page	*pg;		/* page used by dma */
	Page	pg;		/* page used by dma */
	void	*va;		/* virtual address destination/src */
	long	len;		/* bytes to be transferred */
	int	isread;


@@ 79,6 79,27 @@ DMA dma[2] = {
};

/*
 *  DMA must be in the first 16 meg.  This gets called early by main() to
 *  ensure that.
 */
void
dmainit(void)
{
	int i, chan;
	DMA *dp;
	DMAxfer *xp;

	for(i = 0; i < 2; i++){
		dp = &dma[i];
		for(chan = 0; chan < 4; chan++){
			xp = &dp->x[chan];
			xp->pg.pa = (ulong)xspanalloc(BY2PG, BY2PG, 0);
			xp->pg.va = KZERO|xp->pg.pa;
		}
	}
}

/*
 *  setup a dma transfer.  if the destination is not in kernel
 *  memory, allocate a page for the transfer.
 *


@@ 101,22 122,21 @@ dmasetup(int chan, void *va, long len, int isread)
	xp = &dp->x[chan];

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



@@ 168,6 188,6 @@ dmaend(int chan)
	/*
	 *  copy out of temporary page
	 */
	memmove(xp->va, (void*)(KZERO|xp->pg->pa), xp->len);
	memmove(xp->va, (void*)(xp->pg.va), xp->len);
	xp->len = 0;
}

M pc/ether.h => pc/ether.h +7 -6
@@ 10,7 10,7 @@ typedef struct Ctlr Ctlr;
 * Hardware interface.
 */
struct Card {
	char	id[NAMELEN];		/* type of card */
	ISAConf;

	int	(*reset)(Ctlr*);
	void	(*init)(Ctlr*);


@@ 26,13 26,8 @@ struct Card {
	void	(*watch)(Ctlr*);
	void	(*overflow)(Ctlr*);

	ulong	io;			/* card I/O base address */
	uchar	irq;			/* interrupt level */
	uchar	bit16;			/* true if a 16 bit interface */

	uchar	ram;			/* true if card has shared memory */
	ulong	ramstart;		/* card shared memory address start */
	ulong	ramstop;		/* card shared memory address end */

	ulong	dp8390;			/* I/O address of 8390 (if any) */
	ulong	data;			/* I/O data port if no shared memory */


@@ 85,6 80,8 @@ enum {
 */
struct Ctlr {
	QLock;
	int	ctlrno;
	Ctlr	*next;

	Card	card;			/* hardware info */
	int	present;


@@ 140,6 137,7 @@ struct Ctlr {
extern void dp8390reset(Ctlr*);
extern void dp8390attach(Ctlr*);
extern void dp8390mode(Ctlr*, int);
extern void dp8390getea(Ctlr*);
extern void dp8390setea(Ctlr*);
extern void *dp8390read(Ctlr*, void*, ulong, ulong);
extern void *dp8390write(Ctlr*, ulong, void*, ulong);


@@ 166,3 164,6 @@ extern void dp8390outb(ulong, uchar);
enum {
	Dp8390BufSz	= 256,		/* hardware ring buffer size */
};


extern void	addethercard(char*, int	(*)(Ctlr*));

M pc/ether2000.c => pc/ether2000.c +59 -62
@@ 25,44 25,68 @@ enum {
	Reset		= 0x18,		/* offset from I/O base of reset port */
};

static int
reset(Ctlr *ctlr)
int
ne2000reset(Ctlr *ctlr)
{
	ushort buf[16];
	int i;

	/*
	 * We look for boards.
	 * We look for boards to make us barf.
	 * Set up the software configuration.
	 * Use defaults for port, irq, mem and size
	 * if not specified.
	 */
	for(ctlr->card.io = 0x300; ctlr->card.io < 0x380; ctlr->card.io += 0x20){
		/*
		 * Reset the board. This is done by doing a read
		 * followed by a write to the Reset address.
		 */
		buf[0] = inb(ctlr->card.io+Reset);
		delay(2);
		outb(ctlr->card.io+Reset, buf[0]);
	if(ctlr->card.port == 0)
		ctlr->card.port = 0x300;
	if(ctlr->card.irq == 0)
		ctlr->card.irq = 2;
	if(ctlr->card.mem == 0)
		ctlr->card.mem = 0x4000;
	if(ctlr->card.size == 0)
		ctlr->card.size = 16*1024;

		/*
		 * Init the (possible) chip, then use the (possible)
		 * chip to read the (possible) PROM for ethernet address
		 * and a marker byte.
		 * We could just look at the DP8390 command register after
		 * initialisation has been tried, but that wouldn't be
		 * enough, there are other ethernet boards which could
		 * match.
		 */
		ctlr->card.dp8390 = ctlr->card.io;
		ctlr->card.data = ctlr->card.io+Data;
		dp8390reset(ctlr);
		memset(buf, 0, sizeof(buf));
		dp8390read(ctlr, buf, 0, sizeof(buf));
		if((buf[0x0E] & 0xFF) == 0x57 && (buf[0x0F] & 0xFF) == 0x57)
			break;
	}
	if(ctlr->card.io >= 0x380)
	ctlr->card.reset = ne2000reset;
	ctlr->card.attach = dp8390attach;
	ctlr->card.mode = dp8390mode;
	ctlr->card.read = dp8390read;
	ctlr->card.write = dp8390write;
	ctlr->card.receive = dp8390receive;
	ctlr->card.transmit = dp8390transmit;
	ctlr->card.intr = dp8390intr;
	ctlr->card.watch = dp8390watch;
	ctlr->card.overflow = dp8390overflow;

	ctlr->card.bit16 = 1;
	ctlr->card.dp8390 = ctlr->card.port;
	ctlr->card.data = ctlr->card.port+Data;

	ctlr->card.tstart = HOWMANY(ctlr->card.mem, Dp8390BufSz);
	ctlr->card.pstart = ctlr->card.tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
	ctlr->card.pstop = ctlr->card.tstart + HOWMANY(ctlr->card.size, Dp8390BufSz);

	/*
	 * Reset the board. This is done by doing a read
	 * followed by a write to the Reset address.
	 */
	buf[0] = inb(ctlr->card.port+Reset);
	delay(2);
	outb(ctlr->card.port+Reset, buf[0]);
	
	/*
	 * Init the (possible) chip, then use the (possible)
	 * chip to read the (possible) PROM for ethernet address
	 * and a marker byte.
	 * We could just look at the DP8390 command register after
	 * initialisation has been tried, but that wouldn't be
	 * enough, there are other ethernet boards which could
	 * match.
	 */
	dp8390reset(ctlr);
	memset(buf, 0, sizeof(buf));
	dp8390read(ctlr, buf, 0, sizeof(buf));
	if((buf[0x0E] & 0xFF) != 0x57 || (buf[0x0F] & 0xFF) != 0x57)
		return -1;

	/*
	 * Stupid machine. We asked for shorts, we got shorts,
	 * although the PROM is a byte array.


@@ 75,35 99,8 @@ reset(Ctlr *ctlr)
	return 0;
}

Card ether2000 = {
	"NE2000",			/* ident */

	reset,				/* reset */
	0,				/* init */
	dp8390attach,			/* attach */
	dp8390mode,			/* mode */

	dp8390read,			/* read */
	dp8390write,			/* write */

	dp8390receive,			/* receive */
	dp8390transmit,			/* transmit */
	dp8390intr,			/* interrupt */
	dp8390watch,			/* watch */
	dp8390overflow,			/* overflow */

	0x300,				/* addr */
	2,				/* irq */
	1,				/* bit16 */

	0,				/* ram */
	0x4000,				/* ramstart */
	0x4000+16*1024,			/* ramstop */

	0x300,				/* dp8390 */
	0x300+Data,			/* data */
	0,				/* software bndry */
	0x4000/Dp8390BufSz,		/* tstart */
	0x4600/Dp8390BufSz,		/* pstart */
	0x8000/Dp8390BufSz,		/* pstop */
};
void
ether2000link(void)
{
	addethercard("NE2000", ne2000reset);
}

M pc/ether503.c => pc/ether503.c +6 -0
@@ 338,3 338,9 @@ Card ether503 = {
	(RamOffset+0x600)/Dp8390BufSz,	/* pstart */
	(RamOffset+8*1024)/Dp8390BufSz,	/* pstop */
};

void
ether503link(void)
{
	addethercard("3C503",  ccc503reset);
}

M pc/ether509.c => pc/ether509.c +194 -180
@@ 84,145 84,14 @@ enum {
	RxReceiving	= 0x8000,	/* RX Receiving */
};

#define COMMAND(ctlr, cmd, a)	outs(ctlr->card.io+Command, ((cmd)<<11)|(a))

/*
 * Write two 0 bytes to identify the IDport and then reset the
 * ID sequence. Then send the ID sequence to the card to get
 * the card into command state.
 */
static void
idseq(void)
{
	int i;
	uchar al;

	outb(IDport, 0);
	outb(IDport, 0);
	for(al = 0xFF, i = 0; i < 255; i++){
		outb(IDport, al);
		if(al & 0x80){
			al <<= 1;
			al ^= 0xCF;
		}
		else
			al <<= 1;
	}
}

/*
 * Get configuration parameters.
 */
static int
reset(Ctlr *ctlr)
{
	int i, ea;
	ushort x, acr;

	/*
	 * Do the little configuration dance. We only look
	 * at the first card that responds, if we ever have more
	 * than one we'll need to modify this sequence.
	 *
	 * 2. get to command state, reset, then return to command state
	 */
	idseq();
	outb(IDport, 0xC1);
	delay(2);
	idseq();

	/*
	 * 3. Read the Product ID from the EEPROM.
	 *    This is done by writing the IDPort with 0x83 (0x80
	 *    is the 'read EEPROM command, 0x03 is the offset of
	 *    the Product ID field in the EEPROM).
	 *    The data comes back 1 bit at a time.
	 *    We seem to need a delay here between reading the bits.
	 *
	 * If the ID doesn't match the 3C509 ID code, the adapter
	 * probably isn't there, so barf.
	 */
	outb(IDport, 0x83);
	for(x = 0, i = 0; i < 16; i++){
		delay(5);
		x <<= 1;
		x |= inb(IDport) & 0x01;
	}
	if((x & 0xF0FF) != 0x9050)
		return -1;

	/*
	 * 3. Read the Address Configuration from the EEPROM.
	 *    The Address Configuration field is at offset 0x08 in the EEPROM).
	 * 6. Activate the adapter by writing the Activate command
	 *    (0xFF).
	 */
	outb(IDport, 0x88);
	for(acr = 0, i = 0; i < 16; i++){
		delay(20);
		acr <<= 1;
		acr |= inb(IDport) & 0x01;
	}
	outb(IDport, 0xFF);

	/*
	 * 8. Now we can talk to the adapter's I/O base addresses.
	 *    We get the I/O base address from the acr just read.
	 *
	 *    Enable the adapter. 
	 */
	ctlr->card.io = (acr & 0x1F)*0x10 + 0x200;
	outb(ctlr->card.io+ConfigControl, 0x01);

	/*
	 * Read the IRQ from the Resource Configuration Register
	 * and the ethernet address from the EEPROM.
	 * The EEPROM command is 8bits, the lower 6 bits being
	 * the address offset.
	 */
	ctlr->card.irq = (ins(ctlr->card.io+ResourceConfig)>>12) & 0x0F;
	for(ea = 0, i = 0; i < 3; i++, ea += 2){
		while(ins(ctlr->card.io+EEPROMcmd) & 0x8000)
			;
		outs(ctlr->card.io+EEPROMcmd, (2<<6)|i);
		while(ins(ctlr->card.io+EEPROMcmd) & 0x8000)
			;
		x = ins(ctlr->card.io+EEPROMdata);
		ctlr->ea[ea] = (x>>8) & 0xFF;
		ctlr->ea[ea+1] = x & 0xFF;
	}

	/*
	 * Finished with window 0. Now set the ethernet address
	 * in window 2.
	 * Commands have the format 'CCCCCAAAAAAAAAAA' where C
	 * is a bit in the command and A is a bit in the argument.
	 */
	COMMAND(ctlr, SelectWindow, 2);
	for(i = 0; i < 6; i++)
		outb(ctlr->card.io+i, ctlr->ea[i]);

	/*
	 * Finished with window 2.
	 * Set window 1 for normal operation.
	 */
	COMMAND(ctlr, SelectWindow, 1);

	/*
	 * If we have a 10BASE2 transceiver, start the DC-DC
	 * converter. Wait > 800 microseconds.
	 */
	if(((acr>>14) & 0x03) == 0x03){
		COMMAND(ctlr, StartCoax, 0);
		delay(1);
	}

	return 0;
}
#define COMMAND(port, cmd, a)	outs(port+Command, ((cmd)<<11)|(a))

static void
attach(Ctlr *ctlr)
{
	ulong port;

	port = ctlr->card.port;
	/*
	 * Set the receiver packet filter for our own and
	 * and broadcast addresses, set the interrupt masks


@@ 231,20 100,23 @@ attach(Ctlr *ctlr)
	 * is the receiver interrupt. If the transmit FIFO fills up,
	 * we will also see TxAvailable interrupts.
	 */
	COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr);
	COMMAND(ctlr, SetReadZeroMask, AllIntr|Latch);
	COMMAND(ctlr, SetIntrMask, AllIntr|Latch);
	COMMAND(ctlr, RxEnable, 0);
	COMMAND(ctlr, TxEnable, 0);
	COMMAND(port, SetRxFilter, Broadcast|MyEtherAddr);
	COMMAND(port, SetReadZeroMask, AllIntr|Latch);
	COMMAND(port, SetIntrMask, AllIntr|Latch);
	COMMAND(port, RxEnable, 0);
	COMMAND(port, TxEnable, 0);
}

static void
mode(Ctlr *ctlr, int on)
{
	ulong port;

	port = ctlr->card.port;
	if(on)
		COMMAND(ctlr, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
		COMMAND(port, SetRxFilter, Promiscuous|Broadcast|MyEtherAddr);
	else
		COMMAND(ctlr, SetRxFilter, Broadcast|MyEtherAddr);
		COMMAND(port, SetRxFilter, Broadcast|MyEtherAddr);
}

static void


@@ 253,8 125,10 @@ receive(Ctlr *ctlr)
	ushort status;
	RingBuf *rb;
	int len;
	ulong port;

	while(((status = ins(ctlr->card.io+RxStatus)) & RxEmpty) == 0){
	port = ctlr->card.port;
	while(((status = ins(port+RxStatus)) & RxEmpty) == 0){
		/*
		 * If we had an error, log it and continue
		 * without updating the ring.


@@ 295,9 169,9 @@ receive(Ctlr *ctlr)
				 * doubleword. We can pick them out 16-bits
				 * at a time (can try 32-bits at a time
				 * later).
				insl(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 4));
				insl(port+Fifo, rb->pkt, HOWMANY(len, 4));
				 */
				inss(ctlr->card.io+Fifo, rb->pkt, HOWMANY(len, 2));
				inss(port+Fifo, rb->pkt, HOWMANY(len, 2));

				/*
				 * Update the ring.


@@ 311,8 185,8 @@ receive(Ctlr *ctlr)
		 * Discard the packet as we're done with it.
		 * Wait for discard to complete.
		 */
		COMMAND(ctlr, RxDiscard, 0);
		while(ins(ctlr->card.io+Status) & CmdInProgress)
		COMMAND(port, RxDiscard, 0);
		while(ins(port+Status) & CmdInProgress)
			;
	}
}


@@ 322,7 196,9 @@ transmit(Ctlr *ctlr)
{
	RingBuf *tb;
	ushort len;
	ulong port;

	port = ctlr->card.port;
	for(tb = &ctlr->tb[ctlr->ti]; tb->owner == Interface; tb = &ctlr->tb[ctlr->ti]){
		/*
		 * If there's no room in the FIFO for this packet,


@@ 331,8 207,8 @@ transmit(Ctlr *ctlr)
		 * we need 4 bytes for the preamble.
		 */
		len = ROUNDUP(tb->len, 4);
		if(len+4 > ins(ctlr->card.io+TxFreeBytes)){
			COMMAND(ctlr, SetTxAvailable, len);
		if(len+4 > ins(port+TxFreeBytes)){
			COMMAND(port, SetTxAvailable, len);
			break;
		}



@@ 340,9 216,9 @@ transmit(Ctlr *ctlr)
		 * There's room, copy the packet to the FIFO and free
		 * the buffer back to the host.
		 */
		outs(ctlr->card.io+Fifo, tb->len);
		outs(ctlr->card.io+Fifo, 0);
		outss(ctlr->card.io+Fifo, tb->pkt, len/2);
		outs(port+Fifo, tb->len);
		outs(port+Fifo, 0);
		outss(port+Fifo, tb->pkt, len/2);
		tb->owner = Host;
		ctlr->ti = NEXT(ctlr->ti, ctlr->ntb);
	}


@@ 352,10 228,12 @@ static ushort
getdiag(Ctlr *ctlr)
{
	ushort bytes;
	ulong port;

	COMMAND(ctlr, SelectWindow, 4);
	bytes = ins(ctlr->card.io+FIFOdiag);
	COMMAND(ctlr, SelectWindow, 1);
	port = ctlr->card.port;
	COMMAND(port, SelectWindow, 4);
	bytes = ins(port+FIFOdiag);
	COMMAND(port, SelectWindow, 1);
	return bytes & 0xFFFF;
}



@@ 364,8 242,10 @@ interrupt(Ctlr *ctlr)
{
	ushort status, diag;
	uchar txstatus, x;
	ulong port;

	status = ins(ctlr->card.io+Status);
	port = ctlr->card.port;
	status = ins(port+Status);

	if(status & Failure){
		/*


@@ 379,12 259,12 @@ interrupt(Ctlr *ctlr)
		print("ether509: status #%ux, diag #%ux\n", status, diag);

		if(diag & TxOverrun){
			COMMAND(ctlr, TxReset, 0);
			COMMAND(ctlr, TxEnable, 0);
			COMMAND(port, TxReset, 0);
			COMMAND(port, TxEnable, 0);
		}

		if(diag & RxUnderrun){
			COMMAND(ctlr, RxReset, 0);
			COMMAND(port, RxReset, 0);
			attach(ctlr);
		}



@@ 409,14 289,14 @@ interrupt(Ctlr *ctlr)
		 */
		txstatus = 0;
		do{
			if(x = inb(ctlr->card.io+TxStatus))
				outb(ctlr->card.io+TxStatus, 0);
			if(x = inb(port+TxStatus))
				outb(port+TxStatus, 0);
			txstatus |= x;
		}while(ins(ctlr->card.io+Status) & TxComplete);
		}while(ins(port+Status) & TxComplete);

		if(txstatus & (TxJabber|TxUnderrun))
			COMMAND(ctlr, TxReset, 0);
		COMMAND(ctlr, TxEnable, 0);
			COMMAND(port, TxReset, 0);
		COMMAND(port, TxEnable, 0);
		ctlr->oerrs++;
	}



@@ 425,7 305,7 @@ interrupt(Ctlr *ctlr)
		 * Reset the Tx FIFO threshold.
		 */
		if(status & TxAvailable)
			COMMAND(ctlr, AckIntr, TxAvailable);
			COMMAND(port, AckIntr, TxAvailable);
		transmit(ctlr);
		wakeup(&ctlr->tr);
		status &= ~(TxAvailable|TxComplete);


@@ 439,23 319,157 @@ interrupt(Ctlr *ctlr)
	if(status & AllIntr)
		panic("ether509 interrupt: #%lux, #%ux\n", status, getdiag(ctlr));

	COMMAND(ctlr, AckIntr, Latch);
	COMMAND(port, AckIntr, Latch);
}

Card ether509 = {
	"3Com509",			/* ident */
/*
 * Write two 0 bytes to identify the IDport and then reset the
 * ID sequence. Then send the ID sequence to the card to get
 * the card into command state.
 */
static void
idseq(void)
{
	int i;
	uchar al;

	reset,				/* reset */
	0,				/* init */
	attach,				/* attach */
	mode,				/* mode */
	outb(IDport, 0);
	outb(IDport, 0);
	for(al = 0xFF, i = 0; i < 255; i++){
		outb(IDport, al);
		if(al & 0x80){
			al <<= 1;
			al ^= 0xCF;
		}
		else
			al <<= 1;
	}
}

	0,				/* read */
	0,				/* write */
/*
 * Get configuration parameters.
 */
int
ccc509reset(Ctlr *ctlr)
{
	int i, ea;
	ushort x, acr;
	ulong port;

	0,				/* receive */
	transmit,			/* transmit */
	interrupt,			/* interrupt */
	0,				/* watch */
	0,				/* overflow */
};
	/*
	 * Do the little configuration dance. We only look
	 * at the first card that responds, if we ever have more
	 * than one we'll need to modify this sequence.
	 *
	 * 2. get to command state, reset, then return to command state
	 */
	idseq();
	outb(IDport, 0xC1);
	delay(2);
	idseq();

	/*
	 * 3. Read the Product ID from the EEPROM.
	 *    This is done by writing the IDPort with 0x83 (0x80
	 *    is the 'read EEPROM command, 0x03 is the offset of
	 *    the Product ID field in the EEPROM).
	 *    The data comes back 1 bit at a time.
	 *    We seem to need a delay here between reading the bits.
	 *
	 * If the ID doesn't match the 3C509 ID code, the adapter
	 * probably isn't there, so barf.
	 */
	outb(IDport, 0x83);
	for(x = 0, i = 0; i < 16; i++){
		delay(5);
		x <<= 1;
		x |= inb(IDport) & 0x01;
	}
	if((x & 0xF0FF) != 0x9050)
		return -1;

	/*
	 * 3. Read the Address Configuration from the EEPROM.
	 *    The Address Configuration field is at offset 0x08 in the EEPROM).
	 * 6. Activate the adapter by writing the Activate command
	 *    (0xFF).
	 */
	outb(IDport, 0x88);
	for(acr = 0, i = 0; i < 16; i++){
		delay(20);
		acr <<= 1;
		acr |= inb(IDport) & 0x01;
	}
	outb(IDport, 0xFF);

	/*
	 * 8. Now we can talk to the adapter's I/O base addresses.
	 *    We get the I/O base address from the acr just read.
	 *
	 *    Enable the adapter. 
	 */
	ctlr->card.port = (acr & 0x1F)*0x10 + 0x200;
	port = ctlr->card.port;
	outb(port+ConfigControl, 0x01);

	/*
	 * Read the IRQ from the Resource Configuration Register
	 * and the ethernet address from the EEPROM.
	 * The EEPROM command is 8bits, the lower 6 bits being
	 * the address offset.
	 */
	ctlr->card.irq = (ins(port+ResourceConfig)>>12) & 0x0F;
	for(ea = 0, i = 0; i < 3; i++, ea += 2){
		while(ins(port+EEPROMcmd) & 0x8000)
			;
		outs(port+EEPROMcmd, (2<<6)|i);
		while(ins(port+EEPROMcmd) & 0x8000)
			;
		x = ins(port+EEPROMdata);
		ctlr->ea[ea] = (x>>8) & 0xFF;
		ctlr->ea[ea+1] = x & 0xFF;
	}

	/*
	 * Finished with window 0. Now set the ethernet address
	 * in window 2.
	 * Commands have the format 'CCCCCAAAAAAAAAAA' where C
	 * is a bit in the command and A is a bit in the argument.
	 */
	COMMAND(port, SelectWindow, 2);
	for(i = 0; i < 6; i++)
		outb(port+i, ctlr->ea[i]);

	/*
	 * Finished with window 2.
	 * Set window 1 for normal operation.
	 */
	COMMAND(port, SelectWindow, 1);

	/*
	 * If we have a 10BASE2 transceiver, start the DC-DC
	 * converter. Wait > 800 microseconds.
	 */
	if(((acr>>14) & 0x03) == 0x03){
		COMMAND(port, StartCoax, 0);
		delay(1);
	}

	/*
	 * Set up the software configuration.
	 */
	ctlr->card.reset = ccc509reset;
	ctlr->card.attach = attach;
	ctlr->card.mode = mode;
	ctlr->card.transmit = transmit;
	ctlr->card.intr = interrupt;
	ctlr->card.bit16 = 1;

	return 0;
}

void
ether509link(void)
{
	addethercard("3C509",  ccc509reset);
}

M pc/ether8003.c => pc/ether8003.c +105 -109
@@ 57,37 57,105 @@ static int intrmap[] = {
	9, 3, 5, 7, 10, 11, 15, 4,
};

static void*
read(Ctlr *ctlr, void *to, ulong from, ulong len)
{
	/*
	 * In this case, 'from' is an index into the shared memory.
	 */
	memmove(to, (void*)(ctlr->card.mem+from), len);
	return to;
}

static void*
write(Ctlr *ctlr, ulong to, void *from, ulong len)
{
	/*
	 * In this case, 'to' is an index into the shared memory.
	 */
	memmove((void*)(ctlr->card.mem+to), from, len);
	return (void*)to;
}

static void
watch(Ctlr *ctlr)
{
	uchar msr;
	int s;

	s = splhi();
	msr = inb(ctlr->card.port+Msr);
	/*
	 * If the card has reset itself,
	 * start again.
	 */
	if((msr & Menb) == 0){
		delay(100);

		dp8390reset(ctlr);
		etherinit();

		wakeup(&ctlr->tr);
		wakeup(&ctlr->rr);
	}
	splx(s);
}

/*
 * Get configuration parameters, enable memory.
 * There are opportunities here for buckets of code.
 * We'll try to resist.
 */
static int
reset(Ctlr *ctlr)
int
wd8003reset(Ctlr *ctlr)
{
	int i;
	uchar ic[8], sum;
	ulong wd8003;

	/*
	 * Set up the software configuration.
	 * Use defaults for port, irq, mem and size if not specified.
	 * Defaults are set for the dumb 8003E which can't be
	 * autoconfigured.
	 */
	if(ctlr->card.port == 0)
		ctlr->card.port = 0x280;
	if(ctlr->card.irq == 0)
		ctlr->card.irq = 3;
	if(ctlr->card.mem == 0)
		ctlr->card.mem = 0xD0000;
	if(ctlr->card.size == 0)
		ctlr->card.size = 8*1024;

	ctlr->card.reset = wd8003reset;
	ctlr->card.attach = dp8390attach;
	ctlr->card.mode = dp8390mode;
	ctlr->card.read = read;
	ctlr->card.write = write;
	ctlr->card.receive = dp8390receive;
	ctlr->card.transmit = dp8390transmit;
	ctlr->card.intr = dp8390intr;
	ctlr->card.watch = watch;
	ctlr->card.ram = 1;

	wd8003 = ctlr->card.port;
	/*
	 * Look for the interface. We read the LAN address ROM
	 * and validate the checksum - the sum of all 8 bytes
	 * should be 0xFF.
	 * While we're at it, get the (possible) interface chip
	 * registers, we'll use them to check for aliasing later.
	 */
	for(ctlr->card.io = 0x200; ctlr->card.io < 0x400; ctlr->card.io += 0x20){
		sum = 0;
		for(i = 0; i < sizeof(ctlr->ea); i++){
			ctlr->ea[i] = inb(ctlr->card.io+Lar+i);
			sum += ctlr->ea[i];
			ic[i] = inb(ctlr->card.io+i);
		}
		sum += inb(ctlr->card.io+Id);
		sum += inb(ctlr->card.io+Cksum);
		if(sum == 0xFF)
			break;
	sum = 0;
	for(i = 0; i < sizeof(ctlr->ea); i++){
		ctlr->ea[i] = inb(wd8003+Lar+i);
		sum += ctlr->ea[i];
		ic[i] = inb(wd8003+i);
	}
	if(ctlr->card.io >= 0x400)
	sum += inb(wd8003+Id);
	sum += inb(wd8003+Cksum);
	if(sum != 0xFF)
		return -1;

	/*


@@ 101,7 169,7 @@ reset(Ctlr *ctlr)
	 */
	if(memcmp(&ctlr->ea[1], &ic[1], 5) == 0){
		memset(ic, 0, sizeof(ic));
		ic[Msr] = (((ulong)ctlr->card.ramstart)>>13) & 0x3F;
		ic[Msr] = (((ulong)ctlr->card.mem)>>13) & 0x3F;
		ctlr->card.watch = 0;
	}
	else{


@@ 110,13 178,12 @@ reset(Ctlr *ctlr)
		 * the 83C584 interface chip, but has 2 real registers, write Gp2 and if
		 * it reads back the same, it's not an 8013EBT.
		 */
		outb(ctlr->card.io+Gp2, 0xAA);
		inb(ctlr->card.io+Msr);				/* wiggle bus */
		if(inb(ctlr->card.io+Gp2) != 0xAA){
		outb(wd8003+Gp2, 0xAA);
		inb(wd8003+Msr);				/* wiggle bus */
		if(inb(wd8003+Gp2) != 0xAA){
			memset(ic, 0, sizeof(ic));
			ic[Msr] = (((ulong)ctlr->card.ramstart)>>13) & 0x3F;
			ic[Msr] = (((ulong)ctlr->card.mem)>>13) & 0x3F;
			ctlr->card.watch = 0;
			ctlr->card.irq = 2;			/* special */
		}
		else
			ctlr->card.irq = intrmap[((ic[Irr]>>5) & 0x3)|(ic[Icr] & 0x4)];


@@ 126,46 193,43 @@ reset(Ctlr *ctlr)
		 * If Bit16 is read/write, then we have an 8-bit card.
		 * If Bit16 is set, we're in a 16-bit slot.
		 */
		outb(ctlr->card.io+Icr, ic[Icr]^Bit16);
		inb(ctlr->card.io+Msr);				/* wiggle bus */
		if((inb(ctlr->card.io+Icr) & Bit16) == (ic[Icr] & Bit16)){
		outb(wd8003+Icr, ic[Icr]^Bit16);
		inb(wd8003+Msr);				/* wiggle bus */
		if((inb(wd8003+Icr) & Bit16) == (ic[Icr] & Bit16)){
			ctlr->card.bit16 = 1;
			ic[Icr] &= ~Bit16;
		}
		outb(ctlr->card.io+Icr, ic[Icr]);
		outb(wd8003+Icr, ic[Icr]);

		if(ctlr->card.bit16 && (inb(ctlr->card.io+Icr) & Bit16) == 0)
		if(ctlr->card.bit16 && (inb(wd8003+Icr) & Bit16) == 0)
			ctlr->card.bit16 = 0;
	}

	ctlr->card.ramstart = KZERO|((ic[Msr] & 0x3F)<<13);
	ctlr->card.mem = KZERO|((ic[Msr] & 0x3F)<<13);
	if(ctlr->card.bit16)
		ctlr->card.ramstart |= (ic[Laar] & 0x1F)<<19;
		ctlr->card.mem |= (ic[Laar] & 0x1F)<<19;
	else
		ctlr->card.ramstart |= 0x80000;
		ctlr->card.mem |= 0x80000;

	if(ic[Icr] & (1<<3))
		ctlr->card.ramstop = 32*1024;
	else
		ctlr->card.ramstop = 8*1024;
		ctlr->card.size = 32*1024;
	if(ctlr->card.bit16)
		ctlr->card.ramstop <<= 1;
	ctlr->card.ramstop += ctlr->card.ramstart;
		ctlr->card.size <<= 1;

	/*
	 * Set the DP8390 ring addresses.
	 */
	ctlr->card.dp8390 = ctlr->card.io+0x10;
	ctlr->card.pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
	ctlr->card.pstop = HOWMANY(ctlr->card.ramstop-ctlr->card.ramstart, Dp8390BufSz);
	ctlr->card.dp8390 = wd8003+0x10;
	ctlr->card.tstart = 0;
	ctlr->card.pstart = HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
	ctlr->card.pstop = HOWMANY(ctlr->card.size, Dp8390BufSz);

	/*
	 * Enable interface RAM, set interface width.
	 */
	outb(ctlr->card.io+Msr, ic[Msr]|Menb);
	outb(wd8003+Msr, ic[Msr]|Menb);
	if(ctlr->card.bit16)
		outb(ctlr->card.io+Laar, ic[Laar]|L16en|M16en|ZeroWS16);
		outb(wd8003+Laar, ic[Laar]|L16en|M16en|ZeroWS16);

	/*
	 * Finally, init the 8390 and set the


@@ 177,76 241,8 @@ reset(Ctlr *ctlr)
	return 0;
}

static void*
read(Ctlr *ctlr, void *to, ulong from, ulong len)
{
	/*
	 * In this case, 'from' is an index into the shared memory.
	 */
	memmove(to, (void*)(ctlr->card.ramstart+from), len);
	return to;
}

static void*
write(Ctlr *ctlr, ulong to, void *from, ulong len)
{
	/*
	 * In this case, 'to' is an index into the shared memory.
	 */
	memmove((void*)(ctlr->card.ramstart+to), from, len);
	return (void*)to;
}

static void
watch(Ctlr *ctlr)
void
ether8003link(void)
{
	uchar msr;
	int s;

	s = splhi();
	msr = inb(ctlr->card.io+Msr);
	/*
	 * If the card has reset itself,
	 * start again.
	 */
	if((msr & Menb) == 0){
		delay(100);

		dp8390reset(ctlr);
		etherinit();

		wakeup(&ctlr->tr);
		wakeup(&ctlr->rr);
	}
	splx(s);
	addethercard("WD8003", wd8003reset);
}

/*
 * Defaults are set for the dumb 8003E
 * which can't be autoconfigured.
 */
Card ether8003 = {
	"WD8003",			/* ident */

	reset,				/* reset */
	0,				/* init */
	dp8390attach,			/* attach */
	dp8390mode,			/* mode */

	read,				/* read */
	write,				/* write */

	dp8390receive,			/* receive */
	dp8390transmit,			/* transmit */
	dp8390intr,			/* interrupt */
	watch,				/* watch */
	0,				/* overflow */

	0x280,				/* io */
	3,				/* irq */
	0,				/* bit16 */

	1,				/* ram */
	0xD0000,			/* ramstart */
	0xD0000+8*1024,			/* ramstop */
};

M pc/ether8390.c => pc/ether8390.c +133 -91
@@ 149,8 149,10 @@ typedef struct {
static void
dp8390disable(Ctlr *ctlr)
{
	ulong dp8390;
	int timo;

	dp8390 = ctlr->card.dp8390;
	/*
	 * Stop the chip. Set the Stp bit and wait for the chip
	 * to finish whatever was on its tiny mind before it sets


@@ 159,23 161,26 @@ dp8390disable(Ctlr *ctlr)
	 * chip there if this is called when probing for a device
	 * at boot.
	 */
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
	dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
	dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
	for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rst) == 0 && timo; timo--)
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);
	for(timo = 10000; (dp8390inb(dp8390+Isr) & Rst) == 0 && timo; timo--)
			;
}

static void
dp8390ring(Ctlr *ctlr)
{
	dp8390outb(ctlr->card.dp8390+Pstart, ctlr->card.pstart);
	dp8390outb(ctlr->card.dp8390+Pstop, ctlr->card.pstop);
	dp8390outb(ctlr->card.dp8390+Bnry, ctlr->card.pstop-1);
	ulong dp8390;

	dp8390outb(ctlr->card.dp8390+Cr, Page1|RDMAabort|Stp);
	dp8390outb(ctlr->card.dp8390+Curr, ctlr->card.pstart);
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
	dp8390 = ctlr->card.dp8390;
	dp8390outb(dp8390+Pstart, ctlr->card.pstart);
	dp8390outb(dp8390+Pstop, ctlr->card.pstop);
	dp8390outb(dp8390+Bnry, ctlr->card.pstop-1);

	dp8390outb(dp8390+Cr, Page1|RDMAabort|Stp);
	dp8390outb(dp8390+Curr, ctlr->card.pstart);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);

	ctlr->card.nxtpkt = ctlr->card.pstart;
}


@@ 183,6 188,9 @@ dp8390ring(Ctlr *ctlr)
void
dp8390reset(Ctlr *ctlr)
{
	ulong dp8390;

	dp8390 = ctlr->card.dp8390;
	/*
	 * This is the initialisation procedure described
	 * as 'mandatory' in the datasheet, with references


@@ 190,15 198,15 @@ dp8390reset(Ctlr *ctlr)
	 */ 
	dp8390disable(ctlr);
	if(ctlr->card.bit16)
		dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls|Wts);
		dp8390outb(dp8390+Dcr, Ft4|Ls|Wts);
	else
		dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls);
		dp8390outb(dp8390+Dcr, Ft4|Ls);

	dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
	dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);

	dp8390outb(ctlr->card.dp8390+Tcr, 0);
	dp8390outb(ctlr->card.dp8390+Rcr, Mon);
	dp8390outb(dp8390+Tcr, 0);
	dp8390outb(dp8390+Rcr, Mon);

	/*
	 * Init the ring hardware and software ring pointers.


@@ 206,16 214,16 @@ dp8390reset(Ctlr *ctlr)
	 * it yet.
	 */
	dp8390ring(ctlr);
	dp8390outb(ctlr->card.dp8390+Tpsr, ctlr->card.tstart);
	dp8390outb(dp8390+Tpsr, ctlr->card.tstart);

	dp8390outb(ctlr->card.dp8390+Isr, 0xFF);
	dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
	dp8390outb(dp8390+Isr, 0xFF);
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);

	/*
	 * Leave the chip initialised,
	 * but in monitor mode.
	 */
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
}

void


@@ 246,9 254,33 @@ dp8390mode(Ctlr *ctlr, int on)
void
dp8390setea(Ctlr *ctlr)
{
	ulong dp8390;
	uchar cr;
	int i;

	dp8390 = ctlr->card.dp8390;
	/*
	 * Set the ethernet address into the chip.
	 * Take care to restore the command register
	 * afterwards. We don't care about multicast
	 * addresses as we never set the multicast
	 * enable.
	 */
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < sizeof(ctlr->ea); i++)
		dp8390outb(dp8390+Par0+i, ctlr->ea[i]);
	dp8390outb(dp8390+Cr, cr);
}

void
dp8390getea(Ctlr *ctlr)
{
	ulong dp8390;
	uchar cr;
	int i;

	dp8390 = ctlr->card.dp8390;
	/*
	 * Set the ethernet address into the chip.
	 * Take care to restore the command register


@@ 256,43 288,45 @@ dp8390setea(Ctlr *ctlr)
	 * addresses as we never set the multicast
	 * enable.
	 */
	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	for(i = 0; i < sizeof(ctlr->ea); i++)
		dp8390outb(ctlr->card.dp8390+Par0+i, ctlr->ea[i]);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
		ctlr->ea[i] = dp8390inb(dp8390+Par0+i);
	dp8390outb(dp8390+Cr, cr);
}

void*
dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
{
	ulong dp8390;
	uchar cr;
	int timo;

	dp8390 = ctlr->card.dp8390;
	/*
	 * Read some data at offset 'from' in the card's memory
	 * using the DP8390 remote DMA facility, and place it at
	 * 'to' in main memory, via the I/O data port.
	 */
	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Isr, Rdc);

	/*
	 * Set up the remote DMA address and count.
	 */
	if(ctlr->card.bit16)
		len = ROUNDUP(len, 2);
	dp8390outb(ctlr->card.dp8390+Rbcr0, len & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rbcr1, (len>>8) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar0, from & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar1, (from>>8) & 0xFF);
	dp8390outb(dp8390+Rbcr0, len & 0xFF);
	dp8390outb(dp8390+Rbcr1, (len>>8) & 0xFF);
	dp8390outb(dp8390+Rsar0, from & 0xFF);
	dp8390outb(dp8390+Rsar1, (from>>8) & 0xFF);

	/*
	 * Start the remote DMA read and suck the data
	 * out of the I/O port.
	 */
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta);
	dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);
	if(ctlr->card.bit16)
		inss(ctlr->card.data, to, len/2);
	else


@@ 305,28 339,29 @@ dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len)
	 * to the miracles of the bus, we could get this far
	 * and still be talking to a slot full of nothing.
	 */
	for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0 && timo; timo--)
	for(timo = 10000; (dp8390inb(dp8390+Isr) & Rdc) == 0 && timo; timo--)
			;

	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
	dp8390outb(dp8390+Isr, Rdc);
	dp8390outb(dp8390+Cr, cr);
	return to;
}

void*
dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
{
	ulong dp8390, crda;
	uchar cr;
	ulong crda;

	dp8390 = ctlr->card.dp8390;
	/*
	 * Write some data to offset 'to' in the card's memory
	 * using the DP8390 remote DMA facility, reading it at
	 * 'from' in main memory, via the I/O data port.
	 */
	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Isr, Rdc);

	if(ctlr->card.bit16)
		len = ROUNDUP(len, 2);


@@ 337,24 372,24 @@ dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
	 * the initial set up for read.
	 */
	crda = to-1-ctlr->card.bit16;
	dp8390outb(ctlr->card.dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar0, crda & 0xFF);
	dp8390outb(ctlr->card.dp8390+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta);
	dp8390outb(dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF);
	dp8390outb(dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF);
	dp8390outb(dp8390+Rsar0, crda & 0xFF);
	dp8390outb(dp8390+Rsar1, (crda>>8) & 0xFF);
	dp8390outb(dp8390+Cr, Page0|RDMAread|Sta);

	for(;;){
		crda = dp8390inb(ctlr->card.dp8390+Crda0);
		crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8;
		crda = dp8390inb(dp8390+Crda0);
		crda |= dp8390inb(dp8390+Crda1)<<8;
		if(crda == to){
			/*
			 * Start the remote DMA write and make sure
			 * the registers are correct.
			 */
			dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAwrite|Sta);
			dp8390outb(dp8390+Cr, Page0|RDMAwrite|Sta);

			crda = dp8390inb(ctlr->card.dp8390+Crda0);
			crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8;
			crda = dp8390inb(dp8390+Crda0);
			crda |= dp8390inb(dp8390+Crda1)<<8;
			if(crda != to)
				panic("crda write %d to %d\n", crda, to);



@@ 375,28 410,28 @@ dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len)
	 * a timeout here if this ever gets called before
	 * we know there really is a chip there.
	 */
	while((dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0)
	while((dp8390inb(dp8390+Isr) & Rdc) == 0)
			;

	dp8390outb(ctlr->card.dp8390+Isr, Rdc);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
	dp8390outb(dp8390+Isr, Rdc);
	dp8390outb(dp8390+Cr, cr);
	return (void*)to;
}

static uchar
getcurr(Ctlr *ctlr)
getcurr(ulong dp8390)
{
	uchar cr, curr;

	cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(ctlr->card.dp8390+Curr);
	dp8390outb(ctlr->card.dp8390+Cr, cr);
	cr = dp8390inb(dp8390+Cr) & ~Txp;
	dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr));
	curr = dp8390inb(dp8390+Curr);
	dp8390outb(dp8390+Cr, cr);
	return curr;
}

static void
cldaquiet(Ctlr *ctlr)
cldaquiet(ulong dp8390)
{
	uchar a, b, c;



@@ 409,11 444,11 @@ cldaquiet(Ctlr *ctlr)
	 */
	
	for(;;delay(10)){
		a = dp8390inb(ctlr->card.dp8390+Clda0);
		b = dp8390inb(ctlr->card.dp8390+Clda0);
		a = dp8390inb(dp8390+Clda0);
		b = dp8390inb(dp8390+Clda0);
		if(a != b)
			continue;
		c = dp8390inb(ctlr->card.dp8390+Clda0);
		c = dp8390inb(dp8390+Clda0);
		if(c != b)
			continue;
		break;


@@ 426,11 461,12 @@ dp8390receive(Ctlr *ctlr)
	RingBuf *ring;
	uchar curr, len1, *pkt;
	Hdr hdr;
	ulong data, len;
	ulong dp8390, data, len;

	for(curr = getcurr(ctlr); ctlr->card.nxtpkt != curr; curr = getcurr(ctlr)){
	dp8390 = ctlr->card.dp8390;
	for(curr = getcurr(dp8390); ctlr->card.nxtpkt != curr; curr = getcurr(dp8390)){
		if(strcmp(arch->id, "NCRD.0") == 0)
			cldaquiet(ctlr);
			cldaquiet(dp8390);

		ctlr->inpackets++;



@@ 458,9 494,9 @@ dp8390receive(Ctlr *ctlr)
		  || len < 60 || len > sizeof(Etherpkt)){
			print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|",
				hdr.status, hdr.next, hdr.len0, hdr.len1, len);
			dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
			dp8390ring(ctlr);
			dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
			dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
			return;
		}



@@ 500,7 536,7 @@ dp8390receive(Ctlr *ctlr)
		hdr.next--;
		if(hdr.next < ctlr->card.pstart)
			hdr.next = ctlr->card.pstop-1;
		dp8390outb(ctlr->card.dp8390+Bnry, hdr.next);
		dp8390outb(dp8390+Bnry, hdr.next);
	}
}



@@ 510,8 546,10 @@ dp8390receive(Ctlr *ctlr)
void
dp8390transmit(Ctlr *ctlr)
{
	ulong dp8390;
	RingBuf *ring;

	dp8390 = ctlr->card.dp8390;
	ring = &ctlr->tb[ctlr->ti];
	if(ctlr->tbusy == 0 && ring->owner == Interface){



@@ 519,41 557,43 @@ dp8390transmit(Ctlr *ctlr)

		(*ctlr->card.write)(ctlr, ctlr->card.tstart*Dp8390BufSz, ring->pkt, ring->len);

		dp8390outb(ctlr->card.dp8390+Tbcr0, ring->len & 0xFF);
		dp8390outb(ctlr->card.dp8390+Tbcr1, (ring->len>>8) & 0xFF);
		dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta);
		dp8390outb(dp8390+Tbcr0, ring->len & 0xFF);
		dp8390outb(dp8390+Tbcr1, (ring->len>>8) & 0xFF);
		dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
	}
}

void
dp8390overflow(Ctlr *ctlr)
{
	ulong dp8390;
	uchar txp;
	int resend;

	dp8390 = ctlr->card.dp8390;
	/*
	 * The following procedure is taken from the DP8390[12D] datasheet,
	 * it seems pretty adamant that this is what has to be done.
	 */
	txp = dp8390inb(ctlr->card.dp8390+Cr) & Txp;
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp);
	txp = dp8390inb(dp8390+Cr) & Txp;
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp);
	delay(2);
	dp8390outb(ctlr->card.dp8390+Rbcr0, 0);
	dp8390outb(ctlr->card.dp8390+Rbcr1, 0);
	dp8390outb(dp8390+Rbcr0, 0);
	dp8390outb(dp8390+Rbcr1, 0);

	resend = 0;
	if(txp && (dp8390inb(ctlr->card.dp8390+Isr) & (Txe|Ptx)) == 0)
	if(txp && (dp8390inb(dp8390+Isr) & (Txe|Ptx)) == 0)
		resend = 1;

	dp8390outb(ctlr->card.dp8390+Tcr, Lb);
	dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta);
	dp8390outb(dp8390+Tcr, Lb);
	dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta);
	(*ctlr->card.receive)(ctlr);
	dp8390outb(ctlr->card.dp8390+Isr, Ovw);
	dp8390outb(dp8390+Isr, Ovw);
	wakeup(&ctlr->rr);
	dp8390outb(ctlr->card.dp8390+Tcr, 0);
	dp8390outb(dp8390+Tcr, 0);

	if(resend)
		dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta);
		dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta);
}

void


@@ 577,20 617,22 @@ dp8390watch(Ctlr *ctlr)
void
dp8390intr(Ctlr *ctlr)
{
	ulong dp8390;
	RingBuf *ring;
	uchar isr, r;

	dp8390 = ctlr->card.dp8390;
	/*
	 * While there is something of interest,
	 * clear all the interrupts and process.
	 */
	dp8390outb(ctlr->card.dp8390+Imr, 0x00);
	while(isr = dp8390inb(ctlr->card.dp8390+Isr)){
	dp8390outb(dp8390+Imr, 0x00);
	while(isr = dp8390inb(dp8390+Isr)){

		if(isr & Ovw){
			if(ctlr->card.overflow)
				(*ctlr->card.overflow)(ctlr);
			dp8390outb(ctlr->card.dp8390+Isr, Ovw);
			dp8390outb(dp8390+Isr, Ovw);
			ctlr->overflows++;
		}



@@ 601,7 643,7 @@ dp8390intr(Ctlr *ctlr)
		 */
		if(isr & (Rxe|Prx)){
			(*ctlr->card.receive)(ctlr);
			dp8390outb(ctlr->card.dp8390+Isr, Rxe|Prx);
			dp8390outb(dp8390+Isr, Rxe|Prx);
			wakeup(&ctlr->rr);
		}



@@ 611,14 653,14 @@ dp8390intr(Ctlr *ctlr)
		 * and wake the output routine.
		 */
		if(isr & (Txe|Ptx)){
			r = dp8390inb(ctlr->card.dp8390+Tsr);
			r = dp8390inb(dp8390+Tsr);
			if(isr & Txe){
				if((r & (Cdh|Fu|Crs|Abt)) && ctlr->debug)
					print("Tsr#%2.2ux|", r);
				ctlr->oerrs++;
			}

			dp8390outb(ctlr->card.dp8390+Isr, Txe|Ptx);
			dp8390outb(dp8390+Isr, Txe|Ptx);

			if(isr & Ptx)
				ctlr->outpackets++;


@@ 632,11 674,11 @@ dp8390intr(Ctlr *ctlr)
		}

		if(isr & Cnt){
			ctlr->frames += dp8390inb(ctlr->card.dp8390+Cntr0);
			ctlr->crcs += dp8390inb(ctlr->card.dp8390+Cntr1);
			ctlr->buffs += dp8390inb(ctlr->card.dp8390+Cntr2);
			dp8390outb(ctlr->card.dp8390+Isr, Cnt);
			ctlr->frames += dp8390inb(dp8390+Cntr0);
			ctlr->crcs += dp8390inb(dp8390+Cntr1);
			ctlr->buffs += dp8390inb(dp8390+Cntr2);
			dp8390outb(dp8390+Isr, Cnt);
		}
	}
	dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
	dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe);
}

M pc/fault386.c => pc/fault386.c +5 -4
@@ 18,24 18,25 @@ fault386(Ureg *ur)
	int insyscall;
	char buf[ERRLEN];

	insyscall = u->p->insyscall;
	u->p->insyscall = 1;
	insyscall = up->insyscall;
	up->insyscall = 1;
	addr = getcr2();
	read = !(ur->ecode & 2);
	user = (ur->cs&0xffff) == UESEL;
	spllo();
/* print("F%d:A#%lux:U%d:R%d|", up->pid, addr, user, read);/**/
	n = fault(addr, read);
	if(n < 0){
		if(user){
			sprint(buf, "sys: trap: fault %s addr=0x%lux",
				read? "read" : "write", addr);
			postnote(u->p, 1, buf, NDebug);
			postnote(up, 1, buf, NDebug);
			return;
		}
		dumpregs(ur);
		panic("fault: 0x%lux", addr);
	}
	u->p->insyscall = insyscall;
	up->insyscall = insyscall;
}

void

M pc/fns.h => pc/fns.h +15 -2
@@ 1,6 1,6 @@
#include "../port/portfns.h"

void	meminit(void);
void	addconf(char*, char*);
void	bbinit(void);
void	bigcursor(void);
void	bootargs(ulong);


@@ 11,6 11,7 @@ void	config(int);
int	cpuspeed(int);
void	delay(int);
void	dmaend(int);
void	dmainit(void);
long	dmasetup(int, void*, long, int);
#define	evenaddr(x)		/* 386 doesn't care */
void	fault386(Ureg*);


@@ 25,6 26,7 @@ void	fpsave(FPsave*);
ulong	fpstatus(void);
ulong	getcr0(void);
ulong	getcr2(void);
char*	getconf(char*);
void	i8042a20(void);
void	i8042reset(void);
void	ident(void);


@@ 33,13 35,17 @@ int	inb(int);
void	insb(int, void*, int);
ushort	ins(int);
void	inss(int, void*, int);
ulong	inl(int);
void	insl(int, void*, int);
int	isaconfig(char*, int, ISAConf*);
ulong	isamem(int);
void	kbdinit(void);
void*	l0update(uchar*, uchar*, long);
void*	l1update(uchar*, uchar*, long);
void*	l2update(uchar*, uchar*, long);
long*	mapaddr(ulong);
void	mathinit(void);
void	meminit(void);
void	mmuinit(void);
#define	mmunewpage(x)
int	modem(int);


@@ 49,12 55,19 @@ void	outb(int, int);
void	outsb(int, void*, int);
void	outs(int, ushort);
void	outss(int, void*, int);
void	outl(int, ulong);
void	outsl(int, void*, int);
void	pcicreset(void);
int	pcmio(int, ISAConf*);
long	pcmread(int, int, void*, long, ulong);
int	pcmspecial(int);
void	pcmspecialclose(int);
long	pcmwrite(int, int, void*, long, ulong);
void	prhex(ulong);
void	procrestore(Proc*);
void	procsave(Proc*);
void	procsetup(Proc*);
void	ps2poll(void);
void	putgdt(Segdesc*, int);
void	putidt(Segdesc*, int);
void	putcr3(ulong);


@@ 73,7 86,7 @@ void	uartclock(void);
void	uartintr0(Ureg*);
void	uartspecial(int, IOQ*, IOQ*, int);
void	vgainit(void);
#define	waserror()	(u->nerrlab++, setlabel(&u->errlab[u->nerrlab-1]))
#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
#define	kmapperm(x)	kmap(x)
#define getcallerpc(x)	(*(ulong*)(x))
#define KADDR(a)	((void*)((ulong)(a)|KZERO))

M pc/kbd.c => pc/kbd.c +81 -1
@@ 25,6 25,17 @@ enum {

	Cmd=		0x64,	/* command port (write only) */

	CTdata=		0x0,	/* chips & Technologies ps2 data port */
	CTstatus=	0x1,	/* chips & Technologies ps2 status port */
	 Enable=	1<<7,
	 Clear=		1<<6,
	 Error=		1<<5,
	 Intenable=	1<<4,
	 Reset=		1<<3,
	 Tready=	1<<2,
	 Rready=	1<<1,
	 Idle=		1<<0,

	Spec=	0x80,

	PF=	Spec|0x20,	/* num pad function key */


@@ 112,6 123,7 @@ KIOQ	kbdq;
static int keybuttons;
static uchar ccc;
static int shift;
ulong ctport;

enum
{


@@ 125,6 137,7 @@ enum
};

static void	kbdintr(Ureg*);
static void	ctps2intr(Ureg*);
static int	ps2mouseputc(IOQ*, int);

/*


@@ 171,7 184,7 @@ mousecmd(int cmd)
	c = 0;
	tries = 0;
	do{
		if(tries++ > 5)
		if(tries++ > 2)
			break;
		if(outready() < 0)
			break;


@@ 227,6 240,7 @@ i8042reset(void)
	outready();
}


void
kbdinit(void)
{


@@ 279,6 293,54 @@ serialmouse(int port, char *type, int setspeed)
	mousetype = Mouseserial;
}

static void nop(void){};

/*
 *  look for a chips & technologies 82c710 ps2 mouse on a TI travelmate
 */
static int
ct82c710(void)
{
	int c;

	/* on non-C&T 2fa and 3fa are input only ports */
	/* get chips attention */
	outb(0x2fa, 0x55); nop(); nop();
	outb(0x3fa, ~0x55); nop(); nop();
	outb(0x3fa, 0x36); nop(); nop();

	/* tell it where its config register should be */
	outb(0x3fa, 0x390>>2); nop(); nop();
	outb(0x2fa, ~(0x390>>2)); nop(); nop();

	/* see if this is really a 710 */
	outb(0x390, 0xf); nop(); nop();
	if(inb(0x391) != (0x390>>2))
		return -1;

	/* get data port address */
	outb(0x390, 0xd); nop(); nop();
	c = inb(0x391);
	if(c == 0 || c == 0xff)
		return -1;
	ctport = c<<2;

	/* turn off config mode */
	outb(0x390, 0xf); nop(); nop();
	outb(0x391, 0xf);

	setvec(Mousevec, ctps2intr);

	/* enable for interrupts */
	c = inb(ctport + CTstatus);
	c &= ~(Clear|Reset);
	c |= Enable|Intenable;
	outb(ctport + CTstatus, c);

	mousetype = MousePS2;
	return 0;
}

/*
 *  set up a ps2 mouse
 */


@@ 290,6 352,9 @@ ps2mouse(void)
	if(mousetype)
		error(Emouseset);

	if(ct82c710() == 0)
		return;

	/* enable kbd/mouse xfers and interrupts */
	setvec(Mousevec, kbdintr);
	x = splhi();


@@ 563,3 628,18 @@ kbdintr(Ureg *ur)
	USED(ur);
	kbdintr0();
}

void
ctps2intr(Ureg *ur)
{
	uchar c;

	USED(ur);
	c = inb(ctport + CTstatus);
	if(c & Error)
		return;
	if((c & Rready) == 0)
		return;
	c = inb(ctport + CTdata);
	ps2mouseputc(&mouseq, c);
}

M pc/l.s => pc/l.s +67 -91
@@ 1,89 1,16 @@
#include "mem.h"

#define OP16	BYTE	$0x66
#define NOP	XCHGL	AX,AX

/*
 *	about to walk all over ms/dos - turn off interrupts
 *	We assume that b.com got us into 32 bit mode already.  We are now
 *	running with a PC == origin & ~KZERO.
 */
TEXT	origin(SB),$0

	CLI

#ifdef BOOT
/*
 *	This part of l.s is used only in the boot kernel.
 *	It assumes that we are in real address mode, i.e.,
 *	that we look like an 8086.
 */
/*
 *	relocate everything to a half meg and jump there
 *	- looks wierd because it is being assembled by a 32 bit
 *	  assembler for a 16 bit world
 */
	MOVL	$0,BX
	INCL	BX
	SHLL	$15,BX
	MOVL	BX,CX
	MOVW	BX,ES
	MOVL	$0,SI
	MOVL	SI,DI
	CLD; REP; MOVSL
/*	JMPFAR	0X8000:$lowcore(SB) /**/
	 BYTE	$0xEA
	 WORD	$lowcore(SB)
	 WORD	$0X8000

TEXT	lowcore(SB),$0

/*
 *	now that we're in low core, update the DS
 */

	MOVW	BX,DS

/*
 * 	goto protected mode
 */
/*	MOVL	tgdtptr(SB),GDTR /**/
	 BYTE	$0x0f
	 BYTE	$0x01
	 BYTE	$0x16
	 WORD	$tgdtptr(SB)
	MOVL	CR0,AX
	ORL	$1,AX
	MOVL	AX,CR0

/*
 *	clear prefetch queue (weird code to avoid optimizations)
 */
	CLC
	JCC	flush
	MOVL	AX,AX
flush:

/*
 *	set all segs
 */
/*	MOVW	$SELECTOR(1, SELGDT, 0),AX	/**/
	 BYTE	$0xc7
	 BYTE	$0xc0
	 WORD	$SELECTOR(1, SELGDT, 0)
	MOVW	AX,DS
	MOVW	AX,SS
	MOVW	AX,ES
	MOVW	AX,FS
	MOVW	AX,GS

/*	JMPFAR	SELECTOR(2, SELGDT, 0):$mode32bit(SB) /**/
	 BYTE	$0x66
	 BYTE	$0xEA
	 LONG	$mode32bit-KZERO(SB)
	 WORD	$SELECTOR(2, SELGDT, 0)

TEXT	mode32bit(SB),$0

#endif BOOT

	/*
	 * Clear BSS
	 */


@@ 104,8 31,8 @@ TEXT	mode32bit(SB),$0
	LEAL	tpt-KZERO(SB),AX	/* get phys addr of temporary page table */
	ADDL	$(BY2PG-1),AX		/* must be page alligned */
	ANDL	$(~(BY2PG-1)),AX	/* ... */
	MOVL	$(4*1024),CX		/* pte's per page */
	MOVL	$((((4*1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
	MOVL	$(1024),CX		/* pte's per page */
	MOVL	$((((1024)-1)<<PGSHIFT)|PTEVALID|PTEKERNEL|PTEWRITE),BX
setpte:
	MOVL	BX,-4(AX)(CX*4)
	SUBL	$(1<<PGSHIFT),BX


@@ 116,19 43,10 @@ setpte:
	 *  16 meg of memory to 0 thru 16meg and to KZERO thru KZERO+16meg
	 */
	MOVL	AX,BX
	ADDL	$(4*BY2PG),AX
	ADDL	$(BY2PG),AX
	ADDL	$(PTEVALID|PTEKERNEL|PTEWRITE),BX
	MOVL	BX,0(AX)
	MOVL	BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+0)(AX)
	ADDL	$BY2PG,BX
	MOVL	BX,4(AX)
	MOVL	BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+4)(AX)
	ADDL	$BY2PG,BX
	MOVL	BX,8(AX)
	MOVL	BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+8)(AX)
	ADDL	$BY2PG,BX
	MOVL	BX,12(AX)
	MOVL	BX,((((KZERO>>1)&0x7FFFFFFF)>>(2*PGSHIFT-1-4))+12)(AX)

	/*
	 *  point processor to top level page & turn on paging


@@ 155,7 73,7 @@ TEXT	tokzero(SB),$0
	MOVL	SP,m(SB)
	MOVL	$0,0(SP)
	ADDL	$(MACHSIZE-4),SP	/* start stack under machine struct */
	MOVL	$0, u(SB)
	MOVL	$0, up(SB)

	/*
	 *  clear flags


@@ 172,7 90,7 @@ loop:
GLOBL	mach0+0(SB), $MACHSIZE
GLOBL	u(SB), $4
GLOBL	m(SB), $4
GLOBL	tpt(SB), $(BY2PG*6)
GLOBL	tpt(SB), $(BY2PG*3)

/*
 *  gdt to get us to 32-bit/segmented/unpaged mode


@@ 251,7 169,6 @@ TEXT	ins(SB), $0
	OP16; INL
	RET


/*
 *  input a string of shorts from a port
 */


@@ 264,6 181,16 @@ TEXT	inss(SB),$0
	RET

/*
 * input a long from a port
 */
TEXT	inl(SB), $0

	MOVL	p+0(FP), DX
	XORL	AX, AX
	INL
	RET

/*
 *  input a string of longs from a port
 */
TEXT	insl(SB),$0


@@ 295,6 222,15 @@ TEXT	outss(SB),$0
	RET

/*
 * output a long to a port
 */
TEXT	outl(SB), $0
	MOVL	p+0(FP), DX
	MOVL	s+4(FP), AX
	OUTL
	RET

/*
 *  output a string of longs to a port
 */
TEXT	outsl(SB),$0


@@ 553,10 489,12 @@ intrcommon:
	CALL	trap(SB)
	POPL	AX
	POPAL
	NOP
	POPL	GS
	POPL	FS
	POPL	ES
	POPL	DS
	NOP
	ADDL	$8,SP	/* error code and trap type */
	IRETL



@@ 574,10 512,12 @@ intrscommon:
	CALL	trap(SB)
	POPL	AX
	POPAL
	NOP
	POPL	GS
	POPL	FS
	POPL	ES
	POPL	DS
	NOP
	ADDL	$8,SP	/* error code and trap type */
	IRETL



@@ 794,3 734,39 @@ TEXT dp8390outb(SB), $0

_dp8390outb0:
	RET

/*
 * dsp outb string called from devdsp.c
 */
	TEXT	dspoutb+0(SB), $0

	MOVL	a+4(FP), BX
	MOVL	n+8(FP), CX

	MOVL	base+0(FP), DX
	ADDL	$2, DX			/* Pcontrol */

	MOVL	c2+12(FP), DI
	MOVL	c3+16(FP), SI

dsploop:
	MOVL	DI, AX			/* normal */
	OUTB

	SUBL	$1, CX
	CMPL	CX, $0
	JLT	dspout

	SUBL	$2, DX			/* Pdata */
	MOVB	(BX), AX
	ADDL	$1, BX
	OUTB

	ADDL	$2, DX			/* Pcontrol */
	MOVL	SI, AX			/* strobe */
	OUTB

	JMP	dsploop

dspout:
	RET

M pc/main.c => pc/main.c +208 -75
@@ 26,10 26,15 @@ PCArch *knownarch[] =
#define	BOOTARGSLEN	1024
#define	MAXCONF		32

char bootdisk[NAMELEN];
char *confname[MAXCONF];
char *confval[MAXCONF];
int nconf;

/* memory map */
#define MAXMEG 64
char mmap[MAXMEG+2];

void
main(void)
{


@@ 40,6 45,7 @@ main(void)
	active.machs = 1;
	confinit();
	xinit();
	dmainit();
	screeninit();
	printinit();
	mmuinit();


@@ 51,8 57,8 @@ main(void)
	kbdinit();
	procinit0();
	initseg();
	links();
	chandevreset();
	streaminit();
	swapinit();
	userinit();
	schedinit();


@@ 94,10 100,10 @@ init0(void)
	int i;
	char tstr[32];

	u->nerrlab = 0;
	m->proc = u->p;
	u->p->state = Running;
	u->p->mach = m;
	up->nerrlab = 0;
	m->proc = up->p;
	up->state = Running;
	up->mach = m;

	spllo();



@@ 105,21 111,23 @@ init0(void)
	 * These are o.k. because rootinit is null.
	 * Then early kproc's will have a root and dot.
	 */
	u->slash = (*devtab[0].attach)(0);
	u->dot = clone(u->slash, 0);
	up->slash = namec("#/", Atodir, 0, 0);
	up->dot = clone(up->slash, 0);

	kproc("alarm", alarmkproc, 0);
	iallocinit();
	chandevinit();

	if(!waserror()){
		for(i = 0; i < nconf; i++)
			ksetenv(confname[i], confval[i]);
		strcpy(tstr, arch->id);
		strcat(tstr, " %s");
		ksetterm(tstr);
		ksetenv("cputype", "386");
		for(i = 0; i < nconf; i++)
			if(confname[i])
				ksetenv(confname[i], confval[i]);
		poperror();
	}
	kproc("alarm", alarmkproc, 0);
	touser(sp);
}



@@ 152,21 160,12 @@ userinit(void)
	 *	4 bytes for gotolabel's return PC
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = USERADDR + BY2PG - 4;
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));

	/*
	 * User
	 */
	k = kmap(p->upage);
	up = (User*)VA(k);
	up->p = p;
	kunmap(k);
	p->sched.sp = (ulong)p->kstack+KSTACK-(1+MAXSYSARG)*BY2WD;

	/*
	 * User Stack
	 */
	s = newseg(SG_STACK, USTKTOP-BY2PG, 1);
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);


@@ 178,8 177,11 @@ userinit(void)
	 * Text
	 */
	s = newseg(SG_TEXT, UTZERO, 1);
	s->flushme++;
	p->seg[TSEG] = s;
	segpage(s, newpage(1, 0, UTZERO));
	pg = newpage(1, 0, UTZERO);
	memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
	segpage(s, pg);
	k = kmap(s->map[0]->pages[0]);
	memmove((ulong*)VA(k), initcode, sizeof initcode);
	kunmap(k);


@@ 213,13 215,30 @@ bootargs(ulong base)
	av[ac++] = pusharg("/386/9safari");
	av[ac++] = pusharg("-p");
	cp[64] = 0;
	buf[0] = 0;
	if(strncmp(cp, "fd!", 3) == 0){
		sprint(buf, "local!#f/fd%ddisk", atoi(cp+3));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "h!", 2) == 0){
		sprint(buf, "local!#H/hd%dfs", atoi(cp+2));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "hd!", 3) == 0){
		sprint(buf, "local!#h/hd%ddisk", atoi(cp+3));
		sprint(buf, "local!#H/hd%ddisk", atoi(cp+3));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "s!", 2) == 0){
		sprint(buf, "local!#w/sd%dfs", atoi(cp+2));
		av[ac++] = pusharg(buf);
	} else if(strncmp(cp, "sd!", 3) == 0){
		sprint(buf, "local!#w/sd%ddisk", atoi(cp+3));
		av[ac++] = pusharg(buf);
	}
	if(buf[0]){
		cp = strchr(buf, '!');
		if(cp){
			strcpy(bootdisk, cp+1);
			addconf("bootdisk", bootdisk);
		}
	}

	/* 4 byte word align stack */
	sp = (uchar*)((ulong)sp & ~3);


@@ 236,9 255,30 @@ bootargs(ulong base)
Conf	conf;

void
addconf(char *name, char *val)
{
	if(nconf >= MAXCONF)
		return;
	confname[nconf] = name;
	confval[nconf] = val;
	nconf++;
}

char*
getconf(char *name)
{
	int i;

	for(i = 0; i < nconf; i++)
		if(strcmp(confname[i], name) == 0)
			return confval[i];
	return 0;
}

void
confinit(void)
{
	long x, i, j, n, *l;
	long x, i, j, n;
	int pcnt;
	ulong ktop;
	char *cp;


@@ 249,7 289,7 @@ confinit(void)
	/*
	 *  parse configuration args from dos file p9rc
	 */
	cp = BOOTARGS;	/* where b.com leaves it's config */
	cp = BOOTARGS;	/* where b.com leaves its config */
	cp[BOOTARGSLEN-1] = 0;
	n = getfields(cp, line, MAXCONF, '\n');
	for(j = 0; j < n; j++){


@@ 268,60 308,83 @@ confinit(void)
			pcnt = 100 - atoi(confval[nconf]);
		nconf++;
	}

	/*
	 *  the first 640k is the standard useful memory
	 *  the next 128K is the display, I/O mem, and BIOS
	 *  the last 256k belongs to the roms and other devices
	 */
	conf.npage0 = 640/4;
	conf.base0 = 0;

	/*
	 *  size the non-standard memory
	 *  size memory above 1 meg. Kernel sits at 1 meg.  We
	 *  only recognize MB size chunks.
	 */
	memset(mmap, ' ', sizeof(mmap));
	x = 0x12345678;
	for(i=2; i<17; i++){
	for(i = 1; i <= MAXMEG; i++){
		/*
		 *  write the word
		 *  write the first & last word in a megabyte of memory
		 */
		l = (long*)(KZERO|(i*MB));
		l--;
		*l = x;
		*mapaddr(KZERO|(i*MB)) = x;
		*mapaddr(KZERO|((i+1)*MB-BY2WD)) = x;

		/*
		 *  take care of wraps
		 *  write the first and last word in all previous megs to
		 *  handle address wrap around
		 */
		for(j = 1; j < i; j++){
			l = (long*)(KZERO|(j*MB));
			l--;
			*l = ~x;
			*mapaddr(KZERO|(j*MB)) = ~x;
			*mapaddr(KZERO|((j+1)*MB-BY2WD)) = ~x;
		}

		/*
		 *  check
		 *  check for correct value
		 */
		l = (long*)(KZERO|(i*MB));
		l--;
		if(*l != x)
			break;
		memset((char*)(KZERO|((i-1)*MB)), 0, MB);
		if(*mapaddr(KZERO|(i*MB)) == x && *mapaddr(KZERO|((i+1)*MB-BY2WD)) == x){
			mmap[i] = 'x';
			/*
			 *  zero memory to set ECC but skip over the kernel
			 */
			if(i != 1)
				for(j = 0; j < MB/BY2PG; j += BY2PG)
					memset(mapaddr(KZERO|(i*MB+j)), 0, BY2PG);
		}
		x += 0x3141526;
	}
	i--;
	conf.base1 = 1*MB;
	conf.npage1 = (i*MB - conf.base1)/BY2PG;
	/*
	 *  bank0 usually goes from the end of kernel bss to the end of memory
	 */
	ktop = PGROUND((ulong)end);
	ktop = PADDR(ktop);
	conf.base0 = ktop;
	for(i = 1; mmap[i] == 'x'; i++)
		;
	conf.npage0 = (i*MB - ktop)/BY2PG;
	conf.topofmem = i*MB;

	/*
	 *  bank1 usually goes from the end of BOOTARGS to 640k
	 */
	conf.base1 = (ulong)(BOOTARGS+BOOTARGSLEN);
	conf.base1 = PGROUND(conf.base1);
	conf.base1 = PADDR(conf.base1);
	conf.npage1 = (640*1024-conf.base1)/BY2PG;

	/*
	 *  if there is a hole in memory (due to a shadow BIOS) make the
	 *  memory after the hole be bank 1. The memory from 0 to 640k
	 *  is lost.
	 */
	for(; i <= MAXMEG; i++)
		if(mmap[i] == 'x'){
			conf.base1 = i*MB;
			for(j = i+1; mmap[j] == 'x'; j++)
				;
			conf.npage1 = (j - i)*MB/BY2PG;
			conf.topofmem = j*MB;
			break;
		}

	conf.npage = conf.npage0 + conf.npage1;
	conf.ldepth = 0;
	if(pcnt < 10)
		pcnt = 70;
	conf.upages = (conf.npage*pcnt)/100;

	ktop = PGROUND((ulong)end);
	ktop = PADDR(ktop);
	conf.npage0 -= ktop/BY2PG;
	conf.base0 += ktop;

	conf.topofmem = i*MB;
	conf.nproc = 30 + i*5;
	conf.nproc = 30 + ((conf.npage*BY2PG)/MB)*5;
	conf.monitor = 1;
	conf.nswap = conf.nproc*80;
	conf.nimage = 50;


@@ 363,24 426,24 @@ matherror(Ureg *ur)
	/*
	 *  save floating point state to check out error
	 */
	fpenv(&u->fpsave);
	status = u->fpsave.status;
	fpenv(&up->fpsave);
	status = up->fpsave.status;

	msg = 0;
	for(i = 0; i < 8; i++)
		if((1<<i) & status){
			msg = mathmsg[i];
			sprint(note, "sys: fp: %s fppc=0x%lux", msg, u->fpsave.pc);
			postnote(u->p, 1, note, NDebug);
			sprint(note, "sys: fp: %s fppc=0x%lux", msg, up->fpsave.pc);
			postnote(up->p, 1, note, NDebug);
			break;
		}
	if(msg == 0){
		sprint(note, "sys: fp: unknown fppc=0x%lux", u->fpsave.pc);
		postnote(u->p, 1, note, NDebug);
		sprint(note, "sys: fp: unknown fppc=0x%lux", up->fpsave.pc);
		postnote(up->p, 1, note, NDebug);
	}
	if(ur->pc & KZERO)
		panic("fp: status %lux fppc=0x%lux pc=0x%lux", status,
			u->fpsave.pc, ur->pc);
			up->fpsave.pc, ur->pc);
}

/*


@@ 390,14 453,14 @@ void
mathemu(Ureg *ur)
{
	USED(ur);
	switch(u->p->fpstate){
	switch(up->fpstate){
	case FPinit:
		fpinit();
		u->p->fpstate = FPactive;
		up->fpstate = FPactive;
		break;
	case FPinactive:
		fprestore(&u->fpsave);
		u->p->fpstate = FPactive;
		fprestore(&up->fpsave);
		up->fpstate = FPactive;
		break;
	case FPactive:
		panic("math emu", 0);


@@ 412,7 475,7 @@ void
mathover(Ureg *ur)
{
	USED(ur);
print("sys: fp: math overrun pc 0x%lux pid %d\n", ur->pc, u->p->pid);
print("sys: fp: math overrun pc 0x%lux pid %d\n", ur->pc, up->pid);
	pexit("math overrun", 0);
}



@@ 445,7 508,7 @@ procsave(Proc *p)
		if(p->state == Moribund)
			fpoff();
		else
			fpsave(&u->fpsave);
			fpsave(&up->fpsave);
		p->fpstate = FPinactive;
	}
}


@@ 473,8 536,12 @@ exit(int ispanic)
{
	u = 0;
	print("exiting\n");
	if(ispanic)
		for(;;);
	if(ispanic){
		if(cpuflag)
			delay(10000);
		else
			for(;;);
	}

	(*arch->reset)();
}


@@ 541,3 608,69 @@ modem(int onoff)
	else
		return 0;
}

static int
parseether(uchar *to, char *from)
{
	char nip[4];
	char *p;
	int i;

	p = from;
	for(i = 0; i < 6; i++){
		if(*p == 0)
			return -1;
		nip[0] = *p++;
		if(*p == 0)
			return -1;
		nip[1] = *p++;
		nip[2] = 0;
		to[i] = strtoul(nip, 0, 16);
		if(*p == ':')
			p++;
	}
	return 0;
}

int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
	char cc[NAMELEN], *p, *q;
	int n;

	sprint(cc, "%s%d", class, ctlrno);
	for(n = 0; n < nconf; n++){
		if(strncmp(confname[n], cc, NAMELEN))
			continue;
		p = confval[n];
		while(*p){
			while(*p == ' ' || *p == '\t')
				p++;
			if(*p == '\0')
				break;
			if(strncmp(p, "type=", 5) == 0){
				p += 5;
				for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){
					if(*p == '\0' || *p == ' ' || *p == '\t')
						break;
					*q = *p++;
				}
				*q = '\0';
			}
			else if(strncmp(p, "port=", 5) == 0)
				isa->port = strtoul(p+5, &p, 0);
			else if(strncmp(p, "irq=", 4) == 0)
				isa->irq = strtoul(p+4, &p, 0);
			else if(strncmp(p, "mem=", 4) == 0)
				isa->mem = strtoul(p+4, &p, 0);
			else if(strncmp(p, "size=", 5) == 0)
				isa->size = strtoul(p+5, &p, 0);
			else if(strncmp(p, "ea=", 3) == 0)
				parseether(isa->ea, p+3);
			while(*p && *p != ' ' && *p != '\t')
				p++;
		}
		return 1;
	}
	return 0;
}

M pc/mem.h => pc/mem.h +2 -3
@@ 42,12 42,11 @@
#define	UTZERO		(UZERO+BY2PG)		/* first address in user text */
#define	KZERO		0x80000000		/* base of kernel address space */
#define	KTZERO		KZERO			/* first address in kernel text */
#define	USERADDR	0xC0000000		/* struct User */
#define	UREGADDR	(USERADDR+BY2PG-4*19)	
#define	TSTKTOP		USERADDR		/* end of new stack in sysexec */
#define	TSTKTOP		0xC0000000		/* end of new stack in sysexec */
#define TSTKSIZ 10
#define	USTKTOP		(TSTKTOP-TSTKSIZ*BY2PG)	/* byte just beyond user stack */
#define	USTKSIZE	(16*1024*1024 - TSTKSIZ*BY2PG)	/* size of user stack */
#define KSTACK		4096			/* Size of kernel stack */
#define ROMBIOS		(KZERO|0xF0000)
#define	ISAMEMSIZE	(4*MB)			/* mem space reserved for ISA */


M pc/mmu.c => pc/mmu.c +63 -56
@@ 71,7 71,6 @@ Segdesc gdt[] =
static Page	ktoppg;		/* prototype top level page table
				 * containing kernel mappings  */
static ulong	*kpt;		/* 2nd level page tables for kernel mem */
static ulong	*upt;		/* 2nd level page table for struct User */

#define ROUNDUP(s,v)	(((s)+(v-1))&~(v-1))
/*


@@ 97,6 96,21 @@ struct
} isamemalloc;

/*
 *  Change current page table and the stack to use for exceptions
 *  (traps & interrupts).  The exception stack comes from the tss.
 *  Since we use only one tss, (we hope) there's no need for a
 *  puttr().
 */
static void
taskswitch(ulong pagetbl, ulong stack)
{
	putcr3(pagetbl);
	tss.ss0 = KDSEL;
	tss.sp0 = stack;
	tss.cr3 = pagetbl;
}

/*
 *  Create a prototype page map that maps all of memory into
 *  kernel (KZERO) space.  This is the default map.  It is used
 *  whenever the processor not running a process or whenever running


@@ 147,21 161,11 @@ mmuinit(void)
	for(i = 0; i < nkpt; i++)
		top[x+i] = (y+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE;

	/*  page table for u-> */
	upt = xspanalloc(BY2PG, BY2PG, 0);
	x = TOPOFF(USERADDR);
	y = ((ulong)upt)&~KZERO;
	top[x] = y | PTEVALID | PTEKERNEL | PTEWRITE;

	putcr3(ktoppg.pa);

	/*
	 *  set up the task segment
	 */
	memset(&tss, 0, sizeof(tss));
	tss.sp0 = USERADDR+BY2PG;
	tss.ss0 = KDSEL;
	tss.cr3 = ktoppg.pa;
	taskswitch(ktoppg.pa, BY2BG + (ulong)m);
	puttr(TSSSEL);
}



@@ 174,28 178,22 @@ flushmmu(void)
	int s;

	s = splhi();
	if(u){
		u->p->newtlb = 1;
		mapstack(u->p);
	} else
		putcr3(ktoppg.pa);
	up->newtlb = 1;
	mmuswitch(up);
	splx(s);
}

/*
 *  Switch to a process's memory map.  If the process doesn't
 *  have a map yet, just use the prototype one that contains
 *  mappings for only the kernel and the User struct.
 *  mappings for only the kernel.
 */
void
mapstack(Proc *p)
mmuswitch(Proc *p)
{
	Page *pg;
	ulong *top;

	if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0)
		panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va);

	if(p->newtlb){
		/*
		 *  newtlb set means that they are inconsistent


@@ 218,17 216,11 @@ mapstack(Proc *p)
		p->newtlb = 0;
	}

	/* map in u area */
	upt[0] = PPN(p->upage->pa) | PTEVALID | PTEKERNEL | PTEWRITE;

	/* tell processor about new page table (flushes cached entries) */
	if(p->mmutop)
		pg = p->mmutop;
		taskswitch(p->mmutop->pa, p->kstack+KSTACK);
	else
		pg = &ktoppg;
	putcr3(pg->pa);

	u = (User*)USERADDR;
		taskswitch(ktoppg.pa, p->kstack+KSTACK);
}

/*


@@ 241,8 233,8 @@ mmurelease(Proc *p)
	Page *pg;
	Page *next;

	/* point 386 to protoype page map */
	putcr3(ktoppg.pa);
	/* point 386 to protoype page map and m->stack */
	taskswitch(ktoppg.pa, BY2PG + (ulong)m);

	/* give away page table pages */
	for(pg = p->mmufree; pg; pg = next){


@@ 269,24 261,19 @@ putmmu(ulong va, ulong pa, Page *pg)
	int topoff;
	ulong *top;
	ulong *pt;
	Proc *p;
	int s;

	if(u==0)
		panic("putmmu");
	p = u->p;

	/*
	 *  create a top level page if we don't already have one.
	 *  copy the kernel top level page into it for kernel mappings.
	 */
	if(p->mmutop == 0){
	if(up->mmutop == 0){
		pg = newpage(0, 0, 0);
		pg->va = VA(kmap(pg));
		memmove((void*)pg->va, (void*)ktoppg.va, BY2PG);
		p->mmutop = pg;
		up->mmutop = pg;
	}
	top = (ulong*)p->mmutop->va;
	top = (ulong*)up->mmutoup->va;
	topoff = TOPOFF(va);

	/*


@@ 295,20 282,20 @@ putmmu(ulong va, ulong pa, Page *pg)
	 */
	s = splhi();
	if(PPN(top[topoff]) == 0){
		if(p->mmufree == 0){
		if(up->mmufree == 0){
			spllo();
			pg = newpage(1, 0, 0);
			pg->va = VA(kmap(pg));
			splhi();
		} else {
			pg = p->mmufree;
			p->mmufree = pg->next;
			pg = up->mmufree;
			up->mmufree = pg->next;
			memset((void*)pg->va, 0, BY2PG);
		}
		top[topoff] = PPN(pg->pa) | PTEVALID | PTEUSER | PTEWRITE;
		pg->daddr = topoff;
		pg->next = p->mmuused;
		p->mmuused = pg;
		pg->next = up->mmuused;
		up->mmuused = pg;
	}

	/*


@@ 318,20 305,10 @@ putmmu(ulong va, ulong pa, Page *pg)
	pt[BTMOFF(va)] = pa | PTEUSER;

	/* flush cached mmu entries */
	putcr3(p->mmutop->pa);
	taskswitch(up->mmutoup->pa, up->kstack);
	splx(s);
}

void
invalidateu(void)
{
	/* unmap u area */
	upt[0] = 0;

	/* flush cached mmu entries */
	putcr3(ktoppg.pa);
}

/*
 *  allocate some address space (already mapped into the kernel)
 *  for ISA bus memory.


@@ 351,3 328,33 @@ isamem(int len)
	unlock(&isamemalloc);
	return a;
}

/*
 *  used to map a page into 16 meg - BY2PG for confinit(). tpt is the temporary
 *  page table set up by l.s.
 */
long*
mapaddr(ulong addr)
{
	ulong base;
	ulong off;
	static ulong *pte, top;
	extern ulong tpt[];

	if(pte == 0){
		top = (((ulong)tpt)+(BY2PG-1))&~(BY2PG-1);
		pte = (ulong*)top;
		top &= ~KZERO;
		top += BY2PG;
		pte += (4*1024*1024-BY2PG)>>PGSHIFT;
	}

	base = off = addr;
	base &= ~(KZERO|(BY2PG-1));
	off &= BY2PG-1;

	*pte = base|PTEVALID|PTEKERNEL|PTEWRITE; /**/
	putcr3((ulong)top);

	return (long*)(KZERO | 4*1024*1024-BY2PG | off);
}

A pc/scsi.c => pc/scsi.c +84 -0
@@ 0,0 1,84 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

/*
 * Known to devscsi.c.
int scsidebugs[8];
int scsiownid = CtlrID;
 */

void
initscsi(void)
{
}

/*
 * Quick hack. Need to do a better job of dynamic initialisation
 * for machines with peculiar memory/cache restictions.
 * Also, what about 16Mb address limit on the Adaptec?
 */
static ulong bufdatasize;

void
scsibufreset(ulong datasize)
{
	bufdatasize = datasize;
}

Scsibuf *
scsibuf(void)
{
	Scsibuf *b;

	b = smalloc(sizeof(*b));
	b->virt = smalloc(bufdatasize);
	b->phys = (void *)(PADDR(b->virt));
	return b;
}

void
scsifree(Scsibuf *b)
{
	free(b->virt);
	free(b);
}

/*
 * Hack for devvid
 */
Scsibuf *
scsialloc(ulong n)
{
	Scsibuf *b;

	b = smalloc(sizeof(*b));
	b->virt = smalloc(n);
	b->phys = (void *)(PADDR(b->virt));
	return b;
}

extern int (*aha1542reset(void))(Scsi*, int);
extern int (*ultra14freset(void))(Scsi*, int);

static int (*exec)(Scsi*, int);

int
scsiexec(Scsi *p, int rflag)
{
	if(exec == 0)
		error(Enonexist);
	return (*exec)(p, rflag);
}

void
resetscsi(void)
{
	if(exec = aha1542reset())
		return;
	exec = ultra14freset();
}

M pc/trap.c => pc/trap.c +91 -73
@@ 98,12 98,12 @@ debugbpt(Ureg *ur)
{
	char buf[ERRLEN];

	if(u == 0)
	if(up == 0)
		panic("kernel bpt");
	/* restore pc to instruction that caused the trap */
	ur->pc--;
	sprint(buf, "sys: breakpoint");
	postnote(u->p, 1, buf, NDebug);
	postnote(up->p, 1, buf, NDebug);
}

/*


@@ 218,6 218,9 @@ char *excname[] =
[13]	"general protection violation",
};

Ureg lasttrap, *lastur;


/*
 *  All traps
 */


@@ 233,7 236,7 @@ trap(Ureg *ur)

	user = ((ur->cs)&0xffff)!=KESEL && v!=Syscallvec;
	if(user)
		u->dbgreg = ur;
		up->dbgreg = ur;

	/*
	 *  tell the 8259 that we're done with the


@@ 248,6 251,8 @@ trap(Ureg *ur)
	}

	if(v>=256 || (h = halloc.ivec[v]) == 0){
lasttrap = *ur;
lastur = ur;
		/* an old 386 generates these fairly often, no idea why */
		if(v == 13)
			return;


@@ 256,7 261,7 @@ trap(Ureg *ur)
		if(v <= 16){
			if(user){
				sprint(buf, "sys: trap: %s", excname[v]);
				postnote(u->p, 1, buf, NDebug);
				postnote(up->p, 1, buf, NDebug);
				return;
			} else {
				dumpregs(ur);


@@ 267,7 272,7 @@ trap(Ureg *ur)
		if(v >= Int0vec || v < Int0vec+16){
			/* an unknown interrupts */
			v -= Int0vec;
			if(badintr[v]++ == 0 || (badintr[v]%1000) == 0)
			if(badintr[v]++ == 0 || (badintr[v]%100000) == 0)
				print("unknown interrupt %d pc=0x%lux: total %d\n", v,
					ur->pc, badintr[v]);
		} else {


@@ 284,21 289,24 @@ trap(Ureg *ur)
	} while(h);

	/* check user since syscall does its own notifying */
	if(user && (u->p->procctl || u->nnote))
	splhi();
	if(user && (up->procctl || up->nnote))
		notify(ur);
lasttrap = *ur;
lastur = ur;
}

/*
 *  dump registers
 */
void
dumpregs(Ureg *ur)
dumpregs2(Ureg *ur)
{
	if(u)
		print("registers for %s %d\n", u->p->text, u->p->pid);
	if(up)
		print("registers for %s %d\n", up->text, up->pid);
	else
		print("registers for kernel\n");
	print("FLAGS=%lux ECODE=%lux CS=%lux PC=%lux", ur->flags,
	print("FLAGS=%lux TRAP=%lux ECODE=%lux CS=%lux PC=%lux", ur->flags, ur->trap,
		ur->ecode, ur->cs&0xff, ur->pc);
	if(ur == (Ureg*)UREGADDR)
		print(" SS=%lux USP=%lux\n", ur->ss&0xff, ur->usp);


@@ 310,6 318,16 @@ dumpregs(Ureg *ur)
		ur->si, ur->di, ur->bp);
	print("  DS %4.4ux  ES %4.4ux  FS %4.4ux  GS %4.4ux\n",
		ur->ds&0xffff, ur->es&0xffff, ur->fs&0xffff, ur->gs&0xffff);

}

void
dumpregs(Ureg *ur)
{
	dumpregs2(ur);
	print("  ur %lux\n", ur);
	dumpregs2(&lasttrap);
	print("  lastur %lux\n", lastur);
}

void


@@ 318,11 336,11 @@ dumpstack(void)
	ulong l, v, i;
	extern ulong etext;

	if(u == 0)
	if(up == 0)
		return;

	i = 0;
	for(l=(ulong)&l; l<USERADDR+BY2PG; l+=4){
	for(l=(ulong)&l; l<up->kstack+BY2PG; l+=4){
		v = *(ulong*)l;
		if(KTZERO < v && v < (ulong)&etext){
			print("%lux ", v);


@@ 369,52 387,52 @@ syscall(Ureg *ur)
	long	ret;
	int	i;

	u->p->insyscall = 1;
	u->p->pc = ur->pc;
	up->insyscall = 1;
	up->pc = ur->pc;
	if((ur->cs)&0xffff == KESEL)
		panic("recursive system call");

	u->scallnr = ur->ax;
	if(u->scallnr == RFORK && u->p->fpstate == FPactive){
	up->scallnr = ur->ax;
	if(up->scallnr == RFORK && up->fpstate == FPactive){
		/*
		 *  so that the child starts out with the
		 *  same registers as the parent
		 */
		splhi();
		if(u->p->fpstate == FPactive){
			fpsave(&u->fpsave);
			u->p->fpstate = FPinactive;
		if(up->fpstate == FPactive){
			fpsave(&up->fpsave);
			up->fpstate = FPinactive;
		}
		spllo();
	}
	sp = ur->usp;
	u->nerrlab = 0;
	up->nerrlab = 0;
	ret = -1;
	if(!waserror()){
		if(u->scallnr >= sizeof systab/BY2WD){
			pprint("bad sys call number %d pc %lux\n", u->scallnr, ur->pc);
			postnote(u->p, 1, "sys: bad sys call", NDebug);
		if(up->scallnr >= sizeof systab/BY2WD){
			pprint("bad sys call number %d pc %lux\n", up->scallnr, ur->pc);
			postnote(up->p, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD))
			validaddr(sp, (1+MAXSYSARG)*BY2WD, 0);

		u->s = *((Sargs*)(sp+1*BY2WD));
		u->p->psstate = sysctab[u->scallnr];
		up->s = *((Sargs*)(sp+1*BY2WD));
		up->psstate = sysctab[up->scallnr];

		ret = (*systab[u->scallnr])(u->s.args);
		ret = (*systab[up->scallnr])(up->s.args);
		poperror();
	}
	if(u->nerrlab){
		print("bad errstack [%d]: %d extra\n", u->scallnr, u->nerrlab);
	if(up->nerrlab){
		print("bad errstack [%d]: %d extra\n", up->scallnr, up->nerrlab);
		for(i = 0; i < NERR; i++)
			print("sp=%lux pc=%lux\n", u->errlab[i].sp, u->errlab[i].pc);
			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
		panic("error stack");
	}

	u->p->insyscall = 0;
	u->p->psstate = 0;
	up->insyscall = 0;
	up->psstate = 0;

	/*
	 *  Put return value in frame.  On the safari the syscall is


@@ 424,11 442,11 @@ syscall(Ureg *ur)
	 */
	ur->ax = ret;

	if(u->scallnr == NOTED)
	if(up->scallnr == NOTED)
		noted(ur, *(ulong*)(sp+BY2WD));

	splhi(); /* avoid interrupts during the iret */
	if(u->scallnr!=RFORK && (u->p->procctl || u->nnote))
	if(up->scallnr!=RFORK && (up->procctl || up->nnote))
		notify(ur);

	return ret;


@@ 445,61 463,61 @@ notify(Ureg *ur)
	ulong s, sp;
	Note *n;

	if(u->p->procctl)
		procctl(u->p);
	if(u->nnote == 0)
	if(up->procctl)
		procctl(up->p);
	if(up->nnote == 0)
		return 0;

	s = spllo();
	qlock(&u->p->debug);
	u->p->notepending = 0;
	n = &u->note[0];
	qlock(&up->debug);
	up->notepending = 0;
	n = &up->note[0];
	if(strncmp(n->msg, "sys:", 4) == 0){
		l = strlen(n->msg);
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */
			l = ERRLEN-15;
		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
	}
	if(n->flag!=NUser && (u->notified || u->notify==0)){
	if(n->flag!=NUser && (up->notified || up->notify==0)){
		qunlock(&up->debug);
		if(n->flag == NDebug)
			pprint("suicide: %s\n", n->msg);
		qunlock(&u->p->debug);
		pexit(n->msg, n->flag!=NDebug);
	}
	sent = 0;
	if(!u->notified){
		if(!u->notify){
			qunlock(&u->p->debug);
	if(!up->notified){
		if(!up->notify){
			qunlock(&up->debug);
			pexit(n->msg, n->flag!=NDebug);
		}
		sent = 1;
		u->svcs = ur->cs;
		u->svss = ur->ss;
		u->svflags = ur->flags;
		up->svcs = ur->cs;
		up->svss = ur->ss;
		up->svflags = ur->flags;
		sp = ur->usp;
		sp -= sizeof(Ureg);
		if(!okaddr((ulong)u->notify, 1, 0)
		if(!okaddr((ulong)up->notify, 1, 0)
		|| !okaddr(sp-ERRLEN-3*BY2WD, sizeof(Ureg)+ERRLEN-3*BY2WD, 0)){
			qunlock(&up->debug);
			pprint("suicide: bad address in notify\n");
			qunlock(&u->p->debug);
			pexit("Suicide", 0);
		}
		u->ureg = (void*)sp;
		up->ureg = (void*)sp;
		memmove((Ureg*)sp, ur, sizeof(Ureg));
		sp -= ERRLEN;
		memmove((char*)sp, u->note[0].msg, ERRLEN);
		memmove((char*)sp, up->note[0].msg, ERRLEN);
		sp -= 3*BY2WD;
		*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
		*(ulong*)(sp+1*BY2WD) = (ulong)u->ureg;	/* arg 1 is ureg* */
		*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */
		*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */
		ur->usp = sp;
		ur->pc = (ulong)u->notify;
		u->notified = 1;
		u->nnote--;
		memmove(&u->lastnote, &u->note[0], sizeof(Note));
		memmove(&u->note[0], &u->note[1], u->nnote*sizeof(Note));
		ur->pc = (ulong)up->notify;
		up->notified = 1;
		up->nnote--;
		memmove(&up->lastnote, &up->note[0], sizeof(Note));
		memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
	}
	qunlock(&u->p->debug);
	qunlock(&up->debug);
	splx(s);
	return sent;
}


@@ 512,43 530,43 @@ noted(Ureg *ur, ulong arg0)
{
	Ureg *nur;

	nur = u->ureg;		/* pointer to user returned Ureg struct */
	if(nur->cs!=u->svcs || nur->ss!=u->svss
	|| (nur->flags&0xff00)!=(u->svflags&0xff00)){
	nur = up->ureg;		/* pointer to user returned Ureg struct */
	if(nur->cs!=up->svcs || nur->ss!=up->svss
	|| (nur->flags&0xff00)!=(up->svflags&0xff00)){
		pprint("bad noted ureg cs %ux ss %ux flags %ux\n", nur->cs, nur->ss,
			nur->flags);
    Die:
		pexit("Suicide", 0);
	}
	qlock(&u->p->debug);
	if(!u->notified){
	qlock(&up->debug);
	if(!up->notified){
		pprint("call to noted() when not notified\n");
		qunlock(&u->p->debug);
		qunlock(&up->debug);
		return;
	}
	u->notified = 0;
	nur->flags = (u->svflags&0xffffff00) | (nur->flags&0xff);
	up->notified = 0;
	nur->flags = (up->svflags&0xffffff00) | (nur->flags&0xff);
	memmove(ur, nur, sizeof(Ureg));
	switch(arg0){
	case NCONT:
		if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){
			pprint("suicide: trap in noted\n");
			qunlock(&u->p->debug);
			qunlock(&up->debug);
			goto Die;
		}
		qunlock(&u->p->debug);
		qunlock(&up->debug);
		return;

	default:
		pprint("unknown noted arg 0x%lux\n", arg0);
		u->lastnote.flag = NDebug;
		up->lastnote.flag = NDebug;
		/* fall through */
		
	case NDFLT:
		if(u->lastnote.flag == NDebug)
			pprint("suicide: %s\n", u->lastnote.msg);
		qunlock(&u->p->debug);
		pexit(u->lastnote.msg, u->lastnote.flag!=NDebug);
		if(up->lastnote.flag == NDebug)
			pprint("suicide: %s\n", up->lastnote.msg);
		qunlock(&up->debug);
		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
	}
}


A pc/ultrastor.c => pc/ultrastor.c +484 -0
@@ 0,0 1,484 @@
/*
 * Ultrastor [13]4f SCSI Host Adapter.
 * Originally written by Charles Forsyth, forsyth@minster.york.ac.uk.
 * Needs work:
 *	handle multiple controllers;
 *	set options from user-level;
 *	split out to handle adaptec too;
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

#include "ureg.h"

typedef struct Ctlr Ctlr;
typedef struct Mailbox Mailbox;
typedef struct Scatter Scatter;

enum {
	Nctl		= 1,		/* only support one */
	Nmbox		= 8,		/* number of Mailboxes; up to 16? */
	Nscatter 	= 33,		/* s/g list limit fixed by Ultrastor controller */

	Port		= 0x330,	/* factory defaults: I/O port */
	CtlrID		= 7,		/*	adapter SCSI id */
	Irq		= 14,		/*	interrupt request level */
};

struct Scatter {
	ulong	start;	/* physical address; Intel byte order */
	ulong	len;	/* length in bytes; Intel byte order */
};

/*
 * Ultrastor mailbox pointers point to one of these structures
 */
struct Mailbox {
	uchar	op;		/* Adapter operation */
	uchar	addr;		/* lun, chan, scsi ID */
	uchar	datap[4];	/* transfer data phys. pointer */
	uchar	datalen[4];	/* transfer data length */
	uchar	cmdlink[4];	/* command link phys. pointer */
	uchar	linkid;		/* SCSI command link ID */
	uchar	nscatter;	/* scatter/gather length (8 bytes per entry) */
	uchar	senselen;	/* length of sense data */
	uchar	cmdlen;		/* length of CDB */
	uchar	cmd[12];	/* SCSI command */
	uchar	adapterstatus;
	uchar	targetstatus;
	uchar	sensep[4];	/* sense data phys. pointer */

	/* the remainder is used by software, not the device */
	uchar	sensedata[64];	/* enough for AdapterInquiry data too */
	Scatter	sglist[Nscatter];
	Rendez	iodone;
	int	busy;		/* interrupt pending */
	ulong	physaddr;	/* physical address of this Mailbox */
	int	p9status;	/* p9 status value */
	Mailbox	*next;		/* next Mailbox in free list */
};

/* pack pointer as Intel order bytes (can simply assign) */
#define	PL(buf,p)	(*(ulong*)(buf)=(ulong)(p))

enum {
					/* bits in Mailbox.op[0] */
					/* 3 bit opcode */
	OpAdapter	= 0x01,		/* adapter command, not SCSI command */
	OpTarget	= 0x02,		/* SCSI command for device */
	OpReset		= 0x04,		/* device reset */
					/* 2 bit transfer direction */
	CmdDirection	= 0<<3,		/* transfer direction determined by SCSI command */
	DataIn		= 1<<3,		/* SCSI Data In */
	DataOut		= 2<<3,		/* SCSI Data Out */
	NoTransfer	= 3<<3,
	Nodiscon=	1<<5,		/* disable disconnect */
	Usecache=	1<<6,		/* use adapter cache (if available) */
	Scattered=	1<<7,		/* transfer pointer refers to S/G list */

					/* OpAdapter commands in Mailbox.cmd[0] */
	AdapterInquiry	= 0x01,
	AdapterSelftest	= 0x02,
	AdapterRead	= 0x03,		/* read adapter's buffer */
	AdapterWrite	= 0x04,		/* write to adapter's buffer */

					/* IO port offsets and bits */
	AdapterMask	= 0x00, 	/* local doorbell mask register */
	  OGMIntEnable	= 0x01,
	  SoftResetEnable = 0x40,
	  AdapterReady	= 0xe1,		/* adapter ready for work when all these set */
	AdapterIntr	= 0x01,		/* adapter interrupt/status; set by host, reset by adapter */
	  SignalAdapter	= 0x01,		/* tell adapter to read OGMpointer */
	  BusReset	= 0x20,		/* SCSI Bus Reset */
	  SoftReset	= 0x40,		/* Adapter Soft Reset */
	HostMask	= 0x02, 	/* host doorbell mask register */
	  ICMIntEnable	= 0x01,		/* incoming mail enable */
	  SIntEnable	= 0x80, 	/* enable interrupt from HostIntr reg */
	HostIntr	= 0x03, 	/* host doorbell interrupt/status; set by adapter, reset by host */
	  IntPending	= 0x80,		/* interrupt pending for host */
	  SignalHost	= 0x01,		/* Incoming Mail Interrupt */
	ProductID	= 0x04,		/* two byte product ID */
	Config1		= 0x06,
	Config2		= 0x07,
	OGMpointer	= 0x08,		/* pointer to Outgoing Mail */
	ICMpointer	= 0x0c,		/* pointer to Incoming Mail */
};

#define	OUT(c,v) outb(ctlr->io+(c), (v))
#define	IN(c)	inb(ctlr->io+(c))

struct Ctlr {
	Lock;
	QLock;
	int	io;		/* io port */
	int	irq;		/* interrupt vector */
	int	dma;		/* DMA channel */
	int	ownid;		/* adapter's SCSI ID */
	Mailbox	mbox[Nmbox];
	Mailbox	*free;		/* next free Mailbox */
	Rendez	mboxes;		/* wait for free mbox */
	QLock	mboxq;		/* mutex for mboxes */
	Rendez	ogm;		/* wait for free OGM slot with Ctlr qlocked */
};

static	Ctlr	ultra[Nctl];

int	scsidebugs[8] = {0};
int	scsiownid = 7;

static void
prmbox(Mailbox *m)
{
	int i;

	print("scsi %lx: op=%2.2x dir=%x cmd=%d [", m->physaddr, m->op&07, (m->op>>3)&3, m->cmdlen);
	for(i=0; i<m->cmdlen; i++)
		print(" %2.2x", m->cmd[i]);
	print("] id=%d lun=%d chan=%d", m->addr&7, (m->addr>>5)&7, (m->addr>>3)&3);
	print(" dlen=%lx dptr=%lx\n", *(long*)m->datalen, *(long*)m->datap);
	print(" astat=%2.2x dstat=%2.2x sc=%d [", m->adapterstatus, m->targetstatus, m->nscatter);
	for(i=0; i<m->nscatter; i++)
		print(" %lx,%ld", m->sglist[i].start, m->sglist[i].len);
	print("]\n");
	/*for(i=0; i<10; i++)
		print(" %2.2x", m->sensedata[i]);*/
	print("\n");
}

static void
resetadapter(int busreset)
{
	Ctlr *ctlr = &ultra[0];
	int i;

	if(IN(AdapterMask) & SoftResetEnable){
		OUT(AdapterIntr, SoftReset|busreset);
		for(i=50000; IN(AdapterIntr) & (SoftReset|busreset);)
			if(--i<0) {
				print("Ultrastor reset timed out\n");
				break;
			}
	}
}

static void
freebox(Ctlr *ctlr, Mailbox *m)
{
	lock(ctlr);
	if((m->next = ctlr->free) == 0)
		wakeup(&ctlr->mboxes);
	ctlr->free = m;
	unlock(ctlr);
}

static int
boxavail(void *a)
{
	return ((Ctlr*)a)->free != 0;
}

static int
scatter(Scatter *list, void *va, ulong nb)
{
	char *p = (char *)va;
	Scatter *sp = list;
	int limit = Nscatter;

	for(; nb != 0; sp++){
		if(--limit < 0)
			panic("Ultrastor I/O too scattered");
		sp->start = PADDR(p);
		sp->len = BY2PG - (sp->start&(BY2PG-1));	/* the rest of that page */
		if(sp->len > nb)
			sp->len = nb;
		nb -= sp->len;
		p += sp->len;
	}
	return sp - list;
}

static int
isready(void *a)
{
	Ctlr *ctlr = (Ctlr*)a;

	return (IN(AdapterIntr) & SignalAdapter) == 0;
}

static int
isdone(void *a)
{
	return ((Mailbox*)a)->busy == 0;
}

static int
ultra14fexec(Scsi *p, int rflag)
{
	Ctlr *ctlr = &ultra[0];
	Mailbox *m;
	long n;
	uchar *cp;

	if (p == 0 || ctlr->io == 0)
		return 0x0200;	/* device not available */

	/*
	 * get a free Mailbox and build an Ultrastor command
	 */
	while(lock(ctlr), (m = ctlr->free) == 0){
		unlock(ctlr);
		qlock(&ctlr->mboxq);
		if(waserror()){
			qunlock(&ctlr->mboxq);
			nexterror();
		}
		sleep(&ctlr->mboxes, boxavail, ctlr);
		poperror();
		qunlock(&ctlr->mboxq);
	}
	ctlr->free = m->next;
	unlock(ctlr);
	p->rflag = rflag;
	m->p9status = 0;
	m->op = OpTarget | CmdDirection | Usecache;	/* BUG? is it safe always to Usecache? */
	m->addr = p->target | (p->lun<<5);
	if(p->cmd.lim - p->cmd.ptr > sizeof(m->cmd))
		panic("scsiexec");
	m->cmdlen = p->cmd.lim - p->cmd.ptr;
	for(cp = m->cmd; p->cmd.ptr < p->cmd.lim;)
		*cp++ = *p->cmd.ptr++;
	n = p->data.lim - p->data.ptr;
	if(n){
		PL(m->datap, PADDR(m->sglist));
		m->op |= Scattered;
		m->nscatter = scatter(m->sglist, p->data.ptr, n);
	} else {
		m->nscatter = 0; /* controller will not allow s/g when n==0 */
		PL(m->datap, 0);
	}
	PL(m->datalen, n);
	m->adapterstatus = 0;
	m->targetstatus = 0;

	/*
	 * send the command to the host adapter
	 */
	while(lock(ctlr), IN(AdapterIntr) & SignalAdapter) {	/* adapter busy: infrequent? */
		static int fred;
		if(fred == 0){
			print("ultrastor busy\n");
			fred = 1;
		}
		unlock(ctlr);
		qlock(ctlr);
		if(waserror()) {
			freebox(ctlr, m);
			qunlock(ctlr);
			nexterror();
		}
		sleep(&ctlr->ogm, isready, ctlr);
		poperror();
		qunlock(ctlr);
	}
	m->busy = 1;
	outl(ctlr->io+OGMpointer, m->physaddr);
	OUT(AdapterIntr, SignalAdapter);
	unlock(ctlr);

	/*
	 * wait for reply
	 */
	while(waserror())
		;	/* could send MSCP abort request to adapter */
	while(m->busy)
		sleep(&m->iodone, isdone, m);
	poperror();
	p->status = m->p9status;
	if(scsidebugs[2])
		prmbox(m);
	if(p->status == 0x6000)
		p->data.ptr = p->data.lim;	/* can only assume no residue */
	freebox(ctlr, m);
	return p->status;
}

static void
scsimoan(char *msg, Mailbox *m)
{
	/*int i;*/

	print("SCSI error: %s:", msg);
	print("id=%d cmd=%2.2x status=%2.2x adapter=%2.2x", m->addr&7, m->cmd[0], m->targetstatus, m->adapterstatus);
	/*print(" sense:");
	for(i=0; i<10; i++)
		print(" %2.2x", m->sensedata[i]);*/
	print("\n");
}

static void
interrupt(Ureg *ur)
{
	Ctlr *ctlr = &ultra[0];
	Mailbox *m;
	ulong pa;

	USED(ur);
	if(ctlr->ogm.p && (IN(AdapterIntr) & SignalAdapter) == 0)
		wakeup(&ctlr->ogm);
	if((IN(HostIntr) & SignalHost) == 0)
		return;	/* no incoming mail */
	pa = inl(ctlr->io+ICMpointer);
	OUT(HostIntr, SignalHost);	/* release ICM slot */
	for(m = &ctlr->mbox[0]; m->physaddr != pa;)
		if(++m >= &ctlr->mbox[Nmbox]) {
			/* these sometimes happen in response to a scsi bus reset; ignore them */
			print("ultrastor: invalid ICM pointer #%lux\n", pa);
			return;
		}
	if(scsidebugs[1])
		prmbox(m);

	m->p9status = 0x1000 | m->adapterstatus;
	switch(m->adapterstatus){
	default:
		scsimoan("adapter", m);
		if(m->adapterstatus >= 0x92) /* ie, scsi command protocol error */
			resetadapter(BusReset);
		/* might adapter reset be required in other cases? */
		break;

	case 0x91:	/* selection timed out */
		m->p9status = 0x0200;
		if(scsidebugs[0])
			scsimoan("timeout", m);
		break;

	case 0xA3:
		scsimoan("SCSI bus reset error", m);
		break;

	case 0x00:
		m->p9status = 0x6000 | m->targetstatus;
		if(m->targetstatus && scsidebugs[0])
			scsimoan("device", m);
		break;
	}
	m->busy = 0;
	wakeup(&m->iodone);
}

static ISAConf ultra14f = {
	"ultra14f",
	Port,
	Irq,
	0,
	0,
};

static int irq[4] = {
	15, 14, 11, 10,
};

int (*
ultra14freset(void))(Scsi*, int)
{
	ISAConf *isa = &ultra14f;
	Ctlr *ctlr = &ultra[0];
	Mailbox *m;
	int i, model;

	/*
	 * See if we have any configuration info
	 * and check it is an Ultrastor [13]4f.
	 * Only one controller for now.
	 */
	if(isaconfig("scsi", 0, &ultra14f) == 0)
		return 0;
	memset(ctlr, 0, sizeof(Ctlr));
	ctlr->io = isa->port;

	if(IN(ProductID) != 0x56)
		return 0;
	model = IN(ProductID+1);
	switch(model){

	case 0x40:
		model = 14;
		break;

	case 0x41:
		model = 34;
		break;

	default:
		return 0;
	}

	i = IN(Config1);
	ctlr->irq = irq[((i>>4)&03)];
	if(model == 14)
		ctlr->dma = 5 + ((i>>6)&03);
	ctlr->ownid = IN(Config2)&07;
	/*print("Ultrastor %dF id %d io 0x%x irq %d dma %d\n",
		model, ctlr->ownid, ctlr->io, ctlr->irq, ctlr->dma);*/

	/*
	 * set the DMA controller to cascade mode for bus master
	 */
	switch(ctlr->dma){
	case 5:
		outb(0xd6, 0xc1); outb(0xd4, 1); break;
	case 6:
		outb(0xd6, 0xc2); outb(0xd4, 2); break;
	case 7:
		outb(0xd6, 0xc3); outb(0xd4, 3); break;
	}

	resetadapter(0);
	ctlr->free = 0;
	for(i=0; i<Nmbox; i++){
		m = &ctlr->mbox[i];
		memset(m, 0, sizeof(*m));
		m->physaddr = PADDR(m);
		PL(m->sensep, 0);	/* DON'T collect sense data automatically: messes up scuzz? */
		m->senselen = 0;
		m->next = ctlr->free;
		ctlr->free = m;
	}

	setvec(Int0vec+ctlr->irq, interrupt);

	/*
	 * issue AdapterInquiry command to check it's alive
	 * -- could check enquiry data
	 */
	OUT(HostMask, 0);	/* mask interrupts */
	m = &ctlr->mbox[0];
	m->op = OpAdapter | CmdDirection;
	m->addr = ctlr->ownid;
	m->cmdlen = 1;
	m->cmd[0] = AdapterInquiry;
	PL(m->datap, PADDR(m->sensedata));
	PL(m->datalen, 38);
	while(IN(AdapterIntr) & SignalAdapter)
		;
	outl(ctlr->io+OGMpointer, m->physaddr);
	OUT(AdapterIntr, SignalAdapter);
	for(i=100000; (IN(HostIntr)&SignalHost)==0;)
		if(--i < 0){
			print("No response to UltraStor Inquiry\n");
			ctlr->io = 0;
			return 0;
		}
	OUT(HostIntr, SignalHost);

	OUT(HostMask, ICMIntEnable|SIntEnable);
	scsiownid = ctlr->ownid;

	return ultra14fexec;
}

M port/portdat.h => port/portdat.h +1 -1
@@ 488,7 488,7 @@ enum
 */
enum
{
	SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, NSEG
	SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, SEG3, SEG4, NSEG
};

enum

M port/portfns.h => port/portfns.h +1 -1
@@ 113,6 113,7 @@ void		kproftimer(ulong);
void		ksetenv(char*, char*);
long		latin1(uchar*);
void		lights(int);
void		links(void);
void		lock(Lock*);
void		lockinit(void);
Page*		lookpage(Image*, ulong);


@@ 199,7 200,6 @@ void		resetscsi(void);
void		resrcwait(char*);
int		return0(void*);
void		rlock(RWlock*);
void		rootfiles(void);
void		rootrecover(Path*, char*);
void		rootreq(Chan*, Mnt*);
void		runlock(RWlock*);

M power/main.c => power/main.c +1 -1
@@ 38,8 38,8 @@ main(void)
	initseg();
	clockinit();
	ioboardinit();
	links();
	chandevreset();
	rootfiles();
	swapinit();
	userinit();
	launchinit();