~kris/9p

9hist

bb057084b22eb93eeca977bed0906e7644cc10d4 — David du Colombier 25 years ago 40a8025
Plan 9 from Bell Labs 2000-11-16
5 files changed, 159 insertions(+), 108 deletions(-)

M bitsy/devuda1341.c
M bitsy/io.h
M bitsy/main.c
M bitsy/sa1110dma.c
M pc/devi82365.c
M bitsy/devuda1341.c => bitsy/devuda1341.c +50 -58
@@ 138,7 138,6 @@ struct	IOstate
	int				dma;			/* dma chan, alloc on open, free on close */
	int				bufinit;		/* boolean, if buffers allocated */
	Buf				buf[Nbuf];		/* buffers and queues */
	Ref				active;			/* # of dmas in progress */
	volatile Buf	*current;		/* next dma to finish */
	volatile Buf	*next;			/* next candidate for dma */
	volatile Buf	*filling;		/* buffer being filled */


@@ 159,6 158,14 @@ static	struct
	IOstate	o;
} audio;

static struct
{
	ulong	bytes;
	ulong	totaldma;
	ulong	idledma;
	ulong	faildma;
} iostats;

static	struct
{
	char*	name;


@@ 404,22 411,7 @@ audioqnotfull(void *x)
	IOstate *s = x;

	/* called with lock */
	return s->active.ref == 0 || s->filling != s->current;
}

static int
audioqnotempty(IOstate *s)
{
	/* called with lock */
	return s->next != s->filling;
}

static int
audioidle(void *x)
{
	IOstate *s = x;
	/* called with lock */
	return s->active.ref == 0;
	return dmaidle(s->dma) || s->filling != s->current;
}

static void


@@ 436,50 428,46 @@ audioenable(void)
	L3_init();

	/* Setup the uarts */
    ppcregs->assignment &= (1<<18);	/* Could be the other way round! */
    ppcregs->assignment &= ~(1<<18);

    gpioregs->altfunc &= ~(GPIO_SSP_TXD_o | GPIO_SSP_RXD_i | GPIO_SSP_SCLK_o | GPIO_SSP_SFRM_o);
	gpioregs->altfunc |= (GPIO_SSP_CLK_i);
	gpioregs->direction &= ~(GPIO_SSP_CLK_i);

	sspregs->control0 = 0xf<<0 | 0x1<<4 | 0x3<<8;
	sspregs->control1 = 0<<3 + 0<<4 + 1<<5;

	sspregs->control0 |= 1<<7;	/* enable */
	sspregs->control0 = 0;
	sspregs->control0 = 0x031f; /* 16 bits, TI frames, serial clock rate 3 */
	sspregs->control1 = 0x0020; /* ext clock */
	sspregs->control0 = 0x039f;	/* enable */

	/* Enable the audio power */
	audiopower(1);
	amplifierpower(1);
	audiomute(0);

	/* external clock configured for 44100 samples/sec */
	gpioregs->direction |=  (GPIO_CLK_SET0_o|GPIO_CLK_SET1_o);
	  /* external clock configured for 44100 samples/sec */
    gpioregs->set = GPIO_CLK_SET0_o;
    gpioregs->clear = GPIO_CLK_SET1_o;
 
/* This is purportedly the wrong way round: 0 should be set, 1 cleared */
    gpioregs->set	= GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
//    gpioregs->clear	= GPIO_CLK_SET1_o;

	/* Wait for the UDA1341 to wake up */
	delay(100);
    print("Ser4SSSR=0x%lux\n", sspregs->status);

    gpioregs->clear = EGPIO_codec_reset;
    gpioregs->set = EGPIO_codec_reset;

	/* Reset the chip */
	data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */ | 1<<6 /* reset */;
	data[0] = 2<<UdaStatusSC | 1<<UdaStatusIF | 1<<UdaStatusRST;
	L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );
	gpioregs->set = EGPIO_codec_reset;
	gpioregs->clear = EGPIO_codec_reset;
	/* write uda 1341 status[0] */
	data[0] &= ~(1<<UdaStatusRST); /* clear reset */
	L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );

	delay(10);

	data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */;
	L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, data, 1 );
	/* Reset done */

	/* write uda 1341 status[1] */
	data[0] = 0x80 | 0x3<<UdaStatusPC | 1<<UdaStatusIGS | 1<<UdaStatusOGS;
	L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1);

	/* write uda 1341 data0[0] (volume) */
	data[0] = 0x00 | /* volume */ 15 & 0x3f;	/* 6 bits, others must be 0 */
	data[0] = 15 & 0x3f;	/* 6 bits, others must be 0 */
	L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 1);

	/* write uda 1341 data0[2] (mode switch) */


