~kris/9p

9hist

ebb118e0e3a65829192f24cbab12830ce32e3289 — David du Colombier 35 years ago 90f6e35
Plan 9 from Bell Labs 1991-07-27
M gnot/trap.c => gnot/trap.c +1 -0
@@ 148,6 148,7 @@ notify(Ureg *ur)
		unlock(&u->p->debug);
		return;
	}
	u->p->notepending = 0;
	if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){
		if(u->note[0].flag == NDebug)
			pprint("suicide: %s\n", u->note[0].msg);

A pc/devfloppy.c => pc/devfloppy.c +559 -0
@@ 0,0 1,559 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"

typedef	struct Drive	Drive;
typedef	struct Controller	Controller;
typedef struct Type	Type;

enum
{
	Fmotor=		0x3f2,	/* motor port */
	 Fintena=	 0x4,	/* enable floppy interrupt */
	 Fena=		 0x8,	/* 0 == reset controller */

	Fstatus=	0x3f4,	/* controller main status port */
	 Fready=	 0x80,	/* ready to be touched */
	 Ffrom=		 0x40,	/* data from controller */
	 Fbusy=		 0x10,	/* operation not over */

	Fdata=		0x3f5,	/* controller data port */
	 Frecal=	 0x7,	/* recalibrate cmd */
	 Fseek=		 0xf,	/* seek cmd */
	 Fsense=	 0x8,	/* sense cmd */
	 Fread=		 0x66,	/* read cmd */
	 Fwrite=	 0x47,	/* write cmd */
	 Fmulti=	 0x80,	/* or'd with Fread or Fwrite for multi-head */

	DMAmode0=	0xb,
	DMAmode1=	0xc,
	DMAaddr=	0x4,
	DMAtop=		0x81,
	DMAinit=	0xa,
	DMAcount=	0x5,

	Nfloppy=	4,	/* floppies/controller */

	/* sector size encodings */
	S128=		0,
	S256=		1,
	S512=		2,
	S1024=		3,

	/* status 0 byte */
	Drivemask=	3<<0,
	Seekend=	1<<5,
	Codemask=	(3<<6)|(3<<3),
};

/*
 *  floppy types
 */
struct Type
{
	char	*name;
	int	bytes;		/* bytes/sector */
	int	sectors;	/* sectors/track */
	int	heads;		/* number of heads */
	int	steps;		/* steps per cylinder */
	int	tracks;		/* tracks/disk */
	int	gpl;		/* intersector gap length for read/write */	
	int	fgpl;		/* intersector gap length for format */	
	long	cap;		/* drive capacity in bytes */
};
Type floppytype[] =
{
 { "MF2HD",	S512,	18,	2,	1,	80,	0x1B,	0x54,	512*2*18*80 },
 { "MF2DD",	S512,	9,	2,	1,	80,	0x1B,	0x54,	512*2*9*80 },
 { "F2HD",	S512,	15,	2,	1,	80,	0x2A,	0x50,	512*15*2*80 },
 { "F2DD",	S512,	8,	2,	1,	40,	0x2A,	0x50,	512*8*2*40 },
 { "F1DD",	S512,	8,	1,	1,	40,	0x2A,	0x50,	512*8*1*40 },
};
static int secbytes[] =
{
	128,
	256,
	512,
	1024
};

/*
 *  a floppy drive
 */
struct Drive
{
	QLock;
	Type	*t;
	int	dev;

	ulong	lasttouched;	/* time last touched */
	int	motoron;	/* motor is on */
	int	cyl;		/* current cylinder */
	long	offset;		/* current offset */
	int	confused;	/* needs to be recalibrated (or worse) */

	int	tcyl;		/* target cylinder */
	int	thead;		/* target head */
	int	tsec;		/* target sector */
	long	len;

	int	busy;		/* true if drive is seeking */
	Rendez	r;		/* waiting for operation termination */
};

/*
 *  NEC PD765A controller for 4 floppys
 */
struct Controller
{
	QLock;
	Drive	d[Nfloppy];	/* the floppy drives */
	int	busy;		/* true if a read or write in progress */
	uchar	stat[8];	/* status of an operation */
	int	confused;
};

Controller	floppy[1];

/*
 *  start a floppy drive's motor.  set an alarm for 1 second later to
 *  mark it as started (we get no interrupt to tell us).
 *
 *  assume the caller qlocked the drive.
 */
void
floppystart(Drive *dp)
{
	int cmd;

	dp->lasttouched = m->ticks;	
	if(dp->motoron)
		return;

	cmd = (1<<(dp->dev+4)) | Fintena | Fena | dp->dev;
	outb(Fmotor, cmd);
	dp->busy = 1;
	tsleep(&dp->r, noreturn, 0, 1000);
	dp->motoron = 1;
	dp->busy = 0;
	dp->lasttouched = m->ticks;
}

/*
 *  stop the floppy if it hasn't been used in 5 seconds
 */
void
floppystop(Drive *dp)
{
	int cmd;

	if(!canqlock(dp))
		return;
	cmd = Fintena | Fena | dp->dev;
	outb(Fmotor, cmd);
	dp->motoron = 0;	
}
void
floppykproc(Alarm* a)
{
	Drive *dp;

	if(waserror())
	for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){
		if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5)
			floppystop(dp);
	}
		
	alarm(5*1000, floppyalarm, 0);
	cancel(a);
}

