1 /*
2 * Copyright (c) 1991, 1992, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This software was developed by the Computer Systems Engineering group
6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7 * contributed to Berkeley.
8 *
9 * All advertising materials mentioning features or use of this software
10 * must display the following acknowledgement:
11 * This product includes software developed by the University of
12 * California, Lawrence Berkeley Laboratory.
13 *
14 * %sccs.include.redist.c%
15 *
16 * @(#)bsd_audio.c 8.1 (Berkeley) 06/11/93
17 *
18 * from: $Header: bsd_audio.c,v 1.18 93/04/24 16:20:35 leres Exp $ (LBL)
19 */
20 #include "bsdaudio.h"
21 #if NBSDAUDIO > 0
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25
26 #if BSD < 199103
27 #ifndef SUNOS
28 #define SUNOS
29 #endif
30 #endif
31
32 #include <sys/errno.h>
33 #include <sys/file.h>
34 #include <sys/proc.h>
35 #include <sys/user.h>
36 #include <sys/vnode.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
39 #ifndef SUNOS
40 #include <sys/tty.h>
41 #endif
42 #include <sys/uio.h>
43
44 #ifdef SUNOS
45 #include <sundev/mbvar.h>
46 #include <sun4c/intreg.h>
47 #else
48 #include <sys/device.h>
49 #include <machine/autoconf.h>
50 #endif
51 #include <machine/cpu.h>
52
53 /*
54 * Avoid name clashes with SunOS so we can config either the bsd or sun
55 * streams driver in a SunOS kernel.
56 */
57 #ifdef SUNOS
58 #include <sbusdev/bsd_audioreg.h>
59 #include <sbusdev/bsd_audiovar.h>
60 #include <sbusdev/bsd_audioio.h>
61 struct selinfo {
62 struct proc *si_proc;
63 int si_coll;
64 };
65 #else
66 #include <sparc/dev/bsd_audioreg.h>
67 #include <sparc/dev/bsd_audiovar.h>
68 #include <machine/bsd_audioio.h>
69 #endif
70
71 #ifdef SUNOS
72 #include "bsd_audiocompat.h"
73 #endif
74
75 /*
76 * Initial/default block size is patchable.
77 */
78 int audio_blocksize = DEFBLKSIZE;
79 int audio_backlog = 400; /* 50ms in samples */
80
81 /*
82 * Software state, per AMD79C30 audio chip.
83 */
84 struct audio_softc {
85 #ifndef SUNOS
86 struct device sc_dev; /* base device */
87 struct intrhand sc_hwih; /* hardware interrupt vector */
88 struct intrhand sc_swih; /* software interrupt vector */
89 #endif
90 int sc_interrupts; /* number of interrupts taken */
91
92 int sc_open; /* single use device */
93 u_long sc_wseek; /* timestamp of last frame written */
94 u_long sc_rseek; /* timestamp of last frame read */
95 struct mapreg sc_map; /* current contents of map registers */
96 struct selinfo sc_wsel; /* write selector */
97 struct selinfo sc_rsel; /* read selector */
98 /*
99 * keep track of levels so we don't have to convert back from
100 * MAP gain constants
101 */
102 int sc_rlevel; /* record level */
103 int sc_plevel; /* play level */
104 int sc_mlevel; /* monitor level */
105
106 /* sc_au is special in that the hardware interrupt handler uses it */
107 struct auio sc_au; /* recv and xmit buffers, etc */
108
109 };
110
111 /* interrupt interfaces */
112 #ifndef AUDIO_C_HANDLER
113 int audiohwintr __P((void *));
114 #endif
115 int audioswintr __P((void *));
116
117 /* forward declarations */
118 int audio_sleep __P((struct aucb *, int));
119 void audio_setmap __P((volatile struct amd7930 *, struct mapreg *));
120
121 static void init_amd();
122
123 #if !defined(AUDIO_C_HANDLER) || defined(SUNOS)
124 struct auio *audio_au;
125 extern void audio_trap();
126 #endif
127
128 #ifdef SUNOS
129 struct audio_softc audio_softc;
130 #define SOFTC(dev) &audio_softc
131 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio)
132
133 #define AUDIOOPEN(d, f, i, p)\
134 audioopen(d, f, i)\
135 dev_t d; int f, i;
136 #define AUDIOCLOSE(d, f, i, p)\
137 audioclose(d, f, i)\
138 dev_t d; int f, i;
139 #define AUDIOREAD(d, u, f) \
140 audioread(d, u) dev_t d; struct uio *u;
141 #define AUDIOWRITE(d, u, f) \
142 audiowrite(d, u) dev_t d; struct uio *u;
143 #define AUDIOIOCTL(d, c, a, f, o)\
144 audioioctl(d, c, a, f)\
145 dev_t d; int c; caddr_t a; int f;
146 #define AUDIOSELECT(d, r, p)\
147 audio_select(d, r, p)\
148 dev_t d; int r; struct proc *p;
149
150
151 #define AUDIO_SET_SWINTR set_intreg(IR_SOFT_INT4, 1)
152
153 int
audioselect(dev,rw)154 audioselect(dev, rw)
155 register dev_t dev;
156 int rw;
157 {
158 return (audio_select(dev, rw, u.u_procp));
159 }
160
161 static void
selrecord(p,si)162 selrecord(p, si)
163 struct proc *p;
164 struct selinfo *si;
165 {
166 if (si->si_proc != 0)
167 si->si_coll = 1;
168 else
169 si->si_proc = p;
170 }
171 #define SELWAKEUP(si) \
172 {\
173 if ((si)->si_proc != 0) {\
174 selwakeup((si)->si_proc, (si)->si_coll); \
175 (si)->si_proc = 0;\
176 (si)->si_coll = 0;\
177 }\
178 }
179
180
181 static int audioattach();
182 static int audioidentify();
183
184 struct dev_ops bsdaudio_ops = {
185 0,
186 audioidentify,
187 audioattach,
188 };
189
190 static int
audioidentify(cp)191 audioidentify(cp)
192 char *cp;
193 {
194 return (strcmp(cp, "audio") == 0);
195 }
196
197 static int
audioattach(dev)198 audioattach(dev)
199 struct dev_info *dev;
200 {
201 register struct audio_softc *sc;
202 register volatile struct amd7930 *amd;
203 struct dev_reg *reg;
204
205 sc = &audio_softc;
206 if (dev->devi_nreg != 1 || dev->devi_nintr != 1) {
207 printf("audio: bad config\n");
208 return (-1);
209 }
210 reg = dev->devi_reg;
211 amd = (struct amd7930 *)map_regs(reg->reg_addr, reg->reg_size,
212 reg->reg_bustype);
213 sc->sc_au.au_amd = amd;
214 init_amd(amd);
215
216 audio_au = &sc->sc_au;
217 #ifndef AUDIO_C_HANDLER
218 settrap(dev->devi_intr->int_pri, audio_trap);
219 #else
220 /* XXX */
221 addintr(dev->devi_intr->int_pri, audiohwintr, dev->devi_name,
222 dev->devi_unit);
223 #endif
224 addintr(4, audioswintr, dev->devi_name, dev->devi_unit);
225 report_dev(dev);
226
227 return (0);
228 }
229 #else
230 #define AUDIOOPEN(d, f, i, p) audioopen(dev_t d, int f, int i, struct proc *p)
231 #define AUDIOCLOSE(d, f, i, p) audioclose(dev_t d, int f, int i, \
232 struct proc *p)
233 #define AUDIOREAD(d, u, f) audioread(dev_t d, struct uio *u, int f)
234 #define AUDIOWRITE(d, u, f) audiowrite(dev_t d, struct uio *u, int f)
235 #define AUDIOIOCTL(d, c, a, f, o)\
236 audioioctl(dev_t dev, int c, caddr_t a, int f, struct proc *p)
237 #define AUDIOSELECT(d, r, p) audioselect(dev_t dev, int rw, struct proc *p)
238 #define SELWAKEUP selwakeup
239
240 #define AUDIO_SET_SWINTR ienab_bis(IE_L6)
241
242 /* autoconfiguration driver */
243 void audioattach(struct device *, struct device *, void *);
244 struct cfdriver audiocd =
245 { NULL, "audio", matchbyname, audioattach,
246 DV_DULL, sizeof(struct audio_softc) };
247 #define SOFTC(dev) audiocd.cd_devs[minor(dev)]
248 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio)
249
250 /*
251 * Audio chip found.
252 */
253 void
audioattach(parent,self,args)254 audioattach(parent, self, args)
255 struct device *parent, *self;
256 void *args;
257 {
258 register struct audio_softc *sc = (struct audio_softc *)self;
259 register struct romaux *ra = args;
260 register volatile struct amd7930 *amd;
261 register int pri;
262
263 if (ra->ra_nintr != 1) {
264 printf(": expected 1 interrupt, got %d\n", ra->ra_nintr);
265 return;
266 }
267 pri = ra->ra_intr[0].int_pri;
268 printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT);
269 amd = (volatile struct amd7930 *)(ra->ra_vaddr ?
270 ra->ra_vaddr : mapiodev(ra->ra_paddr, sizeof *amd));
271 sc->sc_au.au_amd = amd;
272
273 init_amd(amd);
274
275 #ifndef AUDIO_C_HANDLER
276 audio_au = &sc->sc_au;
277 intr_fasttrap(pri, audio_trap);
278 #else
279 sc->sc_hwih.ih_fun = audiohwintr;
280 sc->sc_hwih.ih_arg = &sc->sc_au;
281 intr_establish(pri, &sc->sc_hwih);
282 #endif
283 sc->sc_swih.ih_fun = audioswintr;
284 sc->sc_swih.ih_arg = sc;
285 intr_establish(PIL_AUSOFT, &sc->sc_swih);
286 }
287 #endif
288
289 static void
init_amd(amd)290 init_amd(amd)
291 register volatile struct amd7930 *amd;
292 {
293 /* disable interrupts */
294 amd->cr = AMDR_INIT;
295 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
296
297 /*
298 * Initialize the mux unit. We use MCR3 to route audio (MAP)
299 * through channel Bb. MCR1 and MCR2 are unused.
300 * Setting the INT enable bit in MCR4 will generate an interrupt
301 * on each converted audio sample.
302 */
303 amd->cr = AMDR_MUX_1_4;
304 amd->dr = 0;
305 amd->dr = 0;
306 amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA;
307 amd->dr = AMD_MCR4_INT_ENABLE;
308 }
309
310 static int audio_default_level = 150;
311 static void ausetrgain __P((struct audio_softc *, int));
312 static void ausetpgain __P((struct audio_softc *, int));
313 static void ausetmgain __P((struct audio_softc *, int));
314 static int audiosetinfo __P((struct audio_softc *, struct audio_info *));
315 static int audiogetinfo __P((struct audio_softc *, struct audio_info *));
316 struct sun_audio_info;
317 static int sunaudiosetinfo __P((struct audio_softc *,
318 struct sun_audio_info *));
319 static int sunaudiogetinfo __P((struct audio_softc *,
320 struct sun_audio_info *));
321 static void audio_setmmr2 __P((volatile struct amd7930 *, int));
322
323 /* ARGSUSED */
324 int
AUDIOOPEN(dev,flags,ifmt,p)325 AUDIOOPEN(dev, flags, ifmt, p)
326 {
327 register struct audio_softc *sc;
328 register volatile struct amd7930 *amd;
329 int unit = minor(dev);
330
331 #ifdef SUNOS
332 if (unit > 0)
333 return (ENXIO);
334 sc = &audio_softc;
335 #else
336 if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL)
337 return (ENXIO);
338 #endif
339 if (sc->sc_open)
340 return (EBUSY);
341 sc->sc_open = 1;
342
343 sc->sc_au.au_lowat = audio_blocksize;
344 sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat;
345 sc->sc_au.au_blksize = audio_blocksize;
346 sc->sc_au.au_backlog = audio_backlog;
347
348 /* set up read and write blocks and `dead sound' zero value. */
349 AUCB_INIT(&sc->sc_au.au_rb);
350 sc->sc_au.au_rb.cb_thresh = AUCB_SIZE;
351 AUCB_INIT(&sc->sc_au.au_wb);
352 sc->sc_au.au_wb.cb_thresh = -1;
353
354 /* nothing read or written yet */
355 sc->sc_rseek = 0;
356 sc->sc_wseek = 0;
357
358 bzero((char *)&sc->sc_map, sizeof sc->sc_map);
359 /* default to speaker */
360 sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS;
361
362 /* enable interrupts and set parameters established above */
363 amd = sc->sc_au.au_amd;
364 audio_setmmr2(amd, sc->sc_map.mr_mmr2);
365 ausetrgain(sc, audio_default_level);
366 ausetpgain(sc, audio_default_level);
367 ausetmgain(sc, 0);
368 amd->cr = AMDR_INIT;
369 amd->dr = AMD_INIT_PMS_ACTIVE;
370
371 return (0);
372 }
373
374 static int
audio_drain(sc)375 audio_drain(sc)
376 register struct audio_softc *sc;
377 {
378 register int error;
379
380 while (!AUCB_EMPTY(&sc->sc_au.au_wb))
381 if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0)
382 return (error);
383 return (0);
384 }
385
386 /*
387 * Close an audio chip.
388 */
389 /* ARGSUSED */
390 int
AUDIOCLOSE(dev,flags,ifmt,p)391 AUDIOCLOSE(dev, flags, ifmt, p)
392 {
393 register struct audio_softc *sc = SOFTC(dev);
394 register volatile struct amd7930 *amd;
395 register struct aucb *cb;
396 register int s;
397
398 /*
399 * Block until output drains, but allow ^C interrupt.
400 */
401 sc->sc_au.au_lowat = 0; /* avoid excessive wakeups */
402 s = splaudio();
403 /*
404 * If there is pending output, let it drain (unless
405 * the output is paused).
406 */
407 cb = &sc->sc_au.au_wb;
408 if (!AUCB_EMPTY(cb) && !cb->cb_pause)
409 (void)audio_drain(sc);
410 /*
411 * Disable interrupts, clear open flag, and done.
412 */
413 amd = sc->sc_au.au_amd;
414 amd->cr = AMDR_INIT;
415 amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
416 splx(s);
417 sc->sc_open = 0;
418 return (0);
419 }
420
421 int
audio_sleep(cb,thresh)422 audio_sleep(cb, thresh)
423 register struct aucb *cb;
424 register int thresh;
425 {
426 register int error;
427 register int s = splaudio();
428
429 cb->cb_thresh = thresh;
430 error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0);
431 splx(s);
432 return (error);
433 }
434
435 /* ARGSUSED */
436 int
AUDIOREAD(dev,uio,ioflag)437 AUDIOREAD(dev, uio, ioflag)
438 {
439 register struct audio_softc *sc = SOFTC(dev);
440 register struct aucb *cb;
441 register int n, head, taildata, error;
442 register int blocksize = sc->sc_au.au_blksize;
443
444 if (uio->uio_resid == 0)
445 return (0);
446 cb = &sc->sc_au.au_rb;
447 error = 0;
448 cb->cb_drops = 0;
449 sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb);
450 do {
451 while (AUCB_LEN(cb) < blocksize) {
452 #ifndef SUNOS
453 if (ioflag & IO_NDELAY) {
454 error = EWOULDBLOCK;
455 return (error);
456 }
457 #endif
458 if ((error = audio_sleep(cb, blocksize)) != 0)
459 return (error);
460 }
461 /*
462 * The space calculation can only err on the short
463 * side if an interrupt occurs during processing:
464 * only cb_tail is altered in the interrupt code.
465 */
466 head = cb->cb_head;
467 if ((n = AUCB_LEN(cb)) > uio->uio_resid)
468 n = uio->uio_resid;
469 taildata = AUCB_SIZE - head;
470 if (n > taildata) {
471 error = UIOMOVE((caddr_t)cb->cb_data + head,
472 taildata, UIO_READ, uio);
473 if (error == 0)
474 error = UIOMOVE((caddr_t)cb->cb_data,
475 n - taildata, UIO_READ, uio);
476 } else
477 error = UIOMOVE((caddr_t)cb->cb_data + head, n,
478 UIO_READ, uio);
479 if (error)
480 break;
481 head = AUCB_MOD(head + n);
482 cb->cb_head = head;
483 } while (uio->uio_resid >= blocksize);
484
485 return (error);
486 }
487
488 /* ARGSUSED */
489 int
AUDIOWRITE(dev,uio,ioflag)490 AUDIOWRITE(dev, uio, ioflag)
491 {
492 register struct audio_softc *sc = SOFTC(dev);
493 register struct aucb *cb = &sc->sc_au.au_wb;
494 register int n, tail, tailspace, error, first, watermark;
495
496 error = 0;
497 first = 1;
498 while (uio->uio_resid > 0) {
499 watermark = sc->sc_au.au_hiwat;
500 while (AUCB_LEN(cb) > watermark) {
501 #ifndef SUNOS
502 if (ioflag & IO_NDELAY) {
503 error = EWOULDBLOCK;
504 return (error);
505 }
506 #endif
507 if ((error = audio_sleep(cb, watermark)) != 0)
508 return (error);
509 watermark = sc->sc_au.au_lowat;
510 }
511 /*
512 * The only value that can change on an interrupt is
513 * cb->cb_head. We only pull that out once to decide
514 * how much to write into cb_data; if we lose a race
515 * and cb_head changes, we will merely be overly
516 * conservative. For a legitimate time stamp,
517 * however, we need to synchronize the accesses to
518 * au_stamp and cb_head at a high ipl below.
519 */
520 tail = cb->cb_tail;
521 if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > uio->uio_resid) {
522 n = uio->uio_resid;
523 if (cb->cb_head == tail &&
524 n <= sc->sc_au.au_blksize &&
525 sc->sc_au.au_stamp - sc->sc_wseek > 400) {
526 /*
527 * the write is 'small', the buffer is empty
528 * and we have been silent for at least 50ms
529 * so we might be dealing with an application
530 * that writes frames synchronously with
531 * reading them. If so, we need an output
532 * backlog to cover scheduling delays or
533 * there will be gaps in the sound output.
534 * Also take this opportunity to reset the
535 * buffer pointers in case we ended up on
536 * a bad boundary (odd byte, blksize bytes
537 * from end, etc.).
538 */
539 register u_int* ip;
540 register int muzero = 0x7f7f7f7f;
541 register int i = splaudio();
542 cb->cb_head = cb->cb_tail = 0;
543 splx(i);
544 tail = sc->sc_au.au_backlog;
545 ip = (u_int*)cb->cb_data;
546 for (i = tail >> 2; --i >= 0; )
547 *ip++ = muzero;
548 }
549 }
550 tailspace = AUCB_SIZE - tail;
551 if (n > tailspace) {
552 /* write first part at tail and rest at head */
553 error = UIOMOVE((caddr_t)cb->cb_data + tail,
554 tailspace, UIO_WRITE, uio);
555 if (error == 0)
556 error = UIOMOVE((caddr_t)cb->cb_data,
557 n - tailspace, UIO_WRITE, uio);
558 } else
559 error = UIOMOVE((caddr_t)cb->cb_data + tail, n,
560 UIO_WRITE, uio);
561 if (error)
562 break;
563
564 tail = AUCB_MOD(tail + n);
565 if (first) {
566 register int s = splaudio();
567 sc->sc_wseek = AUCB_LEN(cb) + sc->sc_au.au_stamp + 1;
568 /*
569 * To guarantee that a write is contiguous in the
570 * sample space, we clear the drop count the first
571 * time through. If we later get drops, we will
572 * break out of the loop below, before writing
573 * a new frame.
574 */
575 cb->cb_drops = 0;
576 cb->cb_tail = tail;
577 splx(s);
578 first = 0;
579 } else {
580 if (cb->cb_drops != 0)
581 break;
582 cb->cb_tail = tail;
583 }
584 }
585 return (error);
586 }
587
588 /* Sun audio compatibility */
589 struct sun_audio_prinfo {
590 u_int sample_rate;
591 u_int channels;
592 u_int precision;
593 u_int encoding;
594 u_int gain;
595 u_int port;
596 u_int reserved0[4];
597 u_int samples;
598 u_int eof;
599 u_char pause;
600 u_char error;
601 u_char waiting;
602 u_char reserved1[3];
603 u_char open;
604 u_char active;
605 };
606 struct sun_audio_info {
607 struct sun_audio_prinfo play;
608 struct sun_audio_prinfo record;
609 u_int monitor_gain;
610 u_int reserved[4];
611 };
612
613 #ifndef SUNOS
614 #define SUNAUDIO_GETINFO _IOR('A', 1, struct sun_audio_info)
615 #define SUNAUDIO_SETINFO _IOWR('A', 2, struct sun_audio_info)
616 #else
617 #define SUNAUDIO_GETINFO _IOR(A, 1, struct sun_audio_info)
618 #define SUNAUDIO_SETINFO _IOWR(A, 2, struct sun_audio_info)
619 #endif
620
621 /* ARGSUSED */
622 int
AUDIOIOCTL(dev,cmd,addr,flag,p)623 AUDIOIOCTL(dev, cmd, addr, flag, p)
624 {
625 register struct audio_softc *sc = SOFTC(dev);
626 int error = 0, s;
627
628 switch (cmd) {
629
630 case AUDIO_GETMAP:
631 bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map));
632 break;
633
634 case AUDIO_SETMAP:
635 bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map));
636 sc->sc_map.mr_mmr2 &= 0x7f;
637 audio_setmap(sc->sc_au.au_amd, &sc->sc_map);
638 break;
639
640 case AUDIO_FLUSH:
641 s = splaudio();
642 AUCB_INIT(&sc->sc_au.au_rb);
643 AUCB_INIT(&sc->sc_au.au_wb);
644 sc->sc_au.au_stamp = 0;
645 splx(s);
646 sc->sc_wseek = 0;
647 sc->sc_rseek = 0;
648 break;
649
650 /*
651 * Number of read samples dropped. We don't know where or
652 * when they were dropped.
653 */
654 case AUDIO_RERROR:
655 *(int *)addr = sc->sc_au.au_rb.cb_drops != 0;
656 break;
657
658 /*
659 * How many samples will elapse until mike hears the first
660 * sample of what we last wrote?
661 */
662 case AUDIO_WSEEK:
663 s = splaudio();
664 *(u_long *)addr = sc->sc_wseek - sc->sc_au.au_stamp
665 + AUCB_LEN(&sc->sc_au.au_rb);
666 splx(s);
667 break;
668
669 case AUDIO_SETINFO:
670 error = audiosetinfo(sc, (struct audio_info *)addr);
671 break;
672
673 case AUDIO_GETINFO:
674 error = audiogetinfo(sc, (struct audio_info *)addr);
675 break;
676
677 case SUNAUDIO_GETINFO:
678 error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr);
679 break;
680
681 case SUNAUDIO_SETINFO:
682 error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr);
683 break;
684
685 case AUDIO_DRAIN:
686 error = audio_drain(sc);
687 break;
688
689 default:
690 error = EINVAL;
691 break;
692 }
693 return (error);
694 }
695
696 /* ARGSUSED */
697 int
AUDIOSELECT(dev,rw,p)698 AUDIOSELECT(dev, rw, p)
699 {
700 register struct audio_softc *sc = SOFTC(dev);
701 register struct aucb *cb;
702 register int s = splaudio();
703
704 switch (rw) {
705
706 case FREAD:
707 cb = &sc->sc_au.au_rb;
708 if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) {
709 splx(s);
710 return (1);
711 }
712 selrecord(p, &sc->sc_rsel);
713 cb->cb_thresh = sc->sc_au.au_blksize;
714 break;
715
716 case FWRITE:
717 cb = &sc->sc_au.au_wb;
718 if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) {
719 splx(s);
720 return (1);
721 }
722 selrecord(p, &sc->sc_wsel);
723 cb->cb_thresh = sc->sc_au.au_lowat;
724 break;
725 }
726 splx(s);
727 return (0);
728 }
729
730 #ifdef AUDIO_C_HANDLER
731 int
audiohwintr(au0)732 audiohwintr(au0)
733 void *au0;
734 {
735 #ifdef SUNOS
736 register struct auio *au = audio_au;
737 #else
738 register struct auio *au = au0;
739 #endif
740 register volatile struct amd7930 *amd = au->au_amd;
741 register struct aucb *cb;
742 register int h, t, k;
743
744 k = amd->ir; /* clear interrupt */
745 ++au->au_stamp;
746
747 /* receive incoming data */
748 cb = &au->au_rb;
749 h = cb->cb_head;
750 t = cb->cb_tail;
751 k = AUCB_MOD(t + 1);
752 if (h == k)
753 cb->cb_drops++;
754 else if (cb->cb_pause != 0)
755 cb->cb_pdrops++;
756 else {
757 cb->cb_data[t] = amd->bbrb;
758 cb->cb_tail = t = k;
759 }
760 if (AUCB_MOD(t - h) >= cb->cb_thresh) {
761 cb->cb_thresh = AUCB_SIZE;
762 cb->cb_waking = 1;
763 AUDIO_SET_SWINTR;
764 }
765 /* send outgoing data */
766 cb = &au->au_wb;
767 h = cb->cb_head;
768 t = cb->cb_tail;
769 if (h == t)
770 cb->cb_drops++;
771 else if (cb->cb_pause != 0)
772 cb->cb_pdrops++;
773 else {
774 cb->cb_head = h = AUCB_MOD(h + 1);
775 amd->bbtb = cb->cb_data[h];
776 }
777 if (AUCB_MOD(t - h) <= cb->cb_thresh) {
778 cb->cb_thresh = -1;
779 cb->cb_waking = 1;
780 AUDIO_SET_SWINTR;
781 }
782 return (1);
783 }
784 #endif
785
786 /* ARGSUSED */
787 int
audioswintr(sc0)788 audioswintr(sc0)
789 void *sc0;
790 {
791 register struct audio_softc *sc;
792 register int s, ret = 0;
793 #ifdef SUNOS
794 sc = &audio_softc;
795 #else
796 sc = sc0;
797 #endif
798 s = splaudio();
799 if (sc->sc_au.au_rb.cb_waking != 0) {
800 sc->sc_au.au_rb.cb_waking = 0;
801 splx(s);
802 ret = 1;
803 wakeup((caddr_t)&sc->sc_au.au_rb);
804 SELWAKEUP(&sc->sc_rsel);
805 }
806 if (sc->sc_au.au_wb.cb_waking != 0) {
807 sc->sc_au.au_wb.cb_waking = 0;
808 splx(s);
809 ret = 1;
810 wakeup((caddr_t)&sc->sc_au.au_wb);
811 SELWAKEUP(&sc->sc_wsel);
812 } else
813 splx(s);
814 return (ret);
815 }
816
817 /* Write 16 bits of data from variable v to the data port of the audio chip */
818
819 #define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8)
820
821 void
audio_setmap(amd,map)822 audio_setmap(amd, map)
823 register volatile struct amd7930 *amd;
824 register struct mapreg *map;
825 {
826 register int i, s, v;
827
828 s = splaudio();
829 amd->cr = AMDR_MAP_1_10;
830 for (i = 0; i < 8; i++) {
831 v = map->mr_x[i];
832 WAMD16(amd, v);
833 }
834 for (i = 0; i < 8; ++i) {
835 v = map->mr_r[i];
836 WAMD16(amd, v);
837 }
838 v = map->mr_gx; WAMD16(amd, v);
839 v = map->mr_gr; WAMD16(amd, v);
840 v = map->mr_ger; WAMD16(amd, v);
841 v = map->mr_stgr; WAMD16(amd, v);
842 v = map->mr_ftgr; WAMD16(amd, v);
843 v = map->mr_atgr; WAMD16(amd, v);
844 amd->dr = map->mr_mmr1;
845 amd->dr = map->mr_mmr2;
846 splx(s);
847 }
848
849 /*
850 * Set the mmr1 register and one other 16 bit register in the audio chip.
851 * The other register is indicated by op and val.
852 */
853 void
audio_setmmr1(amd,mmr1,op,val)854 audio_setmmr1(amd, mmr1, op, val)
855 register volatile struct amd7930 *amd;
856 register int mmr1;
857 register int op;
858 register int val;
859 {
860 register int s = splaudio();
861
862 amd->cr = AMDR_MAP_MMR1;
863 amd->dr = mmr1;
864 amd->cr = op;
865 WAMD16(amd, val);
866 splx(s);
867 }
868
869 /*
870 * Set the mmr2 register.
871 */
872 static void
audio_setmmr2(amd,mmr2)873 audio_setmmr2(amd, mmr2)
874 register volatile struct amd7930 *amd;
875 register int mmr2;
876 {
877 register int s = splaudio();
878
879 amd->cr = AMDR_MAP_MMR2;
880 amd->dr = mmr2;
881 splx(s);
882 }
883
884 /*
885 * gx, gr & stg gains. this table must contain 256 elements with
886 * the 0th being "infinity" (the magic value 9008). The remaining
887 * elements match sun's gain curve (but with higher resolution):
888 * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
889 */
890 static const u_short gx_coeff[256] = {
891 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
892 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
893 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
894 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
895 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
896 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
897 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
898 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
899 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
900 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
901 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
902 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
903 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
904 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
905 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
906 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
907 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
908 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
909 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
910 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
911 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
912 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
913 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
914 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
915 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
916 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
917 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
918 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
919 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
920 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
921 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
922 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
923 };
924
925 /*
926 * second stage play gain.
927 */
928 static const u_short ger_coeff[] = {
929 0x431f, /* 5. dB */
930 0x331f, /* 5.5 dB */
931 0x40dd, /* 6. dB */
932 0x11dd, /* 6.5 dB */
933 0x440f, /* 7. dB */
934 0x411f, /* 7.5 dB */
935 0x311f, /* 8. dB */
936 0x5520, /* 8.5 dB */
937 0x10dd, /* 9. dB */
938 0x4211, /* 9.5 dB */
939 0x410f, /* 10. dB */
940 0x111f, /* 10.5 dB */
941 0x600b, /* 11. dB */
942 0x00dd, /* 11.5 dB */
943 0x4210, /* 12. dB */
944 0x110f, /* 13. dB */
945 0x7200, /* 14. dB */
946 0x2110, /* 15. dB */
947 0x2200, /* 15.9 dB */
948 0x000b, /* 16.9 dB */
949 0x000f /* 18. dB */
950 #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
951 };
952
953 static void
ausetrgain(sc,level)954 ausetrgain(sc, level)
955 register struct audio_softc *sc;
956 register int level;
957 {
958 level &= 0xff;
959 sc->sc_rlevel = level;
960 sc->sc_map.mr_mmr1 |= AMD_MMR1_GX;
961 sc->sc_map.mr_gx = gx_coeff[level];
962 audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
963 AMDR_MAP_GX, sc->sc_map.mr_gx);
964 }
965
966 static void
ausetpgain(sc,level)967 ausetpgain(sc, level)
968 register struct audio_softc *sc;
969 register int level;
970 {
971 register int gi, s;
972 register volatile struct amd7930 *amd;
973
974 level &= 0xff;
975 sc->sc_plevel = level;
976 sc->sc_map.mr_mmr1 |= AMD_MMR1_GER|AMD_MMR1_GR;
977 level *= 256 + NGER;
978 level >>= 8;
979 if (level >= 256) {
980 gi = level - 256;
981 level = 255;
982 } else
983 gi = 0;
984 sc->sc_map.mr_ger = ger_coeff[gi];
985 sc->sc_map.mr_gr = gx_coeff[level];
986
987 amd = sc->sc_au.au_amd;
988 s = splaudio();
989 amd->cr = AMDR_MAP_MMR1;
990 amd->dr = sc->sc_map.mr_mmr1;
991 amd->cr = AMDR_MAP_GR;
992 gi = sc->sc_map.mr_gr;
993 WAMD16(amd, gi);
994 amd->cr = AMDR_MAP_GER;
995 gi = sc->sc_map.mr_ger;
996 WAMD16(amd, gi);
997 splx(s);
998 }
999
1000 static void
ausetmgain(sc,level)1001 ausetmgain(sc, level)
1002 register struct audio_softc *sc;
1003 register int level;
1004 {
1005 level &= 0xff;
1006 sc->sc_mlevel = level;
1007 sc->sc_map.mr_mmr1 |= AMD_MMR1_STG;
1008 sc->sc_map.mr_stgr = gx_coeff[level];
1009 audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
1010 AMDR_MAP_STG, sc->sc_map.mr_stgr);
1011 }
1012
1013 static int
audiosetinfo(sc,ai)1014 audiosetinfo(sc, ai)
1015 struct audio_softc *sc;
1016 struct audio_info *ai;
1017 {
1018 struct audio_prinfo *r = &ai->record, *p = &ai->play;
1019 register int s, bsize;
1020
1021 if (p->gain != ~0)
1022 ausetpgain(sc, p->gain);
1023 if (r->gain != ~0)
1024 ausetrgain(sc, r->gain);
1025 if (ai->monitor_gain != ~0)
1026 ausetmgain(sc, ai->monitor_gain);
1027 if (p->port == AUDIO_SPEAKER) {
1028 sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
1029 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1030 } else if (p->port == AUDIO_HEADPHONE) {
1031 sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
1032 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1033 }
1034 if (p->pause != (u_char)~0)
1035 sc->sc_au.au_wb.cb_pause = p->pause;
1036 if (r->pause != (u_char)~0)
1037 sc->sc_au.au_rb.cb_pause = r->pause;
1038
1039 if (ai->blocksize != ~0) {
1040 if (ai->blocksize == 0)
1041 bsize = ai->blocksize = DEFBLKSIZE;
1042 else if (ai->blocksize > MAXBLKSIZE)
1043 bsize = ai->blocksize = MAXBLKSIZE;
1044 else
1045 bsize = ai->blocksize;
1046
1047 s = splaudio();
1048 sc->sc_au.au_blksize = bsize;
1049 /* AUDIO_FLUSH */
1050 AUCB_INIT(&sc->sc_au.au_rb);
1051 AUCB_INIT(&sc->sc_au.au_wb);
1052 splx(s);
1053
1054 }
1055 if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE)
1056 sc->sc_au.au_hiwat = ai->hiwat;
1057 if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE)
1058 sc->sc_au.au_lowat = ai->lowat;
1059 if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2))
1060 sc->sc_au.au_backlog = ai->backlog;
1061
1062 return (0);
1063 }
1064
1065 static int
sunaudiosetinfo(sc,ai)1066 sunaudiosetinfo(sc, ai)
1067 struct audio_softc *sc;
1068 struct sun_audio_info *ai;
1069 {
1070 struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
1071
1072 if (p->gain != ~0)
1073 ausetpgain(sc, p->gain);
1074 if (r->gain != ~0)
1075 ausetrgain(sc, r->gain);
1076 if (ai->monitor_gain != ~0)
1077 ausetmgain(sc, ai->monitor_gain);
1078 if (p->port == AUDIO_SPEAKER) {
1079 sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
1080 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1081 } else if (p->port == AUDIO_HEADPHONE) {
1082 sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
1083 audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1084 }
1085 /*
1086 * The bsd driver does not distinguish between paused and active.
1087 * (In the sun driver, not active means samples are not ouput
1088 * at all, but paused means the last streams buffer is drained
1089 * and then output stops.) If either are 0, then when stop output.
1090 * Otherwise, if either are non-zero, we resume.
1091 */
1092 if (p->pause == 0 || p->active == 0)
1093 sc->sc_au.au_wb.cb_pause = 0;
1094 else if (p->pause != (u_char)~0 || p->active != (u_char)~0)
1095 sc->sc_au.au_wb.cb_pause = 1;
1096 if (r->pause == 0 || r->active == 0)
1097 sc->sc_au.au_rb.cb_pause = 0;
1098 else if (r->pause != (u_char)~0 || r->active != (u_char)~0)
1099 sc->sc_au.au_rb.cb_pause = 1;
1100
1101 return (0);
1102 }
1103
1104 static int
audiogetinfo(sc,ai)1105 audiogetinfo(sc, ai)
1106 struct audio_softc *sc;
1107 struct audio_info *ai;
1108 {
1109 struct audio_prinfo *r = &ai->record, *p = &ai->play;
1110
1111 p->sample_rate = r->sample_rate = 8000;
1112 p->channels = r->channels = 1;
1113 p->precision = r->precision = 8;
1114 p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
1115
1116 ai->monitor_gain = sc->sc_mlevel;
1117 r->gain = sc->sc_rlevel;
1118 p->gain = sc->sc_plevel;
1119 r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
1120 AUDIO_SPEAKER : AUDIO_HEADPHONE;
1121
1122 p->pause = sc->sc_au.au_wb.cb_pause;
1123 r->pause = sc->sc_au.au_rb.cb_pause;
1124 p->error = sc->sc_au.au_wb.cb_drops != 0;
1125 r->error = sc->sc_au.au_rb.cb_drops != 0;
1126
1127 p->open = sc->sc_open;
1128 r->open = sc->sc_open;
1129
1130 p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
1131 r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
1132
1133 p->seek = sc->sc_wseek;
1134 r->seek = sc->sc_rseek;
1135
1136 ai->blocksize = sc->sc_au.au_blksize;
1137 ai->hiwat = sc->sc_au.au_hiwat;
1138 ai->lowat = sc->sc_au.au_lowat;
1139 ai->backlog = sc->sc_au.au_backlog;
1140
1141 return (0);
1142 }
1143
1144 static int
sunaudiogetinfo(sc,ai)1145 sunaudiogetinfo(sc, ai)
1146 struct audio_softc *sc;
1147 struct sun_audio_info *ai;
1148 {
1149 struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
1150
1151 p->sample_rate = r->sample_rate = 8000;
1152 p->channels = r->channels = 1;
1153 p->precision = r->precision = 8;
1154 p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
1155
1156 ai->monitor_gain = sc->sc_mlevel;
1157 r->gain = sc->sc_rlevel;
1158 p->gain = sc->sc_plevel;
1159 r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
1160 AUDIO_SPEAKER : AUDIO_HEADPHONE;
1161
1162 p->active = p->pause = sc->sc_au.au_wb.cb_pause;
1163 r->active = r->pause = sc->sc_au.au_rb.cb_pause;
1164 p->error = sc->sc_au.au_wb.cb_drops != 0;
1165 r->error = sc->sc_au.au_rb.cb_drops != 0;
1166
1167 p->waiting = 0;
1168 r->waiting = 0;
1169 p->eof = 0;
1170 r->eof = 0;
1171
1172 p->open = sc->sc_open;
1173 r->open = sc->sc_open;
1174
1175 p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
1176 r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
1177
1178 return (0);
1179 }
1180 #endif
1181