~kris/9p

9hist

294530301d08ede88bafdbc8f17d34700f11172c — David du Colombier 25 years ago e071331
Plan 9 from Bell Labs 2001-06-22
9 files changed, 530 insertions(+), 59 deletions(-)

M bitsy/clock.c
M bitsy/power.c
M bitsy/screen.c
M pc/devarch.c
M pc/devether.c
M pc/etherelnk3.c
M pc/fns.h
M pc/io.h
M pc/pci.c
M bitsy/clock.c => bitsy/clock.c +1 -0
@@ 30,6 30,7 @@ clockpower(int on)
		timerregs->oier = 1<<0;
		timerregs->osmr[0] = timerregs->oscr + ClockFreq/HZ;
	}
	clockinited = on;
}

void

M bitsy/power.c => bitsy/power.c +50 -35
@@ 19,6 19,7 @@ ulong	powerflag = 0;	/* set to start power-off sequence */

extern void	sa1100_power_resume(void);
extern int		setpowerlabel(void);
extern void	_start(void);
extern Uart	sa1110uart[];

GPIOregs savedgpioregs;


@@ 71,29 72,40 @@ gpiocpy(GPIOregs *to, GPIOregs *from)
	to->direction = from->direction;
}

void	(*restart)(void) = nil;

static void
sa1100_power_off(void)
{
	cacheflush();
	mmuinvalidate();
	mmudisable();

	/* enable wakeup by µcontroller, on/off switch or real-time clock alarm */
	powerregs->pwer =  1 << IRQrtc | 1 << IRQgpio0 | 1 << IRQgpio1;

	/* clear previous reset status */
	resetregs->rcsr =  RCSR_all;

sa1100_power_resume();

	/* disable internal oscillator, float CS lines */
	powerregs->pcfr = PCFR_opde | PCFR_fp | PCFR_fs;
	powerregs->pgsr = 0;
	/* set resume address. The loader jumps to it */
	powerregs->pspr = (ulong)sa1100_power_resume;
//	powerregs->pspr = (ulong)sa1100_power_resume;
//	powerregs->pspr = (ulong)_start;
	/* set lowest clock; delay to avoid resume hangs on fast sa1110 */

	delay(90);
	powerregs->ppcr = 0;
//	powerregs->ppcr = 0;
	delay(90);

	/* set all GPIOs to input mode  */
	gpioregs->direction = 0;
	delay(100);
	/* enter sleep mode */

	powerregs->pmcr = PCFR_suspend;
	for(;;);
}


@@ 109,28 121,6 @@ bitno(ulong x)
	return i;
}

void
onoffintr(Ureg* , void*)
{
	int i;

	/* Power down interrupt comes on power button release.
	 * Act only after button has been released a full 100 ms
	 */

	if (powerflag)
		return;

	for (i = 0; i < 100; i++) {
		delay(1);
		if ((gpioregs->level & GPIO_PWR_ON_i) == 0)
			return;	/* bounced */
	}

	powerflag = 1;
	wakeup(&powerr);
}