int
floppysend(int data)
{
	int tries;
	uchar c;

	for(tries = 0; tries < 100; tries++){
		/*
		 *  see if its ready for data
		 */
		c = inb(Fstatus);
		if((c&(Ffrom|Fready)) != Fready)
			continue;

		/*
		 *  send the data
		 */
		outb(Fdata, data);
		return 0;
	}
	return -1;
}

int
floppyrcv(void)
{
	int tries;
	uchar c;

	for(tries = 0; tries < 100; tries++){
		/*
		 *  see if its ready for data
		 */
		c = inb(Fstatus);
		if((c&(Ffrom|Fready)) != (Ffrom|Fready))
			continue;

		/*
		 *  get data
		 */
		return inb(Fdata)&0xff;
	}
	return -1;
}

int
floppyrdstat(int n)
{
	int i;
	int c;

	for(i = 0; i < n; i++){
		c = floppyrcv();
		if(c < 0)
			return -1;
		floppy.stat[i] = c;
	}
	return 0;
}

void
floppypos(Drive *dp, long off)
{
	int lsec;
	int end;
	int cyl;

	lsec = off/secbytes[dp->t->bytes];
	dp->tcyl = lsec/(dp->t->sectors*dp->t->heads);
	dp->tsec = (lsec % dp->t->sectors) + 1;
	dp->thead = (lsec/dp->t->sectors) % dp->t->heads;

	/*
	 *  can't read across cylinder boundaries.
	 *  if so, decrement the bytes to be read.
	 */
	lsec = (off+dp->len)/secbytes[dp->t->bytes];
	cyl = lsec/(dp->t->sectors*dp->t->heads);
	if(cyl != dp->tcyl){
		dp->len -= (lsec % dp->t->sectors)*secbytes[dp->t->bytes];
		dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*secbytes[dp->t->bytes]
				*dp->t->sectors;
	}

	dp->lasttouched = m->ticks;	
	floppy.intr = 0;
}

void
floppywait(void)
{
	int tries;

	for(tries = 0; tries < 100 && floppy.intr == 0; tries++)
		delay(5);
	if(tries >= 100)
		print("tired floopy\n");
	floppy.intr = 0;
}

int
floppysense(Drive *dp)
{
	/*
	 *  ask for floppy status
	 */
	if(floppysend(Fsense) < 0){
		floppy.confused = 1;
		return -1;
	}
	if(floppyrdstat(2) < 0){
		floppy.confused = 1;
		dp->confused = 1;
		return -1;
	}

	/*
	 *  make sure it's the right drive
	 */
	if((floppy.stat[0] & Drivemask) != dp-floppy.d){
		print("sense failed\n");
		dp->confused = 1;
		return -1;
	}
	return 0;
}

