xref: /csrg-svn/sys/sparc/dev/bsd_audio.c (revision 59182)
1 /*
2  * Copyright (c) 1991, 1992 The Regents of the University of California.
3  * 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	7.4 (Berkeley) 04/20/93
17  *
18  * from: $Header: bsd_audio.c,v 1.17 93/04/20 05:31:28 torek 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
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
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
191 audioidentify(cp)
192 	char *cp;
193 {
194 	return (strcmp(cp, "audio") == 0);
195 }
196 
197 static int
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
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
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 int
324 AUDIOOPEN(dev, flags, ifmt, p)
325 {
326 	register struct audio_softc *sc;
327 	register volatile struct amd7930 *amd;
328 	int unit = minor(dev), error, s;
329 
330 #ifdef SUNOS
331 	if (unit > 0)
332 		return (ENXIO);
333 	sc = &audio_softc;
334 #else
335 	if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL)
336 		return (ENXIO);
337 #endif
338 	if (sc->sc_open)
339 		return (EBUSY);
340 	sc->sc_open = 1;
341 
342 	sc->sc_au.au_lowat = audio_blocksize;
343 	sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat;
344 	sc->sc_au.au_blksize = audio_blocksize;
345 	sc->sc_au.au_backlog = audio_backlog;
346 
347 	/* set up read and write blocks and `dead sound' zero value. */
348 	AUCB_INIT(&sc->sc_au.au_rb);
349 	sc->sc_au.au_rb.cb_thresh = AUCB_SIZE;
350 	AUCB_INIT(&sc->sc_au.au_wb);
351 	sc->sc_au.au_wb.cb_thresh = -1;
352 
353 	/* nothing read or written yet */
354 	sc->sc_rseek = 0;
355 	sc->sc_wseek = 0;
356 
357 	bzero((char *)&sc->sc_map, sizeof sc->sc_map);
358 	/* default to speaker */
359 	sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS;
360 
361 	/* enable interrupts and set parameters established above */
362 	amd = sc->sc_au.au_amd;
363 	audio_setmmr2(amd, sc->sc_map.mr_mmr2);
364 	ausetrgain(sc, audio_default_level);
365 	ausetpgain(sc, audio_default_level);
366 	ausetmgain(sc, 0);
367 	amd->cr = AMDR_INIT;
368 	amd->dr = AMD_INIT_PMS_ACTIVE;
369 
370 	return (0);
371 }
372 
373 static int
374 audio_drain(sc)
375 	register struct audio_softc *sc;
376 {
377 	register int error;
378 
379 	while (!AUCB_EMPTY(&sc->sc_au.au_wb))
380 		if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0)
381 			return (error);
382 	return (0);
383 }
384 
385 /*
386  * Close an audio chip.
387  */
388 /* ARGSUSED */
389 int
390 AUDIOCLOSE(dev, flags, ifmt, p)
391 {
392 	register struct audio_softc *sc = SOFTC(dev);
393 	register volatile struct amd7930 *amd;
394 	register struct aucb *cb;
395 	register int s;
396 
397 	/*
398 	 * Block until output drains, but allow ^C interrupt.
399 	 */
400 	sc->sc_au.au_lowat = 0;	/* avoid excessive wakeups */
401 	s = splaudio();
402 	/*
403 	 * If there is pending output, let it drain (unless
404 	 * the output is paused).
405 	 */
406 	cb = &sc->sc_au.au_wb;
407 	if (!AUCB_EMPTY(cb) && !cb->cb_pause)
408 		(void)audio_drain(sc);
409 	/*
410 	 * Disable interrupts, clear open flag, and done.
411 	 */
412 	amd = sc->sc_au.au_amd;
413 	amd->cr = AMDR_INIT;
414 	amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
415 	splx(s);
416 	sc->sc_open = 0;
417 	return (0);
418 }
419 
420 int
421 audio_sleep(cb, thresh)
422 	register struct aucb *cb;
423 	register int thresh;
424 {
425 	register int error;
426 	register int s = splaudio();
427 
428 	cb->cb_thresh = thresh;
429 	error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0);
430 	splx(s);
431 	return (error);
432 }
433 
434 int
435 AUDIOREAD(dev, uio, ioflag)
436 {
437 	register struct audio_softc *sc = SOFTC(dev);
438 	register struct aucb *cb;
439 	register int n, head, taildata, error;
440 	register int blocksize = sc->sc_au.au_blksize;
441 
442 	if (uio->uio_resid == 0)
443 		return (0);
444 	cb = &sc->sc_au.au_rb;
445 	error = 0;
446 	cb->cb_drops = 0;
447 	sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb);
448 	do {
449 		while (AUCB_LEN(cb) < blocksize) {
450 #ifndef SUNOS
451 			if (ioflag & IO_NDELAY) {
452 				error = EWOULDBLOCK;
453 				return (error);
454 			}
455 #endif
456 			if ((error = audio_sleep(cb, blocksize)) != 0)
457 				return (error);
458 		}
459 		/*
460 		 * The space calculation can only err on the short
461 		 * side if an interrupt occurs during processing:
462 		 * only cb_tail is altered in the interrupt code.
463 		 */
464 		head = cb->cb_head;
465 		if ((n = AUCB_LEN(cb)) > uio->uio_resid)
466 			n = uio->uio_resid;
467 		taildata = AUCB_SIZE - head;
468 		if (n > taildata) {
469 			error = UIOMOVE((caddr_t)cb->cb_data + head,
470 					taildata, UIO_READ, uio);
471 			if (error == 0)
472 				error = UIOMOVE((caddr_t)cb->cb_data,
473 						n - taildata, UIO_READ, uio);
474 		} else
475 			error = UIOMOVE((caddr_t)cb->cb_data + head, n,
476 					UIO_READ, uio);
477 		if (error)
478 			break;
479 		head = AUCB_MOD(head + n);
480 		cb->cb_head = head;
481 	} while (uio->uio_resid >= blocksize);
482 
483 	return (error);
484 }
485 
486 int
487 AUDIOWRITE(dev, uio, ioflag)
488 {
489 	register struct audio_softc *sc = SOFTC(dev);
490 	register struct aucb *cb = &sc->sc_au.au_wb;
491 	register int n, tail, tailspace, error, first, watermark, drops;
492 
493 	error = 0;
494 	first = 1;
495 	while (uio->uio_resid > 0) {
496 		watermark = sc->sc_au.au_hiwat;
497 		while (AUCB_LEN(cb) > watermark) {
498 #ifndef SUNOS
499 			if (ioflag & IO_NDELAY) {
500 				error = EWOULDBLOCK;
501 				return (error);
502 			}
503 #endif
504 			if ((error = audio_sleep(cb, watermark)) != 0)
505 				return (error);
506 			watermark = sc->sc_au.au_lowat;
507 		}
508 		/*
509 		 * The only value that can change on an interrupt is
510 		 * cb->cb_head.  We only pull that out once to decide
511 		 * how much to write into cb_data; if we lose a race
512 		 * and cb_head changes, we will merely be overly
513 		 * conservative.  For a legitimate time stamp,
514 		 * however, we need to synchronize the accesses to
515 		 * au_stamp and cb_head at a high ipl below.
516 		 */
517 		tail = cb->cb_tail;
518 		if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > uio->uio_resid) {
519 			n = uio->uio_resid;
520 			if (cb->cb_head == tail &&
521 			    n <= sc->sc_au.au_blksize &&
522 			    sc->sc_au.au_stamp - sc->sc_wseek > 400) {
523 				/*
524 				 * the write is 'small', the buffer is empty
525 				 * and we have been silent for at least 50ms
526 				 * so we might be dealing with an application
527 				 * that writes frames synchronously with
528 				 * reading them.  If so, we need an output
529 				 * backlog to cover scheduling delays or
530 				 * there will be gaps in the sound output.
531 				 * Also take this opportunity to reset the
532 				 * buffer pointers in case we ended up on
533 				 * a bad boundary (odd byte, blksize bytes
534 				 * from end, etc.).
535 				 */
536 				register u_int* ip;
537 				register int muzero = 0x7f7f7f7f;
538 				register int i = splaudio();
539 				cb->cb_head = cb->cb_tail = 0;
540 				splx(i);
541 				tail = sc->sc_au.au_backlog;
542 				ip = (u_int*)cb->cb_data;
543 				for (i = tail >> 2; --i >= 0; )
544 					*ip++ = muzero;
545 			}
546 		}
547 		tailspace = AUCB_SIZE - tail;
548 		if (n > tailspace) {
549 			/* write first part at tail and rest at head */
550 			error = UIOMOVE((caddr_t)cb->cb_data + tail,
551 					tailspace, UIO_WRITE, uio);
552 			if (error == 0)
553 				error = UIOMOVE((caddr_t)cb->cb_data,
554 						n - tailspace, UIO_WRITE, uio);
555 		} else
556 			error = UIOMOVE((caddr_t)cb->cb_data + tail, n,
557 					UIO_WRITE, uio);
558 		if (error)
559 			break;
560 
561 		tail = AUCB_MOD(tail + n);
562 		if (first) {
563 			register int s = splaudio();
564 			sc->sc_wseek = AUCB_LEN(cb) + sc->sc_au.au_stamp + 1;
565 			/*
566 			 * To guarantee that a write is contiguous in the
567 			 * sample space, we clear the drop count the first
568 			 * time through.  If we later get drops, we will
569 			 * break out of the loop below, before writing
570 			 * a new frame.
571 			 */
572 			cb->cb_drops = 0;
573 			cb->cb_tail = tail;
574 			splx(s);
575 			first = 0;
576 		} else {
577 			if (cb->cb_drops != 0)
578 				break;
579 			cb->cb_tail = tail;
580 		}
581 	}
582 	return (error);
583 }
584 
585 /* Sun audio compatibility */
586 struct sun_audio_prinfo {
587 	u_int	sample_rate;
588 	u_int	channels;
589 	u_int	precision;
590 	u_int	encoding;
591 	u_int	gain;
592 	u_int	port;
593 	u_int	reserved0[4];
594 	u_int	samples;
595 	u_int	eof;
596 	u_char	pause;
597 	u_char	error;
598 	u_char	waiting;
599 	u_char	reserved1[3];
600 	u_char	open;
601 	u_char	active;
602 };
603 struct sun_audio_info {
604 	struct sun_audio_prinfo play;
605 	struct sun_audio_prinfo record;
606 	u_int monitor_gain;
607 	u_int reserved[4];
608 };
609 
610 #ifndef SUNOS
611 #define SUNAUDIO_GETINFO	_IOR('A', 1, struct sun_audio_info)
612 #define SUNAUDIO_SETINFO	_IOWR('A', 2, struct sun_audio_info)
613 #else
614 #define SUNAUDIO_GETINFO	_IOR(A, 1, struct sun_audio_info)
615 #define SUNAUDIO_SETINFO	_IOWR(A, 2, struct sun_audio_info)
616 #endif
617 
618 int
619 AUDIOIOCTL(dev, cmd, addr, flag, p)
620 {
621 	register struct audio_softc *sc = SOFTC(dev);
622 	int error = 0, i, s;
623 
624 	switch (cmd) {
625 
626 	case AUDIO_GETMAP:
627 		bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map));
628 		break;
629 
630 	case AUDIO_SETMAP:
631 		bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map));
632 		sc->sc_map.mr_mmr2 &= 0x7f;
633 		audio_setmap(sc->sc_au.au_amd, &sc->sc_map);
634 		break;
635 
636 	case AUDIO_FLUSH:
637 		s = splaudio();
638 		AUCB_INIT(&sc->sc_au.au_rb);
639 		AUCB_INIT(&sc->sc_au.au_wb);
640 		sc->sc_au.au_stamp = 0;
641 		splx(s);
642 		sc->sc_wseek = 0;
643 		sc->sc_rseek = 0;
644 		break;
645 
646 	/*
647 	 * Number of read samples dropped.  We don't know where or
648 	 * when they were dropped.
649 	 */
650 	case AUDIO_RERROR:
651 		*(int *)addr = sc->sc_au.au_rb.cb_drops != 0;
652 		break;
653 
654 	/*
655 	 * How many samples will elapse until mike hears the first
656 	 * sample of what we last wrote?
657 	 */
658 	case AUDIO_WSEEK:
659 		s = splaudio();
660 		*(u_long *)addr = sc->sc_wseek - sc->sc_au.au_stamp
661 				  + AUCB_LEN(&sc->sc_au.au_rb);
662 		splx(s);
663 		break;
664 
665 	case AUDIO_SETINFO:
666 		error = audiosetinfo(sc, (struct audio_info *)addr);
667 		break;
668 
669 	case AUDIO_GETINFO:
670 		error = audiogetinfo(sc, (struct audio_info *)addr);
671 		break;
672 
673 	case SUNAUDIO_GETINFO:
674 		error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr);
675 		break;
676 
677 	case SUNAUDIO_SETINFO:
678 		error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr);
679 		break;
680 
681 	case AUDIO_DRAIN:
682 		error = audio_drain(sc);
683 		break;
684 
685 	default:
686 		error = EINVAL;
687 		break;
688 	}
689 	return (error);
690 }
691 
692 int
693 AUDIOSELECT(dev, rw, p)
694 {
695 	register struct audio_softc *sc = SOFTC(dev);
696 	register struct aucb *cb;
697 	register int s = splaudio();
698 
699 	switch (rw) {
700 
701 	case FREAD:
702 		cb = &sc->sc_au.au_rb;
703 		if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) {
704 			splx(s);
705 			return (1);
706 		}
707 		selrecord(p, &sc->sc_rsel);
708 		cb->cb_thresh = sc->sc_au.au_blksize;
709 		break;
710 
711 	case FWRITE:
712 		cb = &sc->sc_au.au_wb;
713 		if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) {
714 			splx(s);
715 			return (1);
716 		}
717 		selrecord(p, &sc->sc_wsel);
718 		cb->cb_thresh = sc->sc_au.au_lowat;
719 		break;
720 	}
721 	splx(s);
722 	return (0);
723 }
724 
725 #ifdef AUDIO_C_HANDLER
726 int
727 audiohwintr(au0)
728 	void *au0;
729 {
730 #ifdef SUNOS
731 	register struct auio *au = audio_au;
732 #else
733 	register struct auio *au = au0;
734 #endif
735 	register volatile struct amd7930 *amd = au->au_amd;
736 	register struct aucb *cb;
737 	register int h, t, k;
738 
739 	k = amd->ir;		/* clear interrupt */
740 	++au->au_stamp;
741 
742 	/* receive incoming data */
743 	cb = &au->au_rb;
744 	h = cb->cb_head;
745 	t = cb->cb_tail;
746 	k = AUCB_MOD(t + 1);
747 	if (h == k)
748 		cb->cb_drops++;
749 	else if  (cb->cb_pause != 0)
750 		cb->cb_pdrops++;
751 	else {
752 		cb->cb_data[t] = amd->bbrb;
753 		cb->cb_tail = t = k;
754 	}
755 	if (AUCB_MOD(t - h) >= cb->cb_thresh) {
756 		cb->cb_thresh = AUCB_SIZE;
757 		cb->cb_waking = 1;
758 		AUDIO_SET_SWINTR;
759 	}
760 	/* send outgoing data */
761 	cb = &au->au_wb;
762 	h = cb->cb_head;
763 	t = cb->cb_tail;
764 	if (h == t)
765 		cb->cb_drops++;
766 	else if (cb->cb_pause != 0)
767 		cb->cb_pdrops++;
768 	else {
769 		cb->cb_head = h = AUCB_MOD(h + 1);
770 		amd->bbtb = cb->cb_data[h];
771 	}
772 	if (AUCB_MOD(t - h) <= cb->cb_thresh) {
773 		cb->cb_thresh = -1;
774 		cb->cb_waking = 1;
775 		AUDIO_SET_SWINTR;
776 	}
777 	return (1);
778 }
779 #endif
780 
781 int
782 audioswintr(sc0)
783 	void *sc0;
784 {
785 	register struct audio_softc *sc;
786 	register int s, ret = 0;
787 #ifdef SUNOS
788 	sc = &audio_softc;
789 #else
790 	sc = sc0;
791 #endif
792 	s = splaudio();
793 	if (sc->sc_au.au_rb.cb_waking != 0) {
794 		sc->sc_au.au_rb.cb_waking = 0;
795 		splx(s);
796 		ret = 1;
797 		wakeup((caddr_t)&sc->sc_au.au_rb);
798 		SELWAKEUP(&sc->sc_rsel);
799 	}
800 	if (sc->sc_au.au_wb.cb_waking != 0) {
801 		sc->sc_au.au_wb.cb_waking = 0;
802 		splx(s);
803 		ret = 1;
804 		wakeup((caddr_t)&sc->sc_au.au_wb);
805 		SELWAKEUP(&sc->sc_wsel);
806 	} else
807 		splx(s);
808 	return (ret);
809 }
810 
811 /* Write 16 bits of data from variable v to the data port of the audio chip */
812 
813 #define	WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8)
814 
815 void
816 audio_setmap(amd, map)
817 	register volatile struct amd7930 *amd;
818 	register struct mapreg *map;
819 {
820 	register int i, s, v;
821 
822 	s = splaudio();
823 	amd->cr = AMDR_MAP_1_10;
824 	for (i = 0; i < 8; i++) {
825 		v = map->mr_x[i];
826 		WAMD16(amd, v);
827 	}
828 	for (i = 0; i < 8; ++i) {
829 		v = map->mr_r[i];
830 		WAMD16(amd, v);
831 	}
832 	v = map->mr_gx; WAMD16(amd, v);
833 	v = map->mr_gr; WAMD16(amd, v);
834 	v = map->mr_ger; WAMD16(amd, v);
835 	v = map->mr_stgr; WAMD16(amd, v);
836 	v = map->mr_ftgr; WAMD16(amd, v);
837 	v = map->mr_atgr; WAMD16(amd, v);
838 	amd->dr = map->mr_mmr1;
839 	amd->dr = map->mr_mmr2;
840 	splx(s);
841 }
842 
843 /*
844  * Set the mmr1 register and one other 16 bit register in the audio chip.
845  * The other register is indicated by op and val.
846  */
847 void
848 audio_setmmr1(amd, mmr1, op, val)
849 	register volatile struct amd7930 *amd;
850 	register int mmr1;
851 	register int op;
852 	register int val;
853 {
854 	register int s = splaudio();
855 
856 	amd->cr = AMDR_MAP_MMR1;
857 	amd->dr = mmr1;
858 	amd->cr = op;
859 	WAMD16(amd, val);
860 	splx(s);
861 }
862 
863 /*
864  * Set the mmr2 register.
865  */
866 static void
867 audio_setmmr2(amd, mmr2)
868 	register volatile struct amd7930 *amd;
869 	register int mmr2;
870 {
871 	register int s = splaudio();
872 
873 	amd->cr = AMDR_MAP_MMR2;
874 	amd->dr = mmr2;
875 	splx(s);
876 }
877 
878 /*
879  * gx, gr & stg gains.  this table must contain 256 elements with
880  * the 0th being "infinity" (the magic value 9008).  The remaining
881  * elements match sun's gain curve (but with higher resolution):
882  * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
883  */
884 static const u_short gx_coeff[256] = {
885 	0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
886 	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
887 	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
888 	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
889 	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
890 	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
891 	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
892 	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
893 	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
894 	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
895 	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
896 	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
897 	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
898 	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
899 	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
900 	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
901 	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
902 	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
903 	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
904 	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
905 	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
906 	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
907 	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
908 	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
909 	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
910 	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
911 	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
912 	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
913 	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
914 	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
915 	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
916 	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
917 };
918 
919 /*
920  * second stage play gain.
921  */
922 static const u_short ger_coeff[] = {
923 	0x431f, /* 5. dB */
924 	0x331f, /* 5.5 dB */
925 	0x40dd, /* 6. dB */
926 	0x11dd, /* 6.5 dB */
927 	0x440f, /* 7. dB */
928 	0x411f, /* 7.5 dB */
929 	0x311f, /* 8. dB */
930 	0x5520, /* 8.5 dB */
931 	0x10dd, /* 9. dB */
932 	0x4211, /* 9.5 dB */
933 	0x410f, /* 10. dB */
934 	0x111f, /* 10.5 dB */
935 	0x600b, /* 11. dB */
936 	0x00dd, /* 11.5 dB */
937 	0x4210, /* 12. dB */
938 	0x110f, /* 13. dB */
939 	0x7200, /* 14. dB */
940 	0x2110, /* 15. dB */
941 	0x2200, /* 15.9 dB */
942 	0x000b, /* 16.9 dB */
943 	0x000f  /* 18. dB */
944 #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
945 };
946 
947 static void
948 ausetrgain(sc, level)
949 	register struct audio_softc *sc;
950 	register int level;
951 {
952 	level &= 0xff;
953 	sc->sc_rlevel = level;
954 	sc->sc_map.mr_mmr1 |= AMD_MMR1_GX;
955 	sc->sc_map.mr_gx = gx_coeff[level];
956 	audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
957 		      AMDR_MAP_GX, sc->sc_map.mr_gx);
958 }
959 
960 static void
961 ausetpgain(sc, level)
962 	register struct audio_softc *sc;
963 	register int level;
964 {
965 	register int gi, s;
966 	register volatile struct amd7930 *amd;
967 
968 	level &= 0xff;
969 	sc->sc_plevel = level;
970 	sc->sc_map.mr_mmr1 |= AMD_MMR1_GER|AMD_MMR1_GR;
971 	level *= 256 + NGER;
972 	level >>= 8;
973 	if (level >= 256) {
974 		gi = level - 256;
975 		level = 255;
976 	} else
977 		gi = 0;
978 	sc->sc_map.mr_ger = ger_coeff[gi];
979 	sc->sc_map.mr_gr = gx_coeff[level];
980 
981 	amd = sc->sc_au.au_amd;
982 	s = splaudio();
983 	amd->cr = AMDR_MAP_MMR1;
984 	amd->dr = sc->sc_map.mr_mmr1;
985 	amd->cr = AMDR_MAP_GR;
986 	gi =  sc->sc_map.mr_gr;
987 	WAMD16(amd, gi);
988 	amd->cr = AMDR_MAP_GER;
989 	gi =  sc->sc_map.mr_ger;
990 	WAMD16(amd, gi);
991 	splx(s);
992 }
993 
994 static void
995 ausetmgain(sc, level)
996 	register struct audio_softc *sc;
997 	register int level;
998 {
999 	level &= 0xff;
1000 	sc->sc_mlevel = level;
1001 	sc->sc_map.mr_mmr1 |= AMD_MMR1_STG;
1002 	sc->sc_map.mr_stgr = gx_coeff[level];
1003 	audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
1004 		      AMDR_MAP_STG, sc->sc_map.mr_stgr);
1005 }
1006 
1007 static int
1008 audiosetinfo(sc, ai)
1009 	struct audio_softc *sc;
1010 	struct audio_info *ai;
1011 {
1012 	struct audio_prinfo *r = &ai->record, *p = &ai->play;
1013 	register int s, bsize;
1014 
1015 	if (p->gain != ~0)
1016 		ausetpgain(sc, p->gain);
1017 	if (r->gain != ~0)
1018 		ausetrgain(sc, r->gain);
1019 	if (ai->monitor_gain != ~0)
1020 		ausetmgain(sc, ai->monitor_gain);
1021 	if (p->port == AUDIO_SPEAKER) {
1022 		sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
1023 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1024 	} else if (p->port == AUDIO_HEADPHONE) {
1025 		sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
1026 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1027 	}
1028 	if (p->pause != (u_char)~0)
1029 		sc->sc_au.au_wb.cb_pause = p->pause;
1030 	if (r->pause != (u_char)~0)
1031 		sc->sc_au.au_rb.cb_pause = r->pause;
1032 
1033 	if (ai->blocksize != ~0) {
1034 		if (ai->blocksize == 0)
1035 			bsize = ai->blocksize = DEFBLKSIZE;
1036 		else if (ai->blocksize > MAXBLKSIZE)
1037 			bsize = ai->blocksize = MAXBLKSIZE;
1038 		else
1039 			bsize = ai->blocksize;
1040 
1041 		s = splaudio();
1042 		sc->sc_au.au_blksize = bsize;
1043 		/* AUDIO_FLUSH */
1044 		AUCB_INIT(&sc->sc_au.au_rb);
1045 		AUCB_INIT(&sc->sc_au.au_wb);
1046 		splx(s);
1047 
1048 	}
1049 	if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE)
1050 		sc->sc_au.au_hiwat = ai->hiwat;
1051 	if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE)
1052 		sc->sc_au.au_lowat = ai->lowat;
1053 	if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2))
1054 		sc->sc_au.au_backlog = ai->backlog;
1055 
1056 	return (0);
1057 }
1058 
1059 static int
1060 sunaudiosetinfo(sc, ai)
1061 	struct audio_softc *sc;
1062 	struct sun_audio_info *ai;
1063 {
1064 	struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
1065 
1066 	if (p->gain != ~0)
1067 		ausetpgain(sc, p->gain);
1068 	if (r->gain != ~0)
1069 		ausetrgain(sc, r->gain);
1070 	if (ai->monitor_gain != ~0)
1071 		ausetmgain(sc, ai->monitor_gain);
1072 	if (p->port == AUDIO_SPEAKER) {
1073 		sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
1074 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1075 	} else if (p->port == AUDIO_HEADPHONE) {
1076 		sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
1077 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
1078 	}
1079 	/*
1080 	 * The bsd driver does not distinguish between paused and active.
1081 	 * (In the sun driver, not active means samples are not ouput
1082 	 * at all, but paused means the last streams buffer is drained
1083 	 * and then output stops.)  If either are 0, then when stop output.
1084 	 * Otherwise, if either are non-zero, we resume.
1085 	 */
1086 	if (p->pause == 0 || p->active == 0)
1087 		sc->sc_au.au_wb.cb_pause = 0;
1088 	else if (p->pause != (u_char)~0 || p->active != (u_char)~0)
1089 		sc->sc_au.au_wb.cb_pause = 1;
1090 	if (r->pause == 0 || r->active == 0)
1091 		sc->sc_au.au_rb.cb_pause = 0;
1092 	else if (r->pause != (u_char)~0 || r->active != (u_char)~0)
1093 		sc->sc_au.au_rb.cb_pause = 1;
1094 
1095 	return (0);
1096 }
1097 
1098 static int
1099 audiogetinfo(sc, ai)
1100 	struct audio_softc *sc;
1101 	struct audio_info *ai;
1102 {
1103 	struct audio_prinfo *r = &ai->record, *p = &ai->play;
1104 
1105 	p->sample_rate = r->sample_rate = 8000;
1106 	p->channels = r->channels = 1;
1107 	p->precision = r->precision = 8;
1108 	p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
1109 
1110 	ai->monitor_gain = sc->sc_mlevel;
1111 	r->gain = sc->sc_rlevel;
1112 	p->gain = sc->sc_plevel;
1113 	r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
1114 		AUDIO_SPEAKER : AUDIO_HEADPHONE;
1115 
1116 	p->pause = sc->sc_au.au_wb.cb_pause;
1117 	r->pause = sc->sc_au.au_rb.cb_pause;
1118 	p->error = sc->sc_au.au_wb.cb_drops != 0;
1119 	r->error = sc->sc_au.au_rb.cb_drops != 0;
1120 
1121 	p->open = sc->sc_open;
1122 	r->open = sc->sc_open;
1123 
1124 	p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
1125 	r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
1126 
1127 	p->seek = sc->sc_wseek;
1128 	r->seek = sc->sc_rseek;
1129 
1130 	ai->blocksize = sc->sc_au.au_blksize;
1131 	ai->hiwat = sc->sc_au.au_hiwat;
1132 	ai->lowat = sc->sc_au.au_lowat;
1133 	ai->backlog = sc->sc_au.au_backlog;
1134 
1135 	return (0);
1136 }
1137 
1138 static int
1139 sunaudiogetinfo(sc, ai)
1140 	struct audio_softc *sc;
1141 	struct sun_audio_info *ai;
1142 {
1143 	struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
1144 
1145 	p->sample_rate = r->sample_rate = 8000;
1146 	p->channels = r->channels = 1;
1147 	p->precision = r->precision = 8;
1148 	p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
1149 
1150 	ai->monitor_gain = sc->sc_mlevel;
1151 	r->gain = sc->sc_rlevel;
1152 	p->gain = sc->sc_plevel;
1153 	r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
1154 		AUDIO_SPEAKER : AUDIO_HEADPHONE;
1155 
1156 	p->active = p->pause = sc->sc_au.au_wb.cb_pause;
1157 	r->active = r->pause = sc->sc_au.au_rb.cb_pause;
1158 	p->error = sc->sc_au.au_wb.cb_drops != 0;
1159 	r->error = sc->sc_au.au_rb.cb_drops != 0;
1160 
1161 	p->waiting = 0;
1162 	r->waiting = 0;
1163 	p->eof = 0;
1164 	r->eof = 0;
1165 
1166 	p->open = sc->sc_open;
1167 	r->open = sc->sc_open;
1168 
1169 	p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
1170 	r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
1171 
1172 	return (0);
1173 }
1174 #endif
1175