~kris/9p

9hist

ac3b56b991691d9838a05b806cc525ae115aae18 — David du Colombier 25 years ago a40d138
Plan 9 from Bell Labs 2000-12-05
M bitsy/clock.c => bitsy/clock.c +1 -1
@@ 31,7 31,7 @@ clockinit(void)

	/* enable interrupts on match register 0, turn off all others */
	timerregs->ossr |= 1<<0;
	intrenable(IRQtimer0, clockintr, nil, "clock");
	intrenable(IRQ, IRQtimer0, clockintr, nil, "clock");
	timerregs->oier = 1<<0;

	/* figure out processor frequency */

M bitsy/dat.h => bitsy/dat.h +20 -10
@@ 4,6 4,7 @@ typedef struct Cycintr		Cycintr;
typedef struct FPU		FPU;
typedef struct FPenv		FPenv;
typedef struct FPsave		FPsave;
typedef struct DevConf		DevConf;
typedef struct Label		Label;
typedef struct Lock		Lock;
typedef struct MMU		MMU;


@@ 21,6 22,8 @@ typedef struct Ureg		Ureg;
typedef struct Vctl		Vctl;
typedef struct Uart		Uart;

typedef void IntrHandler(Ureg*, void*);

/*
 *  parameters for sysproc.c
 */


@@ 316,6 319,8 @@ struct Cisdat
 */
struct PCMslot
{
	RWlock;

	Ref	ref;

	long	memlen;		/* memory length */


@@ 325,19 330,11 @@ struct PCMslot
	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;
	uchar	occupied;	/* card in the slot */
	uchar	configed;	/* card configured */

	/* cis info */
	int	cisread;	/* set when the cis has been read */
	ulong	msec;		/* time of last slotinfo call */
	char	verstr[512];	/* version string */
	uchar	cpresent;	/* config registers present */
	ulong	caddr;		/* relative address of config registers */


@@ 352,3 349,16 @@ struct PCMslot
	PCMmap memmap;
	PCMmap attrmap;
};

/*
 *  hardware info about a device
 */
struct DevConf
{
	ulong	mem;		/* mapped memory address */
	ulong	port;		/* mapped i/o regs */
	int	size;		/* access size */
	int	itype;		/* type of interrupt */
	ulong	interrupt;	/* interrupt number */
	char	type[NAMELEN];	/* card type */
};

M bitsy/devether.c => bitsy/devether.c +93 -94
@@ 12,6 12,97 @@

static Ether *etherxx[MaxEther];

static struct {
	char*	type;
	int	(*reset)(Ether*);
} cards[MaxEther+1];

void
addethercard(char* t, int (*r)(Ether*))
{
	static int ncard;

	if(ncard == MaxEther)
		panic("too many ether cards");
	cards[ncard].type = t;
	cards[ncard].reset = r;
	ncard++;
}

int
etherconfig(int on, char *spec, DevConf *cf)
{
	Ether *ether;
	int n, ctlrno;
	char name[NAMELEN], buf[128];
	char *p, *e;

	/* can't unconfigure yet */
	if(on == 0)
		return -1;

	ctlrno = atoi(spec);
	if(etherxx[ctlrno] != nil)
		return -1;

	ether = malloc(sizeof(Ether));
	if(ether == nil)
		panic("etherconfig");
	memset(ether, 0, sizeof(Ether));
	*(DevConf*)ether = *cf;

print("looking for card type %s\n", ether->type);
	for(n = 0; cards[n].type; n++){
		if(strcmp(cards[n].type, ether->type) != 0)
			continue;
print("found card type %s\n", ether->type);
		if(cards[n].reset(ether))
			break;
		sprint(name, "ether%d", ctlrno);

		if(ether->mbps >= 100){
			netifinit(ether, name, Ntypes, 256*1024);
			if(ether->oq == 0)
				ether->oq = qopen(256*1024, 1, 0, 0);
		}
		else{
			netifinit(ether, name, Ntypes, 65*1024);
			if(ether->oq == 0)
				ether->oq = qopen(65*1024, 1, 0, 0);
		}
		if(ether->oq == 0)
			panic("etherreset %s", name);
		ether->alen = Eaddrlen;
		memmove(ether->addr, ether->ea, Eaddrlen);
		memset(ether->bcast, 0xFF, Eaddrlen);

		if(ether->interrupt != nil)
			intrenable(cf->itype, cf->interrupt, ether->interrupt, ether, name);

		p = buf;
		e = buf+sizeof(buf);
		p = seprint(p, e, "#l%d: %s: %dMbps port 0x%luX",
			ctlrno, ether->type, ether->mbps, ether->port);
		if(ether->mem)
			p = seprint(p, e, " addr 0x%luX", PADDR(ether->mem));
		if(ether->size)
			p = seprint(p, e, " size 0x%luX", ether->size);
		p = seprint(p, e, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
			ether->ea[0], ether->ea[1], ether->ea[2],
			ether->ea[3], ether->ea[4], ether->ea[5]);
		seprint(p, e, "\n");
		print(buf);

		etherxx[ctlrno] = ether;
		return 0;
	}

	free(ether);
	return -1;
}



