1*499069deSDavid du Colombier #include "u.h" 2*499069deSDavid du Colombier #include "lib.h" 3*499069deSDavid du Colombier #include "dat.h" 4*499069deSDavid du Colombier #include "fns.h" 5*499069deSDavid du Colombier #include "error.h" 6*499069deSDavid du Colombier #include "devaudio.h" 7*499069deSDavid du Colombier 8*499069deSDavid du Colombier enum 9*499069deSDavid du Colombier { 10*499069deSDavid du Colombier Qdir = 0, 11*499069deSDavid du Colombier Qaudio, 12*499069deSDavid du Colombier Qvolume, 13*499069deSDavid du Colombier 14*499069deSDavid du Colombier Aclosed = 0, 15*499069deSDavid du Colombier Aread, 16*499069deSDavid du Colombier Awrite, 17*499069deSDavid du Colombier 18*499069deSDavid du Colombier Speed = 44100, 19*499069deSDavid du Colombier Ncmd = 50, /* max volume command words */ 20*499069deSDavid du Colombier }; 21*499069deSDavid du Colombier 22*499069deSDavid du Colombier Dirtab 23*499069deSDavid du Colombier audiodir[] = 24*499069deSDavid du Colombier { 25*499069deSDavid du Colombier ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 26*499069deSDavid du Colombier "audio", {Qaudio}, 0, 0666, 27*499069deSDavid du Colombier "volume", {Qvolume}, 0, 0666, 28*499069deSDavid du Colombier }; 29*499069deSDavid du Colombier 30*499069deSDavid du Colombier static struct 31*499069deSDavid du Colombier { 32*499069deSDavid du Colombier QLock lk; 33*499069deSDavid du Colombier Rendez vous; 34*499069deSDavid du Colombier int amode; /* Aclosed/Aread/Awrite for /audio */ 35*499069deSDavid du Colombier } audio; 36*499069deSDavid du Colombier 37*499069deSDavid du Colombier #define aqlock(a) qlock(&(a)->lk) 38*499069deSDavid du Colombier #define aqunlock(a) qunlock(&(a)->lk) 39*499069deSDavid du Colombier 40*499069deSDavid du Colombier static struct 41*499069deSDavid du Colombier { 42*499069deSDavid du Colombier char* name; 43*499069deSDavid du Colombier int flag; 44*499069deSDavid du Colombier int ilval; /* initial values */ 45*499069deSDavid du Colombier int irval; 46*499069deSDavid du Colombier } volumes[] = 47*499069deSDavid du Colombier { 48*499069deSDavid du Colombier [Vaudio] "audio", Fout, 50, 50, 49*499069deSDavid du Colombier [Vsynth] "synth", Fin|Fout, 0, 0, 50*499069deSDavid du Colombier [Vcd] "cd", Fin|Fout, 0, 0, 51*499069deSDavid du Colombier [Vline] "line", Fin|Fout, 0, 0, 52*499069deSDavid du Colombier [Vmic] "mic", Fin|Fout|Fmono, 0, 0, 53*499069deSDavid du Colombier [Vspeaker] "speaker", Fout|Fmono, 0, 0, 54*499069deSDavid du Colombier 55*499069deSDavid du Colombier [Vtreb] "treb", Fout, 50, 50, 56*499069deSDavid du Colombier [Vbass] "bass", Fout, 50, 50, 57*499069deSDavid du Colombier 58*499069deSDavid du Colombier [Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed, 59*499069deSDavid du Colombier 0 60*499069deSDavid du Colombier }; 61*499069deSDavid du Colombier 62*499069deSDavid du Colombier static char Emode[] = "illegal open mode"; 63*499069deSDavid du Colombier static char Evolume[] = "illegal volume specifier"; 64*499069deSDavid du Colombier 65*499069deSDavid du Colombier static void 66*499069deSDavid du Colombier resetlevel(void) 67*499069deSDavid du Colombier { 68*499069deSDavid du Colombier int i; 69*499069deSDavid du Colombier 70*499069deSDavid du Colombier for(i=0; volumes[i].name; i++) 71*499069deSDavid du Colombier audiodevsetvol(i, volumes[i].ilval, volumes[i].irval); 72*499069deSDavid du Colombier } 73*499069deSDavid du Colombier 74*499069deSDavid du Colombier static void 75*499069deSDavid du Colombier audioinit(void) 76*499069deSDavid du Colombier { 77*499069deSDavid du Colombier } 78*499069deSDavid du Colombier 79*499069deSDavid du Colombier static Chan* 80*499069deSDavid du Colombier audioattach(char *param) 81*499069deSDavid du Colombier { 82*499069deSDavid du Colombier return devattach('A', param); 83*499069deSDavid du Colombier } 84*499069deSDavid du Colombier 85*499069deSDavid du Colombier static Walkqid* 86*499069deSDavid du Colombier audiowalk(Chan *c, Chan *nc, char **name, int nname) 87*499069deSDavid du Colombier { 88*499069deSDavid du Colombier return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen); 89*499069deSDavid du Colombier } 90*499069deSDavid du Colombier 91*499069deSDavid du Colombier static int 92*499069deSDavid du Colombier audiostat(Chan *c, uchar *db, int n) 93*499069deSDavid du Colombier { 94*499069deSDavid du Colombier return devstat(c, db, n, audiodir, nelem(audiodir), devgen); 95*499069deSDavid du Colombier } 96*499069deSDavid du Colombier 97*499069deSDavid du Colombier static Chan* 98*499069deSDavid du Colombier audioopen(Chan *c, int omode) 99*499069deSDavid du Colombier { 100*499069deSDavid du Colombier int amode; 101*499069deSDavid du Colombier 102*499069deSDavid du Colombier switch((ulong)c->qid.path) { 103*499069deSDavid du Colombier default: 104*499069deSDavid du Colombier error(Eperm); 105*499069deSDavid du Colombier break; 106*499069deSDavid du Colombier 107*499069deSDavid du Colombier case Qvolume: 108*499069deSDavid du Colombier case Qdir: 109*499069deSDavid du Colombier break; 110*499069deSDavid du Colombier 111*499069deSDavid du Colombier case Qaudio: 112*499069deSDavid du Colombier amode = Awrite; 113*499069deSDavid du Colombier if((omode&7) == OREAD) 114*499069deSDavid du Colombier amode = Aread; 115*499069deSDavid du Colombier aqlock(&audio); 116*499069deSDavid du Colombier if(waserror()){ 117*499069deSDavid du Colombier aqunlock(&audio); 118*499069deSDavid du Colombier nexterror(); 119*499069deSDavid du Colombier } 120*499069deSDavid du Colombier if(audio.amode != Aclosed) 121*499069deSDavid du Colombier error(Einuse); 122*499069deSDavid du Colombier audiodevopen(); 123*499069deSDavid du Colombier audio.amode = amode; 124*499069deSDavid du Colombier poperror(); 125*499069deSDavid du Colombier aqunlock(&audio); 126*499069deSDavid du Colombier break; 127*499069deSDavid du Colombier } 128*499069deSDavid du Colombier c = devopen(c, omode, audiodir, nelem(audiodir), devgen); 129*499069deSDavid du Colombier c->mode = openmode(omode); 130*499069deSDavid du Colombier c->flag |= COPEN; 131*499069deSDavid du Colombier c->offset = 0; 132*499069deSDavid du Colombier 133*499069deSDavid du Colombier return c; 134*499069deSDavid du Colombier } 135*499069deSDavid du Colombier 136*499069deSDavid du Colombier static void 137*499069deSDavid du Colombier audioclose(Chan *c) 138*499069deSDavid du Colombier { 139*499069deSDavid du Colombier switch((ulong)c->qid.path) { 140*499069deSDavid du Colombier default: 141*499069deSDavid du Colombier error(Eperm); 142*499069deSDavid du Colombier break; 143*499069deSDavid du Colombier 144*499069deSDavid du Colombier case Qdir: 145*499069deSDavid du Colombier case Qvolume: 146*499069deSDavid du Colombier break; 147*499069deSDavid du Colombier 148*499069deSDavid du Colombier case Qaudio: 149*499069deSDavid du Colombier if(c->flag & COPEN) { 150*499069deSDavid du Colombier aqlock(&audio); 151*499069deSDavid du Colombier audiodevclose(); 152*499069deSDavid du Colombier audio.amode = Aclosed; 153*499069deSDavid du Colombier aqunlock(&audio); 154*499069deSDavid du Colombier } 155*499069deSDavid du Colombier break; 156*499069deSDavid du Colombier } 157*499069deSDavid du Colombier } 158*499069deSDavid du Colombier 159*499069deSDavid du Colombier static long 160*499069deSDavid du Colombier audioread(Chan *c, void *v, long n, vlong off) 161*499069deSDavid du Colombier { 162*499069deSDavid du Colombier int liv, riv, lov, rov; 163*499069deSDavid du Colombier long m; 164*499069deSDavid du Colombier char buf[300]; 165*499069deSDavid du Colombier int j; 166*499069deSDavid du Colombier ulong offset = off; 167*499069deSDavid du Colombier char *a; 168*499069deSDavid du Colombier 169*499069deSDavid du Colombier a = v; 170*499069deSDavid du Colombier switch((ulong)c->qid.path) { 171*499069deSDavid du Colombier default: 172*499069deSDavid du Colombier error(Eperm); 173*499069deSDavid du Colombier break; 174*499069deSDavid du Colombier 175*499069deSDavid du Colombier case Qdir: 176*499069deSDavid du Colombier return devdirread(c, a, n, audiodir, nelem(audiodir), devgen); 177*499069deSDavid du Colombier 178*499069deSDavid du Colombier case Qaudio: 179*499069deSDavid du Colombier if(audio.amode != Aread) 180*499069deSDavid du Colombier error(Emode); 181*499069deSDavid du Colombier aqlock(&audio); 182*499069deSDavid du Colombier if(waserror()){ 183*499069deSDavid du Colombier aqunlock(&audio); 184*499069deSDavid du Colombier nexterror(); 185*499069deSDavid du Colombier } 186*499069deSDavid du Colombier n = audiodevread(v, n); 187*499069deSDavid du Colombier poperror(); 188*499069deSDavid du Colombier aqunlock(&audio); 189*499069deSDavid du Colombier break; 190*499069deSDavid du Colombier 191*499069deSDavid du Colombier case Qvolume: 192*499069deSDavid du Colombier j = 0; 193*499069deSDavid du Colombier buf[0] = 0; 194*499069deSDavid du Colombier for(m=0; volumes[m].name; m++){ 195*499069deSDavid du Colombier audiodevgetvol(m, &lov, &rov); 196*499069deSDavid du Colombier liv = lov; 197*499069deSDavid du Colombier riv = rov; 198*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name); 199*499069deSDavid du Colombier if((volumes[m].flag & Fmono) || (liv==riv && lov==rov)){ 200*499069deSDavid du Colombier if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov) 201*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, " %d", liv); 202*499069deSDavid du Colombier else{ 203*499069deSDavid du Colombier if(volumes[m].flag & Fin) 204*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, 205*499069deSDavid du Colombier " in %d", liv); 206*499069deSDavid du Colombier if(volumes[m].flag & Fout) 207*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, 208*499069deSDavid du Colombier " out %d", lov); 209*499069deSDavid du Colombier } 210*499069deSDavid du Colombier }else{ 211*499069deSDavid du Colombier if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && 212*499069deSDavid du Colombier liv==lov && riv==rov) 213*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, 214*499069deSDavid du Colombier " left %d right %d", 215*499069deSDavid du Colombier liv, riv); 216*499069deSDavid du Colombier else{ 217*499069deSDavid du Colombier if(volumes[m].flag & Fin) 218*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, 219*499069deSDavid du Colombier " in left %d right %d", 220*499069deSDavid du Colombier liv, riv); 221*499069deSDavid du Colombier if(volumes[m].flag & Fout) 222*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, 223*499069deSDavid du Colombier " out left %d right %d", 224*499069deSDavid du Colombier lov, rov); 225*499069deSDavid du Colombier } 226*499069deSDavid du Colombier } 227*499069deSDavid du Colombier j += snprint(buf+j, sizeof(buf)-j, "\n"); 228*499069deSDavid du Colombier } 229*499069deSDavid du Colombier return readstr(offset, a, n, buf); 230*499069deSDavid du Colombier } 231*499069deSDavid du Colombier return n; 232*499069deSDavid du Colombier } 233*499069deSDavid du Colombier 234*499069deSDavid du Colombier static long 235*499069deSDavid du Colombier audiowrite(Chan *c, void *vp, long n, vlong off) 236*499069deSDavid du Colombier { 237*499069deSDavid du Colombier long m; 238*499069deSDavid du Colombier int i, v, left, right, in, out; 239*499069deSDavid du Colombier Cmdbuf *cb; 240*499069deSDavid du Colombier char *a; 241*499069deSDavid du Colombier 242*499069deSDavid du Colombier USED(off); 243*499069deSDavid du Colombier a = vp; 244*499069deSDavid du Colombier switch((ulong)c->qid.path) { 245*499069deSDavid du Colombier default: 246*499069deSDavid du Colombier error(Eperm); 247*499069deSDavid du Colombier break; 248*499069deSDavid du Colombier 249*499069deSDavid du Colombier case Qvolume: 250*499069deSDavid du Colombier v = Vaudio; 251*499069deSDavid du Colombier left = 1; 252*499069deSDavid du Colombier right = 1; 253*499069deSDavid du Colombier in = 1; 254*499069deSDavid du Colombier out = 1; 255*499069deSDavid du Colombier cb = parsecmd(vp, n); 256*499069deSDavid du Colombier if(waserror()){ 257*499069deSDavid du Colombier free(cb); 258*499069deSDavid du Colombier nexterror(); 259*499069deSDavid du Colombier } 260*499069deSDavid du Colombier 261*499069deSDavid du Colombier for(i = 0; i < cb->nf; i++){ 262*499069deSDavid du Colombier /* 263*499069deSDavid du Colombier * a number is volume 264*499069deSDavid du Colombier */ 265*499069deSDavid du Colombier if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') { 266*499069deSDavid du Colombier m = strtoul(cb->f[i], 0, 10); 267*499069deSDavid du Colombier if(!out) 268*499069deSDavid du Colombier goto cont0; 269*499069deSDavid du Colombier if(left && right) 270*499069deSDavid du Colombier audiodevsetvol(v, m, m); 271*499069deSDavid du Colombier else if(left) 272*499069deSDavid du Colombier audiodevsetvol(v, m, -1); 273*499069deSDavid du Colombier else if(right) 274*499069deSDavid du Colombier audiodevsetvol(v, -1, m); 275*499069deSDavid du Colombier goto cont0; 276*499069deSDavid du Colombier } 277*499069deSDavid du Colombier 278*499069deSDavid du Colombier for(m=0; volumes[m].name; m++) { 279*499069deSDavid du Colombier if(strcmp(cb->f[i], volumes[m].name) == 0) { 280*499069deSDavid du Colombier v = m; 281*499069deSDavid du Colombier in = 1; 282*499069deSDavid du Colombier out = 1; 283*499069deSDavid du Colombier left = 1; 284*499069deSDavid du Colombier right = 1; 285*499069deSDavid du Colombier goto cont0; 286*499069deSDavid du Colombier } 287*499069deSDavid du Colombier } 288*499069deSDavid du Colombier 289*499069deSDavid du Colombier if(strcmp(cb->f[i], "reset") == 0) { 290*499069deSDavid du Colombier resetlevel(); 291*499069deSDavid du Colombier goto cont0; 292*499069deSDavid du Colombier } 293*499069deSDavid du Colombier if(strcmp(cb->f[i], "in") == 0) { 294*499069deSDavid du Colombier in = 1; 295*499069deSDavid du Colombier out = 0; 296*499069deSDavid du Colombier goto cont0; 297*499069deSDavid du Colombier } 298*499069deSDavid du Colombier if(strcmp(cb->f[i], "out") == 0) { 299*499069deSDavid du Colombier in = 0; 300*499069deSDavid du Colombier out = 1; 301*499069deSDavid du Colombier goto cont0; 302*499069deSDavid du Colombier } 303*499069deSDavid du Colombier if(strcmp(cb->f[i], "left") == 0) { 304*499069deSDavid du Colombier left = 1; 305*499069deSDavid du Colombier right = 0; 306*499069deSDavid du Colombier goto cont0; 307*499069deSDavid du Colombier } 308*499069deSDavid du Colombier if(strcmp(cb->f[i], "right") == 0) { 309*499069deSDavid du Colombier left = 0; 310*499069deSDavid du Colombier right = 1; 311*499069deSDavid du Colombier goto cont0; 312*499069deSDavid du Colombier } 313*499069deSDavid du Colombier error(Evolume); 314*499069deSDavid du Colombier break; 315*499069deSDavid du Colombier cont0:; 316*499069deSDavid du Colombier } 317*499069deSDavid du Colombier free(cb); 318*499069deSDavid du Colombier poperror(); 319*499069deSDavid du Colombier break; 320*499069deSDavid du Colombier 321*499069deSDavid du Colombier case Qaudio: 322*499069deSDavid du Colombier if(audio.amode != Awrite) 323*499069deSDavid du Colombier error(Emode); 324*499069deSDavid du Colombier aqlock(&audio); 325*499069deSDavid du Colombier if(waserror()){ 326*499069deSDavid du Colombier aqunlock(&audio); 327*499069deSDavid du Colombier nexterror(); 328*499069deSDavid du Colombier } 329*499069deSDavid du Colombier n = audiodevwrite(vp, n); 330*499069deSDavid du Colombier poperror(); 331*499069deSDavid du Colombier aqunlock(&audio); 332*499069deSDavid du Colombier break; 333*499069deSDavid du Colombier } 334*499069deSDavid du Colombier return n; 335*499069deSDavid du Colombier } 336*499069deSDavid du Colombier 337*499069deSDavid du Colombier void 338*499069deSDavid du Colombier audioswab(uchar *a, uint n) 339*499069deSDavid du Colombier { 340*499069deSDavid du Colombier ulong *p, *ep, b; 341*499069deSDavid du Colombier 342*499069deSDavid du Colombier p = (ulong*)a; 343*499069deSDavid du Colombier ep = p + (n>>2); 344*499069deSDavid du Colombier while(p < ep) { 345*499069deSDavid du Colombier b = *p; 346*499069deSDavid du Colombier b = (b>>24) | (b<<24) | 347*499069deSDavid du Colombier ((b&0xff0000) >> 8) | 348*499069deSDavid du Colombier ((b&0x00ff00) << 8); 349*499069deSDavid du Colombier *p++ = b; 350*499069deSDavid du Colombier } 351*499069deSDavid du Colombier } 352*499069deSDavid du Colombier 353*499069deSDavid du Colombier Dev audiodevtab = { 354*499069deSDavid du Colombier 'A', 355*499069deSDavid du Colombier "audio", 356*499069deSDavid du Colombier 357*499069deSDavid du Colombier devreset, 358*499069deSDavid du Colombier audioinit, 359*499069deSDavid du Colombier devshutdown, 360*499069deSDavid du Colombier audioattach, 361*499069deSDavid du Colombier audiowalk, 362*499069deSDavid du Colombier audiostat, 363*499069deSDavid du Colombier audioopen, 364*499069deSDavid du Colombier devcreate, 365*499069deSDavid du Colombier audioclose, 366*499069deSDavid du Colombier audioread, 367*499069deSDavid du Colombier devbread, 368*499069deSDavid du Colombier audiowrite, 369*499069deSDavid du Colombier devbwrite, 370*499069deSDavid du Colombier devremove, 371*499069deSDavid du Colombier devwstat, 372*499069deSDavid du Colombier }; 373