xref: /csrg-svn/sys/sparc/dev/bsd_audio.c (revision 55102)
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  * %sccs.include.redist.c%
10  *
11  *	@(#)bsd_audio.c	7.1 (Berkeley) 07/13/92
12  *
13  * from: $Header: bsd_audio.c,v 1.14 92/07/03 23:21:23 mccanne Exp $ (LBL)
14  */
15 #include "bsdaudio.h"
16 #if NBSDAUDIO > 0
17 
18 #include "sys/param.h"
19 #include "sys/systm.h"
20 
21 #if BSD < 199103
22 #ifndef SUNOS
23 #define SUNOS
24 #endif
25 #endif
26 
27 #include "sys/errno.h"
28 #include "sys/file.h"
29 #include "sys/proc.h"
30 #include "sys/user.h"
31 #include "sys/vnode.h"
32 #include "sys/ioctl.h"
33 #include "sys/time.h"
34 #ifndef SUNOS
35 #include "sys/tty.h"
36 #endif
37 #include "sys/uio.h"
38 
39 #ifdef SUNOS
40 #include <sundev/mbvar.h>
41 #include <sun4c/intreg.h>
42 #else
43 #include "sys/device.h"
44 #include "machine/autoconf.h"
45 #endif
46 #include "machine/cpu.h"
47 
48 /*
49  * Avoid name clashes with SunOS so we can config either the bsd or sun
50  * streams driver in a SunOS kernel.
51  */
52 #ifdef SUNOS
53 #include "sbusdev/bsd_audioreg.h"
54 #include "sbusdev/bsd_audiovar.h"
55 #include "sbusdev/bsd_audioio.h"
56 struct selinfo {
57 	struct proc *si_proc;
58 	int si_coll;
59 };
60 #else
61 #include "../dev/bsd_audioreg.h"
62 #include "../dev/bsd_audiovar.h"
63 #include "machine/bsd_audioio.h"
64 #endif
65 
66 #ifdef SUNOS
67 #include "bsd_audiocompat.h"
68 #endif
69 
70 /*
71  * Initial/default block size is patchable.
72  */
73 int audio_blocksize = DEFBLKSIZE;
74 
75 /*
76  * Software state, per AMD79C30 audio chip.
77  */
78 struct audio_softc {
79 #ifndef SUNOS
80 	struct	device sc_dev;		/* base device */
81 	struct	intrhand sc_hwih;	/* hardware interrupt vector */
82 	struct	intrhand sc_swih;	/* software interrupt vector */
83 #endif
84 	int	sc_interrupts;		/* number of interrupts taken */
85 
86 	int	sc_open;		/* single use device */
87 	u_long	sc_wseek;		/* timestamp of last frame written */
88 	u_long	sc_rseek;		/* timestamp of last frame read */
89 	struct	mapreg sc_map;		/* current contents of map registers */
90 	struct	selinfo sc_wsel;	/* write selector */
91 	struct	selinfo sc_rsel;	/* read selector */
92 	/*
93 	 * keep track of levels so we don't have to convert back from
94 	 * MAP gain constants
95 	 */
96 	int	sc_rlevel;		/* record level */
97 	int	sc_plevel;		/* play level */
98 	int	sc_mlevel;		/* monitor level */
99 
100 	/* sc_au is special in that the hardware interrupt handler uses it */
101 	struct	auio sc_au;		/* recv and xmit buffers, etc */
102 
103 };
104 
105 /* interrupt interfaces */
106 #ifndef AUDIO_C_HANDLER
107 int	audiohwintr __P((void *));
108 #endif
109 int	audioswintr __P((void *));
110 
111 /* forward declarations */
112 int	audio_sleep __P((struct aucb *, int));
113 void	audio_setmap __P((volatile struct amd7930 *, struct mapreg *));
114 
115 static void init_amd();
116 
117 #if !defined(AUDIO_C_HANDLER) || defined(SUNOS)
118 struct auio *audio_au;
119 extern void audio_trap();
120 #endif
121 
122 #ifdef SUNOS
123 struct audio_softc audio_softc;
124 #define SOFTC(dev) &audio_softc
125 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio)
126 
127 #define AUDIOOPEN(d, f, i, p)\
128 	audioopen(d, f, i)\
129 	dev_t d; int f, i;
130 #define AUDIOCLOSE(d, f, i, p)\
131 	audioclose(d, f, i)\
132 	dev_t d; int f, i;
133 #define AUDIOREAD(d, u, f) \
134 	audioread(d, u) dev_t d; struct uio *u;
135 #define AUDIOWRITE(d, u, f) \
136 	audiowrite(d, u) dev_t d; struct uio *u;
137 #define AUDIOIOCTL(d, c, a, f, o)\
138 	audioioctl(d, c, a, f)\
139 	dev_t d; int c; caddr_t a; int f;
140 #define AUDIOSELECT(d, r, p)\
141 	audio_select(d, r, p)\
142 	dev_t d; int r; struct proc *p;
143 
144 
145 #define AUDIO_SET_SWINTR set_intreg(IR_SOFT_INT4, 1)
146 
147 int
148 audioselect(dev, rw)
149 	register dev_t dev;
150 	int rw;
151 {
152 	return (audio_select(dev, rw, u.u_procp));
153 }
154 
155 static void
156 selrecord(p, si)
157 	struct proc *p;
158 	struct selinfo *si;
159 {
160 	if (si->si_proc != 0)
161 		si->si_coll = 1;
162 	else
163 		si->si_proc = p;
164 }
165 #define SELWAKEUP(si) \
166 {\
167 	 if ((si)->si_proc != 0) {\
168 		selwakeup((si)->si_proc, (si)->si_coll); \
169 		(si)->si_proc = 0;\
170 		(si)->si_coll = 0;\
171 	}\
172 }
173 
174 
175 static int audioattach();
176 static int audioidentify();
177 
178 struct dev_ops bsdaudio_ops = {
179 	0,
180 	audioidentify,
181 	audioattach,
182 };
183 
184 static int
185 audioidentify(cp)
186 	char *cp;
187 {
188 	return (strcmp(cp, "audio") == 0);
189 }
190 
191 static int
192 audioattach(dev)
193 	struct dev_info *dev;
194 {
195 	register struct audio_softc *sc;
196 	register volatile struct amd7930 *amd;
197 	struct dev_reg *reg;
198 
199 	sc = &audio_softc;
200 	if (dev->devi_nreg != 1 || dev->devi_nintr != 1) {
201 		printf("audio: bad config\n");
202                 return (-1);
203         }
204 	reg = dev->devi_reg;
205 	amd = (struct amd7930 *)map_regs(reg->reg_addr, reg->reg_size,
206 					 reg->reg_bustype);
207 	sc->sc_au.au_amd = amd;
208 	init_amd(amd);
209 
210 	audio_au = &sc->sc_au;
211 #ifndef AUDIO_C_HANDLER
212 	settrap(dev->devi_intr->int_pri, audio_trap);
213 #else
214 	/* XXX */
215 	addintr(dev->devi_intr->int_pri, audiohwintr, dev->devi_name,
216 		dev->devi_unit);
217 #endif
218 	addintr(4, audioswintr, dev->devi_name, dev->devi_unit);
219 	report_dev(dev);
220 
221 	return (0);
222 }
223 #else
224 #define AUDIOOPEN(d, f, i, p) audioopen(dev_t d, int f, int i, struct proc *p)
225 #define AUDIOCLOSE(d, f, i, p) audioclose(dev_t d, int f, int i, \
226 					  struct proc *p)
227 #define AUDIOREAD(d, u, f) audioread(dev_t d, struct uio *u, int f)
228 #define AUDIOWRITE(d, u, f) audiowrite(dev_t d, struct uio *u, int f)
229 #define AUDIOIOCTL(d, c, a, f, o)\
230 	audioioctl(dev_t dev, int c, caddr_t a, int f, struct proc *p)
231 #define AUDIOSELECT(d, r, p) audioselect(dev_t dev, int rw, struct proc *p)
232 #define SELWAKEUP selwakeup
233 
234 #define AUDIO_SET_SWINTR ienab_bis(IE_L6)
235 
236 /* autoconfiguration driver */
237 void	audioattach(struct device *, struct device *, void *);
238 struct	cfdriver audiocd =
239     { NULL, "audio", matchbyname, audioattach,
240       DV_DULL, sizeof(struct audio_softc) };
241 #define SOFTC(dev) audiocd.cd_devs[minor(dev)]
242 #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio)
243 
244 /*
245  * Audio chip found.
246  */
247 void
248 audioattach(parent, self, args)
249 	struct device *parent, *self;
250 	void *args;
251 {
252 	register struct audio_softc *sc = (struct audio_softc *)self;
253 	register struct romaux *ra = args;
254 	register volatile struct amd7930 *amd;
255 	register int pri;
256 
257 	if (ra->ra_nintr != 1) {
258 		printf(": expected 1 interrupt, got %d\n", ra->ra_nintr);
259 		return;
260 	}
261 	pri = ra->ra_intr[0].int_pri;
262 	printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT);
263 	amd = (volatile struct amd7930 *)(ra->ra_vaddr ?
264 	    ra->ra_vaddr : mapiodev(ra->ra_paddr, sizeof *amd));
265 	sc->sc_au.au_amd = amd;
266 
267 	init_amd(amd);
268 
269 #ifndef AUDIO_C_HANDLER
270 	audio_au = &sc->sc_au;
271 	intr_fasttrap(pri, audio_trap);
272 #else
273 	sc->sc_hwih.ih_fun = audiohwintr;
274 	sc->sc_hwih.ih_arg = &sc->sc_au;
275 	intr_establish(pri, &sc->sc_hwih);
276 #endif
277 	sc->sc_swih.ih_fun = audioswintr;
278 	sc->sc_swih.ih_arg = sc;
279 	intr_establish(PIL_AUSOFT, &sc->sc_swih);
280 }
281 #endif
282 
283 static void
284 init_amd(amd)
285 	register volatile struct amd7930 *amd;
286 {
287 	/* disable interrupts */
288 	amd->cr = AMDR_INIT;
289 	amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
290 
291 	/*
292 	 * Initialize the mux unit.  We use MCR3 to route audio (MAP)
293 	 * through channel Bb.  MCR1 and MCR2 are unused.
294 	 * Setting the INT enable bit in MCR4 will generate an interrupt
295 	 * on each converted audio sample.
296 	 */
297 	amd->cr = AMDR_MUX_1_4;
298  	amd->dr = 0;
299 	amd->dr = 0;
300 	amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA;
301 	amd->dr = AMD_MCR4_INT_ENABLE;
302 }
303 
304 static int audio_default_level = 150;
305 static void ausetrgain __P((struct audio_softc *, int));
306 static void ausetpgain __P((struct audio_softc *, int));
307 static int audiosetinfo __P((struct audio_softc *, struct audio_info *));
308 static int audiogetinfo __P((struct audio_softc *, struct audio_info *));
309 struct sun_audio_info;
310 static int sunaudiosetinfo __P((struct audio_softc *,
311 				struct sun_audio_info *));
312 static int sunaudiogetinfo __P((struct audio_softc *,
313 				struct sun_audio_info *));
314 static void audio_setmmr2 __P((volatile struct amd7930 *, int));
315 
316 int
317 AUDIOOPEN(dev, flags, ifmt, p)
318 {
319 	register struct audio_softc *sc;
320 	register volatile struct amd7930 *amd;
321 	int unit = minor(dev), error, s;
322 
323 #ifdef SUNOS
324 	if (unit > 0)
325 		return (ENXIO);
326 	sc = &audio_softc;
327 #else
328 	if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL)
329 		return (ENXIO);
330 #endif
331 	if (sc->sc_open)
332 		return (EBUSY);
333 	sc->sc_open = 1;
334 
335 	sc->sc_au.au_lowat = audio_blocksize;
336 	sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat;
337 	sc->sc_au.au_blksize = audio_blocksize;
338 
339 	/* set up read and write blocks and `dead sound' zero value. */
340 	AUCB_INIT(&sc->sc_au.au_rb);
341 	sc->sc_au.au_rb.cb_thresh = AUCB_SIZE;
342 	AUCB_INIT(&sc->sc_au.au_wb);
343 	sc->sc_au.au_wb.cb_thresh = -1;
344 
345 	/* nothing read or written yet */
346 	sc->sc_rseek = 0;
347 	sc->sc_wseek = 0;
348 
349 	bzero((char *)&sc->sc_map, sizeof sc->sc_map);
350 	/* default to speaker */
351 	sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS;
352 
353 	/* enable interrupts and set parameters established above */
354 	amd = sc->sc_au.au_amd;
355 	audio_setmmr2(amd, sc->sc_map.mr_mmr2);
356 	ausetrgain(sc, audio_default_level);
357 	ausetpgain(sc, audio_default_level);
358 	amd->cr = AMDR_INIT;
359 	amd->dr = AMD_INIT_PMS_ACTIVE;
360 
361 	return (0);
362 }
363 
364 static int
365 audio_drain(sc)
366 	register struct audio_softc *sc;
367 {
368 	register int error;
369 
370 	while (!AUCB_EMPTY(&sc->sc_au.au_wb))
371 		if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0)
372 			return (error);
373 	return (0);
374 }
375 
376 /*
377  * Close an audio chip.
378  */
379 /* ARGSUSED */
380 int
381 AUDIOCLOSE(dev, flags, ifmt, p)
382 {
383 	register struct audio_softc *sc = SOFTC(dev);
384 	register volatile struct amd7930 *amd;
385 	register struct aucb *cb;
386 	register int s;
387 
388 	/*
389 	 * Block until output drains, but allow ^C interrupt.
390 	 */
391 	sc->sc_au.au_lowat = 0;	/* avoid excessive wakeups */
392 	s = splaudio();
393 	/*
394 	 * If there is pending output, let it drain (unless
395 	 * the output is paused).
396 	 */
397 	cb = &sc->sc_au.au_wb;
398 	if (!AUCB_EMPTY(cb) && !cb->cb_pause)
399 		(void)audio_drain(sc);
400 	/*
401 	 * Disable interrupts, clear open flag, and done.
402 	 */
403 	amd = sc->sc_au.au_amd;
404 	amd->cr = AMDR_INIT;
405 	amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
406 	splx(s);
407 	sc->sc_open = 0;
408 	return (0);
409 }
410 
411 int
412 audio_sleep(cb, thresh)
413 	register struct aucb *cb;
414 	register int thresh;
415 {
416 	register int error;
417 
418 	cb->cb_thresh = thresh;
419 	error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0);
420 	return (error);
421 }
422 
423 int
424 AUDIOREAD(dev, uio, ioflag)
425 {
426 	register struct audio_softc *sc = SOFTC(dev);
427 	register struct aucb *cb;
428 	register int s, n, head, taildata, error;
429 	register int blocksize = sc->sc_au.au_blksize;
430 
431 	if (uio->uio_resid == 0)
432 		return (0);
433 	cb = &sc->sc_au.au_rb;
434 	error = 0;
435 	s = splaudio();
436 	cb->cb_drops = 0;
437 	sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb);
438 	do {
439 		while (AUCB_LEN(cb) < blocksize) {
440 #ifndef SUNOS
441 			if (ioflag & IO_NDELAY) {
442 				error = EWOULDBLOCK;
443 				goto out;
444 			}
445 #endif
446 			if ((error = audio_sleep(cb, blocksize)) != 0)
447 				goto out;
448 		}
449 		splx(s);
450 		/*
451 		 * The space calculation can only err on the short
452 		 * side if an interrupt occurs during processing:
453 		 * only cb_tail is altered in the interrupt code.
454 		 */
455 		head = cb->cb_head;
456 		if ((n = AUCB_LEN(cb)) > uio->uio_resid)
457 			n = uio->uio_resid;
458 		taildata = AUCB_SIZE - head;
459 		if (n > taildata) {
460 			error = UIOMOVE((caddr_t)cb->cb_data + head,
461 					taildata, UIO_READ, uio);
462 			if (error == 0)
463 				error = UIOMOVE((caddr_t)cb->cb_data,
464 						n - taildata, UIO_READ, uio);
465 		} else
466 			error = UIOMOVE((caddr_t)cb->cb_data + head, n,
467 					UIO_READ, uio);
468 		if (error)
469 			return (error);
470 		head = AUCB_MOD(head + n);
471 		(void) splaudio();
472 		cb->cb_head = head;
473 	} while (uio->uio_resid >= blocksize);
474 out:
475 	splx(s);
476 	return (error);
477 }
478 
479 int
480 AUDIOWRITE(dev, uio, ioflag)
481 {
482 	register struct audio_softc *sc = SOFTC(dev);
483 	register struct aucb *cb = &sc->sc_au.au_wb;
484 	register int s, n, tail, tailspace, error, first, watermark, drops;
485 
486 	error = 0;
487 	first = 1;
488 	s = splaudio();
489 	while (uio->uio_resid > 0) {
490 		watermark = sc->sc_au.au_hiwat;
491 		while (AUCB_LEN(cb) > watermark) {
492 #ifndef SUNOS
493 			if (ioflag & IO_NDELAY) {
494 				error = EWOULDBLOCK;
495 				goto out;
496 			}
497 #endif
498 			if ((error = audio_sleep(cb, watermark)) != 0)
499 				goto out;
500 			watermark = sc->sc_au.au_lowat;
501 		}
502 		splx(s);
503 		/*
504 		 * The only value that can change on an interrupt is
505 		 * cb->cb_head.  We only pull that out once to decide
506 		 * how much to write into cb_data; if we lose a race
507 		 * and cb_head changes, we will merely be overly
508 		 * conservative.  For a legitimate time stamp,
509 		 * however, we need to synchronize the accesses to
510 		 * au_stamp and cb_head at a high ipl below.
511 		 */
512 		if ((n = AUCB_SIZE - AUCB_LEN(cb) - 1) > uio->uio_resid)
513 			n = uio->uio_resid;
514 		tail = cb->cb_tail;
515 		tailspace = AUCB_SIZE - tail;
516 		if (n > tailspace) {
517 			/* write first part at tail and rest at head */
518 			error = UIOMOVE((caddr_t)cb->cb_data + tail,
519 					tailspace, UIO_WRITE, uio);
520 			if (error == 0)
521 				error = UIOMOVE((caddr_t)cb->cb_data,
522 						n - tailspace, UIO_WRITE, uio);
523 		} else
524 			error = UIOMOVE((caddr_t)cb->cb_data + tail, n,
525 					UIO_WRITE, uio);
526 		if (error)
527 			return (error);
528 		/*
529 		 * We cannot do this outside the loop because if the
530 		 * buffer is empty, an indeterminate amount of time
531 		 * will pass before the output starts to drain.
532 		 */
533 		(void)splaudio();
534 		tail = AUCB_MOD(tail + n);
535 		if (first) {
536 			first = 0;
537 			sc->sc_wseek = sc->sc_au.au_stamp + AUCB_LEN(cb) + 1;
538 			/*
539 			 * To guarantee that a write is contiguous in the
540 			 * sample space, we clear the drop count the first
541 			 * time through.  If we later get drops, we will
542 			 * break out of the loop below, before writing
543 			 * a new frame.
544 			 * XXX I think we're one iteration too late!
545 			 */
546 			cb->cb_drops = 0;
547 		}
548 		cb->cb_tail = tail;
549 		if (cb->cb_drops != 0)
550 			break;
551 	}
552 out:
553 	splx(s);
554 	return (error);
555 }
556 
557 /* Sun audio compatibility */
558 struct sun_audio_prinfo {
559 	u_int	sample_rate;
560 	u_int	channels;
561 	u_int	precision;
562 	u_int	encoding;
563 	u_int	gain;
564 	u_int	port;
565 	u_int	reserved0[4];
566 	u_int	samples;
567 	u_int	eof;
568 	u_char	pause;
569 	u_char	error;
570 	u_char	waiting;
571 	u_char	reserved1[3];
572 	u_char	open;
573 	u_char	active;
574 };
575 struct sun_audio_info {
576 	struct sun_audio_prinfo play;
577 	struct sun_audio_prinfo record;
578 	u_int monitor_gain;
579 	u_int reserved[4];
580 };
581 
582 #ifndef SUNOS
583 #define SUNAUDIO_GETINFO	_IOR('A', 1, struct sun_audio_info)
584 #define SUNAUDIO_SETINFO	_IOWR('A', 2, struct sun_audio_info)
585 #else
586 #define SUNAUDIO_GETINFO	_IOR(A, 1, struct sun_audio_info)
587 #define SUNAUDIO_SETINFO	_IOWR(A, 2, struct sun_audio_info)
588 #endif
589 
590 int
591 AUDIOIOCTL(dev, cmd, addr, flag, p)
592 {
593 	register struct audio_softc *sc = SOFTC(dev);
594 	int error = 0, i, s;
595 
596 	switch (cmd) {
597 
598 	case AUDIO_GETMAP:
599 		bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map));
600 		break;
601 
602 	case AUDIO_SETMAP:
603 		bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map));
604 		sc->sc_map.mr_mmr2 &= 0x7f;
605 		audio_setmap(sc->sc_au.au_amd, &sc->sc_map);
606 		break;
607 
608 	case AUDIO_FLUSH:
609 		s = splaudio();
610 		AUCB_INIT(&sc->sc_au.au_rb);
611 		AUCB_INIT(&sc->sc_au.au_wb);
612 		splx(s);
613 		sc->sc_wseek = 0;
614 		sc->sc_rseek = 0;
615 		break;
616 
617 	/*
618 	 * Number of read samples dropped.  We don't know where or
619 	 * when they were dropped.
620 	 */
621 	case AUDIO_RERROR:
622 		*(int *)addr = sc->sc_au.au_rb.cb_drops != 0;
623 		break;
624 
625 	/*
626 	 * Timestamp of last frame written.
627 	 */
628 	case AUDIO_WSEEK:
629 		*(u_long *)addr = sc->sc_wseek;
630 		break;
631 
632 	case AUDIO_SETINFO:
633 		error = audiosetinfo(sc, (struct audio_info *)addr);
634 		break;
635 
636 	case AUDIO_GETINFO:
637 		error = audiogetinfo(sc, (struct audio_info *)addr);
638 		break;
639 
640 	case SUNAUDIO_GETINFO:
641 		error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr);
642 		break;
643 
644 	case SUNAUDIO_SETINFO:
645 		error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr);
646 		break;
647 
648 	case AUDIO_DRAIN:
649 		s = splaudio();
650 		error = audio_drain(sc);
651 		splx(s);
652 		break;
653 
654 	default:
655 		error = EINVAL;
656 		break;
657 	}
658 	return (error);
659 }
660 
661 int
662 AUDIOSELECT(dev, rw, p)
663 {
664 	register struct audio_softc *sc = SOFTC(dev);
665 	register struct aucb *cb;
666 	register int s = splaudio();
667 
668 	switch (rw) {
669 
670 	case FREAD:
671 		cb = &sc->sc_au.au_rb;
672 		if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) {
673 			splx(s);
674 			return (1);
675 		}
676 		selrecord(p, &sc->sc_rsel);
677 		cb->cb_thresh = sc->sc_au.au_blksize;
678 		break;
679 
680 	case FWRITE:
681 		cb = &sc->sc_au.au_wb;
682 		if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) {
683 			splx(s);
684 			return (1);
685 		}
686 		selrecord(p, &sc->sc_wsel);
687 		cb->cb_thresh = sc->sc_au.au_lowat;
688 		break;
689 	}
690 	splx(s);
691 	return (0);
692 }
693 
694 #ifdef AUDIO_C_HANDLER
695 int
696 audiohwintr(au0)
697 	void *au0;
698 {
699 #ifdef SUNOS
700 	register struct auio *au = audio_au;
701 #else
702 	register struct auio *au = au0;
703 #endif
704 	register volatile struct amd7930 *amd = au->au_amd;
705 	register struct aucb *cb;
706 	register int h, t, k;
707 
708 	k = amd->ir;		/* clear interrupt */
709 	++au->au_stamp;
710 
711 	/* receive incoming data */
712 	cb = &au->au_rb;
713 	h = cb->cb_head;
714 	t = cb->cb_tail;
715 	k = AUCB_MOD(t + 1);
716 	if (h == k)
717 		cb->cb_drops++;
718 	else if  (cb->cb_pause != 0)
719 		cb->cb_pdrops++;
720 	else {
721 		cb->cb_data[t] = amd->bbrb;
722 		cb->cb_tail = t = k;
723 	}
724 	if (AUCB_MOD(t - h) >= cb->cb_thresh) {
725 		cb->cb_thresh = AUCB_SIZE;
726 		cb->cb_waking = 1;
727 		AUDIO_SET_SWINTR;
728 	}
729 	/* send outgoing data */
730 	cb = &au->au_wb;
731 	h = cb->cb_head;
732 	t = cb->cb_tail;
733 	if (h == t)
734 		cb->cb_drops++;
735 	else if (cb->cb_pause != 0)
736 		cb->cb_pdrops++;
737 	else {
738 		cb->cb_head = h = AUCB_MOD(h + 1);
739 		amd->bbtb = cb->cb_data[h];
740 	}
741 	if (AUCB_MOD(t - h) <= cb->cb_thresh) {
742 		cb->cb_thresh = -1;
743 		cb->cb_waking = 1;
744 		AUDIO_SET_SWINTR;
745 	}
746 	return (1);
747 }
748 #endif
749 
750 int
751 audioswintr(sc0)
752 	void *sc0;
753 {
754 	register struct audio_softc *sc;
755 	register int s, ret = 0;
756 #ifdef SUNOS
757 	sc = &audio_softc;
758 #else
759 	sc = sc0;
760 #endif
761 	s = splaudio();
762 	if (sc->sc_au.au_rb.cb_waking != 0) {
763 		sc->sc_au.au_rb.cb_waking = 0;
764 		splx(s);
765 		ret = 1;
766 		wakeup((caddr_t)&sc->sc_au.au_rb);
767 		SELWAKEUP(&sc->sc_rsel);
768 		(void) splaudio();
769 	}
770 	if (sc->sc_au.au_wb.cb_waking != 0) {
771 		sc->sc_au.au_wb.cb_waking = 0;
772 		splx(s);
773 		ret = 1;
774 		wakeup((caddr_t)&sc->sc_au.au_wb);
775 		SELWAKEUP(&sc->sc_wsel);
776 	} else
777 		splx(s);
778 	return (ret);
779 }
780 
781 /* Write 16 bits of data from variable v to the data port of the audio chip */
782 
783 #define	WAMD16(amd, v) ((amd)->dr = v, (amd)->dr = v >> 8)
784 
785 void
786 audio_setmap(amd, map)
787 	register volatile struct amd7930 *amd;
788 	register struct mapreg *map;
789 {
790 	register int i, s, v;
791 
792 	s = splaudio();
793 	amd->cr = AMDR_MAP_1_10;
794 	for (i = 0; i < 8; i++) {
795 		v = map->mr_x[i];
796 		WAMD16(amd, v);
797 	}
798 	for (i = 0; i < 8; ++i) {
799 		v = map->mr_r[i];
800 		WAMD16(amd, v);
801 	}
802 	v = map->mr_gx; WAMD16(amd, v);
803 	v = map->mr_gr; WAMD16(amd, v);
804 	v = map->mr_ger; WAMD16(amd, v);
805 	v = map->mr_stgr; WAMD16(amd, v);
806 	v = map->mr_ftgr; WAMD16(amd, v);
807 	v = map->mr_atgr; WAMD16(amd, v);
808 	amd->dr = map->mr_mmr1;
809 	amd->dr = map->mr_mmr2;
810 	splx(s);
811 }
812 
813 /*
814  * Set the mmr1 register and one other 16 bit register in the audio chip.
815  * The other register is indicated by op and val.
816  */
817 void
818 audio_setmmr1(amd, mmr1, op, val)
819 	register volatile struct amd7930 *amd;
820 	register int mmr1;
821 	register int op;
822 	register int val;
823 {
824 	register int s = splaudio();
825 
826 	amd->cr = AMDR_MAP_MMR1;
827 	amd->dr = mmr1;
828 	amd->cr = op;
829 	WAMD16(amd, val);
830 	splx(s);
831 }
832 
833 /*
834  * Set only the mmr1 regsiter, and one other.
835  */
836 static void
837 audio_setmmr2(amd, mmr2)
838 	register volatile struct amd7930 *amd;
839 	register int mmr2;
840 {
841 	register int s = splaudio();
842 
843 	amd->cr = AMDR_MAP_MMR2;
844 	amd->dr = mmr2;
845 	splx(s);
846 }
847 
848 static u_short ger_coeff[] = {
849 	0xaaaa, 0x9bbb, 0x79ac, 0x099a, 0x4199, 0x3199, 0x9cde, 0x9def,
850 	0x749c, 0x549d, 0x6aae, 0xabcd, 0xabdf, 0x7429, 0x64ab, 0x6aff,
851 	0x2abd, 0xbeef, 0x5cce, 0x75cd, 0x0099, 0x554c, 0x43dd, 0x33dd,
852 	0x52ef, 0x771b, 0x5542, 0x41dd, 0x31dd, 0x441f, 0x431f, 0x331f,
853 	0x40dd, 0x11dd, 0x440f, 0x411f, 0x311f, 0x5520, 0x10dd, 0x4211,
854 	0x410f, 0x111f, 0x600b, 0x00dd, 0x4210, 0x400f, 0x110f, 0x2210,
855 	0x7200, 0x4200, 0x2110, 0x100f, 0x2200, 0x1110, 0x000b, 0x2100,
856 	0x000f,
857 #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
858 };
859 
860 static u_short gx_coeff[] = {
861 	0x0808, 0x4cb2, 0x3dac, 0x2ae5, 0x2533, 0x2222, 0x2122, 0x1fd3,
862 	0x12a2, 0x121b, 0x113b, 0x0bc3, 0x10f2, 0x03ba, 0x02ca, 0x021d,
863 	0x015a, 0x0122, 0x0112, 0x00ec, 0x0032, 0x0021, 0x0013, 0x0011,
864 	0x000e,
865 #define NGX (sizeof(gx_coeff) / sizeof(gx_coeff[0]))
866 };
867 
868 static u_short stg_coeff[] = {
869 	0x8b7c, 0x8b44, 0x8b35, 0x8b2a, 0x8b24, 0x8b22, 0x9123, 0x912e,
870 	0x912a, 0x9132, 0x913b, 0x914b, 0x91f9, 0x91c5, 0x91b6, 0x9212,
871 	0x91a4, 0x9222, 0x9232, 0x92fb, 0x92aa, 0x9327, 0x93b3, 0x94b3,
872 	0x9f91, 0x9cea, 0x9bf9, 0x9aac, 0x9a4a, 0xa222, 0xa2a2, 0xa68d,
873 	0xaaa3, 0xb242, 0xbb52, 0xcbb2, 0x0808,
874 #define NSTG (sizeof(stg_coeff) / sizeof(stg_coeff[0]))
875 };
876 
877 static void
878 ausetrgain(sc, level)
879 	register struct audio_softc *sc;
880 	register int level;
881 {
882 	level &= 0xff;
883 	sc->sc_rlevel = level;
884 	if (level != 0)
885 		sc->sc_map.mr_mmr1 |= AMD_MMR1_GX;
886 	else
887 		sc->sc_map.mr_mmr1 &=~ AMD_MMR1_GX;
888 
889 	sc->sc_map.mr_gx = gx_coeff[(level * NGX) / 256];
890 	audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
891 		      AMDR_MAP_GX, sc->sc_map.mr_gx);
892 }
893 
894 static void
895 ausetpgain(sc, level)
896 	register struct audio_softc *sc;
897 	register int level;
898 {
899 	level &= 0xff;
900 	sc->sc_plevel = level;
901 	if (level != 0)
902 		sc->sc_map.mr_mmr1 |= AMD_MMR1_GER;
903 	else
904 		sc->sc_map.mr_mmr1 &=~ AMD_MMR1_GER;
905 
906 	sc->sc_map.mr_ger = ger_coeff[(level * NGER) / 256];
907 	audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
908 		      AMDR_MAP_GER, sc->sc_map.mr_ger);
909 }
910 
911 static void
912 ausetmgain(sc, level)
913 	register struct audio_softc *sc;
914 	register int level;
915 {
916 	level &= 0xff;
917 	sc->sc_mlevel = level;
918 	if (level != 0)
919 		sc->sc_map.mr_mmr1 |= AMD_MMR1_STG;
920 	else
921 		sc->sc_map.mr_mmr1 &=~ AMD_MMR1_STG;
922 
923 	sc->sc_map.mr_stgr = stg_coeff[(level * NSTG) / 256];
924 	audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
925 		      AMDR_MAP_STG, sc->sc_map.mr_stgr);
926 }
927 
928 static int
929 audiosetinfo(sc, ai)
930 	struct audio_softc *sc;
931 	struct audio_info *ai;
932 {
933 	struct audio_prinfo *r = &ai->record, *p = &ai->play;
934 	register int s, bsize;
935 
936 	if (p->gain != ~0)
937 		ausetpgain(sc, p->gain);
938 	if (r->gain != ~0)
939 		ausetrgain(sc, r->gain);
940 	if (ai->monitor_gain != ~0)
941 		ausetmgain(sc, p->gain);
942 	if (p->port == AUDIO_SPEAKER) {
943 		sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
944 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
945 	} else if (p->port == AUDIO_HEADPHONE) {
946 		sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
947 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
948 	}
949 	if (p->pause != (u_char)~0)
950 		sc->sc_au.au_wb.cb_pause = p->pause;
951 	if (r->pause != (u_char)~0)
952 		sc->sc_au.au_rb.cb_pause = r->pause;
953 
954 	if (ai->blocksize != ~0) {
955 		if (ai->blocksize == 0)
956 			bsize = ai->blocksize = DEFBLKSIZE;
957 		else if (ai->blocksize > MAXBLKSIZE)
958 			bsize = ai->blocksize = MAXBLKSIZE;
959 		else
960 			bsize = ai->blocksize;
961 
962 		s = splaudio();
963 		sc->sc_au.au_blksize = bsize;
964 		/* AUDIO_FLUSH */
965 		AUCB_INIT(&sc->sc_au.au_rb);
966 		AUCB_INIT(&sc->sc_au.au_wb);
967 		splx(s);
968 
969 	}
970 	if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE)
971 		sc->sc_au.au_hiwat = ai->hiwat;
972 	if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE)
973 		sc->sc_au.au_lowat = ai->lowat;
974 
975 	return (0);
976 }
977 
978 static int
979 sunaudiosetinfo(sc, ai)
980 	struct audio_softc *sc;
981 	struct sun_audio_info *ai;
982 {
983 	struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
984 
985 	if (p->gain != ~0)
986 		ausetpgain(sc, p->gain);
987 	if (r->gain != ~0)
988 		ausetrgain(sc, r->gain);
989 	if (ai->monitor_gain != ~0)
990 		ausetmgain(sc, p->gain);
991 	if (p->port == AUDIO_SPEAKER) {
992 		sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
993 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
994 	} else if (p->port == AUDIO_HEADPHONE) {
995 		sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
996 		audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
997 	}
998 	/*
999 	 * The bsd driver does not distinguish between paused and active.
1000 	 * (In the sun driver, not active means samples are not ouput
1001 	 * at all, but paused means the last streams buffer is drained
1002 	 * and then output stops.)  If either are 0, then when stop output.
1003 	 * Otherwise, if either are non-zero, we resume.
1004 	 */
1005 	if (p->pause == 0 || p->active == 0)
1006 		sc->sc_au.au_wb.cb_pause = 0;
1007 	else if (p->pause != (u_char)~0 || p->active != (u_char)~0)
1008 		sc->sc_au.au_wb.cb_pause = 1;
1009 	if (r->pause == 0 || r->active == 0)
1010 		sc->sc_au.au_rb.cb_pause = 0;
1011 	else if (r->pause != (u_char)~0 || r->active != (u_char)~0)
1012 		sc->sc_au.au_rb.cb_pause = 1;
1013 
1014 	return (0);
1015 }
1016 
1017 static int
1018 audiogetinfo(sc, ai)
1019 	struct audio_softc *sc;
1020 	struct audio_info *ai;
1021 {
1022 	struct audio_prinfo *r = &ai->record, *p = &ai->play;
1023 
1024 	p->sample_rate = r->sample_rate = 8000;
1025 	p->channels = r->channels = 1;
1026 	p->precision = r->precision = 8;
1027 	p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
1028 
1029 	ai->monitor_gain = sc->sc_mlevel;
1030 	r->gain = sc->sc_rlevel;
1031 	p->gain = sc->sc_plevel;
1032 	r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
1033 		AUDIO_SPEAKER : AUDIO_HEADPHONE;
1034 
1035 	p->pause = sc->sc_au.au_wb.cb_pause;
1036 	r->pause = sc->sc_au.au_rb.cb_pause;
1037 	p->error = sc->sc_au.au_wb.cb_drops != 0;
1038 	r->error = sc->sc_au.au_rb.cb_drops != 0;
1039 
1040 	p->open = sc->sc_open;
1041 	r->open = sc->sc_open;
1042 
1043 	p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
1044 	r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
1045 
1046 	p->seek = sc->sc_wseek;
1047 	r->seek = sc->sc_rseek;
1048 
1049 	ai->blocksize = sc->sc_au.au_blksize;
1050 	ai->hiwat = sc->sc_au.au_hiwat;
1051 	ai->lowat = sc->sc_au.au_lowat;
1052 
1053 	return (0);
1054 }
1055 
1056 static int
1057 sunaudiogetinfo(sc, ai)
1058 	struct audio_softc *sc;
1059 	struct sun_audio_info *ai;
1060 {
1061 	struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
1062 
1063 	p->sample_rate = r->sample_rate = 8000;
1064 	p->channels = r->channels = 1;
1065 	p->precision = r->precision = 8;
1066 	p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
1067 
1068 	ai->monitor_gain = sc->sc_mlevel;
1069 	r->gain = sc->sc_rlevel;
1070 	p->gain = sc->sc_plevel;
1071 	r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
1072 		AUDIO_SPEAKER : AUDIO_HEADPHONE;
1073 
1074 	p->active = p->pause = sc->sc_au.au_wb.cb_pause;
1075 	r->active = r->pause = sc->sc_au.au_rb.cb_pause;
1076 	p->error = sc->sc_au.au_wb.cb_drops != 0;
1077 	r->error = sc->sc_au.au_rb.cb_drops != 0;
1078 
1079 	p->waiting = 0;
1080 	r->waiting = 0;
1081 	p->eof = 0;
1082 	r->eof = 0;
1083 
1084 	p->open = sc->sc_open;
1085 	r->open = sc->sc_open;
1086 
1087 	p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
1088 	r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
1089 
1090 	return (0);
1091 }
1092 #endif
1093