int
floppyrecal(Drive *dp)
{
	floppy.intr = 0;
	if(floppysend(Frecal) < 0
	|| floppysend(dp - floppy.d) < 0){
		floppy.confused = 0;
		return -1;
	}
	floppywait();

	/*
	 *  get return values
	 */
	if(floppysense(dp) < 0)
		return -1;

	/*
	 *  see if it worked
	 */
	if((floppy.stat[0] & (Codemask|Seekend)) != Seekend){
		print("recalibrate failed\n");
		dp->confused = 1;
		return -1;
	}

	/*
	 *  see what cylinder we got to
	 */
	dp->tcyl = 0;
	dp->cyl = floppy.stat[1]/dp->t->steps;
	if(dp->cyl != dp->tcyl){
		print("recalibrate went to wrong cylinder %d\n", dp->cyl);
		dp->confused = 1;
		return -1;
	}

	dp->confused = 0;
	return 0;
}

void
floppyinit(void)
{
	Drive *dp;

	for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){
		dp->t = &floppytype[0];
		dp->cyl = -1;
		dp->motoron = 1;
		floppystop(dp);
	}
	setvec(22, floppyintr);
	alarm(5*1000, floppyalarm, (void *)0);
}

void
floppyreset(void)
{
	Drive *dp;

	/*
	 *  reset the floppy if'n it's confused
	 */
	if(floppy.confused){
		/* reset controller and turn all motors off */
		floppy.intr = 0;
		splhi();
		outb(Fmotor, 0);
		delay(1);
		outb(Fmotor, Fintena|Fena);
		spllo();
		for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){
			dp->motoron = 0;
			dp->confused = 1;
		}
		floppywait();
		floppy.confused = 0;
	}

	/*
	 *  recalibrate any confused drives
	 */
	for(dp = floppy.d; floppy.confused == 0 && dp < &floppy.d[Nfloppy]; dp++){
		if(dp->confused == 0)
			floppyrecal(dp);

	}

}

long
floppyseek(int dev, long off)
{
	Drive *dp;

	dp = &floppy.d[dev];

	if(floppy.confused || dp->confused)
		floppyreset();

	floppystart(dp);

	floppypos(dp, off);
	if(dp->cyl == dp->tcyl){
		dp->offset = off;
		return off;
	}

	/*
	 *  tell floppy to seek
	 */
	if(floppysend(Fseek) < 0
	|| floppysend((dp->thead<<2) | dev) < 0
	|| floppysend(dp->tcyl * dp->t->steps) < 0){
		print("seek cmd failed\n");
		floppy.confused = 1;
		return -1;
	}

	/*
	 *  wait for interrupt
	 */
	floppywait();

	/*
	 *  get floppy status
	 */
	if(floppysense(dp) < 0)
		return -1;

	/*
 	 *  see if it worked
	 */
	if((floppy.stat[0] & (Codemask|Seekend)) != Seekend){
		print("seek failed\n");
		dp->confused = 1;
		return -1;
	}

	/*
	 *  see what cylinder we got to
	 */
	dp->cyl = floppy.stat[1]/dp->t->steps;
	if(dp->cyl != dp->tcyl){
		print("seek went to wrong cylinder %d instead of %d\n", dp->cyl, dp->tcyl);
		dp->confused = 1;
		return -1;
	}

	dp->offset = off;
	return dp->offset;
}