int
powerdown(void *)
{


@@ 140,8 130,13 @@ powerdown(void *)
void
deepsleep(void) {
	static int power_pl;
	void *xsp, *xlink;

	power_pl = splhi();
	xsp = getsp();
	xlink = getlink();
	iprint("starting power down, sp = %lux, link = %lux\n", xsp, xlink);
	delay(1000);
	cachewb();
	delay(500);
	if (setpowerlabel()) {


@@ 167,6 162,11 @@ deepsleep(void) {
		iprint("\nresuming execution\n");
//		dumpitall();
		delay(800);
		delay(1000);
		xsp = getsp();
		xlink = getlink();
		iprint("power restored, sp = %lux, link = %lux\n", xsp, xlink);

		splx(power_pl);
		return;
	}


@@ 189,33 189,48 @@ deepsleep(void) {
void
powerkproc(void*)
{
	void *xsp, *xlink;

	for(;;){
		while(powerflag == 0)
			sleep(&powerr, powerdown, 0);


		deepsleep();

		delay(2000);

		powerflag = 0;

		xsp = getsp();
		xlink = getlink();
		iprint("starting power down, sp = %lux, link = %lux\n", xsp, xlink);
		delay(1000);
	}
}

		deepsleep();
void
onoffintr(Ureg* , void*)
{
	int i;

		delay(1000);
		xsp = getsp();
		xlink = getlink();
		iprint("power restored, sp = %lux, link = %lux\n", xsp, xlink);
	/* Power down interrupt comes on power button release.
	 * Act only after button has been released a full 100 ms
	 */

	if (powerflag)
		return;

	for (i = 0; i < 100; i++) {
		delay(1);
		if ((gpioregs->level & GPIO_PWR_ON_i) == 0)
			return;	/* bounced */
	}

	deepsleep();
//	powerflag = 1;
//	wakeup(&powerr);
}

void
powerinit(void)
{
	intrenable(GPIOrising, bitno(GPIO_PWR_ON_i), onoffintr, (void*)0x12344321, "on/off");
	intrenable(GPIOrising, bitno(GPIO_PWR_ON_i), onoffintr, nil, "on/off");
}

void

M bitsy/screen.c => bitsy/screen.c +333 -1
@@ 151,4 151,336 @@ Point		curpos;
int			h, w;
int			drawdebug;

static	ulong	rep(u
static	ulong	rep(ulong, int);
static	void	screenwin(void);
static	void	screenputc(char *buf);
static	void	bitsyscreenputs(char *s, int n);
static	void	scroll(void);

static void
lcdstop(void) {
	lcd->lccr0 &= ~(0<<LEN);	/* disable the LCD */
	while((lcd->lcsr & LDD) == 0)
		delay(10);
	lcdpower(0);
}

static void
lcdinit(void)
{
	/* the following line works because main memory is direct mapped */
	lcd->dbar1 = framebuf->palette;
	lcd->lccr3 = pcd<<PCD | 0<<ACB | 0<<API | 1<<VSP | 1<<HSP | 0<<PCP | 0<<OEP;
	lcd->lccr2 = (Wid-1)<<LPP | vsw<<VSW | efw<<EFW | bfw<<BFW;
	lcd->lccr1 = (Ht-16)<<PPL | hsw<<HSW | elw<<ELW | blw<<BLW;
	lcd->lccr0 = 1<<LEN | 0<<CMS | 0<<SDS | 1<<LDM | 1<<BAM | 1<<ERM | 1<<PAS | 0<<BLE | 0<<DPD | 0<<PDD;
}

void
flipscreen(int ls) {
	if (ls == landscape)
		return;
	if (ls) {
		gscreen->r = Rect(0, 0, Ht, Wid);
		gscreen->clipr = gscreen->r;
		xgdata.bdata = (uchar *)framebuf->pixel;
	} else {
		gscreen->r = Rect(0, 0, Wid, Ht);
		gscreen->clipr = gscreen->r;
		xgdata.bdata = (uchar *)vscreen;
	}
	landscape = ls;
}

void
lcdtweak(Cmdbuf *cmd)
{
	if(cmd->nf < 4)
		return;
	if(*cmd->f[0] == 'h')
		lcd->lccr1 = ((Ht-16)<<PPL)
			| (atoi(cmd->f[1])<<HSW)
			| (atoi(cmd->f[2])<<ELW)
			| (atoi(cmd->f[3])<<BLW);
	if(*cmd->f[0] == 'v')
		lcd->lccr2 = ((Wid-1)<<LPP)
			| (atoi(cmd->f[1])<<VSW)
			| (atoi(cmd->f[2])<<EFW)
			| (atoi(cmd->f[3])<<BFW);
}

void
screenpower(int on)
{
	if (on == 0){
		memmove(savedpalette, framebuf->palette, sizeof framebuf->palette);
		blankscreen(1);
	} else {
		memmove(framebuf->palette, savedpalette, sizeof framebuf->palette);
		blankscreen(0);
	}
}

void
screeninit(void)
{
	int i;

	/* map the lcd regs into the kernel's virtual space */
	lcd = (struct sa1110regs*)mapspecial(LCDREGS, sizeof(struct sa1110regs));;

	framebuf = xspanalloc(sizeof *framebuf, 0x100, 0);

	vscreen = xalloc(sizeof(ushort)*Wid*Ht);

	framebuf->palette[0] = Pal0;

	lcdpower(1);
	lcdinit();

	gscreen = &xgscreen;
	xgdata.ref = 1;
	i = 0;
	if (landscape) {
		xgdata.bdata = (uchar *)framebuf->pixel;
		while (i < Wid*Ht*1/3)	framebuf->pixel[i++] = 0xf800;	/* red */
		while (i < Wid*Ht*2/3)	framebuf->pixel[i++] = 0xffff;	/* white */
		while (i < Wid*Ht*3/3)	framebuf->pixel[i++] = 0x001f;	/* blue */
	} else {
		xgdata.bdata = (uchar *)vscreen;
		while (i < Wid*Ht*1/3)	vscreen[i++] = 0xf800;	/* red */
		while (i < Wid*Ht*2/3)	vscreen[i++] = 0xffff;	/* white */
		while (i < Wid*Ht*3/3)	vscreen[i++] = 0x001f;	/* blue */
		flushmemscreen(gscreen->r);
	}
	memimageinit();
	memdefont = getmemdefont();

	out.pos.x = MINX;
	out.pos.y = 0;
	out.bwid = memdefont->info[' '].width;

	blanktime = 3;	/* minutes */

	screenwin();
	screenputs = bitsyscreenputs;
}

void
flushmemscreen(Rectangle r)
{
	int x, y;
	ulong start, end;

	if (landscape == 0) {
		if (r.min.x <   0) r.min.x = 0;
		if (r.max.x > Wid) r.max.x = Wid;
		if (r.min.y <   0) r.min.y = 0;
		if (r.max.y >  Ht) r.max.y = Ht;
		for (x = r.min.x; x < r.max.x; x++)
			for (y = r.min.y; y < r.max.y; y++)
				framebuf->pixel[(x+1)*Ht-1-y] = gamma[vscreen[y*Wid+x]];
		start = (ulong)&framebuf->pixel[(r.min.x+1)*Ht-1-(r.max.y-1)];
		end = (ulong)&framebuf->pixel[(r.max.x-1+1)*Ht-1-(r.min.y)];
	} else {
		start = (ulong)&framebuf->pixel[r.min.y*Ht + r.min.x];
		end = (ulong)&framebuf->pixel[(r.max.y-1)*Ht + r.max.x - 1];
	}
	cachewbregion(start, end-start);
}

/*
 * export screen to devdraw
 */
uchar*
attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
{
	*r = gscreen->r;
	*d = gscreen->depth;
	*chan = gscreen->chan;
	*width = gscreen->width;
	*softscreen = (landscape == 0);

	return (uchar*)gscreen->data->bdata;
}

void
getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
{
	USED(p, pr, pg, pb);
}

int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	USED(p,r,g,b);
	return 0;
}

void
blankscreen(int blank)
{
	if (blank) {
		lcdpower(0);
	} else {
		lcdpower(1);
		lcdinit();
	}
}

static void
bitsyscreenputs(char *s, int n)
{
	int i;
	Rune r;
	char buf[4];

	if(!islo()) {
		/* don't deadlock trying to print in interrupt */
		if(!canlock(&screenlock))
			return;	
	}
	else
		lock(&screenlock);

	while(n > 0){
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		screenputc(buf);
	}
	unlock(&screenlock);
}

static void
screenwin(void)
{
	Point p, q;
	char *greet;
	Memimage *orange;
	Rectangle r;

	memsetchan(gscreen, RGB16);

	back = memwhite;
	conscol = memblack;

	orange = allocmemimage(Rect(0,0,1,1), RGB16);
	orange->flags |= Frepl;
	orange->clipr = gscreen->r;
	orange->data->bdata[0] = 0x40;
	orange->data->bdata[1] = 0xfd;

	w = memdefont->info[' '].width;
	h = memdefont->height;

	r = insetrect(gscreen->r, 4);

	memimagedraw(gscreen, r, memblack, ZP, memopaque, ZP);
	window = insetrect(r, 4);
	memimagedraw(gscreen, window, memwhite, ZP, memopaque, ZP);

	memimagedraw(gscreen, Rect(window.min.x, window.min.y,
			window.max.x, window.min.y+h+5+6), orange, ZP, nil, ZP);
	freememimage(orange);
	window = insetrect(window, 5);

	greet = " Plan 9 Console ";
	p = addpt(window.min, Pt(10, 0));
	q = memsubfontwidth(memdefont, greet);
	memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
	flushmemscreen(r);
	window.min.y += h+6;
	curpos = window.min;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;
}

static void
screenputc(char *buf)
{
	Point p;
	int w, pos;
	Rectangle r;
	static int *xp;
	static int xbuf[256];

	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
		xp = xbuf;

	switch(buf[0]) {
	case '\n':
		if(curpos.y+h >= window.max.y)
			scroll();
		curpos.y += h;
		screenputc("\r");
		break;
	case '\r':
		xp = xbuf;
		curpos.x = window.min.x;
		break;
	case '\t':
		p = memsubfontwidth(memdefont, " ");
		w = p.x;
		if(curpos.x >= window.max.x-4*w)
			screenputc("\n");

		pos = (curpos.x-window.min.x)/w;
		pos = 4-(pos%4);
		*xp++ = curpos.x;
		r = Rect(curpos.x, curpos.y, curpos.x+pos*w, curpos.y + h);
		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min);
		flushmemscreen(r);
		curpos.x += pos*w;
		break;
	case '\b':
		if(xp <= xbuf)
			break;
		xp--;
		r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min);
		flushmemscreen(r);
		curpos.x = *xp;
		break;
	case '\0':
		break;
	default:
		p = memsubfontwidth(memdefont, buf);
		w = p.x;

		if(curpos.x >= window.max.x-w)
			screenputc("\n");

		*xp++ = curpos.x;
		r = Rect(curpos.x, curpos.y, curpos.x+w, curpos.y + h);
		memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min);
		memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
		flushmemscreen(r);
		curpos.x += w;
	}
}

static void
scroll(void)
{
	int o;
	Point p;
	Rectangle r;

	o = 8*h;
	r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
	p = Pt(window.min.x, window.min.y+o);
	memimagedraw(gscreen, r, gscreen, p, nil, p);
	flushmemscreen(r);
	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
	memimagedraw(gscreen, r, back, ZP, nil, ZP);
	flushmemscreen(r);

	curpos.y -= o;
}

M pc/devarch.c => pc/devarch.c +55 -0
@@ 11,6 11,7 @@ typedef struct IOMap IOMap;
struct IOMap
{
	IOMap	*next;
	int		reserved;
	char	tag[13];
	ulong	start;
	ulong	end;


@@ 103,6 104,54 @@ ioinit(void)

	// a dummy entry at 2^16
	ioalloc(0x10000, 1, 0, "dummy");
	ioalloc(0x1000, 1, 0, "dummy");
}

// Reserve a range to be ioalloced later.  This is in particular useful for exchangable cards, such
// as pcmcia and cardbus cards.
int
ioreserve(int port, int size, int align, char *tag)
{
	IOMap *m, **l;
	int i;

	lock(&iomap);
	// find a free port above 0x400 and below 0x1000
	port = 0x400;
	for(l = &iomap.m; *l; l = &(*l)->next){
		m = *l;
		if (m->start < 0x400) continue;
		i = m->start - port;
		if(i > size)
			break;
		if(align > 0)
			port = ((port+align-1)/align)*align;
		else
			port = m->end;
	}
	if(*l == nil){
		unlock(&iomap);
		return -1;
	}
	m = iomap.free;
	if(m == nil){
		print("ioalloc: out of maps");
		unlock(&iomap);
		return port;
	}
	iomap.free = m->next;
	m->next = *l;
	m->start = port;
	m->end = port + size;
	m->reserved = 1;
	strncpy(m->tag, tag, sizeof(m->tag));
	m->tag[sizeof(m->tag)-1] = 0;
	*l = m;

	archdir[0].qid.vers++;

	unlock(&iomap);
	return m->start;
}

//


@@ 121,6 170,7 @@ ioalloc(int port, int size, int align, char *tag)
		port = 0x400;
		for(l = &iomap.m; *l; l = &(*l)->next){
			m = *l;
			if (m->start < 0x400) continue;
			i = m->start - port;
			if(i > size)
				break;


@@ 144,6 194,11 @@ ioalloc(int port, int size, int align, char *tag)
			m = *l;
			if(m->end <= port)
				continue;
			if(m->reserved && m->start == port && m->end == port + size) {
				m->reserved = 0;
				unlock(&iomap);
				return m->start;
			}
			if(m->start >= port+size)
				break;
			unlock(&iomap);

M pc/devether.c => pc/devether.c +1 -0
@@ 354,6 354,7 @@ etherreset(void)
	int i, n, ctlrno;
	char name[32], buf[128];

	print("Searching for ethernet devices\n"); 
	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if(ether == 0)
			ether = malloc(sizeof(Ether));

M pc/etherelnk3.c => pc/etherelnk3.c +51 -12
@@ 167,6 167,7 @@ enum {						/* Window 0 - setup */
	auiAvailable9		= 0x2000,
						/* EepromCommand bits */
	EepromReadRegister	= 0x0080,
	EepromRead8bRegister	= 0x0230,
	EepromBusy		= 0x8000,
};



@@ 571,6 572,13 @@ multicast(void* arg, uchar *addr, int on)
	COMMAND(port, SetRxFilter, filter);
}

/* On the 575B and C, interrupts need to be acknowledged in CardBus memory space */
static void
intrack3c575(ulong *cbfns)
{
	cbfns[1] = 0x8000;
}

static void
attach(Ether* ether)
{


@@ 604,10 612,13 @@ attach(Ether* ether)
	}
	COMMAND(port, SetIndicationEnable, x);
	COMMAND(port, SetInterruptEnable, x);

	COMMAND(port, RxEnable, 0);
	COMMAND(port, TxEnable, 0);

	if (ether->mem)
		/* This must be a cardbus card.  Acknowledge the interrupt */
		intrack3c575(KADDR(ether->mem));
		
	/*
	 * Prime the busmaster channel for receiving directly into a
	 * receive packet buffer if necessary.


@@ 1127,6 1138,8 @@ interrupt(Ureg*, void* arg)
			panic("#l%d: interrupt mask 0x%uX\n", ether->ctlrno, status);

		COMMAND(port, AcknowledgeInterrupt, interruptLatch);
		if (ether->mem) intrack3c575((ulong *)KADDR(ether->mem));

	}while((status = STATUS(port)) & (interruptMask|interruptLatch));

	if(ctlr->busmaster == 2)


@@ 1220,11 1233,13 @@ typedef struct Adapter {
	int	port;
	int	irq;
	int	tbdf;
	int	did;
	ulong cbfns;
} Adapter;
static Block* adapter;

static void
tcmadapter(int port, int irq, int tbdf)
tcmadapter(int port, int irq, int tbdf, int did, ulong cbfns)
{
	Block *bp;
	Adapter *ap;


@@ 1236,6 1251,8 @@ tcmadapter(int port, int irq, int tbdf)
	ap->port = port;
	ap->irq = irq;
	ap->tbdf = tbdf;
	ap->did = did;
	ap->cbfns = cbfns;

	bp->next = adapter;
	adapter = bp;


@@ 1385,7 1402,7 @@ tcm509isa(void)
		COMMAND(port, AcknowledgeInterrupt, 0xFF);

		irq = (ins(port+ResourceConfig)>>12) & 0x0F;
		tcmadapter(port, irq, BUSUNKNOWN);
		tcmadapter(port, irq, BUSUNKNOWN, 0, 0);
	}
}



@@ 1431,7 1448,7 @@ tcm5XXeisa(void)
		COMMAND(port, AcknowledgeInterrupt, 0xFF);

		irq = (ins(port+ResourceConfig)>>12) & 0x0F;
		tcmadapter(port, irq, BUSUNKNOWN);
		tcmadapter(port, irq, BUSUNKNOWN, 0, 0);
	}
}



@@ 1443,6 1460,8 @@ tcm59Xpci(void)

	p = nil;
	while(p = pcimatch(p, 0x10B7, 0)){
		ulong bar;

		/*
		 * Not prepared to deal with memory-mapped
		 * devices yet.


@@ 1459,7 1478,14 @@ tcm59Xpci(void)
		while(STATUS(port) & commandInProgress)
			;

		tcmadapter(port, irq, p->tbdf);
		bar = 0;
		if (p->did == 0x5157) {
			/* Map the CardBus functions */
			bar = pcicfgr32(p, PciBAR2);
			print("tcmp59Xpci: CardBus functions at %.8uX\n", bar & ~KZERO);
		}

		tcmadapter(port, irq, p->tbdf, p->did, bar);
		pcisetbme(p);
	}
}


