am7930.c revision 1.43
1/*	$NetBSD: am7930.c,v 1.43 2000/05/02 06:30:51 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/*
34 * Front-end attachment independent layer for AMD 79c30
35 * audio driver.  No ISDN support.
36 */
37
38#include "audio.h"
39#if NAUDIO > 0
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/errno.h>
44#include <sys/ioctl.h>
45#include <sys/device.h>
46#include <sys/proc.h>
47
48#include <machine/bus.h>
49#include <machine/autoconf.h>
50#include <machine/cpu.h>
51
52#include <sys/audioio.h>
53#include <dev/audio_if.h>
54
55#include <dev/ic/am7930reg.h>
56#include <dev/ic/am7930var.h>
57
58#ifdef AUDIO_DEBUG
59int     am7930debug = 0;
60#define DPRINTF(x)      if (am7930debug) printf x
61#else
62#define DPRINTF(x)
63#endif
64
65
66/* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */
67
68/*
69 * gx, gr & stg gains.  this table must contain 256 elements with
70 * the 0th being "infinity" (the magic value 9008).  The remaining
71 * elements match sun's gain curve (but with higher resolution):
72 * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
73 */
74static const u_short gx_coeff[256] = {
75	0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33,
76	0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
77	0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
78	0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
79	0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
80	0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
81	0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
82	0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
83	0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
84	0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
85	0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
86	0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
87	0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
88	0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
89	0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
90	0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
91	0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
92	0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
93	0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
94	0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
95	0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
96	0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
97	0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
98	0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
99	0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
100	0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
101	0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
102	0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
103	0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
104	0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
105	0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
106	0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
107};
108
109/*
110 * second stage play gain.
111 */
112static const u_short ger_coeff[] = {
113	0x431f, /* 5. dB */
114	0x331f, /* 5.5 dB */
115	0x40dd, /* 6. dB */
116	0x11dd, /* 6.5 dB */
117	0x440f, /* 7. dB */
118	0x411f, /* 7.5 dB */
119	0x311f, /* 8. dB */
120	0x5520, /* 8.5 dB */
121	0x10dd, /* 9. dB */
122	0x4211, /* 9.5 dB */
123	0x410f, /* 10. dB */
124	0x111f, /* 10.5 dB */
125	0x600b, /* 11. dB */
126	0x00dd, /* 11.5 dB */
127	0x4210, /* 12. dB */
128	0x110f, /* 13. dB */
129	0x7200, /* 14. dB */
130	0x2110, /* 15. dB */
131	0x2200, /* 15.9 dB */
132	0x000b, /* 16.9 dB */
133	0x000f  /* 18. dB */
134#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
135};
136
137
138/*
139 * Reset chip and set boot-time softc defaults.
140 */
141void
142am7930_init(sc, flag)
143	struct am7930_softc *sc;
144	int flag;
145{
146
147	DPRINTF(("am7930_init()\n"));
148
149	/* set boot defaults */
150	sc->sc_rlevel = 128;
151	sc->sc_plevel = 128;
152	sc->sc_mlevel = 0;
153	sc->sc_out_port = AUDIOAMD_SPEAKER_VOL;
154	sc->sc_mic_mute = 0;
155
156	/* disable sample interrupts */
157	AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4, 0);
158
159	/* initialise voice and data, and disable interrupts */
160	AM7930_IWRITE(sc, AM7930_IREG_INIT,
161		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
162
163	if (flag == AUDIOAMD_DMA_MODE) {
164
165		/* configure PP for serial (SBP) mode */
166		AM7930_IWRITE(sc, AM7930_IREG_PP_PPCR1, AM7930_PPCR1_SBP);
167
168		/*
169		 * Initialise the MUX unit - route the MAP to the PP
170		 */
171		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1,
172			(AM7930_MCRCHAN_BA << 4) | AM7930_MCRCHAN_BD);
173		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, AM7930_MCRCHAN_NC);
174		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3, AM7930_MCRCHAN_NC);
175
176	} else {
177
178		/*
179		 * Initialize the MUX unit.  We use MCR3 to route the MAP
180		 * through channel Bb.  MCR1 and MCR2 are unused.
181		 * Setting the INT enable bit in MCR4 will generate an
182		 * interrupt on each converted audio sample.
183		 */
184		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR1, 0);
185		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR2, 0);
186		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR3,
187			(AM7930_MCRCHAN_BB << 4) | AM7930_MCRCHAN_BA);
188		AM7930_IWRITE(sc, AM7930_IREG_MUX_MCR4,
189			AM7930_MCR4_INT_ENABLE);
190	}
191
192}
193
194
195int
196am7930_open(addr, flags)
197	void *addr;
198	int flags;
199{
200	struct am7930_softc *sc = addr;
201
202	DPRINTF(("sa_open: unit %p\n", sc));
203
204	if (sc->sc_open)
205		return (EBUSY);
206	sc->sc_open = 1;
207	sc->sc_locked = 0;
208
209	sc->sc_glue->onopen(sc);
210
211	DPRINTF(("saopen: ok -> sc=0x%p\n",sc));
212
213	return (0);
214}
215
216void
217am7930_close(addr)
218	void *addr;
219{
220	struct am7930_softc *sc = addr;
221
222	DPRINTF(("sa_close: sc=%p\n", sc));
223
224	sc->sc_glue->onclose(sc);
225	sc->sc_open = 0;
226
227	DPRINTF(("sa_close: closed.\n"));
228}
229
230
231/*
232 * XXX should be extended to handle a few of the more common formats.
233 */
234int
235am7930_set_params(addr, setmode, usemode, p, r)
236	void *addr;
237	int setmode, usemode;
238	struct audio_params *p, *r;
239{
240	struct am7930_softc *sc = addr;
241
242	if ((usemode & AUMODE_PLAY) == AUMODE_PLAY) {
243		if (p->sample_rate < 7500 || p->sample_rate > 8500 ||
244			p->encoding != AUDIO_ENCODING_ULAW ||
245			p->precision != 8 ||
246			p->channels != 1)
247				return EINVAL;
248		p->sample_rate = 8000;
249		if (sc->sc_glue->factor > 1) {
250			p->factor = sc->sc_glue->factor;
251			p->sw_code = sc->sc_glue->output_conv;
252		}
253	}
254	if ((usemode & AUMODE_RECORD) == AUMODE_RECORD) {
255		if (r->sample_rate < 7500 || r->sample_rate > 8500 ||
256			r->encoding != AUDIO_ENCODING_ULAW ||
257			r->precision != 8 ||
258			r->channels != 1)
259				return EINVAL;
260		r->sample_rate = 8000;
261		if (sc->sc_glue->factor > 1) {
262			r->factor = sc->sc_glue->factor;
263			r->sw_code = sc->sc_glue->input_conv;
264		}
265	}
266
267	return 0;
268}
269
270int
271am7930_query_encoding(addr, fp)
272	void *addr;
273	struct audio_encoding *fp;
274{
275	switch (fp->index) {	/* ??? */
276	    case 0:
277		    strcpy(fp->name, AudioEmulaw);
278		    fp->encoding = AUDIO_ENCODING_ULAW;
279		    fp->precision = 8;
280		    fp->flags = 0;
281		    break;
282	    default:
283		    return(EINVAL);
284		    /*NOTREACHED*/
285	}
286	return(0);
287}
288
289
290int
291am7930_round_blocksize(addr, blk)
292	void *addr;
293	int blk;
294{
295	return(blk);
296}
297
298
299int
300am7930_commit_settings(addr)
301	void *addr;
302{
303	struct am7930_softc *sc = addr;
304	u_int16_t ger, gr, gx, stgr;
305	u_int8_t mmr2, mmr3;
306	int s, level;
307
308	DPRINTF(("sa_commit.\n"));
309
310	gx = gx_coeff[sc->sc_rlevel];
311	stgr = gx_coeff[sc->sc_mlevel];
312
313	level = (sc->sc_plevel * (256 + NGER)) >> 8;
314	if (level >= 256) {
315		ger = ger_coeff[level - 256];
316		gr = gx_coeff[255];
317	} else {
318		ger = ger_coeff[0];
319		gr = gx_coeff[level];
320	}
321
322	s = splaudio();
323
324	mmr2 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR2);
325	if (sc->sc_out_port == AUDIOAMD_SPEAKER_VOL)
326		mmr2 |= AM7930_MMR2_LS;
327	else
328		mmr2 &= ~AM7930_MMR2_LS;
329	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR2, mmr2);
330
331	mmr3 = AM7930_IREAD(sc, AM7930_IREG_MAP_MMR3);
332	if (sc->sc_mic_mute)
333		mmr3 |= AM7930_MMR3_MUTE;
334	else
335		mmr3 &= ~AM7930_MMR3_MUTE;
336	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR3, mmr3);
337
338	AM7930_IWRITE(sc, AM7930_IREG_MAP_MMR1,
339		AM7930_MMR1_GX | AM7930_MMR1_GER |
340		AM7930_MMR1_GR | AM7930_MMR1_STG);
341
342	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GX, gx);
343	AM7930_IWRITE16(sc, AM7930_IREG_MAP_STG, stgr);
344	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GR, gr);
345	AM7930_IWRITE16(sc, AM7930_IREG_MAP_GER, ger);
346
347	splx(s);
348
349	return(0);
350}
351
352
353int
354am7930_halt_output(addr)
355	void *addr;
356{
357	struct am7930_softc *sc = addr;
358
359	/* XXX only halt, if input is also halted ?? */
360	AM7930_IWRITE(sc, AM7930_IREG_INIT,
361		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
362	sc->sc_locked = 0;
363
364	return(0);
365}
366
367
368int
369am7930_halt_input(addr)
370	void *addr;
371{
372	struct am7930_softc *sc = addr;
373
374	/* XXX only halt, if output is also halted ?? */
375	AM7930_IWRITE(sc, AM7930_IREG_INIT,
376		AM7930_INIT_PMS_ACTIVE | AM7930_INIT_INT_DISABLE);
377	sc->sc_locked = 0;
378
379	return(0);
380}
381
382
383/*
384 * XXX chip is full-duplex, but really attach-dependent.
385 * For now we know of no half-duplex attachments.
386 */
387int
388am7930_get_props(addr)
389	void *addr;
390{
391	return AUDIO_PROP_FULLDUPLEX;
392}
393
394/*
395 * Attach-dependent channel set/query
396 */
397int
398am7930_set_port(addr, cp)
399	void *addr;
400	mixer_ctrl_t *cp;
401{
402	struct am7930_softc *sc = addr;
403
404	DPRINTF(("am7930_set_port: port=%d", cp->dev));
405
406	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
407		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
408		cp->dev == AUDIOAMD_MIC_MUTE) {
409		if (cp->type != AUDIO_MIXER_ENUM)
410			return(EINVAL);
411	} else if (cp->type != AUDIO_MIXER_VALUE ||
412					cp->un.value.num_channels != 1) {
413		return(EINVAL);
414	}
415
416	switch(cp->dev) {
417	    case AUDIOAMD_MIC_VOL:
418		    sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
419		    break;
420	    case AUDIOAMD_SPEAKER_VOL:
421	    case AUDIOAMD_HEADPHONES_VOL:
422		    sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
423		    break;
424	    case AUDIOAMD_MONITOR_VOL:
425		    sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
426		    break;
427	    case AUDIOAMD_RECORD_SOURCE:
428		    if (cp->un.ord != AUDIOAMD_MIC_VOL)
429			    return EINVAL;
430		    break;
431	    case AUDIOAMD_MIC_MUTE:
432		    sc->sc_mic_mute = cp->un.ord;
433		    break;
434	    case AUDIOAMD_MONITOR_OUTPUT:
435		    if (cp->un.ord != AUDIOAMD_SPEAKER_VOL &&
436			cp->un.ord != AUDIOAMD_HEADPHONES_VOL)
437			    return EINVAL;
438			sc->sc_out_port = cp->un.ord;
439		    break;
440	    default:
441		    return(EINVAL);
442		    /* NOTREACHED */
443	}
444	return 0;
445}
446
447int
448am7930_get_port(addr, cp)
449	void *addr;
450	mixer_ctrl_t *cp;
451{
452	struct am7930_softc *sc = addr;
453
454	DPRINTF(("am7930_get_port: port=%d\n", cp->dev));
455
456	if (cp->dev == AUDIOAMD_RECORD_SOURCE ||
457		cp->dev == AUDIOAMD_MONITOR_OUTPUT ||
458		cp->dev == AUDIOAMD_MIC_MUTE) {
459		if (cp->type != AUDIO_MIXER_ENUM)
460			return(EINVAL);
461	} else if (cp->type != AUDIO_MIXER_VALUE ||
462		cp->un.value.num_channels != 1) {
463		return(EINVAL);
464	}
465
466	switch(cp->dev) {
467	    case AUDIOAMD_MIC_VOL:
468		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel;
469		    break;
470	    case AUDIOAMD_SPEAKER_VOL:
471	    case AUDIOAMD_HEADPHONES_VOL:
472		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel;
473		    break;
474	    case AUDIOAMD_MONITOR_VOL:
475		    cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel;
476		    break;
477	    case AUDIOAMD_RECORD_SOURCE:
478		    cp->un.ord = AUDIOAMD_MIC_VOL;
479		    break;
480	    case AUDIOAMD_MIC_MUTE:
481		    cp->un.ord = sc->sc_mic_mute;
482		    break;
483	    case AUDIOAMD_MONITOR_OUTPUT:
484		    cp->un.ord = sc->sc_out_port;
485		    break;
486	    default:
487		    return(EINVAL);
488		    /* NOTREACHED */
489	}
490	return 0;
491}
492
493
494/*
495 * Define mixer control facilities.
496 */
497int
498am7930_query_devinfo(addr, dip)
499	void *addr;
500	mixer_devinfo_t *dip;
501{
502
503	DPRINTF(("am7930_query_devinfo()\n"));
504
505	switch(dip->index) {
506	    case AUDIOAMD_MIC_VOL:
507		    dip->type = AUDIO_MIXER_VALUE;
508		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
509		    dip->prev =  AUDIO_MIXER_LAST;
510		    dip->next = AUDIOAMD_MIC_MUTE;
511		    strcpy(dip->label.name, AudioNmicrophone);
512		    dip->un.v.num_channels = 1;
513		    strcpy(dip->un.v.units.name, AudioNvolume);
514		    break;
515	    case AUDIOAMD_SPEAKER_VOL:
516		    dip->type = AUDIO_MIXER_VALUE;
517		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
518		    dip->prev = dip->next = AUDIO_MIXER_LAST;
519		    strcpy(dip->label.name, AudioNspeaker);
520		    dip->un.v.num_channels = 1;
521		    strcpy(dip->un.v.units.name, AudioNvolume);
522		    break;
523	    case AUDIOAMD_HEADPHONES_VOL:
524		    dip->type = AUDIO_MIXER_VALUE;
525		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
526		    dip->prev = dip->next = AUDIO_MIXER_LAST;
527		    strcpy(dip->label.name, AudioNheadphone);
528		    dip->un.v.num_channels = 1;
529		    strcpy(dip->un.v.units.name, AudioNvolume);
530		    break;
531	    case AUDIOAMD_MONITOR_VOL:
532		    dip->type = AUDIO_MIXER_VALUE;
533		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
534		    dip->prev = dip->next = AUDIO_MIXER_LAST;
535		    strcpy(dip->label.name, AudioNmonitor);
536		    dip->un.v.num_channels = 1;
537		    strcpy(dip->un.v.units.name, AudioNvolume);
538		    break;
539	    case AUDIOAMD_RECORD_SOURCE:
540		    dip->type = AUDIO_MIXER_ENUM;
541		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
542		    dip->next = dip->prev = AUDIO_MIXER_LAST;
543		    strcpy(dip->label.name, AudioNsource);
544		    dip->un.e.num_mem = 1;
545		    strcpy(dip->un.e.member[0].label.name, AudioNmicrophone);
546		    dip->un.e.member[0].ord = AUDIOAMD_MIC_VOL;
547		    break;
548	    case AUDIOAMD_MONITOR_OUTPUT:
549		    dip->type = AUDIO_MIXER_ENUM;
550		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
551		    dip->next = dip->prev = AUDIO_MIXER_LAST;
552		    strcpy(dip->label.name, AudioNoutput);
553		    dip->un.e.num_mem = 2;
554		    strcpy(dip->un.e.member[0].label.name, AudioNspeaker);
555		    dip->un.e.member[0].ord = AUDIOAMD_SPEAKER_VOL;
556		    strcpy(dip->un.e.member[1].label.name, AudioNheadphone);
557		    dip->un.e.member[1].ord = AUDIOAMD_HEADPHONES_VOL;
558		    break;
559	    case AUDIOAMD_MIC_MUTE:
560		    dip->type = AUDIO_MIXER_ENUM;
561		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
562		    dip->prev =  AUDIOAMD_MIC_VOL;
563		    dip->next = AUDIO_MIXER_LAST;
564		    strcpy(dip->label.name, AudioNmute);
565		    dip->un.e.num_mem = 2;
566		    strcpy(dip->un.e.member[0].label.name, AudioNoff);
567		    dip->un.e.member[0].ord = 0;
568		    strcpy(dip->un.e.member[1].label.name, AudioNon);
569		    dip->un.e.member[1].ord = 1;
570		    break;
571	    case AUDIOAMD_INPUT_CLASS:
572		    dip->type = AUDIO_MIXER_CLASS;
573		    dip->mixer_class = AUDIOAMD_INPUT_CLASS;
574		    dip->next = dip->prev = AUDIO_MIXER_LAST;
575		    strcpy(dip->label.name, AudioCinputs);
576		    break;
577	    case AUDIOAMD_OUTPUT_CLASS:
578		    dip->type = AUDIO_MIXER_CLASS;
579		    dip->mixer_class = AUDIOAMD_OUTPUT_CLASS;
580		    dip->next = dip->prev = AUDIO_MIXER_LAST;
581		    strcpy(dip->label.name, AudioCoutputs);
582		    break;
583	    case AUDIOAMD_RECORD_CLASS:
584		    dip->type = AUDIO_MIXER_CLASS;
585		    dip->mixer_class = AUDIOAMD_RECORD_CLASS;
586		    dip->next = dip->prev = AUDIO_MIXER_LAST;
587		    strcpy(dip->label.name, AudioCrecord);
588		    break;
589	    case AUDIOAMD_MONITOR_CLASS:
590		    dip->type = AUDIO_MIXER_CLASS;
591		    dip->mixer_class = AUDIOAMD_MONITOR_CLASS;
592		    dip->next = dip->prev = AUDIO_MIXER_LAST;
593		    strcpy(dip->label.name, AudioCmonitor);
594		    break;
595	    default:
596		    return ENXIO;
597		    /*NOTREACHED*/
598	}
599
600	DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name));
601
602	return(0);
603}
604
605#endif	/* NAUDIO */
606