Chan*
etherattach(char* spec)
{


@@ 302,23 393,6 @@ etherbwrite(Chan* chan, Block* bp, ulong)
	return etheroq(ether, bp);
}

static struct {
	char*	type;
	int	(*reset)(Ether*);
} cards[MaxEther+1];

void
addethercard(char* t, int (*r)(Ether*))
{
	static int ncard;

	if(ncard == MaxEther)
		panic("too many ether cards");
	cards[ncard].type = t;
	cards[ncard].reset = r;
	ncard++;
}

int
parseether(uchar *to, char *from)
{


@@ 345,83 419,6 @@ parseether(uchar *to, char *from)
static void
etherreset(void)
{
	Ether *ether;
	int i, n, ctlrno;
	char name[NAMELEN], buf[128];

	for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
		if(ether == 0)
			ether = malloc(sizeof(Ether));
		memset(ether, 0, sizeof(Ether));
		ether->ctlrno = ctlrno;
		ether->tbdf = BUSUNKNOWN;
		ether->mbps = 10;
		ether->minmtu = ETHERMINTU;
		ether->maxmtu = ETHERMAXTU;
		if(isaconfig("ether", ctlrno, ether) == 0)
			continue;
		for(n = 0; cards[n].type; n++){
			if(cistrcmp(cards[n].type, ether->type))
				continue;
			for(i = 0; i < ether->nopt; i++){
				if(strncmp(ether->opt[i], "ea=", 3))
					continue;
				if(parseether(ether->ea, &ether->opt[i][3]) == -1)
					memset(ether->ea, 0, Eaddrlen);
			}	
			if(cards[n].reset(ether))
				break;

			/*
			 * IRQ2 doesn't really exist, it's used to gang the interrupt
			 * controllers together. A device set to IRQ2 will appear on
			 * the second interrupt controller as IRQ9.
			 */
			if(ether->irq == 2)
				ether->irq = 9;
			snprint(name, sizeof(name), "ether%d", ctlrno);

			/* If ether->irq is less than 0, it is a hack to indicate no interrupt
			 * used for the second logical ethernet for the wavelan card
			 */
			if(ether->irq >= 0)
				intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);

			i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
				ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
			if(ether->mem)
				i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
			if(ether->size)
				i += sprint(buf+i, " size 0x%luX", ether->size);
			i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX",
				ether->ea[0], ether->ea[1], ether->ea[2],
				ether->ea[3], ether->ea[4], ether->ea[5]);
			sprint(buf+i, "\n");
			print(buf);

			if(ether->mbps >= 100){
				netifinit(ether, name, Ntypes, 256*1024);
				if(ether->oq == 0)
					ether->oq = qopen(256*1024, 1, 0, 0);
			}
			else{
				netifinit(ether, name, Ntypes, 65*1024);
				if(ether->oq == 0)
					ether->oq = qopen(65*1024, 1, 0, 0);
			}
			if(ether->oq == 0)
				panic("etherreset %s", name);
			ether->alen = Eaddrlen;
			memmove(ether->addr, ether->ea, Eaddrlen);
			memset(ether->bcast, 0xFF, Eaddrlen);

			etherxx[ctlrno] = ether;
			ether = 0;
			break;
		}
	}
	if(ether)
		free(ether);
}

