⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devuda1341.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
}static voidinenable(void) {	/* turn on ADC, set input gain switch */	status1[0] |= 0x22;	L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);	if (debug) {		print("inenable:	status1	= 0x%2.2ux\n", status1[0]);	}}static voidindisable(void) {	dmastop(audio.i.dma);	/* turn off ADC, clear input gain switch */	status1[0] &= ~0x22;	L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);	if (debug) {		print("indisable:	status1	= 0x%2.2ux\n", status1[0]);	}}static voidsendaudio(IOstate *s) {	/* interrupt routine calls this too */	int n;	if (debug > 1) print("#A: sendaudio\n");	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, Flushbuf, volumes[Vbufsize].ilval) & 0xff;		if (zerodma == 0)			if (debug) print("emptyfail\n");		iostats.tx.empties++;		iunlock(&s->ilock);		return;	}	while (s->next != s->filling) {		s->next->nbytes &= ~0x3;	/* must be a multiple of 4 */		if(s->next->nbytes) {			if ((n = dmastart(s->dma, s->next->phys, s->next->nbytes)) == 0) {				iostats.tx.faildma++;				break;			}			iostats.tx.totaldma++;			switch (n >> 8) {			case 1:				iostats.tx.idledma++;				break;			case 3:				iostats.tx.faildma++;				break;			}			if (debug) {				if (debug > 1)					print("dmastart @%p\n", s->next);				else					iprint("+");			}			s->next->nbytes = 0;		}		s->next++;		if (s->next == &s->buf[Nbuf])			s->next = &s->buf[0];	}	iunlock(&s->ilock);}static voidrecvaudio(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, volumes[Vbufsize].ilval)) == 0) {			iostats.rx.faildma++;			break;		}		iostats.rx.totaldma++;		switch (n >> 8) {		case 1:			iostats.rx.idledma++;			break;		case 3:			iostats.rx.faildma++;			break;		}		if (debug) {			if (debug > 1)				print("dmastart @%p\n", s->next);			else				iprint("+");		}		s->next++;		if (s->next == &s->buf[Nbuf])			s->next = &s->buf[0];	}	iunlock(&s->ilock);}voidaudiopower(int flag) {	IOstate *s;	if (debug) {		iprint("audiopower %d\n", flag);	}	if (flag) {		/* power on only when necessary */		if (audio.amode) {			audioamppower(1);			audioicpower(1);			egpiobits(EGPIO_codec_reset, 1);			enable();			if (audio.amode & Aread) {				inenable();				s = &audio.i;				dmareset(s->dma, 1, 0, 4, 2, SSPRecvDMA, Port4SSP);				recvaudio(s);			}			if (audio.amode & Awrite) {				outenable();				s = &audio.o;				dmareset(s->dma, 0, 0, 4, 2, SSPXmitDMA, Port4SSP);				sendaudio(s);			}			mxvolume();		}	} else {		/* power off */		if (audio.amode & Aread)			indisable();		if (audio.amode & Awrite)			outdisable();		egpiobits(EGPIO_codec_reset, 0);		audioamppower(0);		audioicpower(0);	}}static voidaudiointr(void *x, ulong ndma) {	IOstate *s = x;	if (debug) {		if (debug > 1)			iprint("#A: audio interrupt @%p\n", s->current);		else			iprint("-");	}	if (s == &audio.i || (ndma & ~zerodma)) {		/* A dma, not of a zero buffer completed, update current		 * Only interrupt routine touches s->current		 */		s->current->nbytes = (s == &audio.i)? volumes[Vbufsize].ilval: 0;		s->current++;		if (s->current == &s->buf[Nbuf])			s->current = &s->buf[0];	}	if (ndma) {		if (s == &audio.o) {			zerodma &= ~ndma;			sendaudio(s);		} else if (s == &audio.i)			recvaudio(s);	}	wakeup(&s->vous);}static Chan*audioattach(char *param){	return devattach('A', param);}static Walkqid*audiowalk(Chan *c, Chan *nc, char **name, int nname){ 	return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);}static intaudiostat(Chan *c, uchar *db, int n){ 	return devstat(c, db, n, audiodir, nelem(audiodir), devgen);}static Chan*audioopen(Chan *c, int mode){	IOstate *s;	int omode = mode;	switch((ulong)c->qid.path) {	default:		error(Eperm);		break;	case Qstatus:	case Qstats:		if((omode&7) != OREAD)			error(Eperm);	case Qvolume:	case Qdir:		break;	case Qaudio:		omode = (omode & 0x7) + 1;		if (omode & ~(Aread | Awrite))			error(Ebadarg);		qlock(&audio);		if(audio.amode & omode){			qunlock(&audio);			error(Einuse);		}		enable();		memset(&iostats, 0, sizeof(iostats));		if (omode & Aread) {			inenable();			s = &audio.i;			if(s->bufinit == 0)				bufinit(s);			setempty(s);			s->emptying = &s->buf[Nbuf-1];			s->chan = c;			s->dma = dmaalloc(1, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s);			audio.amode |= Aread;		}		if (omode & (Aread|Awrite) && (audio.amode & Awrite) == 0) {			s = &audio.o;			if(s->bufinit == 0)				bufinit(s);			setempty(s);			s->chan = c;			s->dma = dmaalloc(0, 0, 4, 2, SSPXmitDMA, Port4SSP, audiointr, (void*)s);		}			if (omode & Awrite) {			audio.amode |= Awrite;			outenable();		}		mxvolume();		if (audio.amode & Aread)			sendaudio(&audio.o);		qunlock(&audio);					if (debug) print("open done\n");		break;	}	c = devopen(c, mode, audiodir, nelem(audiodir), devgen);	c->mode = openmode(mode);	c->flag |= COPEN;	c->offset = 0;	return c;}static voidaudioclose(Chan *c){	IOstate *s;	switch((ulong)c->qid.path) {	default:		error(Eperm);		break;	case Qdir:	case Qvolume:	case Qstatus:	case Qstats:		break;	case Qaudio:		if (debug > 1) print("#A: close\n");		if(c->flag & COPEN) {			qlock(&audio);			if (audio.i.chan == c) {				/* closing the read end */				audio.amode &= ~Aread;				s = &audio.i;				qlock(s);				indisable();				setempty(s);				dmafree(s->dma);				qunlock(s);				if ((audio.amode & Awrite) == 0) {					s = &audio.o;					qlock(s);					while(waserror())						;					dmawait(s->dma);					poperror();					outdisable();					setempty(s);					dmafree(s->dma);					qunlock(s);				}			}			if (audio.o.chan == c) {				/* closing the write end */				audio.amode &= ~Awrite;				s = &audio.o;				qlock(s);				if (s->filling->nbytes) {					/* send remaining partial buffer */					s->filling++;					if (s->filling == &s->buf[Nbuf])						s->filling = &s->buf[0];					sendaudio(s);				}				while(waserror())					;				dmawait(s->dma);				poperror();				outdisable();				setempty(s);				if ((audio.amode & Aread) == 0)					dmafree(s->dma);				qunlock(s);			}			if (audio.amode == 0) {				/* turn audio off */				egpiobits(EGPIO_codec_reset, 0);				audioicpower(0);			}			qunlock(&audio);		}		break;	}}static longaudioread(Chan *c, void *v, long n, vlong off){	int liv, riv, lov, rov;	long m, n0;	char buf[300];	int j;	ulong offset = off;	char *p;	IOstate *s;	n0 = n;	p = v;	switch((ulong)c->qid.path) {	default:		error(Eperm);		break;	case Qdir:		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.i;		qlock(s);		if(waserror()){			qunlock(s);			nexterror();		}		while(n > 0) {			if(s->emptying->nbytes == 0) {				if (debug > 1) print("#A: emptied @%p\n", s->emptying);				recvaudio(s);				s->emptying++;				if (s->emptying == &s->buf[Nbuf])					s->emptying = s->buf;			}			/* wait if dma in progress */			while (!dmaidle(s->dma) && s->emptying == s->current) {				if (debug > 1) print("#A: sleep\n");				sleep(&s->vous, audioqnotempty, s);			}			m = (s->emptying->nbytes > n)? n: s->emptying->nbytes;			memmove(p, s->emptying->virt + volumes[Vbufsize].ilval - 					  s->emptying->nbytes, m);			s->emptying->nbytes -= m;			n -= m;			p += m;		}		poperror();		qunlock(s);		break;	case Qstatus:		buf[0] = 0;		snprint(buf, sizeof(buf), "bytes %lud\ntime %lld\n",			audio.totcount, audio.tottime);		return readstr(offset, p, n, buf);	case Qstats:		buf[0] = 0;		snprint(buf, sizeof(buf), 			    "bytes %lud\nRX dmas %lud, while idle %lud, while busy %lud, "			    "out-of-order %lud, empty dmas %lud\n"			    "TX dmas %lud, while idle %lud, while busy %lud, "			    "out-of-order %lud, empty dmas %lud\n",  			    iostats.bytes, iostats.rx.totaldma, iostats.rx.idledma, 			    iostats.rx.faildma, iostats.rx.samedma, iostats.rx.empties, 			    iostats.tx.totaldma, iostats.tx.idledma, 			    iostats.tx.faildma, iostats.tx.samedma, iostats.tx.empties);		return readstr(offset, p, n, buf);	case Qvolume:		j = 0;		buf[0] = 0;		for(m=0; volumes[m].name; m++){			if (m == Vaudio) {				liv = audio.livol[m];				riv = audio.rivol[m];				lov = audio.lovol[m];				rov = audio.rovol[m];			}			else {				lov = liv = volumes[m].ilval;				rov = riv = volumes[m].irval;			}				j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);			if((volumes[m].flag & Fmono) || liv==riv && lov==rov){				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)					j += snprint(buf+j, sizeof(buf)-j, " %d", liv);				else{					if(volumes[m].flag & Fin)						j += snprint(buf+j, sizeof(buf)-j,							" in %d", liv);					if(volumes[m].flag & Fout)						j += snprint(buf+j, sizeof(buf)-j,							" out %d", lov);				}			}else{				if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&				    liv==lov && riv==rov)					j += snprint(buf+j, sizeof(buf)-j,						" left %d right %d",						liv, riv);				else{					if(volumes[m].flag & Fin)						j += snprint(buf+j, sizeof(buf)-j,							" in left %d right %d",							liv, riv);					if(volumes[m].flag & Fout)						j += snprint(buf+j, sizeof(buf)-j,							" out left %d right %d",							lov, rov);				}			}			j += snprint(buf+j, sizeof(buf)-j, "\n");		}		return readstr(offset, p, n, buf);	}	return n0-n;}static voidsetaudio(int in, int out, int left, int right, int value){	if (value < 0 || value > 100) 		error(Evolume);	if(left && out)		audio.lovol[Vaudio] = value;	if(left && in)		audio.livol[Vaudio] = value;	if(right && out)		audio.rovol[Vaudio] = value;	if(right && in)		audio.rivol[Vaudio] = value;}static void setspeed(int, int, int, int, int speed){	uchar	clock;	/* external clock configured for 44100 samples/sec */	switch (speed) {	case 32000:		/* 00 */		gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;		clock = SC384FS;	/* Only works in MSB mode! */		break;	case 48000:		/* 00 */		gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;		clock = SC256FS;		break;	default:		speed = 44100;	case 44100:		/* 01 */		gpioregs->set = GPIO_CLK_SET0_o;		gpioregs->clear = GPIO_CLK_SET1_o;		clock = SC256FS;		break;	case 8000:		/* 10 */		gpioregs->set = GPIO_CLK_SET1_o;		gpioregs->clear = GPIO_CLK_SET0_o;		clock = SC512FS;	/* Only works in MSB mode! */		break;	case 16000:		/* 10 */		gpioregs->set = GPIO_CLK_SET1_o;		gpioregs->clear = GPIO_CLK_SET0_o;		clock = SC256FS;		break;	case 11025:		/* 11 */		gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;		clock = SC512FS;	/* Only works in MSB mode! */		break;	case 22050:		/* 11 */		gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;		clock = SC256FS;		break;	}	/* Wait for the UDA1341 to wake up */	delay(100);	/* Reset the chip */	status0[0] &= ~CLOCKMASK;	status0[0] |=clock;	volumes[Vspeed].ilval = speed;}static voidsetbufsize(int, int, int, int, int value){	if ((value % 8) != 0 || value < 8 || value >= Bufsize)		error(Ebadarg);	volumes[Vbufsize].ilval = value;}static longaudiowrite(Chan *c, void *vp, long n, vlong){	long m, n0;	int i, v, left, right, in, out;	char *p;	IOstate *a;	Cmdbuf *cb;	p = vp;	n0 = n;	switch((ulong)c->qid.path) {	default:		error(Eperm);		break;	case Qvolume:		v = Vaudio;		left = 1;		right = 1;		in = 1;		out = 1;		cb = parsecmd(p, n);		if(waserror()){			free(cb);			nexterror();		}		for(i = 0; i < cb->nf; i++){			/*			 * a number is volume			 */			if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {				m = strtoul(cb->f[i], 0, 10);				if (volumes[v].setval)					volumes[v].setval(in, out, left, right, m);				goto cont0;			}			for(m=0; volumes[m].name; m++) {				if(strcmp(cb->f[i], volumes[m].name) == 0) {					v = m;					in = 1;					out = 1;					left = 1;					right = 1;					goto cont0;				}			}			if(strcmp(cb->f[i], "reset") == 0) {				resetlevel();				goto cont0;			}			if(strcmp(cb->f[i], "debug") == 0) {				debug = debug?0:1;				goto cont0;			}			if(strcmp(cb->f[i], "in") == 0) {				in = 1;				out = 0;				goto cont0;			}			if(strcmp(cb->f[i], "out") == 0) {				in = 0;				out = 1;				goto cont0;			}			if(strcmp(cb->f[i], "left") == 0) {				left = 1;				right = 0;				goto cont0;			}			if(strcmp(cb->f[i], "right") == 0) {				left = 0;				right = 1;				goto cont0;			}			if(strcmp(cb->f[i], "reg") == 0) {				if(cb->nf < 3)					error(Evolume);				setreg(cb->f[1], atoi(cb->f[2]), cb->nf == 4 ? atoi(cb->f[3]):1);				return n0;			}			error(Evolume);			break;		cont0:;		}		mxvolume();		poperror();		free(cb);		break;	case Qaudio:		if (debug > 1) print("#A: write %ld\n", n);		if((audio.amode & Awrite) == 0)			error(Emode);		a = &audio.o;		qlock(a);		if(waserror()){			qunlock(a);			nexterror();		}		while(n > 0) {			/* wait if dma in progress */			while (!dmaidle(a->dma) && !zerodma && a->filling == a->current) {				if (debug > 1) print("#A: sleep\n");				sleep(&a->vous, audioqnotfull, a);			}			m = volumes[Vbufsize].ilval - a->filling->nbytes;			if(m > n)				m = n;			memmove(a->filling->virt + a->filling->nbytes, p, m);			a->filling->nbytes += m;			n -= m;			p += m;			if(a->filling->nbytes >= volumes[Vbufsize].ilval) {				if (debug > 1) print("#A: filled @%p\n", a->filling);				a->filling++;				if (a->filling == &a->buf[Nbuf])					a->filling = a->buf;				sendaudio(a);			}		}		poperror();		qunlock(a);		break;	}	return n0 - n;}Dev uda1341devtab = {	'A',	"audio",	devreset,	audioinit,	devshutdown,	audioattach,	audiowalk,	audiostat,	audioopen,	devcreate,	audioclose,	audioread,	devbread,	audiowrite,	devbwrite,	devremove,	devwstat,	audiopower,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -