ref: 4bc74b8aefb222cbc58f42b0fdbc28f50e5f1a35
parent: 334c58f95e3c0834037448a37ca5d4f1c8589b4e
author: cinap_lenrek <cinap_lenrek@localhost>
date: Fri May 20 14:30:46 EDT 2011
audioif, mixer control
--- a/sys/src/9/pc/audioac97.c
+++ b/sys/src/9/pc/audioac97.c
@@ -5,6 +5,7 @@
#include "fns.h"
#include "io.h"
#include "../port/error.h"
+#include "../port/audioif.h"
typedef struct Hwdesc Hwdesc;
typedef struct Ctlr Ctlr;
@@ -65,10 +66,6 @@
ulong civstat[Ndesc];
ulong lvistat[Ndesc];
- int targetrate;
- int hardrate;
-
- int attachok;
int sis7012;
/* for probe */
@@ -145,8 +142,8 @@
#define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
/* audioac97mix */
-extern int ac97hardrate(Audio *, int);
-extern void ac97mixreset(Audio *, void (*wr)(Audio*,int,ushort),
+extern void ac97mixreset(Audio *,
+ void (*wr)(Audio*,int,ushort),
ushort (*rr)(Audio*,int));
static void
@@ -202,11 +199,9 @@
adev = arg;
ctlr = adev->ctlr;
stat = csr32r(ctlr, Sta);
-
stat &= S2ri | Sri | Pri | Mint | Point | Piint | Moint | Miint | Gsci;
-
- ilock(ctlr);
if(stat & Point){
+ ilock(ctlr);
if(ctlr->sis7012)
csr16w(ctlr, Out + Picb, csr16r(ctlr, Out + Picb) & ~Dch);
else
@@ -232,10 +227,11 @@
if(ctlr->outavail > Bufsize/2)
wakeup(&ctlr->outr);
stat &= ~Point;
+ iunlock(ctlr);
}
- iunlock(ctlr);
if(stat) /* have seen 0x400, which is sdin0 resume */
- print("#A%d: ac97 unhandled interrupt(s): stat 0x%lux\n", adev->ctlrno, stat);
+ iprint("#A%d: ac97 unhandled interrupt(s): stat 0x%lux\n",
+ adev->ctlrno, stat);
}
static int
@@ -272,52 +268,30 @@
return ts[Nts/2] / BytesPerSample;
}
-static void
-ac97volume(Audio *adev, char *msg)
-{
- adev->volwrite(adev, msg, strlen(msg), 0);
-}
-
-static void
-ac97attach(Audio *adev)
-{
- Ctlr *ctlr;
- ctlr = adev->ctlr;
- if(!ctlr->attachok){
- ac97hardrate(adev, ctlr->hardrate);
- ac97volume(adev, "audio 75");
- ac97volume(adev, "head 100");
- ac97volume(adev, "master 100");
- ctlr->attachok = 1;
- }
-}
-
static long
-ac97status(Audio *adev, void *a, long n, vlong off)
+ac97status(Audio *adev, void *a, long n, vlong)
{
+ char *p, *e;
Ctlr *ctlr;
- char *buf;
- long i, l;
+ int i;
+
ctlr = adev->ctlr;
- l = 0;
- buf = malloc(READSTR);
- l += snprint(buf + l, READSTR - l, "rate %d\n", ctlr->targetrate);
- l += snprint(buf + l, READSTR - l, "median rate %lud\n", ac97medianoutrate(adev));
- l += snprint(buf + l, READSTR - l, "hard rate %d\n", ac97hardrate(adev, -1));
- l += snprint(buf + l, READSTR - l, "civ stats");
+ p = a;
+ e = p + n;
+
+ p += snprint(p, e - p, "median rate %lud\n", ac97medianoutrate(adev));
+ p += snprint(p, e - p, "civ stats");
for(i = 0; i < Ndesc; i++)
- l += snprint(buf + l, READSTR - l, " %lud", ctlr->civstat[i]);
- l += snprint(buf + l, READSTR - l, "\n");
+ p += snprint(p, e - p, " %lud", ctlr->civstat[i]);
+ p += snprint(p, e - p, "\n");
- l += snprint(buf + l, READSTR - l, "lvi stats");
+ p += snprint(p, e - p, "lvi stats");
for(i = 0; i < Ndesc; i++)
- l += snprint(buf + l, READSTR - l, " %lud", ctlr->lvistat[i]);
- snprint(buf + l, READSTR - l, "\n");
+ p += snprint(p, e - p, " %lud", ctlr->lvistat[i]);
+ p += snprint(p, e - p, "\n");
- n = readstr(off, a, n, buf);
- free(buf);
- return n;
+ return p - (char*)a;
}
static long
@@ -328,41 +302,6 @@
return Bufsize - Bufsize/Ndesc - ctlr->outavail;
}
-static long
-ac97ctl(Audio *adev, void *a, long n, vlong)
-{
- Ctlr *ctlr;
- char *tok[2], *p;
- int ntok;
- long t;
-
- ctlr = adev->ctlr;
- if(n > READSTR)
- n = READSTR - 1;
- p = malloc(READSTR);
-
- if(waserror()){
- free(p);
- nexterror();
- }
- memmove(p, a, n);
- p[n] = 0;
- ntok = tokenize(p, tok, nelem(tok));
- if(ntok > 1 && !strcmp(tok[0], "rate")){
- t = strtol(tok[1], 0, 10);
- if(t < 8000 || t > 48000)
- error("rate must be between 8000 and 48000");
- ctlr->targetrate = t;
- ctlr->hardrate = t;
- ac97hardrate(adev, ctlr->hardrate);
- poperror();
- free(p);
- return n;
- }
- error("invalid ctl");
- return n; /* shut up, you compiler you */
-}
-
static void
ac97kick(Ctlr *ctlr, long reg)
{
@@ -490,9 +429,6 @@
Found:
adev->ctlr = ctlr;
- ctlr->targetrate = 44100;
- ctlr->hardrate = 44100;
-
if(p->vid == 0x1039 && p->did == 0x7012)
ctlr->sis7012 = 1;
@@ -588,13 +524,11 @@
csr8w(ctlr, Out+Cr, Ioce); /* | Lvbie | Feie */
csr8w(ctlr, Mic+Cr, Ioce); /* | Lvbie | Feie */
- adev->attach = ac97attach;
+ ac97mixreset(adev, ac97mixw, ac97mixr);
+
adev->write = ac97write;
adev->status = ac97status;
- adev->ctl = ac97ctl;
adev->buffered = ac97buffered;
-
- ac97mixreset(adev, ac97mixw, ac97mixr);
intrenable(irq, ac97interrupt, adev, tbdf, adev->name);
--- a/sys/src/9/pc/audioac97mix.c
+++ b/sys/src/9/pc/audioac97mix.c
@@ -5,20 +5,8 @@
#include "fns.h"
#include "io.h"
#include "../port/error.h"
+#include "../port/audioif.h"
-typedef ushort (*ac97rdfn)(Audio *, int);
-typedef void (*ac97wrfn)(Audio *, int, ushort);
-
-typedef struct Mixer Mixer;
-typedef struct Volume Volume;
-
-struct Mixer {
- QLock;
- ac97wrfn wr;
- ac97rdfn rr;
- int vra;
-};
-
enum { Maxbusywait = 500000 };
enum {
@@ -33,22 +21,8 @@
Capadc18 = 0x100,
Capadc20 = 0x200,
Capenh = 0xfc00,
- Master = 0x02,
- Headphone = 0x04,
- Monomaster = 0x06,
- Mastertone = 0x08,
- Pcbeep = 0x0A,
- Phone = 0x0C,
- Mic = 0x0E,
- Line = 0x10,
- Cd = 0x12,
- Video = 0x14,
- Aux = 0x16,
- Pcmout = 0x18,
- Mute = 0x8000,
+
Recsel = 0x1A,
- Recgain = 0x1C,
- Micgain = 0x1E,
General = 0x20,
ThreeDctl = 0x22,
Ac97RESER = 0x24,
@@ -118,17 +92,9 @@
Spdifv = 1<<15,
VID1 = 0x7c,
VID2 = 0x7e,
- Speed = 0x1234567,
};
enum {
- Left,
- Right,
- Stereo,
- Absolute,
-};
-
-enum {
Vmaster,
Vhead,
Vaudio,
@@ -143,195 +109,125 @@
Vaux,
Vrecgain,
Vmicgain,
+ Vspeed,
};
-struct Volume {
- int reg;
- int range;
- int type;
- int cap;
- char *name;
+static Volume voltab[] = {
+ [Vmaster] "master", 0x02, 63, Stereo, 0,
+ [Vaudio] "audio", 0x18, 31, Stereo, 0,
+ [Vhead] "head", 0x04, 31, Stereo, Capheadphones,
+ [Vbass] "bass", 0x08, 15, Left, Captonectl,
+ [Vtreb] "treb", 0x08, 15, Right, Captonectl,
+ [Vbeep] "beep", 0x0a, 31, Right, 0,
+ [Vphone] "phone", 0x0c, 31, Right, 0,
+ [Vmic] "mic", 0x0e, 31, Right, Capmic,
+ [Vline] "line", 0x10, 31, Stereo, 0,
+ [Vcd] "cd", 0x12, 31, Stereo, 0,
+ [Vvideo] "video", 0x14, 31, Stereo, 0,
+ [Vaux] "aux", 0x16, 63, Stereo, 0,
+ [Vrecgain] "recgain", 0x1c, 15, Stereo, 0,
+ [Vmicgain] "micgain", 0x1e, 15, Right, Capmic,
+ [Vspeed] "speed", 0x2c, 0, Absolute, 0,
+ 0
};
-struct Topology {
- Volume *this;
- Volume *next[2];
+typedef struct Mixer Mixer;
+struct Mixer
+{
+ ushort (*rr)(Audio *, int);
+ void (*wr)(Audio *, int, ushort);
+ int vra;
};
-Volume vol[] = {
-[Vmaster] {Master, 63, Stereo, 0, "master"},
-[Vaudio] {Pcmout, 31, Stereo, 0, "audio"},
-[Vhead] {Headphone, 31, Stereo, Capheadphones, "head"},
-[Vbass] {Mastertone, 15, Left, Captonectl, "bass"},
-[Vtreb] {Mastertone, 15, Right, Captonectl, "treb"},
-[Vbeep] {Pcbeep, 31, Right, 0, "beep"},
-[Vphone] {Phone, 31, Right, 0, "phone"},
-[Vmic] {Mic, 31, Right, Capmic, "mic"},
-[Vline] {Line, 31, Stereo, 0, "line"},
-[Vcd] {Cd, 31, Stereo, 0, "cd"},
-[Vvideo] {Video, 31, Stereo, 0, "video"},
-[Vaux] {Aux, 63, Stereo, 0, "aux"},
-[Vrecgain] {Recgain, 15, Stereo, 0, "recgain"},
-[Vmicgain] {Micgain, 15, Right, Capmic, "micgain"},
- {0, 0, 0, 0, 0},
-};
-
-long
-ac97mixtopology(Audio *adev, void *a, long n, vlong off)
+static int
+ac97volget(Audio *adev, int x, int a[2])
{
- Mixer *m;
- char *buf;
- long l;
- ulong caps;
- m = adev->mixer;
- qlock(m);
- caps = m->rr(adev, Reset);
- caps |= m->rr(adev, Extid) << 16;
- l = 0;
- buf = malloc(READSTR);
- l += snprint(buf+l, READSTR-l, "not implemented. have fun.\n");
- USED(caps);
- USED(l);
- qunlock(m);
- n = readstr(off, a, n, buf);
- free(buf);
- return n;
-}
-
-long
-ac97mixread(Audio *adev, void *a, long n, vlong off)
-{
- Mixer *m;
- char *nam, *buf;
- long l;
+ Mixer *m = adev->mixer;
+ Volume *vol;
ushort v;
- ulong caps;
- int i, rang, le, ri;
- buf = malloc(READSTR);
- m = adev->mixer;
- qlock(m);
- l = 0;
- caps = m->rr(adev, Reset);
- caps |= m->rr(adev, Extid) << 16;
- for(i = 0; vol[i].name != 0; ++i){
- if(vol[i].cap && ((vol[i].cap & caps) == 0))
- continue;
- v = m->rr(adev, vol[i].reg);
- nam = vol[i].name;
- rang = vol[i].range;
- if(vol[i].type == Absolute){
- l += snprint(buf+l, READSTR-l, "%s %d", nam, v);
+
+ vol = voltab+x;
+ switch(vol->type){
+ case Absolute:
+ a[0] = m->rr(adev, vol->reg);
+ break;
+ default:
+ v = m->rr(adev, vol->reg);
+ if(v & 0x8000){
+ a[0] = 0;
+ a[1] = 0;
} else {
- ri = ((rang-(v&rang)) * 100) / rang;
- le = ((rang-((v>>8)&rang)) * 100) / rang;
- if(vol[i].type == Stereo)
- l += snprint(buf+l, READSTR-l, "%s %d %d", nam, le, ri);
- if(vol[i].type == Left)
- l += snprint(buf+l, READSTR-l, "%s %d", nam, le);
- if(vol[i].type == Right)
- l += snprint(buf+l, READSTR-l, "%s %d", nam, ri);
- if(v&Mute)
- l += snprint(buf+l, READSTR-l, " mute");
+ a[0] = vol->range - ((v>>8) & 0x7f);
+ a[1] = vol->range - (v & 0x7f);
}
- l += snprint(buf+l, READSTR-l, "\n");
}
- qunlock(m);
- n = readstr(off, a, n, buf);
- free(buf);
- return n;
+ return 0;
}
-long
-ac97mixwrite(Audio *adev, void *a, long n, vlong)
+static int
+ac97volset(Audio *adev, int x, int a[2])
{
- Mixer *m;
- char *tok[4];
- int ntok, i, left, right, rang, reg;
- ushort v;
- m = adev->mixer;
- qlock(m);
- ntok = tokenize(a, tok, 4);
- for(i = 0; vol[i].name != 0; ++i){
- if(!strcmp(vol[i].name, tok[0])){
- rang = vol[i].range;
- reg = vol[i].reg;
- left = right = 0;
- if(ntok > 1)
- left = right = atoi(tok[1]);
- if(ntok > 2)
- right = atoi(tok[2]);
+ Mixer *m = adev->mixer;
+ Volume *vol;
+ ushort v, w;
- if(vol[i].type == Absolute){
- m->wr(adev, reg, left);
- } else {
- left = rang - ((left*rang)) / 100;
- right = rang - ((right*rang)) / 100;
- switch(vol[i].type){
- default:
- break;
- case Left:
- v = m->rr(adev, reg);
- v = (v & 0x007f) | (left << 8);
- m->wr(adev, reg, v);
- break;
- case Right:
- v = m->rr(adev, reg);
- v = (v & 0x7f00) | right;
- m->wr(adev, reg, v);
- break;
- case Stereo:
- v = (left<<8) | right;
- m->wr(adev, reg, v);
- break;
- }
- }
- qunlock(m);
- return n;
- }
+ vol = voltab+x;
+ switch(vol->type){
+ case Absolute:
+ m->wr(adev, vol->reg, a[0]);
+ break;
+ case Left:
+ v = (vol->range - a[0]) & 0x7f;
+ w = m->rr(adev, vol->reg) & 0x7f;
+ m->wr(adev, vol->reg, (v<<8)|w);
+ break;
+ case Right:
+ v = m->rr(adev, vol->reg) & 0x7f00;
+ w = (vol->range - a[1]) & 0x7f;
+ m->wr(adev, vol->reg, v|w);
+ break;
+ case Stereo:
+ v = (vol->range - a[0]) & 0x7f;
+ w = (vol->range - a[1]) & 0x7f;
+ m->wr(adev, vol->reg, (v<<8)|w);
+ break;
}
- if(vol[i].name == nil){
- char *p;
- for(p = tok[0]; *p; ++p)
- if(*p < '0' || *p > '9') {
- qunlock(m);
- error("no such volume setting");
- }
- rang = vol[0].range;
- reg = vol[0].reg;
- left = right = rang - ((atoi(tok[0])*rang)) / 100;
- v = (left<<8) | right;
- m->wr(adev, reg, v);
- }
- qunlock(m);
+ return 0;
+}
- return n;
+
+static long
+ac97mixread(Audio *adev, void *a, long n, vlong)
+{
+ Mixer *m = adev->mixer;
+ ulong caps;
+
+ caps = m->rr(adev, Reset);
+ caps |= m->rr(adev, Extid) << 16;
+ return genaudiovolread(adev, a, n, 0, voltab, ac97volget, caps);
}
-int
-ac97hardrate(Audio *adev, int rate)
+static long
+ac97mixwrite(Audio *adev, void *a, long n, vlong)
{
- Mixer *m;
- int oldrate;
- m = adev->mixer;
- oldrate = m->rr(adev, Pcmfrontdacrate);
- if(rate > 0)
- m->wr(adev, Pcmfrontdacrate, rate);
- return oldrate;
+ Mixer *m = adev->mixer;
+ ulong caps;
+
+ caps = m->rr(adev, Reset);
+ caps |= m->rr(adev, Extid) << 16;
+ return genaudiovolwrite(adev, a, n, 0, voltab, ac97volset, caps);
}
void
-ac97mixreset(Audio *adev, ac97wrfn wr, ac97rdfn rr)
+ac97mixreset(Audio *adev, void (*wr)(Audio*,int,ushort), ushort (*rr)(Audio*,int))
{
Mixer *m;
- int i;
ushort t;
- if(adev->mixer == nil)
- adev->mixer = malloc(sizeof(Mixer));
- m = adev->mixer;
+ int i;
+
+ m = malloc(sizeof(Mixer));
m->wr = wr;
m->rr = rr;
- adev->volread = ac97mixread;
- adev->volwrite = ac97mixwrite;
m->wr(adev, Reset, 0);
m->wr(adev, Powerdowncsr, 0);
@@ -361,4 +257,8 @@
print("#A%d: ac97 vra extension not supported\n", adev->ctlrno);
m->vra = 0;
}
+
+ adev->mixer = m;
+ adev->volread = ac97mixread;
+ adev->volwrite = ac97mixwrite;
}
--- a/sys/src/9/pc/audiosb16.c
+++ b/sys/src/9/pc/audiosb16.c
@@ -8,6 +8,7 @@
#include "fns.h"
#include "io.h"
#include "../port/error.h"
+#include "../port/audioif.h"
typedef struct Ring Ring;
typedef struct Blaster Blaster;
@@ -15,11 +16,8 @@
enum
{
- Fmono = 1,
- Fin = 2,
- Fout = 4,
-
- Vaudio = 0,
+ Vmaster,
+ Vaudio,
Vsynth,
Vcd,
Vline,
@@ -27,12 +25,11 @@
Vspeaker,
Vtreb,
Vbass,
+ Vigain,
+ Vogain,
Vspeed,
Nvol,
- Speed = 44100,
- Ncmd = 50, /* max volume command words */
-
Blocksize = 4096,
Blocks = 65536/Blocksize,
};
@@ -70,10 +67,6 @@
QLock;
Rendez vous;
int active; /* boolean dma running */
- 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 */
@@ -80,35 +73,29 @@
vlong tottime; /* time at which totcount bytes were processed */
Ring ring; /* dma ring buffer */
Blaster blaster;
+ int lvol[Nvol];
+ int rvol[Nvol];
Audio *adev;
};
-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
+static Volume voltab[] = {
+ [Vmaster] "master", 0x30, 0xff, Stereo, 0,
+ [Vaudio] "audio", 0x32, 0xff, Stereo, 0,
+ [Vsynth] "synth", 0x34, 0xff, Stereo, 0,
+ [Vcd] "cd", 0x36, 0xff, Stereo, 0,
+ [Vline] "line", 0x38, 0xff, Stereo, 0,
+ [Vmic] "mic", 0x3a, 0xff, Mono, 0,
+ [Vspeaker] "speaker", 0x3b, 0xff, Mono, 0,
+ [Vtreb] "treb", 0x44, 0xff, Stereo, 0,
+ [Vbass] "bass", 0x46, 0xff, Stereo, 0,
+ [Vigain] "recgain", 0x3f, 0xff, Stereo, 0,
+ [Vogain] "outgain", 0x41, 0xff, Stereo, 0,
+ [Vspeed] "speed", 0, 0, Absolute, 0,
+ 0,
};
static char Emajor[] = "soundblaster not responding/wrong version";
-static char Emode[] = "illegal open mode";
-static char Evolume[] = "illegal volume specifier";
-
static long
buffered(Ring *r)
{
@@ -242,109 +229,44 @@
return s;
}
-static void
-mxcmds(Blaster *blaster, int s, int v)
+static int
+mxsetvol(Audio *adev, int x, int a[2])
{
-
- if(v > 100)
- v = 100;
- if(v < 0)
- v = 0;
- mxcmd(blaster, s, (v*255)/100);
-}
-
-static void
-mxcmdt(Blaster *blaster, int s, int v)
-{
-
- if(v > 100)
- v = 100;
- if(v <= 0)
- mxcmd(blaster, s, 0);
- else
- mxcmd(blaster, s, 255-100+v);
-}
-
-static void
-mxcmdu(Blaster *blaster, int s, int v)
-{
-
- if(v > 100)
- v = 100;
- if(v <= 0)
- v = 0;
- mxcmd(blaster, s, 128-50+v);
-}
-
-static void
-mxvolume(Ctlr *ctlr)
-{
Blaster *blaster;
- int *left, *right;
- int source;
+ Ctlr *ctlr = adev->ctlr;
+ Volume *vol;
- if(0){
- left = ctlr->livol;
- right = ctlr->rivol;
- }else{
- left = ctlr->lovol;
- right = ctlr->rovol;
+ if(x == Vspeed){
+ ctlr->lvol[x] = ctlr->rvol[x] = a[0];
+ return 0;
}
+ vol = voltab+x;
blaster = &ctlr->blaster;
-
ilock(blaster);
+ switch(vol->type){
+ case Stereo:
+ ctlr->rvol[x] = a[1];
+ mxcmd(blaster, vol->reg+1, a[1]);
+ /* no break */
+ case Mono:
+ ctlr->lvol[x] = a[0];
+ mxcmd(blaster, vol->reg, a[0]);
+ }
+ iunlock(blaster);
- mxcmd(blaster, 0x30, 255); /* left master */
- mxcmd(blaster, 0x31, 255); /* right master */
- mxcmd(blaster, 0x3f, 0); /* left igain */
- mxcmd(blaster, 0x40, 0); /* right igain */
- mxcmd(blaster, 0x41, 0); /* left ogain */
- mxcmd(blaster, 0x42, 0); /* right ogain */
+ return 0;
+}
- mxcmds(blaster, 0x32, left[Vaudio]);
- mxcmds(blaster, 0x33, right[Vaudio]);
+static int
+mxgetvol(Audio *adev, int x, int a[2])
+{
+ Ctlr *ctlr = adev->ctlr;
- mxcmds(blaster, 0x34, left[Vsynth]);
- mxcmds(blaster, 0x35, right[Vsynth]);
+ a[0] = ctlr->lvol[x];
+ a[1] = ctlr->rvol[x];
- mxcmds(blaster, 0x36, left[Vcd]);
- mxcmds(blaster, 0x37, right[Vcd]);
-
- mxcmds(blaster, 0x38, left[Vline]);
- mxcmds(blaster, 0x39, right[Vline]);
-
- mxcmds(blaster, 0x3a, left[Vmic]);
- mxcmds(blaster, 0x3b, left[Vspeaker]);
-
- mxcmdu(blaster, 0x44, left[Vtreb]);
- mxcmdu(blaster, 0x45, right[Vtreb]);
-
- mxcmdu(blaster, 0x46, left[Vbass]);
- mxcmdu(blaster, 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(0)
- mxcmd(blaster, 0x3c, 0); /* output switch */
- else
- mxcmd(blaster, 0x3c, source);
- mxcmd(blaster, 0x3d, source); /* input left switch */
- mxcmd(blaster, 0x3e, source); /* input right switch */
- iunlock(blaster);
+ return 0;
}
static void
@@ -385,22 +307,20 @@
ring = &ctlr->ring;
ilock(blaster);
dmaend(blaster->dma);
- if(0) {
- sbcmd(blaster, 0x42); /* input sampling rate */
- speed = ctlr->livol[Vspeed];
- } else {
- sbcmd(blaster, 0x41); /* output sampling rate */
- speed = ctlr->lovol[Vspeed];
- }
+ if(0)
+ sbcmd(blaster, 0x42); /* input sampling rate */
+ else
+ sbcmd(blaster, 0x41); /* output sampling rate */
+ speed = ctlr->lvol[Vspeed];
sbcmd(blaster, speed>>8);
sbcmd(blaster, speed);
if(0)
- sbcmd(blaster, 0xbe); /* A/D, autoinit */
+ sbcmd(blaster, 0xbe); /* A/D, autoinit */
else
- sbcmd(blaster, 0xb6); /* D/A, autoinit */
+ sbcmd(blaster, 0xb6); /* D/A, autoinit */
- sbcmd(blaster, 0x30); /* stereo, signed 16 bit */
+ sbcmd(blaster, 0x30); /* stereo, signed 16 bit */
count = (Blocksize>>1) - 1;
sbcmd(blaster, count);
@@ -420,7 +340,7 @@
int i;
outb(blaster->reset, 3);
- delay(1); /* >3 υs */
+ delay(1); /* >3 υs */
outb(blaster->reset, 0);
delay(1);
@@ -430,7 +350,7 @@
return 1;
}
- if(sbcmd(blaster, 0xC6)){ /* extended mode */
+ if(sbcmd(blaster, 0xC6)){ /* extended mode */
print("#A%d: barf 3\n", ctlrno);
return 1;
}
@@ -457,15 +377,11 @@
/*
* Set the speed.
*/
- if(0)
- speed = ctlr->livol[Vspeed];
- else
- speed = ctlr->lovol[Vspeed];
+ speed = ctlr->lvol[Vspeed];
if(speed < 4000)
speed = 4000;
else if(speed > 48000)
speed = 48000;
-
if(speed > 22000)
x = 0x80|(256-(795500+speed/2)/speed);
else
@@ -477,15 +393,15 @@
ess1688w(blaster, 0xA2, x & 0xFF);
if(0)
- ess1688w(blaster, 0xB8, 0x0E); /* A/D, autoinit */
+ ess1688w(blaster, 0xB8, 0x0E); /* A/D, autoinit */
else
- ess1688w(blaster, 0xB8, 0x04); /* D/A, autoinit */
+ ess1688w(blaster, 0xB8, 0x04); /* D/A, autoinit */
x = ess1688r(blaster, 0xA8) & ~0x03;
- ess1688w(blaster, 0xA8, x|0x01); /* 2 channels */
- ess1688w(blaster, 0xB9, 2); /* demand mode, 4 bytes per request */
+ ess1688w(blaster, 0xA8, x|0x01); /* 2 channels */
+ ess1688w(blaster, 0xB9, 2); /* demand mode, 4 bytes per request */
if(1)
- ess1688w(blaster, 0xB6, 0); /* for output */
+ ess1688w(blaster, 0xB6, 0); /* for output */
ess1688w(blaster, 0xB7, 0x71);
ess1688w(blaster, 0xB7, 0xBC);
@@ -496,7 +412,7 @@
ess1688w(blaster, 0xB2, x|0x50);
if(1)
- sbcmd(blaster, 0xD1); /* speaker on */
+ sbcmd(blaster, 0xD1); /* speaker on */
count = -Blocksize;
ess1688w(blaster, 0xA4, count & 0xFF);
@@ -571,19 +487,6 @@
iunlock(&ctlr->blaster);
}
-static void
-resetlevel(Ctlr *ctlr)
-{
- int i;
-
- for(i=0; volumes[i].name; i++) {
- ctlr->lovol[i] = volumes[i].ilval;
- ctlr->rovol[i] = volumes[i].irval;
- ctlr->livol[i] = volumes[i].ilval;
- ctlr->rivol[i] = volumes[i].irval;
- }
-}
-
static long
audiobuffered(Audio *adev)
{
@@ -591,17 +494,15 @@
}
static long
-audiostatus(Audio *adev, void *a, long n, vlong off)
+audiostatus(Audio *adev, void *a, long n, vlong)
{
- char buf[300];
- Ctlr *ctlr;
+ Ctlr *ctlr = adev->ctlr;
- ctlr = adev->ctlr;
- snprint(buf, sizeof(buf),
- "buffered %.4lx/%.4lx offset %10lud time %19lld\n",
- buffered(&ctlr->ring), available(&ctlr->ring),
+ return snprint((char*)a, n,
+ "bufsize %6lud buffered %6ld "
+ "offset %10lud time %19lld\n",
+ ctlr->ring.nbuf, buffered(&ctlr->ring),
ctlr->totcount, ctlr->tottime);
- return readstr(off, a, n, buf);
}
static int
@@ -626,7 +527,6 @@
uchar *p, *e;
Ctlr *ctlr;
Ring *ring;
- long m;
p = vp;
e = p + n;
@@ -638,17 +538,15 @@
}
ring = &ctlr->ring;
while(p < e) {
- if((m = writering(ring, p, e - p)) <= 0){
+ if((n = writering(ring, p, e - p)) <= 0){
if(!ctlr->active && ring->ri == 0)
ctlr->blaster.startdma(ctlr);
- if(!ctlr->active){
+ if(!ctlr->active)
setempty(ctlr);
- continue;
- }
- sleep(&ctlr->vous, anybuf, ctlr);
- continue;
+ else
+ sleep(&ctlr->vous, anybuf, ctlr);
}
- p += m;
+ p += n;
}
poperror();
qunlock(ctlr);
@@ -673,6 +571,49 @@
qunlock(ctlr);
}
+static long
+audiovolread(Audio *adev, void *a, long n, vlong)
+{
+ return genaudiovolread(adev, a, n, 0, voltab, mxgetvol, 0);
+}
+
+static long
+audiovolwrite(Audio *adev, void *a, long n, vlong)
+{
+ Blaster *blaster;
+ Ctlr *ctlr;
+ int source;
+
+ ctlr = adev->ctlr;
+ blaster = &ctlr->blaster;
+
+ n = genaudiovolwrite(adev, a, n, 0, voltab, mxsetvol, 0);
+
+ source = 0;
+ if(ctlr->lvol[Vsynth])
+ source |= 1<<6;
+ if(ctlr->rvol[Vsynth])
+ source |= 1<<5;
+ if(ctlr->lvol[Vaudio])
+ source |= 1<<4;
+ if(ctlr->rvol[Vaudio])
+ source |= 1<<3;
+ if(ctlr->lvol[Vcd])
+ source |= 1<<2;
+ if(ctlr->rvol[Vcd])
+ source |= 1<<1;
+ if(ctlr->lvol[Vmic])
+ source |= 1<<0;
+
+ ilock(blaster);
+ mxcmd(blaster, 0x3c, source); /* output switch */
+ mxcmd(blaster, 0x3d, source); /* input left switch */
+ mxcmd(blaster, 0x3e, source); /* input right switch */
+ iunlock(blaster);
+
+ return n;
+}
+
static int
ess1688(ISAConf* sbconf, Blaster *blaster, int ctlrno)
{
@@ -685,7 +626,8 @@
major = sbread(blaster);
minor = sbread(blaster);
if(major != 0x68 || minor != 0x8B){
- print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n", ctlrno, major, minor);
+ print("#A%d: model %#.2x %#.2x; not ESS1688 compatible\n",
+ ctlrno, major, minor);
return -1;
}
@@ -763,12 +705,14 @@
}
if(ioalloc(sbconf.port, 0x10, 0, "audio") < 0){
- print("#A%d: cannot ioalloc range %lux+0x10\n", adev->ctlrno, sbconf.port);
+ print("#A%d: cannot ioalloc range %lux+0x10\n",
+ adev->ctlrno, sbconf.port);
return -1;
}
if(ioalloc(sbconf.port+0x100, 1, 0, "audio.mpu401") < 0){
iofree(sbconf.port);
- print("#A%d: cannot ioalloc range %lux+0x01\n", adev->ctlrno, sbconf.port+0x100);
+ print("#A%d: cannot ioalloc range %lux+0x01\n",
+ adev->ctlrno, sbconf.port+0x100);
return -1;
}
@@ -792,8 +736,6 @@
blaster->startdma = sb16startdma;
blaster->intr = sb16intr;
- resetlevel(ctlr);
-
outb(blaster->reset, 1);
delay(1); /* >3 υs */
outb(blaster->reset, 0);
@@ -802,6 +744,7 @@
i = sbread(blaster);
if(i != 0xaa) {
print("#A%d: no response #%.2x\n", adev->ctlrno, i);
+Errout:
iofree(sbconf.port);
iofree(sbconf.port+0x100);
free(ctlr);
@@ -813,12 +756,11 @@
ctlr->minor = sbread(blaster);
if(ctlr->major != 4) {
- if(ctlr->major != 3 || ctlr->minor != 1 || ess1688(&sbconf, blaster, adev->ctlrno)){
+ if(ctlr->major != 3 || ctlr->minor != 1 ||
+ ess1688(&sbconf, blaster, adev->ctlrno)){
print("#A%d: model %#.2x %#.2x; not SB 16 compatible\n",
adev->ctlrno, ctlr->major, ctlr->minor);
- iofree(sbconf.port);
- iofree(sbconf.port+0x100);
- return -1;
+ goto Errout;
}
ctlr->major = 4;
}
@@ -827,8 +769,15 @@
* initialize the mixer
*/
mxcmd(blaster, 0x00, 0); /* Reset mixer */
- mxvolume(ctlr);
+ for(i=0; i<Nvol; i++){
+ int a[2];
+
+ a[0] = 0;
+ a[1] = 0;
+ mxsetvol(adev, i, a);
+ }
+
/* set irq */
for(i=0; i<nelem(irq); i++){
if(sbconf.irq == irq[i]){
@@ -857,11 +806,10 @@
break;
}
}
- if(blaster->dma<5){
- blaster->dma = 7;
- continue;
- }
- break;
+ if(blaster->dma>=5)
+ break;
+
+ blaster->dma = 7;
}
print("#A%d: %s port 0x%04lux irq %d dma %d\n", adev->ctlrno, sbconf.type,
@@ -868,21 +816,22 @@
sbconf.port, sbconf.irq, blaster->dma);
ctlr->ring.nbuf = Blocks*Blocksize;
- if(dmainit(blaster->dma, ctlr->ring.nbuf)){
- free(ctlr);
- return -1;
- }
+ if(dmainit(blaster->dma, ctlr->ring.nbuf))
+ goto Errout;
ctlr->ring.buf = dmabva(blaster->dma);
+ print("#A%d: %s dma buffer %p-%p\n", adev->ctlrno, sbconf.type,
+ ctlr->ring.buf, ctlr->ring.buf+ctlr->ring.nbuf);
- intrenable(sbconf.irq, audiointr, adev, BUSUNKNOWN, sbconf.type);
-
setempty(ctlr);
- mxvolume(ctlr);
adev->write = audiowrite;
adev->close = audioclose;
+ adev->volread = audiovolread;
+ adev->volwrite = audiovolwrite;
adev->status = audiostatus;
adev->buffered = audiobuffered;
+
+ intrenable(sbconf.irq, audiointr, adev, BUSUNKNOWN, sbconf.type);
return 0;
}
--- /dev/null
+++ b/sys/src/9/port/audioif.h
@@ -1,0 +1,50 @@
+typedef struct Audio Audio;
+typedef struct Volume Volume;
+
+struct Audio
+{
+ char *name;
+
+ void *ctlr;
+ void *mixer;
+
+ long (*read)(Audio *, void *, long, vlong);
+ long (*write)(Audio *, void *, long, vlong);
+ void (*close)(Audio *);
+
+ long (*volread)(Audio *, void *, long, vlong);
+ long (*volwrite)(Audio *, void *, long, vlong);
+
+ long (*ctl)(Audio *, void *, long, vlong);
+ long (*status)(Audio *, void *, long, vlong);
+ long (*buffered)(Audio *);
+
+ int ctlrno;
+ Audio *next;
+};
+
+enum {
+ Left,
+ Right,
+ Stereo,
+ Absolute,
+};
+
+#define Mono Left
+
+struct Volume
+{
+ char *name;
+ int reg;
+ int range;
+ int type;
+ int cap;
+};
+
+extern void addaudiocard(char *, int (*)(Audio *));
+extern long genaudiovolread(Audio *adev, void *a, long n, vlong off,
+ Volume *vol, int (*volget)(Audio *, int, int *),
+ ulong caps);
+extern long genaudiovolwrite(Audio *adev, void *a, long n, vlong off,
+ Volume *vol, int (*volset)(Audio *, int, int *),
+ ulong caps);
--- a/sys/src/9/port/devaudio.c
+++ b/sys/src/9/port/devaudio.c
@@ -5,13 +5,28 @@
#include "fns.h"
#include "io.h"
#include "../port/error.h"
+#include "../port/audioif.h"
typedef struct Audioprobe Audioprobe;
-struct Audioprobe {
+typedef struct Audiochan Audiochan;
+
+struct Audioprobe
+{
char *name;
int (*probe)(Audio*);
};
+struct Audiochan
+{
+ QLock;
+
+ Chan *owner;
+ Audio *adev;
+
+ char *data;
+ char buf[1024+1];
+};
+
enum {
Qdir = 0,
Qaudio,
@@ -18,14 +33,8 @@
Qaudioctl,
Qaudiostatus,
Qvolume,
-
- Maxaudioprobes = 8,
};
-static int naudioprobes;
-static Audioprobe audioprobes[Maxaudioprobes];
-static Audio *audiodevs;
-
static Dirtab audiodir[] = {
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"audio", {Qaudio}, 0, 0666,
@@ -34,10 +43,22 @@
"volume", {Qvolume}, 0, 0666,
};
+
+static int naudioprobes;
+static Audioprobe audioprobes[16];
+static Audio *audiodevs;
+
+static char Evolume[] = "illegal volume specifier";
+
+
void
addaudiocard(char *name, int (*probefn)(Audio *))
{
Audioprobe *probe;
+
+ if(naudioprobes >= nelem(audioprobes))
+ return;
+
probe = &audioprobes[naudioprobes++];
probe->name = name;
probe->probe = probefn;
@@ -73,42 +94,98 @@
*pp = nil;
}
+static Audiochan*
+audioclone(Chan *c, Audio *adev)
+{
+ Audiochan *ac;
+
+ ac = malloc(sizeof(Audiochan));
+ if(ac == nil){
+ cclose(c);
+ return nil;
+ }
+
+ c->aux = ac;
+ ac->owner = c;
+ ac->adev = adev;
+ ac->data = nil;
+
+ return ac;
+}
+
static Chan*
audioattach(char *spec)
{
+ static int first = 1;
+ Audiochan *ac;
+ Audio *adev;
Chan *c;
- Audio *p;
int i;
+
if(spec != nil && *spec != '\0')
i = strtol(spec, 0, 10);
else
i = 0;
- for(p = audiodevs; p; p = p->next)
+ for(adev = audiodevs; adev; adev = adev->next)
if(i-- == 0)
break;
- if(p == nil)
+ if(adev == nil)
error(Enodev);
+
c = devattach('A', spec);
c->qid.path = Qdir;
- c->aux = p;
- if(p->attach)
- p->attach(p);
+
+ if((ac = audioclone(c, adev)) == nil)
+ error(Enomem);
+
+ if(first && adev->volwrite){
+ first = 0;
+
+ strcpy(ac->buf, "speed 44100");
+ if(!waserror()){
+ adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
+ poperror();
+ }
+ strcpy(ac->buf, "master 100");
+ if(!waserror()){
+ adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
+ poperror();
+ }
+ strcpy(ac->buf, "audio 100");
+ if(!waserror()){
+ adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
+ poperror();
+ }
+ strcpy(ac->buf, "head 100");
+ if(!waserror()){
+ adev->volwrite(adev, ac->buf, strlen(ac->buf), 0);
+ poperror();
+ }
+ }
+
return c;
}
+static Chan*
+audioopen(Chan *c, int omode)
+{
+ return devopen(c, omode, audiodir, nelem(audiodir), devgen);
+}
+
static long
audioread(Chan *c, void *a, long n, vlong off)
{
+ Audiochan *ac;
Audio *adev;
long (*fn)(Audio *, void *, long, vlong);
- adev = c->aux;
+
+ ac = c->aux;
+ adev = ac->adev;
+
+ fn = nil;
switch((ulong)c->qid.path){
- default:
- error("audio bugger (rd)");
- case Qaudioctl:
- fn = adev->ctl;
- break;
case Qdir:
+ /* BUG: race */
if(adev->buffered)
audiodir[Qaudio].length = adev->buffered(adev);
return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
@@ -115,6 +192,9 @@
case Qaudio:
fn = adev->read;
break;
+ case Qaudioctl:
+ fn = adev->ctl;
+ break;
case Qaudiostatus:
fn = adev->status;
break;
@@ -123,7 +203,34 @@
break;
}
if(fn == nil)
- error("not implemented");
+ error(Egreg);
+
+ switch((ulong)c->qid.path){
+ case Qaudioctl:
+ case Qaudiostatus:
+ case Qvolume:
+ qlock(ac);
+ if(waserror()){
+ qunlock(ac);
+ nexterror();
+ }
+ /* generate the text on first read */
+ if(ac->data == nil || off == 0){
+ long l;
+
+ ac->data = nil;
+ l = fn(adev, ac->buf, sizeof(ac->buf)-1, 0);
+ if(l < 0)
+ l = 0;
+ ac->buf[l] = 0;
+ ac->data = ac->buf;
+ }
+ /* then serve all requests from buffer */
+ n = readstr(off, a, n, ac->data);
+ qunlock(ac);
+ poperror();
+ return n;
+ }
return fn(adev, a, n, off);
}
@@ -130,12 +237,15 @@
static long
audiowrite(Chan *c, void *a, long n, vlong off)
{
+ Audiochan *ac;
Audio *adev;
long (*fn)(Audio *, void *, long, vlong);
- adev = c->aux;
+
+ ac = c->aux;
+ adev = ac->adev;
+
+ fn = nil;
switch((ulong)c->qid.path){
- default:
- error("audio bugger (wr)");
case Qaudio:
fn = adev->write;
break;
@@ -147,7 +257,28 @@
break;
}
if(fn == nil)
- error("not implemented");
+ error(Egreg);
+
+ switch((ulong)c->qid.path){
+ case Qaudioctl:
+ case Qvolume:
+ if(n >= sizeof(ac->buf))
+ error(Etoobig);
+
+ /* copy data to audiochan buffer so it can be modified */
+ qlock(ac);
+ if(waserror()){
+ qunlock(ac);
+ nexterror();
+ }
+ ac->data = nil;
+ memmove(ac->buf, a, n);
+ ac->buf[n] = 0;
+ n = fn(adev, ac->buf, n, 0);
+ qunlock(ac);
+ poperror();
+ return n;
+ }
return fn(adev, a, n, off);
}
@@ -154,16 +285,19 @@
static void
audioclose(Chan *c)
{
+ Audiochan *ac;
Audio *adev;
- adev = c->aux;
- switch((ulong)c->qid.path){
- default:
- return;
- case Qaudio:
- if(adev->close == nil)
- return;
- adev->close(adev);
- return;
+
+ ac = c->aux;
+ adev = ac->adev;
+ if(c->qid.path == Qaudio && (c->flag & COPEN))
+ if(adev->close)
+ adev->close(adev);
+
+ if(ac->owner == c){
+ ac->owner = nil;
+ c->aux = nil;
+ free(ac);
}
}
@@ -170,23 +304,148 @@
static Walkqid*
audiowalk(Chan *c, Chan *nc, char **name, int nname)
{
- return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
+ Audiochan *ac;
+ Audio *adev;
+ Walkqid *wq;
+
+ ac = c->aux;
+ adev = ac->adev;
+ wq = devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
+ if(wq && wq->clone){
+ if(audioclone(wq->clone, adev) == nil){
+ free(wq);
+ wq = nil;
+ }
+ }
+ return wq;
}
static int
audiostat(Chan *c, uchar *dp, int n)
{
+ Audiochan *ac;
Audio *adev;
- adev = c->aux;
+
+ ac = c->aux;
+ adev = ac->adev;
+
+ /* BUG: race */
if(adev->buffered && (ulong)c->qid.path == Qaudio)
audiodir[Qaudio].length = adev->buffered(adev);
+
return devstat(c, dp, n, audiodir, nelem(audiodir), devgen);
}
-static Chan*
-audioopen(Chan *c, int omode)
+/*
+ * audioread() made sure the buffer is big enougth so a full volume
+ * table can be serialized in one pass.
+ */
+long
+genaudiovolread(Audio *adev, void *a, long n, vlong,
+ Volume *vol, int (*volget)(Audio *, int, int *), ulong caps)
{
- return devopen(c, omode, audiodir, nelem(audiodir), devgen);
+ int i, j, v[2];
+ char *p, *e;
+
+ p = a;
+ e = p + n;
+ for(i = 0; vol[i].name != 0; ++i){
+ if(vol[i].cap && (vol[i].cap & caps) == 0)
+ continue;
+ v[0] = 0;
+ v[1] = 0;
+ if((*volget)(adev, i, v) != 0)
+ continue;
+ if(vol[i].type == Absolute)
+ p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
+ else {
+ for(j=0; j<2; j++){
+ if(v[j] < 0)
+ v[j] = 0;
+ if(v[j] > vol[i].range)
+ v[j] = vol[i].range;
+ v[j] = (v[j]*100)/vol[i].range;
+ }
+ switch(vol[i].type){
+ case Left:
+ p += snprint(p, e - p, "%s %d\n", vol[i].name, v[0]);
+ break;
+ case Right:
+ p += snprint(p, e - p, "%s %d\n", vol[i].name, v[1]);
+ break;
+ case Stereo:
+ p += snprint(p, e - p, "%s %d %d\n", vol[i].name, v[0], v[1]);
+ break;
+ }
+ }
+ }
+
+ return p - (char*)a;
+}
+
+/*
+ * genaudiovolwrite modifies the buffer that gets passed to it. this
+ * is ok as long as it is called from inside Audio.volwrite() because
+ * audiowrite() copies the data to Audiochan.buf[] and inserts a
+ * terminating \0 byte before calling Audio.volwrite().
+ */
+long
+genaudiovolwrite(Audio *adev, void *a, long n, vlong,
+ Volume *vol, int (*volset)(Audio *, int, int *), ulong caps)
+{
+ int ntok, i, j, v[2];
+ char *p, *e, *x, *tok[4];
+
+ p = a;
+ e = p + n;
+
+ for(;p < e; p = x){
+ if(x = strchr(p, '\n'))
+ *x++ = 0;
+ else
+ x = e;
+ ntok = tokenize(p, tok, 4);
+ if(ntok <= 0)
+ continue;
+ if(ntok == 1){
+ tok[1] = tok[0];
+ tok[0] = "master";
+ ntok = 2;
+ }
+ for(i = 0; vol[i].name != 0; i++){
+ if(vol[i].cap && (vol[i].cap & caps) == 0)
+ continue;
+ if(cistrcmp(vol[i].name, tok[0]))
+ continue;
+
+ if((ntok>2) && (!cistrcmp(tok[1], "out") || !cistrcmp(tok[1], "in")))
+ memmove(tok+1, tok+2, --ntok);
+
+ v[0] = 0;
+ v[1] = 0;
+ if(ntok > 1)
+ v[0] = v[1] = atoi(tok[1]);
+ if(ntok > 2)
+ v[1] = atoi(tok[2]);
+ if(vol[i].type == Absolute)
+ (*volset)(adev, i, v);
+ else {
+ for(j=0; j<2; j++){
+ v[j] = (50+(v[j]*vol[i].range))/100;
+ if(v[j] < 0)
+ v[j] = 0;
+ if(v[j] > vol[i].range)
+ v[j] = vol[i].range;
+ }
+ (*volset)(adev, i, v);
+ }
+ break;
+ }
+ if(vol[i].name == nil)
+ error(Evolume);
+ }
+
+ return n;
}
Dev audiodevtab = {
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -1,5 +1,4 @@
typedef struct Alarms Alarms;
-typedef struct Audio Audio;
typedef struct Block Block;
typedef struct Chan Chan;
typedef struct Cmdbuf Cmdbuf;
@@ -918,23 +917,6 @@
};
extern Uart* consuart;
-
-struct Audio {
- Audio *next;
- char *name;
- void *ctlr;
- void *mixer;
- void (*attach)(Audio *);
- long (*read)(Audio *, void *, long, vlong);
- long (*write)(Audio *, void *, long, vlong);
- long (*volread)(Audio *, void *, long, vlong);
- long (*volwrite)(Audio *, void *, long, vlong);
- void (*close)(Audio *);
- long (*ctl)(Audio *, void *, long, vlong);
- long (*status)(Audio *, void *, long, vlong);
- long (*buffered)(Audio *);
- int ctlrno;
-};
/*
* performance timers, all units in perfticks
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -4,7 +4,6 @@
int addphysseg(Physseg*);
void addbootfile(char*, uchar*, ulong);
void addwatchdog(Watchdog*);
-void addaudiocard(char *, int (*)(Audio *));
Block* adjustblock(Block*, int);
void alarmkproc(void*);
Block* allocb(int);