#define POLY 0xedb88320


@@ 463,4 460,6 @@ Dev etherdevtab = {
	etherbwrite,
	etherremove,
	etherwstat,
	nil,		/* no power management */
	etherconfig,
};

M bitsy/devpcmcia.c => bitsy/devpcmcia.c +181 -67
@@ 23,6 23,17 @@ enum
	Nents = 3,
};

enum
{
	/*
	 *  configuration registers - they start at an offset in attribute
	 *  memory found in the CIS.
	 */
	Rconfig=	0,
	 Creset=	 (1<<7),	/*  reset device */
	 Clevel=	 (1<<6),	/*  level sensitive interrupt line */
};

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


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

	if(i == DEVDOTDOT){


@@ 51,18 62,18 @@ pcmgen(Chan *c, Dirtab *, int , int i, Dir *dp)
		return -1;

	slotno = i/Nents;
	pp = slot + slotno;
	sp = slot + slotno;
	len = 0;
	switch(i%Nents){
	case 0:
		qid.path = QID(slotno, Qmem);
		sprint(name, "pcm%dmem", slotno);
		len = pp->memlen;
		len = sp->memlen;
		break;
	case 1:
		qid.path = QID(slotno, Qattr);
		sprint(name, "pcm%dattr", slotno);
		len = pp->memlen;
		len = sp->memlen;
		break;
	case 2:
		qid.path = QID(slotno, Qctl);


@@ 74,6 85,17 @@ pcmgen(Chan *c, Dirtab *, int , int i, Dir *dp)
	return 1;
}

static int
bitno(ulong x)
{
	int i;

	for(i = 0; i < 8*sizeof(x); i++)
		if((1<<i) & x)
			break;
	return i;
}

/*
 *  set up the cards, default timing is 300 ns
 */


@@ 88,9 110,13 @@ pcmciareset(void)
	slottiming(0, 300, 300, 300, 0);
	slottiming(1, 300, 300, 300, 0);

	/* interrupt on card insertion/removal */
	gpiointrenable(GPIO_CARD_IND1_i, GPIOboth, slotinfo, nil, "pcmcia slot1 status");
	gpiointrenable(GPIO_CARD_IND0_i, GPIOboth, slotinfo, nil, "pcmcia slot0 status");
	/* if there's no pcmcia sleave, no interrupts */
	if(gpioregs->level & GPIO_OPT_IND_i)
		return;

	/* sleave there, interrupt on card removal */
	intrenable(GPIOrising, bitno(GPIO_CARD_IND1_i), slotinfo, nil, "pcmcia slot1 status");
	intrenable(GPIOrising, bitno(GPIO_CARD_IND0_i), slotinfo, nil, "pcmcia slot0 status");
}

static Chan*


@@ 160,18 186,25 @@ memmoves(uchar *to, uchar *from, int n)
}

