## diffname bitsy/devuda1341.c 2000/1103 ## diff -e /dev/null /n/emeliedump/2000/1103/sys/src/9/bitsy/devuda1341.c 0a /* * SAC/UDA 1341 Audio driver for the Bitsy * * The Philips UDA 1341 sound chip is accessed through the Serial Audio * Controller (SAC) of the StrongARM SA-1110. This is much more a SAC * controller than a UDA controller, but we have a devsac.c already. * * The code morphs Nicolas Pitre's 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" /* * GPIO based L3 bus support. * * This provides control of Philips L3 type devices. * GPIO lines are used for clock, data and mode pins. * * Note: The L3 pins are shared with I2C devices. This should not present * any problems as long as an I2C start sequence is not generated. This is * defined as a 1->0 transition on the data lines when the clock is high. * It is critical this code only allow data transitions when the clock * is low. This is always legal in L3. * * The IIC interface requires the clock and data pin to be LOW when idle. We * must make sure we leave them in this state. * * It appears the read data is generated on the falling edge of the clock * and should be held stable during the clock high time. */ /* * L3 setup and hold times (expressed in us) */ #define L3_DataSetupTime 1 /* 190 ns */ #define L3_DataHoldTime 1 /* 30 ns */ #define L3_ModeSetupTime 1 /* 190 ns */ #define L3_ModeHoldTime 1 /* 190 ns */ #define L3_ClockHighTime 100 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ #define L3_ClockLowTime 100 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */ #define L3_HaltTime 1 /* 190 ns */ /* 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 */ #define UDA1341_L3Addr 5 #define UDA1341_DATA0 0 #define UDA1341_DATA1 1 #define UDA1341_STATUS 2 typedef struct AQueue AQueue; typedef struct Buf Buf; enum { Qdir = 0, Qaudio, Qvolume, Qstatus, Fmono = 1, Fin = 2, Fout = 4, Aclosed = 0, Aread, Awrite, Vaudio = 0, Vsynth, Vcd, Vline, Vmic, Vspeaker, Vtreb, Vbass, Vspeed, Nvol, Bufsize = 16*1024, /* 92 ms each */ Nbuf = 16, /* 1.5 seconds total */ Speed = 44100, Ncmd = 50, /* max volume command words */ }; Dirtab audiodir[] = { "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666, "audiostat",{Qstatus}, 0, 0444, }; struct Buf { uchar* virt; ulong phys; Buf* next; }; struct AQueue { Lock; Buf* first; Buf* last; }; static struct { QLock; Rendez vous; int bufinit; /* boolean if buffers allocated */ int curcount; /* how much data in current buffer */ int active; /* boolean dma running */ int intr; /* boolean an interrupt has happened */ int amode; /* Aclosed/Aread/Awrite for /audio */ int rivol[Nvol]; /* right/left input/output volumes */ int livol[Nvol]; int rovol[Nvol]; int lovol[Nvol]; int major; /* SB16 major version number (sb 4) */ int minor; /* SB16 minor version number */ ulong totcount; /* how many bytes processed since open */ vlong tottime; /* time at which totcount bytes were processed */ Buf buf[Nbuf]; /* buffers and queues */ AQueue empty; AQueue full; Buf* current; Buf* filling; } audio; static struct { char* name; int flag; int ilval; /* initial values */ int irval; } volumes[] = { [Vaudio] "audio", Fout, 50, 50, [Vsynth] "synth", Fin|Fout, 0, 0, [Vcd] "cd", Fin|Fout, 0, 0, [Vline] "line", Fin|Fout, 0, 0, [Vmic] "mic", Fin|Fout|Fmono, 0, 0, [Vspeaker] "speaker", Fout|Fmono, 0, 0, [Vtreb] "treb", Fout, 50, 50, [Vbass] "bass", Fout, 50, 50, [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, 0 }; /* * Grab control of the IIC/L3 shared pins */ static inline void L3_acquirepins(void) { GPSR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); GPDR |= (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); } /* * Release control of the IIC/L3 shared pins */ static inline void L3_releasepins(void) { GPDR &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io); GPCR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); } /* * Initialize the interface */ static void __init L3_init(void) { GAFR &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o); GPSR = GPIO_L3_MODE_o; GPDR |= GPIO_L3_MODE_o; L3_releasepins(); } /* * Get a bit. The clock is high on entry and on exit. Data is read after * the clock low time has expired. */ static inline int L3_getbit(void) { int data; GPCR = GPIO_L3_SCLK_o; udelay(L3_ClockLowTime); data = (GPLR & GPIO_L3_SDA_io) ? 1 : 0; GPSR = GPIO_L3_SCLK_o; udelay(L3_ClockHighTime); return data; } /* * Send a bit. The clock is high on entry and on exit. Data is sent only * when the clock is low (I2C compatibility). */ static inline void L3_sendbit(int bit) { GPCR = GPIO_L3_SCLK_o; if (bit & 1) GPSR = GPIO_L3_SDA_io; else GPCR = GPIO_L3_SDA_io; /* Assumes L3_DataSetupTime < L3_ClockLowTime */ udelay(L3_ClockLowTime); GPSR = GPIO_L3_SCLK_o; udelay(L3_ClockHighTime); } /* * Send a byte. The mode line is set or pulsed based on the mode sequence * count. The mode line is high on entry and exit. The mod line is pulsed * before the second data byte and before ech byte thereafter. */ static void L3_sendbyte(char data, int mode) { int i; L3_acquirepins(); switch(mode) { case 0: /* Address mode */ GPCR = GPIO_L3_MODE_o; break; case 1: /* First data byte */ break; default: /* Subsequent bytes */ GPCR = GPIO_L3_MODE_o; udelay(L3_HaltTime); GPSR = GPIO_L3_MODE_o; break; } udelay(L3_ModeSetupTime); for (i = 0; i < 8; i++) L3_sendbit(data >> i); if (mode == 0) /* Address mode */ GPSR = GPIO_L3_MODE_o; udelay(L3_ModeHoldTime); L3_releasepins(); } /* * Get a byte. The mode line is set or pulsed based on the mode sequence * count. The mode line is high on entry and exit. The mod line is pulsed * before the second data byte and before each byte thereafter. This * function is never valid with mode == 0 (address cycle) as the address * is always sent on the bus, not read. */ static char L3_getbyte(int mode) { char data = 0; int i; L3_acquirepins(); GPDR &= ~(GPIO_L3_SDA_io); switch(mode) { case 0: /* Address mode - never valid */ break; case 1: /* First data byte */ break; default: /* Subsequent bytes */ GPCR = GPIO_L3_MODE_o; udelay(L3_HaltTime); GPSR = GPIO_L3_MODE_o; break; } udelay(L3_ModeSetupTime); for (i = 0; i < 8; i++) data |= (L3_getbit() << i); udelay(L3_ModeHoldTime); L3_releasepins(); return data; } /* * Write data to a device on the L3 bus. The address is passed as well as * the data and length. The length written is returned. The register space * is encoded in the address (low two bits are set and device address is * in the upper 6 bits). */ static int L3_write(char addr, char *data, int len) { int mode = 0; int bytes = len; L3_sendbyte(addr, mode++); while(len--) L3_sendbyte(*data++, mode++); return bytes; } /* * Read data from a device on the L3 bus. The address is passed as well as * the data and length. The length read is returned. The register space * is encoded in the address (low two bits are set and device address is * in the upper 6 bits). */ static int L3_read(char addr, char * data, int len) { int mode = 0; int bytes = len; L3_sendbyte(addr, mode++); while(len--) *data++ = L3_getbyte(mode++); return bytes; } static void swab(uchar*); static char Emajor[] = "soundblaster not responding/wrong version"; static char Emode[] = "illegal open mode"; static char Evolume[] = "illegal volume specifier"; static int sbcmd(int val) { int i, s; for(i=1<<16; i!=0; i--) { s = inb(blaster.wstatus); if((s & 0x80) == 0) { outb(blaster.write, val); return 0; } } /* print("#A: sbcmd (0x%.2x) timeout\n", val); /**/ return 1; } static int sbread(void) { int i, s; for(i=1<<16; i!=0; i--) { s = inb(blaster.rstatus); if((s & 0x80) != 0) { return inb(blaster.read); } } /* print("#A: sbread did not respond\n"); /**/ return -1; } static int ess1688w(int reg, int val) { if(sbcmd(reg) || sbcmd(val)) return 1; return 0; } static int ess1688r(int reg) { if(sbcmd(0xC0) || sbcmd(reg)) return -1; return sbread(); } static int mxcmd(int addr, int val) { outb(blaster.mixaddr, addr); outb(blaster.mixdata, val); return 1; } static int mxread(int addr) { int s; outb(blaster.mixaddr, addr); s = inb(blaster.mixdata); return s; } static void mxcmds(int s, int v) { if(v > 100) v = 100; if(v < 0) v = 0; mxcmd(s, (v*255)/100); } static void mxcmdt(int s, int v) { if(v > 100) v = 100; if(v <= 0) mxcmd(s, 0); else mxcmd(s, 255-100+v); } static void mxcmdu(int s, int v) { if(v > 100) v = 100; if(v <= 0) v = 0; mxcmd(s, 128-50+v); } static void mxvolume(void) { int *left, *right; int source; if(audio.amode == Aread){ left = audio.livol; right = audio.rivol; }else{ left = audio.lovol; right = audio.rovol; } ilock(&blaster); mxcmd(0x30, 255); /* left master */ mxcmd(0x31, 255); /* right master */ mxcmd(0x3f, 0); /* left igain */ mxcmd(0x40, 0); /* right igain */ mxcmd(0x41, 0); /* left ogain */ mxcmd(0x42, 0); /* right ogain */ mxcmds(0x32, left[Vaudio]); mxcmds(0x33, right[Vaudio]); mxcmds(0x34, left[Vsynth]); mxcmds(0x35, right[Vsynth]); mxcmds(0x36, left[Vcd]); mxcmds(0x37, right[Vcd]); mxcmds(0x38, left[Vline]); mxcmds(0x39, right[Vline]); mxcmds(0x3a, left[Vmic]); mxcmds(0x3b, left[Vspeaker]); mxcmdu(0x44, left[Vtreb]); mxcmdu(0x45, right[Vtreb]); mxcmdu(0x46, left[Vbass]); mxcmdu(0x47, right[Vbass]); source = 0; if(left[Vsynth]) source |= 1<<6; if(right[Vsynth]) source |= 1<<5; if(left[Vaudio]) source |= 1<<4; if(right[Vaudio]) source |= 1<<3; if(left[Vcd]) source |= 1<<2; if(right[Vcd]) source |= 1<<1; if(left[Vmic]) source |= 1<<0; if(audio.amode == Aread) mxcmd(0x3c, 0); /* output switch */ else mxcmd(0x3c, source); mxcmd(0x3d, source); /* input left switch */ mxcmd(0x3e, source); /* input right switch */ iunlock(&blaster); } static Buf* getbuf(AQueue *q) { Buf *b; ilock(q); b = q->first; if(b) q->first = b->next; iunlock(q); return b; } static void putbuf(AQueue *q, Buf *b) { ilock(q); b->next = 0; if(q->first) q->last->next = b; else q->first = b; q->last = b; iunlock(q); } /* * move the dma to the next buffer */ static void contindma(void) { Buf *b; if(!audio.active) goto shutdown; b = audio.current; if(audio.amode == Aread) { if(b) /* shouldn't happen */ putbuf(&audio.full, b); b = getbuf(&audio.empty); } else { if(b) /* shouldn't happen */ putbuf(&audio.empty, b); b = getbuf(&audio.full); } audio.current = b; if(b == 0) goto shutdown; if(dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread) >= 0) return; print("#A: dmasetup fail\n"); putbuf(&audio.empty, b); shutdown: dmaend(blaster.dma); sbcmd(0xd9); /* exit at end of count */ sbcmd(0xd5); /* pause */ audio.curcount = 0; audio.active = 0; } /* * cause sb to get an interrupt per buffer. * start first dma */ static void sb16startdma(void) { ulong count; int speed; ilock(&blaster); dmaend(blaster.dma); if(audio.amode == Aread) { sbcmd(0x42); /* input sampling rate */ speed = audio.livol[Vspeed]; } else { sbcmd(0x41); /* output sampling rate */ speed = audio.lovol[Vspeed]; } sbcmd(speed>>8); sbcmd(speed); count = (Bufsize >> 1) - 1; if(audio.amode == Aread) sbcmd(0xbe); /* A/D, autoinit */ else sbcmd(0xb6); /* D/A, autoinit */ sbcmd(0x30); /* stereo, 16 bit */ sbcmd(count); sbcmd(count>>8); audio.active = 1; audio.tottime = todget(nil); contindma(); iunlock(&blaster); } static int ess1688reset(void) { int i; outb(blaster.reset, 3); delay(1); /* >3 υs */ outb(blaster.reset, 0); delay(1); i = sbread(); if(i != 0xAA) { print("#A: no response 0x%.2x\n", i); return 1; } if(sbcmd(0xC6)){ /* extended mode */ print("#A: barf 3\n"); return 1; } return 0; } static void ess1688startdma(void) { ulong count; int speed, x; ilock(&blaster); dmaend(blaster.dma); if(audio.amode == Awrite) ess1688reset(); if(audio.amode == Aread) sbcmd(0xD3); /* speaker off */ /* * Set the speed. */ if(audio.amode == Aread) speed = audio.livol[Vspeed]; else speed = audio.lovol[Vspeed]; if(speed < 4000) speed = 4000; else if(speed > 48000) speed = 48000; if(speed > 22000) x = 0x80|(256-(795500+speed/2)/speed); else x = 128-(397700+speed/2)/speed; ess1688w(0xA1, x & 0xFF); speed = (speed * 9) / 20; x = 256 - 7160000 / (speed * 82); ess1688w(0xA2, x & 0xFF); if(audio.amode == Aread) ess1688w(0xB8, 0x0E); /* A/D, autoinit */ else ess1688w(0xB8, 0x04); /* D/A, autoinit */ x = ess1688r(0xA8) & ~0x03; ess1688w(0xA8, x|0x01); /* 2 channels */ ess1688w(0xB9, 2); /* demand mode, 4 bytes per request */ if(audio.amode == Awrite) ess1688w(0xB6, 0); ess1688w(0xB7, 0x71); ess1688w(0xB7, 0xBC); x = ess1688r(0xB1) & 0x0F; ess1688w(0xB1, x|0x50); x = ess1688r(0xB2) & 0x0F; ess1688w(0xB2, x|0x50); if(audio.amode == Awrite) sbcmd(0xD1); /* speaker on */ count = -Bufsize; ess1688w(0xA4, count & 0xFF); ess1688w(0xA5, (count>>8) & 0xFF); x = ess1688r(0xB8); ess1688w(0xB8, x|0x05); audio.active = 1; audio.tottime = todget(nil); contindma(); iunlock(&blaster); } /* * if audio is stopped, * start it up again. */ static void pokeaudio(void) { if(!audio.active) blaster.startdma(); } static void sb16intr(void) { int stat, dummy; stat = mxread(0x82) & 7; /* get irq status */ if(stat) { dummy = 0; if(stat & 2) { ilock(&blaster); dummy = inb(blaster.clri16); audio.totcount += Bufsize; audio.tottime = todget(nil); contindma(); iunlock(&blaster); audio.intr = 1; wakeup(&audio.vous); } if(stat & 1) { dummy = inb(blaster.clri8); } if(stat & 4) { dummy = inb(blaster.clri401); } USED(dummy); } } static void ess1688intr(void) { int dummy; if(audio.active){ ilock(&blaster); audio.totcount += Bufsize; audio.tottime = todget(nil); contindma(); dummy = inb(blaster.clri8); iunlock(&blaster); audio.intr = 1; wakeup(&audio.vous); USED(dummy); } else print("#A: unexpected ess1688 interrupt\n"); } void audiosbintr(void) { /* * Carrera interrupt interface. */ blaster.intr(); } static void pcaudiosbintr(Ureg*, void*) { /* * x86 interrupt interface. */ blaster.intr(); } void audiodmaintr(void) { /* print("#A: dma interrupt\n"); /**/ } static int anybuf(void*) { return audio.intr; } /* * wait for some output to get * empty buffers back. */ static void waitaudio(void) { audio.intr = 0; pokeaudio(); tsleep(&audio.vous, anybuf, 0, 10*1000); if(audio.intr == 0) { /* print("#A: audio timeout\n"); /**/ audio.active = 0; pokeaudio(); } } static void sbbufinit(void) { int i; void *p; for(i=0; iirq){ case 2: case 9: i = 0x50|(0<<2); break; case 5: i = 0x50|(1<<2); break; case 7: i = 0x50|(2<<2); break; case 10: i = 0x50|(3<<2); break; default: print("#A: bad ESS1688 irq %lud\n", sbconf->irq); return 1; } ess1688w(0xB1, i); switch(sbconf->dma){ case 0: i = 0x50|(1<<2); break; case 1: i = 0xF0|(2<<2); break; case 3: i = 0x50|(3<<2); break; default: print("#A: bad ESS1688 dma %lud\n", sbconf->dma); return 1; } ess1688w(0xB2, i); ess1688reset(); blaster.startdma = ess1688startdma; blaster.intr = ess1688intr; return 0; } static void audioinit(void) { int err; /* Acquire and initialize DMA */ if( audio_init_dma( &output_stream, "UDA1341 DMA out" ) || audio_init_dma( &input_stream, "UDA1341 DMA in" ) ){ audio_clear_dma( &output_stream ); audio_clear_dma( &input_stream ); return -EBUSY; } L3_init(); audio_ssp_init(); audio_uda1341_reset(); init_waitqueue_head(&audio_waitq); /* Set some default mixer values... */ STATUS_1.DAC_gain = 1; STATUS_1.ADC_gain = 1; L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, (char*)&STATUS_1, 1 ); DATA0_0.volume = 15; L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_0, 1 ); DATA0_2.mode = 3; L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_2, 1 ); DATA0_ext2.mixer_mode = 2; DATA0_ext2.mic_level = 4; L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext2, 2 ); DATA0_ext4.AGC_ctrl = 1; L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext4, 2 ); DATA0_ext6.AGC_level = 3; L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext6, 2 ); /* register devices */ audio_dev_dsp = register_sound_dsp(&UDA1341_dsp_fops, -1); audio_dev_mixer = register_sound_mixer(&UDA1341_mixer_fops, -1); printk( AUDIO_NAME_VERBOSE " initialized\n" ); return 0; } . ## diffname bitsy/devuda1341.c 2000/1104 ## diff -e /n/emeliedump/2000/1103/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1104/sys/src/9/bitsy/devuda1341.c 563,944d 367,536d 361,363d 233c static void L3_sendbit(int bit) . 214c static int L3_getbit(void) . 193c static void L3_releasepins(void) . 184c static void L3_acquirepins(void) . 156a } input, output; static struct { QLock; Rendez vous; int bufinit; /* boolean if buffers allocated */ int curcount; /* how much data in current buffer */ int active; /* boolean dma running */ int intr; /* boolean an interrupt has happened */ int amode; /* Aclosed/Aread/Awrite for /audio */ int rivol[Nvol]; /* right/left input/output volumes */ int livol[Nvol]; int rovol[Nvol]; int lovol[Nvol]; int major; /* SB16 major version number (sb 4) */ int minor; /* SB16 minor version number */ ulong totcount; /* how many bytes processed since open */ vlong tottime; /* time at which totcount bytes were processed */ Buf buf[Nbuf]; /* buffers and queues */ AQueue empty; AQueue full; Buf* current; Buf* filling; . 133a . 127a . ## diffname bitsy/devuda1341.c 2000/1107 ## diff -e /n/emeliedump/2000/1104/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1107/sys/src/9/bitsy/devuda1341.c 462a static void audioinit(void) {} static Chan* audioattach(char *param) { return devattach('A', param); } static int audiowalk(Chan *c, char *name) { return devwalk(c, name, audiodir, nelem(audiodir), devgen); } static void audiostat(Chan *c, char *db) { devstat(c, db, audiodir, nelem(audiodir), devgen); } static Chan* audioopen(Chan *c, int omode) { int amode; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qstatus: if((omode&7) != OREAD) error(Eperm); case Qvolume: case Qdir: break; case Qaudio: amode = Awrite; switch (omode & 0x7) case OREAD: break; case OWRITE qlock(&audio); if(audio.amode != Aclosed){ qunlock(&audio); error(Einuse); } if(audio.bufinit == 0) { audio.bufinit = 1; sbbufinit(); } audio.amode = amode; setempty(); audio.curcount = 0; qunlock(&audio); mxvolume(); break; } c = devopen(c, omode, audiodir, nelem(audiodir), devgen); c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c; } static void audioclose(Chan *c) { Buf *b; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qdir: case Qvolume: case Qstatus: break; case Qaudio: if(c->flag & COPEN) { qlock(&audio); if(audio.amode == Awrite) { /* flush out last partial buffer */ b = audio.filling; if(b) { audio.filling = 0; memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount); swab(b->virt); putbuf(&audio.full, b); } if(!audio.active && audio.full.first) pokeaudio(); } audio.amode = Aclosed; if(waserror()){ qunlock(&audio); nexterror(); } while(audio.active) waitaudio(); setempty(); poperror(); qunlock(&audio); } break; } } static long audioread(Chan *c, void *v, long n, vlong off) { int liv, riv, lov, rov; long m, n0; char buf[300]; Buf *b; int j; ulong offset = off; char *a; n0 = n; a = v; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qdir: return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); case Qaudio: if(audio.amode != Aread) error(Emode); qlock(&audio); if(waserror()){ qunlock(&audio); nexterror(); } while(n > 0) { b = audio.filling; if(b == 0) { b = getbuf(&audio.full); if(b == 0) { waitaudio(); continue; } audio.filling = b; swab(b->virt); audio.curcount = 0; } m = Bufsize-audio.curcount; if(m > n) m = n; memmove(a, b->virt+audio.curcount, m); audio.curcount += m; n -= m; a += m; if(audio.curcount >= Bufsize) { audio.filling = 0; putbuf(&audio.empty, b); } } poperror(); qunlock(&audio); break; case Qstatus: buf[0] = 0; snprint(buf, sizeof(buf), "bytes %lud\ntime %lld\n", audio.totcount, audio.tottime); return readstr(offset, a, n, buf); case Qvolume: j = 0; buf[0] = 0; for(m=0; volumes[m].name; m++){ liv = audio.livol[m]; riv = audio.rivol[m]; lov = audio.lovol[m]; rov = audio.rovol[m]; 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, a, n, buf); } return n0-n; } static long audiowrite(Chan *c, void *vp, long n, vlong) { long m, n0; int i, nf, v, left, right, in, out; char buf[255], *field[Ncmd]; Buf *b; char *a; a = vp; n0 = n; switch(c->qid.path & ~CHDIR) { default: error(Eperm); break; case Qvolume: v = Vaudio; left = 1; right = 1; in = 1; out = 1; if(n > sizeof(buf)-1) n = sizeof(buf)-1; memmove(buf, a, n); buf[n] = '\0'; nf = getfields(buf, field, Ncmd, 1, " \t\n"); for(i = 0; i < nf; i++){ /* * a number is volume */ if(field[i][0] >= '0' && field[i][0] <= '9') { m = strtoul(field[i], 0, 10); if(left && out) audio.lovol[v] = m; if(left && in) audio.livol[v] = m; if(right && out) audio.rovol[v] = m; if(right && in) audio.rivol[v] = m; mxvolume(); goto cont0; } for(m=0; volumes[m].name; m++) { if(strcmp(field[i], volumes[m].name) == 0) { v = m; in = 1; out = 1; left = 1; right = 1; goto cont0; } } if(strcmp(field[i], "reset") == 0) { resetlevel(); mxvolume(); goto cont0; } if(strcmp(field[i], "in") == 0) { in = 1; out = 0; goto cont0; } if(strcmp(field[i], "out") == 0) { in = 0; out = 1; goto cont0; } if(strcmp(field[i], "left") == 0) { left = 1; right = 0; goto cont0; } if(strcmp(field[i], "right") == 0) { left = 0; right = 1; goto cont0; } error(Evolume); break; cont0:; } break; case Qaudio: if(audio.amode != Awrite) error(Emode); qlock(&audio); if(waserror()){ qunlock(&audio); nexterror(); } while(n > 0) { b = audio.filling; if(b == 0) { b = getbuf(&audio.empty); if(b == 0) { waitaudio(); continue; } audio.filling = b; audio.curcount = 0; } m = Bufsize-audio.curcount; if(m > n) m = n; memmove(b->virt+audio.curcount, a, m); audio.curcount += m; n -= m; a += m; if(audio.curcount >= Bufsize) { audio.filling = 0; swab(b->virt); putbuf(&audio.full, b); } } poperror(); qunlock(&audio); break; } return n0 - n; } Dev audiodevtab = { 'A', "audio", devreset, audioinit, audioattach, devclone, audiowalk, audiostat, audioopen, devcreate, audioclose, audioread, devbread, audiowrite, devbwrite, devremove, devwstat, }; . ## diffname bitsy/devuda1341.c 2000/1108 ## diff -e /n/emeliedump/2000/1107/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1108/sys/src/9/bitsy/devuda1341.c 515,517c if (omode & AudioIn) { /* read */ audio.amode |= AudioIn; if((audio.bufinit & AudioIn) == 0) { audio.bufinit |= AudioIn; sbbufinit(); } } if (omode & 0x2) { /* write */ audio.amode |= 0x2; . 511c omode++; if(audio.amode & omode){ . 505,509c if ((omode & 0x7) > 2) error(Ebadarg); . ## diffname bitsy/devuda1341.c 2000/1109 ## diff -e /n/emeliedump/2000/1108/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1109/sys/src/9/bitsy/devuda1341.c 816c qunlock(a); . 808,812c p += m; if(a->filling->nbytes >= Bufsize) { sendaudio(a); a->filling++; if (a->filling == &a->buf[Nbuf]) a->filling = a->buf; . 806c a->filling->nbytes += m; . 804c memmove(a->filling->buf + a->filling->nbytes, p, m); . 801c m = Bufsize - a->filling->nbytes; . 790,799c /* wait if dma in progress */ while (a->filling->active) waitaudio(a); . 786c qunlock(a); . 784c a = &audio.o; qlock(a); . 782c if((audio.amode & Awrite) == 0) . 717c memmove(buf, p, n); . 702c p = vp; . 700c char *p; IOstate *a; . 567,568d 560,564c b = audio.o.filling; if(audio.o.buf[b].count) { . 558c if(audio.amode & Awrite) { . 529c // mxvolume(); . 525,527d 523c audio.amode |= Awrite; if(audio.o.bufinit == 0) bufinit(&audio.o); setempty(&audio.o); . 515,519c audio.amode |= Aread; if(audio.i.bufinit == 0) bufinit(&audio.i); setempty(&audio.i); . 513c if (omode & Aread) { . 508d 505c omode = (omode & 0x7) + 1; if (omode & ~(Aread | Awrite)) . 490d 468d 465,466c sendaudio(IOstat *b) { if (dmastart(b->chan, b->current->virt, b->current->nbytes)) { b->current->active++; b->current++; if (b->current == &b->buf[Nbuf]) b->current == &b->buf[0]; } } . 409,416c for (i = 0; i < Nbuf; i++) { b->buf[i].nbytes = 0; b->buf[i].active = 0; } b->filling = b->buf; b->current = b->buf; . 407a int i; . 402,406c static void setempty(IOstate *b) . 396,400c for (i = 0; i < Nbuf; i++) b->buf[i].virt = xalloc(Bufsize); b->bufinit = 1; }; . 394c int i; . 391,392c static void bufinit(IOstate *b) . 164,183c 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]; ulong totcount; /* how many bytes processed since open */ vlong tottime; /* time at which totcount bytes were processed */ IOstate i; IOstate o; . 154,160d 140,152c int bufinit; /* boolean, if buffers allocated */ Buf buf[Nbuf]; /* buffers and queues */ Buf *current; /* next candidate for dma */ Buf *filling; /* buffer being filled */ }; . 131,137d 129c struct IOstate . 125,126c uint nbytes; . 123a int active; /* dma running */ . 107,108c Bufsize = 8*1024, /* 46 ms each */ Nbuf = 32, /* 1.5 seconds total */ . 79a typedef struct IOstate IOstate; . ## diffname bitsy/devuda1341.c 2000/1110 ## diff -e /n/emeliedump/2000/1109/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1110/sys/src/9/bitsy/devuda1341.c 770a sendaudio(a); . 767d 755,756c while (a->active && a->filling == a->current) sleep(&a->vous, audioqnotfull, a); . 569,602d 540a qunlock(&audio.o); . 537,539c if (audio.o.chan == c) { /* closing the write end */ audio.amode &= ~Awrite; while (audio.o.filling->nbytes) { audio.o.filling++; if (audio.o.filling == &audio.o.buf[Nbuf]) audio.o.filling = &audio.o.buf[0]; sendaudio(&audio.o); } while(!audioidle(&audio.o)) sleep(&audio.o.vous, audioidle, &audio.o); audioamplifier(0); setempty(&audio.o); } if (audio.i.chan == c) { /* closing the read end */ audio.amode &= ~Aread; setempty(&audio.i); } if (audio.amode == 0) { /* turn audio off */ audiopower(0); } . 533a qunlock(&audio.o); . 525,532c qlock(&audio.o); . 510c IOstate *b; . 493a audio.o.chan = c; &audio.o.dma = dmaalloc(0, 0, 8, 2, AudioDMA, void *port, void (*f)(int, ulong)) . 489a amplifierpower(1); audiomute(0); . 485a audio.i.chan = c; . 480a audiopower(1); . 474c // if (omode & ~(Aread | Awrite)) if (omode & ~(Awrite)) . 435a wakeup(s->vous); . 434a if (canlock(s)) { sendaudio(s); unlock(s); } . 430,432c /* call this with lock held */ while (b->next != b->filling) { assert(b->next->nbytes); if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0) break; incref(&b->active); b->next++; if (b->next == &b->buf[Nbuf]) b->next == &b->buf[0]; } } static void audiointr(void *x, ulong state) { IOstate *s = x; if (s == &audio.o) { decref(&s->active); /* Only interrupt routine touches s->current */ s->current->nbytes = 0; s->current++; . 423,424d 419,421c print("audio enabled\n"); . 402a sspregs->control0 = 0x10<<0 | 0x1<<4 | 1<<7 | 0x8<<8; sspregs->control1 = 0<<3 + 0<<4 + 1<<5; /* Enable the audio power */ set_bitsy_egpio(EGPIO_BITSY_CODEC_NRESET|EGPIO_BITSY_AUD_AMP_ON|EGPIO_BITSY_AUD_PWR_ON); clr_bitsy_egpio(EGPIO_BITSY_QMUTE); gpioregs->direction |= (GPIO_BITSY_CLK_SET0|GPIO_BITSY_CLK_SET1); /* external clock configured for 44100 samples/sec */ GPSR = GPIO_BITSY_CLK_SET0; GPCR = GPIO_BITSY_CLK_SET1; printk("gpioregs->altfunc=%08x gpioregs->direction=%08x GPLR=%08x\n", gpioregs->altfunc, gpioregs->direction, GPLR); printk("PPDR=%08x PPSR=%08x PPAR=%08x PPFR=%08x\n", PPDR, PPSR, PPAR, PPFR); /* Wait for the UDA1341 to wake up */ mdelay(100); printk("Ser4SSSR=%08x\n", Ser4SSSR); audio_uda1341_reset(); . 401c gpioregs->altfunc &= ~(GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM); gpioregs->altfunc |= (GPIO_SSP_CLK); gpioregs->direction &= ~(GPIO_SSP_CLK); . 399c /* Setup the uarts */ ppcregs->assignment &= ~(1<<18); /* Could be the other way round! */ . 397d 387,394d 385a /* do nothing */ } static void audioenable(void) { . 382a static int audioqnotfull(IOstate *s) { /* called with lock */ return s->active == 0 || s->filling != s->current; } static int audioqnotempty(IOstate *s) { /* called with lock */ return s->next != s->filling; } static int audioidle(IOstate *s) { /* called with lock */ return s->active == 0; } . 380a b->next = b->buf; . 345c static int L3_read(char addr, char * data, int len) . 327c static int L3_write(char addr, char *data, int len) . 314c µdelay(L3_ModeHoldTime); . 309c µdelay(L3_ModeSetupTime); . 302,305c default: /* Subsequent bytes */ gpioregs->clear = GPIO_L3_MODE_o; µdelay(L3_HaltTime); gpioregs->set = GPIO_L3_MODE_o; . 300c case 1: /* First data byte */ . 298c case 0: /* Address mode - never valid */ . 295c gpioregs->direction &= ~(GPIO_L3_SDA_io); . 289c static char L3_getbyte(int mode) . 277c µdelay(L3_ModeHoldTime); . 275c gpioregs->set = GPIO_L3_MODE_o; . 269c µdelay(L3_ModeSetupTime); . 262,265c default: /* Subsequent bytes */ gpioregs->clear = GPIO_L3_MODE_o; µdelay(L3_HaltTime); gpioregs->set = GPIO_L3_MODE_o; . 260c case 1: /* First data byte */ . 257,258c case 0: /* Address mode */ gpioregs->clear = GPIO_L3_MODE_o; . 250c static void L3_sendbyte(char data, int mode) . 241,242c gpioregs->set = GPIO_L3_SCLK_o; µdelay(L3_ClockHighTime); . 239c µdelay(L3_ClockLowTime); . 236c gpioregs->clear = GPIO_L3_SDA_io; . 234c gpioregs->set = GPIO_L3_SDA_io; . 231c gpioregs->clear = GPIO_L3_SCLK_o; . 229c static void L3_sendbit(int bit) . 219,220c gpioregs->set = GPIO_L3_SCLK_o; µdelay(L3_ClockHighTime); . 217c data = (gpioregs->level & GPIO_L3_SDA_io) ? 1 : 0; . 214,215c gpioregs->clear = GPIO_L3_SCLK_o; µdelay(L3_ClockLowTime); . 210c static int L3_getbit(void) . 200,202c gpioregs->altfunc &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o); gpioregs->set = GPIO_L3_MODE_o; gpioregs->direction |= GPIO_L3_MODE_o; . 198c static void L3_init(void) . 191,192c gpioregs->direction &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io); gpioregs->clear = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); . 189c static void L3_releasepins(void) . 182,183c gpioregs->set = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); gpioregs->direction |= (GPIO_L3_SCLK_o | GPIO_L3_SDA_io); . 180c static void L3_acquirepins(void) . 133,137c Rendez vous; Chan *chan; /* chan of open */ int dma; /* dma chan, alloc on open, free on close */ int bufinit; /* boolean, if buffers allocated */ Buf buf[Nbuf]; /* buffers and queues */ int 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 */ . 125d 19a #include "sa1110dma.h" . ## diffname bitsy/devuda1341.c 2000/1111 ## diff -e /n/emeliedump/2000/1110/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1111/sys/src/9/bitsy/devuda1341.c 844c Dev uda1341devtab = { . 825c memmove(a->filling->virt + a->filling->nbytes, p, m); . 819c while (a->active.ref && a->filling == a->current) . 778,779c // resetlevel(); // mxvolume(); . 762d 725d 651d 625c amplifierpower(0); . 592d 575c audio.o.dma = dmaalloc(0, 0, 8, 2, AudioDMA, Port4MCP, audiointr, (void*)&audio.o); . 568,569c // amplifierpower(1); // audiomute(0); . 557c audioenable(); . 510c wakeup(&s->vous); . 507c unlock((Lock*)s); . 503,505c if (s->current == &s->buf[Nbuf]) s->current = &s->buf[0]; if (canlock((Lock*)s)) { . 495c audiointr(void *x, ulong) { . 490c b->next = &b->buf[0]; . 481c sendaudio(IOstate *b) { . 477c /* write uda 1341 status[1] */ data[0] = 0x80 | 0x3<clear = EGPIO_codec_reset; gpioregs->set = EGPIO_codec_reset; . 457c /* Reset the chip */ data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */ | 1<<6 /* reset */; L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 ); . 454,455c delay(100); print("Ser4SSSR=0x%lux\n", sspregs->status); . 450,452d 448a 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; . 442,447c audiopower(1); amplifierpower(1); audiomute(0); . 434,436c 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); . 427c uchar data[2]; . 415c return s->active.ref == 0; . 413a IOstate *s = x; . 412c audioidle(void *x) . 401c return s->active.ref == 0 || s->filling != s->current; . 399a IOstate *s = x; . 398c audioqnotfull(void *x) . 390d 358c L3_read(uchar addr, uchar *data, int len) . 339c L3_write(uchar addr, uchar *data, int len) . 138c Ref active; /* # of dmas in progress */ . 77a #define UDA1341_L3Addr 5 . 74d ## diffname bitsy/devuda1341.c 2000/1113 ## diff -e /n/emeliedump/2000/1111/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1113/sys/src/9/bitsy/devuda1341.c 822a if (debug) print("#A: write %ld\n", n); . 596a if (debug) print("#A: open done\n"); . 500a if (debug) print("#A: sendaudio\n"); . 495c if (debug) print("#A: audio enabled\n"); . 387a if (debug) print("#A: setempty\n"); . 377a if (debug) print("#A: bufinit\n"); . 21a static int debug = 1; . ## diffname bitsy/devuda1341.c 2000/1114 ## diff -e /n/emeliedump/2000/1113/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1114/sys/src/9/bitsy/devuda1341.c 598c audio.o.dma = dmaalloc(0, 0, 8, 2, SSPXmitDMA, Port4SSP, audiointr, (void*)&audio.o); . 587a audio.i.chan = c; audio.i.dma = dmaalloc(0, 0, 8, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o); . 586d ## diffname bitsy/devuda1341.c 2000/1115 ## diff -e /n/emeliedump/2000/1114/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1115/sys/src/9/bitsy/devuda1341.c 852a if (debug > 1) print("#A: filled @%p\n", a->filling); . 842a } . 841c while (a->active.ref && a->filling == a->current) { if (debug > 1) print("#A: sleep\n"); . 830c if (debug > 1) print("#A: write %ld\n", n); . 641c if (audio.o.filling->nbytes) { . 628a if (debug > 1) print("#A: close\n"); . 602a qunlock(&audio); . 601d 528,531c decref(&s->active); sendaudio(s); . 524c if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current); . 522d 514a iunlock(&b->ilock); . 510a if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0) { decref(&b->active); break; } if (debug > 1) print("#A: dmastart @%p\n", b->next); b->next->nbytes = 0; . 508,509d 504,505c /* interrupt routine calls this too */ if (debug > 1) print("#A: sendaudio\n"); ilock(&b->ilock); . 498a /* 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 */ . 465,466c delay(10); . 460a gpioregs->clear = EGPIO_codec_reset; gpioregs->set = EGPIO_codec_reset; . 446a sspregs->control0 |= 1<<7; /* enable */ . 444c sspregs->control0 = 0xf<<0 | 0x1<<4 | 0x3<<8; . 438c ppcregs->assignment &= (1<<18); /* Could be the other way round! */ . 134a Lock ilock; . ## diffname bitsy/devuda1341.c 2000/1116 ## diff -e /n/emeliedump/2000/1115/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1116/sys/src/9/bitsy/devuda1341.c 860c while (!dmaidle(a->dma) && a->filling == a->current) { . 682a print("total dmas: %lud\n", iostats.totaldma); print("dmas while idle: %lud\n", iostats.idledma); print("dmas while busy: %lud\n", iostats.faildma); . 669a dmafree(audio.o.dma); . 666,667c delay(2000); // dmawait(audio.o.dma); if (!dmaidle(audio.o.dma)) print("dma still busy\n"); . 598a memset(&iostats, 0, sizeof(iostats)); . 548,549c if (ndma > 0) sendaudio(s); . 539c audiointr(void *x, ulong ndma) { . 528a iostats.totaldma++; if (n == 1) iostats.idledma++; . 524,526c if ((n = dmastart(b->dma, b->next->virt, b->next->nbytes)) == 0) { iostats.faildma++; . 519a int n; . 504,514c if (debug) { print("#A: audio enabled\n"); print("\tsspregs->control0 = 0x%lux\n", sspregs->control0); print("\tsspregs->control1 = 0x%lux\n", sspregs->control1); } . 482c data[0] = 15 & 0x3f; /* 6 bits, others must be 0 */ . 471,476d 469a gpioregs->set = EGPIO_codec_reset; gpioregs->clear = EGPIO_codec_reset; /* write uda 1341 status[0] */ data[0] &= ~(1<set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o; // gpioregs->clear = GPIO_CLK_SET1_o; . 454a /* external clock configured for 44100 samples/sec */ . 448,449d 445,446c sspregs->control0 = 0; sspregs->control0 = 0x031f; /* 16 bits, TI frames, serial clock rate 3 */ sspregs->control1 = 0x0020; /* ext clock */ sspregs->control0 = 0x039f; /* enable */ . 439c ppcregs->assignment &= ~(1<<18); . 410,424d 407c return dmaidle(s->dma) || s->filling != s->current; . 161a static struct { ulong bytes; ulong totaldma; ulong idledma; ulong faildma; } iostats; . 141d ## diffname bitsy/devuda1341.c 2000/1117 ## diff -e /n/emeliedump/2000/1116/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1117/sys/src/9/bitsy/devuda1341.c 810,811c resetlevel(); mxvolume(); . 674a print("out of order dma: %lud\n", iostats.samedma); . 671a poperror(); . 669,670d 662a indisable(); . 657,658c setempty(s); dmafree(s->dma); qunlock(s); poperror(); . 652,655c dmawait(s->dma); outdisable(); . 646,650c if (s->filling->nbytes) { /* send remaining partial buffer */ s->filling++; if (s->filling == &s->buf[Nbuf]) s->filling = &s->buf[0]; sendaudio(s); . 642a s = &audio.o; qlock(s); if(waserror()){ qunlock(s); nexterror(); } . 638d 636d 620a IOstate *s; . 605c mxvolume(); . 599,603c if(s->bufinit == 0) bufinit(s); setempty(s); s->chan = c; s->dma = dmaalloc(0, 0, 4, 2, SSPXmitDMA, Port4SSP, audiointr, (void*)s); . 594a outenable(); s = &audio.o; . 591,592c s->chan = c; s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o); . 585a inenable(); s = &audio.i; . 583c enable(); . 559a IOstate *s; . 520c iunlock(&s->ilock); . 513,518c switch (n) { case 1: iostats.idledma++; break; case 3: iostats.faildma++; break; } if (debug > 1) print("#A: dmastart @%p\n", s->next); s->next->nbytes = 0; s->next++; if (s->next == &s->buf[Nbuf]) s->next = &s->buf[0]; . 505,508c ilock(&s->ilock); while (s->next != s->filling) { assert(s->next->nbytes); if ((n = dmastart(s->dma, s->next->virt, s->next->nbytes)) == 0) { . 500c outdisable(void) { /* turn off DAC, clear output gain switch */ status1 &= ~0x41; L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); if (debug) { print("uchar status1 = 0x%2.2ux\n", status1); } } static void inenable(void) { /* turn on ADC, set input gain switch */ status1 |= 0x22; L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); if (debug) { print("uchar status1 = 0x%2.2ux\n", status1); } } static void indisable(void) { /* turn off ADC, clear input gain switch */ status1 &= ~0x22; L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); if (debug) { print("uchar status1 = 0x%2.2ux\n", status1); } } static void sendaudio(IOstate *s) { . 493,495c print("uchar status1 = 0x%2.2ux\n", status1); print("uchar data00 = 0x%2.2ux\n", data00); . 491a static void outenable(void) { /* turn on DAC, set output gain switch */ status1 |= 0x41; L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); /* set volume */ data00 |= 0xf; L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1); . 487,490c } . 482,485c if(audio.amode & Aread){ left = audio.livol; right = audio.rivol; } if(audio.amode & Awrite){ left = audio.lovol; right = audio.rovol; data00 &= ~0x3f; data00 |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f; L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1); if (debug) print("uchar data00 = 0x%2.2ux (audio out)\n", data00); if (left[Vtreb]+right[Vtreb] <= 100 && left[Vbass]+right[Vbass] <= 100) { /* settings neutral */ data02 &= ~0x03; L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); if (debug) print("uchar data02 = 0x%2.2ux (mode flat)\n", data02); } else { data02 |= 0x03; L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); if (debug) print("uchar data02 = 0x%2.2ux (mode boost)\n", data02); data01 |= ~0x3f; data01 |= ((left[Vtreb]+right[Vtreb]-100)*0x3/100)&0x03; data01 |= (((left[Vbass]+right[Vbass]-100)*0xf/100)&0xf)<<2; L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data01, 1); if (debug) print("uchar data01 = 0x%2.2ux (bass&treb)\n", data01); } } . 477,480c static void mxvolume(void) { int *left, *right; . 473,475c 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; } } . 469,471c static void resetlevel(void) { int i; . 465,467c if (debug) { print("uchar status0 = 0x%2.2ux\n", status0); print("uchar status1 = 0x%2.2ux\n", status1); print("uchar data02 = 0x%2.2ux\n", data02); print("ushort data0e2 = 0x%4.4ux\n", data0e2); print("ushort data0e4 = 0x%4.4ux\n", data0e4); print("ushort data0e6 = 0x%4.4ux\n", data0e6); print("#A: audio enabled\n"); print("\tsspregs->control0 = 0x%lux\n", sspregs->control0); print("\tsspregs->control1 = 0x%lux\n", sspregs->control1); } } . 462,463c L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status0, 1 ); L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e2, 2); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 ); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e6, 2 ); . 460a gpioregs->set = EGPIO_codec_reset; . 457,459c data = status0 | 1<set = GPIO_CLK_SET0_o; gpioregs->clear = GPIO_CLK_SET1_o; . 433,436d 431c ppcregs->assignment &= ~(1<<18); . 426c ushort data; . 424c enable(void) . 422a uchar status0 = 0x22; uchar status1 = 0x80; uchar data00 = 0x00; /* volume control, bits 0 – 5 */ uchar data01 = 0x40; uchar data02 = 0x90; ushort data0e2 = 0xf2c2; ushort data0e4 = 0xf3c4; ushort data0e6 = 0xe3c6; . 184,185c [Vtreb] "treb", Fout|Fmono, 50, 50, [Vbass] "bass", Fout|Fmono, 50, 50, . 177,182c [Vaudio] "audio", Fout|Fmono, 50, 50, [Vmic] "mic", Fin, 0, 0, . 166a ulong samedma; . 105d 101,103d 93c Fin = 2, . 79c #define UDA1341_L3Addr 0x14 . 50,51c #define L3_ClockHighTime 10 /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ #define L3_ClockLowTime 10 /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ . 44c * L3 setup and hold times (expressed in µs) . ## diffname bitsy/devuda1341.c 2000/1118 ## diff -e /n/emeliedump/2000/1117/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1118/sys/src/9/bitsy/devuda1341.c 876a if (m < 0 || m > 100) error(Evolume); . 838c return readstr(offset, p, n, buf); . 797c return readstr(offset, p, n, buf); . 791a break; . 790a if (debug > 1) print("#A: read %ld\n", n); if((audio.amode & Aread) == 0) error(Emode); s = &audio.o; qlock(s); if(waserror()){ qunlock(s); nexterror(); } while(n > 0) { /* wait if dma in progress */ while (!dmaidle(s->dma) && s->emptying == s->next) { if (debug > 1) print("#A: sleep\n"); sleep(&s->vous, audioqnotempty, s); } m = Bufsize - s->emptying->nbytes; if(m > n) m = n; memmove(p, s->emptying->virt + s->emptying->nbytes, m); s->emptying->nbytes -= m; n -= m; p += m; if(s->emptying->nbytes == 0) { if (debug > 1) print("#A: emptied @%p\n", s->emptying); s->emptying++; if (s->emptying == &s->buf[Nbuf]) s->emptying = s->buf; sendaudio(s); } } poperror(); qunlock(s); . 788c return devdirread(c, p, n, audiodir, nelem(audiodir), devgen); . 781c p = v; . 778c char *p; IOstate *s; . 753c setempty(s); dmafree(s->dma); qunlock(s); poperror(); . 751a s = &audio.i; qlock(s); if(waserror()){ qunlock(s); nexterror(); } dmawait(s->dma); . 731,733d 724a /* closing the write end */ audio.amode &= ~Awrite; . 673c s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s); . 670,671c bufinit(s); setempty(s); . 612a } else if (s == &audio.i) { /* Only interrupt routine touches s->current */ if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current); s->current->nbytes = Bufsize; s->current++; if (s->current == &s->buf[Nbuf]) s->current = &s->buf[0]; if (ndma > 0) recvaudio(s); . 601a 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) { assert(s->next->nbytes == 0); if ((n = dmastart(s->dma, s->next->phys, Bufsize)) == 0) { iostats.faildma++; break; } iostats.totaldma++; switch (n) { case 1: iostats.idledma++; break; case 3: iostats.faildma++; break; } if (debug > 1) print("#A: dmastart @%p\n", s->next); s->next++; if (s->next == &s->buf[Nbuf]) s->next = &s->buf[0]; } iunlock(&s->ilock); } static void . 579c if ((n = dmastart(s->dma, s->next->phys, s->next->nbytes)) == 0) { . 497a if (left[Vmic]+right[Vmic] == 0) { /* Turn on automatic gain control (AGC) */ data0e4 |= 0x1000; L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 ); } else { int v; /* Turn on manual gain control */ v = ((left[Vmic]+right[Vmic])*0x7f/200)&0x7f; data0e4 &= ~0x1300; data0e5 &= ~0x1f00; data0e4 |= (v & 0x3)<<8; data0e5 |= (v & 0x7c)<<6; L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 ); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e5, 2 ); } . 462d 422c /* there is no data0e3 */ ushort data0e4 = 0xe0c4; ushort data0e5 = 0xe0c5; . 420a ushort data0e0 = 0xe0c0; ushort data0e1 = 0xe0c1; . 406d 401a audioqnotempty(void *x) { IOstate *s = x; return dmaidle(s->dma) || s->emptying != s->next; } static int . 383a b->buf[i].phys = PADDR(b->buf[i].virt); } . 382c for (i = 0; i < Nbuf; i++) { . 175c [Vmic] "mic", Fin|Fmono, 0, 0, . 139a /* just be be cute (and to have defines like linux, a real operating system) */ #define emptying filling . 124a ulong phys; . 80a enum { UDA1341_DATA0 = 0, UDA1341_DATA1, UDA1341_STATUS, UDA1341_L3Addr = 0x14, }; . 76,79d 46,52c enum { L3_DataSetupTime = 1, /* 190 ns */ L3_DataHoldTime = 1, /* 30 ns */ L3_ModeSetupTime = 1, /* 190 ns */ L3_ModeHoldTime = 1, /* 190 ns */ L3_ClockHighTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ L3_ClockLowTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ L3_HaltTime = 1, /* 190 ns */ }; . ## diffname bitsy/devuda1341.c 2000/1120 ## diff -e /n/emeliedump/2000/1118/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1120/sys/src/9/bitsy/devuda1341.c 1049a mxvolume(); . 1025a if(strcmp(field[i], "debug") == 0) { debug = debug?0:1; goto cont0; } . 1023d 905c recvaudio(s); . 762a resetlevel(); . 557a if (left[Vfilter]+right[Vfilter] == 0) data02 &= ~0x10; else data02 |= 0x10; if (left[Vinvert]+right[Vinvert] == 0) status1 &= ~0x14; else status1 |= 0x14; L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data01, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1); if (debug) { print("uchar status1 = 0x%2.2ux;\n", status1); print("uchar data00 = 0x%2.2ux; /* audio out */\n", data00); print("uchar data01 = 0x%2.2ux; /* bass&treb */\n", data01); print("uchar data02 = 0x%2.2ux; /* mode */\n", data02); } . 555,556d 550,552c data01 &= ~0x3f; . 546,548c else { . 543c && left[Vbass]+right[Vbass] <= 100) . 540,541d 514a if (debug) print("mxvolume\n"); . 437c uchar data02 = 0x80; . 185,186c [Vtreb] "treb", Fout|Fmono, 50, 50, [Vbass] "bass", Fout|Fmono, 50, 50, [Vfilter] "filter", Fout|Fmono, 0, 0, [Vinvert] "invert", Fin|Fout|Fmono, 0, 0, . 182,183c [Vaudio] "audio", Fout|Fmono, 80, 80, [Vmic] "mic", Fin|Fmono, 0, 0, . 112c Bufsize = 4*1024, /* 46 ms each */ . 109a Vfilter, Vinvert, . 22c static int debug = 0; . ## diffname bitsy/devuda1341.c 2000/1121 ## diff -e /n/emeliedump/2000/1120/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1121/sys/src/9/bitsy/devuda1341.c 916,922d 903c while (!dmaidle(s->dma) && s->emptying == s->current) { . 901a 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; } . 895c s = &audio.i; . 784,785c c = devopen(c, mode, audiodir, nelem(audiodir), devgen); c->mode = openmode(mode); . 768,770d 765c if (omode & Awrite) { . 761a s->emptying = &s->buf[Nbuf-1]; . 759c if(s->bufinit == 0) . 757d 744,745c if (omode & ~(Aread | Awrite)) . 728a int omode = mode; . 726c audioopen(Chan *c, int mode) . 694,701c else if (s == &audio.i) . 686,692c if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current); /* Only interrupt routine touches s->current */ s->current++; if (s->current == &s->buf[Nbuf]) s->current = &s->buf[0]; if (ndma > 0) { if (s == &audio.o) . 593a audiomute(1); amplifierpower(0); . 579a amplifierpower(1); audiomute(0); . 467,468d 434c /* Turn MCP operations off */ mcpregs = mapspecial(MCPREGS, 0x34); mcpregs->status &= ~(1<<16); sspregs = mapspecial(SSPREGS, 32); . 430a SSPregs *sspregs; MCPregs *mcpregs; . 420c return dmaidle(s->dma) || s->emptying != s->current; . 22c static int debug = 2; . ## diffname bitsy/devuda1341.c 2000/1122 ## diff -e /n/emeliedump/2000/1121/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1122/sys/src/9/bitsy/devuda1341.c 1129a audiopower, . 856c egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0); . 847d 832d 780c if (debug) print("open done\n"); . 765c s->dma = dmaalloc(1, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s); . 695c if (debug) { if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current); else iprint("-"); } . 683c if (debug) { if (debug > 1) print("dmastart @%p\n", s->next); else iprint("+"); } . 652c if (debug) { if (debug > 1) print("dmastart @%p\n", s->next); else iprint("+"); } . 630a disable(void) { egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0); } static void audiopower(int flag) { if (flag) { egpiobits(EGPIO_audio_power, 1); egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1); } else { /* power off */ egpiobits(EGPIO_audio_power, 0); egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0); } } static void . 626c print("indisable: status1 = 0x%2.2ux\n", status1); . 621a dmastop(audio.i.dma); . 616c print("inenable: status1 = 0x%2.2ux\n", status1); . 612a // egpiobits(EGPIO_audio_power, 1); // audiomute(0); . 607a egpiobits(EGPIO_audio_power, 0); . 606c print("outdisable: status1 = 0x%2.2ux\n", status1); . 602c egpiobits(EGPIO_audio_power, 0); . 599a dmastop(audio.o.dma); . 593,594c print("outenable: status1 = 0x%2.2ux\n", status1); print("outenable: data00 = 0x%2.2ux\n", data00); . 585c egpiobits(EGPIO_audio_power, 1); . 579d 573,576c print("mxvolume: status1 = 0x%2.2ux\n", status1); print("mxvolume: data00 = 0x%2.2ux\n", data00); print("mxvolume: data01 = 0x%2.2ux\n", data01); print("mxvolume: data02 = 0x%2.2ux\n", data02); . 567c status1 |= 0x10; . 565c status1 &= ~0x10; . 543c if (left[Vinvert]+right[Vinvert] == 0) status1 &= ~0x04; else status1 |= 0x04; L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1); if (debug) { print("mxvolume: status1 = 0x%2.2ux\n", status1); print("mxvolume: data0e4 = 0x%4.4ux\n", data0e4); print("mxvolume: data0e5 = 0x%4.4ux\n", data0e5); } . 524d 495,503c print("enable: status0 = 0x%2.2ux\n", status0); print("enable: status1 = 0x%2.2ux\n", status1); print("enable: data02 = 0x%2.2ux\n", data02); print("enable: data0e2 = 0x%4.4ux\n", data0e2); print("enable: data0e4 = 0x%4.4ux\n", data0e4); print("enable: data0e6 = 0x%4.4ux\n", data0e6); print("enable: sspregs->control0 = 0x%lux\n", sspregs->control0); print("enable: sspregs->control1 = 0x%lux\n", sspregs->control1); . 473c egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1); . 406c if (debug) print("setempty\n"); . 393c if (debug) print("bufinit\n"); . 384a void audiomute(int on) { egpiobits(EGPIO_audio_mute, on); } . 22c static int debug = 0; . ## diffname bitsy/devuda1341.c 2000/1123 ## diff -e /n/emeliedump/2000/1122/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1123/sys/src/9/bitsy/devuda1341.c 659,660c if (audio.omode & Aread) indisable(); if (audio.omode & Awrite) outdisable(); egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset | EGPIO_audio_power, 0); . 653a if (debug) { iprint("audiopower %d\n", flag); } . 647,652c void . 627,628d ## diffname bitsy/devuda1341.c 2000/1125 ## diff -e /n/emeliedump/2000/1123/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1125/sys/src/9/bitsy/devuda1341.c 823a audio.amode |= Awrite; . 813a audio.amode |= Aread; . 807d 733a void audiopower(int flag) { IOstate *s; if (debug) { iprint("audiopower %d\n", flag); } if (flag) { /* power on only when necessary */ if (audio.amode) { egpiobits(EGPIO_audio_power | EGPIO_audio_ic_power | 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_audio_ic_power | EGPIO_codec_reset | EGPIO_audio_power, 0); } } . 645,662d ## diffname bitsy/devuda1341.c 2000/1130 ## diff -e /n/emeliedump/2000/1125/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1130/sys/src/9/bitsy/devuda1341.c 925,928c if (debug) { print("total dmas: %lud\n", iostats.totaldma); print("dmas while idle: %lud\n", iostats.idledma); print("dmas while busy: %lud\n", iostats.faildma); print("out of order dma: %lud\n", iostats.samedma); } . ## diffname bitsy/devuda1341.c 2000/1207 ## diff -e /n/emeliedump/2000/1130/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1207/sys/src/9/bitsy/devuda1341.c 184,193c [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} . ## diffname bitsy/devuda1341.c 2000/1216 ## diff -e /n/emeliedump/2000/1207/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1216/sys/src/9/bitsy/devuda1341.c 842d ## diffname bitsy/devuda1341.c 2001/0331 ## diff -e /n/emeliedump/2000/1216/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0331/sys/src/9/bitsy/devuda1341.c 942a uchar voldata; . 47,53c L3_DataSetupTime = 10, /* 190 ns */ L3_DataHoldTime = 10, /* 30 ns */ L3_ModeSetupTime = 10, /* 190 ns */ L3_ModeHoldTime = 10, /* 190 ns */ L3_ClockHighTime = 100, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ L3_ClockLowTime = 100, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */ L3_HaltTime = 10, /* 190 ns */ . ## diffname bitsy/devuda1341.c 2001/0421 ## diff -e /n/emeliedump/2001/0331/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0421/sys/src/9/bitsy/devuda1341.c 1127a } if(strcmp(field[i], "reg") == 0) { if(nf < 3) error(Evolume); setreg(field[1], atoi(field[2]), nf == 4 ? atoi(field[3]):1); return n0; . 943d 639c print("indisable: status1 = 0x%2.2ux\n", status1[0]); . 636,637c status1[0] &= ~0x22; L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); . 628c print("inenable: status1 = 0x%2.2ux\n", status1[0]); . 625,626c status1[0] |= 0x22; L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); . 617c print("outdisable: status1 = 0x%2.2ux\n", status1[0]); . 614,615c status1[0] &= ~0x41; L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); . 603,604c print("outenable: status1 = 0x%2.2ux\n", status1[0]); print("outenable: data00 = 0x%2.2ux\n", data00[0]); . 600,601c data00[0] |= 0xf; L3_write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1); . 597,598c status1[0] |= 0x41; L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); . 592a setreg(char *name, int val, int n) { uchar x[2]; int i; x[0] = val; x[1] = val>>8; if(strcmp(name, "pause") == 0){ for(i = 0; i < n; i++) µdelay(val); return; } switch(n){ case 1: case 2: break; default: error("setreg"); } if(strcmp(name, "status") == 0){ L3_write(UDA1341_L3Addr | UDA1341_STATUS, x, n); } else if(strcmp(name, "data0") == 0){ L3_write(UDA1341_L3Addr | UDA1341_DATA0, x, n); } else if(strcmp(name, "data1") == 0){ L3_write(UDA1341_L3Addr | UDA1341_DATA1, x, n); } else error("setreg"); } static void . 584,587c 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]); . 578,582c status1[0] |= 0x10; L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data01, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1); . 576c status1[0] &= ~0x10; . 574c data02[0]|= 0x10; . 572c data02[0] &= ~0x10; . 566,569c 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; . 564c data02[0] &= ~0x03; . 559,560c data00[0] &= ~0x3f; data00[0] |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f; . 551,553c 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); . 548,549c status1[0] |= 0x04; L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); . 546c status1[0] &= ~0x04; . 538,543c data0e4[1] &= ~0x13; data0e5[1] &= ~0x1f; data0e4[1] |= v & 0x3; data0e5[0] |= (v & 0x7c)<<6; data0e5[1] |= (v & 0x7c)>>2; L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 ); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e5, 2 ); . 532,533c data0e4[1] |= 0x10; L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 ); . 499,504c 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); . 492,496c L3_write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1 ); L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e2, 2); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e6, 2 ); . 487,488c data[0] = status0[0] | 1<direction &= ~(GPIO_L3_SDA_io); . 375a L3_acquirepins(); . 369c * Commented out, not used . 360c L3_releasepins(); . 356a L3_acquirepins(); . 318,319c //suspect L3_acquirepins(); . 302c //suspect L3_releasepins(); . 296a µdelay(L3_ModeHoldTime); . 277c //suspect L3_acquirepins(); . 211d 201a µdelay(2); . 193a static void setreg(char *name, int val, int n); . 67,68c UdaStatusPC = 0, /* 2 bits */ UdaStatusDS = 2, /* 1 bit */ . 62c UdaStatusRST = 6, /* 1 bit */ . 47,53c L3_DataSetupTime = 1, /* 190 ns */ L3_DataHoldTime = 1, /* 30 ns */ L3_ModeSetupTime = 1, /* 190 ns */ L3_ModeHoldTime = 1, /* 190 ns */ L3_ClockHighTime = 1, /* 100 ns */ L3_ClockLowTime = 1, /* 100 ns */ L3_HaltTime = 1, /* 190 ns */ . ## diffname bitsy/devuda1341.c 2001/0428 ## diff -e /n/emeliedump/2001/0421/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0428/sys/src/9/bitsy/devuda1341.c 342,343d 322,323d 305,306d 299,300d 279,280d 223,224d 213c gpioregs->direction &= ~(GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io); µdelay(L3_ReleaseTime); . 202,204c gpioregs->set = (GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io); gpioregs->direction |= (GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io); µdelay(L3_AcquireTime); . 47,53c L3_AcquireTime = 1, L3_ReleaseTime = 1, L3_DataSetupTime = (190+999)/1000, /* 190 ns */ L3_DataHoldTime = ( 30+999)/1000, L3_ModeSetupTime = (190+999)/1000, L3_ModeHoldTime = (190+999)/1000, L3_ClockHighTime = (100+999)/1000, L3_ClockLowTime = (100+999)/1000, L3_HaltTime = (190+999)/1000, . ## diffname bitsy/devuda1341.c 2001/0501 ## diff -e /n/emeliedump/2001/0428/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0501/sys/src/9/bitsy/devuda1341.c 444a . 22c static int debug = 2; . ## diffname bitsy/devuda1341.c 2001/0502 ## diff -e /n/emeliedump/2001/0501/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0502/sys/src/9/bitsy/devuda1341.c 1012,1015c m = (s->emptying->nbytes > n)? n: s->emptying->nbytes; memmove(p, s->emptying->virt + Bufsize - s->emptying->nbytes, m); . 955d 935,949d 933d 931c if ((audio.amode & Aread) == 0) dmafree(s->dma); . 928c while(waserror()) { dmawait(s->dma); if (dmaidle(s->dma)) break; } . 917,920d 908,910c 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); if (dmaidle(s->dma)) break; } outdisable(); setempty(s); dmafree(s->dma); qunlock(s); } . 877a if (audio.amode == Aread) sendaudio(&audio.o); . 874a outenable(); . 873a } if (omode & Awrite) { . 868d 865,866c if (omode & (Aread|Awrite) && (audio.amode & Awrite) == 0) { . 801c } else if (s == &audio.i) . 794,799c 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)? Bufsize: 0; s->current++; if (s->current == &s->buf[Nbuf]) s->current = &s->buf[0]; } if (ndma) { if (s == &audio.o) { zerodma &= ~ndma; . 727c switch (n >> 8) { . 691c switch (n >> 8) { . 683a 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; if (zerodma == 0) if (debug) print("emptyfail\n"); iostats.empties++; iunlock(&s->ilock); return; } . 401a if (b == &audio.o) { zeroes.virt = xalloc(Bufsize); zeroes.phys = PADDR(b->buf[i].virt); memset(zeroes.virt, 0, Bufsize); } . 399a memset(b->buf[i].virt, 0xAA, Bufsize); . 191,193c [Vfilter] {"filter", Fout|Fmono, 0, 0}, [Vinvert] {"invert", Fin|Fout|Fmono, 0, 0}, [Nvol] {0} . 186,189c [Vaudio] {"audio", Fout|Fmono, 80, 80}, [Vmic] {"mic", Fin|Fmono, 0, 0}, [Vtreb] {"treb", Fout|Fmono, 50, 50}, [Vbass] {"bass", Fout|Fmono, 50, 50}, . 175a ulong empties; . 168a Buf zeroes; int zerodma; /* dma buffer used for sending zero */ . 150c /* to have defines just like linux — there's a real operating system */ . 148c volatile Buf *next; /* next candidate for dma */ . 142,146c Rendez vous; Chan *chan; /* chan of open */ int dma; /* dma chan, alloc on open, free on close */ int bufinit; /* boolean, if buffers allocated */ Buf buf[Nbuf]; /* buffers and queues */ . 22c static int debug = 0; . ## diffname bitsy/devuda1341.c 2001/0503 ## diff -e /n/emeliedump/2001/0502/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0503/sys/src/9/bitsy/devuda1341.c 973,977c while(waserror()) ; dmawait(s->dma); poperror(); . 950,954c while(waserror()) ; dmawait(s->dma); poperror(); . ## diffname bitsy/devuda1341.c 2001/0504 ## diff -e /n/emeliedump/2001/0503/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0504/sys/src/9/bitsy/devuda1341.c 905c if (audio.amode & Aread) . ## diffname bitsy/devuda1341.c 2001/0508 ## diff -e /n/emeliedump/2001/0504/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0508/sys/src/9/bitsy/devuda1341.c 1221d 1217c while (!dmaidle(a->dma) && !zerodma && a->filling == a->current) { . 1121a 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; . 1061a case Qspeed: buf[0] = '\0'; snprint(buf, sizeof(buf), "speed %d\n", rate); return readstr(offset, p, n, buf); . 930a case Qspeed: . 902a mxspeed(Speed); . 865a case Qspeed: . 697c zerodma |= dmastart(s->dma, Flushbuf, Bufsize) & 0xff; . 534a 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 . 472a mxspeed(int _rate); static void . 407,412d 199a static int rate = Speed; /* Current sample rate */ . 169d 127a "speed", {Qspeed}, 0, 0666, . 126c "audio", {Qaudio}, 0, 0666, . 122a enum { Flushbuf = 0xe0000000, }; /* System Clock */ enum { SC512FS = 0, SC384FS = 1, SC256FS = 2, }; /* Format */ enum { LSB16 = 1, LSB18 = 2, }; . 96a Qspeed, . ## diffname bitsy/devuda1341.c 2001/0509 ## diff -e /n/emeliedump/2001/0508/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0509/sys/src/9/bitsy/devuda1341.c 1215c i = (int)strtol(field[i], (char **)nil, 0); switch (i) { case 16000: case 22050: case 44100: case 48000: volumes[Vspeed].ilval = volumes[Vspeed].irval = rate = i; break; default: error(Ebadarg); } . 975d 604a 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; } } . 603d 600,601c data[0] = status0[0] | 1<clear = EGPIO_codec_reset; gpioregs->set = EGPIO_codec_reset; /* write uda 1341 status[0] */ data[0] = status0[0] | clock; L3_write(UDA1341_L3Addr | UDA1341_STATUS, data, 1); L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e2, 2); L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e6, 2 ); if (debug) { print("enable: status0 = 0x%2.2ux\n", data[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); print("enable: sspregs->control0 = 0x%lux\n", sspregs->control0); print("enable: sspregs->control1 = 0x%lux\n", sspregs->control1); } . 597c clock = SC384FS; /* Only works in MSB mode! */ . 594c clock = SC256FS; . 589a default: . 588c clock = SC512FS; /* Only works in MSB mode! */ . 584a /* Reset the chip */ . 582a /* Wait for the UDA1341 to wake up */ . 507,557d 491c uchar data[1], clock; . 486,488d 472c uchar status0[1] = {0x02}; . 137,138c LSB16 = 1 << 1, LSB18 = 2 << 1, LSB20 = 3 << 1, MSB = 4 << 1, MSB16 = 5 << 1, MSB18 = 6 << 1, MSB20 = 7 << 1, . 130,132c SC512FS = 0 << 2, SC384FS = 1 << 2, SC256FS = 2 << 2, . 128c /* System Clock -- according to the manual, it seems that when the UDA is configured in non MSB/I2S mode, it uses a divisor of 256 to the 12.288MHz clock. The other rates are only supported in MSB mode, which should be implemented at some point */ . 117c Bufsize = /* 4* */ 1024, /* 46 ms each */ . ## diffname bitsy/devuda1341.c 2001/0510 ## diff -e /n/emeliedump/2001/0509/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0510/sys/src/9/bitsy/devuda1341.c 1327c if(a->filling->nbytes >= bufsize) { . 1319c m = bufsize - a->filling->nbytes; . 1207,1216c while (i < nf) { int newval; if (i + 1 >= nf) error(Ebadarg); newval = (int)strtol(field[i + 1], (char **)nil, 0); if (!strcmp(field[i], "speed")) setrate(newval); else if (!strcmp(field[i], "dmasize")) setbufsize(newval); else error(Ebadarg); i += 2; } . 1199,1205c if (nf == 1) /* The user just supplied a number */ setrate((int)strtol(field[0], (char **)nil, 0)); else { . 1176a static void setrate(int newrate) { switch (newrate) { case 16000: case 22050: case 44100: case 48000: volumes[Vspeed].ilval = volumes[Vspeed].irval = rate = newrate; break; default: error(Ebadarg); } } static void setbufsize(int newbufsize) { if (newbufsize < 0 || newbufsize > 8 * 1024 || newbufsize % sizeof(ulong)) error(Ebadarg); bufsize = newbufsize; } . 1130c snprint(buf, sizeof(buf), "speed %d\ndmasize %d\n", rate, bufsize); . 1110c memmove(p, s->emptying->virt + bufsize - . 882c s->current->nbytes = (s == &audio.i)? bufsize: 0; . 806c if ((n = dmastart(s->dma, s->next->phys, bufsize)) == 0) { . 761c zerodma |= dmastart(s->dma, Flushbuf, bufsize) & 0xff; . 226a static int bufsize = Bufsize; /* Current buffer size */ . 225d 117c Bufsize = 4* 1024, /* 46 ms each */ . ## diffname bitsy/devuda1341.c 2001/0512 ## diff -e /n/emeliedump/2001/0510/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0512/sys/src/9/bitsy/devuda1341.c 118c Nbuf = 10, /* 1.5 seconds total */ . ## diffname bitsy/devuda1341.c 2001/0526 ## diff -e /n/emeliedump/2001/0512/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0526/sys/src/9/bitsy/devuda1341.c 1130c snprint(buf, sizeof(buf), "speed %d\ndmasize %d\nsendbytes %d\n", rate, bufsize, nsendb); . 1128a s = &audio.o; nbufs = s->filling - s->current; if (nbufs < 0) nbufs = Nbuf + nbufs; nsendb = (nbufs - 1) * bufsize + s->current->nbytes; . 1067c int liv, riv, lov, rov, nsendb, nbufs; . 140,146c LSB16 = 1 << 1, LSB18 = 2 << 1, LSB20 = 3 << 1, MSB = 4 << 1, MSB16 = 5 << 1, MSB18 = 6 << 1, MSB20 = 7 << 1, . 121c Ncmd = 50, /* max volume command words */ . 118c Nbuf = 10, /* 1.5 seconds total */ . 102c Fout = 4, . ## diffname bitsy/devuda1341.c 2001/0528 ## diff -e /n/emeliedump/2001/0526/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0528/sys/src/9/bitsy/devuda1341.c 1376d 1215c switch((ulong)c->qid.path) { . 1077c switch((ulong)c->qid.path) { . 989c switch((ulong)c->qid.path) { . 921c switch((ulong)c->qid.path) { . 912c return devstat(c, db, n, audiodir, nelem(audiodir), devgen); . 909,910c static int audiostat(Chan *c, uchar *db, int n) . 906c return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen); . 904c audiowalk(Chan *c, Chan *nc, char **name, int nname) . 774,789d 769,772c 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.faildma++; break; } iostats.totaldma++; switch (n >> 8) { 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; . 151a ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, . 12a . ## diffname bitsy/devuda1341.c 2001/0529 ## diff -e /n/emeliedump/2001/0528/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0529/sys/src/9/bitsy/devuda1341.c 907c static Walkqid* . ## diffname bitsy/devuda1341.c 2001/0530 ## diff -e /n/emeliedump/2001/0529/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0530/sys/src/9/bitsy/devuda1341.c 118,119c Bufsize = 4* 1024, /* 23 ms each */ Nbuf = 10, /* 230 ms total */ . ## diffname bitsy/devuda1341.c 2001/0605 ## diff -e /n/emeliedump/2001/0530/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0605/sys/src/9/bitsy/devuda1341.c 1358c if(a->filling->nbytes >= volumes[Vbufsize].ilval) { . 1350c m = volumes[Vbufsize].ilval - a->filling->nbytes; . 1269,1278c if (volumes[v].setval) volumes[v].setval(in, out, left, right, m); . 1224,1250d 1205c volumes[Vbufsize].ilval = value; . 1203c if ((value % 8) != 0 || value < 8 || value >= Bufsize) . 1201c setbufsize(int, int, int, int, int value) . 1197a /* Wait for the UDA1341 to wake up */ delay(100); /* Reset the chip */ status0[0] &= ~CLOCKMASK; status0[0] |=clock; volumes[Vspeed].ilval = speed; . 1196c 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; . 1193c /* 00 */ gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o; clock = SC256FS; . 1188,1191c 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; . 1186c setaudio(int in, int out, int left, int right, int value) . 1145,1148c 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; } . 1132,1138c 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); . 1114c memmove(p, s->emptying->virt + volumes[Vbufsize].ilval - . 1071c int liv, riv, lov, rov; . 1057,1062d 1001a case Qstats: . 1000d 934d 930a case Qstats: . 916c return devstat(c, db, n, audiodir, nelem(audiodir), devgen); . 910c return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen); . 886c s->current->nbytes = (s == &audio.i)? volumes[Vbufsize].ilval: 0; . 820c iostats.rx.faildma++; . 817c iostats.rx.idledma++; . 814c iostats.rx.totaldma++; . 810,811c if ((n = dmastart(s->dma, s->next->phys, volumes[Vbufsize].ilval)) == 0) { iostats.rx.faildma++; . 783c iostats.tx.faildma++; . 780c iostats.tx.idledma++; . 777c iostats.tx.totaldma++; . 774c iostats.tx.faildma++; . 766c iostats.tx.empties++; . 763c zerodma |= dmastart(s->dma, Flushbuf, volumes[Vbufsize].ilval) & 0xff; . 603a setspeed(0, 0, 0, 0, volumes[Vspeed].ilval); if (!dmaidle(audio.i.dma) || !dmaidle(audio.o.dma)) L3_write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1); . 569a if (debug) print("enable: status0 = 0x%2.2ux\n", data[0]); . 568c data[0] = status0[0]; . 562,564d 540,560c data[0] = status0[0] | 1 << UdaStatusRST; . 513,538c setspeed(0, 0, 0, 0, volumes[Vspeed].ilval); . 498c uchar data[1]; . 227,228d 218,224c [Vaudio] {"audio", Fout|Fmono, 80, 80, setaudio }, [Vmic] {"mic", Fin|Fmono, 0, 0, nil }, [Vtreb] {"treb", Fout|Fmono, 50, 50, nil }, [Vbass] {"bass", Fout|Fmono, 50, 50, nil }, [Vspeed] {"speed", Fin|Fout|Fmono, Speed, Speed, setspeed }, [Vbufsize] {"bufsize", Fin|Fout|Fmono, Bufsize, Bufsize, setbufsize }, [Vfilter] {"filter", Fout|Fmono, 0, 0, nil }, [Vinvert] {"invert", Fin|Fout|Fmono, 0, 0, nil }, . 213,215c int flag; int ilval; /* initial values */ int irval; void (*setval)(int, int, int, int, int); . 209a static void setaudio(int in, int out, int left, int right, int value); static void setspeed(int in, int out, int left, int right, int value); static void setbufsize(int in, int out, int left, int right, int value); . 207a } iostats_t; static struct { ulong bytes; iostats_t rx, tx; . 200,202c typedef struct { . 153,157c ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "audio", {Qaudio}, 0, 0666, "volume", {Qvolume}, 0, 0666, "audiostatus", {Qstatus}, 0, 0444, "audiostats", {Qstats}, 0, 0444, . 136a CLOCKMASK = 3 << 2, . 118,119c Bufsize = 4* 1024, /* 46 ms each */ Nbuf = 10, /* 1.5 seconds total */ . 113a Vbufsize, . 99a Qstats, . 98d 13d ## diffname bitsy/devuda1341.c 2001/0620 ## diff -e /n/emeliedump/2001/0605/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0620/sys/src/9/bitsy/devuda1341.c 1086d 944a qunlock(&audio); . 942d ## diffname bitsy/devuda1341.c 2001/0810 ## diff -e /n/emeliedump/2001/0620/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0810/sys/src/9/bitsy/devuda1341.c 1023c egpiobits(EGPIO_codec_reset, 0); audioicpower(0); . 837c egpiobits(EGPIO_codec_reset, 0); audioamppower(0); audioicpower(0); . 815c audioamppower(1); audioicpower(1); egpiobits(EGPIO_codec_reset, 1); . 699c audioamppower(0); . 693d 675c audioamppower(1); . 520c audioicpower(1); egpiobits(EGPIO_codec_reset, 1); . ## diffname bitsy/devuda1341.c 2001/1117 ## diff -e /n/emeliedump/2001/0810/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/1117/sys/src/9/bitsy/devuda1341.c 1273c nf = tokenize(buf, field, Ncmd); . ## diffname bitsy/devuda1341.c 2001/1121 ## diff -e /n/emeliedump/2001/1117/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/1121/sys/src/9/bitsy/devuda1341.c 1334a poperror(); free(cb); . 1327c setreg(cb->f[1], atoi(cb->f[2]), cb->nf == 4 ? atoi(cb->f[3]):1); . 1324,1325c if(strcmp(cb->f[i], "reg") == 0) { if(cb->nf < 3) . 1319c if(strcmp(cb->f[i], "right") == 0) { . 1314c if(strcmp(cb->f[i], "left") == 0) { . 1309c if(strcmp(cb->f[i], "out") == 0) { . 1304c if(strcmp(cb->f[i], "in") == 0) { . 1300c if(strcmp(cb->f[i], "debug") == 0) { . 1296c if(strcmp(cb->f[i], "reset") == 0) { . 1286c if(strcmp(cb->f[i], volumes[m].name) == 0) { . 1278,1279c if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') { m = strtoul(cb->f[i], 0, 10); . 1273,1274c for(i = 0; i < cb->nf; i++){ . 1268,1271c cb = parsecmd(p, n); if(waserror()){ free(cb); nexterror(); } . 1253a Cmdbuf *cb; . 1250,1251c int i, v, left, right, in, out; . 237a . ## diffname bitsy/devuda1341.c 2002/0109 ## diff -e /n/emeliedump/2001/1121/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2002/0109/sys/src/9/bitsy/devuda1341.c 1384a devshutdown, . ## diffname bitsy/devuda1341.c 2002/0606 ## diff -e /n/emeliedump/2002/0109/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2002/0606/sys/src/9/bitsy/devuda1341.c 652c microdelay(val); . 377c microdelay(L3_ModeHoldTime); . 372c microdelay(L3_ModeSetupTime); . 367c microdelay(L3_HaltTime); . 344c microdelay(L3_ModeHoldTime); . 336c microdelay(L3_ModeSetupTime); . 331c microdelay(L3_HaltTime); . 310c microdelay(L3_ClockHighTime); . 307c microdelay(L3_ClockLowTime); . 287c microdelay(L3_ClockHighTime); . 282c microdelay(L3_ClockLowTime); . 259c microdelay(L3_ReleaseTime); . 249c microdelay(L3_AcquireTime); . ## diffname bitsy/devuda1341.c 2002/1112 ## diff -e /n/emeliedump/2002/0606/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2002/1112/sys/src/9/bitsy/devuda1341.c 488c sspregs = mapspecial(SSPREGS, sizeof(SSPregs)); . 485c mcpregs = mapspecial(MCPREGS, sizeof(MCPregs)); .