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