~kris/9p

9hist

12db97fe6b1cd05b962cb2c0dec6f5e099afbcc8 — David du Colombier 25 years ago 3e56e7c
Plan 9 from Bell Labs 2001-05-08
3 files changed, 125 insertions(+), 28 deletions(-)

M bitsy/devuda1341.c
M port/devsegment.c
M port/segment.c
M bitsy/devuda1341.c => bitsy/devuda1341.c +106 -11
@@ 94,6 94,7 @@ enum
	Qdir		= 0,
	Qaudio,
	Qvolume,
	Qspeed,
	Qstatus,

	Fmono		= 1,


@@ 120,11 121,29 @@ enum
	Ncmd		= 50,		/* max volume command words */
};

enum {
	Flushbuf = 0xe0000000,
};

/* System Clock */
enum {
	SC512FS = 0,
	SC384FS = 1,
	SC256FS = 2,
};

/* Format */
enum {
	LSB16 = 1,
	LSB18 = 2,
};

Dirtab
audiodir[] =
{
	"audio",	{Qaudio},		0,	0666,
	"audio",	{Qaudio},			0,	0666,
	"volume",	{Qvolume},		0,	0666,
	"speed",	{Qspeed},			0,	0666,
	"audiostat",{Qstatus},		0,	0444,
};



@@ 166,7 185,6 @@ static	struct
	IOstate	o;
} audio;

Buf	zeroes;
int	zerodma;	/* dma buffer used for sending zero */

static struct


@@ 197,6 215,7 @@ static	struct
[Nvol]	{0}
};

static int rate = Speed;		/* Current sample rate */
static void	setreg(char *name, int val, int n);

/*


@@ 404,12 423,6 @@ bufinit(IOstate *b)
		memset(b->buf[i].virt, 0xAA, Bufsize);
	}
	b->bufinit = 1;

	if (b == &audio.o) {
		zeroes.virt = xalloc(Bufsize);
		zeroes.phys = PADDR(b->buf[i].virt);
		memset(zeroes.virt, 0, Bufsize);
	}
};

static void


@@ 470,6 483,9 @@ uchar	data0e5[2]	= {0xc5, 0xe0};
uchar	data0e6[2]	= {0xc6, 0xe3};

static void
mxspeed(int _rate);

static void
enable(void)
{
	uchar	data[1];


@@ 532,6 548,61 @@ resetlevel(void)
}

static void
mxspeed(int _rate)
{
	uchar data;

	egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
	/* set the external clock generator */
	rate = _rate;
	switch (rate) {
	case 32000:
	case 48000:
		/* 00 */
		gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
		break;
	default:
		rate = 44100;
	case 44100:
		/* 01 */
		gpioregs->set = GPIO_CLK_SET0_o;
		gpioregs->clear = GPIO_CLK_SET1_o;
		break;
	case 8000:
	case 16000:
		/* 10 */
		gpioregs->set = GPIO_CLK_SET1_o;
		gpioregs->clear = GPIO_CLK_SET0_o;
		break;
	case 11025:
	case 22050:
		/* 11 */
		gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
		break;
	}
	delay(100);

	switch (rate) {
	case 8000:
	case 11025:
		data = SC512FS;
		break;
	case 16000:
	case 22050:
	case 44100:
	case 48000:
		data = SC256FS;
		break;
	case 32000:
		data = SC384FS;
		break;
	}
	data |= (LSB16 << 4)|0x2;
	L3_write(UDA1341_L3Addr | UDA1341_STATUS, &data, 1);
}
	

