diff options
| author | Konstantin Kirik (snegovick) <snegovick@uprojects.org> | 2025-12-28 12:27:31 +0300 |
|---|---|---|
| committer | Konstantin Kirik (snegovick) <snegovick@uprojects.org> | 2025-12-28 12:27:31 +0300 |
| commit | 78ee7d5717807e6ac779293d0d3c78341de6130a (patch) | |
| tree | a43e3b0f61318ac45e6d907c7cc5bad2c6d7f497 /os/ipaq1110/devaudio.c | |
| parent | bdaf46cf45bbb59261da245d548a179d95a42768 (diff) | |
Move existing boards into subdits split per arch
Diffstat (limited to 'os/ipaq1110/devaudio.c')
| -rw-r--r-- | os/ipaq1110/devaudio.c | 1056 |
1 files changed, 0 insertions, 1056 deletions
diff --git a/os/ipaq1110/devaudio.c b/os/ipaq1110/devaudio.c deleted file mode 100644 index 66fb5cdc..00000000 --- a/os/ipaq1110/devaudio.c +++ /dev/null @@ -1,1056 +0,0 @@ -/* - * 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) { - assert(s->next->nbytes == 0); - if ((n = dmastart(s->dma, (void*)s->next->phys, Bufsize)) == 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++; - if (s->next == &s->buf[Nbuf]) - s->next = &s->buf[0]; - } - iunlock(&s->ilock); -} - -static void -audiopower(int flag) { - IOstate *s; - - if (debug) { - iprint("audiopower %d\n", flag); - } - if (flag) { - /* power on only when necessary */ - if (audio.amode) { - archaudiopower(1); - enable(); - if (audio.amode & Aread) { - inenable(); - s = &audio.i; - dmastop(s->dma); - recvaudio(s); - } - if (audio.amode & Awrite) { - outenable(); - s = &audio.o; - dmastop(s->dma); - sendaudio(s); - } - mxvolume(); - } - } else { - /* power off */ - if (audio.amode & Aread) - indisable(); - if (audio.amode & Awrite) - outdisable(); - disable(); - archaudiopower(0); - } -} - -static void -audiointr(void *x, ulong ndma) { - IOstate *s = x; - - if (debug) { - if (debug > 1) - iprint("#A: audio interrupt @%p\n", s->current); - else - iprint("-"); - } - /* 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) - sendaudio(s); - else if (s == &audio.i) - recvaudio(s); - } - wakeup(&s->vous); -} - -static void -audioinit(void) -{ - audio.amode = Aclosed; - resetlevel(); -// powerenable(audiopower); -} - -static Chan* -audioattach(char *param) -{ - return devattach('A', param); -} - -static Walkqid* -audiowalk(Chan *c, Chan *nc, char **name, int nname) -{ - return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen); -} - -static int -audiostat(Chan *c, uchar *db, int n) -{ - return devstat(c, db, n, audiodir, nelem(audiodir), devgen); -} - -static Chan* -audioopen(Chan *c, int mode) -{ - IOstate *s; - int omode = mode; - - switch((ulong)c->qid.path) { - default: - error(Eperm); - break; - - case Qstatus: - if((omode&7) != OREAD) - error(Eperm); - case Qvolume: - case Qaudioctl: - case Qdir: - break; - - case Qaudio: - omode = (omode & 0x7) + 1; - if (omode & ~(Aread | Awrite)) - error(Ebadarg); - qlock(&audio); - if(audio.amode & omode){ - qunlock(&audio); - error(Einuse); - } - enable(); - memset(&iostats, 0, sizeof(iostats)); - if (omode & Aread) { - inenable(); - s = &audio.i; - if(s->bufinit == 0) - bufinit(s); - setempty(s); - s->emptying = &s->buf[Nbuf-1]; - s->chan = c; - s->dma = dmasetup(DmaSSP, 1, 0, audiointr, (void*)s); - audio.amode |= Aread; - audio.clockout = 1; - } - if (omode & Awrite) { - outenable(); - s = &audio.o; - audio.amode |= Awrite; - if(s->bufinit == 0) - bufinit(s); - setempty(s); - s->chan = c; - s->dma = dmasetup(DmaSSP, 0, 0, audiointr, (void*)s); - audio.amode |= Awrite; - } - mxvolume(); - qunlock(&audio); - if (debug) print("open done\n"); - break; - } - c = devopen(c, mode, audiodir, nelem(audiodir), devgen); - c->mode = openmode(mode); - c->flag |= COPEN; - c->offset = 0; - - return c; -} - -static void -audioclose(Chan *c) -{ - IOstate *s; - - switch((ulong)c->qid.path) { - default: - error(Eperm); - break; - - case Qdir: - case Qvolume: - case Qaudioctl: - case Qstatus: - break; - - case Qaudio: - if (debug > 1) print("#A: close\n"); - if(c->flag & COPEN) { - qlock(&audio); - if(waserror()){ - qunlock(&audio); - nexterror(); - } - if (audio.o.chan == c) { - /* closing the write end */ - audio.amode &= ~Awrite; - s = &audio.o; - qlock(s); - if(waserror()){ - qunlock(s); - nexterror(); - } - if (s->filling->nbytes) { - /* send remaining partial buffer */ - s->filling++; - if (s->filling == &s->buf[Nbuf]) - s->filling = &s->buf[0]; - sendaudio(s); - } - dmawait(s->dma); - outdisable(); - setempty(s); - dmafree(s->dma); - qunlock(s); - poperror(); - } - if (audio.i.chan == c) { - /* closing the read end */ - audio.amode &= ~Aread; - s = &audio.i; - qlock(s); - if(waserror()){ - qunlock(s); - nexterror(); - } - indisable(); - setempty(s); - dmafree(s->dma); - qunlock(s); - poperror(); - } - if (audio.amode == 0) { - /* turn audio off */ - archaudiopower(0); - } - qunlock(&audio); - poperror(); - 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); - } - } - break; - } -} - -static long -audioread(Chan *c, void *v, long n, vlong off) -{ - int liv, riv, lov, rov; - long m, n0; - char buf[300]; - int j; - ulong offset = off; - char *p; - IOstate *s; - - n0 = n; - p = v; - switch((ulong)c->qid.path) { - default: - error(Eperm); - break; - - case Qdir: - return devdirread(c, p, n, audiodir, nelem(audiodir), devgen); - - case Qaudio: - if (debug > 1) print("#A: read %ld\n", n); - if((audio.amode & Aread) == 0) - error(Emode); - s = &audio.i; - qlock(s); - if(waserror()){ - qunlock(s); - nexterror(); - } - while(n > 0) { - if(s->emptying->nbytes == 0) { - if (debug > 1) print("#A: emptied @%p\n", s->emptying); - recvaudio(s); - s->emptying++; - if (s->emptying == &s->buf[Nbuf]) - s->emptying = s->buf; - } - /* wait if dma in progress */ - while (!dmaidle(s->dma) && s->emptying == s->current) { - if (debug > 1) print("#A: sleep\n"); - sleep(&s->vous, audioqnotempty, s); - } - - m = 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; - } - poperror(); - qunlock(s); - break; - break; - - case Qstatus: - buf[0] = 0; - snprint(buf, sizeof(buf), "bytes %llud\ntime %lld\n", - audio.totcount, audio.tottime); - return readstr(offset, p, n, buf); - - case Qvolume: - case Qaudioctl: - 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, p, 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]; - char *p; - IOstate *a; - - p = vp; - n0 = n; - switch((ulong)c->qid.path) { - default: - error(Eperm); - break; - - case Qvolume: - case Qaudioctl: - v = Vaudio; - left = 1; - right = 1; - in = 1; - out = 1; - if(n > sizeof(buf)-1) - n = sizeof(buf)-1; - memmove(buf, p, n); - buf[n] = '\0'; - 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(v == Vspeed){ - if(archaudiospeed(m, 0) < 0) - error(Evolume); - }else - if(m < 0 || m > 100) - error(Evolume); - 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; - goto cont0; - } - if(strcmp(field[i], "rate") == 0) - field[i] = "speed"; /* honestly ... */ - - 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], "enc") == 0) { - if(++i >= nf) - error(Evolume); - if(strcmp(field[i], "pcm") != 0) - error(Evolume); - goto cont0; - } - if(strcmp(field[i], "bits") == 0) { - if(++i >= nf) - error(Evolume); - if(strtol(field[i], 0, 0) != 16) - error(Evolume); - goto cont0; - } - if(strcmp(field[i], "chans") == 0) { - if(++i >= nf) - error(Evolume); - if(strtol(field[i], 0, 0) != 2) - error(Evolume); - goto cont0; - } - if(strcmp(field[i], "reset") == 0) { - resetlevel(); - goto cont0; - } - if(strcmp(field[i], "debug") == 0) { - debug = debug?0:1; - 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; - } - 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; - } - error(Evolume); - break; - cont0:; - } - mxvolume(); - break; - - case Qaudio: - if (debug > 1) print("#A: write %ld\n", n); - if((audio.amode & Awrite) == 0) - error(Emode); - a = &audio.o; - qlock(a); - if(waserror()){ - qunlock(a); - nexterror(); - } - while(n > 0) { - /* wait if dma in progress */ - while (!dmaidle(a->dma) && a->filling == a->current) { - if (debug > 1) print("#A: sleep\n"); - sleep(&a->vous, audioqnotfull, a); - } - - m = Bufsize - a->filling->nbytes; - if(m > n) - m = n; - memmove(a->filling->virt + a->filling->nbytes, p, m); - - a->filling->nbytes += m; - n -= m; - p += m; - if(a->filling->nbytes >= Bufsize) { - if (debug > 1) print("#A: filled @%p\n", a->filling); - a->filling++; - if (a->filling == &a->buf[Nbuf]) - a->filling = a->buf; - sendaudio(a); - } - } - poperror(); - qunlock(a); - break; - } - return n0 - n; -} - -Dev audiodevtab = { - 'A', - "audio", - - audioreset, - audioinit, - devshutdown, - audioattach, - audiowalk, - audiostat, - audioopen, - devcreate, - audioclose, - audioread, - devbread, - audiowrite, - devbwrite, - devremove, - devwstat, - audiopower, -}; |
