am7930.c revision 1.20
1/*	$NetBSD: am7930.c,v 1.20 1997/05/09 22:16:29 augustss Exp $	*/
2
3/*
4 * Copyright (c) 1995 Rolf Grossmann
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed by Rolf Grossmann.
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include "audio.h"
34#if NAUDIO > 0
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/errno.h>
39#include <sys/ioctl.h>
40#include <sys/device.h>
41#include <sys/proc.h>
42
43#include <machine/autoconf.h>
44#include <machine/cpu.h>
45
46#include <sys/audioio.h>
47#include <dev/audio_if.h>
48
49#include <dev/ic/am7930reg.h>
50#include <sparc/dev/amd7930var.h>
51
52#ifdef AUDIO_DEBUG
53extern void Dprintf __P((const char *, ...));
54
55int     amd7930debug = 0;
56#define DPRINTF(x)      if (amd7930debug) Dprintf x
57#else
58#define DPRINTF(x)
59#endif
60
61/*
62 * Software state, per AMD79C30 audio chip.
63 */
64struct amd7930_softc {
65	struct	device sc_dev;		/* base device */
66	struct	intrhand sc_hwih;	/* hardware interrupt vector */
67	struct	intrhand sc_swih;	/* software interrupt vector */
68
69	int	sc_open;		/* single use device */
70	int	sc_locked;		/* true when transfering data */
71	struct	mapreg sc_map;		/* current contents of map registers */
72
73	u_char	sc_rlevel;		/* record level */
74	u_char	sc_plevel;		/* play level */
75	u_char	sc_mlevel;		/* monitor level */
76	u_char	sc_out_port;		/* output port */
77
78	/* interfacing with the interrupt handlers */
79	void	(*sc_rintr)(void*);	/* input completion intr handler */
80	void	*sc_rarg;		/* arg for sc_rintr() */
81	void	(*sc_pintr)(void*);	/* output completion intr handler */
82	void	*sc_parg;		/* arg for sc_pintr() */
83
84        /* sc_au is special in that the hardware interrupt handler uses it */
85        struct  auio sc_au;		/* recv and xmit buffers, etc */
86#define sc_intrcnt	sc_au.au_intrcnt	/* statistics */
87};
88
89/* interrupt interfaces */
90#ifdef AUDIO_C_HANDLER
91int	amd7930hwintr __P((void *));
92#if defined(SUN4M)
93#define AUDIO_SET_SWINTR do {		\
94	if (CPU_ISSUN4M)		\
95		raise(0, 4);		\
96	else				\
97		ienab_bis(IE_L4);	\
98} while(0);
99#else
100#define AUDIO_SET_SWINTR ienab_bis(IE_L4)
101#endif /* defined(SUN4M) */
102#else
103struct auio *auiop;
104#endif /* AUDIO_C_HANDLER */
105int	amd7930swintr __P((void *));
106
107/* forward declarations */
108void	audio_setmap __P((volatile struct amd7930 *, struct mapreg *));
109static void init_amd __P((volatile struct amd7930 *));
110
111/* autoconfiguration driver */
112void	amd7930attach __P((struct device *, struct device *, void *));
113int	amd7930match __P((struct device *, struct cfdata *, void *));
114
115struct cfattach audio_ca = {
116	sizeof(struct amd7930_softc), amd7930match, amd7930attach
117};
118
119struct	cfdriver audio_cd = {
120	NULL, "audio", DV_DULL
121};
122
123struct audio_device amd7930_device = {
124	"amd7930",
125	"x",
126	"audio"
127};
128
129/* Write 16 bits of data from variable v to the data port of the audio chip */
130#define	WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8)
131
132/* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
133
134/*
135 * gx, gr & stg gains.  this table must contain 256 elements with
136 * the 0th being "infinity" (the magic value 9008).  The remaining
137 * elements match sun's gain curve (but with higher resolution):
138 * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
139 */
140static const u_short gx_coeff[256] = {
141	0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
142	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
143	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
144	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
145	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
146	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
147	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
148	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
149	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
150	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
151	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
152	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
153	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
154	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
155	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
156	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
157	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
158	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
159	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
160	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
161	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
162	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
163	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
164	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
165	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
166	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
167	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
168	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
169	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
170	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
171	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
172	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
173};
174
175/*
176 * second stage play gain.
177 */
178static const u_short ger_coeff[] = {
179	0x431f, /* 5. dB */
180	0x331f, /* 5.5 dB */
181	0x40dd, /* 6. dB */
182	0x11dd, /* 6.5 dB */
183	0x440f, /* 7. dB */
184	0x411f, /* 7.5 dB */
185	0x311f, /* 8. dB */
186	0x5520, /* 8.5 dB */
187	0x10dd, /* 9. dB */
188	0x4211, /* 9.5 dB */
189	0x410f, /* 10. dB */
190	0x111f, /* 10.5 dB */
191	0x600b, /* 11. dB */
192	0x00dd, /* 11.5 dB */
193	0x4210, /* 12. dB */
194	0x110f, /* 13. dB */
195	0x7200, /* 14. dB */
196	0x2110, /* 15. dB */
197	0x2200, /* 15.9 dB */
198	0x000b, /* 16.9 dB */
199	0x000f  /* 18. dB */
200#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
201};
202
203/*
204 * Define our interface to the higher level audio driver.
205 */
206int	amd7930_open __P((dev_t, int));
207void	amd7930_close __P((void *));
208int	amd7930_query_encoding __P((void *, struct audio_encoding *));
209int	amd7930_set_params __P((void *, int, struct audio_params *, struct audio_params *));
210int	amd7930_round_blocksize __P((void *, int));
211int	amd7930_set_out_port __P((void *, int));
212int	amd7930_get_out_port __P((void *));
213int	amd7930_set_in_port __P((void *, int));
214int	amd7930_get_in_port __P((void *));
215int	amd7930_commit_settings __P((void *));
216int	amd7930_start_output __P((void *, void *, int, void (*)(void *),
217				  void *));
218int	amd7930_start_input __P((void *, void *, int, void (*)(void *),
219				 void *));
220int	amd7930_halt_output __P((void *));
221int	amd7930_halt_input __P((void *));
222int	amd7930_cont_output __P((void *));
223int	amd7930_cont_input __P((void *));
224int	amd7930_getdev __P((void *, struct audio_device *));
225int	amd7930_setfd __P((void *, int));
226int	amd7930_set_port __P((void *, mixer_ctrl_t *));
227int	amd7930_get_port __P((void *, mixer_ctrl_t *));
228int	amd7930_query_devinfo __P((void *, mixer_devinfo_t *));
229
230
231struct audio_hw_if sa_hw_if = {
232	amd7930_open,
233	amd7930_close,
234	NULL,
235	amd7930_query_encoding,
236	amd7930_set_params,
237	amd7930_round_blocksize,
238	amd7930_set_out_port,
239	amd7930_get_out_port,
240	amd7930_set_in_port,
241	amd7930_get_in_port,
242	amd7930_commit_settings,
243	amd7930_start_output,
244	amd7930_start_input,
245	amd7930_halt_output,
246	amd7930_halt_input,
247	amd7930_cont_output,
248	amd7930_cont_input,
249	NULL,
250	amd7930_getdev,
251	amd7930_setfd,
252	amd7930_set_port,
253	amd7930_get_port,
254	amd7930_query_devinfo,
255	1,
256	0
257};
258
259/* autoconfig routines */
260
261int
262amd7930match(parent, cf, aux)
263	struct device *parent;
264	struct cfdata *cf;
265	void *aux;
266{
267	register struct confargs *ca = aux;
268	register struct romaux *ra = &ca->ca_ra;
269
270	if (CPU_ISSUN4)
271		return (0);
272	return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
273}
274
275/*
276 * Audio chip found.
277 */
278void
279amd7930attach(parent, self, args)
280	struct device *parent, *self;
281	void *args;
282{
283	register struct amd7930_softc *sc = (struct amd7930_softc *)self;
284	register struct confargs *ca = args;
285	register struct romaux *ra = &ca->ca_ra;
286	register volatile struct amd7930 *amd;
287	register int pri;
288
289	if (ra->ra_nintr != 1) {
290		printf(": expected 1 interrupt, got %d\n", ra->ra_nintr);
291		return;
292	}
293	pri = ra->ra_intr[0].int_pri;
294	printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT);
295	amd = (volatile struct amd7930 *)(ra->ra_vaddr ?
296		ra->ra_vaddr : mapiodev(ra->ra_reg, 0, sizeof (*amd),
297					ca->ca_bustype));
298
299	sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER |
300			     AMD_MMR1_GR | AMD_MMR1_STG;
301	sc->sc_au.au_amd = amd;
302	/* set boot defaults */
303	sc->sc_rlevel = 128;
304	sc->sc_plevel = 128;
305	sc->sc_mlevel = 0;
306	sc->sc_out_port = SUNAUDIO_SPEAKER;
307
308	init_amd(amd);
309
310#ifndef AUDIO_C_HANDLER
311	auiop = &sc->sc_au;
312	intr_fasttrap(pri, amd7930_trap);
313#else
314	sc->sc_hwih.ih_fun = amd7930hwintr;
315	sc->sc_hwih.ih_arg = &sc->sc_au;
316	intr_establish(pri, &sc->sc_hwih);
317#endif
318	sc->sc_swih.ih_fun = amd7930swintr;
319	sc->sc_swih.ih_arg = sc;
320	intr_establish(PIL_AUSOFT, &sc->sc_swih);
321
322	evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
323
324	if (audio_hardware_attach(&sa_hw_if, sc) != 0)
325		printf("audio: could not attach to audio pseudo-device driver\n");
326}
327
328static void
329init_amd(amd)
330	register volatile struct amd7930 *amd;
331{
332	/* disable interrupts */
333	amd->cr = AMDR_INIT;
334	amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
335
336	/*
337	 * Initialize the mux unit.  We use MCR3 to route audio (MAP)
338	 * through channel Bb.  MCR1 and MCR2 are unused.
339	 * Setting the INT enable bit in MCR4 will generate an interrupt
340	 * on each converted audio sample.
341	 */
342	amd->cr = AMDR_MUX_1_4;
343 	amd->dr = 0;
344	amd->dr = 0;
345	amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA;
346	amd->dr = AMD_MCR4_INT_ENABLE;
347}
348
349int
350amd7930_open(dev, flags)
351	dev_t dev;
352	int flags;
353{
354	register struct amd7930_softc *sc;
355	int unit = AUDIOUNIT(dev);
356
357	DPRINTF(("sa_open: unit %d\n",unit));
358
359	if (unit >= audio_cd.cd_ndevs)
360		return (ENODEV);
361	if ((sc = audio_cd.cd_devs[unit]) == NULL)
362		return (ENXIO);
363	if (sc->sc_open)
364		return (EBUSY);
365	sc->sc_open = 1;
366	sc->sc_locked = 0;
367	sc->sc_rintr = 0;
368	sc->sc_rarg = 0;
369	sc->sc_pintr = 0;
370	sc->sc_parg = 0;
371
372	sc->sc_au.au_rdata = 0;
373	sc->sc_au.au_pdata = 0;
374
375	DPRINTF(("saopen: ok -> sc=0x%x\n",sc));
376
377	return (0);
378}
379
380void
381amd7930_close(addr)
382	void *addr;
383{
384	register struct amd7930_softc *sc = addr;
385
386	DPRINTF(("sa_close: sc=0x%x\n", sc));
387	/*
388	 * halt i/o, clear open flag, and done.
389	 */
390	amd7930_halt_input(sc);
391	amd7930_halt_output(sc);
392	sc->sc_open = 0;
393
394	DPRINTF(("sa_close: closed.\n"));
395}
396
397int
398amd7930_set_params(addr, mode, p, q)
399	void *addr;
400	int mode;
401	struct audio_params *p, *q;
402{
403	if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
404	    p->encoding != AUDIO_ENCODING_ULAW ||
405	    p->precision != 8 ||
406	    p->channels != 1)
407		return EINVAL;
408	p->sample_rate = 8000;	/* no other sampling rates supported by amd chip */
409
410	/* Update setting for the other mode. */
411	q->sample_rate = p->sample_rate;
412	q->encoding = p->encoding;
413	q->channels = p->channels;
414	q->precision = p->precision;
415
416	return 0;
417}
418
419int
420amd7930_query_encoding(addr, fp)
421	void *addr;
422	struct audio_encoding *fp;
423{
424	switch (fp->index) {	/* ??? */
425	    case 0:
426		    strcpy(fp->name, AudioEmulaw);
427		    fp->encoding = AUDIO_ENCODING_ULAW;
428		    fp->precision = 8;
429		    fp->flags = 0;
430		    break;
431	    default:
432		    return(EINVAL);
433		    /*NOTREACHED*/
434	}
435	return(0);
436}
437
438int
439amd7930_round_blocksize(addr, blk)
440	void *addr;
441	int blk;
442{
443	return(blk);
444}
445
446int
447amd7930_set_out_port(addr, port)
448	void *addr;
449	int port;
450{
451	register struct amd7930_softc *sc = addr;
452
453	switch(port) {
454	    case SUNAUDIO_SPEAKER:
455	    case SUNAUDIO_HEADPHONES:
456		sc->sc_out_port = port;	/* set on commit */
457		break;
458	    default:
459		return(EINVAL);
460	}
461	return(0);
462}
463
464int
465amd7930_get_out_port(addr)
466	void *addr;
467{
468	register struct amd7930_softc *sc = addr;
469
470	return(sc->sc_out_port);
471}
472
473int
474amd7930_set_in_port(addr, port)
475	void *addr;
476	int port;
477{
478	if (port != SUNAUDIO_MIC_PORT)
479		return(EINVAL);
480
481	return(0);	/* only microphone input supported by amd chip */
482}
483
484int
485amd7930_get_in_port(addr)
486	void *addr;
487{
488	return(SUNAUDIO_MIC_PORT);
489}
490
491int
492amd7930_commit_settings(addr)
493	void *addr;
494{
495	register struct amd7930_softc *sc = addr;
496	register struct mapreg *map;
497	register volatile struct amd7930 *amd;
498	register int s, level;
499
500	DPRINTF(("sa_commit.\n"));
501
502	map = &sc->sc_map;
503	amd = sc->sc_au.au_amd;
504
505	map->mr_gx = gx_coeff[sc->sc_rlevel];
506	map->mr_stgr = gx_coeff[sc->sc_mlevel];
507
508	level = (sc->sc_plevel * (256 + NGER)) >> 8;
509	if (level >= 256) {
510		map->mr_ger = ger_coeff[level - 256];
511		map->mr_gr = gx_coeff[255];
512	} else {
513		map->mr_ger = ger_coeff[0];
514		map->mr_gr = gx_coeff[level];
515	}
516
517	if (sc->sc_out_port == SUNAUDIO_SPEAKER)
518		map->mr_mmr2 |= AMD_MMR2_LS;
519	else
520		map->mr_mmr2 &= ~AMD_MMR2_LS;
521
522	s = splaudio();
523
524	amd->cr = AMDR_MAP_MMR1;
525	amd->dr = map->mr_mmr1;
526	amd->cr = AMDR_MAP_GX;
527	WAMD16(amd, map->mr_gx);
528	amd->cr = AMDR_MAP_STG;
529	WAMD16(amd, map->mr_stgr);
530	amd->cr = AMDR_MAP_GR;
531	WAMD16(amd, map->mr_gr);
532	amd->cr = AMDR_MAP_GER;
533	WAMD16(amd, map->mr_ger);
534	amd->cr = AMDR_MAP_MMR2;
535	amd->dr = map->mr_mmr2;
536
537	splx(s);
538	return(0);
539}
540
541int
542amd7930_start_output(addr, p, cc, intr, arg)
543	void *addr;
544	void *p;
545	int cc;
546	void (*intr) __P((void *));
547	void *arg;
548{
549	register struct amd7930_softc *sc = addr;
550
551#ifdef AUDIO_DEBUG
552	if (amd7930debug > 1)
553		Dprintf("sa_start_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg);
554#endif
555
556	if (!sc->sc_locked) {
557		register volatile struct amd7930 *amd;
558
559		amd = sc->sc_au.au_amd;
560		amd->cr = AMDR_INIT;
561		amd->dr = AMD_INIT_PMS_ACTIVE;
562		sc->sc_locked = 1;
563		DPRINTF(("sa_start_output: started intrs.\n"));
564	}
565	sc->sc_pintr = intr;
566	sc->sc_parg = arg;
567	sc->sc_au.au_pdata = p;
568	sc->sc_au.au_pend = p + cc - 1;
569	return(0);
570}
571
572/* ARGSUSED */
573int
574amd7930_start_input(addr, p, cc, intr, arg)
575	void *addr;
576	void *p;
577	int cc;
578	void (*intr) __P((void *));
579	void *arg;
580{
581	register struct amd7930_softc *sc = addr;
582
583#ifdef AUDIO_DEBUG
584	if (amd7930debug > 1)
585		Dprintf("sa_start_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg);
586#endif
587
588	if (!sc->sc_locked) {
589		register volatile struct amd7930 *amd;
590
591		amd = sc->sc_au.au_amd;
592		amd->cr = AMDR_INIT;
593		amd->dr = AMD_INIT_PMS_ACTIVE;
594		sc->sc_locked = 1;
595		DPRINTF(("sa_start_input: started intrs.\n"));
596	}
597	sc->sc_rintr = intr;
598	sc->sc_rarg = arg;
599	sc->sc_au.au_rdata = p;
600	sc->sc_au.au_rend = p + cc -1;
601	return(0);
602}
603
604int
605amd7930_halt_output(addr)
606	void *addr;
607{
608	register struct amd7930_softc *sc = addr;
609	register volatile struct amd7930 *amd;
610
611	/* XXX only halt, if input is also halted ?? */
612	amd = sc->sc_au.au_amd;
613	amd->cr = AMDR_INIT;
614	amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
615	sc->sc_locked = 0;
616
617	return(0);
618}
619
620int
621amd7930_halt_input(addr)
622	void *addr;
623{
624	register struct amd7930_softc *sc = addr;
625	register volatile struct amd7930 *amd;
626
627	/* XXX only halt, if output is also halted ?? */
628	amd = sc->sc_au.au_amd;
629	amd->cr = AMDR_INIT;
630	amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
631	sc->sc_locked = 0;
632
633	return(0);
634}
635
636int
637amd7930_cont_output(addr)
638	void *addr;
639{
640	DPRINTF(("amd7930_cont_output: never called, what should it do?!\n"));
641	return(0);
642}
643
644int
645amd7930_cont_input(addr)
646	void *addr;
647{
648	DPRINTF(("amd7930_cont_input: never called, what should it do?!\n"));
649	return(0);
650}
651
652int
653amd7930_getdev(addr, retp)
654        void *addr;
655        struct audio_device *retp;
656{
657        *retp = amd7930_device;
658        return 0;
659}
660
661int
662amd7930_setfd(addr, flag)
663        void *addr;
664        int flag;
665{
666        /* Always full-duplex */
667        return(0);
668}
669
670int
671amd7930_set_port(addr, cp)
672	void *addr;
673	mixer_ctrl_t *cp;
674{
675	register struct amd7930_softc *sc = addr;
676
677	DPRINTF(("amd7930_set_port: port=%d", cp->dev));
678
679	if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1)
680		return(EINVAL);
681
682	switch(cp->dev) {
683	    case SUNAUDIO_MIC_PORT:
684		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
685		    break;
686	    case SUNAUDIO_SPEAKER:
687	    case SUNAUDIO_HEADPHONES:
688		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
689		    break;
690	    case SUNAUDIO_MONITOR:
691		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
692		    break;
693	    default:
694		    return(EINVAL);
695		    /* NOTREACHED */
696	}
697	return(0);
698}
699
700int
701amd7930_get_port(addr, cp)
702	void *addr;
703	mixer_ctrl_t *cp;
704{
705	register struct amd7930_softc *sc = addr;
706
707	DPRINTF(("amd7930_get_port: port=%d", cp->dev));
708
709	if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1)
710		return(EINVAL);
711
712	switch(cp->dev) {
713	    case SUNAUDIO_MIC_PORT:
714		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
715		    break;
716	    case SUNAUDIO_SPEAKER:
717	    case SUNAUDIO_HEADPHONES:
718		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
719		    break;
720	    case SUNAUDIO_MONITOR:
721		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
722		    break;
723	    default:
724		    return(EINVAL);
725		    /* NOTREACHED */
726	}
727	return(0);
728}
729
730int
731amd7930_query_devinfo(addr, dip)
732	void *addr;
733	register mixer_devinfo_t *dip;
734{
735	switch(dip->index) {
736	    case SUNAUDIO_MIC_PORT:
737		    dip->type = AUDIO_MIXER_VALUE;
738		    dip->mixer_class = SUNAUDIO_INPUT_CLASS;
739		    dip->prev = dip->next = AUDIO_MIXER_LAST;
740		    strcpy(dip->label.name, AudioNmicrophone);
741		    dip->un.v.num_channels = 1;
742		    strcpy(dip->un.v.units.name, AudioNvolume);
743		    break;
744	    case SUNAUDIO_SPEAKER:
745		    dip->type = AUDIO_MIXER_VALUE;
746		    dip->mixer_class = SUNAUDIO_OUTPUT_CLASS;
747		    dip->prev = dip->next = AUDIO_MIXER_LAST;
748		    strcpy(dip->label.name, AudioNspeaker);
749		    dip->un.v.num_channels = 1;
750		    strcpy(dip->un.v.units.name, AudioNvolume);
751		    break;
752	    case SUNAUDIO_HEADPHONES:
753		    dip->type = AUDIO_MIXER_VALUE;
754		    dip->mixer_class = SUNAUDIO_OUTPUT_CLASS;
755		    dip->prev = dip->next = AUDIO_MIXER_LAST;
756		    strcpy(dip->label.name, AudioNheadphone);
757		    dip->un.v.num_channels = 1;
758		    strcpy(dip->un.v.units.name, AudioNvolume);
759		    break;
760	    case SUNAUDIO_MONITOR:
761		    dip->type = AUDIO_MIXER_VALUE;
762		    dip->mixer_class = SUNAUDIO_OUTPUT_CLASS;
763		    dip->next = dip->prev = AUDIO_MIXER_LAST;
764		    strcpy(dip->label.name, AudioNmonitor);
765		    dip->un.v.num_channels = 1;
766		    strcpy(dip->un.v.units.name, AudioNvolume);
767		    break;
768	    case SUNAUDIO_INPUT_CLASS:
769		    dip->type = AUDIO_MIXER_CLASS;
770		    dip->mixer_class = SUNAUDIO_INPUT_CLASS;
771		    dip->next = dip->prev = AUDIO_MIXER_LAST;
772		    strcpy(dip->label.name, AudioCInputs);
773		    break;
774	    case SUNAUDIO_OUTPUT_CLASS:
775		    dip->type = AUDIO_MIXER_CLASS;
776		    dip->mixer_class = SUNAUDIO_OUTPUT_CLASS;
777		    dip->next = dip->prev = AUDIO_MIXER_LAST;
778		    strcpy(dip->label.name, AudioCOutputs);
779		    break;
780	    default:
781		    return ENXIO;
782		    /*NOTREACHED*/
783	}
784
785	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
786
787	return(0);
788}
789
790#ifdef AUDIO_C_HANDLER
791int
792amd7930hwintr(au0)
793	void *au0;
794{
795	register struct auio *au = au0;
796	register volatile struct amd7930 *amd = au->au_amd;
797	register u_char *d, *e;
798	register int k;
799
800	k = amd->ir;		/* clear interrupt */
801
802	/* receive incoming data */
803	d = au->au_rdata;
804	e = au->au_rend;
805	if (d && d <= e) {
806		*d = amd->bbrb;
807		au->au_rdata++;
808		if (d == e) {
809#ifdef AUDIO_DEBUG
810		        if (amd7930debug > 1)
811                		Dprintf("amd7930hwintr: swintr(r) requested");
812#endif
813			AUDIO_SET_SWINTR;
814		}
815	}
816
817	/* send outgoing data */
818	d = au->au_pdata;
819	e = au->au_pend;
820	if (d && d <= e) {
821		amd->bbtb = *d;
822		au->au_pdata++;
823		if (d == e) {
824#ifdef AUDIO_DEBUG
825		        if (amd7930debug > 1)
826                		Dprintf("amd7930hwintr: swintr(p) requested");
827#endif
828			AUDIO_SET_SWINTR;
829		}
830	}
831
832	*(au->au_intrcnt)++;
833	return (1);
834}
835#endif /* AUDIO_C_HANDLER */
836
837int
838amd7930swintr(sc0)
839	void *sc0;
840{
841	register struct amd7930_softc *sc = sc0;
842	register struct auio *au;
843	register int s, ret = 0;
844
845#ifdef AUDIO_DEBUG
846	if (amd7930debug > 1)
847		Dprintf("audiointr: sc=0x%x\n",sc);
848#endif
849
850	au = &sc->sc_au;
851	s = splaudio();
852	if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) {
853		splx(s);
854		ret = 1;
855		(*sc->sc_rintr)(sc->sc_rarg);
856		s = splaudio();
857	}
858	if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) {
859		splx(s);
860		ret = 1;
861		(*sc->sc_pintr)(sc->sc_parg);
862	} else
863		splx(s);
864	return (ret);
865}
866#endif /* NAUDIO > 0 */
867