long
floppyxfer(Drive *dp, int cmd, void *a, long n)
{
	int dev;
	ulong addr;
	long offset;

	addr = (ulong)a;
	dev = dp - floppy.d;

	/*
	 *  dma can't cross 64 k boundaries
	 */
	if((addr & 0xffff0000) != ((addr+n) & 0xffff0000))
		n -= (addr+n)&0xffff;

	dp->len = n;
	floppyseek(dev, dp->offset);

/*	print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n",
		dp->tcyl, dp->thead, dp->tsec, addr, n);/**/

	/*
	 *  set up the dma
	 */
	outb(DMAmode1, cmd==Fread ? 0x46 : 0x4a);
	outb(DMAmode0, cmd==Fread ? 0x46 : 0x4a);
	outb(DMAaddr, addr);
	outb(DMAaddr, addr>>8);
	outb(DMAtop, addr>>16);
	outb(DMAcount, n-1);
	outb(DMAcount, (n-1)>>8);
	outb(DMAinit, 2);

	/*
	 *  tell floppy to go
	 */
	cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);
	if(floppysend(cmd) < 0
	|| floppysend((dp->thead<<2) | dev) < 0
	|| floppysend(dp->tcyl * dp->t->steps) < 0
	|| floppysend(dp->thead) < 0
	|| floppysend(dp->tsec) < 0
	|| floppysend(dp->t->bytes) < 0
	|| floppysend(dp->t->sectors) < 0
	|| floppysend(dp->t->gpl) < 0
	|| floppysend(0xFF) < 0){
		print("xfer cmd failed\n");
		floppy.confused = 1;
		return -1;
	}

	floppywait();

	/*
	 *  get status
 	 */
	if(floppyrdstat(7) < 0){
		print("xfer status failed\n");
		floppy.confused = 1;
		return -1;
	}

	if((floppy.stat[0] & Codemask)!=0 || floppy.stat[1] || floppy.stat[2]){
print("xfer failed %lux %lux %lux\n", floppy.stat[0],
			floppy.stat[1], floppy.stat[2]);
		dp->confused = 1;
		return -1;
	}

	offset = (floppy.stat[3]/dp->t->steps) * dp->t->heads + floppy.stat[4];
	offset = offset*dp->t->sectors + floppy.stat[5] - 1;
	offset = offset * secbytes[floppy.stat[6]];
	if(offset != dp->offset+n){
		print("new offset %d instead of %d\n", offset, dp->offset+dp->len);
		dp->confused = 1;
		return -1;/**/
	}

	dp->offset += dp->len;
	return dp->len;
}

long
floppyread(int dev, void *a, long n)
{
	Drive *dp;
	long rv, i;
	uchar *aa = a;

	dp = &floppy.d[dev];
	for(rv = 0; rv < n; rv += i){
		i = floppyxfer(dp, Fread, aa+rv, n-rv);
		if(i <= 0)
			break;
	}
	return rv;
}

void
floppyintr(Ureg *ur)
{
	floppy.intr = 1;
}

M pc/headland.c => pc/headland.c +53 -0
@@ 18,6 18,35 @@ enum
};

/*
 *  ports used by the DMA controllers
 */
typedef struct DMA	DMA;
struct DMA {
	uchar	addr[4];	/* current address (4 channels) */
	uchar	count[4];	/* current count (4 channels) */
	uchar	page[4];	/* page registers (4 channels) */
	uchar	cmd;		/* command status register */
	uchar	req;		/* request registers */
	uchar	sbm;		/* single bit mask register */
	uchar	mode;		/* mode register */
	uchar	cbp;		/* clear byte pointer */
	uchar	mc;		/* master clear */
	uchar	cmask;		/* clear mask register */
	uchar	wam;		/* write all mask register bit */
};

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

/*
 *  enable address bit 20
 */
void


@@ 38,3 67,27 @@ exit(void)
	print("exiting\n");
	outb(Head, Reset);
}

/*
 *  setup a dma transfer.  return count actually set up.  we DMA up
 *  to a page.
 */
long
dmasetup(int d, int chan, Page *pg, long len, int isread)
{
	DMA *dp;
	ulong addr;

	dp = &dma[d];
	addr = (ulong)a;
	addr &= ~KZERO;

	outb(dp->cbp, isread ? 0x46 : 0x4a);
	outb(dp->mode, isread ? 0x46 : 0x4a);
	outb(dp->addr, addr);
	outb(dp->addr, addr>>8);
	outb(dp->page, addr>>16);
	outb(dp->count, len-1);
	outb(dp->count, (len-1)>>8);
	outb(dp->sbm, 2);
}

M pc/main.c => pc/main.c +0 -1
@@ 19,7 19,6 @@ main(void)
	screeninit();
	printinit();
	mmuinit();
	vgainit();
	trapinit();
	kbdinit();
	clockinit();

