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