static long
pcmread(void *a, long n, ulong off, uchar *start, ulong len)
pcmread(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
{
	rlock(sp);
	if(waserror()){
		runlock(sp);
		nexterror();
	}
	if(off > len)
		return 0;
	if(off + n > len)
		n = len - off;
	memmoveb(a, start+off, n);
	runlock(sp);
	poperror();
	return n;
}

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



@@ 183,10 216,10 @@ pcmctlread(void *a, long n, ulong off, PCMslot *pp)
	e = p + READSTR;

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



@@ 199,70 232,137 @@ pcmctlread(void *a, long n, ulong off, PCMslot *pp)
static long
pcmciaread(Chan *c, void *a, long n, vlong off)
{
	PCMslot *pp;
	PCMslot *sp;
	ulong offset = off;

	pp = slot + SLOTNO(c);
	sp = slot + SLOTNO(c);

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

static long
pcmwrite(void *a, long n, ulong off, uchar *start, ulong len)
pcmwrite(void *a, long n, ulong off, PCMslot *sp, uchar *start, ulong len)
{
	rlock(sp);
	if(waserror()){
		runlock(sp);
		nexterror();
	}
	if(off > len)
		error(Eio);
	if(off + n > len)
		error(Eio);
	memmoveb(start+off, a, n);
	poperror();
	runlock(sp);
	return n;
}

static long
pcmctlwrite(char *p, long n, ulong off, PCMslot *pp)
pcmctlwrite(char *p, long n, ulong, PCMslot *sp)
{
	/* nothing yet */
	USED(p, n, off, pp);
	error(Ebadarg);
	Cmdbuf *cmd;
	uchar *cp;
	int index, i, dtx;
	Rune r;
	DevConf cf;

	cmd = parsecmd(p, n);
	if(strcmp(cmd->f[0], "configure") == 0){
		wlock(sp);
		if(waserror()){
			wunlock(sp);
			nexterror();
		}

		/* see if driver exists and is configurable */
		if(cmd->nf < 3)
			error(Ebadarg);
		p = cmd->f[1];
		if(*p++ != '#')
			error(Ebadarg);
		p += chartorune(&r, p);
		dtx = devno(r, 1);
		if(dtx < 0)
			error("no such device type");
		if(devtab[dtx]->config == nil)
			error("not a dynamicly configurable device");

		/* set pcmcia card configuration */
		index = 0;
		if(sp->def != nil)
			index = sp->def->index;
		if(cmd->nf > 3){
			i = atoi(cmd->f[3]);
			if(i < 0 || i >= sp->nctab)
				error("bad configuration index");
			index = i;
		}
		if(sp->cpresent & (1<<Rconfig)){
			cp = sp->attr;
			cp += sp->caddr + Rconfig;
print("writing configuration register (%lux) with index %d\n", cp, index);
			*cp = index;
		}

		/* configure device */
		strncpy(cf.type, cmd->f[2], sizeof(cf.type)-1);
		cf.type[sizeof(cf.type)-1] = 0;
		cf.mem = (ulong)sp->mem;
		cf.port = (ulong)sp->regs;
		cf.itype = GPIOfalling;
		cf.interrupt = bitno(sp == slot ? GPIO_CARD_IRQ0_i : GPIO_CARD_IRQ1_i);
		cf.size = 0;
		if(devtab[dtx]->config(1, p, &cf) < 0)
			error("couldn't configure device");

		wunlock(sp);
		poperror();

		/* don't let the power turn off */
		increfp(sp);
	}
	free(cmd);

	return 0;
}

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

	pp = slot + SLOTNO(c);
	sp = slot + SLOTNO(c);

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


@@ 303,71 403,85 @@ slotinfo(Ureg*, void*)
		if(x & GPIO_CARD_IND0_i){
			slot[0].occupied = 0;
			slot[0].cisread = 0;
		} else if(slot[0].occupied == 0){
		} else {
			if(slot[0].occupied == 0)
				slot[0].cisread = 0;
			slot[0].occupied = 1;
			slot[0].cisread = 0;
		}
		if(x & GPIO_CARD_IND1_i){
			slot[1].occupied = 0;
			slot[1].cisread = 0;
		} else if(slot[1].occupied == 0){
		} else {
			if(slot[1].occupied == 0)
				slot[1].cisread = 0;
			slot[1].occupied = 1;
			slot[1].cisread = 0;
		}
	}
}

/* use reference card to turn cards on and off */
static void
increfp(PCMslot *pp)
increfp(PCMslot *sp)
{
	wlock(sp);
	if(waserror()){
		wunlock(sp);
		nexterror();
	}

	if(incref(&pcmcia) == 1){
		egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 1);
		delay(200);
		egpiobits(EGPIO_pcmcia_reset, 1);
		delay(100);
		egpiobits(EGPIO_pcmcia_reset, 0);
		delay(200);	/* time to power up */
		delay(500);
	}
	incref(&pp->ref);
	if(pp->occupied && pp->cisread == 0)
		pcmcisread(pp);
	incref(&sp->ref);
	slotinfo(nil, nil);
	if(sp->occupied && sp->cisread == 0)
		pcmcisread(sp);

	wunlock(sp);
	poperror();
}