M pc/trap.c => pc/trap.c +1 -0
@@ 279,6 279,7 @@ notify(Ureg *ur)
		unlock(&u->p->debug);
		return;
	}
	u->p->notepending = 0;
	if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){
		if(u->note[0].flag == NDebug)
			pprint("suicide: %s\n", u->note[0].msg);

M pc/vga.c => pc/vga.c +114 -16
@@ 8,44 8,142 @@
enum
{
	GRX=		0x3CE,		/* index to graphics registers */
	GR=		0x3CF,		/* graphics registers 0-8 */
	GR=		0x3CF,		/* graphics registers */
	 Grot=		 0x03,		/*  data rotate register */
	 Gmode=		 0x05,		/*  mode register */
	 Gmisc=		 0x06,		/*  miscillaneous register */
	 Grms=		 0x04,		/*  read map select register */
	SRX=		0x3C4,		/* index to sequence registers */
	SR=		0x3C5,		/* sequence registers 0-7 */
	SR=		0x3C5,		/* sequence registers */
	 Sclock=	 0x01,		/*  clocking register */
	 Smode=		 0x04,		/*  mode register */
	 Smmask=	 0x02,		/*  map mask */
	CRX=		0x3D4,		/* index to crt registers */
	CR=		0x3D5,		/* crt registers */
	 Cmode=		 0x17,		/*  mode register */
	 Cmsl=		 0x09,		/*  max scan line */
	ARX=		0x3C0,		/* index to attribute registers */
	AR=		0x3C1,		/* attribute registers */
	 Amode=		 0x10,		/*  mode register */
	 Acpe=		 0x12,		/*  color plane enable */
};

/*
 *  screen dimensions
 */
#define MAXX	640
#define MAXY	480

/*
 *  routines for setting vga registers
 */
void
srout(int reg, int val)
{
	outb(SRX, reg);
	outb(SR, val);
}

void
grout(int reg, int val)
{
	outb(GRX, reg);
	outb(GR, val);
}
void
arout(int reg, int val)
{
	inb(0x3DA);
	outb(ARX, reg | 0x20);
	outb(AR, val);
}
void
crout(int reg, int val)
{
	outb(CRX, reg);
	outb(CR, val);
}

/*
 *  m is a bit mask of planes to be affected by CPU writes
 */
vgawrmask(int m)
{
	srout(Smmask, m&0xf);
}

/*
 *  look at VGA registers
 *  p is the plane that will respond to CPU reads
 */
vgardplane(int p)
{
	grout(Grms, p&3);
}

/*
 *  partial screen munching squares
 */
#define	DELTA	1
#define	DADDR	((long *) 0)
#define	SIDE	256
void
munch(void)
{
	ulong x,y,i,d;
	uchar *screen, tab[8], *p;

	screen = (uchar *)(0xA0000 | KZERO);
	d=0;
	tab[0] = 0x80;
	tab[1] = 0x40;
	tab[2] = 0x20;
	tab[3] = 0x10;
	tab[4] = 0x08;
	tab[5] = 0x04;
	tab[6] = 0x02;
	tab[7] = 0x01;

	for(i=0; i<MAXY*(MAXX/8); i++)
		screen[i]=0;

	for(;;){
		for(x=0; x<SIDE; x++){
			y = (x^d) % SIDE;
			p = &screen[y*(MAXX/8) + (x/8)];
			y = *p;
			*p = y ^ tab[x&7];
		}
		d+=DELTA;
	}
}

/*
 *  Set up for 4 separately addressed bit planes.  Each plane is 
 */
void
vgainit(void)
{
	uchar *display;
	int i;
	int i, j, k;
	int c;

	srout(2, 0x0f);		/* enable all 4 color planes */
	srout(4, 0x08);		/* quad mode */
	grout(5, 0x40);		/* pixel bits are sequential */
	grout(6, 0x01);		/* graphics mode - display starts at 0xA0000 */
	display = (uchar *)(0xA0000 | KZERO);
	arout(Acpe, 0x0f);	/* enable all planes */
	arout(Amode, 0x01);	/* graphics mode - 4 bit pixels */
	grout(Gmisc, 0x01);	/* graphics mode */
	grout(Gmode, 0x00);	/* write mode 0, read mode 0 */
	grout(Grot, 0x00);	/* CPU writes bytes to video mem without modifications */
	crout(Cmode, 0xe3);	/* turn off address wrap & word mode */
	crout(Cmsl, 0x40);	/* 1 pixel per scan line */
	srout(Smode, 0x06);	/* extended memory, odd/even off */
	srout(Sclock, 0x01);	/* 8 bits/char */

	for(;;);
	display = (uchar*)(0xA0000 | KZERO);
	for(i = 0; i < 128*1024; i++)
		display[i] = 0x00;

	for(i = 0; i < 4*640; i++)
		display[i] = 0xff;
	/*
	 *  zero out display
	 */
	srout(Smmask, 0x0f);	/* enable all 4 color planes for writing */
	for(i=0; i<MAXY*(MAXX/8); i++)
		display[i] = 0;
	
	munch();
}


M port/alarm.c => port/alarm.c +6 -6
@@ 73,8 73,8 @@ alarminit(void)
		lock(&alarmtab[i]);	/* allocate locks, as they are used at interrupt time */
		unlock(&alarmtab[i]);
	}
	qlock(&alarms);
	qunlock(&alarms);
	lock(&alarms);
	unlock(&alarms);
}