@@ 501,31 489,28 @@ audioenable(void)
	data[1] = 0xe0 | 0<<2 | 3;	/* agc time constant and output level */
	L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2 );

	/* Reset the chip */
	data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */ | 1<<6 /* reset */;
	L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );

	delay(10);

	data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */;
	L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, data, 1 );
	/* Reset done */

	if (debug) print("#A: audio enabled\n");
	if (debug) {
		print("#A: audio enabled\n");
		print("\tsspregs->control0 = 0x%lux\n", sspregs->control0);
		print("\tsspregs->control1 = 0x%lux\n", sspregs->control1);
	}
}

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

	if (debug > 1) print("#A: sendaudio\n");
	ilock(&b->ilock);
	while (b->next != b->filling) {
		assert(b->next->nbytes);
		incref(&b->active);
		if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0) {
			decref(&b->active);
		if ((n = dmastart(b->dma, b->next->virt, b->next->nbytes)) == 0) {
			iostats.faildma++;
			break;
		}
		iostats.totaldma++;
		if (n == 1) iostats.idledma++;
		if (debug > 1) print("#A: dmastart @%p\n", b->next);
		b->next->nbytes = 0;
		b->next++;


@@ 536,7 521,7 @@ sendaudio(IOstate *b) {
}

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

	if (s == &audio.o) {


@@ 545,8 530,8 @@ audiointr(void *x, ulong) {
		s->current++;
		if (s->current == &s->buf[Nbuf])
			s->current = &s->buf[0];
		decref(&s->active);
		sendaudio(s);
		if (ndma > 0)
			sendaudio(s);
	}
	wakeup(&s->vous);
}


@@ 596,6 581,7 @@ audioopen(Chan *c, int omode)
			error(Einuse);
		}
		audioenable();
		memset(&iostats, 0, sizeof(iostats));
		if (omode & Aread) {
			/* read */
			audio.amode |= Aread;


@@ 663,10 649,13 @@ audioclose(Chan *c)
						audio.o.filling = &audio.o.buf[0];
					sendaudio(&audio.o);
				}
				while(!audioidle(&audio.o))
					sleep(&audio.o.vous, audioidle, &audio.o);
				delay(2000);
		//		dmawait(audio.o.dma);
				if (!dmaidle(audio.o.dma))
					print("dma still busy\n");
				amplifierpower(0);
				setempty(&audio.o);
				dmafree(audio.o.dma);
			}
			if (audio.i.chan == c) {
				/* closing the read end */


@@ 680,6 669,9 @@ audioclose(Chan *c)
			poperror();
			qunlock(&audio.o);
			qunlock(&audio);
			print("total dmas: %lud\n", iostats.totaldma);
			print("dmas while idle: %lud\n", iostats.idledma);
			print("dmas while busy: %lud\n", iostats.faildma);
		}
		break;
	}