@@ 1711,12 1737,12 @@ autoselect(int port, int xcvr, int is9)
}

static int
eepromdata(int port, int offset)
eepromdata(int did, int port, int offset)
{
	COMMAND(port, SelectRegisterWindow, Wsetup);
	while(EEPROMBUSY(port))
		;
	EEPROMCMD(port, EepromReadRegister, offset);
	EEPROMCMD(port, (did == 0x5157)? EepromRead8bRegister: EepromReadRegister, offset);
	while(EEPROMBUSY(port))
		;
	return EEPROMDATA(port);


@@ 1750,13 1776,16 @@ etherelnk3reset(Ether* ether)
	 * otherwise the ports must match.
	 */
	port = 0;
	did = 0;
	bpp = &adapter;
	for(bp = *bpp; bp; bp = bp->next){
		ap = (Adapter*)bp->rp;
		if(ether->port == 0 || ether->port == ap->port){
			port = ap->port;
			did = ap->did;
			ether->irq = ap->irq;
			ether->tbdf = ap->tbdf;
			ether->mem = ap->cbfns;
			*bpp = bp->next;
			freeb(bp);
			break;


@@ 1770,7 1799,7 @@ etherelnk3reset(Ether* ether)
	 * Read the DeviceID from the EEPROM, it's at offset 0x03,
	 * and do something depending on capabilities.
	 */
	switch(did = eepromdata(port, 0x03)){
	switch(did = eepromdata(did, port, 0x03)){

	case 0x9000:
	case 0x9001:


@@ 1779,6 1808,7 @@ etherelnk3reset(Ether* ether)
	case 0x9051:
	case 0x9055:
	case 0x9200:
	case 0x5157:		/* 3C575 Cyclone */
		if(BUSTYPE(ether->tbdf) != BusPCI)
			goto buggery;
		busmaster = 2;


@@ 1822,7 1852,7 @@ etherelnk3reset(Ether* ether)
	memset(ea, 0, Eaddrlen);
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
		for(i = 0; i < Eaddrlen/2; i++){
			x = eepromdata(port, i);
			x = eepromdata(did, port, i);
			ether->ea[2*i] = x>>8;
			ether->ea[2*i+1] = x;
		}


@@ 1854,10 1884,18 @@ etherelnk3reset(Ether* ether)
	/*
	 * forgive me, but i am weak
	 */
	if(did == 0x9055 || did == 0x9200){
	if(did == 0x9055 || did == 0x9200 || did == 0x5157){
		xcvr = xcvrMii;
		txrxreset(port);
		XCVRDEBUG("905[BC] reset ops 0x%uX\n", ins(port+ResetOp905B));
		if (did == 0x5157) {
			ushort reset_opts;

			COMMAND(port, SelectRegisterWindow, Wstation);
			reset_opts = ins(port + ResetOp905B);
			reset_opts |= 0x0010;		/* Invert LED */
			outs(port + ResetOp905B, reset_opts);
		}
	}
	else if(xcvr & autoSelect)
		xcvr = autoselect(port, xcvr, rxstatus9);


@@ 1870,7 1908,7 @@ etherelnk3reset(Ether* ether)
		 * Quick hack.
		scanphy(port);
		 */
		phyaddr = 24;
		phyaddr = (did == 0x5157)? 0: 24;
		for(i = 0; i < 7; i++)
			XCVRDEBUG(" %2.2uX", miir(port, phyaddr, i));
			XCVRDEBUG("\n");


@@ 2016,7 2054,7 @@ etherelnk3reset(Ether* ether)
		 * until the whole packet has been received.
		 */
		ctlr->upenabled = 1;
		x = eepromdata(port, 0x0F);
		x = eepromdata(did, port, 0x0F);
		if(!(x & 0x01))
			outl(port+PktStatus, upRxEarlyEnable);



@@ 2072,4 2110,5 @@ etherelnk3link(void)
{
	addethercard("elnk3",  etherelnk3reset);
	addethercard("3C509",  etherelnk3reset);
	addethercard("3C575", etherelnk3reset);
}

M pc/fns.h => pc/fns.h +4 -0
@@ 6,6 6,7 @@ Dirtab*	addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,v
//void	addscsilink(char*, Scsiio (*)(int, ISAConf*));
void	archinit(void);
void	bootargs(ulong);
void cbinit(void);
vlong	checkcycintr(Ureg*, void*);
int	cistrcmp(char*, char*);
int	cistrncmp(char*, char*, int);


@@ 59,6 60,7 @@ void	iofree(int);
void	ioinit(void);
int	iounused(int, int);
int	ioalloc(int, int, int, char*);
int	ioreserve(int, int, int, char*);
int	iprint(char*, ...);
int	isaconfig(char*, int, ISAConf*);
void	kbdinit(void);


@@ 83,6 85,8 @@ void	outs(int, ushort);
void	outss(int, void*, int);
void	outl(int, ulong);
void	outsl(int, void*, int);
int	pciscan(int, Pcidev **);
ulong pcibarsize(Pcidev *, int);
int	pcicfgr8(Pcidev*, int);
int	pcicfgr16(Pcidev*, int);
int	pcicfgr32(Pcidev*, int);

M pc/io.h => pc/io.h +4 -0
@@ 191,6 191,10 @@ struct Pcidev
		int	size;
	} mem[6];

	struct {
		ulong	bar;	
		int	size;
	} rom;
	uchar	intl;			/* interrupt line */

	Pcidev*	list;

M pc/pci.c => pc/pci.c +31 -11
@@ 57,7 57,7 @@ enum
};

static Lock pcicfglock;
static Lock pcicfginitlock;
static QLock pcicfginitlock;
static int pcicfgmode = -1;
static int pcimaxbno = 7;
static int pcimaxdno;


@@ 359,7 359,7 @@ pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg)
}

static int
pciscan(int bno, Pcidev** list)
pcilscan(int bno, Pcidev** list)
{
	Pcidev *p, *head, *tail;
	int dno, fno, i, hdt, l, maxfno, maxubn, rno, sbn, tbdf, ubn;


@@ 482,20 482,31 @@ pciscan(int bno, Pcidev** list)
			l = (MaxUBN<<16)|(sbn<<8)|bno;
			pcicfgw32(p, PciPBN, l);
			pcicfgw16(p, PciSPSR, 0xFFFF);
			maxubn = pciscan(sbn, &p->bridge);
			maxubn = pcilscan(sbn, &p->bridge);
			l = (maxubn<<16)|(sbn<<8)|bno;

			pcicfgw32(p, PciPBN, l);
		}
		else {
			maxubn = ubn;
			pciscan(sbn, &p->bridge);
			pcilscan(sbn, &p->bridge);
		}
	}

	return maxubn;
}