#define NA 10		/* alarms per clock tick */


@@ 111,7 111,7 @@ checkalarms(void)
			unlock(&m->alarmlock);
	}

	if(m == MACHP(0) && canqlock(&alarms)){
	if(m == MACHP(0) && canlock(&alarms)){
		now = MACHP(0)->ticks;
		while((rp = alarms.head) && rp->alarm <= now){
			if(rp->alarm != 0L){


@@ 124,7 124,7 @@ checkalarms(void)
			}
			alarms.head = rp->palarm;
		}
		qunlock(&alarms);
		unlock(&alarms);
	}
}



@@ 143,7 143,7 @@ procalarm(ulong time)
	else
		when += MACHP(0)->ticks;

	qlock(&alarms);
	lock(&alarms);
	l = &alarms.head;
	for(f = *l; f; f = f->palarm){
		if(u->p == f){


@@ 170,7 170,7 @@ procalarm(ulong time)
		alarms.head = u->p;
done:
	u->p->alarm = when;
	qunlock(&alarms);
	unlock(&alarms);

	return TK2MS(old);			
}

M port/chan.c => port/chan.c +11 -1
@@ 5,7 5,6 @@
#include	"fns.h"
#include	"errno.h"


struct{
	Lock;
	Chan	*free;


@@ 612,6 611,7 @@ namec(char *name, int amode, int omode, ulong perm)
			close(cc);
			nexterror();
		}
		nameok(elem);
		if((nc=walk(cc, elem, 1)) != 0){
			poperror();
			close(c);


@@ 665,6 665,16 @@ char isfrog[]={
	[0x7f]	1,
};

void
nameok(char *elem)
{
	while(*elem) {
		if((*elem&0x80) || isfrog[*elem])
			error(Ebadchar);
		elem++;
	}
}

/*
 * name[0] should not be a slash.
 * Advance name to next element in path, copying current element into elem.

M port/devcons.c => port/devcons.c +11 -0
@@ 235,6 235,17 @@ echo(int c)
}

/*
 * turn '\r' into '\n' before putting it into the queue
 */
int
kbdcr2nl(IOQ *q, int ch)
{
	if(ch == '\r')
		ch = '\n';
	return kbdputc(q, ch);
}

/*
 * Put character into read queue at interrupt time.
 * Always called splhi from proc 0.
 */

M port/devscc.c => port/devscc.c +8 -0
@@ 370,6 370,14 @@ sccspecial(int port, IOQ *oq, IOQ *iq, int baud)
	sp->iq = iq;
	sccenable(sp);
	sccsetbaud(sp, baud);

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

static void	scctimer(Alarm*);

M port/portdat.h => port/portdat.h +2 -2
@@ 70,7 70,7 @@ struct Alarm

struct Alarms
{
	QLock;
	Lock;
	Proc	*head;
};



@@ 492,7 492,7 @@ struct Proc
	Lock	debug;			/* to access debugging elements of User */
	Rendez	*r;			/* rendezvous point slept on */
	Rendez	sleep;			/* place for tsleep and syssleep */
	int	wokeup;			/* whether sleep was interrupted */
	int	notepending;		/* note issued but not acted on */
	ulong	pc;			/* DEBUG only */
	int	kp;			/* true if a kernel process */
	Proc	*palarm;		/* Next alarm time */

M port/portfns.h => port/portfns.h +2 -0
@@ 96,6 96,7 @@ void	isdir(Chan*);
int	ispages(void*);
void	kbdclock(void);
int	kbdputc(IOQ*, int);
int	kbdcr2nl(IOQ*, int);
void	kbdrepeat(int);
void	kickpager(void);
int	kprint(char*, ...);


@@ 113,6 114,7 @@ void	mntdump(void);
int	mount(Chan*, Chan*, int);
int	mouseputc(IOQ*, int);
Chan*	namec(char*, int, int, ulong);
void	nameok(char*);
Alarm*	newalarm(void);
Chan*	newchan(void);
Egrp*	newegrp(void);

M port/proc.c => port/proc.c +25 -16
@@ 238,6 238,7 @@ loop:
		p->fpstate = FPinit;
		p->kp = 0;
		p->procctl = 0;
		p->notepending = 0;
		memset(p->seg, 0, sizeof p->seg);
		lock(&pidalloc);
		p->pid = ++pidalloc.pid;


@@ 282,12 283,15 @@ sleep1(Rendez *r, int (*f)(void*), void *arg)
	 * at interrupt time. lock is mutual exclusion
	 */
	s = splhi();
	p = u->p;
	p->r = r;	/* early so postnote knows */
	lock(r);

	/*
	 * if condition happened, never mind
	 */
	if((*f)(arg)){	
	if((*f)(arg)){
		p->r = 0;
		unlock(r);
		splx(s);
		return;


@@ 297,11 301,8 @@ sleep1(Rendez *r, int (*f)(void*), void *arg)
	 * now we are committed to
	 * change state and call scheduler
	 */
	p = u->p;
	if(r->p)
		print("double sleep %d %d\n", r->p->pid, p->pid);
	p->r = r;
	p->wokeup = 0;
	p->state = Wakeme;
	r->p = p;
	unlock(r);


@@ 310,10 311,14 @@ sleep1(Rendez *r, int (*f)(void*), void *arg)
void
sleep(Rendez *r, int (*f)(void*), void *arg)
{
	Proc *p;

	p = u->p;
	sleep1(r, f, arg);
	sched();
	if(u->p->wokeup){
		u->p->wokeup = 0;
	if(p->notepending == 0)
		sched();	/* notepending may go true while asleep */
	if(p->notepending){
		p->notepending = 0;
		error(Eintr);
	}
}


@@ 322,13 327,17 @@ void
tsleep(Rendez *r, int (*f)(void*), void *arg, int ms)
{
	Alarm *a;
	Proc *p;

	p = u->p;
	sleep1(r, f, arg);
	a = alarm(ms, twakeme, r);
	sched();
	cancel(a);
	if(u->p->wokeup){
		u->p->wokeup = 0;
	if(p->notepending == 0){
		a = alarm(ms, twakeme, r);
		sched();	/* notepending may go true while asleep */
		cancel(a);
	}
	if(p->notepending){
		p->notepending = 0;
		error(Eintr);
	}
}


@@ 397,6 406,7 @@ postnote(Proc *p, int dolock, char *n, int flag)
			kunmap(k);
		return 0;
	}
	p->notepending = 1;
	strcpy(up->note[up->nnote].msg, n);
	up->note[up->nnote++].flag = flag;
	if(up != u)


@@ 404,15 414,14 @@ postnote(Proc *p, int dolock, char *n, int flag)
	if(dolock)
		unlock(&p->debug);

	if(r = p->r) {		/* assign = */
		/* wake up */
	if(r = p->r){		/* assign = */
		/* wake up; can't call wakeup itself because we're racing with it */
		s = splhi();
		lock(r);
		if(p->r==r && r->p==p){
		if(p->r==r && r->p==p){	/* check we won the race */
			r->p = 0;
			if(p->state != Wakeme)
				panic("postnote wakeup: not Wakeme");
			p->wokeup = 1;
			p->r = 0;
			ready(p);
		}

M port/qlock.c => port/qlock.c +0 -3
@@ 53,10 53,7 @@ qunlock(QLock *q)
		unlock(&q->queue);
		ready(p);
	}else{
		/* horrible botch because clock does a canqlock */
		int s = splhi();
		unlock(&q->use);
		unlock(&q->queue);
		splx(s);
	}
}

M port/swap.c => port/swap.c +2 -1
@@ 123,7 123,8 @@ pager(void *junk)
						executeio();
					}
			}
			else {
			else 
			if(palloc.freecount < HIGHWATER) {
				/* Emulate the old system if no swap channel */
				print("no physical memory\n");
				tsleep(&swapalloc.r, return0, 0, 1000);

M port/tcpinput.c => port/tcpinput.c +1 -1
@@ 9,7 9,7 @@

int tcpdbg = 0;
#define DPRINT	if(tcpdbg) print
#define LPRINT  print
#define LPRINT  if(tcpdbg) print

extern Queue *Tcpoutput;
QLock	reseqlock;

M power/devduart.c => power/devduart.c +8 -0
@@ 466,6 466,7 @@ void
duartspecial(int port, IOQ *oq, IOQ *iq, int baud)
{
	Duartport *dp = &duartport[port];
	IOQ *zq;

	dp->nostream = 1;
	if(oq){


@@ 476,6 477,13 @@ duartspecial(int port, IOQ *oq, IOQ *iq, int baud)
	if(iq){
		dp->iq = iq;
		dp->iq->ptr = dp;

		/*
		 *  Stupid HACK to undo a stupid hack
		 */ 
		zq = &kbdq;
		if(iq == zq)
			kbdq.putc = kbdcr2nl;
	}
	duartenable(dp);
	duartbaud(dp, baud);

M power/devhotrod.c => power/devhotrod.c +4 -2
@@ 26,7 26,7 @@ ulong	testbuf[NTESTBUF];
/*
 * If 1, ENABCKSUM causes data transfers to have checksums
 */
#define	ENABCKSUM	0
#define	ENABCKSUM	1

typedef struct Hotrod	Hotrod;



@@ 72,11 72,14 @@ hotsend(Hotrod *h, Hotmsg *m)

	lock(h);
	mp = (Hotmsg**)&h->addr->reqstq[h->wi];
print("send 1 %lux\n", MP2VME(m)); delay(500);
	*mp = (Hotmsg*)MP2VME(m);
print("send 2\n"); delay(500);
	h->wi++;
	if(h->wi >= NRQ)
		h->wi = 0;
	unlock(h);
print("send 3\n"); delay(500);
	return mp;
}



@@ 211,7 214,6 @@ hotrodopen(Chan *c, int omode)
		}
			
		for(;;){
for(;;);
			print("-");
			mem(hp->addr, &hp->addr->ram[(mp->param[0]-0x40000)/sizeof(ulong)], mp->param[1]);
		}

M power/trap.c => power/trap.c +1 -0
@@ 377,6 377,7 @@ notify(Ureg *ur)
		unlock(&u->p->debug);
		return;
	}
	u->p->notepending = 0;
	if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){
		if(u->note[0].flag == NDebug)
			pprint("suicide: %s\n", u->note[0].msg);

M ss/trap.c => ss/trap.c +1 -0
@@ 218,6 218,7 @@ notify(Ureg *ur)
	ulong sp;

	lock(&u->p->debug);
	u->p->notepending = 0;
	if(u->nnote==0){
		unlock(&u->p->debug);
		return;