static void
mxvolume(void) {
	int *left, *right;



@@ 694,7 765,7 @@ sendaudio(IOstate *s) {
	ilock(&s->ilock);
	if ((audio.amode &  Aread) && s->next == s->filling && dmaidle(s->dma)) {
		// send an empty buffer to provide an input clock
		zerodma |= dmastart(s->dma, zeroes.phys, Bufsize) & 0xff;
		zerodma |= dmastart(s->dma, Flushbuf, Bufsize) & 0xff;
		if (zerodma == 0)
			if (debug) print("emptyfail\n");
		iostats.empties++;


@@ 863,6 934,7 @@ audioopen(Chan *c, int mode)
		if((omode&7) != OREAD)
			error(Eperm);
	case Qvolume:
	case Qspeed:
	case Qdir:
		break;



@@ 900,6 972,7 @@ audioopen(Chan *c, int mode)
			audio.amode |= Awrite;
			outenable();
		}
		mxspeed(Speed);
		mxvolume();
		qunlock(&audio);
		if (audio.amode & Aread)


@@ 928,6 1001,7 @@ audioclose(Chan *c)

	case Qdir:
	case Qvolume:
	case Qspeed:
	case Qstatus:
		break;



@@ 1059,6 1133,11 @@ audioread(Chan *c, void *v, long n, vlong off)
			audio.totcount, audio.tottime);
		return readstr(offset, p, n, buf);

	case Qspeed:
		buf[0] = '\0';
		snprint(buf, sizeof(buf), "speed %d\n", rate);
		return readstr(offset, p, n, buf);

	case Qvolume:
		j = 0;
		buf[0] = 0;


@@ 1119,6 1198,23 @@ audiowrite(Chan *c, void *vp, long n, vlong)
		error(Eperm);
		break;

	case Qspeed:
		if(n > sizeof(buf)-1)
			n = sizeof(buf)-1;
		memmove(buf, p, n);
		buf[n] = '\0';
		nf = getfields(buf, field, Ncmd, 1, " \t\n");
		if (nf != 2 && nf != 1) error(Ebadarg);
		if (nf == 2) {
			if (strcmp(field[0], "speed")) 
				error(Ebadarg);
			i = 1;
		}
		else
			i = 0;
		mxspeed((int)strtol(field[i], (char **)nil, 0));
		break;
		
	case Qvolume:
		v = Vaudio;
		left = 1;


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

			m = Bufsize - a->filling->nbytes;
			if(m > n)
				m = n;

M port/devsegment.c => port/devsegment.c +9 -8
@@ 84,7 84,8 @@ putgseg(Globalseg *g)
{
	if(decref(g) > 0)
		return;
	putseg(g->s);
	if(g->s != nil)
		putseg(g->s);
	if(g->kproc)
		docmd(g, Cdie);
	free(g);


@@ 290,12 291,11 @@ segmentcreate(Chan *c, char *name, int omode, ulong perm)
	if(xfree < 0)
		error("too many global segments");
	g = smalloc(sizeof(Globalseg));
	g->ref = 2;
	g->ref = 1;
	strncpy(g->name, name, sizeof(g->name));
	strncpy(g->uid, up->user, sizeof(g->uid));
	g->perm = 0660; 
	globalseg[xfree] = g;
	c->aux = g;
	unlock(&globalseglock);
	poperror();



@@ 353,8 353,7 @@ segmentwrite(Chan *c, void *a, long n, vlong voff)
{
	Cmdbuf *cb;
	Globalseg *g;
	ulong va;
	ulong len;
	ulong va, len, top;

	if(c->qid.path&CHDIR)
		error(Eperm);


@@ 369,9 368,10 @@ segmentwrite(Chan *c, void *a, long n, vlong voff)
			if(cb->nf < 3)
				error(Ebadarg);
			va = strtoul(cb->f[1], 0, 0);
			va = va&~(BY2PG-1);
			len = strtoul(cb->f[2], 0, 0);
			len = ROUND(len, BY2PG)/BY2PG;
			top = PGROUND(va + len);
			va = va&~(BY2PG-1);
			len = (top - va) / BY2PG;
			if(len == 0)
				error(Ebadarg);
			g->s = newseg(SG_SHARED, va, len);


@@ 474,10 474,11 @@ globalsegattach(Proc *p, char *name)
	s = g->s;
	if(s == nil)
		error("global segment not assigned a virtual address");
	if(isoverlap(p, s->base, s->top-s->base) != nil)
	if(isoverlap(p, s->base, s->top) != nil)
		error("overlaps existing segment");
	incref(s);
	unlock(&globalseglock);
	poperror();
	return s;
}


M port/segment.c => port/segment.c +10 -9
@@ 541,13 541,11 @@ out:
}

Segment*
isoverlap(Proc *p, ulong va, int len)
isoverlap(Proc *p, ulong va, int newtop)
{
	int i;
	Segment *ns;
	ulong newtop;

	newtop = va+len;
	for(i = 0; i < NSEG; i++) {
		ns = p->seg[i];
		if(ns == 0)


@@ 609,6 607,7 @@ ulong
segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
{
	int sno;
	ulong top;
	Segment *s, *os;
	Physseg *ps;



@@ 626,7 625,7 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
		error(Enovmem);

	/*
 	 *  first look for a global segment with the
	 *  first look for a global segment with the
	 *  same name
	 */
	if(_globalsegattach != nil){


@@ 637,7 636,6 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
		}
	}

	len = PGROUND(len);
	if(len == 0)
		error(Ebadarg);



@@ 649,9 647,10 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
	 * or the address space is exhausted.
	 */
	if(va == 0) {
		len = PGROUND(len);
		va = p->seg[SSEG]->base - len;
		for(;;) {
			os = isoverlap(p, va, len);
			os = isoverlap(p, va, va+len);
			if(os == nil)
				break;
			va = os->base;


@@ 661,8 660,10 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
		}
	}

	top = PGROUND(va + len);
	va = va&~(BY2PG-1);
	if(isoverlap(p, va, len) != nil)
	len = top - va;
	if(isoverlap(p, va, top) != nil)
		error(Esoverlap);

	for(ps = physseg; ps->name; ps++)


@@ 701,9 702,9 @@ long
syssegflush(ulong *arg)
{
	Segment *s;
	ulong addr, l;
	ulong addr, l, ps, pe;
	Pte *pte;
	int chunk, ps, pe, len;
	int chunk, len;

	addr = arg[0];
	len = arg[1];