@@ 857,7 849,7 @@ audiowrite(Chan *c, void *vp, long n, vlong)
		}
		while(n > 0) {
			/* wait if dma in progress */
			while (a->active.ref && a->filling == a->current) {
			while (!dmaidle(a->dma) && a->filling == a->current) {
				if (debug > 1) print("#A: sleep\n");
				sleep(&a->vous, audioqnotfull, a);
			}

M bitsy/io.h => bitsy/io.h +15 -0
@@ 248,3 248,18 @@ struct SSPregs {
	ulong	status;
};
extern SSPregs *sspregs;

/* Multimedia Communications Port controller registers */
typedef struct MCPregs MCPregs;
struct MCPregs {
	ulong	control0;
	ulong	reserved0;
	ulong	data0;
	ulong	data1;
	ulong	data2;
	ulong	reserved1;
	ulong	status;
	ulong	reserved[11];
	ulong	control1;
};
extern MCPregs *mcpregs;

M bitsy/main.c => bitsy/main.c +11 -0
@@ 16,6 16,7 @@ int 	noprint;
static void	gpioinit(void);
static void ppcinit(void);
static void sspinit(void);
static void mcpinit(void);

void
main(void)


@@ 39,6 40,7 @@ main(void)
	mmuinit();
	gpioinit();
	ppcinit();
	mcpinit();
	sspinit();
	trapinit();
	sa1100_uartsetup(1);


@@ 386,6 388,15 @@ ppcinit(void) {
	ppcregs = mapspecial(PPCREGS, 32);
}

MCPregs *mcpregs;

static void
mcpinit(void) {
	mcpregs = mapspecial(MCPREGS, 0x34);
	mcpregs->status &= ~(1<<16);
	/* Turn MCP operations off */
}

SSPregs *sspregs;

static void

M bitsy/sa1110dma.c => bitsy/sa1110dma.c +41 -25
@@ 41,8 41,8 @@ enum {
};

typedef struct DMAchan {
	Lock;
	int		allocated;
	Ref		active;
	Rendez	r;
	void	(*intr)(void*, ulong);
	void	*param;


@@ 116,51 116,58 @@ dmafree(int i) {

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

	ilock(&dma.chan[chan]);
	status = dmaregs[chan].dcsr_rd;
	if (debug > 1) print("dma: dmastart 0x%lux\n", status);
	if (debug > 1)
		iprint("dma: dmastart 0x%lux\n", status);

	if (dma.chan[chan].active.ref >= 2) {
		if (debug > 1) print("\n");
	if ((status & (1<<STRTA|1<<STRTB|1<<RUN)) == (1<<STRTA|1<<STRTB|1<<RUN)) {
		iunlock(&dma.chan[chan]);
		return 0;
	}

	if ((status & (1<<DONEA|1<<DONEB|1<<RUN)) == 1<<RUN)
		panic("dmastart called while busy");

	cachewbregion((ulong)addr, count);
	n = 1;
	if ((status & (1<<BIU | 1<<STRTB)) == (1<<BIU | 1<<STRTB) ||
		(status & (1<<BIU | 1<<STRTA)) == 0) {
		dmaregs[chan].dcsr_clr = 1<<DONEA | 1<<STRTA;
		assert((status & 1<<STRTA) == 0);
		if (status & 1<<RUN)
			n = 2;
		dmaregs[chan].dstrtA = addr;
		dmaregs[chan].dxcntA = count-1;
		incref(&dma.chan[chan].active);
		dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTA;
		return 1<<DONEA;
	} else {
		dmaregs[chan].dcsr_clr = 1<<DONEB | 1<<STRTB;
		assert((status & 1<<STRTB) == 0);
		if (status & 1<<RUN)
			n = 2;
		dmaregs[chan].dstrtB = addr;
		dmaregs[chan].dxcntB = count-1;
		incref(&dma.chan[chan].active);
		dmaregs[chan].dcsr_set = 1<<RUN | 1<<IE | 1<<STRTB;
		return 1<<DONEB;
	}
	iunlock(&dma.chan[chan]);
	return n;
}

int
dmaidle(int chan) {
	return dma.chan[chan].active.ref == 0;
	ulong status;

	status = dmaregs[chan].dcsr_rd;
	return (status & (1<<STRTA|1<<STRTB|1<<RUN)) == 0;
}

static int
_dmaidle(void* chan) {
	return dma.chan[(int)chan].active.ref == 0;
	ulong status;

	status = dmaregs[(int)chan].dcsr_rd;
	return (status & (1<<STRTA|1<<STRTB|1<<RUN)) == 0;
}

void
dmawait(int chan) {
	while (dma.chan[chan].active.ref)
	while (!dmaidle(chan))
		sleep(&dma.chan[chan].r, _dmaidle, (void*)chan);
}



@@ 175,6 182,7 @@ dmaintr(Ureg*, void *x)
	ulong dcsr, donebit;

	i = regs - dmaregs;
	ilock(&dma.chan[i]);
	dcsr = regs->dcsr_rd;
	if (debug > 1)
		iprint("dma: interrupt channel %d, status 0x%lux\n", i, dcsr);


@@ 182,12 190,20 @@ dmaintr(Ureg*, void *x)
		iprint("error, channel %d, status 0x%lux\n", i, dcsr);
	donebit = 1<<((dcsr&1<<BIU)?DONEA:DONEB);
	if (dcsr & donebit) {
		regs->dcsr_clr |= donebit;
		if (dma.chan[i].intr)
			(*dma.chan[i].intr)(dma.chan[i].param, 3-dma.chan[i].active.ref);
		/* must call interrupt routine before calling decref */
		decref(&dma.chan[i].active);
		regs->dcsr_clr = donebit;
		/* try the other bit as well */
		donebit ^= 1<<DONEA|1<<DONEB;
		if (dcsr & donebit) {
			regs->dcsr_clr = donebit;
		}
		iunlock(&dma.chan[i]);
		if (dma.chan[i].intr) {
			dcsr &= 1<<STRTA | 1<<STRTB | 1<<RUN;
			(*dma.chan[i].intr)(dma.chan[i].param, dcsr == 0);
		}
		wakeup(&dma.chan[i].r);
	} else
		iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
		return;
	}
	iprint("spurious DMA interrupt, channel %d, status 0x%lux\n", i, dcsr);
	iunlock(&dma.chan[i]);
}

M pc/devi82365.c => pc/devi82365.c +42 -25
@@ 446,19 446,23 @@ pcmspecial(char *idstr, ISAConf *isa)
	for(pp = slot; pp < lastslot; pp++){
		if(pp->special)
			continue;	/* already taken */
		enabled = 0;
		/* make sure we don't power on cards when we already know what's
		 * in them.  We'll reread every two minutes if necessary

		/*
		 *  make sure we don't power on cards when we already know what's
		 *  in them.  We'll reread every two minutes if necessary
		 */
		if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000) {
		enabled = 0;
		if (pp->msec == ~0 || TK2MS(MACHP(0)->ticks) - pp->msec > 120000){
			increfp(pp);
			enabled++;
		}

		if(pp->occupied) {
			if(strstr(pp->verstr, idstr)) {
				if (!enabled)
			if(strstr(pp->verstr, idstr)){
				if (!enabled){
					enabled = 1;
					increfp(pp);
				}
				if(isa == 0 || pcmio(pp->slotno, isa) == 0){
					pp->special = 1;
					return pp->slotno;


@@ 557,7 561,9 @@ i82365probe(int x, int d, int dev)
	outb(x, Rid + (dev<<7));
	id = inb(d);
	if((id & 0xf0) != 0x80)
		return 0;		/* not this family */
		return 0;		/* not a memory & I/O card */
	if((id & 0x0f) == 0x00)
		return 0;		/* no revision number, not possible */

	cp = xalloc(sizeof(I82365));
	cp->xreg = x;


@@ 588,22 594,28 @@ 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 */
		outb(x, 0x0E + (dev<<7));
		outb(x, 0x37 + (dev<<7));

		/* make the id register show the Vadem id */
		outb(x, 0x3A + (dev<<7));
		c = inb(d);
		outb(d, c|0xC0);
		outb(x, Rid + (dev<<7));
		c = inb(d);
		if(c != id && !(c & 0x08))
			print("#y%d: id %uX changed to %uX\n", ncontroller, id, c);
		if(c & 0x08)
			cp->type = Tvg46x;

		/* go back to Intel compatible id */
		outb(x, 0x3A + (dev<<7));
		c = inb(d);
		outb(d, c & ~0xC0);
	}
#endif asdf

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


@@ 661,14 673,14 @@ i82365reset(void)

	/* look for controllers if the ports aren't already taken */
	if(ioalloc(0x3E0, 2, 0, "i82365.0") >= 0){
		i82365probe(0x3E0, 0x3E1, 0) ||
		i82365probe(0x3E0, 0x3E1, 0);
		i82365probe(0x3E0, 0x3E1, 1);
		if(ncontroller == 0)
			iofree(0x3E0);
	}
	if(ioalloc(0x3E2, 2, 0, "i82365.1") >= 0){
		i = ncontroller;
		i82365probe(0x3E2, 0x3E3, 0) ||
		i82365probe(0x3E2, 0x3E3, 0);
		i82365probe(0x3E2, 0x3E3, 1);
		if(ncontroller == i)
			iofree(0x3E2);


@@ 690,6 702,7 @@ i82365reset(void)
			pp->base = (cp->dev<<7) | (j<<6);
			pp->cp = cp;
			pp->msec = ~0;
			pp->verstr[0] = 0;
			slotdis(pp);

			/* interrupt on status change */


@@ 813,8 826,7 @@ pcmread(int slotno, int attr, void *a, long n, vlong off)
static long
i82365read(Chan *c, void *a, long n, vlong off)
{
	char *p;
	int len;
	char *p, *buf, *e;
	Slot *pp;
	ulong offset = off;



@@ 825,26 837,30 @@ i82365read(Chan *c, void *a, long n, vlong off)
	case Qattr:
		return pcmread(SLOTNO(c), TYPE(c) == Qattr, a, n, off);
	case Qctl:
		p = malloc(READSTR);
		len = 0;
		buf = p = malloc(READSTR);
		e = p + READSTR;
		pp = slot + SLOTNO(c);

		if(pp->occupied)
			len += snprint(p+len, READSTR-len, "occupied\n");
		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);
		}
		if(pp->enabled)
			len += snprint(p+len, READSTR-len, "enabled\n");
			p = seprint(p, e, "enabled\n");
		if(pp->powered)
			len += snprint(p+len, READSTR-len, "powered\n");
			p = seprint(p, e, "powered\n");
		if(pp->configed)
			len += snprint(p+len, READSTR-len, "configed\n");
			p = seprint(p, e, "configed\n");
		if(pp->wrprot)
			len += snprint(p+len, READSTR-len, "write protected\n");
			p = seprint(p, e, "write protected\n");
		if(pp->busy)
			len += snprint(p+len, READSTR-len, "busy\n");
		snprint(p+len, READSTR-len, "battery lvl %d\n", pp->battery);
			p = seprint(p, e, "busy\n");
		seprint(p, e, "battery lvl %d\n", pp->battery);

		n = readstr(offset, a, n, p);
		free(p);
		n = readstr(offset, a, n, buf);
		free(buf);

		return n;
	}


@@ 1183,6 1199,7 @@ cisread(Slot *pp)
	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) {