~kris/9p

9hist

c7d3d963bc8253e3d35beddbff98aacea2a16e03 — David du Colombier 25 years ago c188ee7
Plan 9 from Bell Labs 2000-11-18
A bitsy/devpcmcia.c => bitsy/devpcmcia.c +355 -0
@@ 0,0 1,355 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "io.h"

static PCMslot	slot[2];
int nslot = 2;

struct {
	Ref;
} pcmcia;

enum
{
	Qdir,
	Qmem,
	Qattr,
	Qctl,

	Nents = 3,
};

#define SLOTNO(c)	((c->qid.path>>8)&0xff)
#define TYPE(c)		(c->qid.path&0xff)
#define QID(s,t)	(((s)<<8)|(t))

static int
pcmgen(Chan *c, Dirtab *, int , int i, Dir *dp)
{
	int slotno;
	Qid qid;
	long len;
	PCMslot *pp;
	char name[NAMELEN];

	if(i == DEVDOTDOT){
		devdir(c, (Qid){CHDIR, 0}, "#y", 0, eve, 0555, dp);
		return 1;
	}

	if(i >= Nents*nslot)
		return -1;

	slotno = i/Nents;
	pp = slot + slotno;
	len = 0;
	switch(i%Nents){
	case 0:
		qid.path = QID(slotno, Qmem);
		sprint(name, "pcm%dmem", slotno);
		len = pp->memlen;
		break;
	case 1:
		qid.path = QID(slotno, Qattr);
		sprint(name, "pcm%dattr", slotno);
		len = pp->memlen;
		break;
	case 2:
		qid.path = QID(slotno, Qctl);
		sprint(name, "pcm%dctl", slotno);
		break;
	}
	qid.vers = 0;
	devdir(c, qid, name, len, eve, 0660, dp);
	return 1;
}

static void
slotinfo(void)
{
	ulong x = gpioregs->level;

	if(x & GPIO_OPT_IND_i){
		/* no expansion pack */
		slot[0].occupied = 0;
		slot[1].occupied = 0;
	} else {
		slot[0].occupied = (x & GPIO_CARD_IND0_i) == 0;
		slot[1].occupied = (x & GPIO_CARD_IND1_i) == 0;
	}
}

static void
increfp(PCMslot *pp)
{
	if(incref(&pcmcia) == 1)
		exppackpower(1);
	lock(pp);
	if(pp->ref++ == 0)
		;
	unlock(pp);
	slotinfo();
}
static void
decrefp(PCMslot *pp)
{
	slotinfo();
	lock(pp);
	if(pp->ref-- == 1)
		;
	unlock(pp);
	if(decref(&pcmcia) == 0)
		exppackpower(0);
}

/*
 *  get a map for pc card region, return corrected len
 */
PCMmap*
pcmmap(int slotno, ulong, int, int attr)
{
	if(slotno > nslot)
		panic("pcmmap");
	if(attr)
		return &slot[slotno].attrmap;
	else
		return &slot[slotno].memmap;
}
void
pcmunmap(int, PCMmap*)
{
}

/*
 *  map in the space for the cards
 */
static void
pcmciareset(void)
{
	int j;
	PCMslot *pp;

	for(j = 0; j < nslot; j++){
		pp = &slot[j];
		pp->slotno = j;
		pp->memlen = 64*OneMeg;
		pp->msec = ~0;
		pp->verstr[0] = 0;

		pp->mem = mapmem(j == 0 ? PYHSPCM0MEM : PYHSPCM1MEM, 64*OneMeg);
		pp->memmap.ca = 0;
		pp->memmap.cea = 64*MB;
		pp->memmap.isa = (ulong)pp->mem;
		pp->memmap.len = 64*OneMeg;
		pp->memmap.attr = 0;

		pp->attr = mapmem(j == 0 ? PYHSPCM0ATTR : PYHSPCM1ATTR, OneMeg);
		pp->attrmap.ca = 0;
		pp->attrmap.cea = 64*MB;
		pp->attrmap.isa = (ulong)pp->attr;
		pp->attrmap.len = OneMeg;
		pp->attrmap.attr = 1;

		pp->regs = mapspecial(j == 0 ? PHYSPCM0REGS : PHYSPCM1REGS, 32*1024);
	}
}

static Chan*
pcmciaattach(char *spec)
{
	return devattach('y', spec);
}

static int
pcmciawalk(Chan *c, char *name)
{
	return devwalk(c, name, 0, 0, pcmgen);
}

static void
pcmciastat(Chan *c, char *db)
{
	devstat(c, db, 0, 0, pcmgen);
}

static Chan*
pcmciaopen(Chan *c, int omode)
{
	if(c->qid.path == CHDIR){
		if(omode != OREAD)
			error(Eperm);
	} else
		increfp(slot + SLOTNO(c));
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

static void
pcmciaclose(Chan *c)
{
	if(c->flag & COPEN)
		if(c->qid.path != CHDIR)
			decrefp(slot+SLOTNO(c));
}

/* a memmove using only bytes */
static void
memmoveb(uchar *to, uchar *from, int n)
{
	while(n-- > 0)
		*to++ = *from++;
}

/* a memmove using only shorts & bytes */
static void
memmoves(uchar *to, uchar *from, int n)
{
	ushort *t, *f;

	if((((ulong)to) & 1) || (((ulong)from) & 1) || (n & 1)){
		while(n-- > 0)
			*to++ = *from++;
	} else {
		n = n/2;
		t = (ushort*)to;
		f = (ushort*)from;
		while(n-- > 0)
			*t++ = *f++;
	}
}

static long
pcmread(void *a, long n, ulong off, uchar *start, ulong len)
{
	if(off > len)
		return 0;
	if(off + n > len)
		n = len - off;
	memmoves(a, start+off, n);
	return n;
}

static long
pcmctlread(void *a, long n, ulong off, PCMslot *pp)
{
	char *p, *buf, *e;

	buf = p = malloc(READSTR);
	if(waserror()){
		free(buf);
		nexterror();
	}
	e = p + READSTR;

	buf[0] = 0;
	if(pp->occupied){
		p = seprint(p, e, "occupied\n");
		if(pp->verstr[0])
			p = seprint(p, e, "version %s\n", pp->verstr);
	}
	USED(p);

	n = readstr(off, a, n, buf);
	free(buf);
	poperror();
	return n;
}

static long
pcmciaread(Chan *c, void *a, long n, vlong off)
{
	PCMslot *pp;
	ulong offset = off;

	pp = slot + SLOTNO(c);

	switch(TYPE(c)){
	case Qdir:
		return devdirread(c, a, n, 0, 0, pcmgen);
	case Qmem:
		if(!pp->occupied)
			error(Eio);
		return pcmread(a, n, offset, pp->mem, 64*OneMeg);
	case Qattr:
		if(!pp->occupied)
			error(Eio);
		return pcmread(a, n, offset, pp->attr, OneMeg);
	case Qctl:
		return pcmctlread(a, n, offset, pp);
	}
	error(Ebadarg);
	return -1;	/* not reached */
}

static long
pcmwrite(void *a, long n, ulong off, uchar *start, ulong len)
{
	if(off > len)
		error(Eio);
	if(off + n > len)
		error(Eio);
	memmoveb(start+off, a, n);
	return n;
}

static long
pcmctlwrite(char *p, long n, ulong off, PCMslot *pp)
{
	/* nothing yet */
	USED(p, n, off, pp);
	error(Ebadarg);
	return 0;
}

static long
pcmciawrite(Chan *c, void *a, long n, vlong off)
{
	PCMslot *pp;
	ulong offset = off;

	pp = slot + SLOTNO(c);

	switch(TYPE(c)){
	case Qmem:
		if(!pp->occupied)
			error(Eio);
		return pcmwrite(a, n, offset, pp->mem, 64*OneMeg);
	case Qattr:
		if(!pp->occupied)
			error(Eio);
		return pcmwrite(a, n, offset, pp->attr, OneMeg);
	case Qctl:
		if(!pp->occupied)
			error(Eio);
		return pcmctlwrite(a, n, offset, pp);
	}
	error(Ebadarg);
	return -1;	/* not reached */
}

Dev pcmciadevtab = {
	'y',
	"pcmcia",

	pcmciareset,
	devinit,
	pcmciaattach,
	devclone,
	pcmciawalk,
	pcmciastat,
	pcmciaopen,
	devcreate,
	pcmciaclose,
	pcmciaread,
	devbread,
	pcmciawrite,
	devbwrite,
	devremove,
	devwstat,
};

M bitsy/devuda1341.c => bitsy/devuda1341.c +151 -29
@@ 43,13 43,15 @@ static int debug = 1;
/* 
 * L3 setup and hold times (expressed in µs)
 */
#define L3_DataSetupTime	1		/* 190 ns */
#define L3_DataHoldTime		1		/*  30 ns */
#define L3_ModeSetupTime	1		/* 190 ns */
#define L3_ModeHoldTime		1		/* 190 ns */
#define L3_ClockHighTime	10		/* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
#define L3_ClockLowTime		10		/* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
#define L3_HaltTime			1		/* 190 ns */
enum {
	L3_DataSetupTime =	1,		/* 190 ns */
	L3_DataHoldTime =	1,		/*  30 ns */
	L3_ModeSetupTime =	1,		/* 190 ns */
	L3_ModeHoldTime =	1,		/* 190 ns */
	L3_ClockHighTime =	10,		/* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
	L3_ClockLowTime =	10,		/* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
	L3_HaltTime =		1,		/* 190 ns */
};

/* UDA 1341 Registers */
enum {


@@ 73,10 75,13 @@ enum {
/*
 * UDA1341 L3 address and command types
 */
#define UDA1341_DATA0	0
#define UDA1341_DATA1	1
#define UDA1341_STATUS	2
#define UDA1341_L3Addr	0x14

enum {
	UDA1341_DATA0 =	0,
	UDA1341_DATA1,
	UDA1341_STATUS,
	UDA1341_L3Addr = 0x14,
};

typedef struct	AQueue	AQueue;
typedef struct	Buf	Buf;


@@ 122,6 127,7 @@ audiodir[] =
struct	Buf
{
	uchar*	virt;
	ulong	phys;
	uint	nbytes;
};



@@ 137,6 143,8 @@ struct	IOstate
	volatile Buf	*current;		/* next dma to finish */
	volatile Buf	*next;			/* next candidate for dma */
	volatile Buf	*filling;		/* buffer being filled */
/* just be be cute (and to have defines like linux, a real operating system) */
#define emptying filling
};

static	struct


@@ 172,7 180,7 @@ static	struct
} volumes[] =
{
[Vaudio]	"audio",	Fout|Fmono,		50,	50,
[Vmic]		"mic",		Fin,			 0,	 0,
[Vmic]		"mic",		Fin|Fmono,		 0,	 0,

[Vtreb]		"treb",		Fout|Fmono,		50,	50,
[Vbass]		"bass",		Fout|Fmono, 	50,	50,


@@ 379,8 387,10 @@ bufinit(IOstate *b)
	int i;

	if (debug) print("#A: bufinit\n");
	for (i = 0; i < Nbuf; i++)
	for (i = 0; i < Nbuf; i++) {
		b->buf[i].virt = xalloc(Bufsize);
		b->buf[i].phys = PADDR(b->buf[i].virt);
	}
	b->bufinit = 1;
};



@@ 399,11 409,18 @@ setempty(IOstate *b)
}