int
pciscan(int bno, Pcidev **list)
{
	int ubn;

	qlock(&pcicfginitlock);
	ubn = pcilscan(bno, list);
	qunlock(&pcicfginitlock);
	return ubn;
}

static void
pcicfginit(void)
{


@@ 504,7 515,7 @@ pcicfginit(void)
	Pcidev **list;
	ulong mema, ioa;

	lock(&pcicfginitlock);
	qlock(&pcicfginitlock);
	if(pcicfgmode != -1)
		goto out;



@@ 543,7 554,7 @@ pcicfginit(void)

	list = &pciroot;
	for(bno = 0; bno <= pcimaxbno; bno++) {
		bno = pciscan(bno, list);
		bno = pcilscan(bno, list);
		while(*list)
			list = &(*list)->link;
	}


@@ 573,11 584,12 @@ pcicfginit(void)
		pcibusmap(pciroot, &mema, &ioa, 1);
		DBG("Sizes2: mem=%lux io=%lux\n", mema, ioa);
	
		unlock(&pcicfginitlock);
		qunlock(&pcicfginitlock);
		return;
	}
out:
	unlock(&pcicfginitlock);
	qunlock(&pcicfginitlock);
	cbinit();
}

static int


@@ 785,8 797,8 @@ pcimatchtbdf(int tbdf)
	return pcidev;
}

void
pcihinv(Pcidev* p)
static void
pcilhinv(Pcidev* p)
{
	int i;
	Pcidev *t;


@@ 819,7 831,15 @@ pcihinv(Pcidev* p)
		if(p->bridge != nil)
			pcihinv(p->bridge);
		p = p->link;
	}
	}	
}

void
pcihinv(Pcidev* p)
{
	qlock(&pcicfginitlock);
	pcilhinv(p);
	qunlock(&pcicfginitlock);
}

void