static void
decrefp(PCMslot *pp)
decrefp(PCMslot *sp)
{
	decref(&pp->ref);
	decref(&sp->ref);
	if(decref(&pcmcia) == 0)
		egpiobits(EGPIO_exp_nvram_power|EGPIO_exp_full_power, 0);
}

/*
 *  the regions are staticly mapped
 *  the regions are staticly masped
 */
static void
slotmap(int slotno, ulong regs, ulong attr, ulong mem)
{
	PCMslot *pp;

	pp = &slot[slotno];
	pp->slotno = slotno;
	pp->memlen = 64*OneMeg;
	pp->msec = ~0;
	pp->verstr[0] = 0;

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

	pp->attr = mapmem(attr, OneMeg, 0);
	pp->attrmap.ca = 0;
	pp->attrmap.cea = MB;
	pp->attrmap.isa = (ulong)attr;
	pp->attrmap.len = OneMeg;
	pp->attrmap.attr = 1;

	pp->regs = mapspecial(regs, 32*1024);
	PCMslot *sp;

	sp = &slot[slotno];
	sp->slotno = slotno;
	sp->memlen = 64*OneMeg;
	sp->verstr[0] = 0;

	sp->mem = mapmem(mem, 64*OneMeg, 0);
	sp->memmap.ca = 0;
	sp->memmap.cea = 64*MB;
	sp->memmap.isa = (ulong)mem;
	sp->memmap.len = 64*OneMeg;
	sp->memmap.attr = 0;

	sp->attr = mapmem(attr, OneMeg, 0);
	sp->attrmap.ca = 0;
	sp->attrmap.cea = MB;
	sp->attrmap.isa = (ulong)attr;
	sp->attrmap.len = OneMeg;
	sp->attrmap.attr = 1;

	sp->regs = mapspecial(regs, 32*1024);
}
PCMmap*
pcmmap(int slotno, ulong, int, int attr)