static int
audioqnotempty(void *x)
{
	IOstate *s = x;

	return dmaidle(s->dma) || s->emptying != s->next;
}

static int
audioqnotfull(void *x)
{
	IOstate *s = x;

	/* called with lock */
	return dmaidle(s->dma) || s->filling != s->current;
}



@@ 418,8 435,12 @@ uchar	status1	= 0x80;
uchar	data00	= 0x00;		/* volume control, bits 0 – 5 */
uchar	data01	= 0x40;
uchar	data02	= 0x90;
ushort	data0e0	= 0xe0c0;
ushort	data0e1	= 0xe0c1;
ushort	data0e2	= 0xf2c2;
ushort	data0e4	= 0xf3c4;
/* there is no data0e3 */
ushort	data0e4	= 0xe0c4;
ushort	data0e5	= 0xe0c5;
ushort	data0e6	= 0xe3c6;

static void


@@ 459,7 480,6 @@ enable(void)
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1);
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e2, 2);
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 );
	L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e6, 2 );

	if (debug) {


@@ 495,6 515,22 @@ mxvolume(void) {
	if(audio.amode & Aread){
		left = audio.livol;
		right = audio.rivol;
		if (left[Vmic]+right[Vmic] == 0) {
			/* Turn on automatic gain control (AGC) */
			data0e4 |= 0x1000;
			L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 );
		} else {
			int v;
			/* Turn on manual gain control */
			v = ((left[Vmic]+right[Vmic])*0x7f/200)&0x7f;
			data0e4 &= ~0x1300;
			data0e5 &= ~0x1f00;
			data0e4 |= (v & 0x3)<<8;
			data0e5 |= (v & 0x7c)<<6;
			L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 );
			L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e5, 2 );
		}
		
	}
	if(audio.amode & Awrite){
		left = audio.lovol;


@@ 576,7 612,7 @@ sendaudio(IOstate *s) {
	ilock(&s->ilock);
	while (s->next != s->filling) {
		assert(s->next->nbytes);
		if ((n = dmastart(s->dma, s->next->virt, s->next->nbytes)) == 0) {
		if ((n = dmastart(s->dma, s->next->phys, s->next->nbytes)) == 0) {
			iostats.faildma++;
			break;
		}


@@ 599,6 635,36 @@ sendaudio(IOstate *s) {
}

static void
recvaudio(IOstate *s) {
	/* interrupt routine calls this too */
	int n;

	if (debug > 1) print("#A: recvaudio\n");
	ilock(&s->ilock);
	while (s->next != s->emptying) {
		assert(s->next->nbytes == 0);
		if ((n = dmastart(s->dma, s->next->phys, Bufsize)) == 0) {
			iostats.faildma++;
			break;
		}
		iostats.totaldma++;
		switch (n) {
		case 1:
			iostats.idledma++;
			break;
		case 3:
			iostats.faildma++;
			break;
		}
		if (debug > 1) print("#A: dmastart @%p\n", s->next);
		s->next++;
		if (s->next == &s->buf[Nbuf])
			s->next = &s->buf[0];
	}
	iunlock(&s->ilock);
}

static void
audiointr(void *x, ulong ndma) {
	IOstate *s = x;



@@ 610,6 676,15 @@ audiointr(void *x, ulong ndma) {
			s->current = &s->buf[0];
		if (ndma > 0)
			sendaudio(s);
	} else if (s == &audio.i) {
		/* Only interrupt routine touches s->current */
		if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current);
		s->current->nbytes = Bufsize;
		s->current++;
		if (s->current == &s->buf[Nbuf])
			s->current = &s->buf[0];
		if (ndma > 0)
			recvaudio(s);
	}
	wakeup(&s->vous);
}


@@ 667,10 742,10 @@ audioopen(Chan *c, int omode)
			/* read */
			audio.amode |= Aread;
			if(audio.i.bufinit == 0)
				bufinit(&audio.i);
			setempty(&audio.i);
				bufinit(s);
			setempty(s);
			s->chan = c;
			s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o);
			s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s);
		}
		if (omode & 0x2) {
			outenable();


@@ 722,15 797,14 @@ audioclose(Chan *c)
				nexterror();
			}
			if (audio.o.chan == c) {
				/* closing the write end */
				audio.amode &= ~Awrite;
				s = &audio.o;
				qlock(s);
				if(waserror()){
					qunlock(s);
					nexterror();
				}
				/* closing the write end */
				audio.amode &= ~Awrite;

				if (s->filling->nbytes) {
					/* send remaining partial buffer */
					s->filling++;


@@ 749,8 823,18 @@ audioclose(Chan *c)
			if (audio.i.chan == c) {
				/* closing the read end */
				audio.amode &= ~Aread;
				s = &audio.i;
				qlock(s);
				if(waserror()){
					qunlock(s);
					nexterror();
				}
				dmawait(s->dma);
				indisable();
				setempty(&audio.i);
				setempty(s);
				dmafree(s->dma);
				qunlock(s);
				poperror();
			}
			if (audio.amode == 0) {
				/* turn audio off */


@@ 775,26 859,62 @@ audioread(Chan *c, void *v, long n, vlong off)
	char buf[300];
	int j;
	ulong offset = off;
	char *a;
	char *p;
	IOstate *s;

	n0 = n;
	a = v;
	p = v;
	switch(c->qid.path & ~CHDIR) {
	default:
		error(Eperm);
		break;

	case Qdir:
		return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
		return devdirread(c, p, n, audiodir, nelem(audiodir), devgen);

	case Qaudio:
		if (debug > 1) print("#A: read %ld\n", n);
		if((audio.amode & Aread) == 0)
			error(Emode);
		s = &audio.o;
		qlock(s);
		if(waserror()){
			qunlock(s);
			nexterror();
		}
		while(n > 0) {
			/* wait if dma in progress */
			while (!dmaidle(s->dma) && s->emptying == s->next) {
				if (debug > 1) print("#A: sleep\n");
				sleep(&s->vous, audioqnotempty, s);
			}

			m = Bufsize - s->emptying->nbytes;
			if(m > n)
				m = n;
			memmove(p, s->emptying->virt + s->emptying->nbytes, m);

			s->emptying->nbytes -= m;
			n -= m;
			p += m;
			if(s->emptying->nbytes == 0) {
				if (debug > 1) print("#A: emptied @%p\n", s->emptying);
				s->emptying++;
				if (s->emptying == &s->buf[Nbuf])
					s->emptying = s->buf;
				sendaudio(s);
			}
		}
		poperror();
		qunlock(s);
		break;
		break;

	case Qstatus:
		buf[0] = 0;
		snprint(buf, sizeof(buf), "bytes %lud\ntime %lld\n",
			audio.totcount, audio.tottime);
		return readstr(offset, a, n, buf);
		return readstr(offset, p, n, buf);

	case Qvolume:
		j = 0;


@@ 835,7 955,7 @@ audioread(Chan *c, void *v, long n, vlong off)
			}
			j += snprint(buf+j, sizeof(buf)-j, "\n");
		}
		return readstr(offset, a, n, buf);
		return readstr(offset, p, n, buf);
	}
	return n0-n;
}


