summaryrefslogtreecommitdiff
path: root/os/ipaq1110/devaudio.c
diff options
context:
space:
mode:
authorKonstantin Kirik (snegovick) <snegovick@uprojects.org>2025-12-28 12:27:31 +0300
committerKonstantin Kirik (snegovick) <snegovick@uprojects.org>2025-12-28 12:27:31 +0300
commit78ee7d5717807e6ac779293d0d3c78341de6130a (patch)
treea43e3b0f61318ac45e6d907c7cc5bad2c6d7f497 /os/ipaq1110/devaudio.c
parentbdaf46cf45bbb59261da245d548a179d95a42768 (diff)
Move existing boards into subdits split per arch
Diffstat (limited to 'os/ipaq1110/devaudio.c')
-rw-r--r--os/ipaq1110/devaudio.c1056
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,
-};