M bitsy/etherif.h => bitsy/etherif.h +3 -0
@@ 5,7 5,10 @@ enum {

typedef struct Ether Ether;
struct Ether {
	DevConf;

	int	ctlrno;
	int	tbdf;			/* type+busno+devno+funcno */
	int	mbps;			/* Mbps */
	int	minmtu;
	int 	maxmtu;

M bitsy/fns.h => bitsy/fns.h +8 -4
@@ 10,6 10,7 @@ int	cistrcmp(char*, char*);
int	cistrncmp(char*, char*, int);
void	clockinit(void);
#define	coherence()
#define	dcflush(a, b)
void	delay(int);
void	µdelay(int);
void	dmainit(void);


@@ 30,7 31,10 @@ void	h3650uartsetup(void);
void	icacheinvalidate(void);
void	idle(void);
void	idlehands(void);
void	intrenable(int, void (*)(Ureg*, void*), void*, char*);
uchar	inb(ulong);
ushort	ins(ulong);
ulong	inl(ulong);
void	intrenable(int, int, void (*)(Ureg*, void*), void*, char*);
int	iprint(char*, ...);
void	irpower(int);
void	lcdpower(int);


@@ 49,6 53,9 @@ ulong	mmu_paddr(ulong);
int	µcputc(Queue*, int);
void	noted(Ureg*, ulong);
int	notify(Ureg*);
void	outb(ulong, uchar);
void	outs(ulong, ushort);
void	outl(ulong, ulong);
void	pcmcisread(PCMslot*);
int	pcmcistuple(int, int, int, void*, int);
PCMmap*	pcmmap(int, ulong, int, int);


@@ 62,7 69,6 @@ void	putdac(ulong);
void	putttb(ulong);
void	putpid(ulong);
void	qpanic(char *, ...);
void	reset(void);
void	rs232power(int);
Uart*	uartsetup(PhysUart*, void*, ulong, char*);
void	uartspecial(Uart*, int, Queue**, Queue**, int (*)(Queue*, int));


@@ 89,5 95,3 @@ void	wbflush(void);
#define PADDR(a) mmu_paddr((ulong)(a))

#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))

#define	dcflush(a, b)

M bitsy/io.h => bitsy/io.h +2 -1
@@ 110,13 110,14 @@ enum
};

/*
 *  edge argument for gpiointrenable
 *  types of interrupts
 */
enum
{
	GPIOrising,
	GPIOfalling,
	GPIOboth,
	IRQ,
};

/* hardware registers */

M bitsy/l.s => bitsy/l.s +1 -1
@@ 222,7 222,7 @@ TEXT vtable(SB), $-4
	WORD	$_vfiq(SB)			/* FIQ, switch to svc mode */

TEXT _vrst(SB), $-4
	BL	reset(SB)
	BL	resettrap(SB)

TEXT _vsvc(SB), $-4			/* SWI */
	MOVW.W	R14, -4(R13)		/* ureg->pc = interupted PC */

M bitsy/main.c => bitsy/main.c +47 -0
@@ 43,6 43,7 @@ main(void)
	clockinit();
	procinit0();
	initseg();
	links();
	chandevreset();
	pageinit();
	swapinit();


@@ 430,3 431,49 @@ flashprogpower(int on)
{
	egpiobits(EGPIO_prog_flash, on);
}

/* here on hardware reset */
void
resettrap(void)
{
}

/*
 *  for drivers that used to run on x86's
 */
void
outb(ulong a, uchar v)
{
	*(uchar*)a = v;
	µdelay(2);
}
void
outs(ulong a, ushort v)
{
	*(ushort*)a = v;
	µdelay(2);
}
void
outl(ulong a, ulong v)
{
	*(ulong*)a = v;
	µdelay(2);
}
uchar
inb(ulong a)
{
	µdelay(2);
	return *(uchar*)a;
}
ushort
ins(ulong a)
{
	µdelay(2);
	return *(ushort*)a;
}
ulong
inl(ulong a)
{
	µdelay(2);
	return *(ulong*)a;
}

M bitsy/sa1110dma.c => bitsy/sa1110dma.c +1 -1
@@ 74,7 74,7 @@ dmainit(void) {
	if (debug) print("dma: dmaalloc registers 0x%ux mapped at 0x%p\n",
		DMAREGS, dmaregs);
	for (i = 0; i < NDMA; i++) {
		intrenable(IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
		intrenable(IRQ, IRQdma0+i, dmaintr, &dmaregs[i], "DMA");
	}
}


M bitsy/sa1110uart.c => bitsy/sa1110uart.c +2 -2
@@ 424,7 424,7 @@ sa1100_uartsetup(int console)
	/* external serial port (eia0) */
	uart3regs = mapspecial(UART3REGS, 64);
	p = uartsetup(&sa1100_uart, uart3regs, ClockFreq, "serialport3");
	intrenable(IRQuart3, sa1100_uartintr, p, p->name);
	intrenable(IRQ, IRQuart3, sa1100_uartintr, p, p->name);

	/* set eia0 up as a console */
	if(console)


@@ 436,5 436,5 @@ sa1100_uartsetup(int console)
	uart1regs = mapspecial(UART1REGS, 64);
	p = uartsetup(&sa1100_uart, uart1regs, ClockFreq, "serialport1");
	uartspecial(p, 115200, 0, 0, µcputc);
	intrenable(IRQuart1b, sa1100_uartintr, p, p->name);
	intrenable(IRQ, IRQuart1b, sa1100_uartintr, p, p->name);
}

M bitsy/trap.c => bitsy/trap.c +24 -33
@@ 114,10 114,10 @@ warnregs(Ureg *ur, char *tag)
}

/*
 *  enable an interrupt and attach a function to it
 *  enable an irq interrupt
 */
