1 /*
2 * SAC/UDA 1341 Audio driver for the Bitsy
3 *
4 * This code is covered by the Lucent Public Licence 1.02 (http://plan9.bell-labs.com/plan9dist/license.html);
5 * see the file NOTICE in the current directory. Modifications for the Inferno environment by Vita Nuova.
6 *
7 * The Philips UDA 1341 sound chip is accessed through the Serial Audio
8 * Controller (SAC) of the StrongARM SA-1110.
9 *
10 * The code morphs Nicolas Pitre's <nico@cam.org> Linux controller
11 * and Ken's Soundblaster controller.
12 *
13 * The interface should be identical to that of devaudio.c
14 */
15 #include "u.h"
16 #include "../port/lib.h"
17 #include "mem.h"
18 #include "dat.h"
19 #include "fns.h"
20 #include "../port/error.h"
21 #include "io.h"
22
23 static int debug = 0;
24
25 /* UDA 1341 Registers */
26 enum {
27 /* Status0 register */
28 UdaStatusDC = 0, /* 1 bit */
29 UdaStatusIF = 1, /* 3 bits */
30 UdaStatusSC = 4, /* 2 bits */
31 UdaStatusRST = 6, /* 1 bit */
32 };
33
34 enum {
35 /* Status1 register */
36 UdaStatusPC = 0, /* 2 bits */
37 UdaStatusDS = 2, /* 1 bit */
38 UdaStatusPDA = 3, /* 1 bit */
39 UdaStatusPAD = 4, /* 1 bit */
40 UdaStatusIGS = 5, /* 1 bit */
41 UdaStatusOGS = 6, /* 1 bit */
42 };
43
44 /*
45 * UDA1341 L3 address and command types
46 */
47
48 enum {
49 UDA1341_DATA0 = 0,
50 UDA1341_DATA1,
51 UDA1341_STATUS,
52 UDA1341_L3Addr = 0x14,
53 };
54
55 typedef struct AQueue AQueue;
56 typedef struct Buf Buf;
57 typedef struct IOstate IOstate;
58
59 enum
60 {
61 Qdir = 0,
62 Qaudio,
63 Qvolume,
64 Qstatus,
65 Qaudioctl,
66
67 Fmono = 1,
68 Fin = 2,
69 Fout = 4,
70
71 Aclosed = 0,
72 Aread,
73 Awrite,
74
75 Vaudio = 0,
76 Vmic,
77 Vtreb,
78 Vbass,
79 Vspeed,
80 Vfilter,
81 Vinvert,
82 Nvol,
83
84 Bufsize = 4*1024, /* 46 ms each */
85 Nbuf = 32, /* 1.5 seconds total */
86
87 Speed = 44100,
88 Ncmd = 50, /* max volume command words */
89 };
90
91 Dirtab
92 audiodir[] =
93 {
94 ".", {Qdir, 0, QTDIR}, 0, 0555,
95 "audio", {Qaudio}, 0, 0666,
96 "volume", {Qvolume}, 0, 0666,
97 "audioctl", {Qaudioctl}, 0, 0666,
98 "audiostat",{Qstatus}, 0, 0444,
99 };
100
101 struct Buf
102 {
103 uchar* virt;
104 ulong phys;
105 uint nbytes;
106 };
107
108 struct IOstate
109 {
110 QLock;
111 Lock ilock;
112 Rendez vous;
113 Chan *chan; /* chan of open */
114 Dma* dma; /* dma chan, alloc on open, free on close */
115 int bufinit; /* boolean, if buffers allocated */
116 Buf buf[Nbuf]; /* buffers and queues */
117 volatile Buf *current; /* next dma to finish */
118 volatile Buf *next; /* next candidate for dma */
119 volatile Buf *filling; /* buffer being filled */
120 /* just be be cute (and to have defines like linux, a real operating system) */
121 #define emptying filling
122 };
123
124 static struct
125 {
126 QLock;
127 int amode; /* Aclosed/Aread/Awrite for /audio */
128 int intr; /* boolean an interrupt has happened */
129 int rivol[Nvol]; /* right/left input/output volumes */
130 int livol[Nvol];
131 int rovol[Nvol];
132 int lovol[Nvol];
133 uvlong totcount; /* how many bytes processed since open */
134 vlong tottime; /* time at which totcount bytes were processed */
135 int clockout; /* need steady output to provide input clock */
136 IOstate i;
137 IOstate o;
138 } audio;
139
140 static struct
141 {
142 ulong bytes;
143 ulong totaldma;
144 ulong idledma;
145 ulong faildma;
146 ulong samedma;
147 } iostats;
148
149 static struct
150 {
151 char* name;
152 int flag;
153 int ilval; /* initial values */
154 int irval;
155 } volumes[] =
156 {
157 [Vaudio] {"audio", Fout|Fmono, 80, 80},
158 [Vmic] {"mic", Fin|Fmono, 0, 0},
159 [Vtreb] {"treb", Fout|Fmono, 50, 50},
160 [Vbass] {"bass", Fout|Fmono, 50, 50},
161 [Vspeed] {"speed", Fin|Fout|Fmono, Speed, Speed},
162 [Vfilter] {"filter", Fout|Fmono, 0, 0},
163 [Vinvert] {"invert", Fin|Fout|Fmono, 0, 0},
164 [Nvol] {0}
165 };
166
167 static void setreg(char *name, int val, int n);
168
169 static char Emode[] = "illegal open mode";
170 static char Evolume[] = "illegal volume specifier";
171
172 static void
bufinit(IOstate * b)173 bufinit(IOstate *b)
174 {
175 int i;
176
177 if (debug) print("bufinit\n");
178 for (i = 0; i < Nbuf; i++) {
179 b->buf[i].virt = xspanalloc(Bufsize, CACHELINESZ, 0);
180 b->buf[i].phys = PADDR(b->buf[i].virt);
181 }
182 b->bufinit = 1;
183 };
184
185 static void
setempty(IOstate * b)186 setempty(IOstate *b)
187 {
188 int i;
189
190 if (debug) print("setempty\n");
191 for (i = 0; i < Nbuf; i++) {
192 b->buf[i].nbytes = 0;
193 }
194 b->filling = b->buf;
195 b->current = b->buf;
196 b->next = b->buf;
197 }
198
199 static int
audioqnotempty(void * x)200 audioqnotempty(void *x)
201 {
202 IOstate *s = x;
203
204 return dmaidle(s->dma) || s->emptying != s->current;
205 }
206
207 static int
audioqnotfull(void * x)208 audioqnotfull(void *x)
209 {
210 IOstate *s = x;
211
212 return dmaidle(s->dma) || s->filling != s->current;
213 }
214
215 static void
audioreset(void)216 audioreset(void)
217 {
218 /* Turn MCP operations off */
219 MCPREG->mccr = 0;
220 }
221
222 uchar status0[1] = {0x22};
223 uchar status1[1] = {0x80};
224 uchar data00[1] = {0x00}; /* volume control, bits 0 – 5 */
225 uchar data01[1] = {0x40};
226 uchar data02[1] = {0x80};
227 uchar data0e0[2] = {0xc0, 0xe0};
228 uchar data0e1[2] = {0xc1, 0xe0};
229 uchar data0e2[2] = {0xc2, 0xf2};
230 /* there is no data0e3 */
231 uchar data0e4[2] = {0xc4, 0xe0};
232 uchar data0e5[2] = {0xc5, 0xe0};
233 uchar data0e6[2] = {0xc6, 0xe3};
234
235 static void
enable(void)236 enable(void)
237 {
238 uchar data[1];
239 int cs;
240
241 L3init();
242
243 PPCREG->ppar &= ~PPAR_SPR;
244
245 /* external clock and ssp configured for current samples/sec */
246 cs = archaudiospeed(audio.livol[Vspeed], 1);
247 status0[0] = (status0[0] & ~(3<<4)) | (cs<<4);
248
249 /* Enable the audio power */
250 archaudiopower(1);
251 // egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
252
253 /* Wait for the UDA1341 to wake up */
254 delay(100);
255
256 /* Reset the chip */
257 data[0] = status0[0] | 1<<UdaStatusRST;
258 L3write(UDA1341_L3Addr | UDA1341_STATUS, data, 1 );
259 archcodecreset();
260
261 /* write uda 1341 status[0] */
262 L3write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1 );
263 L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
264 L3write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1);
265 L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e2, 2);
266 L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e6, 2 );
267
268 if (debug) {
269 print("enable: status0 = 0x%2.2ux\n", status0[0]);
270 print("enable: status1 = 0x%2.2ux\n", status1[0]);
271 print("enable: data02 = 0x%2.2ux\n", data02[0]);
272 print("enable: data0e2 = 0x%4.4ux\n", data0e2[0] | data0e2[1]<<8);
273 print("enable: data0e4 = 0x%4.4ux\n", data0e4[0] | data0e4[1]<<8);
274 print("enable: data0e6 = 0x%4.4ux\n", data0e6[0] | data0e6[1]<<8);
275 }
276 }
277
278 static void
disable(void)279 disable(void)
280 {
281 SSPREG->sscr0 = 0x031f; /* disable */
282 }
283
284 static void
resetlevel(void)285 resetlevel(void)
286 {
287 int i;
288
289 for(i=0; volumes[i].name; i++) {
290 audio.lovol[i] = volumes[i].ilval;
291 audio.rovol[i] = volumes[i].irval;
292 audio.livol[i] = volumes[i].ilval;
293 audio.rivol[i] = volumes[i].irval;
294 }
295 }
296
297 static void
mxvolume(void)298 mxvolume(void) {
299 int *left, *right;
300 int cs;
301
302 cs = archaudiospeed(audio.livol[Vspeed], 1);
303 status0[0] = (status0[0] & ~(3<<4)) | (cs<<4);
304 L3write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1);
305 if(debug)
306 print("mxvolume: status0 = %2.2ux\n", status0[0]);
307 if(audio.amode & Aread){
308 left = audio.livol;
309 right = audio.rivol;
310 if (left[Vmic]+right[Vmic] == 0) {
311 /* Turn on automatic gain control (AGC) */
312 data0e4[1] |= 0x10;
313 L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 );
314 } else {
315 int v;
316 /* Turn on manual gain control */
317 v = ((left[Vmic]+right[Vmic])*0x7f/200)&0x7f;
318 data0e4[1] &= ~0x13;
319 data0e5[1] &= ~0x1f;
320 data0e4[1] |= v & 0x3;
321 data0e5[0] |= (v & 0x7c)<<6;
322 data0e5[1] |= (v & 0x7c)>>2;
323 L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 );
324 L3write(UDA1341_L3Addr | UDA1341_DATA0, data0e5, 2 );
325 }
326 if (left[Vinvert]+right[Vinvert] == 0)
327 status1[0] &= ~0x10;
328 else
329 status1[0] |= 0x10;
330 L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
331 if (debug) {
332 print("mxvolume: status1 = 0x%2.2ux\n", status1[0]);
333 print("mxvolume: data0e4 = 0x%4.4ux\n", data0e4[0]|data0e4[0]<<8);
334 print("mxvolume: data0e5 = 0x%4.4ux\n", data0e5[0]|data0e5[0]<<8);
335 }
336 }
337 if(audio.amode & Awrite){
338 left = audio.lovol;
339 right = audio.rovol;
340 data00[0] &= ~0x3f;
341 data00[0] |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f;
342 if (left[Vtreb]+right[Vtreb] <= 100
343 && left[Vbass]+right[Vbass] <= 100)
344 /* settings neutral */
345 data02[0] &= ~0x03;
346 else {
347 data02[0] |= 0x03;
348 data01[0] &= ~0x3f;
349 data01[0] |= ((left[Vtreb]+right[Vtreb]-100)*0x3/100)&0x03;
350 data01[0] |= (((left[Vbass]+right[Vbass]-100)*0xf/100)&0xf)<<2;
351 }
352 if (left[Vfilter]+right[Vfilter] == 0)
353 data02[0] &= ~0x10;
354 else
355 data02[0]|= 0x10;
356 if (left[Vinvert]+right[Vinvert] == 0)
357 status1[0] &= ~0x8;
358 else
359 status1[0] |= 0x8;
360 L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
361 L3write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1);
362 L3write(UDA1341_L3Addr | UDA1341_DATA0, data01, 1);
363 L3write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1);
364 if (debug) {
365 print("mxvolume: status1 = 0x%2.2ux\n", status1[0]);
366 print("mxvolume: data00 = 0x%2.2ux\n", data00[0]);
367 print("mxvolume: data01 = 0x%2.2ux\n", data01[0]);
368 print("mxvolume: data02 = 0x%2.2ux\n", data02[0]);
369 }
370 }
371 }
372
373 static void
setreg(char * name,int val,int n)374 setreg(char *name, int val, int n)
375 {
376 uchar x[2];
377 int i;
378
379 if(strcmp(name, "pause") == 0){
380 for(i = 0; i < n; i++)
381 microdelay(val);
382 return;
383 }
384
385 x[0] = val;
386 x[1] = val>>8;
387
388 switch(n){
389 case 1:
390 case 2:
391 break;
392 default:
393 error("setreg");
394 }
395
396 if(strcmp(name, "status") == 0){
397 L3write(UDA1341_L3Addr | UDA1341_STATUS, x, n);
398 } else if(strcmp(name, "data0") == 0){
399 L3write(UDA1341_L3Addr | UDA1341_DATA0, x, n);
400 } else if(strcmp(name, "data1") == 0){
401 L3write(UDA1341_L3Addr | UDA1341_DATA1, x, n);
402 } else
403 error("setreg");
404 }
405
406 static void
outenable(void)407 outenable(void) {
408 /* turn on DAC, set output gain switch */
409 archaudioamp(1);
410 archaudiomute(0);
411 status1[0] |= 0x41;
412 L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
413 /* set volume */
414 data00[0] |= 0xf;
415 L3write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1);
416 if (debug) {
417 print("outenable: status1 = 0x%2.2ux\n", status1[0]);
418 print("outenable: data00 = 0x%2.2ux\n", data00[0]);
419 }
420 }
421
422 static void
outdisable(void)423 outdisable(void) {
424 archaudiomute(1);
425 dmastop(audio.o.dma);
426 /* turn off DAC, clear output gain switch */
427 archaudioamp(0);
428 status1[0] &= ~0x41;
429 L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
430 if (debug) {
431 print("outdisable: status1 = 0x%2.2ux\n", status1[0]);
432 }
433 // egpiobits(EGPIO_audio_power, 0);
434 }
435
436 static void
inenable(void)437 inenable(void) {
438 /* turn on ADC, set input gain switch */
439 status1[0] |= 0x22;
440 L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
441 if (debug) {
442 print("inenable: status1 = 0x%2.2ux\n", status1[0]);
443 }
444 }
445
446 static void
indisable(void)447 indisable(void) {
448 dmastop(audio.i.dma);
449 /* turn off ADC, clear input gain switch */
450 status1[0] &= ~0x22;
451 L3write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
452 if (debug) {
453 print("indisable: status1 = 0x%2.2ux\n", status1[0]);
454 }
455 }
456
457 static void
sendaudio(IOstate * s)458 sendaudio(IOstate *s) {
459 /* interrupt routine calls this too */
460 int n;
461
462 if (debug > 1) print("#A: sendaudio\n");
463 ilock(&s->ilock);
464 while (s->next != s->filling) {
465 assert(s->next->nbytes);
466 if ((n = dmastart(s->dma, (void*)s->next->phys, s->next->nbytes)) == 0) {
467 iostats.faildma++;
468 break;
469 }
470 iostats.totaldma++;
471 switch (n) {
472 case 1:
473 iostats.idledma++;
474 break;
475 case 3:
476 iostats.faildma++;
477 break;
478 }
479 if (debug) {
480 if (debug > 1)
481 print("dmastart @%p\n", s->next);
482 else
483 iprint("+");
484 }
485 s->next->nbytes = 0;
486 s->next++;
487 if (s->next == &s->buf[Nbuf])
488 s->next = &s->buf[0];
489 }
490 iunlock(&s->ilock);
491 }
492
493 static void
recvaudio(IOstate * s)494 recvaudio(IOstate *s) {
495 /* interrupt routine calls this too */
496 int n;
497
498 if (debug > 1) print("#A: recvaudio\n");
499 ilock(&s->ilock);
500 while (s->next != s->emptying) {
501 assert(s->next->nbytes == 0);
502 if ((n = dmastart(s->dma, (void*)s->next->phys, Bufsize)) == 0) {
503 iostats.faildma++;
504 break;
505 }
506 iostats.totaldma++;
507 switch (n) {
508 case 1:
509 iostats.idledma++;
510 break;
511 case 3:
512 iostats.faildma++;
513 break;
514 }
515 if (debug) {
516 if (debug > 1)
517 print("dmastart @%p\n", s->next);
518 else
519 iprint("+");
520 }
521 s->next++;
522 if (s->next == &s->buf[Nbuf])
523 s->next = &s->buf[0];
524 }
525 iunlock(&s->ilock);
526 }
527
528 static void
audiopower(int flag)529 audiopower(int flag) {
530 IOstate *s;
531
532 if (debug) {
533 iprint("audiopower %d\n", flag);
534 }
535 if (flag) {
536 /* power on only when necessary */
537 if (audio.amode) {
538 archaudiopower(1);
539 enable();
540 if (audio.amode & Aread) {
541 inenable();
542 s = &audio.i;
543 dmastop(s->dma);
544 recvaudio(s);
545 }
546 if (audio.amode & Awrite) {
547 outenable();
548 s = &audio.o;
549 dmastop(s->dma);
550 sendaudio(s);
551 }
552 mxvolume();
553 }
554 } else {
555 /* power off */
556 if (audio.amode & Aread)
557 indisable();
558 if (audio.amode & Awrite)
559 outdisable();
560 disable();
561 archaudiopower(0);
562 }
563 }
564
565 static void
audiointr(void * x,ulong ndma)566 audiointr(void *x, ulong ndma) {
567 IOstate *s = x;
568
569 if (debug) {
570 if (debug > 1)
571 iprint("#A: audio interrupt @%p\n", s->current);
572 else
573 iprint("-");
574 }
575 /* Only interrupt routine touches s->current */
576 s->current++;
577 if (s->current == &s->buf[Nbuf])
578 s->current = &s->buf[0];
579 if (ndma > 0) {
580 if (s == &audio.o)
581 sendaudio(s);
582 else if (s == &audio.i)
583 recvaudio(s);
584 }
585 wakeup(&s->vous);
586 }
587
588 static void
audioinit(void)589 audioinit(void)
590 {
591 audio.amode = Aclosed;
592 resetlevel();
593 // powerenable(audiopower);
594 }
595
596 static Chan*
audioattach(char * param)597 audioattach(char *param)
598 {
599 return devattach('A', param);
600 }
601
602 static Walkqid*
audiowalk(Chan * c,Chan * nc,char ** name,int nname)603 audiowalk(Chan *c, Chan *nc, char **name, int nname)
604 {
605 return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
606 }
607
608 static int
audiostat(Chan * c,uchar * db,int n)609 audiostat(Chan *c, uchar *db, int n)
610 {
611 return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
612 }
613
614 static Chan*
audioopen(Chan * c,int mode)615 audioopen(Chan *c, int mode)
616 {
617 IOstate *s;
618 int omode = mode;
619
620 switch((ulong)c->qid.path) {
621 default:
622 error(Eperm);
623 break;
624
625 case Qstatus:
626 if((omode&7) != OREAD)
627 error(Eperm);
628 case Qvolume:
629 case Qaudioctl:
630 case Qdir:
631 break;
632
633 case Qaudio:
634 omode = (omode & 0x7) + 1;
635 if (omode & ~(Aread | Awrite))
636 error(Ebadarg);
637 qlock(&audio);
638 if(audio.amode & omode){
639 qunlock(&audio);
640 error(Einuse);
641 }
642 enable();
643 memset(&iostats, 0, sizeof(iostats));
644 if (omode & Aread) {
645 inenable();
646 s = &audio.i;
647 if(s->bufinit == 0)
648 bufinit(s);
649 setempty(s);
650 s->emptying = &s->buf[Nbuf-1];
651 s->chan = c;
652 s->dma = dmasetup(DmaSSP, 1, 0, audiointr, (void*)s);
653 audio.amode |= Aread;
654 audio.clockout = 1;
655 }
656 if (omode & Awrite) {
657 outenable();
658 s = &audio.o;
659 audio.amode |= Awrite;
660 if(s->bufinit == 0)
661 bufinit(s);
662 setempty(s);
663 s->chan = c;
664 s->dma = dmasetup(DmaSSP, 0, 0, audiointr, (void*)s);
665 audio.amode |= Awrite;
666 }
667 mxvolume();
668 qunlock(&audio);
669 if (debug) print("open done\n");
670 break;
671 }
672 c = devopen(c, mode, audiodir, nelem(audiodir), devgen);
673 c->mode = openmode(mode);
674 c->flag |= COPEN;
675 c->offset = 0;
676
677 return c;
678 }
679
680 static void
audioclose(Chan * c)681 audioclose(Chan *c)
682 {
683 IOstate *s;
684
685 switch((ulong)c->qid.path) {
686 default:
687 error(Eperm);
688 break;
689
690 case Qdir:
691 case Qvolume:
692 case Qaudioctl:
693 case Qstatus:
694 break;
695
696 case Qaudio:
697 if (debug > 1) print("#A: close\n");
698 if(c->flag & COPEN) {
699 qlock(&audio);
700 if(waserror()){
701 qunlock(&audio);
702 nexterror();
703 }
704 if (audio.o.chan == c) {
705 /* closing the write end */
706 audio.amode &= ~Awrite;
707 s = &audio.o;
708 qlock(s);
709 if(waserror()){
710 qunlock(s);
711 nexterror();
712 }
713 if (s->filling->nbytes) {
714 /* send remaining partial buffer */
715 s->filling++;
716 if (s->filling == &s->buf[Nbuf])
717 s->filling = &s->buf[0];
718 sendaudio(s);
719 }
720 dmawait(s->dma);
721 outdisable();
722 setempty(s);
723 dmafree(s->dma);
724 qunlock(s);
725 poperror();
726 }
727 if (audio.i.chan == c) {
728 /* closing the read end */
729 audio.amode &= ~Aread;
730 s = &audio.i;
731 qlock(s);
732 if(waserror()){
733 qunlock(s);
734 nexterror();
735 }
736 indisable();
737 setempty(s);
738 dmafree(s->dma);
739 qunlock(s);
740 poperror();
741 }
742 if (audio.amode == 0) {
743 /* turn audio off */
744 archaudiopower(0);
745 }
746 qunlock(&audio);
747 poperror();
748 if (debug) {
749 print("total dmas: %lud\n", iostats.totaldma);
750 print("dmas while idle: %lud\n", iostats.idledma);
751 print("dmas while busy: %lud\n", iostats.faildma);
752 print("out of order dma: %lud\n", iostats.samedma);
753 }
754 }
755 break;
756 }
757 }
758
759 static long
audioread(Chan * c,void * v,long n,vlong off)760 audioread(Chan *c, void *v, long n, vlong off)
761 {
762 int liv, riv, lov, rov;
763 long m, n0;
764 char buf[300];
765 int j;
766 ulong offset = off;
767 char *p;
768 IOstate *s;
769
770 n0 = n;
771 p = v;
772 switch((ulong)c->qid.path) {
773 default:
774 error(Eperm);
775 break;
776
777 case Qdir:
778 return devdirread(c, p, n, audiodir, nelem(audiodir), devgen);
779
780 case Qaudio:
781 if (debug > 1) print("#A: read %ld\n", n);
782 if((audio.amode & Aread) == 0)
783 error(Emode);
784 s = &audio.i;
785 qlock(s);
786 if(waserror()){
787 qunlock(s);
788 nexterror();
789 }
790 while(n > 0) {
791 if(s->emptying->nbytes == 0) {
792 if (debug > 1) print("#A: emptied @%p\n", s->emptying);
793 recvaudio(s);
794 s->emptying++;
795 if (s->emptying == &s->buf[Nbuf])
796 s->emptying = s->buf;
797 }
798 /* wait if dma in progress */
799 while (!dmaidle(s->dma) && s->emptying == s->current) {
800 if (debug > 1) print("#A: sleep\n");
801 sleep(&s->vous, audioqnotempty, s);
802 }
803
804 m = Bufsize - s->emptying->nbytes;
805 if(m > n)
806 m = n;
807 memmove(p, s->emptying->virt + s->emptying->nbytes, m);
808
809 s->emptying->nbytes -= m;
810 n -= m;
811 p += m;
812 }
813 poperror();
814 qunlock(s);
815 break;
816 break;
817
818 case Qstatus:
819 buf[0] = 0;
820 snprint(buf, sizeof(buf), "bytes %llud\ntime %lld\n",
821 audio.totcount, audio.tottime);
822 return readstr(offset, p, n, buf);
823
824 case Qvolume:
825 case Qaudioctl:
826 j = 0;
827 buf[0] = 0;
828 for(m=0; volumes[m].name; m++){
829 liv = audio.livol[m];
830 riv = audio.rivol[m];
831 lov = audio.lovol[m];
832 rov = audio.rovol[m];
833 j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
834 if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
835 if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
836 j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
837 else{
838 if(volumes[m].flag & Fin)
839 j += snprint(buf+j, sizeof(buf)-j,
840 " in %d", liv);
841 if(volumes[m].flag & Fout)
842 j += snprint(buf+j, sizeof(buf)-j,
843 " out %d", lov);
844 }
845 }else{
846 if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
847 liv==lov && riv==rov)
848 j += snprint(buf+j, sizeof(buf)-j,
849 " left %d right %d",
850 liv, riv);
851 else{
852 if(volumes[m].flag & Fin)
853 j += snprint(buf+j, sizeof(buf)-j,
854 " in left %d right %d",
855 liv, riv);
856 if(volumes[m].flag & Fout)
857 j += snprint(buf+j, sizeof(buf)-j,
858 " out left %d right %d",
859 lov, rov);
860 }
861 }
862 j += snprint(buf+j, sizeof(buf)-j, "\n");
863 }
864 return readstr(offset, p, n, buf);
865 }
866 return n0-n;
867 }
868
869 static long
audiowrite(Chan * c,void * vp,long n,vlong)870 audiowrite(Chan *c, void *vp, long n, vlong)
871 {
872 long m, n0;
873 int i, nf, v, left, right, in, out;
874 char buf[255], *field[Ncmd];
875 char *p;
876 IOstate *a;
877
878 p = vp;
879 n0 = n;
880 switch((ulong)c->qid.path) {
881 default:
882 error(Eperm);
883 break;
884
885 case Qvolume:
886 case Qaudioctl:
887 v = Vaudio;
888 left = 1;
889 right = 1;
890 in = 1;
891 out = 1;
892 if(n > sizeof(buf)-1)
893 n = sizeof(buf)-1;
894 memmove(buf, p, n);
895 buf[n] = '\0';
896 n = 0;
897
898 nf = getfields(buf, field, Ncmd, 1, " \t\n");
899 for(i = 0; i < nf; i++){
900 /*
901 * a number is volume
902 */
903 if(field[i][0] >= '0' && field[i][0] <= '9') {
904 m = strtoul(field[i], 0, 10);
905 if(v == Vspeed){
906 if(archaudiospeed(m, 0) < 0)
907 error(Evolume);
908 }else
909 if(m < 0 || m > 100)
910 error(Evolume);
911 if(left && out)
912 audio.lovol[v] = m;
913 if(left && in)
914 audio.livol[v] = m;
915 if(right && out)
916 audio.rovol[v] = m;
917 if(right && in)
918 audio.rivol[v] = m;
919 goto cont0;
920 }
921 if(strcmp(field[i], "rate") == 0)
922 field[i] = "speed"; /* honestly ... */
923
924 for(m=0; volumes[m].name; m++) {
925 if(strcmp(field[i], volumes[m].name) == 0) {
926 v = m;
927 in = 1;
928 out = 1;
929 left = 1;
930 right = 1;
931 goto cont0;
932 }
933 }
934 if(strcmp(field[i], "enc") == 0) {
935 if(++i >= nf)
936 error(Evolume);
937 if(strcmp(field[i], "pcm") != 0)
938 error(Evolume);
939 goto cont0;
940 }
941 if(strcmp(field[i], "bits") == 0) {
942 if(++i >= nf)
943 error(Evolume);
944 if(strtol(field[i], 0, 0) != 16)
945 error(Evolume);
946 goto cont0;
947 }
948 if(strcmp(field[i], "chans") == 0) {
949 if(++i >= nf)
950 error(Evolume);
951 if(strtol(field[i], 0, 0) != 2)
952 error(Evolume);
953 goto cont0;
954 }
955 if(strcmp(field[i], "reset") == 0) {
956 resetlevel();
957 goto cont0;
958 }
959 if(strcmp(field[i], "debug") == 0) {
960 debug = debug?0:1;
961 goto cont0;
962 }
963 if(strcmp(field[i], "in") == 0) {
964 in = 1;
965 out = 0;
966 goto cont0;
967 }
968 if(strcmp(field[i], "out") == 0) {
969 in = 0;
970 out = 1;
971 goto cont0;
972 }
973 if(strcmp(field[i], "left") == 0) {
974 left = 1;
975 right = 0;
976 goto cont0;
977 }
978 if(strcmp(field[i], "right") == 0) {
979 left = 0;
980 right = 1;
981 goto cont0;
982 }
983 if(strcmp(field[i], "reg") == 0) {
984 if(nf < 3)
985 error(Evolume);
986 setreg(field[1], atoi(field[2]), nf == 4 ? atoi(field[3]):1);
987 return n0;
988 }
989 error(Evolume);
990 break;
991 cont0:;
992 }
993 mxvolume();
994 break;
995
996 case Qaudio:
997 if (debug > 1) print("#A: write %ld\n", n);
998 if((audio.amode & Awrite) == 0)
999 error(Emode);
1000 a = &audio.o;
1001 qlock(a);
1002 if(waserror()){
1003 qunlock(a);
1004 nexterror();
1005 }
1006 while(n > 0) {
1007 /* wait if dma in progress */
1008 while (!dmaidle(a->dma) && a->filling == a->current) {
1009 if (debug > 1) print("#A: sleep\n");
1010 sleep(&a->vous, audioqnotfull, a);
1011 }
1012
1013 m = Bufsize - a->filling->nbytes;
1014 if(m > n)
1015 m = n;
1016 memmove(a->filling->virt + a->filling->nbytes, p, m);
1017
1018 a->filling->nbytes += m;
1019 n -= m;
1020 p += m;
1021 if(a->filling->nbytes >= Bufsize) {
1022 if (debug > 1) print("#A: filled @%p\n", a->filling);
1023 a->filling++;
1024 if (a->filling == &a->buf[Nbuf])
1025 a->filling = a->buf;
1026 sendaudio(a);
1027 }
1028 }
1029 poperror();
1030 qunlock(a);
1031 break;
1032 }
1033 return n0 - n;
1034 }
1035
1036 Dev audiodevtab = {
1037 'A',
1038 "audio",
1039
1040 audioreset,
1041 audioinit,
1042 devshutdown,
1043 audioattach,
1044 audiowalk,
1045 audiostat,
1046 audioopen,
1047 devcreate,
1048 audioclose,
1049 audioread,
1050 devbread,
1051 audiowrite,
1052 devbwrite,
1053 devremove,
1054 devwstat,
1055 audiopower,
1056 };
1057