@@ 874,6 994,8 @@ audiowrite(Chan *c, void *vp, long n, vlong)
			 */
			if(field[i][0] >= '0' && field[i][0] <= '9') {
				m = strtoul(field[i], 0, 10);
				if (m < 0 || m > 100) 
					error(Evolume);
				if(left && out)
					audio.lovol[v] = m;
				if(left && in)

M bitsy/fns.h => bitsy/fns.h +10 -3
@@ 15,9 15,12 @@ void	clockinit(void);
void	delay(int);
void	µdelay(int);
void	dmainit(void);
void	egpiobits(ulong, int);
void	evenaddr(ulong);
void	exppackpower(int);
void	flashprogpower(int);
void	flushmmu(void);
int		fpiarm(Ureg *ur);
int	fpiarm(Ureg *ur);
char*	getconf(char*);
ulong	getfar(void);
ulong	getfsr(void);


@@ 30,6 33,7 @@ void	intrenable(int, void (*)(Ureg*, void*), void*, char*);
int	iprint(char*, ...);
void	irpower(int);
void	lcdpower(int);
void*	mapmem(ulong, int);
void	mappedIvecEnable(void);
void	mappedIvecDisable(void);
void*	mapspecial(ulong, int);


@@ 39,9 43,12 @@ void	mmuenable(void);
void	mmudisable(void);
void	mmuinvalidate(void);
void	mmuinvalidateaddr(ulong);
ulong	mmu_kaddr(ulong);
ulong	mmu_paddr(ulong);
int	µcputc(Queue*, int);
void	noted(Ureg*, ulong);
int	notify(Ureg*);
int	pcmcistuple(int, int, int, void*, int);
void	penbutton(int, int);
void	pentrackxy(int x, int y);
#define	procrestore(p)


@@ 74,9 81,9 @@ int	unsac(uchar*, uchar*, int, int);
void	vectors(void);
void	vtable(void);
void	wbflush(void);
#define KADDR(a) (void*)mmu_kaddr((ulong)(a))
#define PADDR(a) mmu_paddr((ulong)(a))

#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
#define KADDR(a)	((void*)((ulong)(a)|KZERO))
#define PADDR(a)	((ulong)(a))

#define	dcflush(a, b)

M bitsy/io.h => bitsy/io.h +91 -1
@@ 76,7 76,8 @@ enum
	GPIO_COM_CTS_i=		1<<25,	/* CTS from UART3 */
	GPIO_COM_RTS_o=		1<<26,	/* RTS to UART3 */
	GPIO_OPT_IND_i=		1<<27,	/* expansion pack inserted */
/* Peripheral Unit GPIO pin assignments: */

/* Peripheral Unit GPIO pin assignments: alternate functions */
	GPIO_SSP_TXD_o=		1<<10,	/* SSP Transmit Data */
	GPIO_SSP_RXD_i=		1<<11,	/* SSP Receive Data */
	GPIO_SSP_SCLK_o=	1<<12,	/* SSP Sample CLocK */


@@ 263,3 264,92 @@ struct MCPregs {
	ulong	control1;
};
extern MCPregs *mcpregs;

/*
 * PCMCIA support code.
 */

typedef struct PCMmap		PCMmap;
typedef struct PCMslot		PCMslot;
typedef struct PCMconftab	PCMconftab;
typedef struct Cisdat 		Cisdat;

/*
 * Map between ISA memory space and PCMCIA card memory space.
 */
struct PCMmap {
	ulong	ca;			/* card address */
	ulong	cea;			/* card end address */
	ulong	isa;			/* local virtual address */
	int	len;			/* length of the ISA area */
	int	attr;			/* attribute memory */
};

/* configuration table entry */
struct PCMconftab
{
	int	index;
	ushort	irqs;		/* legal irqs */
	uchar	irqtype;
	uchar	bit16;		/* true for 16 bit access */
	struct {
		ulong	start;
		ulong	len;
	} io[16];
	int	nio;
	uchar	vpp1;
	uchar	vpp2;
	uchar	memwait;
	ulong	maxwait;
	ulong	readywait;
	ulong	otherwait;
};

/* cis memory walking */
struct Cisdat
{
	uchar	*cisbase;
	int	cispos;
	int	cisskip;
	int	cislen;
};

/* a card slot */
struct PCMslot
{
	Lock;
	int	ref;

	long	memlen;		/* memory length */
	uchar	slotno;		/* slot number */
	void	*regs;		/* i/o registers */
	void	*mem;		/* memory */
	void	*attr;		/* attribute memory */

	/* status */
	uchar	special;	/* in use for a special device */
	uchar	already;	/* already inited */
	uchar	occupied;
	uchar	battery;
	uchar	wrprot;
	uchar	powered;
	uchar	configed;
	uchar	enabled;
	uchar	busy;

	/* cis info */
	ulong	msec;		/* time of last slotinfo call */
	char	verstr[512];	/* version string */
	uchar	cpresent;	/* config registers present */
	ulong	caddr;		/* relative address of config registers */
	int	nctab;		/* number of config table entries */
	PCMconftab	ctab[8];
	PCMconftab	*def;		/* default conftab */

	/* for walking through cis */
	Cisdat;

	/* maps are fixed */
	PCMmap memmap;
	PCMmap attrmap;
};

M bitsy/main.c => bitsy/main.c +9 -1
@@ 407,7 407,7 @@ sspinit(void) {

static ulong egpiosticky;

static void
void
egpiobits(ulong bits, int on)
{
	if(on)


@@ 458,3 458,11 @@ flashprogpower(int on)
{
	egpiobits(EGPIO_prog_flash, on);
}

void
exppackpower(int on)
{
	egpiobits(EGPIO_exp_full_power|EGPIO_exp_nvram_power, on);
	if(on)
		delay(100);
}

M bitsy/mem.h => bitsy/mem.h +14 -2
@@ 45,8 45,10 @@
#define	UTZERO		(UZERO+BY2PG)		/* first address in user text */
#define	KZERO		0xC0000000		/* base of kernel address space */
#define	KTZERO		0xC0008000		/* first address in kernel text */
#define	REGZERO		0xA0000000		/* 256 meg for mapspecial regs */
#define	REGTOP		0xB0000000		/* ... */
#define	EMEMZERO	0x90000000		/* 256 meg for add on memory */
#define	EMEMTOP		0xA0000000		/* ... */
#define	REGZERO		0xA0000000		/* 128 meg for mapspecial regs */
#define	REGTOP		0xA8000000		/* ... */
#define	FLASHZERO	0xB0000000		/* 128 meg for flash */
#define	FLASHTOP	0xB8000000		/* ... */
#define	DRAMZERO	0xC0000000		/* 128 meg for memory */


@@ 107,6 109,16 @@
#define OSTIMERREGS	0x90000000	/* operating system timer registers */

/*
 *  PCMCIA addresses
 */
#define PHYSPCM0REGS	0x20000000
#define PYHSPCM0ATTR	0x28000000
#define PYHSPCM0MEM	0x2C000000
#define PHYSPCM1REGS	0x30000000
#define PYHSPCM1ATTR	0x38000000
#define PYHSPCM1MEM	0x3C000000

/*
 *  Program Status Registers
 */
#define PsrMusr		0x00000010	/* mode */

M bitsy/mmu.c => bitsy/mmu.c +117 -13
@@ 51,7 51,7 @@ enum
};

ulong *l1table;

static int mmuinited;

/*
 *  We map all of memory, flash, and the zeros area with sections.


@@ 67,28 67,27 @@ mmuinit(void)
	l1table = xspanalloc(16*1024, 16*1024, 0);
	memset(l1table, 0, 16*1024);

	/* map low mem */
	/* map low mem (I really don't know why I have to do this -- presotto) */
	for(o = 0; o < 1*OneMeg; o += OneMeg)
		l1table[(0+o)>>20] = L1Section | L1KernelRW| L1Domain0 
			| L1Cached | L1Buffered
			| ((0+o)&L1SectBaseMask);

	/* map DRAM */
	for(o = 0; o < 128*OneMeg; o += OneMeg)
	for(o = 0; o < DRAMTOP-DRAMZERO; o += OneMeg)
		l1table[(DRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0 
			| L1Cached | L1Buffered
			| ((PHYSDRAM0+o)&L1SectBaseMask);

	/* map zeros area */
	for(o = 0; o < 128 * OneMeg; o += OneMeg)
	for(o = 0; o < NULLTOP-NULLZERO; o += OneMeg)
		l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0
			| L1Cached | L1Buffered
			| ((PHYSNULL0+o)&L1SectBaseMask);

	/* map flash */
	for(o = 0; o < 128 * OneMeg; o += OneMeg)
	for(o = 0; o < FLASHTOP-FLASHZERO; o += OneMeg)
		l1table[(FLASHZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0
			| L1Cached | L1Buffered
			| ((PHYSFLASH0+o)&L1SectBaseMask);

	/* map peripheral control module regs */


@@ 117,13 116,15 @@ mmuinit(void)
	mmuinvalidate();
	mmuenable();
	cacheflush();

	mmuinited = 1;
}

/*
 *  map special space uncached, assume that the space isn't already mapped
 *  map on request
 */
void*
mapspecial(ulong pa, int len)
static void*
_map(ulong pa, int len, ulong zero, ulong top, ulong l1prop, ulong l2prop)
{
	ulong *t;
	ulong va, i, base, end, off, entry;


@@ 141,14 142,14 @@ mapspecial(ulong pa, int len)
	}
	off = pa - base;

	for(va = REGZERO; va < REGTOP && base <= end; va += OneMeg){
	for(va = zero; va < top && base <= end; va += OneMeg){
		switch(l1table[va>>20] & L1TypeMask){
		default:
			/* found unused entry on level 1 table */
			if(large){
				if(rv == nil)
					rv = (ulong*)(va+off);
				l1table[va>>20] = L1Section | L1KernelRW | L1Domain0 |
				l1table[va>>20] = L1Section | l1prop | L1Domain0 |
							(base & L1SectBaseMask);
				base += OneMeg;
				continue;


@@ 166,7 167,7 @@ mapspecial(ulong pa, int len)
			entry = l1table[va>>20];
			i = entry & L1SectBaseMask;
			if(pa >= i && (pa+len) <= i + OneMeg)
			if((entry & ~L1SectBaseMask) == (L1Section | L1KernelRW | L1Domain0))
			if((entry & ~L1SectBaseMask) == (L1Section | l1prop | L1Domain0))
				return (void*)(va + (pa & (OneMeg-1)));
				
			continue;


@@ 185,7 186,7 @@ mapspecial(ulong pa, int len)
			if((entry & L2TypeMask) != L2SmallPage){
				if(rv == nil)
					rv = (ulong*)(va+i+off);
				t[i>>PGSHIFT] = L2SmallPage | L2KernelRW | 
				t[i>>PGSHIFT] = L2SmallPage | l2prop | 
						(base & L2PageBaseMask);
				base += BY2PG;
				continue;


@@ 201,6 202,109 @@ mapspecial(ulong pa, int len)
	return rv;
}

/* map in i/o registers */
void*
mapspecial(ulong pa, int len)
{
	return _map(pa, len, REGZERO, REGTOP, L1KernelRW, L2KernelRW);
}

/* map add on memory */
void*
mapmem(ulong pa, int len)
{
	return _map(pa, len, EMEMZERO, EMEMTOP, L1KernelRW|L1Cached|L1Buffered,
			L2KernelRW|L2Cached|L2Buffered);
}

/* map a virtual address to a physical one */
ulong
mmu_paddr(ulong va)
{
	ulong entry;
	ulong *t;

	entry = l1table[va>>20];
	switch(entry & L1TypeMask){
	case L1Section:
		return (entry & L1SectBaseMask) | (va & (OneMeg-1));
	case L1PageTable:
		t = (ulong*)(entry & L1PTBaseMask);
		va &= OneMeg-1;
		entry = t[va>>PGSHIFT];
		switch(entry & L1TypeMask){
		case L2SmallPage:
			return (entry & L2PageBaseMask) | (va & (BY2PG-1));
		}
	}
	return 0;
}

/* map a physical address to a virtual one */
static ulong
findva(ulong pa, ulong zero, ulong top)
{
	int i;
	ulong entry, va;
	ulong start, end;
	ulong *t;

	for(va = zero; va < top; va += OneMeg){
		/* search the L1 entry */
		entry = l1table[va>>20];
		switch(entry & L1TypeMask){
		default:
			return 0;	/* no holes */
		case L1Section:
			start = entry & L1SectBaseMask;
			end = start + OneMeg;
			if(pa >= start && pa < end)
				return va | (pa & (OneMeg-1));
			continue;
		case L1PageTable:
			break;
		}

		/* search the L2 entry */
		t = (ulong*)(l1table[va>>20] & L1PTBaseMask);
		for(i = 0; i < OneMeg; i += BY2PG){
			entry = t[i>>PGSHIFT];

			/* found unused entry on level 2 table */
			if((entry & L2TypeMask) != L2SmallPage)
				break;

			start = entry & L2PageBaseMask;
			end = start + BY2PG;
			if(pa >= start && pa < end)
				return va | (BY2PG*i) | (pa & (BY2PG-1));
		}
	}
	return 0;
}
ulong
mmu_kaddr(ulong pa)
{
	ulong va;

	/* try the easy stuff first (the first case is true most of the time) */
	if(pa >= PHYSDRAM0 && pa <= PHYSDRAM0+(DRAMTOP-DRAMZERO))
		return DRAMZERO+(pa-PHYSDRAM0);
	if(pa >= PHYSFLASH0 && pa <= PHYSFLASH0+(FLASHTOP-FLASHZERO))
		return FLASHZERO+(pa-PHYSFLASH0);
	if(pa >= PHYSNULL0 && pa <= PHYSNULL0+(NULLTOP-NULLZERO))
		return NULLZERO+(pa-PHYSNULL0);

	if(!mmuinited)
		return 0;	/* this shouldn't happen */

	/* walk the map for the special regs and extended memory */
	va = findva(pa, EMEMZERO, EMEMTOP);
	if(va != 0)
		return va;
	return findva(pa, REGZERO, REGTOP);
}

/*
 *  table to map fault.c bits to physical bits
 */

M bitsy/sa1110dma.c => bitsy/sa1110dma.c +4 -4
@@ 57,9 57,9 @@ struct dmaregs {
	ulong	dcsr_set;
	ulong	dcsr_clr;
	ulong	dcsr_rd;
	void*	dstrtA;
	ulong	dstrtA;
	ulong	dxcntA;
	void*	dstrtB;
	ulong	dstrtB;
	ulong	dxcntB;
} *dmaregs;



@@ 116,7 116,7 @@ dmafree(int i) {
}

ulong
dmastart(int chan, void *addr, int count) {
dmastart(int chan,  ulong addr, int count) {
	ulong status, n;
	static int last;



@@ 128,7 128,7 @@ dmastart(int chan, void *addr, int count) {
	if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
		return 0;
	}
	cachewbregion((ulong)addr, count);
	cachewbregion(addr, count);
	n = 1;
	if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
		(status & (1<<BIU | 1<<STRTA)) == 0) {

M bitsy/sa1110dma.h => bitsy/sa1110dma.h +1 -1
@@ 11,7 11,7 @@ void	dmainit(void);
int		dmaalloc(int, int, int, int, int, ulong, void (*)(void*, ulong), void*);
void	dmafree(int);

ulong	dmastart(int, void *, int);
ulong	dmastart(int, ulong, int);

void	dmawait(int);
int		dmaidle(int);

M pc/dat.h => pc/dat.h +1 -0
@@ 9,6 9,7 @@ typedef struct Notsave	Notsave;
typedef struct PCArch	PCArch;
typedef struct Pcidev	Pcidev;
typedef struct PCMmap	PCMmap;
typedef struct PCMslot	PCMslot;
typedef struct Page	Page;
typedef struct PMMU	PMMU;
typedef struct Proc	Proc;

M pc/devi82365.c => pc/devi82365.c +33 -537
@@ 7,7 7,7 @@
#include "io.h"

/*
 *  Support for up to 4 Slot card slots.  Generalizing above that is hard
 *  Support for up to 4 PCMslot card slots.  Generalizing above that is hard
 *  since addressing is not obvious. - presotto
 *
 *  WARNING: This has never been tried with more than one card slot.


@@ 84,10 84,6 @@ enum
	Moffhi=		0x5,		/* Card memory offset address high byte */
	 Fregactive=	 (1<<6),	/*  attribute memory */

	Mbits=		13,		/* msb of Mchunk */
	Mchunk=		1<<Mbits,	/* logical mapping granularity */
	Nmap=		4,		/* max number of maps to use */

	/*
	 *  configuration registers - they start at an offset in attribute
	 *  memory found in the CIS.


@@ 95,16 91,11 @@ enum
	Rconfig=	0,
	 Creset=	 (1<<7),	/*  reset device */
	 Clevel=	 (1<<6),	/*  level sensitive interrupt line */

	Maxctab=	8,		/* maximum configuration table entries */
};

#define MAP(x,o)	(Rmap + (x)*0x8 + o)

typedef struct I82365	I82365;
typedef struct Slot	Slot;
typedef struct Conftab	Conftab;
typedef struct Cisdat Cisdat;

/* a controller */
enum


@@ 125,109 116,39 @@ struct I82365
};
static I82365 *controller[4];
static int ncontroller;

/* configuration table entry */
struct Conftab
{
	int	index;
	ushort	irqs;		/* legal irqs */
	uchar	irqtype;
	uchar	bit16;		/* true for 16 bit access */
	struct {
		ulong	start;
		ulong	len;
	} io[16];
	int	nio;
	uchar	vpp1;
	uchar	vpp2;
	uchar	memwait;
	ulong	maxwait;
	ulong	readywait;
	ulong	otherwait;
};

/* cis memory walking */
struct Cisdat
{
	uchar	*cisbase;
	int	cispos;
	int	cisskip;
	int	cislen;
};

/* a card slot */
struct Slot
{
	Lock;
	int	ref;

	I82365	*cp;		/* controller for this slot */
	long	memlen;		/* memory length */
	uchar	base;		/* index register base */
	uchar	slotno;		/* slot number */

	/* status */
	uchar	special;	/* in use for a special device */
	uchar	already;	/* already inited */
	uchar	occupied;
	uchar	battery;
	uchar	wrprot;
	uchar	powered;
	uchar	configed;
	uchar	enabled;
	uchar	busy;

	/* cis info */
	ulong	msec;		/* time of last slotinfo call */
	char	verstr[512];	/* version string */
	uchar	cpresent;	/* config registers present */
	ulong	caddr;		/* relative address of config registers */
	int	nctab;		/* number of config table entries */
	Conftab	ctab[Maxctab];
	Conftab	*def;		/* default conftab */

	/* for walking through cis */
	Cisdat;

	/* memory maps */
	Lock	mlock;		/* lock down the maps */
	int	time;
	PCMmap	mmap[Nmap];	/* maps, last is always for the kernel */
};
static Slot	*slot;
static Slot	*lastslot;
static PCMslot	*slot;
static PCMslot	*lastslot;
static nslot;

static void	cisread(Slot*);
static void	i82365intr(Ureg*, void*);
static void	i82365reset(void);
static int	pcmio(int, ISAConf*);
static long	pcmread(int, int, void*, long, vlong);
static long	pcmwrite(int, int, void*, long, vlong);

static void i82365dump(Slot*);
static void i82365dump(PCMslot*);

/*
 *  reading and writing card registers
 */
static uchar
rdreg(Slot *pp, int index)
rdreg(PCMslot *pp, int index)
{
	outb(pp->cp->xreg, pp->base + index);
	return inb(pp->cp->dreg);
	outb(((I82365*)pp->cp)->xreg, pp->base + index);
	return inb(((I82365*)pp->cp)->dreg);
}
static void
wrreg(Slot *pp, int index, uchar val)
wrreg(PCMslot *pp, int index, uchar val)
{
	outb(pp->cp->xreg, pp->base + index);
	outb(pp->cp->dreg, val);
	outb(((I82365*)pp->cp)->xreg, pp->base + index);
	outb(((I82365*)pp->cp)->dreg, val);
}

/*
 *  get info about card
 */
static void
slotinfo(Slot *pp)
slotinfo(PCMslot *pp)
{
	uchar isr;



@@ 257,7 178,7 @@ vcode(int volt)
 *  enable the slot card
 */
static void
slotena(Slot *pp)
slotena(PCMslot *pp)
{
	if(pp->enabled)
		return;


@@ 273,7 194,7 @@ slotena(Slot *pp)
	/* get configuration */
	slotinfo(pp);
	if(pp->occupied){
		cisread(pp);
		pcmcisread(pp);
		pp->enabled = 1;
	} else
		wrreg(pp, Rpc, Fautopower);


@@ 283,7 204,7 @@ slotena(Slot *pp)
 *  disable the slot card
 */
static void
slotdis(Slot *pp)
slotdis(PCMslot *pp)
{
	wrreg(pp, Rpc, 0);	/* turn off card power */
	wrreg(pp, Rwe, 0);	/* no windows */


@@ 297,7 218,7 @@ static void
i82365intr(Ureg *, void *)
{
	uchar csc, was;
	Slot *pp;
	PCMslot *pp;

	if(slot == 0)
		return;


@@ 326,7 247,7 @@ enum
PCMmap*
pcmmap(int slotno, ulong offset, int len, int attr)
{
	Slot *pp;
	PCMslot *pp;
	uchar we, bit;
	PCMmap *m, *nm;
	int i;


@@ 346,7 267,7 @@ pcmmap(int slotno, ulong offset, int len, int attr)
	we = rdreg(pp, Rwe);
	bit = 1;
	nm = 0;
	for(m = pp->mmap; m < &pp->mmap[Nmap]; m++){
	for(m = pp->mmap; m < &pp->mmap[nelem(pp->mmap)]; m++){
		if((we & bit))
		if(m->attr == attr)
		if(offset >= m->ca && e <= m->cea){


@@ 406,7 327,7 @@ pcmmap(int slotno, ulong offset, int len, int attr)
void
pcmunmap(int slotno, PCMmap* m)
{
	Slot *pp;
	PCMslot *pp;

	pp = slot + slotno;
	lock(&pp->mlock);


@@ 415,7 336,7 @@ pcmunmap(int slotno, PCMmap* m)
}

static void
increfp(Slot *pp)
increfp(PCMslot *pp)
{
	lock(pp);
	if(pp->ref++ == 0)


@@ 424,7 345,7 @@ increfp(Slot *pp)
}

static void
decrefp(Slot *pp)
decrefp(PCMslot *pp)
{
	lock(pp);
	if(pp->ref-- == 1)


@@ 438,7 359,7 @@ decrefp(Slot *pp)
int
pcmspecial(char *idstr, ISAConf *isa)
{
	Slot *pp;
	PCMslot *pp;
	extern char *strstr(char*, char*);
	int enabled;



@@ 479,7 400,7 @@ pcmspecial(char *idstr, ISAConf *isa)
void
pcmspecialclose(int slotno)
{
	Slot *pp;
	PCMslot *pp;

	if(slotno >= nslot)
		panic("pcmspecialclose");


@@ 508,7 429,7 @@ pcmgen(Chan *c, Dirtab *, int , int i, Dir *dp)
	int slotno;
	Qid qid;
	long len;
	Slot *pp;
	PCMslot *pp;
	char name[NAMELEN];

	if(i == DEVDOTDOT){


@@ 594,7 515,6 @@ i82365probe(int x, int d, int dev)
		break;
	}

#ifdef adsf
	/* if it's not a Cirrus, it could be a Vadem... */
	if(cp->type == Ti82365){
		/* unlock the Vadem extended regs */


@@ 615,7 535,6 @@ i82365probe(int x, int d, int dev)
		c = inb(d);
		outb(d, c & ~0xC0);
	}
#endif asdf

	/* low power mode */
	outb(x, Rmisc2 + (dev<<7));


@@ 641,7 560,7 @@ i82365probe(int x, int d, int dev)
}

static void
i82365dump(Slot *pp)
i82365dump(PCMslot *pp)
{
	int i;



@@ 664,7 583,7 @@ i82365reset(void)
	static int already;
	int i, j;
	I82365 *cp;
	Slot *pp;
	PCMslot *pp;
	char buf[NAMELEN];

	if(already)


@@ 687,7 606,7 @@ i82365reset(void)
	}
	for(i = 0; i < ncontroller; i++)
		nslot += controller[i]->nslot;
	slot = xalloc(nslot * sizeof(Slot));
	slot = xalloc(nslot * sizeof(PCMslot));

	/* if the card is there turn on 5V power to keep its battery alive */
	lastslot = slot;


@@ 788,7 707,7 @@ pcmread(int slotno, int attr, void *a, long n, vlong off)
	int i, len;
	PCMmap *m;
	uchar *ac;
	Slot *pp;
	PCMslot *pp;
	ulong offset = off;

	pp = slot + slotno;


@@ 827,7 746,7 @@ static long
i82365read(Chan *c, void *a, long n, vlong off)
{
	char *p, *buf, *e;
	Slot *pp;
	PCMslot *pp;
	ulong offset = off;

	switch(TYPE(c)){


@@ 874,7 793,7 @@ pcmwrite(int dev, int attr, void *a, long n, vlong off)
	int i, len;
	PCMmap *m;
	uchar *ac;
	Slot *pp;
	PCMslot *pp;
	ulong offset = off;

	pp = slot + dev;


@@ 912,7 831,7 @@ pcmwrite(int dev, int attr, void *a, long n, vlong off)
static long
i82365write(Chan *c, void *a, long n, vlong off)
{
	Slot *pp;
	PCMslot *pp;
	char buf[32];

	switch(TYPE(c)){


@@ 965,15 884,15 @@ Dev i82365devtab = {
};

/*
 *  configure the Slot for IO.  We assume very heavily that we can read
 *  configure the PCMslot for IO.  We assume very heavily that we can read
 *  configuration info from the CIS.  If not, we won't set up correctly.
 */
static int
pcmio(int slotno, ISAConf *isa)
{
	uchar we, x, *p;
	Slot *pp;
	Conftab *ct, *et, *t;
	PCMslot *pp;
	PCMconftab *ct, *et, *t;
	PCMmap *m;
	int i, index, irq;
	char *cp;


@@ 1094,426 1013,3 @@ pcmio(int slotno, ISAConf *isa)
	}
	return 0;
}

/*
 *  read and crack the card information structure enough to set
 *  important parameters like power
 */
static void	tcfig(Slot*, Cisdat*, int);
static void	tentry(Slot*, Cisdat*, int);
static void	tvers1(Slot*, Cisdat*, int);

struct {
	int n;
	void (*parse)(Slot*, Cisdat*, int);
} cistab[] = {
	0x15, tvers1,
	0x1A, tcfig,
	0x1B, tentry,
};

static int
readc(Cisdat *pp, uchar *x)
{
	if(pp->cispos >= pp->cislen)
		return 0;
	*x = pp->cisbase[pp->cisskip*pp->cispos];
	pp->cispos++;
	return 1;
}

static int
xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
{
	PCMmap *m;
	Cisdat cis;
	int i, l;
	uchar *p;
	uchar type, link, n, c;
	int this, subtype;

	m = pcmmap(slotno, 0, 0, attr);
	if(m == 0)
		return -1;

	cis.cisbase = KADDR(m->isa);
	cis.cispos = 0;
	cis.cisskip = attr ? 2 : 1;
	cis.cislen = Mchunk;

	/* loop through all the tuples */
	for(i = 0; i < 1000; i++){
		this = cis.cispos;
		if(readc(&cis, &type) != 1)
			break;
		if(type == 0xFF)
			break;
		if(readc(&cis, &link) != 1)
			break;
		if(link == 0xFF)
			break;

		n = link;
		if (link > 1 && subtuple != -1) {
			if (readc(&cis, &c) != 1)
				break;
			subtype = c;
			n--;
		} else
			subtype = -1;

		if(type == tuple && subtype == subtuple) {
			p = v;
			for(l=0; l<nv && l<n; l++)
				if(readc(&cis, p++) != 1)
					break;
			pcmunmap(slotno, m);
			return nv;
		}
		cis.cispos = this + (2+link);
	}
	pcmunmap(slotno, m);
	return -1;
}

int
pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
{
	int n;

	/* try attribute space, then memory */
	if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
		return n;
	return xcistuple(slotno, tuple, subtuple, v, nv, 0);
}

static void
cisread(Slot *pp)
{
	uchar v[256];
	int i, nv;
	Cisdat cis;

	memset(pp->ctab, 0, sizeof(pp->ctab));
	pp->caddr = 0;
	pp->cpresent = 0;
	pp->configed = 0;
	pp->nctab = 0;
	pp->verstr[0] = 0;

	for(i = 0; i < nelem(cistab); i++) {
		if((nv = pcmcistuple(pp->slotno, cistab[i].n, -1, v, sizeof(v))) >= 0) {
			cis.cisbase = v;
			cis.cispos = 0;
			cis.cisskip = 1;
			cis.cislen = nv;
			
			(*cistab[i].parse)(pp, &cis, cistab[i].n);
		}
	}
}

static ulong
getlong(Cisdat *cis, int size)
{
	uchar c;
	int i;
	ulong x;

	x = 0;
	for(i = 0; i < size; i++){
		if(readc(cis, &c) != 1)
			break;
		x |= c<<(i*8);
	}
	return x;
}

static void
tcfig(Slot *pp, Cisdat *cis, int )
{
	uchar size, rasize, rmsize;
	uchar last;

	if(readc(cis, &size) != 1)
		return;
	rasize = (size&0x3) + 1;
	rmsize = ((size>>2)&0xf) + 1;
	if(readc(cis, &last) != 1)
		return;
	pp->caddr = getlong(cis, rasize);
	pp->cpresent = getlong(cis, rmsize);
}

static ulong vexp[8] =
{
	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
};
static ulong vmant[16] =
{
	10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
};

static ulong
microvolt(Cisdat *cis)
{
	uchar c;
	ulong microvolts;
	ulong exp;

	if(readc(cis, &c) != 1)
		return 0;
	exp = vexp[c&0x7];
	microvolts = vmant[(c>>3)&0xf]*exp;
	while(c & 0x80){
		if(readc(cis, &c) != 1)
			return 0;
		switch(c){
		case 0x7d:
			break;		/* high impedence when sleeping */
		case 0x7e:
		case 0x7f:
			microvolts = 0;	/* no connection */
			break;
		default:
			exp /= 10;
			microvolts += exp*(c&0x7f);
		}
	}
	return microvolts;
}

static ulong
nanoamps(Cisdat *cis)
{
	uchar c;
	ulong nanoamps;

	if(readc(cis, &c) != 1)
		return 0;
	nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
	while(c & 0x80){
		if(readc(cis, &c) != 1)
			return 0;
		if(c == 0x7d || c == 0x7e || c == 0x7f)
			nanoamps = 0;
	}
	return nanoamps;
}

/*
 *  only nominal voltage is important for config
 */
static ulong
power(Cisdat *cis)
{
	uchar feature;
	ulong mv;

	mv = 0;
	if(readc(cis, &feature) != 1)
		return 0;
	if(feature & 1)
		mv = microvolt(cis);
	if(feature & 2)
		microvolt(cis);
	if(feature & 4)
		microvolt(cis);
	if(feature & 8)
		nanoamps(cis);
	if(feature & 0x10)
		nanoamps(cis);
	if(feature & 0x20)
		nanoamps(cis);
	if(feature & 0x40)
		nanoamps(cis);
	return mv/1000000;
}

static ulong mantissa[16] =
{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };

static ulong exponent[8] =
{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };

static ulong
ttiming(Cisdat *cis, int scale)
{
	uchar unscaled;
	ulong nanosecs;

	if(readc(cis, &unscaled) != 1)
		return 0;
	nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
	nanosecs = nanosecs * vexp[scale];
	return nanosecs;
}

static void
timing(Cisdat *cis, Conftab *ct)
{
	uchar c, i;

	if(readc(cis, &c) != 1)
		return;
	i = c&0x3;
	if(i != 3)
		ct->maxwait = ttiming(cis, i);		/* max wait */
	i = (c>>2)&0x7;
	if(i != 7)
		ct->readywait = ttiming(cis, i);		/* max ready/busy wait */
	i = (c>>5)&0x7;
	if(i != 7)
		ct->otherwait = ttiming(cis, i);		/* reserved wait */
}

static void
iospaces(Cisdat *cis, Conftab *ct)
{
	uchar c;
	int i, nio;

	ct->nio = 0;
	if(readc(cis, &c) != 1)
		return;

	ct->bit16 = ((c>>5)&3) >= 2;
	if(!(c & 0x80)){
		ct->io[0].start = 0;
		ct->io[0].len = 1<<(c&0x1f);
		ct->nio = 1;
		return;
	}

	if(readc(cis, &c) != 1)
		return;

	nio = (c&0xf)+1;
	for(i = 0; i < nio; i++){
		ct->io[i].start = getlong(cis, (c>>4)&0x3);
		ct->io[0].len = getlong(cis, (c>>6)&0x3);
	}
	ct->nio = nio;
}

static void
irq(Cisdat *cis, Conftab *ct)
{
	uchar c;

	if(readc(cis, &c) != 1)
		return;
	ct->irqtype = c & 0xe0;
	if(c & 0x10)
		ct->irqs = getlong(cis, 2);
	else
		ct->irqs = 1<<(c&0xf);
	ct->irqs &= 0xDEB8;		/* levels available to card */
}

static void
memspace(Cisdat *cis, int asize, int lsize, int host)
{
	ulong haddress, address, len;

	len = getlong(cis, lsize)*256;
	address = getlong(cis, asize)*256;
	USED(len, address);
	if(host){
		haddress = getlong(cis, asize)*256;
		USED(haddress);
	}
}

static void
tentry(Slot *pp, Cisdat *cis, int )
{
	uchar c, i, feature;
	Conftab *ct;

	if(pp->nctab >= Maxctab)
		return;
	if(readc(cis, &c) != 1)
		return;
	ct = &pp->ctab[pp->nctab++];

	/* copy from last default config */
	if(pp->def)
		*ct = *pp->def;

	ct->index = c & 0x3f;

	/* is this the new default? */
	if(c & 0x40)
		pp->def = ct;

	/* memory wait specified? */
	if(c & 0x80){
		if(readc(cis, &i) != 1)
			return;
		if(i&0x80)
			ct->memwait = 1;
	}

	if(readc(cis, &feature) != 1)
		return;
	switch(feature&0x3){
	case 1:
		ct->vpp1 = ct->vpp2 = power(cis);
		break;
	case 2:
		power(cis);
		ct->vpp1 = ct->vpp2 = power(cis);
		break;
	case 3:
		power(cis);
		ct->vpp1 = power(cis);
		ct->vpp2 = power(cis);
		break;
	default:
		break;
	}
	if(feature&0x4)
		timing(cis, ct);
	if(feature&0x8)
		iospaces(cis, ct);
	if(feature&0x10)
		irq(cis, ct);
	switch((feature>>5)&0x3){
	case 1:
		memspace(cis, 0, 2, 0);
		break;
	case 2:
		memspace(cis, 2, 2, 0);
		break;
	case 3:
		if(readc(cis, &c) != 1)
			return;
		for(i = 0; i <= (c&0x7); i++)
			memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
		break;
	}
	pp->configed++;
}

static void
tvers1(Slot *pp, Cisdat *cis, int )
{
	uchar c, major, minor;
	int  i;

	if(readc(cis, &major) != 1)
		return;
	if(readc(cis, &minor) != 1)
		return;
	for(i = 0; i < sizeof(pp->verstr)-1; i++){
		if(readc(cis, &c) != 1)
			return;
		if(c == 0)
			c = '\n';
		if(c == 0xff)
			break;
		pp->verstr[i] = c;
	}
	pp->verstr[i] = 0;
}

M pc/fns.h => pc/fns.h +1 -0
@@ 95,6 95,7 @@ Pcidev* pcimatch(Pcidev*, int, int);
Pcidev* pcimatchtbdf(int);
void	pcireset(void);
void	pcisetbme(Pcidev*);
void	pcmcisread(PCMslot*);
int	pcmcistuple(int, int, int, void*, int);
PCMmap*	pcmmap(int, ulong, int, int);
int	pcmspecial(char*, ISAConf*);

M pc/io.h => pc/io.h +89 -15
@@ 209,21 209,6 @@ struct Pcidev
#define ISAWINDOW	0
#define ISAWADDR(va)	(PADDR(va)+ISAWINDOW)

/*
 * PCMCIA support code.
 */
/*
 * Map between ISA memory space and PCMCIA card memory space.
 */
struct PCMmap {
	ulong	ca;			/* card address */
	ulong	cea;			/* card end address */
	ulong	isa;			/* ISA address */
	int	len;			/* length of the ISA area */
	int	attr;			/* attribute memory */
	int	ref;
};

/* SMBus transactions */
enum
{


@@ 249,3 234,92 @@ struct SMBus {
	int	busy;
	void	(*transact)(SMBus*, int, int, int, uchar*);
};

/*
 * PCMCIA support code.
 */

typedef struct PCMslot		PCMslot;
typedef struct PCMconftab	PCMconftab;
typedef struct Cisdat 		Cisdat;

/*
 * Map between ISA memory space and PCMCIA card memory space.
 */
struct PCMmap {
	ulong	ca;			/* card address */
	ulong	cea;			/* card end address */
	ulong	isa;			/* ISA address */
	int	len;			/* length of the ISA area */
	int	attr;			/* attribute memory */
	int	ref;
};

/* configuration table entry */
struct PCMconftab
{
	int	index;
	ushort	irqs;		/* legal irqs */
	uchar	irqtype;
	uchar	bit16;		/* true for 16 bit access */
	struct {
		ulong	start;
		ulong	len;
	} io[16];
	int	nio;
	uchar	vpp1;
	uchar	vpp2;
	uchar	memwait;
	ulong	maxwait;
	ulong	readywait;
	ulong	otherwait;
};

/* cis memory walking */
struct Cisdat
{
	uchar	*cisbase;
	int	cispos;
	int	cisskip;
	int	cislen;
};

/* a card slot */
struct PCMslot
{
	Lock;
	int	ref;

	void	*cp;		/* controller for this slot */
	long	memlen;		/* memory length */
	uchar	base;		/* index register base */
	uchar	slotno;		/* slot number */

	/* status */
	uchar	special;	/* in use for a special device */
	uchar	already;	/* already inited */
	uchar	occupied;
	uchar	battery;
	uchar	wrprot;
	uchar	powered;
	uchar	configed;
	uchar	enabled;
	uchar	busy;

	/* cis info */
	ulong	msec;		/* time of last slotinfo call */
	char	verstr[512];	/* version string */
	uchar	cpresent;	/* config registers present */
	ulong	caddr;		/* relative address of config registers */
	int	nctab;		/* number of config table entries */
	PCMconftab	ctab[8];
	PCMconftab	*def;		/* default conftab */

	/* for walking through cis */
	Cisdat;

	/* memory maps */
	Lock	mlock;		/* lock down the maps */
	int	time;
	PCMmap	mmap[4];	/* maps, last is always for the kernel */
};

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


/*
 *  read and crack the card information structure enough to set
 *  important parameters like power
 */
static void	tcfig(PCMslot*, Cisdat*, int);
static void	tentry(PCMslot*, Cisdat*, int);
static void	tvers1(PCMslot*, Cisdat*, int);

struct {
	int n;
	void (*parse)(PCMslot*, Cisdat*, int);
} cistab[] = {
	0x15, tvers1,
	0x1A, tcfig,
	0x1B, tentry,
};

static int
readc(Cisdat *pp, uchar *x)
{
	if(pp->cispos >= pp->cislen)
		return 0;
	*x = pp->cisbase[pp->cisskip*pp->cispos];
	pp->cispos++;
	return 1;
}

static int
xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
{
	PCMmap *m;
	Cisdat cis;
	int i, l;
	uchar *p;
	uchar type, link, n, c;
	int this, subtype;

	m = pcmmap(slotno, 0, 0, attr);
	if(m == 0)
		return -1;

	cis.cisbase = KADDR(m->isa);
	cis.cispos = 0;
	cis.cisskip = attr ? 2 : 1;
	cis.cislen = m->len;

	/* loop through all the tuples */
	for(i = 0; i < 1000; i++){
		this = cis.cispos;
		if(readc(&cis, &type) != 1)
			break;
		if(type == 0xFF)
			break;
		if(readc(&cis, &link) != 1)
			break;
		if(link == 0xFF)
			break;

		n = link;
		if (link > 1 && subtuple != -1) {
			if (readc(&cis, &c) != 1)
				break;
			subtype = c;
			n--;
		} else
			subtype = -1;

		if(type == tuple && subtype == subtuple) {
			p = v;
			for(l=0; l<nv && l<n; l++)
				if(readc(&cis, p++) != 1)
					break;
			pcmunmap(slotno, m);
			return nv;
		}
		cis.cispos = this + (2+link);
	}
	pcmunmap(slotno, m);
	return -1;
}

int
pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
{
	int n;

	/* try attribute space, then memory */
	if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
		return n;
	return xcistuple(slotno, tuple, subtuple, v, nv, 0);
}

void
pcmcisread(PCMslot *pp)
{
	uchar v[256];
	int i, nv;
	Cisdat cis;

	memset(pp->ctab, 0, sizeof(pp->ctab));
	pp->caddr = 0;
	pp->cpresent = 0;
	pp->configed = 0;
	pp->nctab = 0;
	pp->verstr[0] = 0;

	for(i = 0; i < nelem(cistab); i++) {
		if((nv = pcmcistuple(pp->slotno, cistab[i].n, -1, v, sizeof(v))) >= 0) {
			cis.cisbase = v;
			cis.cispos = 0;
			cis.cisskip = 1;
			cis.cislen = nv;
			
			(*cistab[i].parse)(pp, &cis, cistab[i].n);
		}
	}
}

static ulong
getlong(Cisdat *cis, int size)
{
	uchar c;
	int i;
	ulong x;

	x = 0;
	for(i = 0; i < size; i++){
		if(readc(cis, &c) != 1)
			break;
		x |= c<<(i*8);
	}
	return x;
}

static void
tcfig(PCMslot *pp, Cisdat *cis, int )
{
	uchar size, rasize, rmsize;
	uchar last;

	if(readc(cis, &size) != 1)
		return;
	rasize = (size&0x3) + 1;
	rmsize = ((size>>2)&0xf) + 1;
	if(readc(cis, &last) != 1)
		return;
	pp->caddr = getlong(cis, rasize);
	pp->cpresent = getlong(cis, rmsize);
}

static ulong vexp[8] =
{
	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
};
static ulong vmant[16] =
{
	10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, 90,
};

static ulong
microvolt(Cisdat *cis)
{
	uchar c;
	ulong microvolts;
	ulong exp;

	if(readc(cis, &c) != 1)
		return 0;
	exp = vexp[c&0x7];
	microvolts = vmant[(c>>3)&0xf]*exp;
	while(c & 0x80){
		if(readc(cis, &c) != 1)
			return 0;
		switch(c){
		case 0x7d:
			break;		/* high impedence when sleeping */
		case 0x7e:
		case 0x7f:
			microvolts = 0;	/* no connection */
			break;
		default:
			exp /= 10;
			microvolts += exp*(c&0x7f);
		}
	}
	return microvolts;
}

static ulong
nanoamps(Cisdat *cis)
{
	uchar c;
	ulong nanoamps;

	if(readc(cis, &c) != 1)
		return 0;
	nanoamps = vexp[c&0x7]*vmant[(c>>3)&0xf];
	while(c & 0x80){
		if(readc(cis, &c) != 1)
			return 0;
		if(c == 0x7d || c == 0x7e || c == 0x7f)
			nanoamps = 0;
	}
	return nanoamps;
}

/*
 *  only nominal voltage is important for config
 */
static ulong
power(Cisdat *cis)
{
	uchar feature;
	ulong mv;

	mv = 0;
	if(readc(cis, &feature) != 1)
		return 0;
	if(feature & 1)
		mv = microvolt(cis);
	if(feature & 2)
		microvolt(cis);
	if(feature & 4)
		microvolt(cis);
	if(feature & 8)
		nanoamps(cis);
	if(feature & 0x10)
		nanoamps(cis);
	if(feature & 0x20)
		nanoamps(cis);
	if(feature & 0x40)
		nanoamps(cis);
	return mv/1000000;
}

static ulong mantissa[16] =
{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, };

static ulong exponent[8] =
{ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, };

static ulong
ttiming(Cisdat *cis, int scale)
{
	uchar unscaled;
	ulong nanosecs;

	if(readc(cis, &unscaled) != 1)
		return 0;
	nanosecs = (mantissa[(unscaled>>3)&0xf]*exponent[unscaled&7])/10;
	nanosecs = nanosecs * vexp[scale];
	return nanosecs;
}

static void
timing(Cisdat *cis, PCMconftab *ct)
{
	uchar c, i;

	if(readc(cis, &c) != 1)
		return;
	i = c&0x3;
	if(i != 3)
		ct->maxwait = ttiming(cis, i);		/* max wait */
	i = (c>>2)&0x7;
	if(i != 7)
		ct->readywait = ttiming(cis, i);		/* max ready/busy wait */
	i = (c>>5)&0x7;
	if(i != 7)
		ct->otherwait = ttiming(cis, i);		/* reserved wait */
}

static void
iospaces(Cisdat *cis, PCMconftab *ct)
{
	uchar c;
	int i, nio;

	ct->nio = 0;
	if(readc(cis, &c) != 1)
		return;

	ct->bit16 = ((c>>5)&3) >= 2;
	if(!(c & 0x80)){
		ct->io[0].start = 0;
		ct->io[0].len = 1<<(c&0x1f);
		ct->nio = 1;
		return;
	}

	if(readc(cis, &c) != 1)
		return;

	nio = (c&0xf)+1;
	for(i = 0; i < nio; i++){
		ct->io[i].start = getlong(cis, (c>>4)&0x3);
		ct->io[0].len = getlong(cis, (c>>6)&0x3);
	}
	ct->nio = nio;
}

static void
irq(Cisdat *cis, PCMconftab *ct)
{
	uchar c;

	if(readc(cis, &c) != 1)
		return;
	ct->irqtype = c & 0xe0;
	if(c & 0x10)
		ct->irqs = getlong(cis, 2);
	else
		ct->irqs = 1<<(c&0xf);
	ct->irqs &= 0xDEB8;		/* levels available to card */
}

static void
memspace(Cisdat *cis, int asize, int lsize, int host)
{
	ulong haddress, address, len;

	len = getlong(cis, lsize)*256;
	address = getlong(cis, asize)*256;
	USED(len, address);
	if(host){
		haddress = getlong(cis, asize)*256;
		USED(haddress);
	}
}

static void
tentry(PCMslot *pp, Cisdat *cis, int )
{
	uchar c, i, feature;
	PCMconftab *ct;

	if(pp->nctab >= nelem(pp->ctab))
		return;
	if(readc(cis, &c) != 1)
		return;
	ct = &pp->ctab[pp->nctab++];

	/* copy from last default config */
	if(pp->def)
		*ct = *pp->def;

	ct->index = c & 0x3f;

	/* is this the new default? */
	if(c & 0x40)
		pp->def = ct;

	/* memory wait specified? */
	if(c & 0x80){
		if(readc(cis, &i) != 1)
			return;
		if(i&0x80)
			ct->memwait = 1;
	}

	if(readc(cis, &feature) != 1)
		return;
	switch(feature&0x3){
	case 1:
		ct->vpp1 = ct->vpp2 = power(cis);
		break;
	case 2:
		power(cis);
		ct->vpp1 = ct->vpp2 = power(cis);
		break;
	case 3:
		power(cis);
		ct->vpp1 = power(cis);
		ct->vpp2 = power(cis);
		break;
	default:
		break;
	}
	if(feature&0x4)
		timing(cis, ct);
	if(feature&0x8)
		iospaces(cis, ct);
	if(feature&0x10)
		irq(cis, ct);
	switch((feature>>5)&0x3){
	case 1:
		memspace(cis, 0, 2, 0);
		break;
	case 2:
		memspace(cis, 2, 2, 0);
		break;
	case 3:
		if(readc(cis, &c) != 1)
			return;
		for(i = 0; i <= (c&0x7); i++)
			memspace(cis, (c>>5)&0x3, (c>>3)&0x3, c&0x80);
		break;
	}
	pp->configed++;
}

static void
tvers1(PCMslot *pp, Cisdat *cis, int )
{
	uchar c, major, minor;
	int  i;

	if(readc(cis, &major) != 1)
		return;
	if(readc(cis, &minor) != 1)
		return;
	for(i = 0; i < sizeof(pp->verstr)-1; i++){
		if(readc(cis, &c) != 1)
			return;
		if(c == 0)
			c = '\n';
		if(c == 0xff)
			break;
		pp->verstr[i] = c;
	}
	pp->verstr[i] = 0;
}