void
intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
irqenable(int irq, IntrHandler *f, void* a, char *name)
{
	Vctl *v;



@@ 138,28 138,29 @@ intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
}

/*
 *  enable an interrupt on gpio line.  edge is encoded as follows
 *  enable an interrupt
 */
void
gpiointrenable(ulong mask, int edge, void (*f)(Ureg*, void*), void* a, char *name)
intrenable(int type, int which, IntrHandler *f, void* a, char *name)
{
	int irq, bit;
	int irq;
	Vctl *v;

	/* figure out which bit */
	for(bit = 0; bit < 32; bit++)
		if((1<<bit) == mask)
			break;
	if(type == IRQ){
		irqenable(which, f, a, name);
		return;
	}

	irq = bit;
	if(bit >= nelem(gpiovctl) || bit < 0)
	/* from here down, it must be a GPIO edge interrupt */
	irq = which;
	if(which >= nelem(gpiovctl) || which < 0)
		panic("gpiointrenable");
	if(bit > 11)
	if(which > 11)
		irq = 11;

	/* the pin had better be configured as input */
	if((1<<bit) & gpioregs->direction)
		panic("gpiointrenable of output pin %d", bit);
	if((1<<which) & gpioregs->direction)
		panic("gpiointrenable of output pin %d", which);

	/* create a second level vctl for the gpio edge interrupt */
	v = xalloc(sizeof(Vctl));


@@ 169,26 170,27 @@ gpiointrenable(ulong mask, int edge, void (*f)(Ureg*, void*), void* a, char *nam
	v->name[NAMELEN-1] = 0;

	lock(&vctllock);
	v->next = gpiovctl[bit];
	gpiovctl[bit] = v;
	v->next = gpiovctl[which];
	gpiovctl[which] = v;
	unlock(&vctllock);

	/* set edge register to enable interrupt */
	switch(edge){
	switch(type){
	case GPIOboth:
		gpioregs->rising |= mask;
		gpioregs->falling |= mask;
		gpioregs->rising |= 1<<which;
		gpioregs->falling |= 1<<which;
		break;
	case GPIOfalling:
		gpioregs->falling |= mask;
		gpioregs->falling |= 1<<which;
		break;
	case GPIOrising:
		gpioregs->rising |= mask;
		gpioregs->rising |= 1<<which;
		break;
	}

	/* point the irq to the gpio interrupt handler */
	if(gpioirqref[irq]++ == 0)
		intrenable(irq, gpiointr, nil, "gpio edge");
		irqenable(irq, gpiointr, nil, "gpio edge");
}

/*


@@ 376,8 378,6 @@ gpiointr(Ureg *ur, void*)
	va = gpioregs->edgestatus;
	gpioregs->edgestatus = va;

iprint("gpio intr %lux\n", va);

	for(i = 0; i < 27; i++){
		if(((1<<i) & va) == 0)
			continue;


@@ 792,12 792,3 @@ evenaddr(ulong addr)
		error(Ebadarg);
	}
}


/*
 *  here on a hardware reset
 */
void
reset(void)
{
}

M port/cis.c => port/cis.c +8 -2
@@ 411,21 411,27 @@ tentry(PCMslot *pp, Cisdat *cis, int )
static void
tvers1(PCMslot *pp, Cisdat *cis, int )
{
	uchar c, major, minor;
	uchar c, major, minor, last;
	int  i;

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

M port/portdat.h => port/portdat.h +2 -0
@@ 9,6 9,7 @@ typedef struct Dirtab	Dirtab;
typedef struct Egrp	Egrp;
typedef struct Evalue	Evalue;
typedef struct Fgrp	Fgrp;
typedef struct DevConf	DevConf;
typedef struct Image	Image;
typedef struct List	List;
typedef struct Log	Log;


@@ 194,6 195,7 @@ struct Dev
	void	(*remove)(Chan*);
	void	(*wstat)(Chan*, char*);
	void	(*power)(int);	/* power mgt: power(1) → on, power (0) → off */
	int	(*config)(int, char*, DevConf*);
};

struct Dirtab