/* * SAC/UDA 1341 Audio driver for the Bitsy * * This code is covered by the Lucent Public Licence 1.02 (http://plan9.bell-labs.com/plan9dist/license.html); * see the file NOTICE in the current directory. Modifications for the Inferno environment by Vita Nuova. * * The Philips UDA 1341 sound chip is accessed through the Serial Audio * Controller (SAC) of the StrongARM SA-1110. * * The code morphs Nicolas Pitre's <nico@cam.org> Linux controller * and Ken's Soundblaster controller. * * The interface should be identical to that of devaudio.c */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "io.h" static int debug = 0; /* UDA 1341 Registers */enum { /* Status0 register */ UdaStatusDC = 0, /* 1 bit */ UdaStatusIF = 1, /* 3 bits */ UdaStatusSC = 4, /* 2 bits */ UdaStatusRST = 6, /* 1 bit */}; enum { /* Status1 register */ UdaStatusPC = 0, /* 2 bits */ UdaStatusDS = 2, /* 1 bit */ UdaStatusPDA = 3, /* 1 bit */ UdaStatusPAD = 4, /* 1 bit */ UdaStatusIGS = 5, /* 1 bit */ UdaStatusOGS = 6, /* 1 bit */}; /* * UDA1341 L3 address and command types */ enum { UDA1341_DATA0 = 0, UDA1341_DATA1, UDA1341_STATUS, UDA1341_L3Addr = 0x14,}; typedef struct AQueue AQueue;typedef struct Buf Buf;typedef struct IOstate IOstate; enum{ Qdir = 0, Qaudio, Qvolume, Qstatus, Qaudioctl, Fmono = 1, Fin = 2, Fout = 4, Aclosed = 0, Aread, Awrite, Vaudio = 0, Vmic, Vtreb, Vbass, Vspeed, Vfilter, Vinvert, Nvol, Bufsize = 4*1024, /* 46 ms each */ Nbuf = 32, /* 1.5 seconds total */ Speed = 44100, Ncmd = 50, /* max volume command words */}; Dirtabaudiodir[] ={ ".", {Qdir, 0, QTDIR}, 0, 0555, "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666, "audioctl", {Qaudioctl}, 0, 0666, "audiostat",{Qstatus}, 0, 0444,}; struct Buf{ uchar* virt; ulong phys; uint nbytes;}; struct IOstate{ QLock; Lock ilock; Rendez vous; Chan *chan; /* chan of open */ Dma* dma; /* dma chan, alloc on open, free on close */ int bufinit; /* boolean, if buffers allocated */ Buf buf[Nbuf]; /* buffers and queues */ 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{ QLock; int amode; /* Aclosed/Aread/Awrite for /audio */ int intr; /* boolean an interrupt has happened */ int rivol[Nvol]; /* right/left input/output volumes */ int livol[Nvol]; int rovol[Nvol]; int lovol[Nvol]; uvlong totcount; /* how many bytes processed since open */ vlong tottime; /* time at which totcount bytes were processed */ int clockout; /* need steady output to provide input clock */ IOstate i; IOstate o;} audio; static struct{ ulong bytes; ulong totaldma; ulong idledma; ulong faildma; ulong samedma;} iostats; static struct{ char* name; int flag; int ilval; /* initial values */ int irval;} volumes[] ={[Vaudio] {"audio", Fout|Fmono, 80, 80},[Vmic] {"mic", Fin|Fmono, 0, 0},[Vtreb] {"treb", Fout|Fmono, 50, 50},[Vbass] {"bass", Fout|Fmono, 50, 50},[Vspeed] {"speed", Fin|Fout|Fmono, Speed, Speed},[Vfilter] {"filter", Fout|Fmono, 0, 0},[Vinvert] {"invert", Fin|Fout|Fmono, 0, 0},[Nvol] {0}}; static void setreg(char *name, int val, int n); static char Emode[] = "illegal open mode";static char Evolume[] = "illegal volume specifier"; static voidbufinit(IOstate *b){ int i; if (debug) print("bufinit\n"); for (i = 0; i < Nbuf; i++) { b->buf[i].virt = xspanalloc(Bufsize, CACHELINESZ, 0); b->buf[i].phys = PADDR(b->buf[i].virt); } b->bufinit = 1;}; static voidsetempty(IOstate *b){ int i; if (debug) print("setempty\n"); for (i = 0; i < Nbuf; i++) { b->buf[i].nbytes = 0; } b->filling = b->buf; b->current = b->buf; b->next = b->buf;} static intaudioqnotempty(void *x){ IOstate *s = x; return dmaidle(s->dma) || s->emptying != s->current;} static intaudioqnotfull(void *x){ IOstate *s = x; return dmaidle(s->dma) || s->filling != s->current;} static voidaudioreset(void){ /* Turn MCP operations off */ MCPREG->mccr = 0;} uchar status0[1] = {0x22};uchar status1[1] = {0x80};uchar data00[1] = {0x00}; /* volume control, bits 0 – 5 */uchar data01[1] = {0x40};uchar data02[1] = {0x80};uchar data0e0[2] = {0xc0, 0xe0};uchar data0e1[2] = {0xc1, 0xe0};uchar data0e2[2] = {0xc2, 0xf2};/* there is no data0e3 */uchar data0e4[2] = {0xc4, 0xe0};uchar data0e5[2] = {0xc5, 0xe0};uchar data0e6[2] = {0xc6, 0xe3}; static voidenable(void){ uchar data[1]; int cs; L3init(); PPCREG->ppar &= ~PPAR_SPR; /* external clock and ssp configured for current samples/sec */ cs = archaudiospeed(audio.livol[Vspeed], 1); status0[0] = (status0[0] & ~(3<<4)) | (cs<<4); /* Enable the audio power */ archaudiopower(1);// egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1); /* Wait for the UDA1341 to wake up */ delay(100); /* Reset the chip */ data[0] = status0[0] | 1<<UdaStatusRST; L3write(UDA1341_L3Addr | UDA1341_STATUS, data, 1 ); archcodecreset(); /* write uda 1341 status[0] */ L3write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1 ); L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e2, 2); L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e6, 2 ); if (debug) { print("enable: status0 = 0x%2.2ux\n", status0[0]); print("enable: status1 = 0x%2.2ux\n", status1[0]); print("enable: data02 = 0x%2.2ux\n", data02[0]); print("enable: data0e2 = 0x%4.4ux\n", data0e2[0] | data0e2[1]<<8); print("enable: data0e4 = 0x%4.4ux\n", data0e4[0] | data0e4[1]<<8); print("enable: data0e6 = 0x%4.4ux\n", data0e6[0] | data0e6[1]<<8); }} static voiddisable(void){ SSPREG->sscr0 = 0x031f; /* disable */} static voidresetlevel(void){ int i; for(i=0; volumes[i].name; i++) { audio.lovol[i] = volumes[i].ilval; audio.rovol[i] = volumes[i].irval; audio.livol[i] = volumes[i].ilval; audio.rivol[i] = volumes[i].irval; }} static voidmxvolume(void) { int *left, *right; int cs; cs = archaudiospeed(audio.livol[Vspeed], 1); status0[0] = (status0[0] & ~(3<<4)) | (cs<<4); L3write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1); if(debug) print("mxvolume: status0 = %2.2ux\n", status0[0]); if(audio.amode & Aread){ left = audio.livol; right = audio.rivol; if (left[Vmic]+right[Vmic] == 0) { /* Turn on automatic gain control (AGC) */ data0e4[1] |= 0x10; L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 ); } else { int v; /* Turn on manual gain control */ v = ((left[Vmic]+right[Vmic])*0x7f/200)&0x7f; data0e4[1] &= ~0x13; data0e5[1] &= ~0x1f; data0e4[1] |= v & 0x3; data0e5[0] |= (v & 0x7c)<<6; data0e5[1] |= (v & 0x7c)>>2; L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 ); L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e5, 2 ); } if (left[Vinvert]+right[Vinvert] == 0) status1[0] &= ~0x10; else status1[0] |= 0x10; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); if (debug) { print("mxvolume: status1 = 0x%2.2ux\n", status1[0]); print("mxvolume: data0e4 = 0x%4.4ux\n", data0e4[0]|data0e4[0]<<8); print("mxvolume: data0e5 = 0x%4.4ux\n", data0e5[0]|data0e5[0]<<8); } } if(audio.amode & Awrite){ left = audio.lovol; right = audio.rovol; data00[0] &= ~0x3f; data00[0] |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f; if (left[Vtreb]+right[Vtreb] <= 100 && left[Vbass]+right[Vbass] <= 100) /* settings neutral */ data02[0] &= ~0x03; else { data02[0] |= 0x03; data01[0] &= ~0x3f; data01[0] |= ((left[Vtreb]+right[Vtreb]-100)*0x3/100)&0x03; data01[0] |= (((left[Vbass]+right[Vbass]-100)*0xf/100)&0xf)<<2; } if (left[Vfilter]+right[Vfilter] == 0) data02[0] &= ~0x10; else data02[0]|= 0x10; if (left[Vinvert]+right[Vinvert] == 0) status1[0] &= ~0x8; else status1[0] |= 0x8; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data01, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1); if (debug) { print("mxvolume: status1 = 0x%2.2ux\n", status1[0]); print("mxvolume: data00 = 0x%2.2ux\n", data00[0]); print("mxvolume: data01 = 0x%2.2ux\n", data01[0]); print("mxvolume: data02 = 0x%2.2ux\n", data02[0]); } }} static voidsetreg(char *name, int val, int n){ uchar x[2]; int i; if(strcmp(name, "pause") == 0){ for(i = 0; i < n; i++) microdelay(val); return; } x[0] = val; x[1] = val>>8; switch(n){ case 1: case 2: break; default: error("setreg"); } if(strcmp(name, "status") == 0){ L3write(UDA1341_L3Addr | UDA1341_STATUS, x, n); } else if(strcmp(name, "data0") == 0){ L3write(UDA1341_L3Addr | UDA1341_DATA0, x, n); } else if(strcmp(name, "data1") == 0){ L3write(UDA1341_L3Addr | UDA1341_DATA1, x, n); } else error("setreg");} static voidoutenable(void) { /* turn on DAC, set output gain switch */ archaudioamp(1); archaudiomute(0); status1[0] |= 0x41; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); /* set volume */ data00[0] |= 0xf; L3write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1); if (debug) { print("outenable: status1 = 0x%2.2ux\n", status1[0]); print("outenable: data00 = 0x%2.2ux\n", data00[0]); }} static voidoutdisable(void) { archaudiomute(1); dmastop(audio.o.dma); /* turn off DAC, clear output gain switch */ archaudioamp(0); status1[0] &= ~0x41; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); if (debug) { print("outdisable: status1 = 0x%2.2ux\n", status1[0]); }// egpiobits(EGPIO_audio_power, 0);} static voidinenable(void) { /* turn on ADC, set input gain switch */ status1[0] |= 0x22; L3write(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; L3write(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); while (s->next != s->filling) { assert(s->next->nbytes); if ((n = dmastart(s->dma, (void*)s->next->phys, s->next->nbytes)) == 0) { iostats.faildma++; break; } iostats.totaldma++; switch (n) { case 1: iostats.idledma++; break; case 3: iostats.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) {Lines 1–500 of 1056. Load more
/* * SAC/UDA 1341 Audio driver for the Bitsy * * This code is covered by the Lucent Public Licence 1.02 (http://plan9.bell-labs.com/plan9dist/license.html); * see the file NOTICE in the current directory. Modifications for the Inferno environment by Vita Nuova. * * The Philips UDA 1341 sound chip is accessed through the Serial Audio * Controller (SAC) of the StrongARM SA-1110. * * The code morphs Nicolas Pitre's <nico@cam.org> Linux controller * and Ken's Soundblaster controller. * * The interface should be identical to that of devaudio.c */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "io.h" static int debug = 0; /* UDA 1341 Registers */ enum { /* Status0 register */ UdaStatusDC = 0, /* 1 bit */ UdaStatusIF = 1, /* 3 bits */ UdaStatusSC = 4, /* 2 bits */ UdaStatusRST = 6, /* 1 bit */ }; enum { /* Status1 register */ UdaStatusPC = 0, /* 2 bits */ UdaStatusDS = 2, /* 1 bit */ UdaStatusPDA = 3, /* 1 bit */ UdaStatusPAD = 4, /* 1 bit */ UdaStatusIGS = 5, /* 1 bit */ UdaStatusOGS = 6, /* 1 bit */ }; /* * UDA1341 L3 address and command types */ enum { UDA1341_DATA0 = 0, UDA1341_DATA1, UDA1341_STATUS, UDA1341_L3Addr = 0x14, }; typedef struct AQueue AQueue; typedef struct Buf Buf; typedef struct IOstate IOstate; enum { Qdir = 0, Qaudio, Qvolume, Qstatus, Qaudioctl, Fmono = 1, Fin = 2, Fout = 4, Aclosed = 0, Aread, Awrite, Vaudio = 0, Vmic, Vtreb, Vbass, Vspeed, Vfilter, Vinvert, Nvol, Bufsize = 4*1024, /* 46 ms each */ Nbuf = 32, /* 1.5 seconds total */ Speed = 44100, Ncmd = 50, /* max volume command words */ }; Dirtab audiodir[] = { ".", {Qdir, 0, QTDIR}, 0, 0555, "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666, "audioctl", {Qaudioctl}, 0, 0666, "audiostat",{Qstatus}, 0, 0444, }; struct Buf { uchar* virt; ulong phys; uint nbytes; }; struct IOstate { QLock; Lock ilock; Rendez vous; Chan *chan; /* chan of open */ Dma* dma; /* dma chan, alloc on open, free on close */ int bufinit; /* boolean, if buffers allocated */ Buf buf[Nbuf]; /* buffers and queues */ 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 { QLock; int amode; /* Aclosed/Aread/Awrite for /audio */ int intr; /* boolean an interrupt has happened */ int rivol[Nvol]; /* right/left input/output volumes */ int livol[Nvol]; int rovol[Nvol]; int lovol[Nvol]; uvlong totcount; /* how many bytes processed since open */ vlong tottime; /* time at which totcount bytes were processed */ int clockout; /* need steady output to provide input clock */ IOstate i; IOstate o; } audio; static struct { ulong bytes; ulong totaldma; ulong idledma; ulong faildma; ulong samedma; } iostats; static struct { char* name; int flag; int ilval; /* initial values */ int irval; } volumes[] = { [Vaudio] {"audio", Fout|Fmono, 80, 80}, [Vmic] {"mic", Fin|Fmono, 0, 0}, [Vtreb] {"treb", Fout|Fmono, 50, 50}, [Vbass] {"bass", Fout|Fmono, 50, 50}, [Vspeed] {"speed", Fin|Fout|Fmono, Speed, Speed}, [Vfilter] {"filter", Fout|Fmono, 0, 0}, [Vinvert] {"invert", Fin|Fout|Fmono, 0, 0}, [Nvol] {0} }; static void setreg(char *name, int val, int n); static char Emode[] = "illegal open mode"; static char Evolume[] = "illegal volume specifier"; static void bufinit(IOstate *b) { int i; if (debug) print("bufinit\n"); for (i = 0; i < Nbuf; i++) { b->buf[i].virt = xspanalloc(Bufsize, CACHELINESZ, 0); b->buf[i].phys = PADDR(b->buf[i].virt); } b->bufinit = 1; }; static void setempty(IOstate *b) { int i; if (debug) print("setempty\n"); for (i = 0; i < Nbuf; i++) { b->buf[i].nbytes = 0; } b->filling = b->buf; b->current = b->buf; b->next = b->buf; } static int audioqnotempty(void *x) { IOstate *s = x; return dmaidle(s->dma) || s->emptying != s->current; } static int audioqnotfull(void *x) { IOstate *s = x; return dmaidle(s->dma) || s->filling != s->current; } static void audioreset(void) { /* Turn MCP operations off */ MCPREG->mccr = 0; } uchar status0[1] = {0x22}; uchar status1[1] = {0x80}; uchar data00[1] = {0x00}; /* volume control, bits 0 – 5 */ uchar data01[1] = {0x40}; uchar data02[1] = {0x80}; uchar data0e0[2] = {0xc0, 0xe0}; uchar data0e1[2] = {0xc1, 0xe0}; uchar data0e2[2] = {0xc2, 0xf2}; /* there is no data0e3 */ uchar data0e4[2] = {0xc4, 0xe0}; uchar data0e5[2] = {0xc5, 0xe0}; uchar data0e6[2] = {0xc6, 0xe3}; static void enable(void) { uchar data[1]; int cs; L3init(); PPCREG->ppar &= ~PPAR_SPR; /* external clock and ssp configured for current samples/sec */ cs = archaudiospeed(audio.livol[Vspeed], 1); status0[0] = (status0[0] & ~(3<<4)) | (cs<<4); /* Enable the audio power */ archaudiopower(1); // egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1); /* Wait for the UDA1341 to wake up */ delay(100); /* Reset the chip */ data[0] = status0[0] | 1<<UdaStatusRST; L3write(UDA1341_L3Addr | UDA1341_STATUS, data, 1 ); archcodecreset(); /* write uda 1341 status[0] */ L3write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1 ); L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e2, 2); L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e6, 2 ); if (debug) { print("enable: status0 = 0x%2.2ux\n", status0[0]); print("enable: status1 = 0x%2.2ux\n", status1[0]); print("enable: data02 = 0x%2.2ux\n", data02[0]); print("enable: data0e2 = 0x%4.4ux\n", data0e2[0] | data0e2[1]<<8); print("enable: data0e4 = 0x%4.4ux\n", data0e4[0] | data0e4[1]<<8); print("enable: data0e6 = 0x%4.4ux\n", data0e6[0] | data0e6[1]<<8); } } static void disable(void) { SSPREG->sscr0 = 0x031f; /* disable */ } static void resetlevel(void) { int i; for(i=0; volumes[i].name; i++) { audio.lovol[i] = volumes[i].ilval; audio.rovol[i] = volumes[i].irval; audio.livol[i] = volumes[i].ilval; audio.rivol[i] = volumes[i].irval; } } static void mxvolume(void) { int *left, *right; int cs; cs = archaudiospeed(audio.livol[Vspeed], 1); status0[0] = (status0[0] & ~(3<<4)) | (cs<<4); L3write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1); if(debug) print("mxvolume: status0 = %2.2ux\n", status0[0]); if(audio.amode & Aread){ left = audio.livol; right = audio.rivol; if (left[Vmic]+right[Vmic] == 0) { /* Turn on automatic gain control (AGC) */ data0e4[1] |= 0x10; L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 ); } else { int v; /* Turn on manual gain control */ v = ((left[Vmic]+right[Vmic])*0x7f/200)&0x7f; data0e4[1] &= ~0x13; data0e5[1] &= ~0x1f; data0e4[1] |= v & 0x3; data0e5[0] |= (v & 0x7c)<<6; data0e5[1] |= (v & 0x7c)>>2; L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 ); L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e5, 2 ); } if (left[Vinvert]+right[Vinvert] == 0) status1[0] &= ~0x10; else status1[0] |= 0x10; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); if (debug) { print("mxvolume: status1 = 0x%2.2ux\n", status1[0]); print("mxvolume: data0e4 = 0x%4.4ux\n", data0e4[0]|data0e4[0]<<8); print("mxvolume: data0e5 = 0x%4.4ux\n", data0e5[0]|data0e5[0]<<8); } } if(audio.amode & Awrite){ left = audio.lovol; right = audio.rovol; data00[0] &= ~0x3f; data00[0] |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f; if (left[Vtreb]+right[Vtreb] <= 100 && left[Vbass]+right[Vbass] <= 100) /* settings neutral */ data02[0] &= ~0x03; else { data02[0] |= 0x03; data01[0] &= ~0x3f; data01[0] |= ((left[Vtreb]+right[Vtreb]-100)*0x3/100)&0x03; data01[0] |= (((left[Vbass]+right[Vbass]-100)*0xf/100)&0xf)<<2; } if (left[Vfilter]+right[Vfilter] == 0) data02[0] &= ~0x10; else data02[0]|= 0x10; if (left[Vinvert]+right[Vinvert] == 0) status1[0] &= ~0x8; else status1[0] |= 0x8; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data01, 1); L3write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1); if (debug) { print("mxvolume: status1 = 0x%2.2ux\n", status1[0]); print("mxvolume: data00 = 0x%2.2ux\n", data00[0]); print("mxvolume: data01 = 0x%2.2ux\n", data01[0]); print("mxvolume: data02 = 0x%2.2ux\n", data02[0]); } } } static void setreg(char *name, int val, int n) { uchar x[2]; int i; if(strcmp(name, "pause") == 0){ for(i = 0; i < n; i++) microdelay(val); return; } x[0] = val; x[1] = val>>8; switch(n){ case 1: case 2: break; default: error("setreg"); } if(strcmp(name, "status") == 0){ L3write(UDA1341_L3Addr | UDA1341_STATUS, x, n); } else if(strcmp(name, "data0") == 0){ L3write(UDA1341_L3Addr | UDA1341_DATA0, x, n); } else if(strcmp(name, "data1") == 0){ L3write(UDA1341_L3Addr | UDA1341_DATA1, x, n); } else error("setreg"); } static void outenable(void) { /* turn on DAC, set output gain switch */ archaudioamp(1); archaudiomute(0); status1[0] |= 0x41; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); /* set volume */ data00[0] |= 0xf; L3write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1); if (debug) { print("outenable: status1 = 0x%2.2ux\n", status1[0]); print("outenable: data00 = 0x%2.2ux\n", data00[0]); } } static void outdisable(void) { archaudiomute(1); dmastop(audio.o.dma); /* turn off DAC, clear output gain switch */ archaudioamp(0); status1[0] &= ~0x41; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); if (debug) { print("outdisable: status1 = 0x%2.2ux\n", status1[0]); } // egpiobits(EGPIO_audio_power, 0); } static void inenable(void) { /* turn on ADC, set input gain switch */ status1[0] |= 0x22; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); if (debug) { print("inenable: status1 = 0x%2.2ux\n", status1[0]); } } static void indisable(void) { dmastop(audio.i.dma); /* turn off ADC, clear input gain switch */ status1[0] &= ~0x22; L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); if (debug) { print("indisable: status1 = 0x%2.2ux\n", status1[0]); } } static void sendaudio(IOstate *s) { /* interrupt routine calls this too */ int n; if (debug > 1) print("#A: sendaudio\n"); ilock(&s->ilock); while (s->next != s->filling) { assert(s->next->nbytes); if ((n = dmastart(s->dma, (void*)s->next->phys, s->next->nbytes)) == 0) { iostats.faildma++; break; } iostats.totaldma++; switch (n) { case 1: iostats.idledma++; break; case 3: iostats.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 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) {